From 209e8df823605afbe201ceea40a91ce8e5446674 Mon Sep 17 00:00:00 2001 From: rurban Date: Sat, 13 May 2006 19:59:55 +0000 Subject: [PATCH] added wysiwyg_editor-1.3a feature by Jean-Nicolas GEREONE converted wysiwyg_editor-1.3a js to WysiwygEdit framework changed default ENABLE_WYSIWYG = true and added WYSIWYG_BACKEND = Wikiwyg git-svn-id: svn://svn.code.sf.net/p/phpwiki/code/trunk@5059 96ab9672-09ca-45d6-a79d-3d69d39ca109 --- config/config-default.ini | 6 +- config/config-dist.ini | 3 +- lib/IniConfig.php | 9 +- lib/WysiwygEdit.php | 15 +- lib/WysiwygEdit/Wikiwyg.php | 131 +++ lib/editpage.php | 7 +- lib/main.php | 27 +- themes/default/Wikiwyg/Selection.htc | 78 ++ themes/default/Wikiwyg/Wikiwyg.js | 491 +++++++++ themes/default/Wikiwyg/Wikiwyg/Debug.js | 60 ++ themes/default/Wikiwyg/Wikiwyg/HTML.js | 53 + themes/default/Wikiwyg/Wikiwyg/Phpwiki.js | 488 +++++++++ themes/default/Wikiwyg/Wikiwyg/Preview.js | 48 + themes/default/Wikiwyg/Wikiwyg/Toolbar.js | 285 +++++ themes/default/Wikiwyg/Wikiwyg/Wikitext.js | 1054 +++++++++++++++++++ themes/default/Wikiwyg/Wikiwyg/Wysiwyg.js | 300 ++++++ themes/default/Wikiwyg/images/bold.gif | Bin 0 -> 76 bytes themes/default/Wikiwyg/images/h1.gif | Bin 0 -> 84 bytes themes/default/Wikiwyg/images/h2.gif | Bin 0 -> 86 bytes themes/default/Wikiwyg/images/h3.gif | Bin 0 -> 86 bytes themes/default/Wikiwyg/images/h4.gif | Bin 0 -> 85 bytes themes/default/Wikiwyg/images/h5.gif | Bin 0 -> 103 bytes themes/default/Wikiwyg/images/h6.gif | Bin 0 -> 105 bytes themes/default/Wikiwyg/images/help.gif | Bin 0 -> 76 bytes themes/default/Wikiwyg/images/hr.gif | Bin 0 -> 73 bytes themes/default/Wikiwyg/images/image.gif | Bin 0 -> 181 bytes themes/default/Wikiwyg/images/indent.gif | Bin 0 -> 90 bytes themes/default/Wikiwyg/images/italic.gif | Bin 0 -> 79 bytes themes/default/Wikiwyg/images/link.gif | Bin 0 -> 894 bytes themes/default/Wikiwyg/images/ordered.gif | Bin 0 -> 84 bytes themes/default/Wikiwyg/images/outdent.gif | Bin 0 -> 91 bytes themes/default/Wikiwyg/images/p.gif | Bin 0 -> 73 bytes themes/default/Wikiwyg/images/pre.gif | Bin 0 -> 105 bytes themes/default/Wikiwyg/images/separator.gif | Bin 0 -> 102 bytes themes/default/Wikiwyg/images/strike.gif | Bin 0 -> 84 bytes themes/default/Wikiwyg/images/table.gif | Bin 0 -> 923 bytes themes/default/Wikiwyg/images/underline.gif | Bin 0 -> 87 bytes themes/default/Wikiwyg/images/unordered.gif | Bin 0 -> 82 bytes themes/default/Wikiwyg/images/www.gif | Bin 0 -> 189 bytes themes/default/phpwiki.css | 57 +- 40 files changed, 3096 insertions(+), 16 deletions(-) create mode 100644 lib/WysiwygEdit/Wikiwyg.php create mode 100644 themes/default/Wikiwyg/Selection.htc create mode 100644 themes/default/Wikiwyg/Wikiwyg.js create mode 100644 themes/default/Wikiwyg/Wikiwyg/Debug.js create mode 100644 themes/default/Wikiwyg/Wikiwyg/HTML.js create mode 100755 themes/default/Wikiwyg/Wikiwyg/Phpwiki.js create mode 100644 themes/default/Wikiwyg/Wikiwyg/Preview.js create mode 100644 themes/default/Wikiwyg/Wikiwyg/Toolbar.js create mode 100644 themes/default/Wikiwyg/Wikiwyg/Wikitext.js create mode 100644 themes/default/Wikiwyg/Wikiwyg/Wysiwyg.js create mode 100755 themes/default/Wikiwyg/images/bold.gif create mode 100755 themes/default/Wikiwyg/images/h1.gif create mode 100755 themes/default/Wikiwyg/images/h2.gif create mode 100755 themes/default/Wikiwyg/images/h3.gif create mode 100755 themes/default/Wikiwyg/images/h4.gif create mode 100755 themes/default/Wikiwyg/images/h5.gif create mode 100755 themes/default/Wikiwyg/images/h6.gif create mode 100755 themes/default/Wikiwyg/images/help.gif create mode 100755 themes/default/Wikiwyg/images/hr.gif create mode 100755 themes/default/Wikiwyg/images/image.gif create mode 100755 themes/default/Wikiwyg/images/indent.gif create mode 100755 themes/default/Wikiwyg/images/italic.gif create mode 100755 themes/default/Wikiwyg/images/link.gif create mode 100755 themes/default/Wikiwyg/images/ordered.gif create mode 100755 themes/default/Wikiwyg/images/outdent.gif create mode 100755 themes/default/Wikiwyg/images/p.gif create mode 100755 themes/default/Wikiwyg/images/pre.gif create mode 100755 themes/default/Wikiwyg/images/separator.gif create mode 100755 themes/default/Wikiwyg/images/strike.gif create mode 100755 themes/default/Wikiwyg/images/table.gif create mode 100755 themes/default/Wikiwyg/images/underline.gif create mode 100755 themes/default/Wikiwyg/images/unordered.gif create mode 100755 themes/default/Wikiwyg/images/www.gif diff --git a/config/config-default.ini b/config/config-default.ini index b20c753aa..9238c8a32 100644 --- a/config/config-default.ini +++ b/config/config-default.ini @@ -1,4 +1,4 @@ -; $Id: config-default.ini,v 1.44 2006-03-19 14:23:51 rurban Exp $ +; $Id: config-default.ini,v 1.45 2006-05-13 19:59:54 rurban Exp $ ; This is the default PhpWiki configuration for undefined config.ini entries. ; recent development and debugging features: @@ -23,8 +23,8 @@ USE_CAPTCHA_RANDOM_WORD = false ENABLE_ACDROPDOWN = false ; deprecated ENABLE_LIVESEARCH = false -ENABLE_WYSIWYG = false -WYSIWYG_BACKEND = tinymce +ENABLE_WYSIWYG = true +WYSIWYG_BACKEND = Wikiwyg WYSIWYG_DEFAULT_PAGETYPE_HTML = false WIKI_NAME = PhpWiki diff --git a/config/config-dist.ini b/config/config-dist.ini index 62bc9f34a..8df3bb913 100644 --- a/config/config-dist.ini +++ b/config/config-dist.ini @@ -54,7 +54,8 @@ ; spaw http://sourceforge.net/projects/spaw ; htmlarea3 ; htmlarea2 -;WYSIWYG_BACKEND = tinymce +; Wikiwyg http://openjsan.org/doc/i/in/ingy/Wikiwyg/ +;WYSIWYG_BACKEND = Wikiwyg ; Store all pages as HTML? Will loose most link and plugin options. ;WYSIWYG_DEFAULT_PAGETYPE_HTML = false diff --git a/lib/IniConfig.php b/lib/IniConfig.php index 94f49458a..f52bcddea 100644 --- a/lib/IniConfig.php +++ b/lib/IniConfig.php @@ -1,5 +1,5 @@ 'text' */ function ConvertBefore($text) { @@ -134,6 +134,9 @@ class HtmlTransformer extends InlineTransformer /* $Log: not supported by cvs2svn $ + Revision 1.3 2005/10/31 17:20:40 rurban + fix ConvertBefore + Revision 1.2 2005/10/31 16:46:13 rurban move old default transformers to baseclass diff --git a/lib/WysiwygEdit/Wikiwyg.php b/lib/WysiwygEdit/Wikiwyg.php new file mode 100644 index 000000000..1ba4f4ab5 --- /dev/null +++ b/lib/WysiwygEdit/Wikiwyg.php @@ -0,0 +1,131 @@ +_transformer_tags = false; + $this->BasePath = DATA_PATH.'/themes/default/Wikiwyg'; + $this->_htmltextid = "edit:content"; + $this->_wikitextid = "editareawiki"; + $this->_jsdefault = " +var base_url = '".DATA_PATH."'; +var data_url = '$this->BasePath'; +var script_url = '".deduce_script_name()."'; +"; + } + + function Head($name='edit[content]') { + global $WikiTheme; + $WikiTheme->addMoreHeaders + (array('src' => $this->BasePath . '/' . $js, + 'language' => 'JavaScript'))); + foreach (array("Wikiwyg.js","Wikiwyg/Toolbar.js","Wikiwyg/Preview.js","Wikiwyg/Wikitext.js", + "Wikiwyg/Wysiwyg.js","Wikiwyg/Phpwiki.js","Wikiwyg/HTML.js", + "Wikiwyg/Toolbar.js") as $js) { + $WikiTheme->addMoreHeaders + (Javascript('', array('src' => $this->BasePath . '/' . $js, + 'language' => 'JavaScript'))); + } + $doubleClickToEdit = ($GLOBALS['request']->getPref('doubleClickEdit') or ENABLE_DOUBLECLICKEDIT) + ? 'true' : 'false'; + return JavaScript($this->_jsdefault . " +window.onload = function() { + var wikiwyg = new Wikiwyg.Phpwiki(); + var config = { + doubleClickToEdit: $doubleClickToEdit, + javascriptLocation: data_url, + toolbar: { + imagesLocation: data_url+'/images/', + controlLayout: [ + 'save','mode_selector', '/', + 'p','|', + 'h2', 'h3', 'h4','|', + 'bold', 'italic', '|' + //'pre','|', + //'ordered', 'unordered','hr','|', + //'link','table', '|' + ], + styleSelector: [ + 'label', 'p', 'h2', 'h3', 'h4', 'pre' + ], + controlLabels: { + save: '"._("Apply changes")."', + cancel: '"._("Exit toolbar")."', + h2: '"._("Title 1")."', + h3: '"._("Title 2")."', + h4: '"._("Title 3")."', + verbatim: '"._("Verbatim")."', + richtable: '"._("Rich Table")."' + } + }, + wysiwyg: { + iframeId: 'iframe0' + }, + wikitext: { + supportCamelCaseLinks: true + } + }; + var div = document.getElementById(\"" . $this->_htmltextid . "\"); + wikiwyg.createWikiwygArea(div, config); + wikiwyg_divs.push(wikiwyg); + wikiwyg.editMode(); +}"); + } + + function Textarea ($textarea, $wikitext, $name='edit[content]') { + $htmltextid = $this->_htmltextid; + $textarea->SetAttr('id', $htmltextid); + $iframe0 = new RawXml(''); + $out = HTML($iframe0, + $textarea, + "\n"); + return $out; + } + + /** + * Handler to convert the Wiki Markup to HTML before editing. + * This will be converted back by WysiwygEdit_ConvertAfter if required. + * *text* => 'text' + */ + function ConvertBefore($text) { + return $text; + } + + /* + * No special PHP HTML->Wikitext conversion needed. This is done in js thanksfully. + * Avoided in editpage.php: PageEditor->getContent + */ + function ConvertAfter($text) { + return TransformInline($text); + } +} + + +/* + $Log: not supported by cvs2svn $ + +*/ + +// Local Variables: +// mode: php +// tab-width: 8 +// c-basic-offset: 4 +// c-hanging-comment-ender-p: nil +// indent-tabs-mode: nil +// End: +?> \ No newline at end of file diff --git a/lib/editpage.php b/lib/editpage.php index be062c5c4..c3544a487 100644 --- a/lib/editpage.php +++ b/lib/editpage.php @@ -1,5 +1,5 @@ _content; $xml_output = $this->WysiwygEdit->ConvertAfter($this->_content); $this->_content = join("", $xml_output->_content); } else { @@ -775,6 +777,9 @@ extends PageEditor /** $Log: not supported by cvs2svn $ + Revision 1.106 2005/11/21 22:03:08 rurban + fix syntax error inside ENABLE_SPAMBLOCKLIST + Revision 1.105 2005/11/21 20:53:59 rurban beautify request pref lines, no antispam if admin (netznetz request), user is a member anyway diff --git a/lib/main.php b/lib/main.php index 5d189973e..cded1b500 100644 --- a/lib/main.php +++ b/lib/main.php @@ -1,5 +1,5 @@ getArg('action'); - if ($this->isPost() and !$this->_user->isAdmin() and $action != 'browse') { + if ($this->isPost() and + !$this->_user->isAdmin() + and $action != 'browse' + and $action !='wikitohtml' + ) + { $page = $this->getPage(); if ( $page->get('moderation') ) { require_once("lib/WikiPlugin.php"); @@ -1140,6 +1145,15 @@ class WikiRequest extends Request { $captcha->image ( $captcha->captchaword() ); } + function action_wikitohtml () { + $content = $this->getArg("content"); + + require_once("lib/BlockParser.php"); + $xml = TransformText($content, 2.0, $this->getArg('pagename')); + $xml->printXML(); + return true; + } + } //FIXME: deprecated with ENABLE_PAGEPERM (?) @@ -1221,6 +1235,12 @@ function main () { // Should this go into constructor? $request->initializeTheme(); + // convert wiki to html + if ($action == 'wikitohtml') { + $request->handleAction(); + return; + } + $request->updateAuthAndPrefs(); $request->initializeLang(); @@ -1275,6 +1295,9 @@ if (!defined('PHPWIKI_NOMAIN') or !PHPWIKI_NOMAIN) // $Log: not supported by cvs2svn $ +// Revision 1.223 2006/03/19 15:01:00 rurban +// sf.net patch #1333957 by Matt Brown: Authentication cookie identical across all wikis on a host +// // Revision 1.222 2006/03/19 14:53:12 rurban // sf.net patch #1438392 by Matt Brown: Bogo Login is broken when ENABLE_PAGEPERM=false // diff --git a/themes/default/Wikiwyg/Selection.htc b/themes/default/Wikiwyg/Selection.htc new file mode 100644 index 000000000..214d76c79 --- /dev/null +++ b/themes/default/Wikiwyg/Selection.htc @@ -0,0 +1,78 @@ + + + + + + diff --git a/themes/default/Wikiwyg/Wikiwyg.js b/themes/default/Wikiwyg/Wikiwyg.js new file mode 100644 index 000000000..88c05088b --- /dev/null +++ b/themes/default/Wikiwyg/Wikiwyg.js @@ -0,0 +1,491 @@ +/*============================================================================== +Wikiwyg - Turn any HTML div into a wikitext /and/ wysiwyg edit area. + +DESCRIPTION: + +Wikiwyg is a Javascript library that can be easily integrated into any +wiki or blog software. It offers the user multiple ways to edit/view a +piece of content: Wysiwyg, Wikitext, Raw-HTML and Preview. + +The library is easy to use, completely object oriented, configurable and +extendable. + +See the Wikiwyg documentation for details. + +AUTHORS: + + Brian Ingerson + Casey West + Chris Dent + Matt Liggett + Ryan King + Dave Rolsky + +COPYRIGHT: + + Copyright (c) 2005 Socialtext Corporation + 655 High Street + Palo Alto, CA 94301 U.S.A. + All rights reserved. + +Wikiwyg is free software. + +This library is free software; you can redistribute it and/or modify it +under the terms of the GNU Lesser General Public License as published by +the Free Software Foundation; either version 2.1 of the License, or (at +your option) any later version. + +This library is distributed in the hope that it will be useful, but +WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser +General Public License for more details. + + http://www.gnu.org/copyleft/lesser.txt + + =============================================================================*/ + +/*============================================================================== +Subclass - this can be used to create new classes + =============================================================================*/ + +Subclass = function(name, base) { + if (!name) die("Can't create a subclass without a name"); + + var parts = name.split('.'); + var subclass = window; + for (var i = 0; i < parts.length; i++) { + if (! subclass[parts[i]]) + subclass[parts[i]] = function() {}; + subclass = subclass[parts[i]]; + } + + if (base) { + var baseclass = eval('new ' + base + '()'); + subclass.prototype = baseclass; + subclass.prototype.baseclass = base; + subclass.prototype.superfunc = Subclass.generate_superfunc(); + } + subclass.prototype.classname = name; + return subclass.prototype; +} + +Subclass.generate_superfunc = function() { + return function(func) { + var p; + for (var b = this.baseclass; b; b = p.baseclass) { + p = eval(b + '.prototype'); + if (p[func] && p[func] != this[func]) + return p[func]; + } + die( + "No superfunc function for: " + func + "\n" + + "baseclass was: " + this.baseclass + "\n" + + "caller was: " + arguments.callee.caller + ); + } +} + +/*============================================================================== +Wikiwyg - Primary Wikiwyg base class + =============================================================================*/ + +// Constructor and class methods +proto = new Subclass('Wikiwyg'); + +Wikiwyg.VERSION = '0.12'; + +// Browser support properties +Wikiwyg.ua = navigator.userAgent.toLowerCase(); +Wikiwyg.is_ie = ( + Wikiwyg.ua.indexOf("msie") != -1 && + Wikiwyg.ua.indexOf("opera") == -1 && + Wikiwyg.ua.indexOf("webtv") == -1 +); +Wikiwyg.is_gecko = ( + Wikiwyg.ua.indexOf('gecko') != -1 && + Wikiwyg.ua.indexOf('safari') == -1 +); +Wikiwyg.is_safari = ( + Wikiwyg.ua.indexOf('safari') != -1 +); +Wikiwyg.is_opera = ( + Wikiwyg.ua.indexOf('opera') != -1 +); +Wikiwyg.browserIsSupported = ( + Wikiwyg.is_gecko || + Wikiwyg.is_ie +); + +// Wikiwyg environment setup public methods +proto.createWikiwygArea = function(div, config) { + this.set_config(config); + this.initializeObject(div, config); +}; + +proto.config = { + javascriptLocation: 'lib/', + doubleClickToEdit: false, + toolbarClass: 'Wikiwyg.Toolbar', + modeClasses: [ + 'Wikiwyg.Wysiwyg', + 'Wikiwyg.Wikitext', + 'Wikiwyg.Preview' + ] +}; + +proto.initializeObject = function(div, config) { + if (! Wikiwyg.browserIsSupported) { + alert('Your browser is not supported yet. The toolbar will not be activated.') + return; + } + if (this.enabled) return; + this.enabled = true; + this.div = div; + this.divHeight = this.div.offsetHeight; + if (!config) config = {}; + + this.mode_objects = {}; + for (var i = 0; i < this.config.modeClasses.length; i++) { + var class_name = this.config.modeClasses[i]; + var mode_object = eval('new ' + class_name + '()'); + mode_object.wikiwyg = this; + mode_object.set_config(config[mode_object.classtype]); + mode_object.initializeObject(); + this.mode_objects[class_name] = mode_object; + if (! this.first_mode) { + this.first_mode = mode_object; + } + } + + if (this.config.toolbarClass) { + var class_name = this.config.toolbarClass; + this.toolbarObject = eval('new ' + class_name + '()'); + this.toolbarObject.wikiwyg = this; + this.toolbarObject.set_config(config.toolbar); + this.toolbarObject.initializeObject(); + this.placeToolbar(this.toolbarObject.div); + } + + // These objects must be _created_ before the toolbar is created + // but _inserted_ after. + for (var i = 0; i < this.config.modeClasses.length; i++) { + var mode_class = this.config.modeClasses[i]; + var mode_object = this.mode_objects[mode_class]; + this.insert_div_before(mode_object.div); + } + + if (this.config.doubleClickToEdit) { + var self = this; + this.div.ondblclick = function() { self.editMode() }; + } +} + +proto.placeToolbar = function(div) { + this.insert_div_before(div); +} + +// Wikiwyg environment setup private methods +proto.set_config = function(user_config) { + for (var key in this.config) + if (user_config && user_config[key]) + this.config[key] = user_config[key]; + else if (this[key] != null) + this.config[key] = this[key]; +} + +proto.insert_div_before = function(div) { + div.style.display = 'none'; + if (! div.iframe_hack) { + this.div.parentNode.insertBefore(div, this.div); + } +} + +// Wikiwyg actions - public interface methods +proto.saveChanges = function() { + alert('Wikiwyg.prototype.saveChanges not subclassed'); +} + +// Wikiwyg actions - public methods +proto.editMode = function() { // See IE, below + this.current_mode = this.first_mode; + //this.current_mode.fromHtml(this.div.innerHTML); + this.current_mode.fromWikitext(this.div.value); + this.toolbarObject.resetModeSelector(); + this.current_mode.enableThis(); +} + +proto.displayMode = function() { + for (var i = 0; i < this.config.modeClasses.length; i++) { + var mode_class = this.config.modeClasses[i]; + var mode_object = this.mode_objects[mode_class]; + mode_object.disableThis(); + } + this.toolbarObject.disableThis(); + this.div.style.display = 'block'; + this.divHeight = this.div.offsetHeight; +} + +proto.switchMode = function(new_mode_key) { + var new_mode = this.mode_objects[new_mode_key]; + var old_mode = this.current_mode; + + if( new_mode == old_mode) + return; + + var self = this; + new_mode.enableStarted(); + old_mode.disableStarted(); + old_mode.toHtml( + function(html) { + self.previous_mode = old_mode; + new_mode.fromHtml(html); + old_mode.disableThis(); + new_mode.enableThis(); + new_mode.enableFinished(); + old_mode.disableFinished(); + self.current_mode = new_mode; + } + ); +} + +proto.cancelEdit = function() { + this.displayMode(); +} + +proto.fromHtml = function(html) { + this.div.innerHTML = html; +} + +// Class level helper methods +Wikiwyg.unique_id_base = 0; +Wikiwyg.createUniqueId = function() { + return 'wikiwyg_' + Wikiwyg.unique_id_base++; +} + +Wikiwyg.liveUpdate = function(method, url, query, callback) { + var req = new XMLHttpRequest(); + var data = null; + if (method == 'GET') + url = url + '?' + query; + else + data = query; + req.open(method, url); + req.onreadystatechange = function() { + if (req.readyState == 4 && req.status == 200) + callback(req.responseText); + } + if (method == 'POST') { + req.setRequestHeader( + 'Content-Type', + 'application/x-www-form-urlencoded' + ); + } + req.send(data); +} + +Wikiwyg.htmlUnescape = function(escaped) { + // XXX Need a better way to unescape all entities + return escaped + .replace(/&/g, '&') + .replace(/</g, '<') + .replace(/>/g, '>'); +} + +Wikiwyg.showById = function(id) { + document.getElementById(id).style.visibility = 'inherit'; +} + +Wikiwyg.hideById = function(id) { + document.getElementById(id).style.visibility = 'hidden'; +} + + +Wikiwyg.changeLinksMatching = function(attribute, pattern, func) { + var links = document.getElementsByTagName('a'); + for (var i = 0; i < links.length; i++) { + var link = links[i]; + var my_attribute = link.getAttribute(attribute); + if (my_attribute && my_attribute.match(pattern)) { + link.setAttribute('href', '#'); + link.onclick = func; + } + } +} + +Wikiwyg.createElementWithAttrs = function(element, attrs, doc) { + if (doc == null) + doc = document; + return Wikiwyg.create_element_with_attrs(element, attrs, doc); +} + +// See IE, below +Wikiwyg.create_element_with_attrs = function(element, attrs, doc) { + var elem = doc.createElement(element); + for (name in attrs) + elem.setAttribute(name, attrs[name]); + return elem; +} + +die = function(e) { // See IE, below + throw(e); +} + +String.prototype.times = function(n) { + return n ? this + this.times(n-1) : ""; +} + +/*============================================================================== +Base class for Wikiwyg classes + =============================================================================*/ +proto = new Subclass('Wikiwyg.Base'); + +proto.set_config = function(user_config) { + for (var key in this.config) { + if (user_config != null && user_config[key] != null) + this.merge_config(key, user_config[key]); + else if (this[key] != null) + this.merge_config(key, this[key]); + else if (this.wikiwyg.config[key] != null) + this.merge_config(key, this.wikiwyg.config[key]); + } +} + +proto.merge_config = function(key, value) { + if (value instanceof Array) { + this.config[key] = value; + } + // cross-browser RegExp object check + else if (typeof value.test == 'function') { + this.config[key] = value; + } + else if (value instanceof Object) { + if (!this.config[key]) + this.config[key] = {}; + for (var subkey in value) { + this.config[key][subkey] = value[subkey]; + } + } + else { + this.config[key] = value; + } +} + +/*============================================================================== +Base class for Wikiwyg Mode classes + =============================================================================*/ +proto = new Subclass('Wikiwyg.Mode', 'Wikiwyg.Base'); + +proto.enableThis = function() { + this.div.style.display = 'block'; + this.display_unsupported_toolbar_buttons('none'); + this.wikiwyg.toolbarObject.enableThis(); + this.wikiwyg.div.style.display = 'none'; +} + +proto.display_unsupported_toolbar_buttons = function(display) { + if (!this.config) return; + var disabled = this.config.disabledToolbarButtons; + if (!disabled || disabled.length < 1) return; + + var toolbar_div = this.wikiwyg.toolbarObject.div; + var toolbar_buttons = toolbar_div.childNodes; + for (var i in disabled) { + var action = disabled[i]; + + for (var i in toolbar_buttons) { + var button = toolbar_buttons[i]; + var src = button.src; + if (!src) continue; + + if (src.match(action)) { + button.style.display = display; + break; + } + } + } +} + +proto.enableStarted = function() {} +proto.enableFinished = function() {} +proto.disableStarted = function() {} +proto.disableFinished = function() {} + +proto.disableThis = function() { + this.display_unsupported_toolbar_buttons('inline'); + this.div.style.display = 'none'; +} + +proto.process_command = function(command) { + if (this['do_' + command]) + this['do_' + command](command); +} + +proto.enable_keybindings = function() { // See IE + if (!this.key_press_function) { + this.key_press_function = this.get_key_press_function(); + this.get_keybinding_area().addEventListener( + 'keypress', this.key_press_function, true + ); + } +} + +proto.get_key_press_function = function() { + var self = this; + return function(e) { + if (! e.ctrlKey) return; + var key = String.fromCharCode(e.charCode).toLowerCase(); + var command = ''; + switch (key) { + case 'b': command = 'bold'; break; + case 'i': command = 'italic'; break; + case 'u': command = 'underline'; break; + case 'd': command = 'strike'; break; + case 'l': command = 'link'; break; + }; + + if (command) { + e.preventDefault(); + e.stopPropagation(); + self.process_command(command); + } + }; +} + +proto.get_edit_height = function() { + var height = parseInt( + this.wikiwyg.divHeight * + this.config.editHeightAdjustment + ); + var min = this.config.editHeightMinimum; + return height < min + ? min + : height; +} + +proto.setHeightOf = function(elem) { + elem.height = this.get_edit_height() + 'px'; +} + +/*============================================================================== +Support for Internet Explorer in Wikiwyg + =============================================================================*/ +if (Wikiwyg.is_ie) { + +Wikiwyg.create_element_with_attrs = function(element, attrs, doc) { + var str = ''; + // Note the double-quotes (make sure your data doesn't use them): + for (name in attrs) + str += ' ' + name + '="' + attrs[name] + '"'; + return doc.createElement('<' + element + str + '>'); +} + +die = function(e) { + alert(e); + throw(e); +} + +proto = Wikiwyg.Mode.prototype; + +proto.enable_keybindings = function() {} + +} // end of global if statement for IE overrides diff --git a/themes/default/Wikiwyg/Wikiwyg/Debug.js b/themes/default/Wikiwyg/Wikiwyg/Debug.js new file mode 100644 index 000000000..832e9e0b8 --- /dev/null +++ b/themes/default/Wikiwyg/Wikiwyg/Debug.js @@ -0,0 +1,60 @@ +/*============================================================================== +This Wikiwyg mode supports a textarea editor with toolbar buttons. + +COPYRIGHT: + + Copyright (c) 2005 Socialtext Corporation + 655 High Street + Palo Alto, CA 94301 U.S.A. + All rights reserved. + +Wikiwyg is free software. + +This library is free software; you can redistribute it and/or modify it +under the terms of the GNU Lesser General Public License as published by +the Free Software Foundation; either version 2.1 of the License, or (at +your option) any later version. + +This library is distributed in the hope that it will be useful, but +WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser +General Public License for more details. + + http://www.gnu.org/copyleft/lesser.txt + + =============================================================================*/ + +(function() { + +new Subclass('XXX'); +var klass = XXX; + +klass.sort_object_keys = function(o) { + var a = []; + for (p in o) a.push(p); + return a.sort(); +} + +klass.dump_keys = function(o) { + var a = klass.sort_object_keys(o); + var str=''; + for (p in a) + str += a[p] + "\t"; + alert(str); +} + +klass.dump_object_into_screen = function(o) { + var a = klass.sort_object_keys(o); + var str=''; + for (p in a) { + var i = a[p]; + try { + str += a[p] + ': ' + o[i] + '\n'; + } catch(e) { + // alert('Died on key "' + i + '":\n' + e.message); + } + } + document.write('' + str + ''); +} + +})(); diff --git a/themes/default/Wikiwyg/Wikiwyg/HTML.js b/themes/default/Wikiwyg/Wikiwyg/HTML.js new file mode 100644 index 000000000..3a6741681 --- /dev/null +++ b/themes/default/Wikiwyg/Wikiwyg/HTML.js @@ -0,0 +1,53 @@ + +/*============================================================================== +This Wikiwyg mode supports a simple HTML editor + +COPYRIGHT: + + Copyright (c) 2005 Socialtext Corporation + 655 High Street + Palo Alto, CA 94301 U.S.A. + All rights reserved. + +Wikiwyg is free software. + +This library is free software; you can redistribute it and/or modify it +under the terms of the GNU Lesser General Public License as published by +the Free Software Foundation; either version 2.1 of the License, or (at +your option) any later version. + +This library is distributed in the hope that it will be useful, but +WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser +General Public License for more details. + + http://www.gnu.org/copyleft/lesser.txt + + =============================================================================*/ + +proto = new Subclass('Wikiwyg.HTML', 'Wikiwyg.Mode'); + +proto.classtype = 'html'; +proto.modeDescription = 'HTML'; + +proto.initializeObject = function() { + this.div = document.createElement('div'); + this.textarea = document.createElement('textarea'); + this.div.appendChild(this.textarea); +} + +proto.enableThis = function() { + this.superfunc('enableThis').call(this); + this.textarea.style.width = '100%'; + this.textarea.style.height = '200px'; +} + +proto.fromHtml = function(html) { + this.textarea.value = html; +} + +proto.toHtml = function(func) { + func(this.textarea.value); +} + +proto.process_command = function(command) {}; diff --git a/themes/default/Wikiwyg/Wikiwyg/Phpwiki.js b/themes/default/Wikiwyg/Wikiwyg/Phpwiki.js new file mode 100755 index 000000000..27b8f8fcd --- /dev/null +++ b/themes/default/Wikiwyg/Wikiwyg/Phpwiki.js @@ -0,0 +1,488 @@ +/*============================================================================== + + * Copyright(c) STMicroelectronics, 2006 + * + * Originally written by Jean-Nicolas GEREONE, STMicroelectronics, 2006. + +COPYRIGHT: + + Copyright (c) 2005 Socialtext Corporation + 655 High Street + Palo Alto, CA 94301 U.S.A. + All rights reserved. + +Wikiwyg is free software. + +This library is free software; you can redistribute it and/or modify it +under the terms of the GNU Lesser General Public License as published by +the Free Software Foundation; either version 2.1 of the License, or (at +your option) any later version. + +This library is distributed in the hope that it will be useful, but +WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser +General Public License for more details. + + http://www.gnu.org/copyleft/lesser.txt + + =============================================================================*/ + +var wikiwyg_divs = []; + +proto = new Subclass('Wikiwyg.Phpwiki', 'Wikiwyg'); + +proto.submit_action_form = function(action, value) { + this.div.value = value; +} + +// Convert to wikitext mode if needed +// and save changes in the textarea of phpwiki +proto.saveChanges = function() { + + var self = this; + var submit_changes = function(wikitext) { + self.submit_action_form( + 'wikiwyg_save_wikitext',wikitext + ); + } + // var self = this; + if (this.current_mode.classname.match(/(Wysiwyg|Preview)/)) { + this.current_mode.toHtml( + function(html) { + var wikitext_mode = self.mode_objects['Wikiwyg.Wikitext.Phpwiki']; + wikitext_mode.convertHtmlToWikitext( + html, + function(wikitext) { submit_changes(wikitext) } + ); + } + ); + } + else { + submit_changes(this.current_mode.toWikitext()); + } +} + +proto.modeClasses = [ + 'Wikiwyg.Wikitext.Phpwiki', + 'Wikiwyg.Wysiwyg' + // 'Wikiwyg.HTML' +]; + +proto.call_action = function(action, content, func) { + var postdata = 'action=wikitohtml' + + '&content=' + encodeURIComponent(content); + Wikiwyg.liveUpdate( + 'POST', + script_url, + postdata, + func + ); +} + +proto = new Subclass('Wikiwyg.Wikitext.Phpwiki', 'Wikiwyg.Wikitext'); + +proto.convertWikitextToHtml = function(wikitext, func) { + this.wikiwyg.call_action('wikiwyg_wikitext_to_html', wikitext, func); +} + +proto.markupRules = { + link: ['bound_phrase', '[', ']'], + bold: ['bound_phrase', '', ''], + italic: ['bound_phrase', '', ''], + underline: ['bound_phrase', '', ''], + strike: ['bound_phrase', '', ''], + pre: ['bound_phrase', '\n\n
\n', '\n
\n'], + h2: ['start_line', '!!! '], + h3: ['start_line', '!! '], + h4: ['start_line', '! '], + ordered: ['start_lines', '#'], + unordered: ['start_lines', '*'], + indent: ['start_lines', ' '], + hr: ['line_alone', '----'], + table: ['line_alone', 'A |\n B |\n C\n |\n |\n \n |\n |\n \n'], + link: ['bound_phrase', '[ Name of the link | ', ' ]' ], + verbatim: ['bound_phrase', '\n','\n\n'], + richtable:['line_alone', + ''] +}; + +/*============================================================================== +Code to convert from html to wikitext. Hack for phpwiki and IE + =============================================================================*/ +proto.convert_html_to_wikitext = function(html) { + this.copyhtml = html; + var dom = document.createElement('div'); + html = html.replace(//g, '-->'); + + // Change * to ~* for phpwiki + html = html.replace(/\*/g,'~*'); + // Change _ to ~_ for phpwiki + html = html.replace(/\_/g,'~_'); + + // Hack for IE + // convert

 

