You are viewing a plain text version of this content. The canonical link for it is here.
Posted to graffito-commits@incubator.apache.org by cl...@apache.org on 2005/02/17 23:57:32 UTC
svn commit: r154214 [7/10] - in incubator/graffito/trunk/applications: ./
browser/ browser/src/ browser/src/java/ browser/src/java/org/
browser/src/java/org/apache/ browser/src/java/org/apache/portals/
browser/src/java/org/apache/portals/graffito/
browser/src/java/org/apache/portals/graffito/portlets/
browser/src/java/org/apache/portals/graffito/portlets/resources/
browser/src/java/org/apache/portals/graffito/portlets/util/
browser/src/java/org/apache/portals/graffito/servlets/
browser/src/java/org/apache/portals/graffito/util/ browser/src/webapp/
browser/src/webapp/WEB-INF/ browser/src/webapp/WEB-INF/tabs/
browser/src/webapp/WEB-INF/velocity/ browser/src/webapp/WEB-INF/view/
browser/src/webapp/WEB-INF/view/document/
browser/src/webapp/WEB-INF/view/folder/
browser/src/webapp/WEB-INF/view/security/ browser/src/webapp/kupu/
browser/src/webapp/kupu/kupudrawers/
browser/src/webapp/kupu/kupudrawers/logos/
browser/src/webapp/kupu/kupuimages/ browser/src/webapp/kupu/kupupopups/
Added: incubator/graffito/trunk/applications/browser/src/webapp/kupu/kupueditor.js
URL: http://svn.apache.org/viewcvs/incubator/graffito/trunk/applications/browser/src/webapp/kupu/kupueditor.js?view=auto&rev=154214
==============================================================================
--- incubator/graffito/trunk/applications/browser/src/webapp/kupu/kupueditor.js (added)
+++ incubator/graffito/trunk/applications/browser/src/webapp/kupu/kupueditor.js Thu Feb 17 15:57:09 2005
@@ -0,0 +1,725 @@
+/*****************************************************************************
+ *
+ * Copyright (c) 2003-2004 Kupu Contributors. All rights reserved.
+ *
+ * This software is distributed under the terms of the Kupu
+ * License. See LICENSE.txt for license text. For a list of Kupu
+ * Contributors see CREDITS.txt.
+ *
+ *****************************************************************************/
+
+// $Id: kupueditor.js 8408 2005-01-19 11:20:56Z duncan $
+
+//----------------------------------------------------------------------------
+// Main classes
+//----------------------------------------------------------------------------
+
+/* KupuDocument
+
+ This essentially wraps the iframe.
+ XXX Is this overkill?
+
+*/
+
+function KupuDocument(iframe) {
+ /* Model */
+
+ // attrs
+ this.editable = iframe; // the iframe
+ this.window = this.editable.contentWindow;
+ this.document = this.window.document;
+
+ this._browser = _SARISSA_IS_IE ? 'IE' : 'Mozilla';
+
+ // methods
+ this.execCommand = function(command, arg) {
+ /* delegate execCommand */
+ // XXX Is the command always a string? Can't it be '' or 0 or so?
+ if (!arg) arg = null;
+ this.document.execCommand(command, false, arg);
+ };
+
+ this.reloadSource = function() {
+ /* reload the source */
+
+ // XXX To temporarily work around problems with resetting the
+ // state after a reload, currently the whole page is reloaded.
+ // XXX Nasty workaround!! to solve refresh problems...
+ document.location = document.location;
+ };
+
+ this.getDocument = function() {
+ /* returns a reference to the window.document object of the iframe */
+ return this.document;
+ };
+
+ this.getWindow = function() {
+ /* returns a reference to the window object of the iframe */
+ return this.window;
+ };
+
+ this.getSelection = function() {
+ if (this._browser == 'Mozilla') {
+ return new MozillaSelection(this);
+ } else {
+ return new IESelection(this);
+ };
+ };
+
+ this.getEditable = function() {
+ return this.editable;
+ };
+
+};
+
+/* KupuEditor
+
+ This controls the document, should be used from the UI.
+
+*/
+
+function KupuEditor(document, config, logger) {
+ /* Controller */
+
+ // attrs
+ this.document = document; // the model
+ this.config = config; // an object that holds the config values
+ this.log = logger; // simple logger object
+ this.tools = {}; // mapping id->tool
+ this.filters = new Array(); // contentfilters
+
+ this._designModeSetAttempts = 0;
+ this._initialized = false;
+
+ // some properties to save the selection, required for IE to remember where
+ // in the iframe the selection was
+ this._previous_range = null;
+
+ // this property is true if the content is changed, false if no changes are made yet
+ this.content_changed = false;
+
+ // methods
+ this.initialize = function() {
+ /* Should be called on iframe.onload, will initialize the editor */
+ //DOM2Event.initRegistration();
+ this._initializeEventHandlers();
+ this.focusDocument();
+ if (this.getBrowserName() == "IE") {
+ var body = this.getInnerDocument().getElementsByTagName('body')[0];
+ body.setAttribute('contentEditable', 'true');
+ // provide an 'afterInit' method on KupuEditor.prototype
+ // for additional bootstrapping (after editor init)
+ this._initialized = true;
+ if (this.afterInit) {
+ this.afterInit();
+ };
+ this._saveSelection();
+ } else {
+ this._setDesignModeWhenReady();
+ };
+ this.logMessage('Editor initialized');
+ };
+
+ this.setContextMenu = function(menu) {
+ /* initialize the contextmenu */
+ menu.initialize(this);
+ };
+
+ this.registerTool = function(id, tool) {
+ /* register a tool */
+ this.tools[id] = tool;
+ tool.initialize(this);
+ };
+
+ this.getTool = function(id) {
+ /* get a tool by id */
+ return this.tools[id];
+ };
+
+ this.registerFilter = function(filter) {
+ /* register a content filter method
+
+ the method will be called together with any other registered
+ filters before the content is saved to the server, the methods
+ can be used to filter any trash out of the content. they are
+ called with 1 argument, which is a reference to the rootnode
+ of the content tree (the html node)
+ */
+ this.filters.push(filter);
+ filter.initialize(this);
+ };
+
+ this.updateStateHandler = function(event) {
+ /* check whether the event is interesting enough to trigger the
+ updateState machinery and act accordingly */
+ var interesting_codes = new Array(8, 13, 37, 38, 39, 40, 46);
+ // unfortunately it's not possible to do this on blur, since that's
+ // too late. also (some versions of?) IE 5.5 doesn't support the
+ // onbeforedeactivate event, which would be ideal here...
+ if (this.getBrowserName() == 'IE') {
+ this._saveSelection();
+ };
+
+ if (event.type == 'click' || event.type=='mouseup' ||
+ (event.type == 'keyup' &&
+ interesting_codes.contains(event.keyCode))) {
+ // Filthy trick to make the updateState method get called *after*
+ // the event has been resolved. This way the updateState methods can
+ // react to the situation *after* any actions have been performed (so
+ // can actually stay up to date).
+ this.updateState(event);
+ }
+ };
+
+ this.updateState = function(event) {
+ /* let each tool change state if required */
+ // first see if the event is interesting enough to trigger
+ // the whole updateState machinery
+ var selNode = this.getSelectedNode();
+ for (var id in this.tools) {
+ try {
+ this.tools[id].updateState(selNode, event);
+ } catch (e) {
+ if (e == UpdateStateCancelBubble) {
+ this.updateState(event);
+ break;
+ } else {
+ this.logMessage('Exception while processing updateState on ' + id + ': ' + e, 2);
+ };
+ };
+ };
+ };
+
+ this.saveDocument = function(redirect, synchronous) {
+ /* save the document, redirect if te arg is provided and the save is successful
+
+ the (optional) redirect argument can be used to make the client jump to
+ another URL when the save action was successful.
+ */
+
+ // if no dst is available, bail out
+ if (!this.config.dst) {
+ this.logMessage('No destination URL available!', 2);
+ return;
+ }
+ var sourcetool = this.getTool('sourceedittool');
+ if (sourcetool) {sourcetool.cancelSourceMode();};
+
+ // make sure people can't edit or save during saving
+ if (!this._initialized) {
+ return;
+ }
+ this._initialized = false;
+
+ // set the window status so people can see we're actually saving
+ window.status= "Please wait while saving document...";
+
+ // pass the content through the filters
+ this.logMessage("Starting HTML cleanup");
+ var transform = this._filterContent(this.getInnerDocument().documentElement);
+
+ // serialize to a string
+ var contents = this._serializeOutputToString(transform);
+
+ this.logMessage("Cleanup done, sending document to server");
+ var request = Sarissa.getXmlHttpRequest();
+
+ if (!synchronous) {
+ request.onreadystatechange = (new ContextFixer(this._saveCallback,
+ this, request, redirect)).execute;
+ request.open("PUT", this.config.dst, true);
+ request.setRequestHeader("Content-type", this.config.content_type);
+ request.send(contents);
+ this.logMessage("Request sent to server");
+ } else {
+ this.logMessage('Sending request to server');
+ request.open("PUT", this.config.dst, false);
+ request.setRequestHeader("Content-type", this.config.content_type);
+ request.send(contents);
+ this.handleSaveResponse(request,redirect)
+ };
+ };
+
+ this.prepareForm = function(form, id) {
+ /* add a field to the form and place the contents in it
+
+ can be used for simple POST support where Kupu is part of a
+ form
+ */
+ var sourcetool = this.getTool('sourceedittool');
+ if (sourcetool) {sourcetool.cancelSourceMode();};
+
+ // make sure people can't edit or save during saving
+ if (!this._initialized) {
+ return;
+ }
+ this._initialized = false;
+
+ // set the window status so people can see we're actually saving
+ window.status= "Please wait while saving document...";
+
+ // set a default id
+ if (!id) {
+ id = 'kupu';
+ };
+
+ // pass the content through the filters
+ this.logMessage("Starting HTML cleanup");
+ var transform = this._filterContent(this.getInnerDocument().documentElement);
+
+ // XXX need to fix this. Sometimes a spurious "\n\n" text
+ // node appears in the transform, which breaks the Moz
+ // serializer on .xml
+ var contents = this._serializeOutputToString(transform);
+
+ this.logMessage("Cleanup done, sending document to server");
+
+ // now create the form input, since IE 5.5 doesn't support the
+ // ownerDocument property we use window.document as a fallback (which
+ // will almost by definition be correct).
+ var document = form.ownerDocument ? form.ownerDocument : window.document;
+ var ta = document.createElement('textarea');
+ ta.style.visibility = 'hidden';
+ var text = document.createTextNode(contents);
+ ta.appendChild(text);
+ ta.setAttribute('name', id);
+
+ // and add it to the form
+ form.appendChild(ta);
+
+ // let the calling code know we have added the textarea
+ return true;
+ };
+
+ this.execCommand = function(command, param) {
+ /* general stuff like making current selection bold, italics etc.
+ and adding basic elements such as lists
+ */
+ if (!this._initialized) {
+ this.logMessage('Editor not initialized yet!');
+ return;
+ };
+ if (this.getBrowserName() == "IE") {
+ this._restoreSelection();
+ } else {
+ this.focusDocument();
+ if (command != 'useCSS') {
+ this.content_changed = true;
+ // note the negation: the argument doesn't work as
+ // expected...
+ // Done here otherwise it doesn't always work or gets lost
+ // after some commands
+ this.getDocument().execCommand('useCSS', !this.config.use_css);
+ };
+ };
+ this.getDocument().execCommand(command, param);
+ var message = 'Command ' + command + ' executed';
+ if (param) {
+ message += ' with parameter ' + param;
+ }
+ this.updateState();
+ this.logMessage(message);
+ };
+
+ this.getSelection = function() {
+ /* returns a Selection object wrapping the current selection */
+ if (this.getBrowserName() == "IE") {
+ this._restoreSelection();
+ };
+ return this.getDocument().getSelection();
+ };
+
+ this.getSelectedNode = function() {
+ /* returns the selected node (read: parent) or none */
+ return this.getSelection().getSelectedNode();
+ };
+
+ this.getNearestParentOfType = function(node, type) {
+ /* well the title says it all ;) */
+ var type = type.toLowerCase();
+ while (node) {
+ if (node.nodeName.toLowerCase() == type) {
+ return node
+ }
+ var node = node.parentNode;
+ }
+ return false;
+ };
+
+ this.removeNearestParentOfType = function(node, type) {
+ var nearest = this.getNearestParentOfType(node, type);
+ if (!nearest) {
+ return false;
+ };
+ var parent = nearest.parentNode;
+ while (nearest.childNodes.length) {
+ var child = nearest.firstChild;
+ child = nearest.removeChild(child);
+ parent.insertBefore(child, nearest);
+ };
+ parent.removeChild(nearest);
+ };
+
+ this.getDocument = function() {
+ /* returns a reference to the document object that wraps the iframe */
+ return this.document;
+ };
+
+ this.getInnerDocument = function() {
+ /* returns a reference to the window.document object of the iframe */
+ return this.getDocument().getDocument();
+ };
+
+ this.insertNodeAtSelection = function(insertNode, selectNode) {
+ /* insert a newly created node into the document */
+ if (!this._initialized) {
+ this.logMessage('Editor not initialized yet!');
+ return;
+ };
+
+ this.content_changed = true;
+
+ var browser = this.getBrowserName();
+ if (browser != "IE") {
+ this.focusDocument();
+ };
+
+ var ret = this.getSelection().replaceWithNode(insertNode, selectNode);
+
+ if (browser == 'IE') {
+ this._saveSelection();
+ };
+
+ return ret;
+ };
+
+ this.focusDocument = function() {
+ this.getDocument().getWindow().focus();
+ }
+
+ this.logMessage = function(message, severity) {
+ /* log a message using the logger, severity can be 0 (message, default), 1 (warning) or 2 (error) */
+ this.log.log(message, severity);
+ };
+
+ this.registerContentChanger = function(element) {
+ /* set this.content_changed to true (marking the content changed) when the
+ element's onchange is called
+ */
+ addEventHandler(element, 'change', function() {this.content_changed = true;}, this);
+ };
+
+ // helper methods
+ this.getBrowserName = function() {
+ /* returns either 'Mozilla' (for Mozilla, Firebird, Netscape etc.) or 'IE' */
+ if (_SARISSA_IS_MOZ) {
+ return "Mozilla";
+ } else if (_SARISSA_IS_IE) {
+ return "IE";
+ } else {
+ throw "Browser not supported!";
+ }
+ };
+
+ this.handleSaveResponse = function(request, redirect) {
+ if (request.status != '200' && request.status != '204'){
+ alert('Error saving your data.\nResponse status: ' +
+ request.status +
+ '.\nCheck your server log for more information.')
+ window.status = "Error saving document"
+ } else if (redirect) { // && (!request.status || request.status == '200' || request.status == '204'))
+ window.document.location = redirect;
+ this.content_changed = false;
+ } else {
+ // clear content_changed before reloadSrc so saveOnPart is not triggered
+ this.content_changed = false;
+ if (this.config.reload_after_save) {
+ this.reloadSrc();
+ };
+ // we're done so we can start editing again
+ window.status= "Document saved";
+ };
+ this._initialized = true;
+ };
+
+ // private methods
+ this._addEventHandler = addEventHandler;
+
+ this._saveCallback = function(request, redirect) {
+ /* callback for Sarissa */
+ if (request.readyState == 4) {
+ this.handleSaveResponse(request, redirect)
+ };
+ };
+
+ this.reloadSrc = function() {
+ /* reload the src, called after a save when reload_src is set to true */
+ // XXX Broken!!!
+ /*
+ if (this.getBrowserName() == "Mozilla") {
+ this.getInnerDocument().designMode = "Off";
+ }
+ */
+ // XXX call reloadSrc() which has a workaround, reloads the full page
+ // instead of just the iframe...
+ this.getDocument().reloadSource();
+ if (this.getBrowserName() == "Mozilla") {
+ this.getInnerDocument().designMode = "On";
+ };
+ /*
+ var selNode = this.getSelectedNode();
+ this.updateState(selNode);
+ */
+ };
+
+ this._initializeEventHandlers = function() {
+ /* attache the event handlers to the iframe */
+ // Initialize DOM2Event compatibility
+ // XXX should come back and change to passing in an element
+ this._addEventHandler(this.getInnerDocument(), "click", this.updateStateHandler, this);
+ this._addEventHandler(this.getInnerDocument(), "dblclick", this.updateStateHandler, this);
+ this._addEventHandler(this.getInnerDocument(), "keyup", this.updateStateHandler, this);
+ this._addEventHandler(this.getInnerDocument(), "keyup", function() {this.content_changed = true}, this);
+ this._addEventHandler(this.getInnerDocument(), "mouseup", this.updateStateHandler, this);
+ };
+
+ this._setDesignModeWhenReady = function() {
+ /* Rather dirty polling loop to see if Mozilla is done doing it's
+ initialization thing so design mode can be set.
+ */
+ this._designModeSetAttempts++;
+ if (this._designModeSetAttempts > 25) {
+ alert('Couldn\'t set design mode. Kupu will not work on this browser.');
+ return;
+ };
+ var success = false;
+ try {
+ this._setDesignMode();
+ success = true;
+ } catch (e) {
+ // register a function to the timer_instance because
+ // window.setTimeout can't refer to 'this'...
+ timer_instance.registerFunction(this, this._setDesignModeWhenReady, 100);
+ };
+ if (success) {
+ // provide an 'afterInit' method on KupuEditor.prototype
+ // for additional bootstrapping (after editor init)
+ if (this.afterInit) {
+ this.afterInit();
+ };
+ };
+ };
+
+ this._setDesignMode = function() {
+ this.getInnerDocument().designMode = "On";
+ this.execCommand("undo");
+ // note the negation: the argument doesn't work as expected...
+ this._initialized = true;
+ };
+
+ this._saveSelection = function() {
+ /* Save the selection, works around a problem with IE where the
+ selection in the iframe gets lost. We only save if the current
+ selection in the document */
+ if (this._isDocumentSelected()) {
+ var currange = this.getInnerDocument().selection.createRange();
+ this._previous_range = currange;
+ };
+ };
+
+ this._restoreSelection = function() {
+ /* re-selects the previous selection in IE. We only restore if the
+ current selection is not in the document.*/
+ if (this._previous_range && !this._isDocumentSelected()) {
+ try {
+ this._previous_range.select();
+ } catch (e) {
+ this.logMessage('Error placing back selection');
+ };
+ };
+ };
+
+ this._isDocumentSelected = function() {
+ var editable_body = this.getInnerDocument().getElementsByTagName('body')[0];
+ var selrange = this.getInnerDocument().selection.createRange();
+ var someelement = selrange.parentElement ? selrange.parentElement() : selrange.item(0);
+
+ while (someelement.nodeName.toLowerCase() != 'body') {
+ someelement = someelement.parentNode;
+ };
+
+ return someelement == editable_body;
+ };
+
+ this._clearSelection = function() {
+ /* clear the last stored selection */
+ this._previous_range = null;
+ };
+
+ this._filterContent = function(documentElement) {
+ /* pass the content through all the filters */
+ // first copy all nodes to a Sarissa document so it's usable
+ var xhtmldoc = Sarissa.getDomDocument();
+ var doc = this._convertToSarissaNode(xhtmldoc, documentElement);
+ // now pass it through all filters
+ for (var i=0; i < this.filters.length; i++) {
+ var doc = this.filters[i].filter(xhtmldoc, doc);
+ };
+ // fix some possible structural problems, such as an empty or missing head, title
+ // or script or textarea tags without closing tag...
+ this._fixXML(doc, xhtmldoc);
+ return doc;
+ };
+
+ this.getXMLBody = function(transform) {
+ var bodies = transform.getElementsByTagName('body');
+ var data = '';
+ for (var i = 0; i < bodies.length; i++) {
+ data += bodies[i].xml;
+ }
+ return data;
+ };
+
+ this.getHTMLBody = function() {
+ var doc = this.getInnerDocument();
+ var docel = doc.documentElement;
+ var bodies = docel.getElementsByTagName('body');
+ var data = '';
+ for (var i = 0; i < bodies.length; i++) {
+ data += bodies[i].innerHTML;
+ }
+ return data;
+ };
+
+ // If we have multiple bodies this needs to remove the extras.
+ this.setHTMLBody = function(text) {
+ var bodies = this.getInnerDocument().documentElement.getElementsByTagName('body');
+ for (var i = 0; i < bodies.length-1; i++) {
+ bodies[i].parentNode.removeChild(bodies[i]);
+ }
+ bodies[bodies.length-1].innerHTML = text;
+ };
+
+ this._fixXML = function(doc, document) {
+ /* fix some structural problems in the XML that make it invalid XTHML */
+ // find if we have a head and title, and if not add them
+ var heads = doc.getElementsByTagName('head');
+ var titles = doc.getElementsByTagName('title');
+ if (!heads.length) {
+ // assume we have a body, guess Kupu won't work without one anyway ;)
+ var body = doc.getElementsByTagName('body')[0];
+ var head = document.createElement('head');
+ body.parentNode.insertBefore(head, body);
+ var title = document.createElement('title');
+ var titletext = document.createTextNode('');
+ head.appendChild(title);
+ title.appendChild(titletext);
+ } else if (!titles.length) {
+ var head = heads[0];
+ var title = document.createElement('title');
+ var titletext = document.createTextNode('');
+ head.appendChild(title);
+ title.appendChild(titletext);
+ };
+ // create a closing element for all elements that require one in XHTML
+ var dualtons = new Array('a', 'abbr', 'acronym', 'address', 'applet',
+ 'b', 'bdo', 'big', 'blink', 'blockquote',
+ 'button', 'caption', 'center', 'cite',
+ 'comment', 'del', 'dfn', 'dir', 'div',
+ 'dl', 'dt', 'em', 'embed', 'fieldset',
+ 'font', 'form', 'frameset', 'h1', 'h2',
+ 'h3', 'h4', 'h5', 'h6', 'i', 'iframe',
+ 'ins', 'kbd', 'label', 'legend', 'li',
+ 'listing', 'map', 'marquee', 'menu',
+ 'multicol', 'nobr', 'noembed', 'noframes',
+ 'noscript', 'object', 'ol', 'optgroup',
+ 'option', 'p', 'pre', 'q', 's', 'script',
+ 'select', 'small', 'span', 'strike',
+ 'strong', 'style', 'sub', 'sup', 'table',
+ 'tbody', 'td', 'textarea', 'tfoot',
+ 'th', 'thead', 'title', 'tr', 'tt', 'u',
+ 'ul', 'xmp');
+ // XXX I reckon this is *way* slow, can we use XPath instead or
+ // something to speed this up?
+ for (var i=0; i < dualtons.length; i++) {
+ var elname = dualtons[i];
+ var els = doc.getElementsByTagName(elname);
+ for (var j=0; j < els.length; j++) {
+ var el = els[j];
+ if (!el.hasChildNodes()) {
+ var child = document.createTextNode('');
+ el.appendChild(child);
+ };
+ };
+ };
+ };
+
+ this.xhtmlvalid = new XhtmlValidation(this);
+
+ this._convertToSarissaNode = function(ownerdoc, htmlnode) {
+ /* Given a string of non-well-formed HTML, return a string of
+ well-formed XHTML.
+
+ This function works by leveraging the already-excellent HTML
+ parser inside the browser, which generally can turn a pile
+ of crap into a DOM. We iterate over the HTML DOM, appending
+ new nodes (elements and attributes) into a node.
+
+ The primary problems this tries to solve for crappy HTML: mixed
+ element names, elements that open but don't close,
+ and attributes that aren't in quotes. This can also be adapted
+ to filter out tags that you don't want and clean up inline styles.
+
+ Inspired by Guido, adapted by Paul from something in usenet.
+ Tag and attribute tables added by Duncan
+ */
+ return this.xhtmlvalid._convertToSarissaNode(ownerdoc, htmlnode);
+ };
+
+ this._fixupSingletons = function(xml) {
+ return xml.replace(/<([^>]+)\/>/g, "<$1 />");
+ }
+ this._serializeOutputToString = function(transform) {
+ // XXX need to fix this. Sometimes a spurious "\n\n" text
+ // node appears in the transform, which breaks the Moz
+ // serializer on .xml
+
+ if (this.config.strict_output) {
+ var contents = '<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Strict//EN" ' +
+ '"http://www.w3.org/TR/xhtml1/DTD/xhtml1-strict.dtd">\n' +
+ '<html xmlns="http://www.w3.org/1999/xhtml">' +
+ transform.getElementsByTagName("head")[0].xml +
+ transform.getElementsByTagName("body")[0].xml +
+ '</html>';
+ } else {
+ var contents = '<html>' +
+ transform.getElementsByTagName("head")[0].xml +
+ transform.getElementsByTagName("body")[0].xml +
+ '</html>';
+ };
+
+ if (this.config.compatible_singletons) {
+ contents = this._fixupSingletons(contents);
+ };
+
+ return contents;
+ };
+
+ this.getFullEditor = function() {
+ var fulleditor = this.getDocument().getEditable();
+ while (!/kupu-fulleditor/.test(fulleditor.className)) {
+ fulleditor = fulleditor.parentNode;
+ }
+ return fulleditor;
+ }
+ // Control the className and hence the style for the whole editor.
+ this.setClass = function(name) {
+ this.getFullEditor().className += ' '+name;
+ }
+
+ this.clearClass = function(name) {
+ var fulleditor = this.getFullEditor();
+ fulleditor.className = fulleditor.className.replace(' '+name, '');
+ }
+}
+
Added: incubator/graffito/trunk/applications/browser/src/webapp/kupu/kupuform.html
URL: http://svn.apache.org/viewcvs/incubator/graffito/trunk/applications/browser/src/webapp/kupu/kupuform.html?view=auto&rev=154214
==============================================================================
--- incubator/graffito/trunk/applications/browser/src/webapp/kupu/kupuform.html (added)
+++ incubator/graffito/trunk/applications/browser/src/webapp/kupu/kupuform.html Thu Feb 17 15:57:09 2005
@@ -0,0 +1,363 @@
+
+<html xmlns="http://www.w3.org/1999/xhtml">
+ <head>
+ <title>Test Editor</title>
+ <meta http-equiv="Content-Type" content="text/html; charset=UTF-8"/>
+ <link href="kupustyles.css" rel="stylesheet" type="text/css"/>
+ <link href="kupudrawerstyles.css" rel="stylesheet" type="text/css"/>
+ <script type="text/javascript" src="sarissa.js"> </script>
+ <script type="text/javascript" src="kupuhelpers.js"> </script>
+ <script type="text/javascript" src="kupueditor.js"> </script>
+ <script type="text/javascript" src="kupubasetools.js"> </script>
+ <script type="text/javascript" src="kupuloggers.js"> </script>
+ <script type="text/javascript" src="kupucontentfilters.js"> </script>
+ <script type="text/javascript" src="kupucontextmenu.js"> </script>
+ <script type="text/javascript" src="kupuinit_form.js"> </script>
+ <script type="text/javascript" src="kupustart_form.js"> </script>
+ <script type="text/javascript" src="kupusourceedit.js"> </script>
+ <script type="text/javascript" src="kupudrawers.js"> </script>
+ </head>
+ <body onload="kupu = startKupu()">
+ <h1>Kupu Editor Test Page</h1>
+ <form action="http://debris.demon.nl/printpost" method="POST">
+ <div style="display: none;">
+ <xml id="kupuconfig">
+ <kupuconfig>
+ <dst>fulldoc.html</dst>
+ <use_css>1</use_css>
+ <reload_after_save>0</reload_after_save>
+ <strict_output>1</strict_output>
+ <content_type>application/xhtml+xml</content_type>
+ <compatible_singletons>1</compatible_singletons>
+ <table_classes>
+ <class>plain</class>
+ <class>listing</class>
+ <class>grid</class>
+ <class>data</class>
+ </table_classes>
+ <image_xsl_uri>kupudrawers/drawer.xsl</image_xsl_uri>
+ <link_xsl_uri>kupudrawers/drawer.xsl</link_xsl_uri>
+ <image_libraries_uri>kupudrawers/imagelibrary.xml</image_libraries_uri>
+ <link_libraries_uri>kupudrawers/linklibrary.xml</link_libraries_uri>
+ <search_images_uri> </search_images_uri>
+ <search_links_uri> </search_links_uri>
+ </kupuconfig>
+ </xml>
+ </div>
+ <div class="kupu-fulleditor">
+ <div class="kupu-tb" id="toolbar">
+ <span id="kupu-tb-buttons">
+ <span class="kupu-tb-buttongroup" style="float: right" id="kupu-logo">
+ <button type="button" class="kupu-logo" title="Kupu 1.2rc1" accesskey="k" onclick="window.open('http://kupu.oscom.org');"> </button>
+ </span>
+ <select id="kupu-tb-styles">
+ <option xmlns:i18n="http://xml.zope.org/namespaces/i18n" value="P" i18n:translate="paragraph-normal">
+ Normal
+ </option>
+ <option value="H1"><span xmlns:i18n="http://xml.zope.org/namespaces/i18n" i18n:translate="heading">Heading</span> 1
+ </option>
+ <option value="H2"><span xmlns:i18n="http://xml.zope.org/namespaces/i18n" i18n:translate="heading">Heading</span> 2
+ </option>
+ <option value="H3"><span xmlns:i18n="http://xml.zope.org/namespaces/i18n" i18n:translate="heading">Heading</span> 3
+ </option>
+ <option value="H4"><span xmlns:i18n="http://xml.zope.org/namespaces/i18n" i18n:translate="heading">Heading</span> 4
+ </option>
+ <option value="H5"><span xmlns:i18n="http://xml.zope.org/namespaces/i18n" i18n:translate="heading">Heading</span> 5
+ </option>
+ <option value="H6"><span xmlns:i18n="http://xml.zope.org/namespaces/i18n" i18n:translate="heading">Heading</span> 6
+ </option>
+ <option xmlns:i18n="http://xml.zope.org/namespaces/i18n" value="PRE" i18n:translate="paragraph-formatted">
+ Formatted
+ </option>
+ </select>
+ <span class="kupu-tb-buttongroup">
+ <button xmlns:i18n="http://xml.zope.org/namespaces/i18n" type="button" class="kupu-save" id="kupu-save-button" title="Save" i18n:attributes="title" accesskey="s"> </button>
+ </span>
+ <span class="kupu-tb-buttongroup" id="kupu-bg-basicmarkup">
+ <button xmlns:i18n="http://xml.zope.org/namespaces/i18n" type="button" class="kupu-bold" id="kupu-bold-button" title="bold: alt-b" i18n:attributes="title" accesskey="b"> </button>
+ <button xmlns:i18n="http://xml.zope.org/namespaces/i18n" type="button" class="kupu-italic" id="kupu-italic-button" title="italic: alt-i" i18n:attributes="title" accesskey="i"> </button>
+ <button xmlns:i18n="http://xml.zope.org/namespaces/i18n" type="button" class="kupu-underline" id="kupu-underline-button" title="underline: alt-u" i18n:attributes="title" accesskey="u"> </button>
+ </span>
+ <span class="kupu-tb-buttongroup" id="kupu-bg-subsuper">
+ <button xmlns:i18n="http://xml.zope.org/namespaces/i18n" type="button" class="kupu-subscript" id="kupu-subscript-button" title="subscript: alt--" i18n:attributes="title" accesskey="-"> </button>
+ <button xmlns:i18n="http://xml.zope.org/namespaces/i18n" type="button" class="kupu-superscript" id="kupu-superscript-button" title="superscript: alt-+" i18n:attributes="title" accesskey="+"> </button>
+ </span>
+ <span class="kupu-tb-buttongroup">
+ <button xmlns:i18n="http://xml.zope.org/namespaces/i18n" type="button" class="kupu-forecolor" id="kupu-forecolor-button" title="text color: alt-f" i18n:attributes="title" accesskey="f"> </button>
+ <button xmlns:i18n="http://xml.zope.org/namespaces/i18n" type="button" class="kupu-hilitecolor" id="kupu-hilitecolor-button" title="background color: alt-h" i18n:attributes="title" accesskey="h"> </button>
+ </span>
+ <span class="kupu-tb-buttongroup" id="kupu-bg-justify">
+ <button xmlns:i18n="http://xml.zope.org/namespaces/i18n" type="button" class="kupu-justifyleft" id="kupu-justifyleft-button" title="left justify: alt-l" i18n:attributes="title" accesskey="l"> </button>
+ <button xmlns:i18n="http://xml.zope.org/namespaces/i18n" type="button" class="kupu-justifycenter" id="kupu-justifycenter-button" title="center justify: alt-c" i18n:attributes="title" accesskey="c"> </button>
+ <button xmlns:i18n="http://xml.zope.org/namespaces/i18n" type="button" class="kupu-justifyright" id="kupu-justifyright-button" title="right justify: alt-r" i18n:attributes="title" accesskey="r"> </button>
+ </span>
+ <span class="kupu-tb-buttongroup" id="kupu-bg-list">
+ <button xmlns:i18n="http://xml.zope.org/namespaces/i18n" type="button" class="kupu-insertorderedlist" title="numbered list: alt-#" id="kupu-list-ol-addbutton" i18n:attributes="title" accesskey="#"> </button>
+ <button xmlns:i18n="http://xml.zope.org/namespaces/i18n" type="button" class="kupu-insertunorderedlist" title="unordered list: alt-*" id="kupu-list-ul-addbutton" i18n:attributes="title" accesskey="*"> </button>
+ </span>
+ <span class="kupu-tb-buttongroup" id="kupu-bg-definitionlist">
+ <button xmlns:i18n="http://xml.zope.org/namespaces/i18n" type="button" class="kupu-insertdefinitionlist" title="definition list: alt-=" id="kupu-list-dl-addbutton" i18n:attributes="title" accesskey="="> </button>
+ </span>
+ <span class="kupu-tb-buttongroup" id="kupu-bg-indent">
+ <button xmlns:i18n="http://xml.zope.org/namespaces/i18n" type="button" class="kupu-outdent" id="kupu-outdent-button" title="outdent: alt-<" i18n:attributes="title" accesskey="<"> </button>
+ <button xmlns:i18n="http://xml.zope.org/namespaces/i18n" type="button" class="kupu-indent" id="kupu-indent-button" title="indent: alt->" i18n:attributes="title" accesskey=">"> </button>
+ </span>
+ <span class="kupu-tb-buttongroup">
+ <button xmlns:i18n="http://xml.zope.org/namespaces/i18n" type="button" class="kupu-image" id="kupu-imagelibdrawer-button" title="image" i18n:attributes="title"> </button>
+ <button xmlns:i18n="http://xml.zope.org/namespaces/i18n" type="button" class="kupu-inthyperlink" id="kupu-linklibdrawer-button" title="internal link" i18n:attributes="title"> </button>
+ <button xmlns:i18n="http://xml.zope.org/namespaces/i18n" type="button" class="kupu-exthyperlink" id="kupu-linkdrawer-button" title="external link" i18n:attributes="title"> </button>
+ <button xmlns:i18n="http://xml.zope.org/namespaces/i18n" type="button" class="kupu-table" id="kupu-tabledrawer-button" title="table" i18n:attributes="title"> </button>
+ </span>
+ <span class="kupu-tb-buttongroup" id="kupu-bg-remove">
+ <button xmlns:i18n="http://xml.zope.org/namespaces/i18n" type="button" class="kupu-removeimage invisible" id="kupu-removeimage-button" title="Remove image" i18n:attributes="title"> </button>
+ <button xmlns:i18n="http://xml.zope.org/namespaces/i18n" type="button" class="kupu-removelink invisible" id="kupu-removelink-button" title="Remove link" i18n:attributes="title"> </button>
+ </span>
+ <span class="kupu-tb-buttongroup" id="kupu-bg-undo">
+ <button xmlns:i18n="http://xml.zope.org/namespaces/i18n" type="button" class="kupu-undo" id="kupu-undo-button" title="undo: alt-z" i18n:attributes="title" accesskey="z"> </button>
+ <button xmlns:i18n="http://xml.zope.org/namespaces/i18n" type="button" class="kupu-redo" id="kupu-redo-button" title="redo: alt-y" i18n:attributes="title" accesskey="y"> </button>
+ </span>
+ <span class="kupu-tb-buttongroup" id="kupu-source">
+ <button xmlns:i18n="http://xml.zope.org/namespaces/i18n" type="button" class="kupu-source" id="kupu-source-button" title="edit HTML code" i18n:attributes="title"> </button>
+ </span>
+ </span>
+ <select id="kupu-ulstyles">
+ <option xmlns:i18n="http://xml.zope.org/namespaces/i18n" value="disc" i18n:translate="list-disc">●</option>
+ <option xmlns:i18n="http://xml.zope.org/namespaces/i18n" value="square" i18n:translate="list-square">■</option>
+ <option xmlns:i18n="http://xml.zope.org/namespaces/i18n" value="circle" i18n:translate="list-circle">○</option>
+ <option xmlns:i18n="http://xml.zope.org/namespaces/i18n" value="none" i18n:translate="list-nobullet">no bullet</option>
+ </select>
+ <select id="kupu-olstyles">
+ <option xmlns:i18n="http://xml.zope.org/namespaces/i18n" value="decimal" i18n:translate="list-decimal">1</option>
+ <option xmlns:i18n="http://xml.zope.org/namespaces/i18n" value="upper-roman" i18n:translate="list-upperroman">I</option>
+ <option xmlns:i18n="http://xml.zope.org/namespaces/i18n" value="lower-roman" i18n:translate="list-lowerroman">i</option>
+ <option xmlns:i18n="http://xml.zope.org/namespaces/i18n" value="upper-alpha" i18n:translate="list-upperalpha">A</option>
+ <option xmlns:i18n="http://xml.zope.org/namespaces/i18n" value="lower-alpha" i18n:translate="list-loweralpha">a</option>
+ </select>
+ <div style="display:block;">
+ <div id="kupu-librarydrawer" class="kupu-drawer">
+ </div>
+ </div>
+ <div id="kupu-linkdrawer" class="kupu-drawer">
+ <h1 xmlns:i18n="http://xml.zope.org/namespaces/i18n" i18n:translate="">External Link</h1>
+ <div id="kupu-linkdrawer-addlink" class="kupu-panels">
+ <table>
+ <tr>
+ <td>
+ <div class="kupu-toolbox-label"><span xmlns:i18n="http://xml.zope.org/namespaces/i18n" i18n:translate="items-matching-keyword">
+ Link the highlighted text to this URL
+ </span>:
+ </div>
+ <input id="kupu-linkdrawer-input" class="kupu-toolbox-st" type="text"/>
+ </td>
+ <td class="kupu-preview-button">
+ <button type="button" onclick="drawertool.current_drawer.preview()">Preview</button>
+ </td>
+ </tr>
+ <tr>
+ <td colspan="2" align="center">
+ <iframe frameborder="1" scrolling="auto" width="440" height="198" id="kupu-linkdrawer-preview" src="kupublank.html">
+ </iframe>
+ </td>
+ </tr>
+ </table>
+ <div class="kupu-dialogbuttons">
+ <button type="button" onclick="drawertool.current_drawer.save()">Ok</button>
+ <button type="button" onclick="drawertool.closeDrawer()">Cancel</button>
+ </div>
+ </div>
+ </div>
+ <div id="kupu-tabledrawer" class="kupu-drawer">
+ <h1>Table</h1>
+ <div class="kupu-panels">
+ <table width="99%">
+ <tr class="kupu-panelsrow">
+ <td class="kupu-panel">
+ <table width="100%">
+ <tbody>
+ <tr>
+ <td class="kupu-toolbox-label">Table Class</td>
+ <td width="50%">
+ <select id="kupu-tabledrawer-classchooser" onchange="drawertool.current_drawer.tool.setTableClass(this.options[this.selectedIndex].value)">
+ <option value="plain">Plain</option>
+ <option value="listing">Listing</option>
+ <option value="grid">Grid</option>
+ <option value="data">Data</option>
+ </select>
+ </td>
+ </tr>
+ <tr>
+ <td colspan="2" class="">
+ <div id="kupu-tabledrawer-addtable">
+ <table width="100%">
+ <tr>
+ <td class="kupu-toolbox-label" width="50%">Rows</td>
+ <td>
+ <input type="text" id="kupu-tabledrawer-newrows"/>
+ </td>
+ </tr>
+ <tr>
+ <td class="kupu-toolbox-label">Columns</td>
+ <td>
+ <input type="text" id="kupu-tabledrawer-newcols"/>
+ </td>
+ </tr>
+ <tr>
+ <td class="kupu-toolbox-label">Headings</td>
+ <td class="kupu-toolbox-label">
+ <input name="kupu-tabledrawer-makeheader" id="kupu-tabledrawer-makeheader" type="checkbox"/>
+ <label for="kupu-tabledrawer-makeheader">Create</label>
+ </td>
+ </tr>
+ <tr>
+ <td colspan="2" style="text-align: center">
+ <button type="button" onclick="drawertool.current_drawer.createTable()">Add Table</button>
+ </td>
+ </tr>
+ <tr>
+ <td colspan="2" style="text-align: center">
+ <button type="button" onclick="drawertool.current_drawer.tool.fixAllTables()">Fix All Tables</button>
+ </td>
+ </tr>
+ </table>
+ </div>
+ <div id="kupu-tabledrawer-edittable">
+ <table width="100%">
+ <tr>
+ <td width="50%">Current column alignment</td>
+ <td>
+ <select id="kupu-tabledrawer-alignchooser" onchange="drawertool.current_drawer.tool.setColumnAlign(this.options[this.selectedIndex].value)">
+ <option value="left">Left</option>
+ <option value="center">Center</option>
+ <option value="right">Right</option>
+ </select>
+ </td>
+ </tr>
+ <tr>
+ <td>Column</td>
+ <td>
+ <button type="button" id="kupu-tabledrawer-addcolumn-button" onclick="drawertool.current_drawer.tool.addTableColumn()">Add</button>
+ <button type="button" id="kupu-tabledrawer-delcolumn-button" onclick="drawertool.current_drawer.tool.delTableColumn()">Remove</button>
+ </td>
+ </tr>
+ <tr>
+ <td>Row</td>
+ <td>
+ <button type="button" id="kupu-tabledrawer-addrow-button" onclick="drawertool.current_drawer.tool.addTableRow()">Add</button>
+ <button type="button" id="kupu-tabledrawer-delrow-button" onclick="drawertool.current_drawer.tool.delTableRow()">Remove</button>
+ </td>
+ </tr>
+ <tr>
+ <td>Fix Table</td>
+ <td>
+ <button type="button" id="kupu-tabledrawer-addrow-button" onclick="drawertool.current_drawer.tool.fixTable()">Fix</button>
+ </td>
+ </tr>
+ </table>
+ </div>
+ </td>
+ </tr>
+ </tbody>
+ </table>
+ </td>
+ </tr>
+ </table>
+ <div class="kupu-dialogbuttons">
+ <button type="button" onclick="drawertool.closeDrawer()">Close</button>
+ </div>
+ </div>
+ </div>
+ </div>
+ <div xmlns="" class="kupu-toolboxes">
+ <div class="kupu-toolbox" id="kupu-toolbox-properties">
+ <h1>Properties</h1>
+ <div class="kupu-toolbox-label">Title:</div>
+ <input class="wide" id="kupu-properties-title"/>
+ <div class="kupu-toolbox-label">Description:</div>
+ <textarea class="wide" id="kupu-properties-description"> </textarea>
+ </div>
+ <div class="kupu-toolbox" id="kupu-toolbox-links">
+ <h1 xmlns:i18n="http://xml.zope.org/namespaces/i18n" i18n:translate="links">Links</h1>
+ <div id="kupu-toolbox-addlink">
+ <div class="kupu-toolbox-label">
+ <span xmlns:i18n="http://xml.zope.org/namespaces/i18n" i18n:translate="items-matching-keyword">
+ Link the highlighted text to this URL:
+ </span>
+ </div>
+ <input id="kupu-link-input" class="wide" type="text"/>
+ <div class="kupu-toolbox-buttons">
+ <button type="button" id="kupu-link-button" class="kupu-toolbox-action">Make Link</button>
+ </div>
+ </div>
+ </div>
+ <div class="kupu-toolbox" id="kupu-toolbox-images">
+ <h1 xmlns:i18n="http://xml.zope.org/namespaces/i18n" i18n:translate="images">Images</h1>
+ <div class="kupu-toolbox-label">
+ <span xmlns:i18n="http://xml.zope.org/namespaces/i18n" i18n:translate="">
+ Insert image at the following URL:
+ </span>
+ </div>
+ <input id="kupu-image-input" value="kupuimages/kupu_icon.gif" class="wide" type="text"/>
+ <span xmlns:i18n="http://xml.zope.org/namespaces/i18n" i18n:translate="">
+ Image float:
+ </span>
+ <select class="wide" id="kupu-image-float-select">
+ <option value="none">No float</option>
+ <option value="left">Left</option>
+ <option value="right">Right</option>
+ </select>
+ <div class="kupu-toolbox-buttons">
+ <button type="button" id="kupu-image-addbutton" class="kupu-toolbox-action">Insert Image</button>
+ </div>
+ </div>
+ <div class="kupu-toolbox" id="kupu-toolbox-tables">
+ <h1 xmlns:i18n="http://xml.zope.org/namespaces/i18n" i18n:translate="table-inspector">Tables</h1>
+ <div class="kupu-toolbox-label">Table Class:
+ <select class="wide" id="kupu-table-classchooser"> </select>
+ </div>
+ <div id="kupu-toolbox-addtable">
+ <div class="kupu-toolbox-label">Rows:</div>
+ <input class="wide" type="text" id="kupu-table-newrows"/>
+ <div class="kupu-toolbox-label">Columns:</div>
+ <input class="wide" type="text" id="kupu-table-newcols"/>
+ <div class="kupu-toolbox-label">
+ Headings:
+ <input name="kupu-table-makeheader" id="kupu-table-makeheader" type="checkbox"/>
+ <label for="kupu-table-makeheader">Create</label>
+ </div>
+ <div class="kupu-toolbox-buttons">
+ <button type="button" id="kupu-table-fixall-button">Fix Table</button>
+ <button type="button" id="kupu-table-addtable-button">Add Table</button>
+ </div>
+ </div>
+ <div id="kupu-toolbox-edittable">
+ <div class="kupu-toolbox-label">Col Align:
+ <select class="wide" id="kupu-table-alignchooser"><option value="left">Left</option><option value="center">Center</option><option value="right">Right</option></select>
+ </div>
+ <div class="kupu-toolbox-buttons">
+ <br/>
+ <button type="button" id="kupu-table-addcolumn-button">Add Column</button>
+ <button type="button" id="kupu-table-delcolumn-button">Remove Column</button>
+ <br/>
+ <button type="button" id="kupu-table-addrow-button">Add Row</button>
+ <button type="button" id="kupu-table-delrow-button">Remove Row</button>
+ <button type="button" id="kupu-table-fix-button">Fix</button>
+ </div>
+ </div>
+ </div>
+ <div class="kupu-toolbox" id="kupu-toolbox-debug">
+ <h1 xmlns:i18n="http://xml.zope.org/namespaces/i18n" i18n:translate="debug-log">Debug Log</h1>
+ <div id="kupu-toolbox-debuglog" class="kupu-toolbox-label">
+ </div>
+ </div>
+ </div>
+ <table id="kupu-colorchooser" cellpadding="0" cellspacing="0" style="position: fixed; border-style: solid; border-color: black; border-width: 1px;">
+ </table>
+ <div class="kupu-editorframe">
+ <iframe id="kupu-editor" frameborder="0" src="fulldoc.html" scrolling="auto">
+ </iframe>
+ <textarea class="kupu-editor-textarea" id="kupu-editor-textarea"> </textarea>
+ </div>
+ </div>
+ </form>
+ </body>
+</html>