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:31 UTC
svn commit: r154214 [5/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/kupucnftable.js
URL: http://svn.apache.org/viewcvs/incubator/graffito/trunk/applications/browser/src/webapp/kupu/kupucnftable.js?view=auto&rev=154214
==============================================================================
--- incubator/graffito/trunk/applications/browser/src/webapp/kupu/kupucnftable.js (added)
+++ incubator/graffito/trunk/applications/browser/src/webapp/kupu/kupucnftable.js Thu Feb 17 15:57:09 2005
@@ -0,0 +1,135 @@
+/*****************************************************************************
+ *
+ * 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: kupubasetools.js 6120 2004-08-22 23:23:42Z roku $
+
+TableTool.prototype.setTableRowRepeat = function() {
+ var selNode = this.editor.getSelectedNode();
+ var row = this.editor.getNearestParentOfType(selNode, 'tr');
+ if (!row) {
+ this.editor.logMessage('Not inside a row!', 1);
+ return;
+ };
+ row.setAttribute('repeatable', 'repeatable');
+ row.className = 'repeatable';
+ this.editor.logMessage('Row repeated');
+ this.updateState(selNode);
+};
+
+TableTool.prototype.delTableRowRepeat = function() {
+ var selNode = this.editor.getSelectedNode();
+ var row = this.editor.getNearestParentOfType(selNode, 'tr');
+ if (!row) {
+ this.editor.logMessage('Not inside a row!', 1);
+ return;
+ };
+ row.removeAttribute('repeatable');
+ row.className = '';
+ row.removeAttribute('class');
+ this.editor.logMessage('Row repeat turned off');
+ this.updateState(selNode);
+};
+
+function CNFTableToolBox(addtabledivid, edittabledivid, newrowsinputid,
+ newcolsinputid, makeheaderinputid, classselectid, alignselectid, addtablebuttonid,
+ addrowbuttonid, delrowbuttonid, setrowrepeatbuttonid, delrowrepeatbuttonid,
+ addcolbuttonid, delcolbuttonid, fixbuttonid,
+ fixallbuttonid, toolboxid, plainclass, activeclass) {
+
+ this.addtablediv = document.getElementById(addtabledivid);
+ this.edittablediv = document.getElementById(edittabledivid);
+ this.newrowsinput = document.getElementById(newrowsinputid);
+ this.newcolsinput = document.getElementById(newcolsinputid);
+ this.makeheaderinput = document.getElementById(makeheaderinputid);
+ this.classselect = document.getElementById(classselectid);
+ this.alignselect = document.getElementById(alignselectid);
+ this.addtablebutton = document.getElementById(addtablebuttonid);
+ this.addrowbutton = document.getElementById(addrowbuttonid);
+ this.delrowbutton = document.getElementById(delrowbuttonid);
+ this.setrowrepeatbutton = document.getElementById(setrowrepeatbuttonid);
+ this.delrowrepeatbutton = document.getElementById(delrowrepeatbuttonid);
+ this.addcolbutton = document.getElementById(addcolbuttonid);
+ this.delcolbutton = document.getElementById(delcolbuttonid);
+ this.fixbutton = document.getElementById(fixbuttonid);
+ this.fixallbutton = document.getElementById(fixallbuttonid);
+ this.toolboxel = document.getElementById(toolboxid);
+ this.plainclass = plainclass;
+ this.activeclass = activeclass;
+
+ this.initialize = function(tool, editor) {
+ /* attach the event handlers */
+ this.tool = tool;
+ this.editor = editor;
+ // build the select list of table classes if configured
+ if (this.editor.config.table_classes) {
+ var classes = this.editor.config.table_classes['class'];
+ while (this.classselect.hasChildNodes()) {
+ this.classselect.removeChild(this.classselect.firstChild);
+ };
+ for (var i=0; i < classes.length; i++) {
+ var classname = classes[i];
+ var option = document.createElement('option');
+ var content = document.createTextNode(classname);
+ option.appendChild(content);
+ option.setAttribute('value', classname);
+ this.classselect.appendChild(option);
+ };
+ };
+ addEventHandler(this.addtablebutton, "click", this.addTable, this);
+ addEventHandler(this.addrowbutton, "click", this.tool.addTableRow, this.tool);
+ addEventHandler(this.delrowbutton, "click", this.tool.delTableRow, this.tool);
+ addEventHandler(this.setrowrepeatbutton, "click", this.tool.setTableRowRepeat, this.tool);
+ addEventHandler(this.delrowrepeatbutton, "click", this.tool.delTableRowRepeat, this.tool);
+ addEventHandler(this.addcolbutton, "click", this.tool.addTableColumn, this.tool);
+ addEventHandler(this.delcolbutton, "click", this.tool.delTableColumn, this.tool);
+ addEventHandler(this.alignselect, "change", this.setColumnAlign, this);
+ addEventHandler(this.classselect, "change", this.setTableClass, this);
+ addEventHandler(this.fixbutton, "click", this.tool.fixTable, this.tool);
+ addEventHandler(this.fixallbutton, "click", this.tool.fixAllTables, this.tool);
+ this.addtablediv.style.display = "block";
+ this.edittablediv.style.display = "none";
+ this.editor.logMessage('Table tool initialized');
+ };
+
+ this.updateState = function(selNode) {
+ /* update the state (add/edit) and update the pulldowns (if required) */
+ var table = this.editor.getNearestParentOfType(selNode, 'table');
+ if (table) {
+ this.addtablediv.style.display = "none";
+ this.edittablediv.style.display = "block";
+
+ var align = this.tool._getColumnAlign(selNode);
+ selectSelectItem(this.alignselect, align);
+ selectSelectItem(this.classselect, table.className);
+ if (this.toolboxel) {
+ this.toolboxel.className = this.activeclass;
+ };
+ var row = this.editor.getNearestParentOfType(selNode, 'tr');
+ var isRepeatable = row.getAttribute('repeatable');
+ if (isRepeatable) {
+ this.setrowrepeatbutton.style.display = 'none';
+ this.delrowrepeatbutton.style.display = 'inline';
+ } else {
+ this.setrowrepeatbutton.style.display = 'inline';
+ this.delrowrepeatbutton.style.display = 'none';
+ };
+ } else {
+ this.edittablediv.style.display = "none";
+ this.addtablediv.style.display = "block";
+ this.alignselect.selectedIndex = 0;
+ this.classselect.selectedIndex = 0;
+ if (this.toolboxel) {
+ this.toolboxel.className = this.plainclass;
+ };
+ };
+ };
+};
+
+CNFTableToolBox.prototype = new TableToolBox;
Added: incubator/graffito/trunk/applications/browser/src/webapp/kupu/kupucontentfilters.js
URL: http://svn.apache.org/viewcvs/incubator/graffito/trunk/applications/browser/src/webapp/kupu/kupucontentfilters.js?view=auto&rev=154214
==============================================================================
--- incubator/graffito/trunk/applications/browser/src/webapp/kupu/kupucontentfilters.js (added)
+++ incubator/graffito/trunk/applications/browser/src/webapp/kupu/kupucontentfilters.js Thu Feb 17 15:57:09 2005
@@ -0,0 +1,605 @@
+/*****************************************************************************
+ *
+ * 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: kupucontentfilters.js 7950 2004-12-21 13:19:30Z duncan $
+
+
+//----------------------------------------------------------------------------
+//
+// ContentFilters
+//
+// These are (or currently 'this is') filters for HTML cleanup and
+// conversion. Kupu filters should be classes that should get registered to
+// the editor using the registerFilter method with 2 methods: 'initialize'
+// and 'filter'. The first will be called with the editor as its only
+// argument and the latter with a reference to the ownerdoc (always use
+// that to create new nodes and such) and the root node of the HTML DOM as
+// its arguments.
+//
+//----------------------------------------------------------------------------
+
+function NonXHTMLTagFilter() {
+ /* filter out non-XHTML tags*/
+
+ // A mapping from element name to whether it should be left out of the
+ // document entirely. If you want an element to reappear in the resulting
+ // document *including* it's contents, add it to the mapping with a 1 value.
+ // If you want an element not to appear but want to leave it's contents in
+ // tact, add it to the mapping with a 0 value. If you want an element and
+ // it's contents to be removed from the document, don't add it.
+ if (arguments.length) {
+ // allow an optional filterdata argument
+ this.filterdata = arguments[0];
+ } else {
+ // provide a default filterdata dict
+ this.filterdata = {'html': 1,
+ 'body': 1,
+ 'head': 1,
+ 'title': 1,
+
+ 'a': 1,
+ 'abbr': 1,
+ 'acronym': 1,
+ 'address': 1,
+ 'b': 1,
+ 'base': 1,
+ 'blockquote': 1,
+ 'br': 1,
+ 'caption': 1,
+ 'cite': 1,
+ 'code': 1,
+ 'col': 1,
+ 'colgroup': 1,
+ 'dd': 1,
+ 'dfn': 1,
+ 'div': 1,
+ 'dl': 1,
+ 'dt': 1,
+ 'em': 1,
+ 'h1': 1,
+ 'h2': 1,
+ 'h3': 1,
+ 'h4': 1,
+ 'h5': 1,
+ 'h6': 1,
+ 'h7': 1,
+ 'i': 1,
+ 'img': 1,
+ 'kbd': 1,
+ 'li': 1,
+ 'link': 1,
+ 'meta': 1,
+ 'ol': 1,
+ 'p': 1,
+ 'pre': 1,
+ 'q': 1,
+ 'samp': 1,
+ 'script': 1,
+ 'span': 1,
+ 'strong': 1,
+ 'style': 1,
+ 'sub': 1,
+ 'sup': 1,
+ 'table': 1,
+ 'tbody': 1,
+ 'td': 1,
+ 'tfoot': 1,
+ 'th': 1,
+ 'thead': 1,
+ 'tr': 1,
+ 'ul': 1,
+ 'u': 1,
+ 'var': 1,
+
+ // even though they're deprecated we should leave
+ // font tags as they are, since Kupu sometimes
+ // produces them itself.
+ 'font': 1,
+ 'center': 0
+ };
+ };
+
+ this.initialize = function(editor) {
+ /* init */
+ this.editor = editor;
+ };
+
+ this.filter = function(ownerdoc, htmlnode) {
+ return this._filterHelper(ownerdoc, htmlnode);
+ };
+
+ this._filterHelper = function(ownerdoc, node) {
+ /* filter unwanted elements */
+ if (node.nodeType == 3) {
+ return ownerdoc.createTextNode(node.nodeValue);
+ } else if (node.nodeType == 4) {
+ return ownerdoc.createCDATASection(node.nodeValue);
+ };
+ // create a new node to place the result into
+ // XXX this can be severely optimized by doing stuff inline rather
+ // than on creating new elements all the time!
+ var newnode = ownerdoc.createElement(node.nodeName);
+ // copy the attributes
+ for (var i=0; i < node.attributes.length; i++) {
+ var attr = node.attributes[i];
+ newnode.setAttribute(attr.nodeName, attr.nodeValue);
+ };
+ for (var i=0; i < node.childNodes.length; i++) {
+ var child = node.childNodes[i];
+ var nodeType = child.nodeType;
+ var nodeName = child.nodeName.toLowerCase();
+ if (nodeType == 3 || nodeType == 4) {
+ newnode.appendChild(this._filterHelper(ownerdoc, child));
+ };
+ if (nodeName in this.filterdata && this.filterdata[nodeName]) {
+ newnode.appendChild(this._filterHelper(ownerdoc, child));
+ } else if (nodeName in this.filterdata) {
+ for (var j=0; j < child.childNodes.length; j++) {
+ newnode.appendChild(this._filterHelper(ownerdoc, child.childNodes[j]));
+ };
+ };
+ };
+ return newnode;
+ };
+};
+
+//-----------------------------------------------------------------------------
+//
+// XHTML validation support
+//
+// This class is the XHTML 1.0 transitional DTD expressed as Javascript
+// data structures.
+//
+function XhtmlValidation(editor) {
+ // Support functions
+ this.Set = function(ary) {
+ if (typeof(ary)==typeof('')) ary = [ary];
+ if (ary instanceof Array) {
+ for (var i = 0; i < ary.length; i++) {
+ this[ary[i]] = 1;
+ }
+ }
+ else {
+ for (var v in ary) { // already a set?
+ this[v] = 1;
+ }
+ }
+ }
+
+ this._exclude = function(array, exceptions) {
+ var ex;
+ if (exceptions.split) {
+ ex = exceptions.split("|");
+ } else {
+ ex = exceptions;
+ }
+ var exclude = new this.Set(ex);
+ var res = [];
+ for (var k=0; k < array.length;k++) {
+ if (!exclude[array[k]]) res.push(array[k]);
+ }
+ return res;
+ }
+ this.setAttrFilter = function(attributes, filter) {
+ for (var j = 0; j < attributes.length; j++) {
+ var attr = attributes[j];
+ this.attrFilters[attr] = filter || this._defaultCopyAttribute;
+ }
+ }
+
+ this.setTagAttributes = function(tags, attributes) {
+ for (var j = 0; j < tags.length; j++) {
+ this.tagAttributes[tags[j]] = attributes;
+ }
+ }
+
+ // define some new attributes for existing tags
+ this.includeTagAttributes = function(tags, attributes) {
+ for (var j = 0; j < tags.length; j++) {
+ var tag = tags[j];
+ this.tagAttributes[tag] = this.tagAttributes[tag].concat(attributes);
+ }
+ }
+
+ this.excludeTagAttributes = function(tags, attributes) {
+ var bad = new this.Set(attributes);
+ var tagset = new this.Set(tags);
+ for (var tag in tagset) {
+ var val = this.tagAttributes[tag];
+ for (var i = val.length; i >= 0; i--) {
+ if (bad[val[i]]) {
+ val = val.concat(); // Copy
+ val.splice(i,1);
+ }
+ }
+ this.tagAttributes[tag] = val;
+ }
+ }
+
+ this.excludeTags = function(badtags) {
+ if (typeof(badtags)==typeof('')) badtags = [badtags];
+ for (var i = 0; i < badtags.length; i++) {
+ delete this.tagAttributes[badtags[i]];
+ }
+ }
+
+ this.excludeAttributes = function(badattrs) {
+ this.excludeTagAttributes(this.tagAttributes, badattrs);
+ for (var i = 0; i < badattrs.length; i++) {
+ delete this.attrFilters[badattrs[i]];
+ }
+ }
+ if (editor.getBrowserName()=="IE") {
+ this._getTagName = function(htmlnode) {
+ var nodename = htmlnode.nodeName.toLowerCase();
+ if (htmlnode.scopeName && htmlnode.scopeName != "HTML") {
+ nodename = htmlnode.scopeName+':'+nodename;
+ }
+ return nodename;
+ }
+ } else {
+ this._getTagName = function(htmlnode) {
+ return htmlnode.nodeName.toLowerCase();
+ }
+ };
+
+ // Supporting declarations
+ this.elements = new function(validation) {
+ // A list of all attributes
+ this.attributes = [
+ 'abbr','accept','accept-charset','accesskey','action','align','alink',
+ 'alt','archive','axis','background','bgcolor','border','cellpadding',
+ 'cellspacing','char','charoff','charset','checked','cite','class',
+ 'classid','clear','code','codebase','codetype','color','cols','colspan',
+ 'compact','content','coords','data','datetime','declare','defer','dir',
+ 'disabled','enctype','face','for','frame','frameborder','halign','headers',
+ 'height','href','hreflang','hspace','http-equiv','id','ismap','label',
+ 'lang','language','link','longdesc','marginheight','marginwidth',
+ 'maxlength','media','method','multiple','name','nohref','noshade','nowrap',
+ 'object','onblur','onchange','onclick','ondblclick','onfocus','onkeydown',
+ 'onkeypress','onkeyup','onload','onmousedown','onmousemove','onmouseout',
+ 'onmouseover','onmouseup','onreset','onselect','onsubmit','onunload',
+ 'profile','prompt','readonly','rel','rev','rows','rowspan','rules',
+ 'scheme','scope','scrolling','selected','shape','size','span','src',
+ 'standby','start','style','summary','tabindex','target','text','title',
+ 'type','usemap','valign','value','valuetype','vlink','vspace','width',
+ 'xml:lang','xml:space','xmlns'];
+
+ // Core attributes
+ this.coreattrs = ['id', 'title', 'style', 'class'];
+ this.i18n = ['lang', 'dir', 'xml:lang'];
+ // All event attributes are here but commented out so we don't
+ // have to remove them later.
+ this.events = []; // 'onclick|ondblclick|onmousedown|onmouseup|onmouseover|onmousemove|onmouseout|onkeypress|onkeydown|onkeyup'.split('|');
+ this.focusevents = []; // ['onfocus','onblur']
+ this.loadevents = []; // ['onload', 'onunload']
+ this.formevents = []; // ['onsubmit','onreset']
+ this.inputevents = [] ; // ['onselect', 'onchange']
+ this.focus = ['accesskey', 'tabindex'].concat(this.focusevents);
+ this.attrs = [].concat(this.coreattrs, this.i18n, this.events);
+
+ // entities
+ this.special_extra = ['object','applet','img','map','iframe'];
+ this.special_basic=['br','span','bdo'];
+ this.special = [].concat(this.special_basic, this.special_extra);
+ this.fontstyle_extra = ['big','small','font','basefont'];
+ this.fontstyle_basic = ['tt','i','b','u','s','strike'];
+ this.fontstyle = [].concat(this.fontstyle_basic, this.fontstyle_extra);
+ this.phrase_extra = ['sub','sup'];
+ this.phrase_basic=[
+ 'em','strong','dfn','code','q',
+ 'samp','kbd','var', 'cite','abbr','acronym'];
+ this.inline_forms = ['input','select','textarea','label','button'];
+ this.misc_inline = ['ins','del'];
+ this.misc = ['noscript'].concat(this.misc_inline);
+ this.inline = ['a'].concat(this.special, this.fontstyle, this.phrase, this.inline_forms);
+
+ this.Inline = ['#PCDATA'].concat(this.inline, this.misc_inline);
+
+ this.heading = ['h1','h2','h3','h4','h5','h6'];
+ this.lists = ['ul','ol','dl','menu','dir'];
+ this.blocktext = ['pre','hr','blockquote','address','center','noframes'];
+ this.block = ['p','div','isindex','fieldset','table'].concat(
+ this.heading, this.lists, this.blocktext);
+
+ this.Flow = ['#PCDATA','form'].concat(this.block, this.inline);
+ }(this);
+
+ this._commonsetting = function(self, names, value) {
+ for (var n = 0; n < names.length; n++) {
+ self[names[n]] = value;
+ }
+ }
+
+ // The tagAttributes class returns all valid attributes for a tag,
+ // e.g. a = this.tagAttributes.head
+ // a.head -> [ 'lang', 'xml:lang', 'dir', 'id', 'profile' ]
+ this.tagAttributes = new function(el, validation) {
+ this.title = el.i18n.concat('id');
+ this.html = this.title.concat('xmlns');
+ this.head = this.title.concat('profile');
+ this.base = ['id', 'href', 'target'];
+ this.meta = this.title.concat('http-equiv','name','content', 'scheme');
+ this.link = el.attrs.concat('charset','href','hreflang','type', 'rel','rev','media','target');
+ this.style = this.title.concat('type','media','title', 'xml:space');
+ this.script = ['id','charset','type','language','src','defer', 'xml:space'];
+ this.iframe = [
+ 'longdesc','name','src','frameborder','marginwidth',
+ 'marginheight','scrolling','align','height','width'].concat(el.coreattrs);
+ this.body = ['background','bgcolor','text','link','vlink','alink'].concat(el.attrs, el.loadevents);
+ validation._commonsetting(this,
+ ['p','div'].concat(el.heading),
+ ['align'].concat(el.attrs));
+ this.dl = this.dir = this.menu = el.attrs.concat('compact');
+ this.ul = this.menu.concat('type');
+ this.ol = this.ul.concat('start');
+ this.li = el.attrs.concat('type','value');
+ this.hr = el.attrs.concat('align','noshade','size','width');
+ this.pre = el.attrs.concat('width','xml:space');
+ this.blockquote = this.q = el.attrs.concat('cite');
+ this.ins = this.del = this.blockquote.concat('datetime');
+ this.a = el.attrs.concat(el.focus,'charset','type','name','href','hreflang','rel','rev','shape','coords','target');
+ this.bdo = el.coreattrs.concat(el.events, 'lang','xml:lang','dir');
+ this.br = el.coreattrs.concat('clear');
+ validation._commonsetting(this,
+ ['noscript','noframes','dt', 'dd', 'address','center','span','em', 'strong', 'dfn','code',
+ 'samp','kbd','var','cite','abbr','acronym','sub','sup','tt',
+ 'i','b','big','small','u','s','strike', 'fieldset'],
+ el.attrs);
+
+ this.basefont = ['id','size','color','face'];
+ this.font = el.coreattrs.concat(el.i18n, 'size','color','face');
+ this.object = el.attrs.concat('declare','classid','codebase','data','type','codetype','archive','standby','height','width','usemap','name','tabindex','align','border','hspace','vspace');
+ this.param = ['id','name','value','valuetype','type'];
+ this.applet = el.coreattrs.concat('codebase','archive','code','object','alt','name','width','height','align','hspace','vspace');
+ this.img = el.attrs.concat('src','alt','name','longdesc','height','width','usemap','ismap','align','border','hspace','vspace');
+ this.map = this.title.concat('title','name', 'style', 'class', el.events);
+ this.area = el.attrs.concat('shape','coords','href','nohref','alt','target', el.focus);
+ this.form = el.attrs.concat('action','method','name','enctype',el.formevents,'accept','accept-charset','target');
+ this.label = el.attrs.concat('for','accesskey', el.focusevents);
+ this.input = el.attrs.concat('type','name','value','checked','disabled','readonly','size','maxlength','src','alt','usemap',el.input,'accept','align', el.focus);
+ this.select = el.attrs.concat('name','size','multiple','disabled','tabindex', el.focusevents,el.input);
+ this.optgroup = el.attrs.concat('disabled','label');
+ this.option = el.attrs.concat('selected','disabled','label','value');
+ this.textarea = el.attrs.concat('name','rows','cols','disabled','readonly', el.inputevents, el.focus);
+ this.legend = el.attrs.concat('accesskey','align');
+ this.button = el.attrs.concat('name','value','type','disabled',el.focus);
+ this.isindex = el.coreattrs.concat('prompt', el.i18n);
+ this.table = el.attrs.concat('summary','width','border','frame','rules','cellspacing','cellpadding','align','bgcolor');
+ this.caption = el.attrs.concat('align');
+ this.col = this.colgroup = el.attrs.concat('span','width','halign','char','charoff','valign');
+ this.thead = el.attrs.concat('halign','char','charoff','valign');
+ this.tfoot = this.tbody = this.thead;
+ this.tr = this.thead.concat('bgcolor');
+ this.td = this.th = this.tr.concat('abbr','axis','headers','scope','rowspan','colspan','nowrap','width','height');
+ }(this.elements, this);
+
+ // State array. For each tag identifies what it can contain.
+ // I'm not attempting to check the order or number of contained
+ // tags (yet).
+ this.States = new function(el, validation) {
+
+ var here = this;
+ function setStates(tags, value) {
+ var valset = new validation.Set(value);
+
+ for (var i = 0; i < tags.length; i++) {
+ here[tags[i]] = valset;
+ }
+ }
+
+ setStates(['html'], ['head','body']);
+ setStates(['head'], ['title','base','script','style', 'meta','link','object','isindex']);
+ setStates([
+ 'base', 'meta', 'link', 'hr', 'param', 'img', 'area', 'input',
+ 'br', 'basefont', 'isindex', 'col',
+ ], []);
+
+ setStates(['title','style','script','option','textarea'], ['#PCDATA']);
+ setStates([ 'noscript', 'iframe', 'noframes', 'body', 'div',
+ 'li', 'dd', 'blockquote', 'center', 'ins', 'del', 'td', 'th',
+ ], el.Flow);
+
+ setStates(el.heading, el.Inline);
+ setStates([ 'p', 'dt', 'address', 'span', 'bdo', 'caption',
+ 'em', 'strong', 'dfn','code','samp','kbd','var',
+ 'cite','abbr','acronym','q','sub','sup','tt','i',
+ 'b','big','small','u','s','strike','font','label',
+ 'legend'], el.Inline);
+
+ setStates(['ul', 'ol', 'menu', 'dir', 'ul', ], ['li']);
+ setStates(['dl'], ['dt','dd']);
+ setStates(['pre'], validation._exclude(el.Inline, "img|object|applet|big|small|sub|sup|font|basefont"));
+ setStates(['a'], validation._exclude(el.Inline, "a"));
+ setStates(['applet', 'object'], ['#PCDATA', 'param','form'].concat(el.block, el.inline, el.misc));
+ setStates(['map'], ['form', 'area'].concat(el.block, el.misc));
+ setStates(['form'], validation._exclude(el.Flow, ['form']));
+ setStates(['select'], ['optgroup','option']);
+ setStates(['optgroup'], ['option']);
+ setStates(['fieldset'], ['#PCDATA','legend','form'].concat(el.block,el.inline,el.misc));
+ setStates(['button'], validation._exclude(el.Flow, ['a','form','iframe'].concat(el.inline_forms)));
+ setStates(['table'], ['caption','col','colgroup','thead','tfoot','tbody','tr']);
+ setStates(['thead', 'tfoot', 'tbody'], ['tr']);
+ setStates(['colgroup'], ['col']);
+ setStates(['tr'], ['th','td']);
+ }(this.elements, this);
+
+ // Permitted elements for style.
+ this.styleWhitelist = new this.Set(['text-align', 'list-style-type']);
+ this.classBlacklist = new this.Set(['MsoNormal', 'MsoTitle', 'MsoHeader', 'MsoFootnoteText',
+ 'Bullet1', 'Bullet2']);
+
+ this.classFilter = function(value) {
+ var classes = value.split(' ');
+ var filtered = [];
+ for (var i = 0; i < classes.length; i++) {
+ var c = classes[i];
+ if (c && !this.classBlacklist[c]) {
+ filtered.push(c);
+ }
+ }
+ return filtered.join(' ');
+ }
+ this._defaultCopyAttribute = function(name, htmlnode, xhtmlnode) {
+ var val = htmlnode.getAttribute(name);
+ if (val) xhtmlnode.setAttribute(name, val);
+ }
+ // Set up filters for attributes.
+ this.attrFilters = new function(validation, editor) {
+ var attrs = validation.elements.attributes;
+ for (var i=0; i < attrs.length; i++) {
+ this[attrs[i]] = validation._defaultCopyAttribute;
+ }
+ this['class'] = function(name, htmlnode, xhtmlnode) {
+ var val = htmlnode.getAttribute('class');
+ if (val) val = validation.classFilter(val);
+ if (val) xhtmlnode.setAttribute('class', val);
+ }
+ if (editor.getBrowserName()=="IE") {
+ this['class'] = function(name, htmlnode, xhtmlnode) {
+ var val = htmlnode.className;
+ if (val) val = validation.classFilter(val);
+ if (val) xhtmlnode.setAttribute('class', val);
+ }
+ this['http-equiv'] = function(name, htmlnode, xhtmlnode) {
+ var val = htmlnode.httpEquiv;
+ if (val) xhtmlnode.setAttribute('http-equiv', val);
+ }
+ this['xml:lang'] = this['xml:space'] = function(name, htmlnode, xhtmlnode) {
+ try {
+ var val = htmlnode.getAttribute(name);
+ if (val) xhtmlnode.setAttribute(name, val);
+ } catch(e) {
+ }
+ }
+ }
+ this.rowspan = this.colspan = function(name, htmlnode, xhtmlnode) {
+ var val = htmlnode.getAttribute(name);
+ if (val && val != '1') xhtmlnode.setAttribute(name, val);
+ }
+ this.style = function(name, htmlnode, xhtmlnode) {
+ var val = htmlnode.style.cssText;
+ if (val) {
+ var styles = val.split(/; */);
+ for (var i = styles.length; i >= 0; i--) if (styles[i]) {
+ var parts = /^([^:]+): *(.*)$/.exec(styles[i]);
+ var name = parts[1].toLowerCase();
+ if (validation.styleWhitelist[name]) {
+ styles[i] = name+': '+parts[2];
+ } else {
+ styles.splice(i,1); // delete
+ }
+ }
+ if (styles[styles.length-1]) styles.push('');
+ val = styles.join('; ').strip();
+ }
+ if (val) xhtmlnode.setAttribute('style', val);
+ }
+ }(this, editor);
+
+ // Exclude unwanted tags.
+ this.excludeTags(['center']);
+
+ if (editor.config && editor.config.htmlfilter) {
+ this.filterStructure = editor.config.htmlfilter.filterstructure;
+
+ var exclude = editor.config.htmlfilter;
+ if (exclude.a)
+ this.excludeAttributes(exclude.a);
+ if (exclude.t)
+ this.excludeTags(exclude.t);
+ if (exclude.c) {
+ var c = exclude.c;
+ if (!c.length) c = [c];
+ for (var i = 0; i < c.length; i++) {
+ this.excludeTagAttributes(c[i].t, c[i].a);
+ }
+ }
+ if (exclude.style) {
+ var s = exclude.style;
+ for (var i = 0; i < s.length; i++) {
+ this.styleWhitelist[s[i]] = 1;
+ }
+ }
+ if (exclude['class']) {
+ var c = exclude['class'];
+ for (var i = 0; i < c.length; i++) {
+ this.classBlacklist[c[i]] = 1;
+ }
+ }
+ };
+
+ // Copy all valid attributes from htmlnode to xhtmlnode.
+ this._copyAttributes = function(htmlnode, xhtmlnode, valid) {
+ for (var i = 0; i < valid.length; i++) {
+ var name = valid[i];
+ var filter = this.attrFilters[name];
+ if (filter) filter(name, htmlnode, xhtmlnode);
+ }
+ }
+
+ this._convertToSarissaNode = function(ownerdoc, htmlnode, xhtmlparent) {
+ return this._convertNodes(ownerdoc, htmlnode, xhtmlparent, new this.Set(['html']));
+ };
+
+ this._convertNodes = function(ownerdoc, htmlnode, xhtmlparent, permitted) {
+ var name, parentnode = xhtmlparent;
+ var nodename = this._getTagName(htmlnode);
+ var nostructure = !this.filterstructure;
+
+ // TODO: This permits valid tags anywhere. it should use the state
+ // table in xhtmlvalid to only permit tags where the XHTML DTD
+ // says they are valid.
+ var validattrs = this.tagAttributes[nodename];
+ if (validattrs && (nostructure || permitted[nodename])) {
+ try {
+ var xhtmlnode = ownerdoc.createElement(nodename);
+ parentnode = xhtmlnode;
+ } catch (e) { };
+
+ if (validattrs && xhtmlnode)
+ this._copyAttributes(htmlnode, xhtmlnode, validattrs);
+ }
+
+ var kids = htmlnode.childNodes;
+ if (kids && /base|meta|link|hr|param|img|area|input|br|basefont|isindex|col/.exec(nodename)) {
+ kids = []; // IE bug: base can think it has children
+ }
+ var permittedChildren = this.States[parentnode.tagName] || permitted;
+
+ if (kids.length == 0) {
+ if (htmlnode.text && htmlnode.text != "" &&
+ (nostructure || permittedChildren['#PCDATA'])) {
+ var text = htmlnode.text;
+ var tnode = ownerdoc.createTextNode(text);
+ parentnode.appendChild(tnode);
+ }
+ } else {
+ for (var i = 0; i < kids.length; i++) {
+ var kid = kids[i];
+ if (kid.nodeType == 1) {
+ var newkid = this._convertNodes(ownerdoc, kid, parentnode, permittedChildren);
+ if (newkid != null) {
+ parentnode.appendChild(newkid);
+ };
+ } else if (kid.nodeType == 3) {
+ if (nostructure || permittedChildren['#PCDATA'])
+ parentnode.appendChild(ownerdoc.createTextNode(kid.nodeValue));
+ } else if (kid.nodeType == 4) {
+ if (nostructure || permittedChildren['#PCDATA'])
+ parentnode.appendChild(ownerdoc.createCDATASection(kid.nodeValue));
+ }
+ }
+ }
+ return xhtmlnode;
+ };
+}
+
+
Added: incubator/graffito/trunk/applications/browser/src/webapp/kupu/kupucontextmenu.js
URL: http://svn.apache.org/viewcvs/incubator/graffito/trunk/applications/browser/src/webapp/kupu/kupucontextmenu.js?view=auto&rev=154214
==============================================================================
--- incubator/graffito/trunk/applications/browser/src/webapp/kupu/kupucontextmenu.js (added)
+++ incubator/graffito/trunk/applications/browser/src/webapp/kupu/kupucontextmenu.js Thu Feb 17 15:57:09 2005
@@ -0,0 +1,201 @@
+/*****************************************************************************
+ *
+ * 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: kupucontextmenu.js 7629 2004-11-23 17:05:25Z duncan $
+
+
+//----------------------------------------------------------------------------
+// ContextMenu
+//----------------------------------------------------------------------------
+
+function ContextMenu() {
+ /* the contextmenu */
+ this.contextmenu = null;
+ this.seperator = 1;
+
+ this.initialize = function(editor) {
+ /* set the event handlers and such */
+ this.editor = editor;
+ // needs some work since it won't work for more than one editor
+ addEventHandler(this.editor.getInnerDocument(), "contextmenu", this.createContextMenu, this);
+ //addEventHandler(editor.getInnerDocument(), "focus", this.hideContextMenu, this);
+ addEventHandler(document, "focus", this.hideContextMenu, this);
+ addEventHandler(editor.getInnerDocument(), "mousedown", this.hideContextMenu, this);
+ addEventHandler(document, "mousedown", this.hideContextMenu, this);
+ };
+
+ this.createContextMenu = function(event) {
+ /* Create and show the context menu
+
+ The method will ask all tools for any (optional) elements they
+ want to add the menu and when done render it
+ */
+ if (event.stopPropagation) {
+ event.stopPropagation();
+ };
+ event.returnValue = false;
+ if (this.editor.getBrowserName() == 'IE') {
+ this.editor._saveSelection();
+ };
+ // somehow Mozilla on Windows seems to generate the oncontextmenu event
+ // several times on each rightclick, here's a workaround
+ if (this.editor.getBrowserName() == 'Mozilla' && this.contextmenu) {
+ return false;
+ };
+ this.hideContextMenu();
+ var selNode = this.editor.getSelectedNode();
+ var elements = new Array();
+ for (var id in this.editor.tools) {
+ var tool = this.editor.tools[id];
+ // alas, some people seem to want backward compatibility ;)
+ if (tool.createContextMenuElements) {
+ var els = tool.createContextMenuElements(selNode, event);
+ elements = elements.concat(els);
+ };
+ };
+ // remove the last seperator
+ this._createNewContextMenu(elements, event);
+ this.last_event = event;
+ return false;
+ };
+
+ this.hideContextMenu = function(event) {
+ /* remove the context menu from view */
+ if (this.contextmenu) {
+ try {
+ window.document.getElementsByTagName('body')[0].removeChild(this.contextmenu);
+ } catch (e) {
+ // after some commands, the contextmenu will be removed by
+ // the browser, ignore those cases
+ };
+ this.contextmenu = null;
+ };
+ };
+
+ this._createNewContextMenu = function(elements, event) {
+ /* add the elements to the contextmenu and show it */
+ var doc = window.document;
+ var menu = doc.createElement('div');
+ menu.contentEditable = false;
+ menu.designMode = 'Off';
+ this._setMenuStyle(menu);
+ for (var i=0; i < elements.length; i++) {
+ var element = elements[i];
+ if (element !== this.seperator) {
+ var div = doc.createElement('div');
+ div.style.width = '100%';
+ var label = doc.createTextNode('\u00a0' + element.label);
+ div.appendChild(label);
+ menu.appendChild(div);
+ // set a reference to the div on the element
+ element.element = div;
+ addEventHandler(div, "mousedown", element.action, element.context);
+ addEventHandler(div, "mouseover", element.changeOverStyle, element);
+ addEventHandler(div, "mouseout", element.changeNormalStyle, element);
+ addEventHandler(div, "mouseup", this.hideContextMenu, this);
+ } else {
+ var hr = doc.createElement('hr');
+ menu.appendChild(hr);
+ };
+ };
+ // now move the menu to the right position
+ var iframe = this.editor.getDocument().getEditable();
+ var left = 0;
+ var top = 0;
+ if (this.editor.getBrowserName() == 'IE') {
+ var orgnode = event.srcElement;
+ left = event.clientX;
+ top = event.clientY;
+ var currnode = iframe;
+ while (currnode) {
+ left += currnode.offsetLeft + currnode.clientLeft;
+ top += currnode.offsetTop + currnode.clientTop;
+ currnode = currnode.offsetParent;
+ };
+ } else {
+ left = event.pageX;
+ top = event.pageY;
+ var body = this.editor.getInnerDocument().body;
+ left -= body.scrollLeft;
+ top -= body.scrollTop;
+ var node = iframe;
+ while (node) {
+ left += node.offsetLeft;
+ top += node.offsetTop;
+ node = node.offsetParent;
+ }
+ };
+ //var clienttop = event.clientY;
+ /*if (clienttop > (parseInt(this.editor.getDocument().getWindow().innerHeight) -
+ (parseInt(menu.style.lineHeight) * elements.length))) {
+ top -= parseInt(menu.style.lineHeight) * elements.length;
+ };*/
+ menu.style.left = left + 'px';
+ menu.style.top = top + 'px';
+ menu.style.visibility = 'visible';
+ addEventHandler(menu, 'focus', function() {this.blur}, menu)
+ doc.getElementsByTagName('body')[0].appendChild(menu);
+ this.contextmenu = menu;
+ };
+
+ this._setMenuStyle = function(menu) {
+ /* set the styles for the menu
+
+ to change the menu style, override this method
+ */
+ menu.style.position = 'absolute';
+ menu.style.backgroundColor = 'white';
+ menu.style.fontFamily = 'Verdana, Arial, Helvetica, sans-serif';
+ menu.style.fontSize = '12px';
+ menu.style.lineHeight = '16px';
+ menu.style.borderWidth = '1px';
+ menu.style.borderStyle = 'solid';
+ menu.style.borderColor = 'black';
+ menu.style.cursor = 'default';
+ menu.style.width = "8em";
+ };
+
+ this._showOriginalMenu = function(event) {
+ window.document.dispatchEvent(this._last_event);
+ };
+};
+
+function ContextMenuElement(label, action, context) {
+ /* context menu element struct
+
+ should be returned (optionally in a list) by the tools'
+ createContextMenuElements methods
+ */
+ this.label = label; // the text shown in the menu
+ this.action = action; // a reference to the method that should be called
+ this.context = context; // a reference to the object on which the method
+ // is defined
+ this.element = null; // the contextmenu machinery will add a reference
+ // to the element here
+
+ this.changeOverStyle = function(event) {
+ /* set the background of the element to 'mouseover' style
+
+ override only for the prototype, not for individual elements
+ so every element looks the same
+ */
+ this.element.style.backgroundColor = 'blue';
+ };
+
+ this.changeNormalStyle = function(event) {
+ /* set the background of the element back to 'normal' style
+
+ override only for the prototype, not for individual elements
+ so every element looks the same
+ */
+ this.element.style.backgroundColor = 'white';
+ };
+};
+
Added: incubator/graffito/trunk/applications/browser/src/webapp/kupu/kupudrawers.js
URL: http://svn.apache.org/viewcvs/incubator/graffito/trunk/applications/browser/src/webapp/kupu/kupudrawers.js?view=auto&rev=154214
==============================================================================
--- incubator/graffito/trunk/applications/browser/src/webapp/kupu/kupudrawers.js (added)
+++ incubator/graffito/trunk/applications/browser/src/webapp/kupu/kupudrawers.js Thu Feb 17 15:57:09 2005
@@ -0,0 +1,895 @@
+/*****************************************************************************
+ *
+ * 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: kupudrawers.js 7887 2004-12-16 16:15:29Z duncan $
+
+function DrawerTool() {
+ /* a tool to open and fill drawers
+
+ this tool has to (and should!) only be instantiated once
+ */
+ this.drawers = {};
+ this.current_drawer = null;
+
+ this.initialize = function(editor) {
+ this.editor = editor;
+ // this essentially makes the drawertool a singleton
+ window.drawertool = this;
+ };
+
+ this.registerDrawer = function(id, drawer) {
+ this.drawers[id] = drawer;
+ drawer.initialize(this.editor, this);
+ };
+
+ this.openDrawer = function(id) {
+ /* open a drawer */
+ if (this.current_drawer) {
+ this.closeDrawer();
+ };
+ if (this.editor.getBrowserName() == 'IE') {
+ this.editor._saveSelection();
+ }
+ var drawer = this.drawers[id];
+ drawer.createContent();
+ this.current_drawer = drawer;
+ };
+
+ this.updateState = function(selNode) {
+ if (this.current_drawer) {
+ this.closeDrawer();
+ };
+ };
+
+ this.closeDrawer = function() {
+ if (!this.current_drawer) {
+ return;
+ };
+ this.current_drawer.hide();
+ this.current_drawer = null;
+ };
+
+ this.getDrawerEnv = function(iframe_win) {
+ var drawer = null;
+ for (var id in this.drawers) {
+ var ldrawer = this.drawers[id];
+ // Note that we require drawers to provide us with an
+ // element property!
+ if (ldrawer.element.contentWindow == iframe_win) {
+ drawer = ldrawer;
+ };
+ };
+ if (!drawer) {
+ this.editor.logMessage("Drawer not found", 1);
+ return;
+ };
+ return {
+ 'drawer': drawer,
+ 'drawertool': this,
+ 'tool': drawer.tool
+ };
+ };
+};
+
+DrawerTool.prototype = new KupuTool;
+
+function Drawer(elementid, tool) {
+ /* base prototype for drawers */
+
+ this.element = document.getElementById(elementid);
+ this.tool = tool;
+
+ this.initialize = function(editor, drawertool) {
+ this.editor = editor;
+ this.drawertool = drawertool;
+ };
+
+ this.createContent = function() {
+ /* fill the drawer with some content */
+ // here's where any intelligence and XSLT transformation and such
+ // is done
+ this.element.style.display = 'block';
+ if (this.editor.getBrowserName() == 'IE') {
+ this.element.focus();
+ }
+ };
+
+ this.hide = function() {
+ this.element.style.display = 'none';
+ };
+};
+
+function LinkDrawer(elementid, tool) {
+ /* Link drawer */
+ this.element = document.getElementById(elementid);
+ this.tool = tool;
+
+ this.createContent = function() {
+ /* display the drawer */
+ var currnode = this.editor.getSelectedNode();
+ var linkel = this.editor.getNearestParentOfType(currnode, 'a');
+ var input = document.getElementById('kupu-linkdrawer-input');
+ input.value = "";
+ this.preview();
+ if (linkel) {
+ input.value = linkel.getAttribute('href');
+ } else {
+ input.value = 'http://';
+ };
+ this.element.style.display = 'block';
+ if (this.editor.getBrowserName() == 'IE') {
+ this.element.focus();
+ }
+ };
+
+ this.save = function() {
+ /* add or modify a link */
+ var input = document.getElementById('kupu-linkdrawer-input');
+ var url = input.value;
+ var target = '_self';
+ if (this.target) target = this.target;
+ this.tool.createLink(url, null, null, target);
+ input.value = '';
+
+ // XXX when reediting a link, the drawer does not close for
+ // some weird reason. BUG! Close the drawer manually until we
+ // find a fix:
+ this.drawertool.closeDrawer();
+ };
+
+ this.preview = function() {
+ var input = document.getElementById('kupu-linkdrawer-input');
+ var preview = document.getElementById('kupu-linkdrawer-preview');
+ preview.src = input.value;
+ if (this.editor.getBrowserName() == 'IE') {
+ preview.width = "800";
+ preview.height = "365";
+ preview.style.zoom = "60%";
+ };
+ }
+ this.preview_loaded = function() {
+ var input = document.getElementById('kupu-linkdrawer-input');
+ var preview = document.getElementById('kupu-linkdrawer-preview');
+ if (input.value != preview.src) {
+ input.value = preview.src;
+ }
+ }
+};
+
+LinkDrawer.prototype = new Drawer;
+
+function TableDrawer(elementid, tool) {
+ /* Table drawer */
+ this.element = document.getElementById(elementid);
+ this.tool = tool;
+
+ this.addpanelid = 'kupu-tabledrawer-addtable';
+ this.editpanelid = 'kupu-tabledrawer-edittable';
+
+ this.addpanel = document.getElementById(this.addpanelid);
+ this.editpanel = document.getElementById(this.editpanelid);
+
+ this.createContent = function() {
+ var selNode = this.editor.getSelectedNode();
+ if (this.editor.config.table_classes) {
+ var classselect = document.getElementById('kupu-tabledrawer-classchooser');
+ var classes = this.editor.config.table_classes['class'];
+ while (classselect.hasChildNodes()) {
+ classselect.removeChild(classselect.firstChild);
+ };
+ for (var i=0; i < classes.length; i++) {
+ var classname = classes[i];
+ var option = document.createElement('option');
+ var content = document.createTextNode(classname);
+ option.appendChild(content);
+ option.setAttribute('value', classname);
+ classselect.appendChild(option);
+ };
+ };
+
+ var table = this.editor.getNearestParentOfType(selNode, 'table');
+
+ if (!table) {
+ // show add table drawer
+ show = this.addpanel;
+ hide = this.editpanel;
+ } else {
+ // show edit table drawer
+ show = this.editpanel;
+ hide = this.addpanel;
+ var align = this.tool._getColumnAlign(selNode);
+ var alignselect = document.getElementById('kupu-tabledrawer-alignchooser');
+ selectSelectItem(alignselect, align);
+ var classselect = document.getElementById('kupu-tabledrawer-classchooser');
+ selectSelectItem(classselect, table.className);
+ };
+ hide.style.display = 'none';
+ show.style.display = 'block';
+ this.element.style.display = 'block';
+ if (this.editor.getBrowserName() == 'IE') {
+ this.element.focus();
+ }
+ };
+
+ this.createTable = function() {
+ var rows = document.getElementById('kupu-tabledrawer-newrows').value;
+ var cols = document.getElementById('kupu-tabledrawer-newcols').value;
+ var style = document.getElementById('kupu-tabledrawer-classchooser').value;
+ var add_header = document.getElementById('kupu-tabledrawer-makeheader').checked;
+ this.tool.createTable(parseInt(rows), parseInt(cols), add_header, style);
+ this.drawertool.closeDrawer();
+ };
+};
+
+TableDrawer.prototype = new Drawer;
+
+function LibraryDrawer(tool, xsluri, libsuri, searchuri) {
+ /* a drawer that loads XSLT and XML from the server
+ and converts the XML to XHTML for the drawer using the XSLT
+
+ there are 2 types of XML file loaded from the server: the first
+ contains a list of 'libraries', partitions for the data items,
+ and the second a list of data items for a certain library
+
+ all XML loading is done async, since sync loading can freeze Mozilla
+ */
+
+ this.init = function(tool, xsluri, libsuri, searchuri) {
+ /* This method is there to thin out the constructor and to be
+ able to inherit it in sub-prototypes. Don't confuse this
+ method with the component initializer (initialize()).
+ */
+ // these are used in the XSLT. Maybe they should be
+ // parameterized or something, but we depend on so many other
+ // things implicitly anyway...
+ this.drawerid = 'kupu-librarydrawer';
+ this.librariespanelid = 'kupu-librariespanel';
+ this.resourcespanelid = 'kupu-resourcespanel';
+ this.propertiespanelid = 'kupu-propertiespanel';
+
+ this.tool = tool;
+ this.element = document.getElementById(this.drawerid);
+ this.xsluri = xsluri;
+ this.libsuri = libsuri;
+ this.searchuri = searchuri;
+
+ // marker that gets set when a new image has been uploaded
+ this.newimages = null;
+
+ // the following vars will be available after this.initialize()
+ // has been called
+
+ // this will be filled by this._libXslCallback()
+ this.xsl = null;
+ // this will be filled by this.loadLibraries(), which is called
+ // somewhere further down the chain starting with
+ // this._libsXslCallback()
+ this.xmldata = null;
+
+ };
+ this.init(tool, xsluri, libsuri, searchuri);
+
+ this.initialize = function(editor, drawertool) {
+ this.editor = editor;
+ this.drawertool = drawertool;
+
+ // load the xsl and the initial xml
+ var wrapped_callback = new ContextFixer(this._libsXslCallback, this);
+ this._loadXML(this.xsluri, wrapped_callback.execute);
+ };
+
+ /*** bootstrapping ***/
+
+ this._libsXslCallback = function(dom) {
+ /* callback for when the xsl for the libs is loaded
+
+ this is called on init and since the initial libs need
+ to be loaded as well (and everything is async with callbacks
+ so there's no way to wait until the XSL is loaded) this
+ will also make the first loadLibraries call
+ */
+ this.xsl = dom;
+
+ // Change by Paul to have cached xslt transformers for reuse of
+ // multiple transforms and also xslt params
+ try {
+ this.xsltproc = new XSLTProcessor();
+ this.xsltproc.importStylesheet(dom);
+ this.xsltproc.setParameter("", "drawertype", this.drawertype);
+ this.xsltproc.setParameter("", "drawertitle", this.drawertitle);
+ this.xsltproc.setParameter("", "showupload", this.showupload);
+ if (this.editor.config.captions) {
+ this.xsltproc.setParameter("", "usecaptions", 'yes');
+ }
+ } catch(e) {
+ return; // No XSLT Processor, maybe IE 5.5?
+ }
+ };
+
+ this.createContent = function() {
+ // load the initial XML
+ if(!this.xmldata) {
+ // Do a meaningful test to see if this is IE5.5 or some other
+ // editor-enabled version whose XML support isn't good enough
+ // for the drawers
+ if (!Sarissa.IS_ENABLED_XSLTPROC) {
+ alert("This function requires better XML support in your browser.");
+ return;
+ }
+ this.loadLibraries();
+ } else {
+ if (this.newimages) {
+ this.reloadCurrent();
+ this.newimages = null;
+ };
+ this.updateDisplay();
+ };
+
+ // display the drawer div
+ this.element.style.display = 'block';
+ if (this.editor.getBrowserName() == 'IE') {
+ this.element.focus();
+ }
+ };
+
+ this._singleLibsXslCallback = function(dom) {
+ /* callback for then the xsl for single libs (items) is loaded
+
+ nothing special needs to be called here, since initially the
+ items pane will be empty
+ */
+ this.singlelibxsl = dom;
+ };
+
+ this.loadLibraries = function() {
+ /* load the libraries and display them in a redrawn drawer */
+ var wrapped_callback = new ContextFixer(this._libsContentCallback, this);
+ this._loadXML(this.libsuri, wrapped_callback.execute);
+ };
+
+ this._libsContentCallback = function(dom) {
+ /* this is called when the libs xml is loaded
+
+ does the xslt transformation to set up or renew the drawer's full
+ content and adds the content to the drawer
+ */
+ this.xmldata = dom;
+ this.xmldata.setProperty("SelectionLanguage", "XPath");
+
+ // replace whatever is in there with our stuff
+ this.updateDisplay(this.drawerid);
+ };
+
+ this.updateDisplay = function(id) {
+ /* (re-)transform XML and (re-)display the necessary part
+ */
+ if(!id) {
+ id = this.drawerid;
+ };
+ try {
+ this.xsltproc.setParameter("", "showupload", this.showupload);
+ } catch(e) {};
+ var doc = this._transformXml();
+ var sourcenode = doc.selectSingleNode('//*[@id="'+id+'"]');
+ var targetnode = document.getElementById(id);
+ this._replaceNodeContents(document, targetnode, sourcenode);
+
+ if (this.editor.getBrowserName() == 'IE' && id == this.resourcespanelid) {
+ this.updateDisplay(this.drawerid);
+ };
+ };
+
+ this.deselectActiveCollection = function() {
+ /* Deselect the currently active collection or library */
+ while (1) {
+ // deselect selected DOM node
+ var selected = this.xmldata.selectSingleNode('//*[@selected]');
+ if (!selected) {
+ return;
+ };
+ selected.removeAttribute('selected');
+ };
+ };
+
+ /*** Load a library ***/
+
+ this.selectLibrary = function(id) {
+ /* unselect the currently selected lib and select a new one
+
+ the selected lib (libraries pane) will have a specific CSS class
+ (selected)
+ */
+ // remove selection in the DOM
+ this.deselectActiveCollection();
+ // as well as visual selection in CSS
+ // XXX this is slow, but we can't do XPath, unfortunately
+ var divs = this.element.getElementsByTagName('div');
+ for (var i=0; i<divs.length; i++ ) {
+ if (divs[i].className == 'kupu-libsource-selected') {
+ divs[i].className = 'kupu-libsource';
+ };
+ };
+
+ var libnode_path = '/libraries/library[@id="' + id + '"]';
+ var libnode = this.xmldata.selectSingleNode(libnode_path);
+ libnode.setAttribute('selected', '1');
+
+ var items_xpath = "items";
+ var items_node = libnode.selectSingleNode(items_xpath);
+
+ if (items_node && !this.newimages) {
+ // The library has already been loaded before or was
+ // already provided with an items list. No need to do
+ // anything except for displaying the contents in the
+ // middle pane. Newimages is set if we've lately
+ // added an image.
+ this.updateDisplay(this.resourcespanelid);
+ this.updateDisplay(this.propertiespanelid);
+ } else {
+ // We have to load the library from XML first.
+ var src_uri = libnode.selectSingleNode('src/text()').nodeValue;
+ src_uri = src_uri.strip(); // needs kupuhelpers.js
+ // Now load the library into the items pane. Since we have
+ // to load the XML, do this via a call back
+ var wrapped_callback = new ContextFixer(this._libraryContentCallback, this);
+ this._loadXML(src_uri, wrapped_callback.execute, null);
+ this.newimages = null;
+ };
+ // instead of running the full transformations again we get a
+ // reference to the element and set the classname...
+ var newseldiv = document.getElementById(id);
+ newseldiv.className = 'kupu-libsource-selected';
+ };
+
+ this._libraryContentCallback = function(dom, src_uri) {
+ /* callback for when a library's contents (item list) is loaded
+
+ This is also used as he handler for reloading a standard
+ collection.
+ */
+ var libnode = this.xmldata.selectSingleNode('//*[@selected]');
+ var itemsnode = libnode.selectSingleNode("items");
+ var newitemsnode = dom.selectSingleNode("//items");
+
+ // IE does not support importNode on XML document nodes. As an
+ // evil hack, clonde the node instead.
+
+ if (this.editor.getBrowserName() == 'IE') {
+ newitemsnode = newitemsnode.cloneNode(true);
+ } else {
+ newitemsnode = this.xmldata.importNode(newitemsnode, true);
+ }
+ if (!itemsnode) {
+ // We're loading this for the first time
+ libnode.appendChild(newitemsnode);
+ } else {
+ // User has clicked reload
+ libnode.replaceChild(newitemsnode, itemsnode);
+ };
+ this.updateDisplay(this.resourcespanelid);
+ this.updateDisplay(this.propertiespanelid);
+ };
+
+ /*** Load a collection ***/
+
+ this.selectCollection = function(id) {
+ this.deselectActiveCollection();
+
+ // First turn off current selection, if any
+ this.removeSelection();
+
+ var leafnode_path = "//collection[@id='" + id + "']";
+ var leafnode = this.xmldata.selectSingleNode(leafnode_path);
+
+ // Case 1: We've already loaded the data, so we just need to
+ // refer to the data by id.
+ var loadedInNode = leafnode.getAttribute('loadedInNode');
+ if (loadedInNode) {
+ var collnode_path = "/libraries/collection[@id='" + loadedInNode + "']";
+ var collnode = this.xmldata.selectSingleNode(collnode_path);
+ if (collnode) {
+ collnode.setAttribute('selected', '1');
+ this.updateDisplay(this.resourcespanelid);
+ this.updateDisplay(this.propertiespanelid);
+ return;
+ };
+ };
+
+ // Case 2: We've already loaded the data, but there hasn't
+ // been a reference made yet. So, make one :)
+ uri = leafnode.selectSingleNode('uri/text()').nodeValue;
+ uri = (new String(uri)).strip(); // needs kupuhelpers.js
+ var collnode_path = "/libraries/collection/uri[text()='" + uri + "']/..";
+ var collnode = this.xmldata.selectSingleNode(collnode_path);
+ if (collnode) {
+ id = collnode.getAttribute('id');
+ leafnode.setAttribute('loadedInNode', id);
+ collnode.setAttribute('selected', '1');
+ this.updateDisplay(this.resourcespanelid);
+ this.updateDisplay(this.propertiespanelid);
+ return;
+ };
+
+ // Case 3: We've not loaded the data yet, so we need to load it
+ // this is just so we can find the leafnode much easier in the
+ // callback.
+ leafnode.setAttribute('selected', '1');
+ var src_uri = leafnode.selectSingleNode('src/text()').nodeValue;
+ src_uri = src_uri.strip(); // needs kupuhelpers.js
+ var wrapped_callback = new ContextFixer(this._collectionContentCallback, this);
+ this._loadXML(src_uri, wrapped_callback.execute, null);
+ };
+
+ this._collectionContentCallback = function(dom, src_uri) {
+ // Unlike with libraries, we don't have to find a node to hook
+ // our results into (UNLESS we've hit the reload button, but
+ // that is handled in _libraryContentCallback anyway).
+ // We need to give the newly retrieved data a unique ID, we
+ // just use the time.
+ date = new Date();
+ time = date.getTime();
+
+ // attach 'loadedInNode' attribute to leaf node so Case 1
+ // applies next time.
+ var leafnode = this.xmldata.selectSingleNode('//*[@selected]');
+ leafnode.setAttribute('loadedInNode', time);
+ this.deselectActiveCollection()
+
+ var collnode = dom.selectSingleNode('/collection');
+ collnode.setAttribute('id', time);
+ collnode.setAttribute('selected', '1');
+
+ var libraries = this.xmldata.selectSingleNode('/libraries');
+
+ // IE does not support importNode on XML documet nodes
+ if (this.editor.getBrowserName() == 'IE') {
+ collnode = collnode.cloneNode(true);
+ } else {
+ collnode = this.xmldata.importNode(collnode, true);
+ }
+ libraries.appendChild(collnode);
+ this.updateDisplay(this.resourcespanelid);
+ this.updateDisplay(this.propertiespanelid);
+ };
+
+ /*** Reloading a collection or library ***/
+
+ this.reloadCurrent = function() {
+ // Reload current collection or library
+ this.showupload = '';
+ var current = this.xmldata.selectSingleNode('//*[@selected]');
+ // make sure we're dealing with a collection even though a
+ // resource might be selected
+ if (current.tagName == "resource") {
+ current.removeAttribute("selected");
+ current = current.parentNode;
+ current.setAttribute("selected", "1");
+ };
+ var src_node = current.selectSingleNode('src');
+ if (!src_node) {
+ // simply do nothing if the library cannot be reloaded. This
+ // is currently the case w/ search result libraries.
+ return;
+ };
+
+ var src_uri = src_node.selectSingleNode('text()').nodeValue;
+
+ src_uri = src_uri.strip(); // needs kupuhelpers.js
+
+ var wrapped_callback = new ContextFixer(this._libraryContentCallback, this);
+ this._loadXML(src_uri, wrapped_callback.execute);
+ };
+
+ this.removeSelection = function() {
+ // turn off current selection, if any
+ var oldselxpath = '/libraries/*[@selected]//resource[@selected]';
+ var oldselitem = this.xmldata.selectSingleNode(oldselxpath);
+ if (oldselitem) {
+ oldselitem.removeAttribute("selected");
+ };
+ this.showupload = '';
+ }
+
+ this.selectUpload = function() {
+ this.removeSelection();
+ this.showupload = 'yes';
+ this.updateDisplay(this.resourcespanelid);
+ this.updateDisplay(this.propertiespanelid);
+ }
+ /*** Selecting a resource ***/
+
+ this.selectItem = function (id) {
+ /* select an item in the item pane, show the item's metadata */
+
+ // First turn off current selection, if any
+ this.removeSelection();
+
+ // Grab XML DOM node for clicked "resource" and mark it selected
+ var newselxpath = '/libraries/*[@selected]//resource[@id="' + id + '"]';
+ var newselitem = this.xmldata.selectSingleNode(newselxpath);
+ newselitem.setAttribute("selected", "1");
+
+ this.updateDisplay(this.resourcespanelid);
+ this.updateDisplay(this.propertiespanelid);
+ return;
+ }
+
+
+ this.search = function() {
+ /* search */
+ var searchvalue = document.getElementById('kupu-searchbox-input').value;
+ //XXX make search variable configurable
+ var body = 'SearchableText=' + escape(searchvalue);
+
+ // the search uri might contain query parameters in HTTP GET
+ // style. We want to do a POST though, so find any possible
+ // parameters, trim them from the URI and append them to the
+ // POST body instead.
+ var chunks = this.searchuri.split('?');
+ var searchuri = chunks[0];
+ if (chunks[1]) {
+ body += "&" + chunks[1];
+ };
+ var wrapped_callback = new ContextFixer(this._searchCallback, this);
+ this._loadXML(searchuri, wrapped_callback.execute, body);
+ };
+
+ this._searchCallback = function(dom) {
+ var resultlib = dom.selectSingleNode("/library");
+
+ var items = resultlib.selectNodes("items/*");
+ if (!items.length) {
+ alert("No results found.");
+ return;
+ };
+
+ // we need to give the newly retrieved data a unique ID, we
+ // just use the time.
+ date = new Date();
+ time = date.getTime();
+ resultlib.setAttribute("id", time);
+
+ // deselect the previous collection and mark the result
+ // library as selected
+ this.deselectActiveCollection();
+ resultlib.setAttribute("selected", "1");
+
+ // now hook the result library into our DOM
+ if (this.editor.getBrowserName() == 'IE') {
+ resultlib = resultlib.cloneNode(true);
+ } else {
+ this.xmldata.importNode(resultlib, true);
+ }
+ var libraries = this.xmldata.selectSingleNode("/libraries");
+ libraries.appendChild(resultlib);
+
+ this.updateDisplay(this.drawerid);
+ var newseldiv = document.getElementById(time);
+ newseldiv.className = 'selected';
+ };
+
+ this.save = function() {
+ /* save the element, should be implemented on subclasses */
+ throw "Not yet implemented";
+ };
+
+ /*** Auxiliary methods ***/
+
+ this._transformXml = function() {
+ /* transform this.xmldata to HTML using this.xsl and return it */
+ var doc = Sarissa.getDomDocument();
+
+ //var xsltproc = new XSLTProcessor();
+ var result = this.xsltproc.transformToDocument(this.xmldata);
+
+ // this.xmldata.transformNodeToObject(this.xsl, doc);
+ return result;
+ };
+
+ this._loadXML = function(uri, callback, body) {
+ /* load the XML from a uri
+
+ calls callback with one arg (the XML DOM) when done
+ the (optional) body arg should contain the body for the request
+*/
+ var xmlhttp = Sarissa.getXmlHttpRequest();
+ var method = 'GET';
+ if (body) {
+ method = 'POST';
+ } else {
+ // be sure that body is null and not an empty string or
+ // something
+ body = null;
+ };
+ xmlhttp.open(method, uri, true);
+ // use ContextFixer to wrap the Sarissa callback, both for isolating
+ // the 'this' problem and to be able to pass in an extra argument
+ // (callback)
+ var wrapped_callback = new ContextFixer(this._sarissaCallback, xmlhttp,
+ callback, uri);
+ xmlhttp.onreadystatechange = wrapped_callback.execute;
+ if (method == "POST") {
+ // by default, we would send a 'text/xml' request, which
+ // is a dirty lie; explicitly set the content type to what
+ // a web server expects from a POST.
+ xmlhttp.setRequestHeader('content-type', 'application/x-www-form-urlencoded');
+ };
+ xmlhttp.send(body);
+ };
+
+ this._replaceNodeContents = function(doc, target, container) {
+ /* replace all childnodes in target with all childnodes in container */
+ var importedContainer = doc.importNode(container, true);
+ // XXX it seems that IE doesn't allow hacks like these
+ // no need to worry anyway, since the transformed HTML seems
+ // to have the right JS context variables anyway.
+
+ if (this.editor.getBrowserName() != 'IE') {
+ container.ownerDocument.contentWindow = doc.contentWindow;
+ };
+ while (target.hasChildNodes()) {
+ target.removeChild(target.firstChild);
+ };
+ // XXX don't know if this works since i'm not sure whether
+ // appendChild actually removes a child from a previous
+ // location (although i think it does)
+ while (importedContainer.hasChildNodes()) {
+ target.appendChild(importedContainer.firstChild);
+ };
+ };
+
+ this._sarissaCallback = function(user_callback, uri) {
+ /* callback for Sarissa
+ when the callback is called because the data's ready it
+ will get the responseXML DOM and call user_callback
+ with the DOM as the first argument and the uri loaded
+ as the second
+
+ note that this method should be called in the context of an
+ xmlhttp object
+ */
+ var errmessage = 'Error loading XML: ';
+ if (uri) {
+ errmessage = 'Error loading ' + uri + ':';
+ };
+ if (this.readyState == 4) {
+ if (this.status && this.status != 200) {
+ alert(errmessage + this.status);
+ throw "Error loading XML";
+ };
+ var dom = this.responseXML;
+ user_callback(dom, uri);
+ };
+ };
+};
+
+LibraryDrawer.prototype = new Drawer;
+
+function ImageLibraryDrawer(tool, xsluri, libsuri, searchuri) {
+ /* a specific LibraryDrawer for images */
+
+ this.drawertitle = "Image Library";
+ this.drawertype = "image";
+ this.showupload = '';
+ this.init(tool, xsluri, libsuri, searchuri);
+
+
+ // upload, on submit/insert press
+ this.uploadImage = function() {
+ var form = document.kupu_upload_form;
+ if (!form || form.node_prop_image.value=='') return;
+
+ if (form.node_prop_caption.value == "") {
+ alert("Please enter a title for the image you are uploading");
+ return;
+ };
+
+ var targeturi = this.xmldata.selectSingleNode('/libraries/*[@selected]/uri/text()').nodeValue
+ document.kupu_upload_form.action = targeturi + "/kupuUploadImage";
+ document.kupu_upload_form.submit();
+ };
+
+ // called for example when no permission to upload for some reason
+ this.cancelUpload = function(msg) {
+ var s = this.xmldata.selectSingleNode('/libraries/*[@selected]');
+ s.removeAttribute("selected");
+ this.updateDisplay();
+ if (msg != '') {
+ alert(msg);
+ };
+ };
+
+ // called by onLoad within document sent by server
+ this.finishUpload = function(url) {
+ var img = this.tool.createImage(url);
+ if (this.editor.config.captions) {
+ img.className = img.className + " captioned";
+ }
+ this.newimages = 1;
+ this.drawertool.closeDrawer();
+ };
+
+
+ this.save = function() {
+ /* create an image in the iframe according to collected data
+ from the drawer */
+ var selxpath = '//resource[@selected]';
+ var selnode = this.xmldata.selectSingleNode(selxpath);
+
+ // If no image resource is selected, check for upload
+ if (!selnode) {
+ var uploadbutton = this.xmldata.selectSingleNode("/libraries/*[@selected]//uploadbutton");
+ if (uploadbutton) {
+ this.uploadImage();
+ };
+ return;
+ };
+
+ var uri = selnode.selectSingleNode('uri/text()').nodeValue;
+ uri = uri.strip(); // needs kupuhelpers.js
+ var img = this.tool.createImage(uri);
+ var alt = document.getElementById('image_alt').value;
+ img.setAttribute('alt', alt);
+
+ // Set image class from the alignment radio buttons
+ var radios = document.getElementsByName('image-align');
+ for (var i = 0; i < radios.length; i++) {
+ if (radios[i].checked) {
+ img.className = radios[i].value;
+ }
+ }
+
+ var caption = document.getElementsByName('image-caption');
+ if (caption && caption.length>0 && caption[0].checked) {
+ img.className = img.className + " captioned";
+ }
+
+ this.drawertool.closeDrawer();
+ };
+};
+
+ImageLibraryDrawer.prototype = new LibraryDrawer;
+
+function LinkLibraryDrawer(tool, xsluri, libsuri, searchuri) {
+ /* a specific LibraryDrawer for links */
+
+ this.drawertitle = "Link Drawer";
+ this.drawertype = "link";
+ this.showupload = '';
+ this.init(tool, xsluri, libsuri, searchuri);
+
+ this.save = function() {
+ /* create a link in the iframe according to collected data
+ from the drawer */
+ var selxpath = '//resource[@selected]';
+ var selnode = this.xmldata.selectSingleNode(selxpath);
+ if (!selnode) {
+ return;
+ };
+
+ var uri = selnode.selectSingleNode('uri/text()').nodeValue;
+ uri = uri.strip(); // needs kupuhelpers.js
+ var title = '';
+ title = selnode.selectSingleNode('title/text()').nodeValue;
+ title = title.strip();
+
+ // XXX requiring the user to know what link type to enter is a
+ // little too much I think. (philiKON)
+ var type = null;
+ var name = document.getElementById('link_name').value;
+ var target = null;
+ if (document.getElementById('link_target') && document.getElementById('link_target').value != '')
+ target = document.getElementById('link_target').value;
+
+ this.tool.createLink(uri, type, name, target, title);
+ };
+};
+
+LinkLibraryDrawer.prototype = new LibraryDrawer;
Added: incubator/graffito/trunk/applications/browser/src/webapp/kupu/kupudrawers/allimages.xml
URL: http://svn.apache.org/viewcvs/incubator/graffito/trunk/applications/browser/src/webapp/kupu/kupudrawers/allimages.xml?view=auto&rev=154214
==============================================================================
--- incubator/graffito/trunk/applications/browser/src/webapp/kupu/kupudrawers/allimages.xml (added)
+++ incubator/graffito/trunk/applications/browser/src/webapp/kupu/kupudrawers/allimages.xml Thu Feb 17 15:57:09 2005
@@ -0,0 +1,21 @@
+<?xml version="1.0" ?>
+<collection>
+ <uri>kupudrawers/allimages.xml</uri>
+ <icon>kupuimages/kupulibrary.png</icon>
+ <title>All images</title>
+ <src>kupudrawers/allimages.xml</src>
+ <items>
+ <collection id="logos">
+ <uri>kupudrawers/logos.xml</uri>
+ <title>Logo's</title>
+ <src>kupudrawers/logos.xml</src>
+ <icon>kupuimages/kupulibrary.png</icon>
+ </collection>
+ <collection id="kupubuttons">
+ <uri>kupudrawers/kupubuttons.xml</uri>
+ <title>Kupu buttons</title>
+ <src>kupudrawers/kupubuttons.xml</src>
+ <icon>kupuimages/kupulibrary.png</icon>
+ </collection>
+ </items>
+</collection>