diff options
Diffstat (limited to 'ratatoeskr')
26 files changed, 837 insertions, 435 deletions
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 Binary files differnew file mode 100644 index 0000000..995e8cf --- /dev/null +++ b/ratatoeskr/cms_style/images/backendbg.png diff --git a/ratatoeskr/cms_style/images/expandarrow_collapsed.png b/ratatoeskr/cms_style/images/expandarrow_collapsed.png Binary files differnew file mode 100644 index 0000000..62f662b --- /dev/null +++ b/ratatoeskr/cms_style/images/expandarrow_collapsed.png diff --git a/ratatoeskr/cms_style/images/expandarrow_expanded.png b/ratatoeskr/cms_style/images/expandarrow_expanded.png Binary files differnew file mode 100644 index 0000000..a5e4c41 --- /dev/null +++ b/ratatoeskr/cms_style/images/expandarrow_expanded.png 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' />" /> <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' />" /> <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> </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> </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" => "<-- vorherige Seite", "page_next" => "nächste Seite -->", "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" => "<-- previous page", "page_next" => "next page -->", "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", |