]> CyberLeo.Net >> Repos - SourceForge/phpwiki.git/blob - lib/EditToolbar.php
function finfo_open exists
[SourceForge/phpwiki.git] / lib / EditToolbar.php
1 <?php
2
3 /* Copyright 2004-2010 $ThePhpWikiProgrammingTeam
4  * Copyright 2008-2009 Marc-Etienne Vargenau, Alcatel-Lucent
5  *
6  * This file is part of PhpWiki.
7  *
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.
12  *
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.
17  *
18  * You should have received a copy of the GNU General Public License along
19  * with PhpWiki; if not, write to the Free Software Foundation, Inc.,
20  * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
21  */
22
23 /**
24  * EDIT Toolbar Initialization.
25  * The default/themes/toolbar.js is from Mediawiki, this PHP is written from scratch.
26  *
27  * Features:
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)
31  */
32
33 class EditToolbar
34 {
35     function __construct()
36     {
37         global $WikiTheme;
38
39         $this->tokens = array();
40
41         //FIXME: enable Undo button for all other buttons also, not only the search/replace button
42         if (JS_SEARCHREPLACE) {
43             $this->tokens['JS_SEARCHREPLACE'] = 1;
44             $undo_btn = $WikiTheme->getImageURL("ed_undo.png");
45             $undo_d_btn = $WikiTheme->getImageURL("ed_undo_d.png");
46             // JS_SEARCHREPLACE from walterzorn.de
47             $js = Javascript("
48 uri_undo_btn   = '" . $undo_btn . "'
49 msg_undo_alt   = '" . _("Undo") . "'
50 uri_undo_d_btn = '" . $undo_d_btn . "'
51 msg_undo_d_alt = '" . _("Undo disabled") . "'
52 msg_do_undo    = '" . _("Operation undone") . "'
53 msg_replfound  = '" . _("Substring “\\1” found \\2 times. Replace with “\\3”?") . "'
54 msg_replnot    = '" . _("String “%s” not found.") . "'
55 msg_repl_title     = '" . _("Search & Replace") . "'
56 msg_repl_search    = '" . _("Search for") . "'
57 msg_repl_replace_with = '" . _("Replace with") . "'
58 msg_repl_ok        = '" . _("OK") . "'
59 msg_repl_close     = '" . _("Close") . "'
60 ");
61             if (empty($WikiTheme->_headers_printed)) {
62                 $WikiTheme->addMoreHeaders($js);
63                 $WikiTheme->addMoreAttr('body', "SearchReplace", " onload='define_f()'");
64             } else { // from an actionpage: WikiBlog, AddComment, WikiForum
65                 printXML($js);
66             }
67         } else {
68             $WikiTheme->addMoreAttr('body', "editfocus", "document.getElementById('edit-content]').editarea.focus()");
69         }
70
71         if (ENABLE_EDIT_TOOLBAR) {
72             $init = JavaScript("var data_path = '" . javascript_quote_string(DATA_PATH) . "';\n");
73             $js = JavaScript('', array('src' => $WikiTheme->_findData("toolbar.js")));
74             if (empty($WikiTheme->_headers_printed)) {
75                 $WikiTheme->addMoreHeaders($init);
76                 $WikiTheme->addMoreHeaders($js);
77             } else { // from an actionpage: WikiBlog, AddComment, WikiForum
78                 printXML($init);
79                 printXML($js);
80                 printXML(JavaScript('define_f()'));
81             }
82         }
83
84         require_once 'lib/WikiPluginCached.php';
85         $cache = WikiPluginCached::newCache();
86         $dbi = $GLOBALS['request']->getDbh();
87         // regenerate if number of pages changes (categories, pages, templates)
88         $key = $dbi->numPages();
89         $key .= '+categories+plugin' . (isBrowserSafari() ? '+safari' : '');
90         if (TOOLBAR_PAGELINK_PULLDOWN) {
91             $key .= "+pages";
92         }
93         if (TOOLBAR_TEMPLATE_PULLDOWN) {
94             $key .= "+templates_" . $dbi->getTimestamp();
95         }
96         $id = $cache->generateId($key);
97         $content = $cache->get($id, 'toolbarcache');
98
99         if (!empty($content)) {
100             $this->tokens['EDIT_TOOLBAR'] =& $content;
101         } else {
102             $content = $this->_generate();
103             // regenerate buttons every 1 hr/6 hrs
104             $cache->save($id, $content, DEBUG ? '+3600' : '+21600', 'toolbarcache');
105             $this->tokens['EDIT_TOOLBAR'] =& $content;
106         }
107     }
108
109     public function getTokens()
110     {
111         return $this->tokens;
112     }
113
114     private function _generate()
115     {
116         global $WikiTheme, $request;
117
118         $toolbar = "document.writeln(\"<div class=\\\"edit-toolbar\\\" id=\\\"toolbar\\\">\");\n";
119
120         if (ENABLE_EDIT_TOOLBAR) {
121             $username = $request->_user->UserName();
122             if ((defined('FUSIONFORGE') and FUSIONFORGE) or DISABLE_MARKUP_WIKIWORD or (!isWikiWord($username))) {
123                 $username = '[[' . $username . ']]';
124             }
125             $signature = " ––" . $username . " " . CTime();
126             $toolarray = array(
127                 array(
128                     "image" => "ed_format_bold.png",
129                     "open" => "**",
130                     "close" => "**",
131                     "sample" => _("Bold text"),
132                     "title" => _("Bold text [alt-b]")),
133                 array("image" => "ed_format_italic.png",
134                     "open" => "//",
135                     "close" => "//",
136                     "sample" => _("Italic text"),
137                     "title" => _("Italic text [alt-i]")),
138                 array("image" => "ed_format_strike.png",
139                     "open" => "<s>",
140                     "close" => "</s>",
141                     "sample" => _("Strike-through text"),
142                     "title" => _("Strike")),
143                 array("image" => "ed_format_color.png",
144                     "open" => "%color=green% ",
145                     "close" => " %%",
146                     "sample" => _("Color text"),
147                     "title" => _("Color")),
148                 array("image" => "ed_pagelink.png",
149                     "open" => "[[",
150                     "close" => "]]",
151                     "sample" => _("PageName|optional label"),
152                     "title" => _("Link to page")),
153                 array("image" => "ed_link.png",
154                     "open" => "[[",
155                     "close" => "]]",
156                     "sample" => _("http://www.example.com|optional label"),
157                     "title" => _("External link (remember http:// prefix)")),
158                 array("image" => "ed_headline.png",
159                     "open" => "\\n== ",
160                     "close" => " ==\\n",
161                     "sample" => _("Headline text"),
162                     "title" => _("Level 1 headline")),
163                 array("image" => "ed_nowiki.png",
164                     "open" => "\\<verbatim\\>\\n",
165                     "close" => "\\n\\</verbatim\\>",
166                     "sample" => _("Insert non-formatted text here"),
167                     "title" => _("Ignore wiki formatting")),
168                 array("image" => "ed_sig.png",
169                     "open" => $signature,
170                     "close" => "",
171                     "sample" => "",
172                     "title" => _("Your signature")),
173                 array("image" => "ed_hr.png",
174                     "open" => "\\n----\\n",
175                     "close" => "",
176                     "sample" => "",
177                     "title" => _("Horizontal line")),
178                 array("image" => "ed_table.png",
179                     "open" => "\\n{| class=\"bordered\"\\n|+ This is the table caption\\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",
180                     "close" => "",
181                     "sample" => "",
182                     "title" => _("Sample table")),
183                 array("image" => "ed_enumlist.png",
184                     "open" => "\\n# Item 1\\n# Item 2\\n# Item 3\\n",
185                     "close" => "",
186                     "sample" => "",
187                     "title" => _("Enumeration")),
188                 array("image" => "ed_list.png",
189                     "open" => "\\n* Item 1\\n* Item 2\\n* Item 3\\n",
190                     "close" => "",
191                     "sample" => "",
192                     "title" => _("List")),
193                 array("image" => "ed_toc.png",
194                     "open" => "<<CreateToc with_toclink||=1>>\\n",
195                     "close" => "",
196                     "sample" => "",
197                     "title" => _("Table of Contents")),
198                 array("image" => "ed_redirect.png",
199                     "open" => "<<RedirectTo page=\"",
200                     "close" => "\">>",
201                     "sample" => _("Page Name"),
202                     "title" => _("Redirect")),
203                 array("image" => "ed_templateplugin.png",
204                     "open" => "{{",
205                     "close" => "}}",
206                     "sample" => _("Template Name"),
207                     "title" => _("Template"))
208             );
209             $btn = new SubmitImageButton(_("Save"), "edit[save]", 'toolbar',
210                 $WikiTheme->getImageURL("ed_save.png"));
211             $btn->addTooltip(_("Save"));
212             $btn->setAccesskey("s");
213             $toolbar .= ('document.writeln("' . addslashes($btn->asXml()) . '");' . "\n");
214             // preview not supported yet on Wikiblog
215             if (empty($WikiTheme->_headers_printed)) {
216                 $btn = new SubmitImageButton(_("Preview"), "edit[preview]", 'toolbar',
217                     $WikiTheme->getImageURL("ed_preview.png"));
218                 $btn->addTooltip(_("Preview"));
219                 $btn->setAccesskey("p");
220                 $toolbar .= ('document.writeln("' . addslashes($btn->asXml()) . '");' . "\n");
221             }
222
223             foreach ($toolarray as $tool) {
224                 $image = $WikiTheme->getImageURL($tool["image"]);
225                 $open = $tool["open"];
226                 $close = $tool["close"];
227                 $sample = addslashes($tool["sample"]);
228                 // Note that we use the title both for the ALT tag and the TITLE tag of the image.
229                 // Older browsers show a "speedtip" type message only for ALT.
230                 // Ideally these should be different, realistically they
231                 // probably don't need to be.
232                 $tool = $WikiTheme->fixAccesskey($tool);
233                 $title = addslashes($tool["title"]);
234                 $toolbar .= ("addTagButton('$image','$title','$open','$close','$sample');\n");
235             }
236             /* Fails with Chrome */
237             if (!isBrowserSafari()) {
238                 $toolbar .= ("addInfobox('"
239                     . addslashes(_("Click a button to get an example text"))
240                     . "');\n");
241             }
242         }
243
244         if (JS_SEARCHREPLACE) {
245             $undo_d_btn = $WikiTheme->getImageURL("ed_undo_d.png");
246             //$redo_btn = $WikiTheme->getImageURL("ed_redo.png");
247             $sr_btn = $WikiTheme->getImageURL("ed_replace.png");
248             //TODO: generalize the UNDO button and fix it for Search & Replace
249             $sr_html = HTML(HTML::img
250                 (array('class' => "toolbar",
251                     'id' => "sr_undo",
252                     'src' => $undo_d_btn,
253                     'title' => _("Undo Search & Replace"),
254                     'alt' => _("Undo Search & Replace"),
255                     //'disabled'=>"disabled",   //non-XHTML conform
256                     //'onfocus' =>"if(this.blur && undo_buffer_index==0) this.blur()",
257                     'onclick' => "do_undo()")),
258                 HTML::img
259                 (array('class' => "toolbar",
260                     'src' => $sr_btn,
261                     'alt' => _("Search & Replace"),
262                     'title' => _("Search & Replace"),
263                     'onclick' => "replace()")));
264         } else {
265             $sr_html = '';
266         }
267
268         //TODO: Delegate this to run-time with showing an hidden input at the right, and do
269         // a separate moacdropdown and xmlrpc:titleSearch.
270
271         // Button to generate categories, display in extra window as popup and insert
272         $sr_html = HTML($sr_html, $this->categoriesPulldown());
273         // Button to generate plugins, display in extra window as popup and insert
274         $sr_html = HTML($sr_html, $this->pluginPulldown());
275
276         // Button to generate pagenames, display in extra window as popup and insert
277         if (TOOLBAR_PAGELINK_PULLDOWN)
278             $sr_html = HTML($sr_html, $this->pagesPulldown(TOOLBAR_PAGELINK_PULLDOWN));
279         // Button to insert from an template, display pagename in extra window as popup and insert
280         if (TOOLBAR_TEMPLATE_PULLDOWN)
281             $sr_html = HTML($sr_html, $this->templatePulldown(TOOLBAR_TEMPLATE_PULLDOWN));
282
283         // Button to add images, display in extra window as popup and insert
284         if (TOOLBAR_IMAGE_PULLDOWN)
285             $sr_html = HTML($sr_html, $this->imagePulldown());
286
287         // don't use document.write for replace, otherwise self.opener is not defined.
288         $toolbar_end = "document.writeln(\"</div>\");";
289         if ($sr_html)
290             return HTML(Javascript($toolbar),
291                 "\n", $sr_html, "\n",
292                 Javascript($toolbar_end));
293         else
294             return HTML(Javascript($toolbar . $toolbar_end));
295     }
296
297     //result is cached
298     private function categoriesPulldown()
299     {
300         global $WikiTheme;
301
302         require_once 'lib/TextSearchQuery.php';
303         $dbi =& $GLOBALS['request']->_dbi;
304         // KEYWORDS formerly known as $KeywordLinkRegexp
305         $pages = $dbi->titleSearch(new TextSearchQuery(KEYWORDS, true));
306         if ($pages) {
307             $categories = array();
308             while ($p = $pages->next()) {
309                 $page = $p->getName();
310                 if ((defined('FUSIONFORGE') and FUSIONFORGE)) {
311                     $categories[] = "['$page', '%0A----%0A%5B%5B" . $page . "%5D%5D']";
312                 } elseif (DISABLE_MARKUP_WIKIWORD or (!isWikiWord($page))) {
313                     $categories[] = "['$page', '%0A%5B" . $page . "%5D']";
314                 } else {
315                     $categories[] = "['$page', '%0A" . $page . "']";
316                 }
317             }
318             if (!$categories) return '';
319             // Ensure this to be inserted at the very end. Hence we added the id to the function.
320             $more_buttons = HTML::img(array('class' => "toolbar",
321                 'id' => 'tb-categories',
322                 'src' => $WikiTheme->getImageURL("ed_category.png"),
323                 'title' => _("Insert Categories"),
324                 'alt' => "Insert Categories", // to detect this at js
325                 'onclick' => "showPulldown('" .
326                     _("Insert Categories")
327                     . "',[" . join(",", $categories) . "],'"
328                     . _("Insert") . "','"
329                     . _("Close") . "','tb-categories')"));
330             return HTML("\n", $more_buttons);
331         }
332         return '';
333     }
334
335     // result is cached. Esp. the args are expensive
336     private function pluginPulldown()
337     {
338         global $WikiTheme;
339         global $AllAllowedPlugins;
340
341         $plugin_dir = 'lib/plugin';
342         if (defined('PHPWIKI_DIR'))
343             $plugin_dir = PHPWIKI_DIR . "/$plugin_dir";
344         $pd = new fileSet($plugin_dir, '*.php');
345         $plugins = $pd->getFiles();
346         unset($pd);
347         sort($plugins);
348         if (!empty($plugins)) {
349             $plugin_js = '';
350             require_once 'lib/WikiPlugin.php';
351             $w = new WikiPluginLoader();
352             foreach ($plugins as $plugin) {
353                 $pluginName = str_replace(".php", "", $plugin);
354                 if (in_array($pluginName, $AllAllowedPlugins)) {
355                     $p = $w->getPlugin($pluginName, false); // second arg?
356                     // trap php files which aren't WikiPlugin~s
357                     if (strtolower(substr(get_parent_class($p), 0, 10)) == 'wikiplugin') {
358                         $plugin_args = '';
359                         $desc = $p->getArgumentsDescription();
360                         $src = array("\n", '"', "'", '|', '[', ']', '\\');
361                         $replace = array('%0A', '%22', '%27', '%7C', '%5B', '%5D', '%5C');
362                         $desc = str_replace("<br />", ' ', $desc->asXML());
363                         if ($desc)
364                             $plugin_args = ' ' . str_replace($src, $replace, $desc);
365                         $toinsert = "%0A<<" . $pluginName . $plugin_args . ">>"; // args?
366                         $plugin_js .= ",['$pluginName','$toinsert']";
367                     }
368                 }
369             }
370             $plugin_js = substr($plugin_js, 1);
371             $more_buttons = HTML::img(array('class' => "toolbar",
372                 'id' => 'tb-plugins',
373                 'src' => $WikiTheme->getImageURL("ed_plugins.png"),
374                 'title' => _("Insert Plugin"),
375                 'alt' => _("Insert Plugin"),
376                 'onclick' => "showPulldown('" .
377                     _("Insert Plugin")
378                     . "',[" . $plugin_js . "],'"
379                     . _("Insert") . "','"
380                     . _("Close") . "','tb-plugins')"));
381             return HTML("\n", $more_buttons);
382         }
383         return '';
384     }
385
386     // result is cached. Esp. the args are expensive
387     private function pagesPulldown($query, $case_exact = false, $regex = 'auto')
388     {
389         require_once 'lib/TextSearchQuery.php';
390         $dbi =& $GLOBALS['request']->_dbi;
391         $page_iter = $dbi->titleSearch(new TextSearchQuery($query, $case_exact, $regex));
392         if ($page_iter->count() > 0) {
393             global $WikiTheme;
394             $pages = array();
395             while ($p = $page_iter->next()) {
396                 $page = $p->getName();
397                 if (DISABLE_MARKUP_WIKIWORD or (!isWikiWord($page)))
398                     $pages[] = "['$page', '%5B" . $page . "%5D']";
399                 else
400                     $pages[] = "['$page', '$page']";
401             }
402             return HTML("\n", HTML::img(array('class' => "toolbar",
403                 'id' => 'tb-pages',
404                 'src' => $WikiTheme->getImageURL("ed_pages.png"),
405                 'title' => _("Insert PageLink"),
406                 'alt' => _("Insert PageLink"),
407                 'onclick' => "showPulldown('" .
408                     _("Insert PageLink")
409                     . "',[" . join(",", $pages) . "],'"
410                     . _("Insert") . "','"
411                     . _("Close") . "','tb-pages')")));
412         }
413         return '';
414     }
415
416     // result is cached. Esp. the args are expensive
417     private function imagePulldown()
418     {
419         global $WikiTheme, $request;
420
421         $image_dir = getUploadFilePath();
422         $pd = new fileSet($image_dir, '*');
423         $images = $pd->getFiles();
424         unset($pd);
425         if (UPLOAD_USERDIR) {
426             $image_dir .= "/" . $request->_user->_userid;
427             $pd = new fileSet($image_dir, '*');
428             $images = array_merge($images, $pd->getFiles());
429             unset($pd);
430         }
431         sort($images);
432         if (!empty($images)) {
433             $image_js = '';
434             foreach ($images as $image) {
435                 // Select only image and video files
436                 if (is_image($image) or is_video($image)) {
437                     $image_js .= ",['$image','{{" . $image . "}}']";
438                 }
439             }
440             $image_js = substr($image_js, 1);
441             $more_buttons = HTML::img(array('class' => "toolbar",
442                 'id' => 'tb-images',
443                 'src' => $WikiTheme->getImageURL("ed_image.png"),
444                 'title' => _("Insert Image or Video"),
445                 'alt' => _("Insert Image or Video"),
446                 'onclick' => "showPulldown('" .
447                     _("Insert Image or Video")
448                     . "',[" . $image_js . "],'"
449                     . _("Insert") . "','"
450                     . _("Close") . "','tb-images')"));
451             return HTML("\n", $more_buttons);
452         }
453         return '';
454     }
455
456     // result is cached. Esp. the args are expensive
457     // FIXME!
458     private function templatePulldown($query, $case_exact = false, $regex = 'auto')
459     {
460         global $request;
461         require_once 'lib/TextSearchQuery.php';
462         $dbi =& $request->_dbi;
463         $page_iter = $dbi->titleSearch(new TextSearchQuery($query, $case_exact, $regex));
464         if ($page_iter->count()) {
465             global $WikiTheme;
466             $pages_js = '';
467             while ($p = $page_iter->next()) {
468                 $rev = $p->getCurrentRevision();
469                 $toinsert = str_replace(array("\n", '"'), array('_nl', '_quot'), $rev->_get_content());
470                 //$toinsert = str_replace("\n",'\n',addslashes($rev->_get_content()));
471                 $pages_js .= ",['" . $p->getName() . "','_nl$toinsert']";
472             }
473             $pages_js = substr($pages_js, 1);
474             if (!empty($pages_js))
475                 return HTML("\n", HTML::img
476                 (array('class' => "toolbar",
477                     'id' => 'tb-templates',
478                     'src' => $WikiTheme->getImageURL("ed_template.png"),
479                     'title' => _("Insert Template"),
480                     'alt' => _("Insert Template"),
481                     'onclick' => "showPulldown('" .
482                         _("Insert Template")
483                         . "',[" . $pages_js . "],'"
484                         . _("Insert") . "','"
485                         . _("Close") . "','tb-templates')")));
486         }
487         return '';
488     }
489
490 }
491
492 // Local Variables:
493 // mode: php
494 // tab-width: 8
495 // c-basic-offset: 4
496 // c-hanging-comment-ender-p: nil
497 // indent-tabs-mode: nil
498 // End: