aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--.gitignore1
-rwxr-xr-xcreate-package.sh1
-rw-r--r--ratatoeskr/backend.php319
-rw-r--r--ratatoeskr/cms_style/images/backendbg.pngbin0 -> 4816 bytes
-rw-r--r--ratatoeskr/cms_style/images/expandarrow_collapsed.pngbin0 -> 142 bytes
-rw-r--r--ratatoeskr/cms_style/images/expandarrow_expanded.pngbin0 -> 154 bytes
-rw-r--r--ratatoeskr/cms_style/layout.css27
-rw-r--r--ratatoeskr/frontend.php130
-rw-r--r--ratatoeskr/js/backend.js19
-rw-r--r--ratatoeskr/libs/INFO6
-rw-r--r--ratatoeskr/licenses/jquery20
-rw-r--r--ratatoeskr/setup/create_tables.php49
-rw-r--r--ratatoeskr/sys/models.php343
-rw-r--r--ratatoeskr/sys/plugin_api.php55
-rw-r--r--ratatoeskr/templates/src/systemtemplates/areyousure.html11
-rw-r--r--ratatoeskr/templates/src/systemtemplates/content_write.html56
-rw-r--r--ratatoeskr/templates/src/systemtemplates/image_list.html6
-rwxr-xr-xratatoeskr/templates/src/systemtemplates/master.html9
-rw-r--r--ratatoeskr/templates/src/systemtemplates/repos.html6
-rw-r--r--ratatoeskr/templates/src/systemtemplates/sections.html5
-rw-r--r--ratatoeskr/templates/src/systemtemplates/settings.html2
-rw-r--r--ratatoeskr/templates/src/systemtemplates/styles.html6
-rw-r--r--ratatoeskr/templates/src/systemtemplates/tags_overview.html45
-rw-r--r--ratatoeskr/templates/src/systemtemplates/templates.html6
-rw-r--r--ratatoeskr/templates/src/systemtemplates/users.html4
-rw-r--r--ratatoeskr/templates/src/usertemplates/standard.html118
-rw-r--r--ratatoeskr/translations/de.php15
-rw-r--r--ratatoeskr/translations/en.php15
28 files changed, 839 insertions, 435 deletions
diff --git a/.gitignore b/.gitignore
index 3604f16..2505a76 100644
--- a/.gitignore
+++ b/.gitignore
@@ -8,4 +8,5 @@ ratatoeskr/templates/transc/*
ratatoeskr/libs/stupid_template_engine.php
ratatoeskr/libs/markdown.php
ratatoeskr/libs/kses.php
+ratatoeskr/libs/jquery.min.js
ratatoeskr/config.php
diff --git a/create-package.sh b/create-package.sh
index cf0f688..7aec2fd 100755
--- a/create-package.sh
+++ b/create-package.sh
@@ -23,6 +23,7 @@ unzip kses-*.zip
mv kses-*/kses.php .
rm -rf kses-*
rm kses-*.zip
+wget http://code.jquery.com/jquery.min.js
cd ../..
rm session_doctor.php
cd ..
diff --git a/ratatoeskr/backend.php b/ratatoeskr/backend.php
index ae72195..2db82d7 100644
--- a/ratatoeskr/backend.php
+++ b/ratatoeskr/backend.php
@@ -12,6 +12,7 @@
require_once(dirname(__FILE__) . "/sys/models.php");
require_once(dirname(__FILE__) . "/sys/pwhash.php");
require_once(dirname(__FILE__) . "/sys/textprocessors.php");
+require_once(dirname(__FILE__) . "/sys/plugin_api.php");
require_once(dirname(__FILE__) . "/languages.php");
$admin_grp = NULL;
@@ -38,25 +39,6 @@ function maketags($tagnames, $lang)
return $rv;
}
-/* Generates Yes/No form / checks it. */
-function askyesno($ste, $callback, $question, $yes=NULL, $no=NULL, $moredetails="")
-{
- if(isset($_POST["yes"]))
- return True;
- if(isset($_POST["no"]))
- return False;
-
- $ste->vars["callback"] = $callback;
- $ste->vars["question"] = $question;
- if($yes !== NULL)
- $ste->vars["yestext"] = $yes;
- if($no !== NULL)
- $ste->vars["notext"] = $no;
- if($moredetails !== NULL)
- $ste->vars["moredetails"] = $moredetails;
- return $ste->exectemplate("/systemtemplates/areyousure.html");
-}
-
$backend_subactions = NULL;
function build_backend_subactions()
@@ -116,6 +98,7 @@ $backend_subactions = url_action_subactions(array(
}
}
load_language();
+
/* If we are here, user is not logged in... */
$url_next = array("login");
},
@@ -160,7 +143,7 @@ $backend_subactions = url_action_subactions(array(
"content" => url_action_subactions(array(
"write" => function(&$data, $url_now, &$url_next)
{
- global $ste, $translation, $textprocessors, $ratatoeskr_settings, $languages;
+ global $ste, $translation, $textprocessors, $ratatoeskr_settings, $languages, $articleeditor_plugins;
list($article, $editlang) = array_slice($url_next, 0);
if(!isset($editlang))
@@ -192,11 +175,11 @@ $backend_subactions = url_action_subactions(array(
if(isset($_POST["save_article"]))
{
- if(!preg_match('/^[a-zA-Z0-9-_]+$/', @$_POST["urlname"]))
+ if(!Article::test_urlname($_POST["urlname"]))
$fail_reasons[] = $translation["invalid_urlname"];
else
$inputs["urlname"] = $_POST["urlname"];
- if((@$_POST["article_status"] < 0) or (@$_POST["article_status"] > 3))
+ if(!Article::test_status(@$_POST["article_status"]))
$fail_reasons[] = $translation["invalid_article_status"];
else
$inputs["article_status"] = (int) $_POST["article_status"];
@@ -235,14 +218,21 @@ $backend_subactions = url_action_subactions(array(
if(isset($_POST["saveaslang"]))
$editlang = $_POST["saveaslang"];
}
+ else
+ {
+ /* Call articleeditor plugins */
+ $article = empty($article) ? NULL : Article::by_urlname($article);
+ foreach($articleeditor_plugins as $plugin)
+ call_user_func($plugin["fx"], $article, False);
+ }
function fill_article(&$article, $inputs, $editlang)
{
$article->urlname = $inputs["urlname"];
$article->status = $inputs["article_status"];
$article->timestamp = $inputs["date"];
- $article->title [$editlang] = new Translation($inputs["title"], "" );
- $article->text [$editlang] = new Translation($inputs["content"], $inputs["content_txtproc"]);
+ $article->title[$editlang] = new Translation($inputs["title"], "");
+ $article->text[$editlang] = new Translation($inputs["content"], $inputs["content_txtproc"]);
$article->excerpt[$editlang] = new Translation($inputs["excerpt"], $inputs["excerpt_txtproc"]);
$article->set_tags(maketags($inputs["tags"], $editlang));
$article->set_section($inputs["article_section"]);
@@ -257,15 +247,32 @@ $backend_subactions = url_action_subactions(array(
{
$article = Article::create($inputs["urlname"]);
fill_article($article, $inputs, $editlang);
- try
+
+ /* Calling articleeditor plugins */
+ $call_after_save = array();
+ foreach($articleeditor_plugins as $plugin)
{
- $article->save();
- $ste->vars["article_editurl"] = urlencode($article->urlname) . "/" . urlencode($editlang);
- $ste->vars["success"] = htmlesc($translation["article_save_success"]);
+ $result = call_user_func($plugin["fx"], $article, True);
+ if(is_string($result))
+ $fail_reasons[] = $result;
+ elseif($result !== NULL)
+ $call_after_save[] = $result;
}
- catch(AlreadyExistsError $e)
+
+ if(empty($fail_reasons))
{
- $fail_reasons[] = $translation["article_name_already_in_use"];
+ try
+ {
+ $article->save();
+ foreach($call_after_save as $cb)
+ call_user_func($cb, $article);
+ $ste->vars["article_editurl"] = urlencode($article->urlname) . "/" . urlencode($editlang);
+ $ste->vars["success"] = htmlesc($translation["article_save_success"]);
+ }
+ catch(AlreadyExistsError $e)
+ {
+ $fail_reasons[] = $translation["article_name_already_in_use"];
+ }
}
}
}
@@ -273,7 +280,8 @@ $backend_subactions = url_action_subactions(array(
{
try
{
- $article = Article::by_urlname($article);
+ if(!($article instanceof Article))
+ $article = Article::by_urlname($article);
}
catch(DoesNotExistError $e)
{
@@ -283,15 +291,32 @@ $backend_subactions = url_action_subactions(array(
if(empty($fail_reasons) and isset($_POST["save_article"]))
{
fill_article($article, $inputs, $editlang);
- try
+
+ /* Calling articleeditor plugins */
+ $call_after_save = array();
+ foreach($articleeditor_plugins as $plugin)
{
- $article->save();
- $ste->vars["article_editurl"] = urlencode($article->urlname) . "/" . urlencode($editlang);
- $ste->vars["success"] = htmlesc($translation["article_save_success"]);
+ $result = call_user_func($plugin["fx"], $article, True);
+ if(is_string($result))
+ $fail_reasons[] = $result;
+ elseif($result !== NULL)
+ $call_after_save[] = $result;
}
- catch(AlreadyExistsError $e)
+
+ if(empty($fail_reasons))
{
- $fail_reasons[] = $translation["article_name_already_in_use"];
+ try
+ {
+ $article->save();
+ foreach($call_after_save as $cb)
+ call_user_func($cb, $article);
+ $ste->vars["article_editurl"] = urlencode($article->urlname) . "/" . urlencode($editlang);
+ $ste->vars["success"] = htmlesc($translation["article_save_success"]);
+ }
+ catch(AlreadyExistsError $e)
+ {
+ $fail_reasons[] = $translation["article_name_already_in_use"];
+ }
}
}
@@ -367,6 +392,9 @@ $backend_subactions = url_action_subactions(array(
$ste->vars[$k_out] = $inputs[$k_in];
}
+ /* Displaying article editor plugins */
+ $ste->vars["displayed_plugins"] = array_map(function($x) { return array("label" => $x["label"], "template" => $x["template"]); }, array_filter($articleeditor_plugins, function($x) { return $x["display"]; }));
+
if(!empty($fail_reasons))
$ste->vars["failed"] = $fail_reasons;
@@ -375,149 +403,136 @@ $backend_subactions = url_action_subactions(array(
"tags" => function(&$data, $url_now, &$url_next)
{
global $translation, $languages, $ste, $rel_path_to_root;
- $ste->vars["section"] = "content";
- $ste->vars["submenu"] = "tags";
- list($tagname, $tagaction) = $url_next;
$url_next = array();
- if(isset($tagname))
+ $ste->vars["section"] = "content";
+ $ste->vars["submenu"] = "tags";
+ $ste->vars["pagetitle"] = $translation["tags_overview"];
+
+ if(isset($_POST["delete"]) and ($_POST["really_delete"] == "yes"))
{
- try
+ foreach($_POST["tag_multiselect"] as $tagid)
{
- $tag = Tag::by_name($tagname);
+ try
+ {
+ $tag = Tag::by_id($tagid);
+ $tag->delete();
+ }
+ catch(DoesNotExistError $e)
+ {
+ continue;
+ }
}
- catch(DoesNotExistError $e)
+
+ $ste->vars["success"] = $translation["tags_successfully_deleted"];
+ }
+
+ if(isset($_POST["save_changes"]))
+ {
+ $newlang = (!empty($_POST["new_language"])) ? $_POST["new_language"] : NULL;
+ $newtag = NULL;
+
+ if(!empty($_POST["newtagname"]))
{
- throw new NotFoundError();
+ if(!Tag::test_name(@$_POST["newtagname"]))
+ $ste->vars["error"] = $translation["invalid_tag_name"];
+ else
+ $newtag = $_POST["newtagname"];
}
- if(isset($tagaction))
+ if(($newlang !== NULL) and (!isset($languages[$newlang])))
+ $newlang = NULL;
+ if($newtag !== NULL)
{
- switch($tagaction)
+ try
{
- case "delete":
- $ste->vars["pagetitle"] = str_replace("[[TAGNAME]]", $tag->name, $translation["delete_tag_pagetitle"]);
- $yesnoresp = askyesno($ste, "$rel_path_to_root/backend/content/tags/{$tag->name}/delete", $translation["delete_comment_question"]);
- if(is_string($yesnoresp))
- {
- echo $yesnoresp;
- return;
- }
-
- if($yesnoresp)
- {
- $tag->delete();
- echo $ste->exectemplate("/systemtemplates/tag_deleted.html");
- }
- else
- goto backend_content_tags_overview; /* Hopefully no dinosaur will attack me: http://xkcd.com/292/ :-) */
- break;
- case "addtranslation":
- $ste->vars["pagetitle"] = $translation["tag_add_lang"];
- $ste->vars["tagname"] = $tag->name;
- if(isset($_POST["addtranslation"]))
- {
- $errors = array();
- if(!isset($languages[@$_POST["language"]]))
- $errors[] = $translation["language_unknown"];
- if(empty($_POST["translation"]))
- $errors[] = $translation["no_translation_text_given"];
- if(empty($errors))
- {
- $tag->title[$_POST["language"]] = new Translation($_POST["translation"], "");
- $tag->save();
- $ste->vars["success"] = $translation["tag_translation_added"];
- goto backend_content_tags_overview;
- }
- else
- $ste->vars["errors"] = $errors;
- }
- echo $ste->exectemplate("/systemtemplates/tag_addtranslation.html");
- break;
+ $newtag = Tag::create($newtag);
+ }
+ catch(AlreadyExistsError $e)
+ {
+ $newtag = NULL;
}
}
- }
- else
- {
- backend_content_tags_overview:
- if(isset($_POST["create_new_tag"]))
+ $translations = array();
+ foreach($_POST as $k => $v)
{
- if((strpos(@$_POST["new_tag_name"], ",") !== False) or (strpos(@$_POST["new_tag_name"], " ") !== False) or (strlen(@$_POST["new_tag_name"]) == 0))
- $ste->vars["error"] = $translation["invalid_tag_name"];
- else
+ if(preg_match('/tagtrans_(NEW|[a-z]{2})_(.*)/', $k, $matches) == 1)
{
- try
- {
- $tag = Tag::create($_POST["new_tag_name"]);
- $tag->title[$data["user"]->language] = new Translation($_POST["new_tag_name"], "");
- $tag->save();
- $ste->vars["success"] = $translation["tag_created_successfully"];
- }
- catch(AlreadyExistsError $e)
- {
- $ste->vars["error"] = $translation["tag_name_already_in_use"];
- }
+ $lang = ($matches[1] == "NEW") ? $newlang : $matches[1];
+ $tag = $matches[2];
+ if($lang === NULL)
+ continue;
+ $translations[$tag][$lang] = $v;
}
}
- if(isset($_POST["edit_translations"]))
+ foreach($translations as $tag => $langmap)
{
- $tagbuffer = array();
- foreach($_POST as $k => $v)
+ if($tag == "NEW")
+ {
+ if($newtag === NULL)
+ continue;
+ $tag = $newtag;
+ }
+ else
{
- if(preg_match("/^tagtrans_(.*?)_(.*)$/", $k, $matches))
+ try
{
- if(!isset($languages[$matches[1]]))
- continue;
-
- if(!isset($tagbuffer[$matches[2]]))
- {
- try
- {
- $tagbuffer[$matches[2]] = Tag::by_name($matches[2]);
- }
- catch(DoesNotExistError $e)
- {
- continue;
- }
- }
-
- if(empty($v) and isset($tagbuffer[$matches[2]]->title[$matches[1]]))
- unset($tagbuffer[$matches[2]]->title[$matches[1]]);
- elseif(empty($v))
- continue;
- else
- $tagbuffer[$matches[2]]->title[$matches[1]] = new Translation($v, "");
+ $tag = Tag::by_id($tag);
+ }
+ catch(DoesNotExistError $e)
+ {
+ continue;
}
}
- foreach($tagbuffer as $tag)
- $tag->save();
+ foreach($langmap as $l => $text)
+ {
+ if(empty($text))
+ unset($tag->title[$l]);
+ else
+ $tag->title[$l] = new Translation($text, "");
+ }
- $ste->vars["success"] = $translation["tag_titles_edited_successfully"];
+ $tag->save();
}
- $ste->vars["pagetitle"] = $translation["tags_overview"];
-
- $alltags = Tag::all();
- usort($alltags, function($a, $b) { return strcmp($a->name, $b->name); });
- $ste->vars["all_tag_langs"] = array();
- $ste->vars["alltags"] = array();
- foreach($alltags as $tag)
- {
- $tag_pre = array("name" => $tag->name, "translations" => array());
- foreach($tag->title as $langcode => $translation_obj)
- {
- $tag_pre["translations"][$langcode] = $translation_obj->text;
- if(!isset($ste->vars["all_tag_langs"][$langcode]))
- $ste->vars["all_tag_langs"][$langcode] = $languages[$langcode]["language"];
- }
- $ste->vars["alltags"][] = $tag_pre;
+ $ste->vars["success"] = $translation["tags_successfully_edited"];
+ }
+
+ $ste->vars["alltags"] = array();
+ $taglangs = array();
+
+ $alltags = Tag::all();
+ foreach($alltags as $tag)
+ {
+ $transls = array();
+ foreach($tag->title as $l => $t)
+ {
+ if(!in_array($l, $taglangs))
+ $taglangs[] = $l;
+ $transls[$l] = $t->text;
}
- echo $ste->exectemplate("/systemtemplates/tags_overview.html");
+
+ $ste->vars["alltags"][] = array(
+ "id" => $tag->get_id(),
+ "name" => $tag->name,
+ "translations" => $transls
+ );
}
+
+ $unused_langs = array_diff(array_keys($languages), $taglangs);
+
+ $ste->vars["all_tag_langs"] = array();
+ foreach($taglangs as $l)
+ $ste->vars["all_tag_langs"][$l] = $languages[$l]["language"];
+ $ste->vars["unused_languages"] = array();
+ foreach($unused_langs as $l)
+ $ste->vars["unused_languages"][$l] = $languages[$l]["language"];
+
+ echo $ste->exectemplate("/systemtemplates/tags_overview.html");
},
"articles" => function(&$data, $url_now, &$url_next)
{
@@ -1045,7 +1060,7 @@ $backend_subactions = url_action_subactions(array(
/* A write request? */
if(isset($_POST["save_style"]))
{
- if(preg_match("/^[a-zA-Z0-9\\-_\\.]+$/", $_POST["style_name"]) == 1)
+ if(Style::test_name($_POST["style_name"]))
{
$ste->vars["style_name"] = $_POST["style_name"];
$ste->vars["style_code"] = $_POST["style_code"];
@@ -1098,7 +1113,7 @@ $backend_subactions = url_action_subactions(array(
{
if((preg_match("/^[a-zA-Z0-9\\-_\\.]+$/", $_POST["template"]) == 0) or (!is_file(SITE_BASE_PATH . "/ratatoeskr/templates/src/usertemplates/{$_POST['template']}")))
$ste->vars["error"] = $translation["unknown_template"];
- else if(preg_match("/^[a-zA-Z0-9\\-_]+$/", $_POST["section_name"]) == 0)
+ else if(!Section::test_name($_POST["section_name"]))
$ste->vars["error"] = $translation["invalid_section_name"];
else
{
diff --git a/ratatoeskr/cms_style/images/backendbg.png b/ratatoeskr/cms_style/images/backendbg.png
new file mode 100644
index 0000000..995e8cf
--- /dev/null
+++ b/ratatoeskr/cms_style/images/backendbg.png
Binary files differ
diff --git a/ratatoeskr/cms_style/images/expandarrow_collapsed.png b/ratatoeskr/cms_style/images/expandarrow_collapsed.png
new file mode 100644
index 0000000..62f662b
--- /dev/null
+++ b/ratatoeskr/cms_style/images/expandarrow_collapsed.png
Binary files differ
diff --git a/ratatoeskr/cms_style/images/expandarrow_expanded.png b/ratatoeskr/cms_style/images/expandarrow_expanded.png
new file mode 100644
index 0000000..a5e4c41
--- /dev/null
+++ b/ratatoeskr/cms_style/images/expandarrow_expanded.png
Binary files differ
diff --git a/ratatoeskr/cms_style/layout.css b/ratatoeskr/cms_style/layout.css
index 1163887..aac132a 100644
--- a/ratatoeskr/cms_style/layout.css
+++ b/ratatoeskr/cms_style/layout.css
@@ -19,6 +19,7 @@ a:hover {
body, html {
margin: 0px;
padding:0px;
+ background: white url(images/backendbg.png) bottom right no-repeat fixed;
}
hr {
@@ -241,6 +242,10 @@ table.listtab td {
border-top: 1px solid #eee;
}
+table.listtab th, table.listtab td {
+ padding: 0mm 1mm 0mm;
+}
+
table.listtab tr:first-child td {
border-top: 1px solid #666;
}
@@ -249,6 +254,10 @@ table.listtab tbody tr:hover {
background: #eee;
}
+table.listtab tbody input[type="text"] {
+ width: 100%;
+}
+
textarea.codeedit {
font-family: monospace;
}
@@ -257,3 +266,21 @@ ul.bulletfree {
list-style: none;
padding-left: 0mm;
}
+
+.metabar_element_expanded, .metabar_element_collapsed {
+ min-height: 12px;
+ padding-left: 12px;
+ cursor: pointer;
+}
+
+.metabar_element_expanded:hover, .metabar_element_collapsed:hover {
+ text-decoration: underline;
+}
+
+.metabar_element_expanded {
+ background: url(images/expandarrow_expanded.png) 0px 4px no-repeat;
+}
+
+.metabar_element_collapsed {
+ background: url(images/expandarrow_collapsed.png) 0px 4px no-repeat;
+} \ No newline at end of file
diff --git a/ratatoeskr/frontend.php b/ratatoeskr/frontend.php
index 883f842..76b0afc 100644
--- a/ratatoeskr/frontend.php
+++ b/ratatoeskr/frontend.php
@@ -25,9 +25,10 @@ require_once(dirname(__FILE__) . "/libs/kses.php");
*
* Returns:
* Array with these fields:
- * * id
- * * name
- * * title
+ * * id - The ID of the section.
+ * * name - The name of the section.
+ * * title - The title of the section in the current language
+ * * __obj - The <Section> object. Useful for plugins, so they do not need to fetch the object from the database again.
*/
function section_transform_ste($section, $lang)
{
@@ -49,9 +50,10 @@ function section_transform_ste($section, $lang)
*
* Returns:
* Array with these fields:
- * * id
- * * name
- * * title
+ * * id - The ID of the tag.
+ * * name - The name of the tag.
+ * * title - The title in the current language.
+ * * __obj - The <Tag> object. Useful for plugins, so they do not need to fetch the object from the database again.
*/
function tag_transform_ste($tag, $lang)
{
@@ -93,6 +95,7 @@ function tag_transform_ste($tag, $lang)
* * tags (array(sub-fields: <tag_transform_ste>))
* * languages (array: language name=>url)
* * comments_allowed
+ * * __obj - Useful for plugins, so they do not need to fetch the object from the database again.
*/
function article_transform_ste($article, $lang)
{
@@ -155,18 +158,20 @@ function comment_transform_ste($comment)
* The fields of an article can be looked up at <article_transform_ste>.
*
* Parameters:
- * var - (mandatory) The name of the variable, where the current article should be stored at.
- * id - (optional) Filter by ID.
- * urlname - (optional) Filter by urlname.
- * section - (optional) Filter by section (section name).
- * status - (optional) Filter by status (numeric, <ARTICLE_STATUS_>).
- * tag - (optional) Filter by tag (tag name).
- * sort - (optional) How to sort. Format: "fieldname direction" where fieldname is one of [id, urlname, title, timestamp] and direction is one of [asc, desc].
- * perpage - (optional) How many articles should be shown per page (default unlimited).
- * page - (optional) On which page are we (starting with 1). Useful in combination with $current[page], <page_prev> and <page_next>. (Default: 1)
- * maxpage - (optional) (variable name) If given, the number of pages are stored in this variable.
- * skip - (optional) How many articles should be skipped? (Default: none)
- * count - (optional) How many articles to output. (Default unlimited)
+ * var - (mandatory) The name of the variable, where the current article should be stored at.
+ * id - (optional) Filter by ID.
+ * urlname - (optional) Filter by urlname.
+ * section - (optional) Filter by section (section name).
+ * sectionvar - (optional) Filter by section (Name of variable that contains a section).
+ * status - (optional) Filter by status (numeric, <ARTICLE_STATUS_>).
+ * tag - (optional) Filter by tag (tag name).
+ * tagvar - (optional) Filter by tag (Name of variable that contains a tag).
+ * sort - (optional) How to sort. Format: "fieldname direction" where fieldname is one of [id, urlname, title, timestamp] and direction is one of [asc, desc].
+ * perpage - (optional) How many articles should be shown per page (default unlimited).
+ * page - (optional) On which page are we (starting with 1). Useful in combination with $current[page], <page_prev> and <page_next>. (Default: 1)
+ * maxpage - (optional) (variable name) If given, the number of pages are stored in this variable.
+ * skip - (optional) How many articles should be skipped? (Default: none)
+ * count - (optional) How many articles to output. (Default unlimited)
*
* Tag Content:
* The tag's content will be executed for every article. The current article will be written to the variable specified by the var parameter before.
@@ -180,27 +185,32 @@ $ste->register_tag("articles_get", function($ste, $params, $sub)
if(!isset($params["var"]))
throw new \ste\RuntimeError("Parameter var is needed in article_get!");
- if(isset($params["section"]))
- {
- try
- {
- $params["section"] = Section::by_name($params["section"]);
- }
- catch(NotFoundError $e)
- {
- unset($params["section"]);
- }
- }
$criterias = array("langavail" => $lang, "onlyvisible" => True);
if(isset($params["id"]))
$criterias["id"] = $params["id"];
if(isset($params["urlname"]))
$criterias["urlname"];
- if(isset($params["section"]))
- $criterias["section"] = $params["section"];
if(isset($params["status"]))
$criterias["status"] = $params["status"];
+ if(isset($params["sectionvar"]))
+ {
+ $sectionvar = $ste->get_var_by_name($params["sectionvar"]);
+ $criterias["section"] = $sectionvar["__obj"];
+ }
+ else if(isset($params["section"]))
+ {
+ try
+ {
+ $criterias["section"] = Section::by_name($params["section"]);
+ }
+ catch(DoesNotExistError $e) {}
+ }
+ if(isset($params["tagvar"]))
+ {
+ $tagvar = $ste->get_var_by_name($params["tagvar"]);
+ $criterias["tag"] = $tagvar["__obj"];
+ }
if(isset($params["tag"]))
{
try
@@ -389,8 +399,9 @@ $ste->register_tag("article_comments", function($ste, $params, $sub)
* Generates a HTML form tag that allows the visitor to write a comment.
*
* Parameters:
- * article - (mandatory) The name of the variable, where the article is stored at.
- * default - (optional) If not empty, a default formular with the mandatory fields will be generated.
+ * article - (mandatory) The name of the variable, where the article is stored at.
+ * default - (optional) If not empty, a default formular with the mandatory fields will be generated.
+ * previewbtn - (optional) If not empty and default form is choosen, a preview button will also be generated.
*
* Tag Content:
* The tag's content will be written into the HTML form tag.
@@ -443,11 +454,13 @@ $ste->register_tag("comment_form", function($ste, $params, $sub)
$form_header = "<form action=\"{$tpl_article["fullurl"]}?comment\" method=\"post\" accept-charset=\"UTF-8\"><input type=\"hidden\" name=\"comment_token\" value=\"$token\" />";
+ $previewbtn = $ste->evalbool(@$params["previewbtn"]) ? " <input type=\"submit\" name=\"preview_comment\" value=\"{$translation["comment_form_preview"]}\" />" : "";
+
if($ste->evalbool(@$params["default"]))
$form_body = "<p>{$translation["comment_form_name"]}: <input type=\"text\" name=\"author_name\" value=\"" . htmlesc(@$_POST["author_name"]) . "\" /></p>
<p>{$translation["comment_form_mail"]}: <input type=\"text\" name=\"author_mail\" value=\"" . htmlesc(@$_POST["author_mail"]) . "\" /></p>
<p>{$translation["comment_form_text"]}:<br /><textarea name=\"comment_text\" cols=\"50\" rows=\"10\">" . htmlesc(@$_POST["comment_text"]) . "</textarea></p>
-<p><input type=\"submit\" name=\"post_comment\" /></p>";
+<p><input type=\"submit\" name=\"post_comment\" value=\"{$translation["comment_form_submit"]}\" />$previewbtn</p>";
else
{
$ste->vars["current"]["oldcomment"] = array(
@@ -648,6 +661,55 @@ $ste->register_tag("title", function($ste, $params, $sub)
return "<title>$pagetitle</title>";
});
+function make_on_anything_tag($field)
+{
+ return function($ste, $params, $sub) use ($field)
+ {
+ if($ste->evalbool($ste->vars["current"][$field]))
+ {
+ if(!empty($params["var"]))
+ $ste->set_var_by_name($params["var"], $ste->vars["current"][$field]);
+ return $sub($ste);
+ }
+ };
+}
+
+/*
+ * STETag: on_article
+ * Execute tag content, if currently an article is requested.
+ *
+ * Parameters:
+ * var - (optional) If set, the article will be stored in the variable with that name (see <article_transform_ste> for sub-fields).
+ *
+ * Returns:
+ * The executed tag content, if an article was requested.
+ */
+$ste->register_tag("on_article", make_on_anything_tag("article"));
+
+/*
+ * STETag: on_tag
+ * Execute tag content, if currently a tag is requested.
+ *
+ * Parameters:
+ * var - (optional) If set, the tag will be stored in the variable with that name (see <tag_transform_ste> for sub-fields).
+ *
+ * Returns:
+ * The executed tag content, if a tag was requested.
+ */
+$ste->register_tag("on_tag", make_on_anything_tag("tag"));
+
+/*
+ * STETag: on_section
+ * Execute tag content, if currently a section is requested.
+ *
+ * Parameters:
+ * var - (optional) If set, the section will be stored in the variable with that name (see <section_transform_ste> for sub-fields).
+ *
+ * Returns:
+ * The executed tag content, if a section was requested.
+ */
+$ste->register_tag("on_section", make_on_anything_tag("section"));
+
/*
* STEVar: $current
* Holds information about the current page in the frontend (the part of the webpage, the visitor sees).
diff --git a/ratatoeskr/js/backend.js b/ratatoeskr/js/backend.js
new file mode 100644
index 0000000..d131bfe
--- /dev/null
+++ b/ratatoeskr/js/backend.js
@@ -0,0 +1,19 @@
+$(function()
+{
+ $("div.articleeditor-metabar-element h2").addClass("metabar_element_expanded").click(function()
+ {
+ self = $(this);
+ if(self.hasClass("metabar_element_expanded"))
+ {
+ self.removeClass("metabar_element_expanded");
+ self.addClass("metabar_element_collapsed");
+ $("div.articleeditor-metabar-element-content", self.parent()).hide("fast");
+ }
+ else
+ {
+ self.removeClass("metabar_element_collapsed");
+ self.addClass("metabar_element_expanded");
+ $("div.articleeditor-metabar-element-content", self.parent()).show("fast");
+ }
+ });
+}); \ No newline at end of file
diff --git a/ratatoeskr/libs/INFO b/ratatoeskr/libs/INFO
index 60d4df4..e2bc19b 100644
--- a/ratatoeskr/libs/INFO
+++ b/ratatoeskr/libs/INFO
@@ -17,3 +17,9 @@ This directory will hold some libraries Ratatöskr needs.
Place "kses.php" from the archive directly into this directory.
kses can be found at <http://sourceforge.net/projects/kses/>
+
+4. jQuery
+
+ Place jquery.min.js into this folder.
+
+ jQuery can be found at <http://jquery.com> \ No newline at end of file
diff --git a/ratatoeskr/licenses/jquery b/ratatoeskr/licenses/jquery
new file mode 100644
index 0000000..0dee009
--- /dev/null
+++ b/ratatoeskr/licenses/jquery
@@ -0,0 +1,20 @@
+Copyright (c) 2012 John Resig, http://jquery.com/
+
+Permission is hereby granted, free of charge, to any person obtaining
+a copy of this software and associated documentation files (the
+"Software"), to deal in the Software without restriction, including
+without limitation the rights to use, copy, modify, merge, publish,
+distribute, sublicense, and/or sell copies of the Software, and to
+permit persons to whom the Software is furnished to do so, subject to
+the following conditions:
+
+The above copyright notice and this permission notice shall be
+included in all copies or substantial portions of the Software.
+
+THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
+EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
+MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
+NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
+LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
+OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
+WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. \ No newline at end of file
diff --git a/ratatoeskr/setup/create_tables.php b/ratatoeskr/setup/create_tables.php
index 819970a..97a4cd5 100644
--- a/ratatoeskr/setup/create_tables.php
+++ b/ratatoeskr/setup/create_tables.php
@@ -20,12 +20,12 @@ CREATE TABLE IF NOT EXISTS `PREFIX_articles` (
`timestamp` bigint(20) NOT NULL,
`allow_comments` int(11) NOT NULL,
PRIMARY KEY (`id`)
-) ENGINE=MyISAM DEFAULT CHARSET=utf8 COLLATE=utf8_unicode_ci;
+) DEFAULT CHARSET=utf8 COLLATE=utf8_unicode_ci;
CREATE TABLE IF NOT EXISTS `PREFIX_article_tag_relations` (
`tag` int(11) NOT NULL,
`article` int(11) NOT NULL
-) ENGINE=MyISAM DEFAULT CHARSET=utf8 COLLATE=utf8_unicode_ci;
+) DEFAULT CHARSET=utf8 COLLATE=utf8_unicode_ci;
CREATE TABLE IF NOT EXISTS `PREFIX_comments` (
`id` int(11) NOT NULL AUTO_INCREMENT,
@@ -38,30 +38,30 @@ CREATE TABLE IF NOT EXISTS `PREFIX_comments` (
`visible` tinyint(4) NOT NULL,
`read_by_admin` tinyint(4) NOT NULL,
PRIMARY KEY (`id`)
-) ENGINE=MyISAM DEFAULT CHARSET=utf8 COLLATE=utf8_unicode_ci;
+) DEFAULT CHARSET=utf8 COLLATE=utf8_unicode_ci;
CREATE TABLE IF NOT EXISTS `PREFIX_groups` (
`id` int(11) NOT NULL AUTO_INCREMENT,
`name` text COLLATE utf8_unicode_ci NOT NULL,
PRIMARY KEY (`id`)
-) ENGINE=MyISAM DEFAULT CHARSET=utf8 COLLATE=utf8_unicode_ci;
+) DEFAULT CHARSET=utf8 COLLATE=utf8_unicode_ci;
CREATE TABLE IF NOT EXISTS `PREFIX_group_members` (
`user` int(11) NOT NULL,
`group` int(11) NOT NULL
-) ENGINE=MyISAM DEFAULT CHARSET=utf8 COLLATE=utf8_unicode_ci;
+) DEFAULT CHARSET=utf8 COLLATE=utf8_unicode_ci;
CREATE TABLE IF NOT EXISTS `PREFIX_images` (
`id` int(11) NOT NULL AUTO_INCREMENT,
`name` text COLLATE utf8_unicode_ci NOT NULL,
`file` text COLLATE utf8_unicode_ci NOT NULL,
PRIMARY KEY (`id`)
-) ENGINE=MyISAM DEFAULT CHARSET=utf8 COLLATE=utf8_unicode_ci;
+) DEFAULT CHARSET=utf8 COLLATE=utf8_unicode_ci;
CREATE TABLE IF NOT EXISTS `PREFIX_multilingual` (
`id` int(11) NOT NULL AUTO_INCREMENT,
PRIMARY KEY (`id`)
-) ENGINE=MyISAM DEFAULT CHARSET=utf8 COLLATE=utf8_unicode_ci;
+) DEFAULT CHARSET=utf8 COLLATE=utf8_unicode_ci;
CREATE TABLE IF NOT EXISTS `PREFIX_plugins` (
`id` int(11) NOT NULL AUTO_INCREMENT,
@@ -82,13 +82,13 @@ CREATE TABLE IF NOT EXISTS `PREFIX_plugins` (
`update` tinyint(4) NOT NULL,
`api` int(11) NOT NULL,
PRIMARY KEY (`id`)
-) ENGINE=MyISAM DEFAULT CHARSET=utf8 COLLATE=utf8_unicode_ci;
+) DEFAULT CHARSET=utf8 COLLATE=utf8_unicode_ci;
CREATE TABLE IF NOT EXISTS `PREFIX_plugin_kvstorage` (
`plugin` int(11) NOT NULL,
`key` text COLLATE utf8_unicode_ci NOT NULL,
`value` text COLLATE utf8_unicode_ci NOT NULL
-) ENGINE=MyISAM DEFAULT CHARSET=utf8 COLLATE=utf8_unicode_ci;
+) DEFAULT CHARSET=utf8 COLLATE=utf8_unicode_ci;
CREATE TABLE IF NOT EXISTS `PREFIX_repositories` (
`id` int(11) NOT NULL AUTO_INCREMENT,
@@ -98,7 +98,7 @@ CREATE TABLE IF NOT EXISTS `PREFIX_repositories` (
`pkgcache` text COLLATE utf8_unicode_ci NOT NULL,
`lastrefresh` bigint(20) NOT NULL,
PRIMARY KEY (`id`)
-) ENGINE=MyISAM DEFAULT CHARSET=utf8 COLLATE=utf8_unicode_ci;
+) DEFAULT CHARSET=utf8 COLLATE=utf8_unicode_ci;
CREATE TABLE IF NOT EXISTS `PREFIX_sections` (
`id` int(11) NOT NULL AUTO_INCREMENT,
@@ -107,38 +107,38 @@ CREATE TABLE IF NOT EXISTS `PREFIX_sections` (
`template` text COLLATE utf8_unicode_ci NOT NULL,
`styles` text COLLATE utf8_unicode_ci NOT NULL,
PRIMARY KEY (`id`)
-) ENGINE=MyISAM DEFAULT CHARSET=utf8 COLLATE=utf8_unicode_ci;
+) DEFAULT CHARSET=utf8 COLLATE=utf8_unicode_ci;
CREATE TABLE IF NOT EXISTS `PREFIX_section_style_relations` (
`section` int(11) NOT NULL,
`style` int(11) NOT NULL
-) ENGINE=MyISAM DEFAULT CHARSET=utf8 COLLATE=utf8_unicode_ci;
+) DEFAULT CHARSET=utf8 COLLATE=utf8_unicode_ci;
CREATE TABLE IF NOT EXISTS `PREFIX_settings_kvstorage` (
`key` text COLLATE utf8_unicode_ci NOT NULL,
`value` text COLLATE utf8_unicode_ci NOT NULL
-) ENGINE=MyISAM DEFAULT CHARSET=utf8 COLLATE=utf8_unicode_ci;
+) DEFAULT CHARSET=utf8 COLLATE=utf8_unicode_ci;
CREATE TABLE IF NOT EXISTS `PREFIX_styles` (
`id` int(11) NOT NULL AUTO_INCREMENT,
`name` text COLLATE utf8_unicode_ci NOT NULL,
`code` text COLLATE utf8_unicode_ci NOT NULL,
PRIMARY KEY (`id`)
-) ENGINE=MyISAM DEFAULT CHARSET=utf8 COLLATE=utf8_unicode_ci;
+) DEFAULT CHARSET=utf8 COLLATE=utf8_unicode_ci;
CREATE TABLE IF NOT EXISTS `PREFIX_tags` (
`id` int(11) NOT NULL AUTO_INCREMENT,
`name` text COLLATE utf8_unicode_ci NOT NULL,
`title` int(11) NOT NULL,
PRIMARY KEY (`id`)
-) ENGINE=MyISAM DEFAULT CHARSET=utf8 COLLATE=utf8_unicode_ci;
+) DEFAULT CHARSET=utf8 COLLATE=utf8_unicode_ci;
CREATE TABLE IF NOT EXISTS `PREFIX_translations` (
`multilingual` int(11) NOT NULL,
`language` varchar(10) COLLATE utf8_unicode_ci NOT NULL,
`text` text COLLATE utf8_unicode_ci NOT NULL,
`texttype` text COLLATE utf8_unicode_ci NOT NULL
-) ENGINE=MyISAM DEFAULT CHARSET=utf8 COLLATE=utf8_unicode_ci;
+) DEFAULT CHARSET=utf8 COLLATE=utf8_unicode_ci;
CREATE TABLE IF NOT EXISTS `PREFIX_users` (
`id` int(11) NOT NULL AUTO_INCREMENT,
@@ -148,7 +148,20 @@ CREATE TABLE IF NOT EXISTS `PREFIX_users` (
`fullname` text COLLATE utf8_unicode_ci NOT NULL,
`language` varchar(10) COLLATE utf8_unicode_ci NOT NULL,
PRIMARY KEY (`id`)
-) ENGINE=MyISAM DEFAULT CHARSET=utf8 COLLATE=utf8_unicode_ci;
+) DEFAULT CHARSET=utf8 COLLATE=utf8_unicode_ci;
+
+CREATE TABLE IF NOT EXISTS `PREFIX_meta` (
+ `key` text COLLATE utf8_unicode_ci NOT NULL,
+ `value` text COLLATE utf8_unicode_ci NOT NULL
+) DEFAULT CHARSET=utf8 COLLATE=utf8_unicode_ci;
+
+
+CREATE TABLE IF NOT EXISTS `PREFIX_article_extradata` (
+ `article` int(11) NOT NULL,
+ `plugin` int(11) NOT NULL,
+ `key` text COLLATE utf8_unicode_ci NOT NULL,
+ `value` text COLLATE utf8_unicode_ci NOT NULL
+) DEFAULT CHARSET=utf8 COLLATE=utf8_unicode_ci;
SQL;
function create_mysql_tables()
@@ -161,6 +174,8 @@ function create_mysql_tables()
if(!empty($q))
qdb($q);
}
+
+ qdb("INSERT INTO `PREFIX_meta` (`key`, `value`) VALUES ('dbversion', '%s')", base64_encode(serialize(1)));
}
?>
diff --git a/ratatoeskr/sys/models.php b/ratatoeskr/sys/models.php
index fe80ce4..44367dd 100644
--- a/ratatoeskr/sys/models.php
+++ b/ratatoeskr/sys/models.php
@@ -74,6 +74,13 @@ class AlreadyExistsError extends Exception { }
*/
class NotAllowedError extends Exception { }
+/*
+ * Class: InvalidDataError
+ * Exception that will be thrown, if a object with invalid data (e.g. urlname in this form not allowed) should have been saved / created.
+ * Unless something else is said at a function, the exception message is a translation key.
+ */
+class InvalidDataError extends Exception { }
+
abstract class BySQLRowEnabled
{
protected function __construct() { }
@@ -89,6 +96,101 @@ abstract class BySQLRowEnabled
}
/*
+ * Class: KVStorage
+ * An abstract class for a KVStorage.
+ *
+ * See also:
+ * <PluginKVStorage>, <ArticleExtradata>
+ */
+abstract class KVStorage implements Countable, ArrayAccess, Iterator
+{
+ private $keybuffer;
+ private $counter;
+ private $prepared_queries;
+ private $silent_mode;
+
+ final protected function init($sqltable, $common_fields)
+ {
+ $this->silent_mode = False;
+ $this->keybuffer = array();
+
+ $selector = "WHERE " . (empty($common_fields) ? 1 : implode(" AND ", array_map(function($x) { return qdb_fmt("`{$x[0]}` = {$x[1]}", $x[2]); }, $common_fields)));
+ $this->prepared_queries = array(
+ "get" => "SELECT `value` FROM `$sqltable` $selector AND `key` = '%s'",
+ "unset" => "DELETE FROM `$sqltable` $selector AND `key` = '%s'",
+ "update" => "UPDATE `$sqltable` SET `value` = '%s' $selector AND `key` = '%s'",
+ "create" => "INSERT INTO `$sqltable` (`key`, `value` "
+ . (empty($common_fields) ?: ", " . implode(", ", array_map(function($x) { return "`".$x[0]."`"; }, $common_fields)))
+ . ") VALUES ('%s', '%s'"
+ . (empty($common_fields) ?: ", " . implode(", ", array_map(function($x) { return qdb_fmt($x[1], $x[2]); }, $common_fields)))
+ . ")"
+ );
+
+ $result = qdb("SELECT `key` FROM `$sqltable` $selector");
+ while($sqlrow = mysql_fetch_assoc($result))
+ $this->keybuffer[] = $sqlrow["key"];
+
+ $this->counter = 0;
+ }
+
+ /*
+ * Functions: Silent mode
+ * If the silent mode is enabled, the KVStorage behaves even more like a PHP array, i.e. it just returns NULL,
+ * if a unknown key was requested and does not throw an DoesNotExistError Exception.
+ *
+ * enable_silent_mode - Enable the silent mode.
+ * disable_silent_mode - Disable the silent mode (default).
+ */
+ final public function enable_silent_mode() { $this->silent_mode = True; }
+ final public function disable_silent_mode() { $this->silent_mode = False; }
+
+ /* Countable interface implementation */
+ final public function count() { return count($this->keybuffer); }
+
+ /* ArrayAccess interface implementation */
+ final public function offsetExists($offset) { return in_array($offset, $this->keybuffer); }
+ final public function offsetGet($offset)
+ {
+ if($this->offsetExists($offset))
+ {
+ $result = qdb($this->prepared_queries["get"], $offset);
+ $sqlrow = mysql_fetch_assoc($result);
+ return unserialize(base64_decode($sqlrow["value"]));
+ }
+ elseif($this->silent_mode)
+ return NULL;
+ else
+ throw new DoesNotExistError();
+ }
+ final public function offsetUnset($offset)
+ {
+ if($this->offsetExists($offset))
+ {
+ unset($this->keybuffer[array_search($offset, $this->keybuffer)]);
+ $this->keybuffer = array_merge($this->keybuffer);
+ qdb($this->prepared_queries["unset"], $offset);
+ }
+ }
+ final public function offsetSet($offset, $value)
+ {
+ if($this->offsetExists($offset))
+ qdb($this->prepared_queries["update"], base64_encode(serialize($value)), $offset);
+ else
+ {
+ qdb($this->prepared_queries["create"], $offset, base64_encode(serialize($value)));
+ $this->keybuffer[] = $offset;
+ }
+ }
+
+ /* Iterator interface implementation */
+ final public function rewind() { return $this->counter = 0; }
+ final public function current() { return $this->offsetGet($this->keybuffer[$this->counter]); }
+ final public function key() { return $this->keybuffer[$this->counter]; }
+ final public function next() { ++$this->counter; }
+ final public function valid() { return isset($this->keybuffer[$this->counter]); }
+}
+
+/*
* Class: User
* Data model for Users
*/
@@ -771,13 +873,11 @@ $ratatoeskr_settings = Settings::get_instance();
* A Key-Value-Storage for Plugins
* Can be accessed like an array.
* Keys are strings and Values can be everything serialize() can process.
+ *
+ * Extends the abstract <KVStorage> class.
*/
-class PluginKVStorage implements Countable, ArrayAccess, Iterator
+class PluginKVStorage extends KVStorage
{
- private $plugin_id;
- private $keybuffer;
- private $counter;
-
/*
* Constructor: __construct
*
@@ -786,60 +886,10 @@ class PluginKVStorage implements Countable, ArrayAccess, Iterator
*/
public function __construct($plugin_id)
{
- $this->keybuffer = array();
- $this->plugin_id = $plugin_id;
-
- $result = qdb("SELECT `key` FROM `PREFIX_plugin_kvstorage` WHERE `plugin` = %d", $plugin_id);
- while($sqlrow = mysql_fetch_assoc($result))
- $this->keybuffer[] = $sqlrow["key"];
-
- $this->counter = 0;
- }
-
- /* Countable interface implementation */
- public function count() { return count($this->keybuffer); }
-
- /* ArrayAccess interface implementation */
- public function offsetExists($offset) { return in_array($offset, $this->keybuffer); }
- public function offsetGet($offset)
- {
- if($this->offsetExists($offset))
- {
- $result = qdb("SELECT `value` FROM `PREFIX_plugin_kvstorage` WHERE `key` = '%s' AND `plugin` = %d", $offset, $this->plugin_id);
- $sqlrow = mysql_fetch_assoc($result);
- return unserialize(base64_decode($sqlrow["value"]));
- }
- else
- throw new DoesNotExistError();
- }
- public function offsetUnset($offset)
- {
- if($this->offsetExists($offset))
- {
- unset($this->keybuffer[array_search($offset, $this->keybuffer)]);
- $this->keybuffer = array_merge($this->keybuffer);
- qdb("DELETE FROM `PREFIX_plugin_kvstorage` WHERE `key` = '%s' AND `plugin` = %d", $offset, $this->plugin_id);
- }
- }
- public function offsetSet($offset, $value)
- {
- if($this->offsetExists($offset))
- qdb("UPDATE `PREFIX_plugin_kvstorage` SET `value` = '%s' WHERE `key` = '%s' AND `plugin` = %d",
- base64_encode(serialize($value)), $offset, $this->plugin_id);
- else
- {
- qdb("INSERT INTO `PREFIX_plugin_kvstorage` (`plugin`, `key`, `value`) VALUES (%d, '%s', '%s')",
- $this->plugin_id, $offset, base64_encode(serialize($value)));
- $this->keybuffer[] = $offset;
- }
+ $this->init("PREFIX_plugin_kvstorage", array(
+ array("plugin", "%d", $plugin_id)
+ ));
}
-
- /* Iterator interface implementation */
- function rewind() { return $this->position = 0; }
- function current() { return $this->offsetGet($this->keybuffer[$this->position]); }
- function key() { return $this->keybuffer[$this->position]; }
- function next() { ++$this->position; }
- function valid() { return isset($this->keybuffer[$this->position]); }
}
/*
@@ -1080,6 +1130,21 @@ class Style extends BySQLRowEnabled
}
/*
+ * Function: test_name
+ * Test, if a name is a valid Style name.
+ *
+ * Parameters:
+ * $name - The name to test
+ *
+ * Returns:
+ * True, if the name is a valid style name, False if not.
+ */
+ public static function test_name($name)
+ {
+ return preg_match("/^[a-zA-Z0-9\\-_\\.]+$/", $name) == 1;
+ }
+
+ /*
* Function: get_id
*/
public function get_id() { return $this->id; }
@@ -1096,6 +1161,9 @@ class Style extends BySQLRowEnabled
*/
public static function create($name)
{
+ if(!self::test_name($name))
+ throw new InvalidDataError("invalid_style_name");
+
try
{
self::by_name($name);
@@ -1181,6 +1249,9 @@ class Style extends BySQLRowEnabled
*/
public function save()
{
+ if(!self::test_name($name))
+ throw new InvalidDataError("invalid_style_name");
+
$result = qdb("SELECT COUNT(*) AS `n` FROM `PREFIX_styles` WHERE `name` = '%s' AND `id` != %d", $this->name, $this->id);
$sqlrow = mysql_fetch_assoc($result);
if($sqlrow["n"] > 0)
@@ -1372,6 +1443,7 @@ class Plugin extends BySQLRowEnabled
{
qdb("DELETE FROM `PREFIX_plugins` WHERE `id` = %d", $this->id);
qdb("DELETE FROM `PREFIX_plugin_kvstorage` WHERE `plugin` = %d", $this->id);
+ qdb("DELETE FROM `PREFIX_article_extradata` WHERE `plugin` = %d", $this->id);
if(is_dir(SITE_BASE_PATH . "/ratatoeskr/plugin_extradata/private/" . $this->id))
delete_directory(SITE_BASE_PATH . "/ratatoeskr/plugin_extradata/private/" . $this->id);
if(is_dir(SITE_BASE_PATH . "/ratatoeskr/plugin_extradata/public/" . $this->id))
@@ -1421,6 +1493,21 @@ class Section extends BySQLRowEnabled
}
/*
+ * Function: test_name
+ * Tests, if a name is a valid section name.
+ *
+ * Parameters:
+ * $name - The name to test.
+ *
+ * Returns:
+ * True, if the name is a valid section name, False otherwise.
+ */
+ public static function test_name($name)
+ {
+ return preg_match("/^[a-zA-Z0-9\\-_]+$/", $name) != 0;
+ }
+
+ /*
* Function: get_id
*/
public function get_id() { return $this->id; }
@@ -1433,10 +1520,13 @@ class Section extends BySQLRowEnabled
* $name - The name of the new section.
*
* Throws:
- * <AlreadyExistsError>
+ * <AlreadyExistsError>, <InvalidDataError>
*/
public static function create($name)
{
+ if(!self::test_name($name))
+ throw new InvalidDataError("invalid_section_name");
+
try
{
$obj = self::by_name($name);
@@ -1568,10 +1658,13 @@ class Section extends BySQLRowEnabled
* Function: save
*
* Throws:
- * <AlreadyExistsError>
+ * <AlreadyExistsError>, <InvalidDataError>
*/
public function save()
{
+ if(!self::test_name($name))
+ throw new InvalidDataError("invalid_section_name");
+
$result = qdb("SELECT COUNT(*) AS `n` FROM `PREFIX_sections` WHERE `name` = '%s' AND `id` != %d", $this->name, $this->id);
$sqlrow = mysql_fetch_assoc($result);
if($sqlrow["n"] > 0)
@@ -1627,6 +1720,21 @@ class Tag extends BySQLRowEnabled
public $title;
/*
+ * Function: test_name
+ * Test, if a name is a valid tag name.
+ *
+ * Parameters:
+ * $name - Name to test.
+ *
+ * Returns:
+ * True, if the name is valid, False otherwise.
+ */
+ public static function test_name($name)
+ {
+ return (strpos($name, ",") === False) and (strpos($name, " ") === False);
+ }
+
+ /*
* Function: get_id
*/
public function get_id() { return $this->id; }
@@ -1646,10 +1754,13 @@ class Tag extends BySQLRowEnabled
* $name - The name
*
* Throws:
- * <AlreadyExistsError>
+ * <AlreadyExistsError>, <InvalidDataError>
*/
public static function create($name)
{
+ if(!self::test_name($name))
+ throw new InvalidDataError("invalid_tag_name");
+
try
{
$obj = self::by_name($name);
@@ -1763,10 +1874,13 @@ WHERE `b`.`tag` = '%d'" , $this->id);
* Function: save
*
* Throws:
- * <AlreadyExistsError>
+ * <AlreadyExistsError>, <InvalidDataError>
*/
public function save()
{
+ if(!self::test_name($name))
+ throw new InvalidDataError("invalid_tag_name");
+
$result = qdb("SELECT COUNT(*) AS `n` FROM `PREFIX_tags` WHERE `name` = '%s' AND `id` != %d", $this->name, $this->id);
$sqlrow = mysql_fetch_assoc($result);
if($sqlrow["n"] > 0)
@@ -2286,6 +2400,36 @@ class Article extends BySQLRowEnabled
public function get_id() { return $this->id; }
/*
+ * Function: test_urlname
+ * Test, if a urlname is a valid urlname.
+ *
+ * Parameters:
+ * $urlname - Urlname to test
+ *
+ * Returns:
+ * True, if the urlname is valid, False otherwise.
+ */
+ public static function test_urlname($urlname)
+ {
+ return (bool) preg_match('/^[a-zA-Z0-9-_]+$/', $urlname);
+ }
+
+ /*
+ * Function: test_status
+ * Test, if a status is valid.
+ *
+ * Parameters:
+ * $status - Status value to test.
+ *
+ * Returns:
+ * True, if the status is a valid status value, False otherwise.
+ */
+ public static function test_status($status)
+ {
+ return is_numeric($status) and ($status >= 0) and ($status <= 3);
+ }
+
+ /*
* Constructor: create
* Create a new Article object.
*
@@ -2293,12 +2437,15 @@ class Article extends BySQLRowEnabled
* urlname - A unique URL name
*
* Throws:
- * <AlreadyExistsError>
+ * <AlreadyExistsError>, <InvalidDataError>
*/
public static function create($urlname)
{
global $ratatoeskr_settings;
+ if(!self::test_urlname($urlname))
+ throw new InvalidDataError("invalid_urlname");
+
try
{
self::by_urlname($urlname);
@@ -2562,10 +2709,34 @@ WHERE " . implode(" AND ", $subqueries) . " $sorting");
}
/*
+ * Function: get_extradata
+ * Get the extradata for this article and the given plugin.
+ *
+ * Parameters:
+ * $plugin_id - The ID of the plugin.
+ *
+ * Returns:
+ * An <ArticleExtradata> object.
+ */
+ public function get_extradata($plugin_id)
+ {
+ return new ArticleExtradata($this->id, $plugin_id);
+ }
+
+ /*
* Function: save
+ *
+ * Throws:
+ * <AlreadyExistsError>, <InvalidDataError>
*/
public function save()
{
+ if(!self::test_urlname($this->urlname))
+ throw new InvalidDataError("invalid_urlname");
+
+ if(!self::test_status($this->status))
+ throw new InvalidDataError("invalid_article_status");
+
$result = qdb("SELECT COUNT(*) AS `n` FROM `PREFIX_articles` WHERE `urlname` = '%s' AND `id` != %d", $this->urlname, $this->id);
$sqlrow = mysql_fetch_assoc($result);
if($sqlrow["n"] > 0)
@@ -2604,11 +2775,57 @@ WHERE " . implode(" AND ", $subqueries) . " $sorting");
$comment->delete();
qdb("DELETE FROM `PREFIX_article_tag_relations` WHERE `article` = %d", $this->id);
+ qdb("DELETE FROM `PREFIX_article_extradata` WHERE `article` = %d", $this->id);
qdb("DELETE FROM `PREFIX_articles` WHERE `id` = %d", $this->id);
}
}
/*
+ * Class: ArticleExtradata
+ * A Key-Value-Storage assigned to Articles for plugins to store additional data.
+ * Can be accessed like an array.
+ * Keys are strings and Values can be everything serialize() can process.
+ *
+ * Extends the abstract <KVStorage> class.
+ */
+class ArticleExtradata extends KVStorage
+{
+ /*
+ * Constructor: __construct
+ *
+ * Parameters:
+ * $article_id - The ID of the Article.
+ * $plugin_id - The ID of the Plugin.
+ */
+ public function __construct($article_id, $plugin_id)
+ {
+ $this->init("PREFIX_article_extradata", array(
+ array("article", "%d", $article_id),
+ array("plugin", "%d", $plugin_id)
+ ));
+ }
+}
+
+/*
+ * Function: dbversion
+ * Get the version of the database structure currently used.
+ *
+ * Returns:
+ * The numerical version of the current database structure.
+ */
+function dbversion()
+{
+ /* Is the meta table present? If no, the version is 0. */
+ $result = qdb("SHOW TABLES LIKE 'PREFIX_meta'");
+ if(mysql_num_rows($result) == 0)
+ return 0;
+
+ $result = qdb("SELECT `value` FROM `PREFIX_meta` WHERE `key` = 'dbversion'");
+ $sqlrow = mysql_fetch_assoc($result);
+ return unserialize(base64_decode($sqlrow["value"]));
+}
+
+/*
* Function: clean_database
* Clean up the database
*/
diff --git a/ratatoeskr/sys/plugin_api.php b/ratatoeskr/sys/plugin_api.php
index f6d1c2d..cd3e42b 100644
--- a/ratatoeskr/sys/plugin_api.php
+++ b/ratatoeskr/sys/plugin_api.php
@@ -15,17 +15,18 @@ require_once(dirname(__FILE__) . "/../frontend.php");
/*
* Constant: APIVERSION
- * The current API version (5).
+ * The current API version (6).
*/
-define("APIVERSION", 5);
+define("APIVERSION", 6);
/*
* Array: $api_compat
* Array of API versions, this version is compatible to (including itself).
*/
-$api_compat = array(3, 4, 5);
+$api_compat = array(3, 4, 5, 6);
+
+$url_handlers = array(); /* master URL handler */
-$url_handlers = array();
/*
* Function: register_url_handler
* Register an URL handler. See <ratatoeskr/sys/urlprocess.php> for more details.
@@ -42,6 +43,8 @@ function register_url_handler($name, $callback)
$pluginpages_handlers = array();
+$articleeditor_plugins = array();
+
/*
* Class: RatatoeskrPlugin
* An abstract class to be extended in order to write your own Plugin.
@@ -93,7 +96,7 @@ abstract class RatatoeskrPlugin
final protected function get_custompub_dir() { return SITE_BASE_PATH . "/ratatoeskr/plugin_extradata/public/" . $this->id; }
final protected function get_custompub_url() { return $GLOBALS["rel_path_to_root"] . "/ratatoeskr/plugin_extradata/public/" . $this->id; }
final protected function get_template_dir() { return "/plugintemplates/" . $this->id; }
-
+
/*
* Function: register_url_handler
* Register a URL handler
@@ -194,6 +197,33 @@ abstract class RatatoeskrPlugin
}
/*
+ * Function: register_articleeditor_plugin
+ * Register a plugin for the article editor in the backend.
+ *
+ * Parameters:
+ * $label - The label for the plugin.
+ * $fx - A function that will be called during the articleeditor.
+ * This function must accept these parameters:
+ * * $article - An <Article> object or NULL, if no Article is edited right now.
+ * * $about_to_save - If True, the article is about to be saved.
+ * If you want to veto the saving, return the rejection reason as a string.
+ * If everything is okay and you need to save additional data, return a callback function that accepts the saved <Article> object (that callback should also write data back to the template, if necessary).
+ * If everything is okay and you do not need to save additional data, return NULL.
+ * $template - The name of the template to display in the editor, relative to your template directory. If you do not want to display anything, you can set ths to NULL.
+ */
+ final protected function register_articleeditor_plugin($label, $fx, $template)
+ {
+ global $articleeditor_plugins;
+
+ $articleeditor_plugins[] = array(
+ "label" => $label,
+ "fx" => $fx,
+ "template" => $this->get_template_dir() . "/" . $template,
+ "display" => $template != NULL
+ );
+ }
+
+ /*
* Function: get_backend_pluginpage_url
* Get the URL to your backend plugin page.
*
@@ -207,6 +237,21 @@ abstract class RatatoeskrPlugin
}
/*
+ * Function: get_article_extradata
+ * Get the <ArticleExtradata> object for this plugin and the given article.
+ *
+ * Parameters:
+ * $article - An <Article> object.
+ *
+ * Returns:
+ * An <ArticleExtradata> object for this plugin and the given article.
+ */
+ final protected function get_article_extradata($article)
+ {
+ return new ArticleExtradata($article->get_id(), $this->id);
+ }
+
+ /*
* Function: prepare_backend_pluginpage
* Automatically sets the page title and highlights the menu-entry of your backend subpage.
*/
diff --git a/ratatoeskr/templates/src/systemtemplates/areyousure.html b/ratatoeskr/templates/src/systemtemplates/areyousure.html
deleted file mode 100644
index 0d40585..0000000
--- a/ratatoeskr/templates/src/systemtemplates/areyousure.html
+++ /dev/null
@@ -1,11 +0,0 @@
-<ste:load name="master.html" />
-<ste:block name="content">
- <div class="pos_center">
- <h2><ste:escape>$question</ste:escape></h2>
- ?{$moredetails|<p><ste:escape>$moredetails</ste:escape></p>|}
- <form action="$callback" method="post">
- <input type="submit" class="yes_btn" name="yes" value="<ste:escape>?{$yestext|$yestext|<ste:get_translation for='yes' raw='y' />}</ste:escape>" />
- <input type="submit" class="no_btn" name="no" value="<ste:escape>?{$notext|$notext|<ste:get_translation for='no' raw='y' />}</ste:escape>" />
- </form>
- </div>
-</ste:block>
diff --git a/ratatoeskr/templates/src/systemtemplates/content_write.html b/ratatoeskr/templates/src/systemtemplates/content_write.html
index 82c86c4..08d6ec1 100644
--- a/ratatoeskr/templates/src/systemtemplates/content_write.html
+++ b/ratatoeskr/templates/src/systemtemplates/content_write.html
@@ -26,29 +26,41 @@
</div>
<div class="column_right">
- <h2><ste:get_translation for="settings_meta" /></h2>
+ <div class="articleeditor-metabar-element">
+ <h2><ste:get_translation for="settings_meta" /></h2>
+ <div class="articleeditor-metabar-element-content">
+ <p><ste:get_translation for="urlname" />: <input type="text" name="urlname" value="<ste:escape>$urlname</ste:escape>" class="fullwidth" /></p>
+ <p>
+ <ste:get_translation for="article_section" />:
+ <select name="section" class="fullwidth">
+ <ste:foreach array="sections" value="section_name">
+ <option value="<ste:escape>$section_name</ste:escape>"?{~{$section_name|eq|$article_section}| selected="selected"|}><ste:escape>$section_name</ste:escape></option>
+ </ste:foreach>
+ </select>
+ </p>
+ <p><ste:get_translation for="tags_cs" />: <input type="text" name="tags" value="<ste:escape>$tags</ste:escape>" class="fullwidth" /></p>
+ <p><ste:get_translation for="date_time" />:<br />(YYYY-MM-DD HH:MM:SS) <input type="text" name="date"?{$date| value="<ste:date timestamp='$date'>%Y-%m-%d %H:%M:%S</ste:date>"|} class="fullwidth" /></p>
+ <p>
+ <ste:get_translation for="article_status" />:
+ <ste:set var="article_status">?{$article_status|$article_status|1}</ste:set>
+ <select name="article_status" class="fullwidth">
+ <option value="0"?{~{$article_status|eq|0}| selected="selected"|}><ste:get_translation for="article_status_hidden" /></option>
+ <option value="1"?{~{$article_status|eq|1}| selected="selected"|}><ste:get_translation for="article_status_live" /></option>
+ <option value="2"?{~{$article_status|eq|2}| selected="selected"|}><ste:get_translation for="article_status_sticky" /></option>
+ </select>
+ </p>
+ <p><ste:get_translation for="allow_comments" />: <input type="checkbox" name="allow_comments" value="yes" ?{$allow_comments|checked="checked" |}/></p>
+ </div>
+ </div>
- <p><ste:get_translation for="urlname" />: <input type="text" name="urlname" value="<ste:escape>$urlname</ste:escape>" class="fullwidth" /></p>
- <p>
- <ste:get_translation for="article_section" />:
- <select name="section" class="fullwidth">
- <ste:foreach array="sections" value="section_name">
- <option value="<ste:escape>$section_name</ste:escape>"?{~{$section_name|eq|$article_section}| selected="selected"|}><ste:escape>$section_name</ste:escape></option>
- </ste:foreach>
- </select>
- </p>
- <p><ste:get_translation for="tags_cs" />: <input type="text" name="tags" value="<ste:escape>$tags</ste:escape>" class="fullwidth" /></p>
- <p><ste:get_translation for="date_time" />:<br />(YYYY-MM-DD HH:MM:SS) <input type="text" name="date"?{$date| value="<ste:date timestamp='$date'>%Y-%m-%d %H:%M:%S</ste:date>"|} class="fullwidth" /></p>
- <p>
- <ste:get_translation for="article_status" />:
- <ste:set var="article_status">?{$article_status|$article_status|1}</ste:set>
- <select name="article_status" class="fullwidth">
- <option value="0"?{~{$article_status|eq|0}| selected="selected"|}><ste:get_translation for="article_status_hidden" /></option>
- <option value="1"?{~{$article_status|eq|1}| selected="selected"|}><ste:get_translation for="article_status_live" /></option>
- <option value="2"?{~{$article_status|eq|2}| selected="selected"|}><ste:get_translation for="article_status_sticky" /></option>
- </select>
- </p>
- <p><ste:get_translation for="allow_comments" />: <input type="checkbox" name="allow_comments" value="yes" ?{$allow_comments|checked="checked" |}/></p>
+ <ste:foreach array="displayed_plugins" value="plugin">
+ <div class="articleeditor-metabar-element">
+ <h2><ste:escape>$plugin[label]</ste:escape></h2>
+ <div class="articleeditor-metabar-element-content">
+ <ste:load name="$plugin[template]" />
+ </div>
+ </div>
+ </ste:foreach>
</div>
<div class="column_main">
diff --git a/ratatoeskr/templates/src/systemtemplates/image_list.html b/ratatoeskr/templates/src/systemtemplates/image_list.html
index 7b40ddc..fe600aa 100644
--- a/ratatoeskr/templates/src/systemtemplates/image_list.html
+++ b/ratatoeskr/templates/src/systemtemplates/image_list.html
@@ -47,11 +47,7 @@
</tbody>
</table>
<div>
- <input type="submit" name="delete" value="<ste:get_translation for='delete' />" />
- <select name="really_delete">
- <option value="no" selected="selected"><ste:get_translation for="no" /></option>
- <option value="yes"><ste:get_translation for="yes" /></option>
- </select>
+ <ste:default_delete_yesno />
</div>
</form>
</div>
diff --git a/ratatoeskr/templates/src/systemtemplates/master.html b/ratatoeskr/templates/src/systemtemplates/master.html
index ddf6d08..bce92b1 100755
--- a/ratatoeskr/templates/src/systemtemplates/master.html
+++ b/ratatoeskr/templates/src/systemtemplates/master.html
@@ -19,12 +19,21 @@
</ste:then>
</ste:if>
</ste:mktag>
+<ste:mktag name="default_delete_yesno">
+ <input type="submit" name="?{$_tag_parameters[name]|$_tag_parameters[name]|delete}" value="<ste:get_translation for='delete' />" />
+ <select name="really_delete">
+ <option value="no" selected="selected"><ste:get_translation for="no" /></option>
+ <option value="yes"><ste:get_translation for="yes" /></option>
+ </select>
+</ste:mktag>
<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">
<html xmlns="http://www.w3.org/1999/xhtml">
<head>
<meta http-equiv="Content-Type" content="text/html; charset=utf-8" />
<meta http-equiv="Content-Style-Type" content="text/css" />
<title><ste:get_translation for="section_$section" />::<ste:escape>$pagetitle</ste:escape> - Ratatöskr</title>
+ <script type="text/javascript" src="$rel_path_to_root/ratatoeskr/libs/jquery.min.js"></script>
+ <script type="text/javascript" src="$rel_path_to_root/ratatoeskr/js/backend.js"></script>
<ste:mktag name="cms_style"><link rel="stylesheet" type="text/css" media="screen" href="$rel_path_to_root/ratatoeskr/cms_style/<ste:tagcontent />" /></ste:mktag>
<ste:cms_style>layout.css</ste:cms_style>
<ste:foreach array="additional_styles" value="cssfile"><ste:cms_style>$cssfile</ste:cms_style></ste:foreach>
diff --git a/ratatoeskr/templates/src/systemtemplates/repos.html b/ratatoeskr/templates/src/systemtemplates/repos.html
index f724ece..31de6a5 100644
--- a/ratatoeskr/templates/src/systemtemplates/repos.html
+++ b/ratatoeskr/templates/src/systemtemplates/repos.html
@@ -45,11 +45,7 @@
</tbody>
</table>
<div>
- <input type="submit" name="delete_repos" value="<ste:get_translation for='delete' />" />
- <select name="really_delete">
- <option value="no" selected="selected"><ste:get_translation for="no" /></option>
- <option value="yes"><ste:get_translation for="yes" /></option>
- </select>
+ <ste:default_delete_yesno name="delete_repos" />
|
<input type="submit" name="force_repo_refresh" value="<ste:get_translation for='force_repo_refresh' />" />
</div>
diff --git a/ratatoeskr/templates/src/systemtemplates/sections.html b/ratatoeskr/templates/src/systemtemplates/sections.html
index b67563d..7ac3241 100644
--- a/ratatoeskr/templates/src/systemtemplates/sections.html
+++ b/ratatoeskr/templates/src/systemtemplates/sections.html
@@ -56,10 +56,7 @@
</tbody>
</table>
<div>
- <input type="submit" name="delete" value="<ste:get_translation for='delete' />" />&nbsp;<select name="really_delete">
- <option value="no" selected="selected"><ste:get_translation for="no" /></option>
- <option value="yes"><ste:get_translation for="yes" /></option>
- </select>
+ <ste:default_delete_yesno />
|
<input type="submit" name="make_default" value="<ste:get_translation for='make_default' />" />
|
diff --git a/ratatoeskr/templates/src/systemtemplates/settings.html b/ratatoeskr/templates/src/systemtemplates/settings.html
index b7fee48..31021fe 100644
--- a/ratatoeskr/templates/src/systemtemplates/settings.html
+++ b/ratatoeskr/templates/src/systemtemplates/settings.html
@@ -38,7 +38,7 @@
</tbody>
</table>
<div>
- <input type="submit" name="delete" value="<ste:get_translation for='delete' />" />&nbsp;<select name="really_delete"><option value="no" selected="selected"><ste:get_translation for="no" /></option><option value="yes"><ste:get_translation for="yes" /></option></select>
+ <ste:default_delete_yesno />
|
<input type="submit" name="make_default" value="<ste:get_translation for='make_default' />" />
|
diff --git a/ratatoeskr/templates/src/systemtemplates/styles.html b/ratatoeskr/templates/src/systemtemplates/styles.html
index 71464fb..30c4277 100644
--- a/ratatoeskr/templates/src/systemtemplates/styles.html
+++ b/ratatoeskr/templates/src/systemtemplates/styles.html
@@ -27,11 +27,7 @@
</tbody>
</table>
<div>
- <input type="submit" name="delete" value="<ste:get_translation for='delete' />" />
- <select name="really_delete">
- <option value="no" selected="selected"><ste:get_translation for="no" /></option>
- <option value="yes"><ste:get_translation for="yes" /></option>
- </select>
+ <ste:default_delete_yesno />
</div>
</form>
<hr />
diff --git a/ratatoeskr/templates/src/systemtemplates/tags_overview.html b/ratatoeskr/templates/src/systemtemplates/tags_overview.html
index 1f5b8d5..e82fd61 100644
--- a/ratatoeskr/templates/src/systemtemplates/tags_overview.html
+++ b/ratatoeskr/templates/src/systemtemplates/tags_overview.html
@@ -7,41 +7,52 @@
<table class="listtab">
<thead>
<tr>
+ <th>&nbsp;</th>
<th><ste:get_translation for="tag_name" /></th>
- <th><ste:get_translation for="delete" /></th>
<ste:foreach array="all_tag_langs" key="langcode" value="langname">
<th>($langcode) <ste:escape>$langname</ste:escape></th>
</ste:foreach>
- <th><ste:get_translation for="tag_add_lang" /></th>
+ <th>
+ <select name="new_language">
+ <option value="" selected="selected"><ste:get_translation for="tag_add_lang" /></option>
+ <ste:foreach array="unused_languages" key="langcode" value="langname">
+ <option value="$langcode">$langcode: <ste:escape>$langname</ste:escape></option>
+ </ste:foreach>
+ </select>
+ </th>
</tr>
</thead>
<tbody>
<ste:foreach array="alltags" value="tagdata">
<tr>
- <td>$tagdata[name]</td>
- <td>
- <a href="$rel_path_to_root/backend/content/tags/$tagdata[name]/delete"><img src="$rel_path_to_root/ratatoeskr/cms_style/images/delete.png" alt="<ste:get_translation for='delete' />" /></a>
- </td>
+ <td><input type="checkbox" name="tag_multiselect[]" value="$tagdata[id]" /></td>
+ <td><ste:escape>$tagdata[name]</ste:escape></td>
<ste:foreach array="all_tag_langs" key="langcode" value="_">
<td>
- <input type="text" name="tagtrans_${langcode}_${tagdata[name]}" value="<ste:escape>$tagdata[translations][$langcode]</ste:escape>" />
+ <input type="text" name="tagtrans_${langcode}_${tagdata[id]}" value="<ste:escape>$tagdata[translations][$langcode]</ste:escape>" />
</td>
</ste:foreach>
<td>
- <a href="$rel_path_to_root/backend/content/tags/$tagdata[name]/addtranslation"><img src="$rel_path_to_root/ratatoeskr/cms_style/images/add.png" alt="<ste:get_translation for='tag_add_lang' />" /></a>
+ <input type="text" name="tagtrans_NEW_${tagdata[id]}" />
</td>
</tr>
</ste:foreach>
+ <tr>
+ <td>&nbsp;</td>
+ <td><input type="text" name="newtagname" /></td>
+ <ste:foreach array="all_tag_langs" key="langcode" value="_">
+ <td>
+ <input type="text" name="tagtrans_${langcode}_NEW" />
+ </td>
+ </ste:foreach>
+ <td>
+ <input type="text" name="tagtrans_NEW_NEW" />
+ </td>
+ </tr>
</tbody>
</table>
- <div><input type="submit" name="edit_translations" /></div>
+ <div>
+ <ste:default_delete_yesno /> | <input type="submit" name="save_changes" value="<ste:get_translation for='save_changes' />">
+ </div>
</form>
-
- <div>
- <h2><ste:get_translation for="create_new_tag" /></h2>
- <form action="$rel_path_to_root/backend/content/tags" method="post" accept-charset="UTF-8">
- <p><ste:get_translation for="new_tag_name" />: <input type="text" name="new_tag_name" /></p>
- <p><input type="submit" name="create_new_tag" /></p>
- </form>
- </div>
</ste:block>
diff --git a/ratatoeskr/templates/src/systemtemplates/templates.html b/ratatoeskr/templates/src/systemtemplates/templates.html
index eca33cf..1a33e31 100644
--- a/ratatoeskr/templates/src/systemtemplates/templates.html
+++ b/ratatoeskr/templates/src/systemtemplates/templates.html
@@ -27,11 +27,7 @@
</tbody>
</table>
<div>
- <input type="submit" name="delete" value="<ste:get_translation for='delete' />" />
- <select name="really_delete">
- <option value="no" selected="selected"><ste:get_translation for="no" /></option>
- <option value="yes"><ste:get_translation for="yes" /></option>
- </select>
+ <ste:default_delete_yesno />
</div>
</form>
</div>
diff --git a/ratatoeskr/templates/src/systemtemplates/users.html b/ratatoeskr/templates/src/systemtemplates/users.html
index d9542a2..255759a 100644
--- a/ratatoeskr/templates/src/systemtemplates/users.html
+++ b/ratatoeskr/templates/src/systemtemplates/users.html
@@ -39,7 +39,7 @@
</tbody>
</table>
<div>
- <input type="submit" name="delete_groups" value="<ste:get_translation for='delete' />" /><select name="really_delete"><option value="no" selected="selected"><ste:get_translation for="no" /></option><option value="yes"><ste:get_translation for="yes" /></option></select>
+ <ste:default_delete_yesno name="delete_groups" />
</div>
</form>
@@ -72,7 +72,7 @@
</tbody>
</table>
<div>
- <input type="submit" name="delete_users" value="<ste:get_translation for='delete' />" /><select name="really_delete"><option value="no" selected="selected"><ste:get_translation for="no" /></option><option value="yes"><ste:get_translation for="yes" /></option></select>
+ <ste:default_delete_yesno name="delete_users" />
</div>
</form>
</div>
diff --git a/ratatoeskr/templates/src/usertemplates/standard.html b/ratatoeskr/templates/src/usertemplates/standard.html
index c4d1eb9..ef78001 100644
--- a/ratatoeskr/templates/src/usertemplates/standard.html
+++ b/ratatoeskr/templates/src/usertemplates/standard.html
@@ -1,72 +1,56 @@
<ste:load name="master.html" />
<ste:block name="content">
- <ste:if>
- $current[section]
- <ste:then>
- <ste:articles_get var="article" section="$current[section][name]" sort="timestamp desc" perpage="10" page="$current[page]" maxpage="maxpage">
- <div class="article_short">
- <h2>$article[title]</h2>
- $article[excerpt]
- <div class="readmore_link"><a href="<ste:escape>$article[fullurl]</ste:escape>"><ste:get_translation for="read_more" /></a></div>
- </div class="article_short">
- </ste:articles_get>
- <ste:page_prev current="$current[page]" maxpage="$maxpage" default="y" />
- <ste:page_next current="$current[page]" maxpage="$maxpage" default="y" />
- </ste:then>
- </ste:if>
+ <ste:on_section var="section">
+ <ste:articles_get var="article" sectionvar="section" sort="timestamp desc" perpage="10" page="$current[page]" maxpage="maxpage">
+ <div class="article_short">
+ <h2>$article[title]</h2>
+ $article[excerpt]
+ <div class="readmore_link"><a href="<ste:escape>$article[fullurl]</ste:escape>"><ste:get_translation for="read_more" /></a></div>
+ </div class="article_short">
+ </ste:articles_get>
+ <ste:page_prev current="$current[page]" maxpage="$maxpage" default="y" />
+ <ste:page_next current="$current[page]" maxpage="$maxpage" default="y" />
+ </ste:on_section>
- <ste:if>
- $current[article]
- <ste:then>
- <div class="fullarticle">
- <h2>$current[article][title]</h2>
- <div class="article_meta">Published: <ste:date timestamp="$current[article][timestamp]">%d. %h. %Y, %H:%M</ste:date></div>
- $current[article][text]<!-- $current[article][comments_allowed] -->
- <ste:if>
- $current[article][comments_allowed]
- <ste:then>
- <h3>Comments (<ste:article_comments_count article="current[article]" />)</h3>
- <ste:article_comments var="comment" article="current[article]" sort="asc">
- <div class="comment">
- <p><strong>Name</strong>: $comment[author]</p>
- <p><strong>Date</strong>: <ste:date timestamp="$comment[timestamp]">%d. %B %Y, %H:%M</ste:date></p>
- $comment[text]
- </div>
- </ste:article_comments>
- ?{$current[commented]|Comment sucessfully stored!|}
- ?{$current[comment_fail]|Comment could not be stored: $current[comment_fail]|}
- <ste:if>$current[comment_prev]
- <ste:then>
- <h3>Comment preview</h3>
- <div class="comment">$current[comment_prev]</div>
- </ste:then>
- </ste:if>
- <ste:comment_form article="current[article]">
- Name: <input type="text" name="author_name" value="$current[oldcomment][name]" /><br />
- Mail: <input type="text" name="author_mail" value="$current[oldcomment][mail]" /><br />
- Text (Markdown): <br />
- <textarea name="comment_text" cols="50" rows="10">$current[oldcomment][text]</textarea><br />
- <input type="submit" name="post_comment" value="Post" />
- <input type="submit" name="preview_comment" value="Preview" />
- </ste:comment_form>
- </ste:then>
- </ste:if>
- </div>
- </ste:then>
- </ste:if>
+ <ste:on_article var="article">
+ <div class="fullarticle">
+ <h2>$article[title]</h2>
+ <div class="article_meta">Published: <ste:date timestamp="$article[timestamp]">%d. %h. %Y, %H:%M</ste:date></div>
+ $article[text]
+ <ste:if>
+ $article[comments_allowed]
+ <ste:then>
+ <h3>Comments (<ste:article_comments_count article="article" />)</h3>
+ <ste:article_comments var="comment" article="article" sort="asc">
+ <div class="comment">
+ <p><strong>Name</strong>: $comment[author]</p>
+ <p><strong>Date</strong>: <ste:date timestamp="$comment[timestamp]">%d. %B %Y, %H:%M</ste:date></p>
+ $comment[text]
+ </div>
+ </ste:article_comments>
+ ?{$current[commented]|Comment sucessfully stored!|}
+ ?{$current[comment_fail]|Comment could not be stored: $current[comment_fail]|}
+ <ste:if>$current[comment_prev]
+ <ste:then>
+ <h3>Comment preview</h3>
+ <div class="comment">$current[comment_prev]</div>
+ </ste:then>
+ </ste:if>
+ <ste:comment_form article="article" default="y" previewbtn="y" />
+ </ste:then>
+ </ste:if>
+ </div>
+ </ste:on_article>
- <ste:if>
- $current[tag]
- <ste:then>
- <ste:articles_get var="article" tag="$current[tag][name]" sort="timestamp desc" perpage="10" page="$current[page]" maxpage="maxpage">
- <div class="article_short">
- <h2><ste:escape>$article[title]</ste:escape></h2>
- $article[excerpt]
- <div class="readmore_link"><a href="<ste:escape>$article[fullurl]</ste:escape>"><ste:get_translation for="read_more" /></a></div>
- </div class="article_short">
- </ste:articles_get>
- <ste:page_prev current="$current[page]" maxpage="$maxpage" default="y" />
- <ste:page_next current="$current[page]" maxpage="$maxpage" default="y" />
- </ste:then>
- </ste:if>
+ <ste:on_tag var="tag">
+ <ste:articles_get var="article" tagvar="tag" sort="timestamp desc" perpage="10" page="$current[page]" maxpage="maxpage">
+ <div class="article_short">
+ <h2><ste:escape>$article[title]</ste:escape></h2>
+ $article[excerpt]
+ <div class="readmore_link"><a href="<ste:escape>$article[fullurl]</ste:escape>"><ste:get_translation for="read_more" /></a></div>
+ </div class="article_short">
+ </ste:articles_get>
+ <ste:page_prev current="$current[page]" maxpage="$maxpage" default="y" />
+ <ste:page_next current="$current[page]" maxpage="$maxpage" default="y" />
+ </ste:on_tag>
</ste:block>
diff --git a/ratatoeskr/translations/de.php b/ratatoeskr/translations/de.php
index 66c68d8..f49f379 100644
--- a/ratatoeskr/translations/de.php
+++ b/ratatoeskr/translations/de.php
@@ -33,6 +33,8 @@ $translation = array(
"comment_form_name" => "Dein Name",
"comment_form_mail" => "Deine E-Mailadresse",
"comment_form_text" => "Dein Kommentar (Markdown Format)",
+ "comment_form_submit" => "Kommentar senden",
+ "comment_form_preview" => "Vorschau",
"page_prev" => "&lt;-- vorherige Seite",
"page_next" => "nächste Seite --&gt;",
"e404_details" => "Die Seite [[URL]] konte nicht gefunden werden. Das tut uns leid.",
@@ -61,25 +63,18 @@ $translation = array(
"allow_comments" => "Kommentare erlauben?",
"article_name_already_in_use" => "Artikelname bereits vergeben.",
"article_save_success" => "Artikel erfolgreich abgespeichert.",
- "delete_tag_pagetitle" => "\"[[TAGNAME]]\" löschen",
- "delete_comment_question" => "Möchtest du diesen Tag löschen?",
- "tag_deleted" => "Tag gelöscht.",
- "back_to_tags" => "Zurück zu Inhalt::Tags",
- "create_new_tag" => "Neuen Tag erstellen",
+ "tags_successfully_deleted" => "Tags erfolgreich gelöscht.",
"new_tag_name" => "Name",
+ "tags_successfully_edited" => "Tags erfolgreich bearbeitet.",
"tags_overview" => "Tag Übersicht",
"tag_name" => "Tag Name",
"yes" => "Ja",
"no" => "Nein",
"tag_add_lang" => "Übersetzung hinzufügen",
+ "save_changes" => "Änderungen speichern",
"language_unknown" => "Unbekannte Sprache",
- "no_translation_text_given" => "Kein Übersetzungstext angegeben.",
"translation_added_successfully" => "Übersetzung erfolgreich hinzufügefügt.",
- "tag_translation_added" => "Übersetzung hinzugefügt.",
"invalid_tag_name" => "Ungülter Tagname. Ein Tagname darf keine Kommas (,) oder Leerzeichen ( ) enthalten und darf nicht leer sein.",
- "tag_name_already_in_use" => "Tagname bereits vergeben.",
- "tag_created_successfully" => "Tag erfolgreich erstellt.",
- "tag_titles_edited_successfully" => "Tagtitel erfolgreich geändert.",
"available_languages" => "Verfügbare Sprachen",
"tags" => "Tags",
"section" => "Sektion",
diff --git a/ratatoeskr/translations/en.php b/ratatoeskr/translations/en.php
index 27374c6..a53617c 100644
--- a/ratatoeskr/translations/en.php
+++ b/ratatoeskr/translations/en.php
@@ -33,6 +33,8 @@ $translation = array(
"comment_form_name" => "Your name",
"comment_form_mail" => "Your E-Mailaddress",
"comment_form_text" => "Your comment (Markdown format)",
+ "comment_form_submit" => "Submit comment",
+ "comment_form_preview" => "Preview",
"page_prev" => "&lt;-- previous page",
"page_next" => "next page --&gt;",
"e404_details" => "The page [[URL]] could not be found. Sorry.",
@@ -61,25 +63,18 @@ $translation = array(
"allow_comments" => "Allow comments?",
"article_name_already_in_use" => "Article name is already in use.",
"article_save_success" => "Article successfully saved.",
- "delete_tag_pagetitle" => "Delete \"[[TAGNAME]]\"",
- "delete_comment_question" => "Do you want to delete this tag?",
- "tag_deleted" => "Tag was deleted.",
- "back_to_tags" => "Go back to Content::Tags",
- "create_new_tag" => "Create a new Tag",
+ "tags_successfully_deleted" => "Tags successfully deleted.",
"new_tag_name" => "Name",
+ "tags_successfully_edited" => "Successfully edited tags.",
"tags_overview" => "Tag Overview",
"tag_name" => "Tag name",
"yes" => "Yes",
"no" => "No",
"tag_add_lang" => "Add translation",
+ "save_changes" => "Save changes",
"language_unknown" => "Unknown language",
- "no_translation_text_given" => "No translation text given.",
"translation_added_successfully" => "Translation added successfully.",
- "tag_translation_added" => "Translation added.",
"invalid_tag_name" => "Invalid tag name. A tag name can not contain commas (,) or spaces ( ) and must not be empty.",
- "tag_name_already_in_use" => "Tag name already in use.",
- "tag_created_successfully" => "Tag created successfully.",
- "tag_titles_edited_successfully" => "Tag titles changed successfully.",
"available_languages" => "Available languages",
"tags" => "Tags",
"section" => "Section",