into  ( unknown char :) + html = html.replace(/\ /g,''); + + dom.innerHTML = html; + this.output = []; + this.list_type = []; + this.indent_level = 0; + + this.walk(dom); + + // add final whitespace + this.assert_new_line(); + + return this.join_output(this.output); +} + +/*============================================================================== +Code to convert from html to wikitext. + =============================================================================*/ + +/*============================================================================== +[Wikitext.js] Support of Headings in phpwiki + =============================================================================*/ + +// Adding match headings : '!', for phpwiki. +proto.add_markup_lines = function(markup_start) { + var already_set_re = new RegExp( '^' + this.clean_regexp(markup_start), 'gm'); + var other_markup_re = /^(\^+|\=+|\*+|#+|>+|!+| )/gm; + + var match; + // if paragraph, reduce everything. + if (! markup_start.length) { + this.sel = this.sel.replace(other_markup_re, ''); + this.sel = this.sel.replace(/^\ +/gm, ''); + } + // if pre and not all indented, indent + else if ((markup_start == ' ') && this.sel.match(/^\S/m)) + this.sel = this.sel.replace(/^/gm, markup_start); + // if not requesting heading and already this style, kill this style + else if ( + (! markup_start.match(/[\!\^]/)) && + this.sel.match(already_set_re) + ) { + this.sel = this.sel.replace(already_set_re, ''); + if (markup_start != ' ') + this.sel = this.sel.replace(/^ */gm, ''); + } + // if some other style, switch to new style + else if (match = this.sel.match(other_markup_re)) + // if pre, just indent + if (markup_start == ' ') + this.sel = this.sel.replace(/^/gm, markup_start); + // if heading, just change it + else if (markup_start.match(/[\!\^]/)) + this.sel = this.sel.replace(other_markup_re, markup_start); + // else try to change based on level + else + this.sel = this.sel.replace( + other_markup_re, + function(match) { + return markup_start.times(match.length); + } + ); + // if something selected, use this style + else if (this.sel.length > 0) + this.sel = this.sel.replace(/^(.*\S+)/gm, markup_start + ' $1'); + // just add the markup + else + this.sel = markup_start + ' '; + + var text = this.start + this.sel + this.finish; + var start = this.selection_start; + var end = this.selection_start + this.sel.length; + this.set_text_and_selection(text, start, end); + this.area.focus(); +} + +/*============================================================================== +End Hack for headings in phpwiki + =============================================================================*/ + + +/*============================================================================== +Support for incremental numbers : +When there is +# list1 +## list 2 +phpwiki convert it with a

