2 // rcs_id('$Id: EditToolbar.php 7696 2010-09-20 10:20:25Z rurban $');
3 /* Copyright 2004-2010 $ThePhpWikiProgrammingTeam
4 * Copyright 2008-2009 Marc-Etienne Vargenau, Alcatel-Lucent
6 * This file is part of PhpWiki.
8 * PhpWiki is free software; you can redistribute it and/or modify
9 * it under the terms of the GNU General Public License as published by
10 * the Free Software Foundation; either version 2 of the License, or
11 * (at your option) any later version.
13 * PhpWiki is distributed in the hope that it will be useful,
14 * but WITHOUT ANY WARRANTY; without even the implied warranty of
15 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
16 * GNU General Public License for more details.
18 * You should have received a copy of the GNU General Public License along
19 * with this program; if not, write to the Free Software Foundation, Inc.,
20 * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
24 * EDIT Toolbar Initialization.
25 * The default/themes/toolbar.js is from Mediawiki, this PHP is written from scratch.
28 * - save-preview and formatting buttons from mediawiki
29 * - Search&Replace from walterzorn.de
30 * - pageinsert popup by Reini Urban (TODO: should be a pulldown, use acdropdown)
35 function EditToolbar() {
38 $this->tokens = array();
40 //FIXME: enable Undo button for all other buttons also, not only the search/replace button
41 if (JS_SEARCHREPLACE) {
42 $this->tokens['JS_SEARCHREPLACE'] = 1;
43 $undo_btn = $WikiTheme->getImageURL("ed_undo.png");
44 $undo_d_btn = $WikiTheme->getImageURL("ed_undo_d.png");
45 // JS_SEARCHREPLACE from walterzorn.de
47 uri_undo_btn = '".$undo_btn."'
48 msg_undo_alt = '"._("Undo")."'
49 uri_undo_d_btn = '".$undo_d_btn."'
50 msg_undo_d_alt = '"._("Undo disabled")."'
51 msg_do_undo = '"._("Operation undone")."'
52 msg_replfound = '"._("Substring \"\\1\" found \\2 times. Replace with \"\\3\"?")."'
53 msg_replnot = '"._("String \"%s\" not found.")."'
54 msg_repl_title = '"._("Search & Replace")."'
55 msg_repl_search = '"._("Search for")."'
56 msg_repl_replace_with = '"._("Replace with")."'
57 msg_repl_ok = '"._("OK")."'
58 msg_repl_close = '"._("Close")."'
60 if (empty($WikiTheme->_headers_printed)) {
61 $WikiTheme->addMoreHeaders($js);
62 $WikiTheme->addMoreAttr('body', "SearchReplace"," onload='define_f()'");
63 } else { // from an actionpage: WikiBlog, AddComment, WikiForum
67 $WikiTheme->addMoreAttr('body', "editfocus", "document.getElementById('edit-content]').editarea.focus()");
70 if (ENABLE_EDIT_TOOLBAR) {
71 $js = JavaScript('',array('src' => $WikiTheme->_findData("toolbar.js")));
72 if (empty($WikiTheme->_headers_printed)) {
73 $WikiTheme->addMoreHeaders($js);
75 else { // from an actionpage: WikiBlog, AddComment, WikiForum
77 printXML(JavaScript('define_f()'));
81 require_once("lib/WikiPluginCached.php");
82 $cache = WikiPluginCached::newCache();
83 $dbi = $GLOBALS['request']->getDbh();
84 // regenerate if number of pages changes (categories, pages, templates)
85 $key = $dbi->numPages();
86 $key .= '+categories+plugin' . (isBrowserSafari() ? '+safari' : '');
87 if (TOOLBAR_PAGELINK_PULLDOWN) {
90 if (TOOLBAR_TEMPLATE_PULLDOWN) {
91 $key .= "+templates_" . $dbi->getTimestamp();
93 $id = $cache->generateId($key);
94 $content = $cache->get($id, 'toolbarcache');
96 if (!empty($content)) {
97 $this->tokens['EDIT_TOOLBAR'] =& $content;
99 $content = $this->_generate();
100 // regenerate buttons every 1 hr/6 hrs
101 $cache->save($id, $content, DEBUG ? '+3600' : '+21600', 'toolbarcache');
102 $this->tokens['EDIT_TOOLBAR'] =& $content;
106 function getTokens () {
107 return $this->tokens;
110 function _generate () {
111 global $WikiTheme, $request;
113 $toolbar = "document.writeln(\"<div class=\\\"edit-toolbar\\\" id=\\\"toolbar\\\">\");\n";
115 if (ENABLE_EDIT_TOOLBAR) {
116 $username = $request->_user->UserName();
117 if (FUSIONFORGE or DISABLE_MARKUP_WIKIWORD or (!isWikiWord($username))) {
118 $username = '[['.$username.']]';
120 $signature = " ––".$username." ".CTime();
123 "image"=>"ed_format_bold.png",
126 "sample"=>_("Bold text"),
127 "title"=>_("Bold text [alt-b]")),
128 array("image"=>"ed_format_italic.png",
131 "sample"=>_("Italic text"),
132 "title"=>_("Italic text [alt-i]")),
133 array("image"=>"ed_format_strike.png",
136 "sample"=>_("Strike-through text"),
137 "title"=>_("Strike")),
138 array("image"=>"ed_format_color.png",
139 "open"=>"%color=green% ",
141 "sample"=>_("Color text"),
142 "title"=>_("Color")),
143 array("image"=>"ed_pagelink.png",
146 "sample"=>_("PageName|optional label"),
147 "title"=>_("Link to page")),
148 array("image"=>"ed_link.png",
151 "sample"=>_("http://www.example.com|optional label"),
152 "title"=>_("External link (remember http:// prefix)")),
153 array("image"=>"ed_headline.png",
156 "sample"=>_("Headline text"),
157 "title"=>_("Level 1 headline")),
158 array("image"=>"ed_nowiki.png",
159 "open"=>"\\<verbatim\\>\\n",
160 "close"=>"\\n\\</verbatim\\>",
161 "sample"=>_("Insert non-formatted text here"),
162 "title"=>_("Ignore wiki formatting")),
163 array("image"=>"ed_sig.png",
164 "open" => $signature,
167 "title"=>_("Your signature")),
168 array("image"=>"ed_hr.png",
169 "open"=>"\\n----\\n",
172 "title"=>_("Horizontal line")),
173 array("image"=>"ed_table.png",
174 "open"=>"\\n{| class=\"bordered\"\\n|+ This is the table caption\\n|= This is the table summary\\n|-\\n! Header A !! Header B !! Header C\\n|-\\n| Cell A1 || Cell B1 || Cell C1\\n|-\\n| Cell A2 || Cell B2 || Cell C2\\n|-\\n| Cell A3 || Cell B3 || Cell C3\\n|}\\n",
177 "title"=>_("Sample table")),
178 array("image"=>"ed_enumlist.png",
179 "open"=>"\\n# Item 1\\n# Item 2\\n# Item 3\\n",
182 "title"=>_("Enumeration")),
183 array("image"=>"ed_list.png",
184 "open"=>"\\n* Item 1\\n* Item 2\\n* Item 3\\n",
188 array("image"=>"ed_toc.png",
189 "open"=>"<<CreateToc with_toclink||=1>>\\n",
192 "title"=>_("Table of Contents")),
193 array("image"=>"ed_redirect.png",
194 "open"=>"<<RedirectTo page=\"",
196 "sample"=>_("Page Name"),
197 "title"=>_("Redirect")),
198 array("image"=>"ed_templateplugin.png",
201 "sample"=>_("Template Name"),
202 "title"=>_("Template"))
204 $btn = new SubmitImageButton(_("Save"), "edit[save]", 'toolbar',
205 $WikiTheme->getImageURL("ed_save.png"));
206 $btn->addTooltip(_("Save"));
207 $btn->setAccesskey("s");
208 $toolbar .= ('document.writeln("'.addslashes($btn->asXml()).'");'."\n");
209 // preview not supported yet on Wikiblog
210 if (empty($WikiTheme->_headers_printed)) {
211 $btn = new SubmitImageButton(_("Preview"), "edit[preview]", 'toolbar',
212 $WikiTheme->getImageURL("ed_preview.png"));
213 $btn->addTooltip(_("Preview"));
214 $btn->setAccesskey("p");
215 $toolbar .= ('document.writeln("'.addslashes($btn->asXml()).'");'."\n");
218 foreach ($toolarray as $tool) {
219 $image = $WikiTheme->getImageURL($tool["image"]);
220 $open = $tool["open"];
221 $close = $tool["close"];
222 $sample = addslashes( $tool["sample"] );
223 // Note that we use the title both for the ALT tag and the TITLE tag of the image.
224 // Older browsers show a "speedtip" type message only for ALT.
225 // Ideally these should be different, realistically they
226 // probably don't need to be.
227 $tool = $WikiTheme->fixAccesskey($tool);
228 $title = addslashes( $tool["title"] );
229 $toolbar .= ("addTagButton('$image','$title','$open','$close','$sample');\n");
231 /* Fails with Chrome */
232 if (!isBrowserSafari()) {
233 $toolbar .= ("addInfobox('"
234 . addslashes( _("Click a button to get an example text") )
239 if (JS_SEARCHREPLACE) {
240 $undo_d_btn = $WikiTheme->getImageURL("ed_undo_d.png");
241 //$redo_btn = $WikiTheme->getImageURL("ed_redo.png");
242 $sr_btn = $WikiTheme->getImageURL("ed_replace.png");
243 //TODO: generalize the UNDO button and fix it for Search & Replace
244 $sr_html = HTML(HTML::img
245 (array('class'=>"toolbar",
248 'title'=>_("Undo Search & Replace"),
249 'alt' =>_("Undo Search & Replace"),
250 //'disabled'=>"disabled", //non-XHTML conform
251 //'onfocus' =>"if(this.blur && undo_buffer_index==0) this.blur()",
252 'onclick' =>"do_undo()")),
254 (array('class'=>"toolbar",
256 'alt' =>_("Search & Replace"),
257 'title'=>_("Search & Replace"),
258 'onclick'=>"replace()")));
263 //TODO: Delegate this to run-time with showing an hidden input at the right, and do
264 // a seperate moacdropdown and xmlrpc:titleSearch.
266 // Button to generate categories, display in extra window as popup and insert
267 $sr_html = HTML($sr_html, $this->categoriesPulldown());
268 // Button to generate plugins, display in extra window as popup and insert
269 $sr_html = HTML($sr_html, $this->pluginPulldown());
271 // Button to generate pagenames, display in extra window as popup and insert
272 if (TOOLBAR_PAGELINK_PULLDOWN)
273 $sr_html = HTML($sr_html, $this->pagesPulldown(TOOLBAR_PAGELINK_PULLDOWN));
274 // Button to insert from an template, display pagename in extra window as popup and insert
275 if (TOOLBAR_TEMPLATE_PULLDOWN)
276 $sr_html = HTML($sr_html, $this->templatePulldown(TOOLBAR_TEMPLATE_PULLDOWN));
278 // Button to add images, display in extra window as popup and insert
279 if (TOOLBAR_IMAGE_PULLDOWN)
280 $sr_html = HTML($sr_html, $this->imagePulldown(TOOLBAR_IMAGE_PULLDOWN));
282 // don't use document.write for replace, otherwise self.opener is not defined.
283 $toolbar_end = "document.writeln(\"</div>\");";
285 return HTML(Javascript($toolbar),
286 "\n", $sr_html, "\n",
287 Javascript($toolbar_end));
289 return HTML(Javascript($toolbar . $toolbar_end));
293 function categoriesPulldown() {
296 require_once('lib/TextSearchQuery.php');
297 $dbi =& $GLOBALS['request']->_dbi;
298 // KEYWORDS formerly known as $KeywordLinkRegexp
299 $pages = $dbi->titleSearch(new TextSearchQuery(KEYWORDS, true));
301 $categories = array();
302 while ($p = $pages->next()) {
303 $page = $p->getName();
305 $categories[] = "['$page', '%0A----%0A%5B%5B".$page."%5D%5D']";
306 } else if (DISABLE_MARKUP_WIKIWORD or (!isWikiWord($page))) {
307 $categories[] = "['$page', '%0A%5B".$page."%5D']";
309 $categories[] = "['$page', '%0A".$page."']";
312 if (!$categories) return '';
313 // Ensure this to be inserted at the very end. Hence we added the id to the function.
314 $more_buttons = HTML::img(array('class'=> "toolbar",
315 'id' => 'tb-categories',
316 'src' => $WikiTheme->getImageURL("ed_category.png"),
317 'title'=>_("AddCategory"),
318 'alt'=>"AddCategory", // to detect this at js
319 'onclick'=>"showPulldown('".
320 _("Insert Categories")
321 ."',[".join(",",$categories)."],'"
323 ._("Close")."','tb-categories')"));
324 return HTML("\n", $more_buttons);
329 // result is cached. Esp. the args are expensive
330 function pluginPulldown() {
332 global $AllAllowedPlugins;
334 $plugin_dir = 'lib/plugin';
335 if (defined('PHPWIKI_DIR'))
336 $plugin_dir = PHPWIKI_DIR . "/$plugin_dir";
337 $pd = new fileSet($plugin_dir, '*.php');
338 $plugins = $pd->getFiles();
341 if (!empty($plugins)) {
343 require_once("lib/WikiPlugin.php");
344 $w = new WikiPluginLoader;
345 foreach ($plugins as $plugin) {
346 $pluginName = str_replace(".php", "", $plugin);
347 if (in_array($pluginName, $AllAllowedPlugins)) {
348 $p = $w->getPlugin($pluginName, false); // second arg?
349 // trap php files which aren't WikiPlugin~s
350 if (strtolower(substr(get_parent_class($p), 0, 10)) == 'wikiplugin') {
352 $desc = $p->getArgumentsDescription();
353 $src = array("\n",'"',"'",'|','[',']','\\');
354 $replace = array('%0A','%22','%27','%7C','%5B','%5D','%5C');
355 $desc = str_replace("<br />",' ',$desc->asXML());
357 $plugin_args = ' '.str_replace($src, $replace, $desc);
358 $toinsert = "%0A<<".$pluginName.$plugin_args.">>"; // args?
359 $plugin_js .= ",['$pluginName','$toinsert']";
363 $plugin_js = substr($plugin_js, 1);
364 $more_buttons = HTML::img(array('class'=>"toolbar",
365 'id' => 'tb-plugins',
366 'src' => $WikiTheme->getImageURL("ed_plugins.png"),
367 'title'=>_("AddPlugin"),
368 'alt'=>_("AddPlugin"),
369 'onclick'=>"showPulldown('".
371 ."',[".$plugin_js."],'"
373 ._("Close")."','tb-plugins')"));
374 return HTML("\n", $more_buttons);
379 // result is cached. Esp. the args are expensive
380 function pagesPulldown($query, $case_exact=false, $regex='auto') {
381 require_once('lib/TextSearchQuery.php');
382 $dbi =& $GLOBALS['request']->_dbi;
383 $page_iter = $dbi->titleSearch(new TextSearchQuery($query, $case_exact, $regex));
384 if ($page_iter->count() > 0) {
387 while ($p = $page_iter->next()) {
388 $page = $p->getName();
389 if (DISABLE_MARKUP_WIKIWORD or (!isWikiWord($page)))
390 $pages[] = "['$page', '%5B".$page."%5D']";
392 $pages[] = "['$page', '$page']";
394 return HTML("\n", HTML::img(array('class'=>"toolbar",
396 'src' => $WikiTheme->getImageURL("ed_pages.png"),
397 'title'=>_("AddPageLink"),
398 'alt'=>_("AddPageLink"),
399 'onclick'=>"showPulldown('".
401 ."',[".join(",",$pages)."],'"
403 ._("Close")."','tb-pages')")));
408 // result is cached. Esp. the args are expensive
409 function imagePulldown($query, $case_exact=false, $regex='auto') {
412 $image_dir = getUploadFilePath();
413 $pd = new fileSet($image_dir, '*');
414 $images = $pd->getFiles();
416 if (UPLOAD_USERDIR) {
417 $image_dir .= "/" . $request->_user->_userid;
418 $pd = new fileSet($image_dir, '*');
419 $images = array_merge($images, $pd->getFiles());
423 if (!empty($images)) {
425 foreach ($images as $image) {
426 // Select only image and video files
427 if (is_image($image) or is_video($image)) {
428 $image_js .= ",['$image','{{".$image."}}']";
431 $image_js = substr($image_js, 1);
432 $more_buttons = HTML::img(array('class'=>"toolbar",
434 'src' => $WikiTheme->getImageURL("ed_image.png"),
435 'title'=>_("Add Image or Video"),
436 'alt'=>_("Add Image or Video"),
437 'onclick'=>"showPulldown('".
438 _("Insert Image or Video")
439 ."',[".$image_js."],'"
441 ._("Close")."','tb-images')"));
442 return HTML("\n", $more_buttons);
447 // result is cached. Esp. the args are expensive
449 function templatePulldown($query, $case_exact=false, $regex='auto') {
451 require_once('lib/TextSearchQuery.php');
452 $dbi =& $request->_dbi;
453 $page_iter = $dbi->titleSearch(new TextSearchQuery($query, $case_exact, $regex));
455 if ($page_iter->count()) {
458 while ($p = $page_iter->next()) {
459 $rev = $p->getCurrentRevision();
460 $toinsert = str_replace(array("\n",'"'), array('_nl','_quot'), $rev->_get_content());
461 //$toinsert = str_replace("\n",'\n',addslashes($rev->_get_content()));
462 $pages_js .= ",['".$p->getName()."','_nl$toinsert']";
464 $pages_js = substr($pages_js, 1);
465 if (!empty($pages_js))
466 return HTML("\n", HTML::img
467 (array('class'=>"toolbar",
468 'id' => 'tb-templates',
469 'src' => $WikiTheme->getImageURL("ed_template.png"),
470 'title'=>_("AddTemplate"),
471 'alt'=>_("AddTemplate"),
472 'onclick'=>"showPulldown('".
474 ."',[".$pages_js."],'"
476 ._("Close")."','tb-templates')")));
487 // c-hanging-comment-ender-p: nil
488 // indent-tabs-mode: nil