0byt3m1n1
Path:
/
data
/
applications
/
aps
/
phpwiki
/
1.4.0-0
/
standard
/
htdocs
/
themes
/
default
/
Wikiwyg
/
[
Home
]
File: Wikiwyg.js
/*============================================================================== 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 <ingy@cpan.org> Casey West <casey@geeknest.com> Chris Dent <cdent@burningchrome.com> Matt Liggett <mml@pobox.com> Ryan King <rking@panoptic.com> Dave Rolsky <autarch@urth.org> 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: 'Wikiwyg/', doubleClickToEdit: false, toolbarClass: 'Wikiwyg.Toolbar', modeClasses: [ 'Wikiwyg.Wysiwyg', '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; //Set cookie to keep last editing mode //document.cookie = "Mode="+new_mode_key; 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