element inside the

  • element +So the

    element have to be ignored + =============================================================================*/ + +proto.format_p = function(element) { + + // Hack to avoid \n to be inserted if an li element is parent + if( element.parentNode.nodeType == '1' + && element.parentNode.nodeName.toLowerCase() == "li") { + this.walk(element); + } + else { + var style = element.getAttribute('style','true'); + if ( style ) { + if ( !Wikiwyg.is_ie ) { + this.assert_blank_line(); + this.assert_space_or_newline(); + if (style.match(/\bbold\b/)) + this.appendOutput(this.config.markupRules.bold[1]); + if (style.match(/\bitalic\b/)) + this.appendOutput(this.config.markupRules.italic[1]); + if (style.match(/\bunderline\b/)) + this.appendOutput(this.config.markupRules.underline[1]); + if (style.match(/\bline-through\b/)) + this.appendOutput(this.config.markupRules.strike[1]); + + this.no_following_whitespace(); + this.walk(element); + + if (style.match(/\bline-through\b/)) + this.appendOutput(this.config.markupRules.strike[2]); + if (style.match(/\bunderline\b/)) + this.appendOutput(this.config.markupRules.underline[2]); + if (style.match(/\bitalic\b/)) + this.appendOutput(this.config.markupRules.italic[2]); + if (style.match(/\bbold\b/)) + this.appendOutput(this.config.markupRules.bold[2]); + + this.assert_blank_line(); + } // end if(!is_ie) + else{ + this.assert_blank_line(); + this.walk(element); + this.assert_blank_line(); + } + } // end if (style) + else { + this.assert_blank_line(); + this.walk(element); + this.assert_blank_line(); + } + } +} + + +/*============================================================================== +End Support for incremental numbers + =============================================================================*/ + +/*============================================================================== +Support for
    tag + =============================================================================*/ + + proto.format_br = function(element) { + this.assert_new_line(); + } + +/*============================================================================== +End Support for
    tag + =============================================================================*/ + + +/*============================================================================== +Support for links in phpwiki + =============================================================================*/ + +proto.make_wikitext_link = function(label, href, element) { + + // comes with label = ? + // element = anchor element + + // href have the link + + // come here with phpwiki conversion of the link + // So this.output contains something like : + // [....,,object,label,] + + //alert(' in link'); + + var before = '['; + var after = ']'; + + // XXX Hack to remove and on the label name + // because phpwiki convert links in : + // label ? + + //alert('before ?'); + + if (label == '?') { + // Verify if the output poped is + + //alert(' ? found '); + + if ( this.output[this.output.length-1] == '' ) { + //alert(' found'); + + // removed_u1 is and have to be removed + var removed_u1 = this.output.pop(); + + // XXX Verify if the output poped is text ( => =textnode => 3) + var oldlabel = label; + label = this.output.pop(); + + // XXX Verify if the output poped is ... an object ? + var object = this.output.pop(); + + //Verify if the output poped is + if ( this.output[this.output.length-1] == '' ) { + var removed_u2 = this.output.pop(); + + } + // If not found + // the ouput will be restored + else { + alert('Error : not found in the link'); + this.appendOutput(removed_u2); + this.appendOutput(object); + this.appendOutput(oldlabel); + this.appendOutput(removed_u1); + } + } + } + + // XXX If the link really have a '?' + // if the link cointains ? + // it takes the first part + if ( href.match(/\?/) ) + href = href.split('?')[0]; + + // alert('label '+label ); + // alert('href '+href); + + this.assert_space_or_newline(); + if (! href) { + this.appendOutput(before + label + after); + } + else if (href == label) { + if (this.camel_case_link(label)) + this.appendOutput(label); + else + this.appendOutput(before + href + after); + } + else if (this.href_is_wiki_link(href)) { + if (this.camel_case_link(label)) + this.appendOutput(label); + else + this.appendOutput(before + label + '|' + href + after); + } + else { + this.appendOutput(before + label + '|' + href + after); + } +} + +// IE support of links +proto.format_span = function(element) { + if (this.is_opaque(element)) { + this.handle_opaque_phrase(element); + return; + } + + var style = element.getAttribute('style','true'); + + if (!style ) { + this.pass(element); + return; + } + + if ( !Wikiwyg.is_ie ) { + + this.assert_space_or_newline(); + if (style.match(/\bbold\b/)) + this.appendOutput(this.config.markupRules.bold[1]); + if (style.match(/\bitalic\b/)) + this.appendOutput(this.config.markupRules.italic[1]); + if (style.match(/\bunderline\b/)) + this.appendOutput(this.config.markupRules.underline[1]); + if (style.match(/\bline-through\b/)) + this.appendOutput(this.config.markupRules.strike[1]); + + } + + this.no_following_whitespace(); + this.walk(element); + + + if ( !Wikiwyg.is_ie ) { + + if (style.match(/\bline-through\b/)) + this.appendOutput(this.config.markupRules.strike[2]); + if (style.match(/\bunderline\b/)) + this.appendOutput(this.config.markupRules.underline[2]); + if (style.match(/\bitalic\b/)) + this.appendOutput(this.config.markupRules.italic[2]); + if (style.match(/\bbold\b/)) + this.appendOutput(this.config.markupRules.bold[2]); + } +} + +/*============================================================================== +End Support for links in phpwiki + =============================================================================*/ + + +/*============================================================================== +Support for plugin RichTable in phpwiki + =============================================================================*/ + +proto.format_table = function(element) { + this.assert_blank_line(); + this.appendOutput(' \n\n'); + this.assert_blank_line(); +} + +proto.format_tr = function(element) { + this.appendOutput('-\n'); + this.walk(element); +} + +proto.format_td = function(element) { + this.appendOutput('|'); + this.walk(element); + this.appendOutput('\n'); +} + +proto.format_th = function(element) { + this.appendOutput('|'); + this.walk(element); + this.appendOutput(' \n'); +} + +/*============================================================================== +END RichTable + =============================================================================*/ + +proto.do_verbatim = Wikiwyg.Wikitext.make_do('verbatim'); +proto.do_line_break = Wikiwyg.Wikitext.make_do('line_break'); +proto.do_richtable = Wikiwyg.Wikitext.make_do('richtable'); + +proto = new Subclass('Wikiwyg.Preview.phpwiki', 'Wikiwyg.Preview'); + +proto.fromHtml = function(html) { + if (this.wikiwyg.previous_mode.classname.match(/(Wysiwyg|HTML)/)) { + var wikitext_mode = this.wikiwyg.mode_objects['Wikiwyg.Wikitext.phpwiki']; + var self = this; + wikitext_mode.convertWikitextToHtml( + wikitext_mode.convert_html_to_wikitext(html), + function(new_html) { self.div.innerHTML = new_html } + ); + } + else { + this.div.innerHTML = html; + } +} + +/*============================================================================== +Support for Internet Explorer in Wikiwyg + =============================================================================*/ +if (Wikiwyg.is_ie) { + +if (window.ActiveXObject && !window.XMLHttpRequest) { + window.XMLHttpRequest = function() { + return new ActiveXObject((navigator.userAgent.toLowerCase().indexOf('msie 5') != -1) ? 'Microsoft.XMLHTTP' : 'Msxml2.XMLHTTP'); + }; +} + +} // end of global if statement for IE overrides diff --git a/themes/default/Wikiwyg/Wikiwyg/Preview.js b/themes/default/Wikiwyg/Wikiwyg/Preview.js new file mode 100644 index 000000000..8bb1a3db9 --- /dev/null +++ b/themes/default/Wikiwyg/Wikiwyg/Preview.js @@ -0,0 +1,48 @@ +/*============================================================================== +This Wikiwyg mode supports a preview of current changes + +COPYRIGHT: + + Copyright (c) 2005 Socialtext Corporation + 655 High Street + Palo Alto, CA 94301 U.S.A. + All rights reserved. + +Wikiwyg is free software. + +This library is free software; you can redistribute it and/or modify it +under the terms of the GNU Lesser General Public License as published by +the Free Software Foundation; either version 2.1 of the License, or (at +your option) any later version. + +This library is distributed in the hope that it will be useful, but +WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser +General Public License for more details. + + http://www.gnu.org/copyleft/lesser.txt + + =============================================================================*/ + +proto = new Subclass('Wikiwyg.Preview', 'Wikiwyg.Mode'); + +proto.classtype = 'preview'; +proto.modeDescription = 'Preview'; + +proto.initializeObject = function() { + this.div = document.createElement('div'); + // XXX Make this a config option. + this.div.style.backgroundColor = 'lightyellow'; +} + +proto.fromHtml = function(html) { + this.div.innerHTML = html; +} + +proto.toHtml = function(func) { + func(this.div.innerHTML); +} + +proto.disableStarted = function() { + this.wikiwyg.divHeight = this.div.offsetHeight; +} diff --git a/themes/default/Wikiwyg/Wikiwyg/Toolbar.js b/themes/default/Wikiwyg/Wikiwyg/Toolbar.js new file mode 100644 index 000000000..f443e7ca9 --- /dev/null +++ b/themes/default/Wikiwyg/Wikiwyg/Toolbar.js @@ -0,0 +1,285 @@ +/*============================================================================== +This Wikiwyg class provides toolbar support + +COPYRIGHT: + + Copyright (c) 2005 Socialtext Corporation + 655 High Street + Palo Alto, CA 94301 U.S.A. + All rights reserved. + +Wikiwyg is free software. + +This library is free software; you can redistribute it and/or modify it +under the terms of the GNU Lesser General Public License as published by +the Free Software Foundation; either version 2.1 of the License, or (at +your option) any later version. + +This library is distributed in the hope that it will be useful, but +WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser +General Public License for more details. + + http://www.gnu.org/copyleft/lesser.txt + + =============================================================================*/ + +proto = new Subclass('Wikiwyg.Toolbar', 'Wikiwyg.Base'); +proto.classtype = 'toolbar'; + +proto.config = { + imagesLocation: 'images/', + imagesExtension: '.gif', + controlLayout: [ + 'save', 'cancel', 'mode_selector', '/', + 'selector', + 'h1', 'h2', 'h3', 'h4', 'p', 'pre', '|', + 'bold', 'italic', 'underline', 'strike', '|', + 'link', 'hr', '|', + 'ordered', 'unordered', '|', + 'indent', 'outdent', '|', + 'table', '|', + 'help' + ], + styleSelector: [ + 'label', 'p', 'h1', 'h2', 'h3', 'h4', 'h5', 'h6', 'pre' + ], + controlLabels: { + save: 'Save', + cancel: 'Cancel', + bold: 'Bold (ctl-b)', + italic: 'Italic (ctl-i)', + underline: 'Underline (ctl-u)', + strike: 'Strike Through (ctl-d)', + hr: 'Horizontal Rule', + ordered: 'Numbered List', + unordered: 'Bulleted List', + indent: 'More Indented', + outdent: 'Less Indented', + help: 'About Wikiwyg', + label: '[Style]', + p: 'Normal Text', + pre: 'Preformatted', + h1: 'Heading 1', + h2: 'Heading 2', + h3: 'Heading 3', + h4: 'Heading 4', + h5: 'Heading 5', + h6: 'Heading 6', + link: 'Create Link', + table: 'Create Table' + } +}; + +proto.initializeObject = function() { + this.div = Wikiwyg.createElementWithAttrs( + 'div', { + 'class': 'wikiwyg_toolbar', + id: 'wikiwyg_toolbar' + } + ); + + var config = this.config; + for (var i = 0; i < config.controlLayout.length; i++) { + var action = config.controlLayout[i]; + var label = config.controlLabels[action] + if (action == 'save') + this.addControlItem(label, 'saveChanges'); + else if (action == 'cancel') + this.addControlItem(label, 'cancelEdit'); + else if (action == 'mode_selector') + this.addModeSelector(); + else if (action == 'selector') + this.add_styles(); + else if (action == 'help') + this.add_help_button(action, label); + else if (action == '|') + this.add_separator(); + else if (action == '/') + this.add_break(); + else + this.add_button(action, label); + } +} + +proto.enableThis = function() { + this.div.style.display = 'block'; +} + +proto.disableThis = function() { + this.div.style.display = 'none'; +} + +proto.make_button = function(type, label) { + var base = this.config.imagesLocation; + var ext = this.config.imagesExtension; + return Wikiwyg.createElementWithAttrs( + 'img', { + 'class': 'wikiwyg_button', + onmouseup: "this.style.border='1px outset';", + onmouseover: "this.style.border='1px outset';", + onmouseout: + "this.style.borderColor=this.style.backgroundColor;" + + "this.style.borderStyle='solid';", + onmousedown: "this.style.border='1px inset';", + alt: label, + title: label, + src: base + type + ext + } + ); +} + +proto.add_button = function(type, label) { + var img = this.make_button(type, label); + var self = this; + img.onclick = function() { + self.wikiwyg.current_mode.process_command(type); + }; + this.div.appendChild(img); +} + +proto.add_help_button = function(type, label) { + var img = this.make_button(type, label); + var a = Wikiwyg.createElementWithAttrs( + 'a', { + target: 'wikiwyg_button', + href: 'http://www.wikiwyg.net/about/' + } + ); + a.appendChild(img); + this.div.appendChild(a); +} + +proto.add_separator = function() { + var base = this.config.imagesLocation; + var ext = this.config.imagesExtension; + this.div.appendChild( + Wikiwyg.createElementWithAttrs( + 'img', { + 'class': 'wikiwyg_separator', + alt: ' | ', + title: '', + src: base + 'separator' + ext + } + ) + ); +} + +proto.addControlItem = function(text, method) { + var span = Wikiwyg.createElementWithAttrs( + 'span', { 'class': 'wikiwyg_control_link' } + ); + + var link = Wikiwyg.createElementWithAttrs( + 'a', { href: '#' } + ); + link.innerHTML = text; + span.appendChild(link); + + var self = this; + link.onclick = function() { eval('self.wikiwyg.' + method + '()'); return false }; + + + // XXX Hack to auto-save wikitext on mouse move + this.div.ownerDocument.onmousemove = function() { + self.wikiwyg.saveChanges(); + } + + this.div.appendChild(span); +} + +proto.resetModeSelector = function() { + if (this.firstModeRadio) { + var temp = this.firstModeRadio.onclick; + this.firstModeRadio.onclick = null; + this.firstModeRadio.click(); + this.firstModeRadio.onclick = temp; + } +} + +proto.addModeSelector = function() { + var span = document.createElement('span'); + + var radio_name = Wikiwyg.createUniqueId(); + for (var i = 0; i < this.wikiwyg.config.modeClasses.length; i++) { + var class_name = this.wikiwyg.config.modeClasses[i]; + var mode_object = this.wikiwyg.mode_objects[class_name]; + + var radio_id = Wikiwyg.createUniqueId(); + + var checked = i == 0 ? 'checked' : ''; + if ( i==0 ) + var radio = Wikiwyg.createElementWithAttrs( + 'input', { + type: 'radio', + name: radio_name, + id: radio_id, + value: mode_object.classname, + 'checked': checked + } + ); + else + var radio = Wikiwyg.createElementWithAttrs( + 'input', { + type: 'radio', + name: radio_name, + id: radio_id, + value: mode_object.classname + } + ); + + if (!this.firstModeRadio) + this.firstModeRadio = radio; + + var self = this; + radio.onclick = function() { + self.wikiwyg.switchMode(this.value); + }; + + var label = Wikiwyg.createElementWithAttrs( + 'label', { 'for': radio_id } + ); + label.innerHTML = mode_object.modeDescription; + + span.appendChild(radio); + span.appendChild(label); + } + this.div.appendChild(span); +} + +proto.add_break = function() { + this.div.appendChild(document.createElement('br')); +} + +proto.add_styles = function() { + var options = this.config.styleSelector; + var labels = this.config.controlLabels; + + this.styleSelect = Wikiwyg.createElementWithAttrs( + 'select', { + 'class': 'wikiwyg_selector' + } + ); + + for (var i = 0; i < options.length; i++) { + value = options[i]; + var option = Wikiwyg.createElementWithAttrs( + 'option', { 'value': value } + ); + option.textContent = labels[value]; + this.styleSelect.appendChild(option); + } + var self = this; + this.styleSelect.onchange = function() { + self.set_style(this.value) + }; + this.div.appendChild(this.styleSelect); +} + +proto.set_style = function(style_name) { + var idx = this.styleSelect.selectedIndex; + // First one is always a label + if (idx != 0) + this.wikiwyg.current_mode.process_command(style_name); + this.styleSelect.selectedIndex = 0; +} diff --git a/themes/default/Wikiwyg/Wikiwyg/Wikitext.js b/themes/default/Wikiwyg/Wikiwyg/Wikitext.js new file mode 100644 index 000000000..9871f2052 --- /dev/null +++ b/themes/default/Wikiwyg/Wikiwyg/Wikitext.js @@ -0,0 +1,1054 @@ +/*============================================================================== +This Wikiwyg mode supports a textarea editor with toolbar buttons. + +COPYRIGHT: + + Copyright (c) 2005 Socialtext Corporation + 655 High Street + Palo Alto, CA 94301 U.S.A. + All rights reserved. + +Wikiwyg is free software. + +This library is free software; you can redistribute it and/or modify it +under the terms of the GNU Lesser General Public License as published by +the Free Software Foundation; either version 2.1 of the License, or (at +your option) any later version. + +This library is distributed in the hope that it will be useful, but +WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser +General Public License for more details. + + http://www.gnu.org/copyleft/lesser.txt + + =============================================================================*/ + +proto = new Subclass('Wikiwyg.Wikitext', 'Wikiwyg.Mode'); +klass = Wikiwyg.Wikitext; + +proto.classtype = 'wikitext'; +proto.modeDescription = 'Wikitext'; + +proto.config = { + supportCamelCaseLinks: false, + javascriptLocation: null, + clearRegex: null, + editHeightMinimum: 10, + editHeightAdjustment: 1.3, + markupRules: { + link: ['bound_phrase', '[', ']'], + bold: ['bound_phrase', '*', '*'], + code: ['bound_phrase', '`', '`'], + italic: ['bound_phrase', '/', '/'], + underline: ['bound_phrase', '_', '_'], + strike: ['bound_phrase', '-', '-'], + p: ['start_lines', ''], + pre: ['start_lines', ' '], + h1: ['start_line', '= '], + h2: ['start_line', '== '], + h3: ['start_line', '=== '], + h4: ['start_line', '==== '], + h5: ['start_line', '===== '], + h6: ['start_line', '====== '], + ordered: ['start_lines', '#'], + unordered: ['start_lines', '*'], + indent: ['start_lines', '>'], + hr: ['line_alone', '----'], + table: ['line_alone', '| A | B | C |\n| | | |\n| | | |'] + } +} + +proto.initializeObject = function() { // See IE + this.initialize_object(); +} + +proto.initialize_object = function() { + this.div = document.createElement('div'); + this.textarea = document.createElement('textarea'); + this.textarea.setAttribute('id', 'wikiwyg_wikitext_textarea'); + this.div.appendChild(this.textarea); + this.area = this.textarea; + this.clear_inner_text(); +} + +proto.clear_inner_text = function() { + var self = this; + this.area.onclick = function() { + var inner_text = self.area.value; + var clear = self.config.clearRegex; + if (clear && inner_text.match(clear)) + self.area.value = ''; + } +} + +proto.enableThis = function() { + this.superfunc('enableThis').call(this); + this.textarea.style.width = '100%'; + this.setHeightOfEditor(); + this.enable_keybindings(); +} + +proto.setHeightOfEditor = function() { + var config = this.config; + var adjust = config.editHeightAdjustment; + var area = this.textarea; + var text = this.textarea.value; + var rows = text.split(/\n/).length; + + var height = parseInt(rows * adjust); + if (height < config.editHeightMinimum) + height = config.editHeightMinimum; + + area.setAttribute('rows', height); +} + +proto.toWikitext = function() { + return this.textarea.value; +} + +proto.toHtml = function(func) { + var wikitext = this.textarea.value; + this.convertWikitextToHtml(wikitext, func); +} + +proto.fromHtml = function(html) { + this.textarea.value = 'Loading...'; + var textarea = this.textarea; + this.convertHtmlToWikitext( + html, + function(value) { textarea.value = value } + ); +} + +proto.fromWikitext = function(html) { + this.textarea.value = html; +} + + +proto.convertWikitextToHtml = function(wikitext, func) { + alert('Wikitext changes cannot be converted to HTML\nWikiwyg.Wikitext.convertWikitextToHtml is not implemented here'); + func(this.copyhtml); +} + +proto.convertHtmlToWikitext = function(html, func) { + func(this.convert_html_to_wikitext(html)); +} + +proto.get_keybinding_area = function() { + return this.textarea; +} + +/*============================================================================== +Code to markup wikitext + =============================================================================*/ +Wikiwyg.Wikitext.phrase_end_re = /[\s\.\:\;\,\!\?\(\)]/; + +proto.find_left = function(t, selection_start, matcher) { + var substring = t.substr(selection_start - 1, 1); + var nextstring = t.substr(selection_start - 2, 1); + if (selection_start == 0) + return selection_start; + if (substring.match(matcher)) { + // special case for word.word + if ((substring != '.') || (nextstring.match(/\s/))) + return selection_start; + } + return this.find_left(t, selection_start - 1, matcher); +} + +proto.find_right = function(t, selection_end, matcher) { + var substring = t.substr(selection_end, 1); + var nextstring = t.substr(selection_end + 1, 1); + if (selection_end >= t.length) + return selection_end; + if (substring.match(matcher)) { + // special case for word.word + if ((substring != '.') || (nextstring.match(/\s/))) + return selection_end; + } + return this.find_right(t, selection_end + 1, matcher); +} + +proto.get_lines = function() { + t = this.area; + var selection_start = t.selectionStart; + var selection_end = t.selectionEnd; + + if (selection_start == null || selection_end == null) + return false + + var our_text = t.value.replace(/\r/g, ''); + selection = our_text.substr(selection_start, + selection_end - selection_start); + + selection_start = this.find_right(our_text, selection_start, /[^\r\n]/); + selection_end = this.find_left(our_text, selection_end, /[^\r\n]/); + + this.selection_start = this.find_left(our_text, selection_start, /[\r\n]/); + this.selection_end = this.find_right(our_text, selection_end, /[\r\n]/); + t.setSelectionRange(selection_start, selection_end); + t.focus(); + + this.start = our_text.substr(0,this.selection_start); + this.sel = our_text.substr(this.selection_start, this.selection_end - + this.selection_start); + this.finish = our_text.substr(this.selection_end, our_text.length); + + return true; +} + +proto.alarm_on = function() { + var area = this.area; + var background = area.style.background; + area.style.background = '#f88'; + + function alarm_off() { + area.style.background = background; + } + + window.setTimeout(alarm_off, 250); + area.focus() +} + +proto.get_words = function() { + function is_insane(selection) { + return selection.match(/\r?\n(\r?\n|\*+ |\#+ |\=+ )/); + } + + t = this.area; + var selection_start = t.selectionStart; + var selection_end = t.selectionEnd; + if (selection_start == null || selection_end == null) + return false; + + var our_text = t.value.replace(/\r/g, ''); + selection = our_text.substr(selection_start, + selection_end - selection_start); + + selection_start = this.find_right(our_text, selection_start, /(\S|\r?\n)/); + if (selection_start > selection_end) + selection_start = selection_end; + selection_end = this.find_left(our_text, selection_end, /(\S|\r?\n)/); + if (selection_end < selection_start) + selection_end = selection_start; + + if (is_insane(selection)) { + this.alarm_on(); + return false; + } + + this.selection_start = + this.find_left(our_text, selection_start, Wikiwyg.Wikitext.phrase_end_re); + this.selection_end = + this.find_right(our_text, selection_end, Wikiwyg.Wikitext.phrase_end_re); + + t.setSelectionRange(this.selection_start, this.selection_end); + t.focus(); + + this.start = our_text.substr(0,this.selection_start); + this.sel = our_text.substr(this.selection_start, this.selection_end - + this.selection_start); + this.finish = our_text.substr(this.selection_end, our_text.length); + + return true; +} + +proto.markup_is_on = function(start, finish) { + return (this.sel.match(start) && this.sel.match(finish)); +} + +proto.clean_selection = function(start, finish) { + this.sel = this.sel.replace(start, ''); + this.sel = this.sel.replace(finish, ''); +} + +proto.toggle_same_format = function(start, finish) { + start = this.clean_regexp(start); + finish = this.clean_regexp(finish); + var start_re = new RegExp('^' + start); + var finish_re = new RegExp(finish + '$'); + if (this.markup_is_on(start_re, finish_re)) { + this.clean_selection(start_re, finish_re); + return true; + } + return false; +} + +proto.clean_regexp = function(string) { + string = string.replace(/([\^\$\*\+\.\?\[\]\{\}])/g, '\\$1'); + return string; +} + +proto.set_text_and_selection = function(text, start, end) { + this.area.value = text; + this.area.setSelectionRange(start, end); +} + +proto.add_markup_words = function(markup_start, markup_finish, example) { + if (this.toggle_same_format(markup_start, markup_finish)) { + this.selection_end = this.selection_end - + (markup_start.length + markup_finish.length); + markup_start = ''; + markup_finish = ''; + } + if (this.sel.length == 0) { + if (example) + this.sel = example; + var text = this.start + markup_start + + this.sel + markup_finish + this.finish; + var start = this.selection_start + markup_start.length; + var end = this.selection_end + markup_start.length + this.sel.length; + this.set_text_and_selection(text, start, end); + } else { + var text = this.start + markup_start + this.sel + + markup_finish + this.finish; + var start = this.selection_start; + var end = this.selection_end + markup_start.length + + markup_finish.length; + this.set_text_and_selection(text, start, end); + } + this.area.focus(); +} + +// XXX - A lot of this is hardcoded. +proto.add_markup_lines = function(markup_start) { + var already_set_re = new RegExp( '^' + this.clean_regexp(markup_start), 'gm'); + var other_markup_re = /^(\^+|\=+|\*+|#+|>+| )/gm; + + var match; + // if paragraph, reduce everything. + if (! markup_start.length) { + this.sel = this.sel.replace(other_markup_re, ''); + this.sel = this.sel.replace(/^\ +/gm, ''); + } + // if pre and not all indented, indent + else if ((markup_start == ' ') && this.sel.match(/^\S/m)) + this.sel = this.sel.replace(/^/gm, markup_start); + // if not requesting heading and already this style, kill this style + else if ( + (! markup_start.match(/[\=\^]/)) && + this.sel.match(already_set_re) + ) { + this.sel = this.sel.replace(already_set_re, ''); + if (markup_start != ' ') + this.sel = this.sel.replace(/^ */gm, ''); + } + // if some other style, switch to new style + else if (match = this.sel.match(other_markup_re)) + // if pre, just indent + if (markup_start == ' ') + this.sel = this.sel.replace(/^/gm, markup_start); + // if heading, just change it + else if (markup_start.match(/[\=\^]/)) + this.sel = this.sel.replace(other_markup_re, markup_start); + // else try to change based on level + else + this.sel = this.sel.replace( + other_markup_re, + function(match) { + return markup_start.times(match.length); + } + ); + // if something selected, use this style + else if (this.sel.length > 0) + this.sel = this.sel.replace(/^(.*\S+)/gm, markup_start + ' $1'); + // just add the markup + else + this.sel = markup_start + ' '; + + var text = this.start + this.sel + this.finish; + var start = this.selection_start; + var end = this.selection_start + this.sel.length; + this.set_text_and_selection(text, start, end); + this.area.focus(); +} + +// XXX - A lot of this is hardcoded. +proto.bound_markup_lines = function(markup_array) { + var markup_start = markup_array[1]; + var markup_finish = markup_array[2]; + var already_start = new RegExp('^' + this.clean_regexp(markup_start), 'gm'); + var already_finish = new RegExp(this.clean_regexp(markup_finish) + '$', 'gm'); + var other_start = /^(\^+|\=+|\*+|#+|>+) */gm; + var other_finish = /( +(\^+|\=+))?$/gm; + + var match; + if (this.sel.match(already_start)) { + this.sel = this.sel.replace(already_start, ''); + this.sel = this.sel.replace(already_finish, ''); + } + else if (match = this.sel.match(other_start)) { + this.sel = this.sel.replace(other_start, markup_start); + this.sel = this.sel.replace(other_finish, markup_finish); + } + // if something selected, use this style + else if (this.sel.length > 0) { + this.sel = this.sel.replace( + /^(.*\S+)/gm, + markup_start + '$1' + markup_finish + ); + } + // just add the markup + else + this.sel = markup_start + markup_finish; + + var text = this.start + this.sel + this.finish; + var start = this.selection_start; + var end = this.selection_start + this.sel.length; + this.set_text_and_selection(text, start, end); + this.area.focus(); +} + +proto.markup_bound_line = function(markup_array) { + var scroll_top = this.area.scrollTop; + if (this.get_lines()) + this.bound_markup_lines(markup_array); + this.area.scrollTop = scroll_top; +} + +proto.markup_start_line = function(markup_array) { + var markup_start = markup_array[1]; + markup_start = markup_start.replace(/ +/, ''); + var scroll_top = this.area.scrollTop; + if (this.get_lines()) + this.add_markup_lines(markup_start); + this.area.scrollTop = scroll_top; +} + +proto.markup_start_lines = function(markup_array) { + var markup_start = markup_array[1]; + var scroll_top = this.area.scrollTop; + if (this.get_lines()) + this.add_markup_lines(markup_start); + this.area.scrollTop = scroll_top; +} + +proto.markup_bound_phrase = function(markup_array) { + var markup_start = markup_array[1]; + var markup_finish = markup_array[2]; + var scroll_top = this.area.scrollTop; + if (markup_finish == 'undefined') + markup_finish = markup_start; + if (this.get_words()) + this.add_markup_words(markup_start, markup_finish, null); + this.area.scrollTop = scroll_top; +} + +klass.make_do = function(style) { + return function() { + var markup = this.config.markupRules[style]; + var handler = markup[0]; + if (! this['markup_' + handler]) + die('No handler for markup: "' + handler + '"'); + this['markup_' + handler](markup); + } +} + +proto.do_link = klass.make_do('link'); +proto.do_bold = klass.make_do('bold'); +proto.do_code = klass.make_do('code'); +proto.do_italic = klass.make_do('italic'); +proto.do_underline = klass.make_do('underline'); +proto.do_strike = klass.make_do('strike'); +proto.do_p = klass.make_do('p'); +proto.do_pre = klass.make_do('pre'); +proto.do_h1 = klass.make_do('h1'); +proto.do_h2 = klass.make_do('h2'); +proto.do_h3 = klass.make_do('h3'); +proto.do_h4 = klass.make_do('h4'); +proto.do_h5 = klass.make_do('h5'); +proto.do_h6 = klass.make_do('h6'); +proto.do_ordered = klass.make_do('ordered'); +proto.do_unordered = klass.make_do('unordered'); +proto.do_hr = klass.make_do('hr'); +proto.do_table = klass.make_do('table'); + +proto.do_dent = function(method) { + var scroll_top = this.area.scrollTop; + if (! this.get_lines()) { + this.area.scrollTop = scroll_top; + return; + } + + if (method(this)) { + var text = this.start + this.sel + this.finish; + var start = this.selection_start; + var end = this.selection_start + this.sel.length; + this.set_text_and_selection(text, start, end); + } + this.area.focus(); +} + +proto.do_indent = function() { + this.do_dent( + function(that) { + if (that.sel == '') return false; + that.sel = that.sel.replace(/^(([\*\-\#])+(?=\s))/gm, '$2$1'); + that.sel = that.sel.replace(/^([\>\=])/gm, '$1$1'); + that.sel = that.sel.replace(/^([^\>\*\-\#\=\r\n])/gm, '> $1'); + that.sel = that.sel.replace(/^\={7,}/gm, '======'); + return true; + } + ) +} + +proto.do_outdent = function() { + this.do_dent( + function(that) { + if (that.sel == '') return false; + that.sel = that.sel.replace(/^([\>\*\-\#\=] ?)/gm, ''); + return true; + } + ) +} + +proto.markup_line_alone = function(markup_array) { + var t = this.area; + var scroll_top = t.scrollTop; + var selection_start = t.selectionStart; + var text = t.value; + this.selection_start = this.find_right(text, selection_start, /\r?\n/); + this.selection_end = this.selection_start; + t.setSelectionRange(this.selection_start, this.selection_start); + t.focus(); + + var markup = markup_array[1]; + this.start = t.value.substr(0, this.selection_start); + this.finish = t.value.substr(this.selection_end, t.value.length); + var text = this.start + '\n' + markup + this.finish; + var start = this.selection_start + markup.length + 1; + var end = this.selection_end + markup.length + 1; + this.set_text_and_selection(text, start, end); + t.scrollTop = scroll_top; +} + + +/*============================================================================== +Code to convert from html to wikitext. + =============================================================================*/ +proto.convert_html_to_wikitext = function(html) { + this.copyhtml = html; + var dom = document.createElement('div'); + html = html.replace(//g, '-->'); + dom.innerHTML = html; + this.output = []; + this.list_type = []; + this.indent_level = 0; + + this.walk(dom); + + // add final whitespace + this.assert_new_line(); + + return this.join_output(this.output); +} + +proto.appendOutput = function(string) { + this.output.push(string); +} + +proto.join_output = function(output) { + var list = this.remove_stops(output); + list = this.cleanup_output(list); + return list.join(''); +} + +// This is a noop, but can be subclassed. +proto.cleanup_output = function(list) { + return list; +} + +proto.remove_stops = function(list) { + var clean = []; + for (var i = 0 ; i < list.length ; i++) { + if (typeof(list[i]) != 'string') continue; + clean.push(list[i]); + } + return clean; +} + +proto.walk = function(element) { + if (!element) return; + for (var part = element.firstChild; part; part = part.nextSibling) { + if (part.nodeType == 1) { + this.dispatch_formatter(part); + } + else if (part.nodeType == 3) { + if (part.nodeValue.match(/\S/)) { + var string = part.nodeValue; + if (! string.match(/^[\.\,\?\!\)]/)) { + this.assert_space_or_newline(); + string = this.trim(string); + } + this.appendOutput(this.collapse(string)); + } + } + } +} + +proto.dispatch_formatter = function(element) { + var dispatch = 'format_' + element.nodeName.toLowerCase(); + if (! this[dispatch]) + dispatch = 'handle_undefined'; + this[dispatch](element); +} + +proto.skip = function() { } +proto.pass = function(element) { + this.walk(element); +} +proto.handle_undefined = function(element) { + this.appendOutput('<' + element.nodeName + '>'); + this.walk(element); + this.appendOutput(''); +} +proto.handle_undefined = proto.skip; + +proto.format_abbr = proto.pass; +proto.format_acronym = proto.pass; +proto.format_address = proto.pass; +proto.format_applet = proto.skip; +proto.format_area = proto.skip; +proto.format_basefont = proto.skip; +proto.format_base = proto.skip; +proto.format_bgsound = proto.skip; +proto.format_big = proto.pass; +proto.format_blink = proto.pass; +proto.format_body = proto.pass; +proto.format_br = proto.skip; +proto.format_button = proto.skip; +proto.format_caption = proto.pass; +proto.format_center = proto.pass; +proto.format_cite = proto.pass; +proto.format_col = proto.pass; +proto.format_colgroup = proto.pass; +proto.format_dd = proto.pass; +proto.format_dfn = proto.pass; +proto.format_dl = proto.pass; +proto.format_dt = proto.pass; +proto.format_embed = proto.skip; +proto.format_field = proto.skip; +proto.format_fieldset = proto.skip; +proto.format_font = proto.pass; +proto.format_form = proto.skip; +proto.format_frame = proto.skip; +proto.format_frameset = proto.skip; +proto.format_head = proto.skip; +proto.format_html = proto.pass; +proto.format_iframe = proto.pass; +proto.format_input = proto.skip; +proto.format_ins = proto.pass; +proto.format_isindex = proto.skip; +proto.format_label = proto.skip; +proto.format_legend = proto.skip; +proto.format_link = proto.skip; +proto.format_map = proto.skip; +proto.format_marquee = proto.skip; +proto.format_meta = proto.skip; +proto.format_multicol = proto.pass; +proto.format_nobr = proto.skip; +proto.format_noembed = proto.skip; +proto.format_noframes = proto.skip; +proto.format_nolayer = proto.skip; +proto.format_noscript = proto.skip; +proto.format_nowrap = proto.skip; +proto.format_object = proto.skip; +proto.format_optgroup = proto.skip; +proto.format_option = proto.skip; +proto.format_param = proto.skip; +proto.format_select = proto.skip; +proto.format_small = proto.pass; +proto.format_spacer = proto.skip; +proto.format_style = proto.skip; +proto.format_sub = proto.pass; +proto.format_submit = proto.skip; +proto.format_sup = proto.pass; +proto.format_tbody = proto.pass; +proto.format_textarea = proto.skip; +proto.format_tfoot = proto.pass; +proto.format_thead = proto.pass; +proto.format_wiki = proto.pass; + +proto.format_img = function(element) { + var uri = element.getAttribute('src'); + if (uri) { + this.assert_space_or_newline(); + this.appendOutput(uri); + } +} + +// XXX This little dance relies on knowning lots of little details about where +// indentation fangs are added and deleted by the various insert/assert calls. +proto.format_blockquote = function(element) { + if (! this.indent_level) { + this.assert_new_line(); + this.indent_level++; + this.insert_new_line(); + } + else { + this.indent_level++; + this.assert_new_line(); + } + + this.walk(element); + + this.indent_level--; + + if (! this.indent_level) + this.assert_blank_line(); + else + this.assert_new_line(); +} + +proto.format_div = function(element) { + if (this.is_opaque(element)) { + this.handle_opaque_block(element); + return; + } + this.walk(element); +} + +proto.format_span = function(element) { + if (this.is_opaque(element)) { + this.handle_opaque_phrase(element); + return; + } + + var style = element.getAttribute('style'); + if (!style) { + this.pass(element); + return; + } + + this.assert_space_or_newline(); + if (style.match(/\bbold\b/)) + this.appendOutput(this.config.markupRules.bold[1]); + if (style.match(/\bitalic\b/)) + this.appendOutput(this.config.markupRules.italic[1]); + if (style.match(/\bunderline\b/)) + this.appendOutput(this.config.markupRules.underline[1]); + if (style.match(/\bline-through\b/)) + this.appendOutput(this.config.markupRules.strike[1]); + + this.no_following_whitespace(); + this.walk(element); + + if (style.match(/\bline-through\b/)) + this.appendOutput(this.config.markupRules.strike[2]); + if (style.match(/\bunderline\b/)) + this.appendOutput(this.config.markupRules.underline[2]); + if (style.match(/\bitalic\b/)) + this.appendOutput(this.config.markupRules.italic[2]); + if (style.match(/\bbold\b/)) + this.appendOutput(this.config.markupRules.bold[2]); +} + +klass.make_format = function(style) { + return function(element) { + var markup = this.config.markupRules[style]; + var handler = markup[0]; + this['handle_' + handler](element, markup); + } +} + +proto.format_b = klass.make_format('bold'); +proto.format_strong = proto.format_b; +proto.format_code = klass.make_format('code'); +proto.format_kbd = proto.format_code; +proto.format_samp = proto.format_code; +proto.format_tt = proto.format_code; +proto.format_var = proto.format_code; +proto.format_i = klass.make_format('italic'); +proto.format_em = proto.format_i; +proto.format_u = klass.make_format('underline'); +proto.format_strike = klass.make_format('strike'); +proto.format_del = proto.format_strike; +proto.format_s = proto.format_strike; +proto.format_hr = klass.make_format('hr'); +proto.format_h1 = klass.make_format('h1'); +proto.format_h2 = klass.make_format('h2'); +proto.format_h3 = klass.make_format('h3'); +proto.format_h4 = klass.make_format('h4'); +proto.format_h5 = klass.make_format('h5'); +proto.format_h6 = klass.make_format('h6'); +proto.format_pre = klass.make_format('pre'); + +proto.format_p = function(element) { + this.assert_blank_line(); + this.walk(element); + this.assert_blank_line(); +} + +proto.format_a = function(element) { + var label = Wikiwyg.htmlUnescape(element.innerHTML); + label = label.replace(/<[^>]*?>/g, ' '); + label = label.replace(/\s+/g, ' '); + label = label.replace(/^\s+/, ''); + label = label.replace(/\s+$/, ''); + this.make_wikitext_link(label, element.getAttribute('href'), element); +} + +proto.format_table = function(element) { + this.assert_blank_line(); + this.walk(element); + this.assert_blank_line(); +} + +proto.format_tr = function(element) { + this.walk(element); + this.appendOutput('|'); + this.insert_new_line(); +} + +proto.format_td = function(element) { + this.appendOutput('| '); + this.walk(element); + this.appendOutput(' '); +} +proto.format_th = proto.format_td; + +proto.format_ol = function(element) { + if (!this.list_type.length) + this.assert_blank_line(); + else + this.assert_new_line(); + + this.list_type.push('ordered'); + this.walk(element); + this.list_type.pop(); + + if (!this.list_type.length) + this.assert_blank_line(); +} + +// XXX - Maybe a refactoring for the duplication above +proto.format_ul = function(element) { + if (!this.list_type.length) + this.assert_blank_line(); + else + this.assert_new_line(); + + this.list_type.push('unordered'); + this.walk(element); + this.list_type.pop(); + + if (!this.list_type.length) + this.assert_blank_line(); +} + +proto.format_li = function(element) { + var level = this.list_type.length; + if (!level) die("List error"); + var type = this.list_type[level - 1]; + var markup = this.config.markupRules[type]; + this.appendOutput(markup[1].times(level) + ' '); + + this.walk(element); + + this.chomp(); + this.insert_new_line(); +} + + +proto.chomp = function() { + var string; + while (this.output.length) { + string = this.output.pop(); + if (typeof(string) != 'string') { + this.appendOutput(string); + return; + } + if (! string.match(/^\n>+ $/) && string.match(/\S/)) + break; + } + if (string) { + string = string.replace(/[\r\n\s]+$/, ''); + this.appendOutput(string); + } +} + +proto.collapse = function(string) { + return string.replace(/[ \r\n]+/g, ' '); +} + +proto.trim = function(string) { + return string.replace(/^\s+/, ''); +} + +proto.insert_new_line = function() { + var fang = ''; + if (this.indent_level > 0) + fang = '>'.times(this.indent_level) + ' '; + // XXX - ('\n' + fang) MUST be in the same element in this.output so that + // it can be properly matched by chomp above. + if (this.output.length) + this.appendOutput('\n' + fang); + else if (fang.length) + this.appendOutput(fang); +} + +proto.assert_new_line = function() { + this.chomp(); + this.insert_new_line(); +} + +proto.assert_blank_line = function() { + this.chomp(); + this.insert_new_line(); + this.insert_new_line(); +} + +proto.assert_space_or_newline = function() { + var string; + if (! this.output.length) return; + + string = this.output[this.output.length - 1]; + + if (! string.whitespace && ! string.match(/\s+$/)) + this.appendOutput(' '); +} + +proto.no_following_whitespace = function() { + this.appendOutput({whitespace: 'stop'}); +} + +proto.handle_bound_phrase = function(element, markup) { + this.assert_space_or_newline(); + this.appendOutput(markup[1]); + this.no_following_whitespace(); + this.walk(element); + // assume that walk leaves no trailing whitespace. + this.appendOutput(markup[2]); +} + +// XXX - A very promising refactoring is that we don't need the trailing +// assert_blank_line in block formatters. +proto.handle_bound_line = function(element,markup) { + this.assert_blank_line(); + this.appendOutput(markup[1]); + this.walk(element); + this.appendOutput(markup[2]); + this.assert_blank_line(); +} + +proto.handle_start_line = function (element, markup) { + this.assert_blank_line(); + this.appendOutput(markup[1]); + this.walk(element); + this.assert_blank_line(); +} + +proto.handle_start_lines = function (element, markup) { + var text = element.firstChild.nodeValue; + if (!text) return; + this.assert_blank_line(); + text = text.replace(/^/mg, markup[1]); + this.appendOutput(text); + this.assert_blank_line(); +} + +proto.handle_line_alone = function (element, markup) { + this.assert_blank_line(); + this.appendOutput(markup[1]); + this.assert_blank_line(); +} + +proto.get_first_comment = function(element) { + var comment = element.firstChild; + if (comment && (comment.nodeType == 8)) + return comment; + else + return null; +} + +proto.is_opaque = function(element) { + var comment = this.get_first_comment(element); + if (!comment) return false; + + var text = comment.data; + if (text.match(/^\s*wiki:/)) return true; + return false; +} + +proto.handle_opaque_phrase = function(element) { + var comment = this.get_first_comment(element); + if (comment) { + var text = comment.data; + text = text.replace(/^ wiki:\s+/, ''); + text = text.replace(/\s$/, ''); + this.assert_space_or_newline(); + this.appendOutput(text); + this.assert_space_or_newline(); + } +} + +proto.handle_opaque_block = function(element) { + var comment = this.get_first_comment(element); + if (!comment) return; + + var text = comment.data; + text = text.replace(/^\s*wiki:\s+/, ''); + this.appendOutput(text); +} + +proto.make_wikitext_link = function(label, href, element) { + var before = this.config.markupRules.link[1]; + var after = this.config.markupRules.link[2]; + + this.assert_space_or_newline(); + if (! href) { + this.appendOutput(label); + } + else if (href == label) { + this.appendOutput(href); + } + else if (this.href_is_wiki_link(href)) { + if (this.camel_case_link(label)) + this.appendOutput(label); + else + this.appendOutput(before + label + after); + } + else { + this.appendOutput(before + href + ' ' + label + after); + } +} + +proto.camel_case_link = function(label) { + if (! this.config.supportCamelCaseLinks) + return false; + return label.match(/[a-z][A-Z]/); +} + +proto.href_is_wiki_link = function(href) { + if (! this.looks_like_a_url(href)) + return true; + if (! href.match(/\?/)) + return false; + var no_arg_input = href.split('?')[0]; + var no_arg_current = location.href.split('?')[0]; + return no_arg_input == no_arg_current; +} + +proto.looks_like_a_url = function(string) { + return string.match(/^(http|https|ftp|irc|mailto):/); +} + +/*============================================================================== +Support for Internet Explorer in Wikiwyg.Wikitext + =============================================================================*/ +if (Wikiwyg.is_ie) { + +proto.setHeightOf = function() { + // XXX hardcode this until we can keep window from jumping after button + // events. + this.textarea.style.height = '200px'; +} + +proto.initializeObject = function() { + this.initialize_object(); + this.area.addBehavior(this.config.javascriptLocation + "Selection.htc"); +} + +} // end of global if diff --git a/themes/default/Wikiwyg/Wikiwyg/Wysiwyg.js b/themes/default/Wikiwyg/Wikiwyg/Wysiwyg.js new file mode 100644 index 000000000..c4812b661 --- /dev/null +++ b/themes/default/Wikiwyg/Wikiwyg/Wysiwyg.js @@ -0,0 +1,300 @@ +/*============================================================================== +This Wikiwyg mode supports a DesignMode wysiwyg editor with toolbar buttons + +COPYRIGHT: + + Copyright (c) 2005 Socialtext Corporation + 655 High Street + Palo Alto, CA 94301 U.S.A. + All rights reserved. + +Wikiwyg is free software. + +This library is free software; you can redistribute it and/or modify it +under the terms of the GNU Lesser General Public License as published by +the Free Software Foundation; either version 2.1 of the License, or (at +your option) any later version. + +This library is distributed in the hope that it will be useful, but +WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser +General Public License for more details. + + http://www.gnu.org/copyleft/lesser.txt + + =============================================================================*/ + +proto = new Subclass('Wikiwyg.Wysiwyg', 'Wikiwyg.Mode'); + +proto.classtype = 'wysiwyg'; +proto.modeDescription = 'Wysiwyg'; + +proto.config = { + useParentStyles: true, + useStyleMedia: 'wikiwyg', + iframeId: null, + iframeObject: null, + disabledToolbarButtons: [], + editHeightMinimum: 150, + editHeightAdjustment: 1.3, + clearRegex: null +}; + +proto.initializeObject = function() { + this.edit_iframe = this.get_edit_iframe(); + this.div = this.edit_iframe; + this.set_design_mode_early(); +} + +proto.set_design_mode_early = function() { // Se IE, below + // Unneeded for Gecko +} + +proto.fromHtml = function(html) { + + html = html.replace(/\n/g,'
    ') ; + this.set_inner_html(html); +} + +proto.toHtml = function(func) { + func(this.get_inner_html()); +} + +// This is needed to work around the broken IMGs in Firefox design mode. +// Works harmlessly on IE, too. +// TODO - IMG URLs that don't match /^\// +proto.fix_up_relative_imgs = function() { + var base = location.href.replace(/(.*?:\/\/.*?\/).*/, '$1'); + var imgs = this.get_edit_document().getElementsByTagName('img'); + for (var ii = 0; ii < imgs.length; ++ii) + imgs[ii].src = imgs[ii].src.replace(/^\//, base); +} + +proto.enableThis = function() { + this.superfunc('enableThis').call(this); + this.edit_iframe.style.border = '1px black solid'; + this.edit_iframe.width = '100%'; + this.setHeightOf(this.edit_iframe); + this.fix_up_relative_imgs(); + this.get_edit_document().designMode = 'on'; + // XXX - Doing stylesheets in initializeObject might get rid of blue flash + this.apply_stylesheets(); + this.enable_keybindings(); + this.clear_inner_html(); +} + +proto.clear_inner_html = function() { + var inner_html = this.get_inner_html(); + var clear = this.config.clearRegex; + if (clear && inner_html.match(clear)) + this.set_inner_html(''); +} + +proto.get_keybinding_area = function() { + return this.get_edit_document(); +} + +proto.get_edit_iframe = function() { + var iframe; + if (this.config.iframeId) { + iframe = document.getElementById(this.config.iframeId); + iframe.iframe_hack = true; + } + else if (this.config.iframeObject) { + iframe = this.config.iframeObject; + iframe.iframe_hack = true; + } + else { + // XXX in IE need to wait a little while for iframe to load up + iframe = document.createElement('iframe'); + } + return iframe; +} + +proto.get_edit_window = function() { // See IE, below + return this.edit_iframe.contentWindow; +} + +proto.get_edit_document = function() { // See IE, below + return this.get_edit_window().document; +} + +proto.get_inner_html = function() { + return this.get_edit_document().body.innerHTML; +} +proto.set_inner_html = function(html) { + this.get_edit_document().body.innerHTML = html; +} + +proto.apply_stylesheets = function(styles) { + var styles = document.styleSheets; + var head = this.get_edit_document().getElementsByTagName("head")[0]; + + for (var i = 0; i < styles.length; i++) { + var style = styles[i]; + + if (style.href == location.href) + this.apply_inline_stylesheet(style, head); + else + if (this.should_link_stylesheet(style)) + this.apply_linked_stylesheet(style, head); + } +} + +proto.apply_inline_stylesheet = function(style, head) { + // TODO: figure this out +} + +proto.should_link_stylesheet = function(style, head) { + var media = style.media; + var config = this.config; + var media_text = media.mediaText ? media.mediaText : media; + var use_parent = + ((!media_text || media_text == 'screen') && + config.useParentStyles); + var use_style = (media_text && (media_text == config.useStyleMedia)); + if (!use_parent && !use_style) // TODO: simplify + return false; + else + return true; +} + +proto.apply_linked_stylesheet = function(style, head) { + var link = Wikiwyg.createElementWithAttrs( + 'link', { + href: style.href, + type: style.type, + media: 'screen', + rel: 'STYLESHEET' + }, this.get_edit_document() + ); + head.appendChild(link); +} + +proto.process_command = function(command) { + if (this['do_' + command]) + this['do_' + command](command); + if (! Wikiwyg.is_ie) + this.get_edit_window().focus(); +} + +proto.exec_command = function(command, option) { + this.get_edit_document().execCommand(command, false, option); +} + +proto.format_command = function(command) { + this.exec_command('formatblock', '<' + command + '>'); +} + +proto.do_bold = proto.exec_command; +proto.do_italic = proto.exec_command; +proto.do_underline = proto.exec_command; +proto.do_strike = function() { + this.exec_command('strikethrough'); +} +proto.do_hr = function() { + this.exec_command('inserthorizontalrule'); +} +proto.do_ordered = function() { + this.exec_command('insertorderedlist'); +} +proto.do_unordered = function() { + this.exec_command('insertunorderedlist'); +} +proto.do_indent = proto.exec_command; +proto.do_outdent = proto.exec_command; + +proto.do_h1 = proto.format_command; +proto.do_h2 = proto.format_command; +proto.do_h3 = proto.format_command; +proto.do_h4 = proto.format_command; +proto.do_h5 = proto.format_command; +proto.do_h6 = proto.format_command; +proto.do_pre = proto.format_command; +proto.do_p = proto.format_command; + +proto.do_table = function() { + var html = + '' + + '' + + '' + + '' + + '' + + '' + + '
    ABC
       
       
    '; + if (! Wikiwyg.is_ie) + this.get_edit_window().focus(); + this.insert_table(html); +} + +proto.insert_table = function(html) { // See IE + this.exec_command('inserthtml', html); +} + +proto.do_link = function() { + var selection = this.get_link_selection_text(); + if (! selection) return; + var url; + var match = selection.match(/(.*?)\b((?:http|https|ftp|irc):\/\/\S+)(.*)/); + if (match) { + if (match[1] || match[3]) return null; + url = match[2]; + } + else { + url = '?' + escape(selection); + } + this.exec_command('createlink', url); +} + +proto.get_selection_text = function() { // See IE, below + return this.get_edit_window().getSelection().toString(); +} + +proto.get_link_selection_text = function() { + var selection = this.get_selection_text(); + if (! selection) { + alert("Please select the text you would like to turn into a link."); + return; + } + return selection; +} + +/*============================================================================== +Support for Internet Explorer in Wikiwyg.Wysiwyg + =============================================================================*/ +if (Wikiwyg.is_ie) { + +proto.set_design_mode_early = function(wikiwyg) { + // XXX - need to know if iframe is ready yet... + this.get_edit_document().designMode = 'on'; +} + +proto.get_edit_window = function() { + return this.edit_iframe; +} + +proto.get_edit_document = function() { + return this.edit_iframe.contentWindow.document; +} + +proto.get_selection_text = function() { + var selection = this.get_edit_document().selection; + if (selection != null) + return selection.createRange().htmlText; + return ''; +} + +proto.insert_table = function(html) { + var doc = this.get_edit_document(); + var range = this.get_edit_document().selection.createRange(); + if (range.boundingTop == 2 && range.boundingLeft == 2) + return; + range.pasteHTML(html); + range.collapse(false); + range.select(); +} + +// Use IE's design mode default key bindings for now. +proto.enable_keybindings = function() {} + +} // end of global if diff --git a/themes/default/Wikiwyg/images/bold.gif b/themes/default/Wikiwyg/images/bold.gif new file mode 100755 index 0000000000000000000000000000000000000000..c7e968c9bf443c57150a54aac3968be99b5a5250 GIT binary patch literal 76 zcmZ?wbhEHb6k!lyXkcUjg8%>jEB<5wG8q|kKzxu41Cw%3|H{*E`4{snxFxmrVt?`T a#Jj3}2g1xAW-eOewd}Ib^>4o74AuZKHyUjK literal 0 HcmV?d00001 diff --git a/themes/default/Wikiwyg/images/h1.gif b/themes/default/Wikiwyg/images/h1.gif new file mode 100755 index 0000000000000000000000000000000000000000..6087954490315a427c7e5cd770f45d8aea6ff107 GIT binary patch literal 84 zcmZ?wbhEHb6k!lyXkY+=0|yQ${$ycfU|?j>0r5dH3{2WR{VPwu79v#hi@k2H3hSK`!he|rLZhC$F$6o_fZ4Ch4m>oX= literal 0 HcmV?d00001 diff --git a/themes/default/Wikiwyg/images/h2.gif b/themes/default/Wikiwyg/images/h2.gif new file mode 100755 index 0000000000000000000000000000000000000000..58581be5524b312ee3b34f0e350ee63b7a8920f7 GIT binary patch literal 86 zcmZ?wbhEHb6k!lyXkY+=0|yQ${$ycfU|?j>0r5dH3{1K`{VPwu0r5dH3{1K`{VPwu>T-3O@Yr%_ECtkgIn##LNkClh3eF77MH2@S49cTam literal 0 HcmV?d00001 diff --git a/themes/default/Wikiwyg/images/h4.gif b/themes/default/Wikiwyg/images/h4.gif new file mode 100755 index 0000000000000000000000000000000000000000..6f60a07edf49c408dec6f5c2225a2bc47d28e00d GIT binary patch literal 85 zcmZ?wbhEHb6k!lyXkcUjg8%>jEB<5wG8q|kKzxu41Cvfq|H{*E`4`V&j}XwS+m`oP jRrW`3mt~UTqFBij3s!AAkrVSQ``NB5{5)KZtPIuw_%$3A literal 0 HcmV?d00001 diff --git a/themes/default/Wikiwyg/images/h5.gif b/themes/default/Wikiwyg/images/h5.gif new file mode 100755 index 0000000000000000000000000000000000000000..163d0120f371396c08caf5dd0caf36f966297d20 GIT binary patch literal 103 zcmZ?wbhEHb6k!lyXkcUzU|{(F|G(ltzVOWK%<{@~1*g)IlKead#h)yUTnvm1It)Mn zQp>=k)6>85^jrSLbJ!V@H=gbKeY<9sGMn`DIrG?*mfj9i&?^6&bE)*)u`B#MT=J|8 F)&ORbB254Q literal 0 HcmV?d00001 diff --git a/themes/default/Wikiwyg/images/h6.gif b/themes/default/Wikiwyg/images/h6.gif new file mode 100755 index 0000000000000000000000000000000000000000..0c54b108b9a17b90757e1046c723199c63696716 GIT binary patch literal 105 zcmZ?wbhEHb6k!lyXkcUzU|{(F|G(ltzVOWK%<{@~1*g)IlKead#h)yUTnvm1It)Mn zQp>=k*VDi9^jrSLbJ!V@C!X#6JfZd~>!d}GW=h{&`>Jczj63JbB=0|+_V}|WCs+Fs IH%10)0Q}-7P5=M^ literal 0 HcmV?d00001 diff --git a/themes/default/Wikiwyg/images/help.gif b/themes/default/Wikiwyg/images/help.gif new file mode 100755 index 0000000000000000000000000000000000000000..a3e2ff5ea4c640e858be998818057eabc2ae2804 GIT binary patch literal 76 zcmZ?wbhEHb6k!lyXkY+=0|yQ${$ycfU|?j>0r5dH3{1*B{VPwum2a41aE@Dbkzam* aYFtL6Vp)-9WzQS#?RiU&eOoKSU=0Apuol_? literal 0 HcmV?d00001 diff --git a/themes/default/Wikiwyg/images/hr.gif b/themes/default/Wikiwyg/images/hr.gif new file mode 100755 index 0000000000000000000000000000000000000000..2a4d88c09e61dc615ab1fc178704931d2c2f06aa GIT binary patch literal 73 zcmZ?wbhEHb6k!lySjfaMbLLEAW8?o|p!k!8k%57UL5BedK=KSsQd9a@o_@=}c+Qq6 XiB0!x8u{BExlVi5xolM+1A{dHh`ky` literal 0 HcmV?d00001 diff --git a/themes/default/Wikiwyg/images/image.gif b/themes/default/Wikiwyg/images/image.gif new file mode 100755 index 0000000000000000000000000000000000000000..65522006f8a339105886151ecba44df856159476 GIT binary patch literal 181 zcmZ?wbhEHb6k!lyc+ABB1`P}h{~5pp!~g&PL7e{$4Gjkl902mrfZ|UUMg|6c1|5(_ zkQodtNgqynuHO5j>8$ms2BkjbPnlke)@d!86S{-%@T+~(=I|V0STQ#y%l-FS5r&6Z zhrJZ0`Zk(O=~>F7D~v6L>4%8zn=3j kbv4V}kB#jedCxskd2c7ZQk#D3&J}@klmGIU099K906Z!p4gdfE literal 0 HcmV?d00001 diff --git a/themes/default/Wikiwyg/images/italic.gif b/themes/default/Wikiwyg/images/italic.gif new file mode 100755 index 0000000000000000000000000000000000000000..ddf76b8c79aac4b087240ed66f6f2e4ac2fe264a GIT binary patch literal 79 zcmZ?wbhEHb6k!lySjfZx1Pu)h|G_}g>& zT;&HJ@|nEC`KZh5CLmw!V4m71{!R@n5LaN51fpswi1Ob z=AIeV&LS8dl(VARXksA;jK^uL#Y@b?E$qP$3_vjwAq^I+p$RXDuo-Bu0b`nW>O63& zGs8+0vY2~ygyc`)Buu1aNNA))EaZUkIE}S!F9+A=HoqNw{JL}Hv)(T}m_6Bj ze0A;U`Ro1D-O7~V`*))czC|DKU`nlyz}tZ>bu+bE{>l5 T{B-}-cyDg&?8}eiZRzemiMemE literal 0 HcmV?d00001 diff --git a/themes/default/Wikiwyg/images/ordered.gif b/themes/default/Wikiwyg/images/ordered.gif new file mode 100755 index 0000000000000000000000000000000000000000..767e03cff7dfc0e4b36f77f6a7b0b76664e489b7 GIT binary patch literal 84 zcmZ?wbhEHb6k!lySjfZx1`YqgK=CIFBLf2ygAM}&BZDvyGBBx5>0f#Jt(063+l}gl hJ`3NUuXy0d_^dK3*}Yfqx7>?8TV}s_mcYnh4FFNU9<%@e literal 0 HcmV?d00001 diff --git a/themes/default/Wikiwyg/images/outdent.gif b/themes/default/Wikiwyg/images/outdent.gif new file mode 100755 index 0000000000000000000000000000000000000000..0f5c432b6e495e4f517543fefe37a8d889ac19ce GIT binary patch literal 91 zcmZ?wbhEHb6k!lySjfb{z|a81|G_}0f!e_u(Rug-+eC o=R8QA&2aZ)BYVT5*$XE{8cW^Zl^DW#v3KpueSf&QWLX)k0a02Zga7~l literal 0 HcmV?d00001 diff --git a/themes/default/Wikiwyg/images/p.gif b/themes/default/Wikiwyg/images/p.gif new file mode 100755 index 0000000000000000000000000000000000000000..3a5adfacf5a90c42995f6195775acef393c37253 GIT binary patch literal 73 zcmZ?wbhEHb6k!lyXkcUjg8%>jEB<5wG8q|kKzxu41Cv5e|H{*E`4`XOj_^KsaS}U! XmEU~e=k*VDi9^jrSLbJ%ZG^`5m#dC+)IY1-Wt4e={-PlOdE8I@;y%`ct0*?^UYtKG$& Hk--`O)!rkK literal 0 HcmV?d00001 diff --git a/themes/default/Wikiwyg/images/separator.gif b/themes/default/Wikiwyg/images/separator.gif new file mode 100755 index 0000000000000000000000000000000000000000..87a94ddbd726803821683c0797372a2af5addf05 GIT binary patch literal 102 zcmZ?wbhEHbRAvxiXkcVmwQAM>|Nj;Li8>dhCYGe8D3oWGWGIAWq$;?3`UWs4{$yd~ zVqj#@VE_VU1|bFpCY7H4m8akGFP^hSDM9mGQSpmfKMkXlm2+NfHOrFTvv$v=6};Z8 G4Aub2?<0f& literal 0 HcmV?d00001 diff --git a/themes/default/Wikiwyg/images/strike.gif b/themes/default/Wikiwyg/images/strike.gif new file mode 100755 index 0000000000000000000000000000000000000000..dae104d40d6067892ec6b11b364225170d1f53e6 GIT binary patch literal 84 zcmZ?wbhEHb6k!lyXkY+=|Ns9h{$ycfU|?j>0r5dH4ouoT{VUmXKQP5?xuqR@+qk^P jSLX4AJC#kZPHkIvt21bdL()&hk2cTW^ZyZLV6X-N2qYc~ literal 0 HcmV?d00001 diff --git a/themes/default/Wikiwyg/images/table.gif b/themes/default/Wikiwyg/images/table.gif new file mode 100755 index 0000000000000000000000000000000000000000..607ff38b4ecb49682b6acf3e59147551e96e77a3 GIT binary patch literal 923 zcmZ?wbhEHblw^=#XlDQe=Kufy5P?y0Gz3OS2q^w!VP;@pV$cEk7nCO$ zI4T%eIb=LGEI8QAA*>a1V#C72?VOArb38UGHFPi5FQOSux#yRUtg#be%BTLYt zkeQ!UJe$?R=jCV?A2{8_!1m(K$;r=sn+!9#LVp$~1WfaYb$fHNBt5XvJzZ_9WZeK{v3RWUUR%+M9RdaCvIuXEq)7#XYq1Q8)o literal 0 HcmV?d00001 diff --git a/themes/default/Wikiwyg/images/unordered.gif b/themes/default/Wikiwyg/images/unordered.gif new file mode 100755 index 0000000000000000000000000000000000000000..ea1500126ba5a5016fae628545b132ef0666f66c GIT binary patch literal 82 zcmZ?wbhEHb6k!lySjfb{z|a81|G_}0f#JEx+&#LEnU? fd(n5f+AfGsy7Myd(J3jFjCpgHZ2NXsguxmB1K=G* literal 0 HcmV?d00001 diff --git a/themes/default/Wikiwyg/images/www.gif b/themes/default/Wikiwyg/images/www.gif new file mode 100755 index 0000000000000000000000000000000000000000..d96cf1dfc5c3079f4063d3bda7164dc950ce3258 GIT binary patch literal 189 zcmZ?wbhEHb6k!lyc+AS+>+8$Vz;NKe0S1Qu4Gj(d|NmzI^1%!s8xtu0WMO1r;9$^U z00NL13@lj!Cp}m1wU~U?_-?xbTSL1*>jXBPm4ePzXPCVcHfTuXyp7u#cA((F)CS{5 z0|V=*1e1q}57r3qT)cLm;4ni*gTVoXbwS4%rgBa2nyLPBQ_Kgq4UczKER>tx{W31A UI=4ZRp