diff options
Diffstat (limited to 'js/dojo/dojox/editor/plugins/TablePlugins.js')
| -rw-r--r-- | js/dojo/dojox/editor/plugins/TablePlugins.js | 1224 |
1 files changed, 1224 insertions, 0 deletions
diff --git a/js/dojo/dojox/editor/plugins/TablePlugins.js b/js/dojo/dojox/editor/plugins/TablePlugins.js new file mode 100644 index 0000000..f57de34 --- /dev/null +++ b/js/dojo/dojox/editor/plugins/TablePlugins.js @@ -0,0 +1,1224 @@ +//>>built +define("dojox/editor/plugins/TablePlugins", [ + "dojo", + "dijit", + "dojox", + "dijit/_base/popup", + "dijit/_Widget", + "dijit/_TemplatedMixin", + "dijit/_WidgetsInTemplateMixin", + "dijit/Menu", + "dijit/MenuItem", + "dijit/MenuSeparator", + "dijit/TooltipDialog", + "dijit/form/Button", + "dijit/form/DropDownButton", + "dijit/Dialog", + "dijit/form/TextBox", + "dijit/form/FilteringSelect", + "dijit/popup", + "dijit/_editor/_Plugin", + "dijit/_editor/range", + "dijit/_editor/selection", + "dijit/ColorPalette", + "dojox/widget/ColorPicker", + "dojo/_base/connect", + "dojo/_base/declare", + "dojo/i18n", + "dojo/i18n!dojox/editor/plugins/nls/TableDialog" +], function(dojo, dijit, dojox) { + +dojo.experimental("dojox.editor.plugins.TablePlugins"); + +// summary: +// A series of plugins that give the Editor the ability to create and edit +// HTML tables. See the end of this document for all avaiable plugins +// and dojox/editorPlugins/tests/editorTablePlugs.html for an example +// +// example: +// | <div dojoType="dijit.Editor" plugins="[ +// | 'bold','italic','|', +// | {name: 'dojox.editor.plugins.TablePlugins', command: 'insertTable'}, +// | {name: 'dojox.editor.plugins.TablePlugins', command: 'modifyTable'} +// | ]"> +// | Editor text is here +// | </div> +// +// TODO: +// Currently not supporting merging or splitting cells +// +// FIXME: Undo is very buggy, and therefore unimeplented in all browsers +// except IE - which itself has only been lightly tested. +// +// FIXME: Selecting multiple table cells in Firefox looks to be impossible. +// This affect the 'colorTableCell' plugin. Cells can still be +// colored individually or in rows. + +dojo.declare("dojox.editor.plugins._TableHandler", dijit._editor._Plugin,{ + // summary: + // A global object that handles common tasks for all the plugins. Since + // there are several plugins that are all calling common methods, it's preferable + // that they call a centralized location that either has a set variable or a + // timeout to only repeat code-heavy calls when necessary. + // + tablesConnected:false, + currentlyAvailable: false, + alwaysAvailable:false, + availableCurrentlySet:false, + initialized:false, + tableData: null, + shiftKeyDown:false, + editorDomNode: null, + undoEnabled: true, //Using custom undo for all browsers. + refCount: 0, + + doMixins: function(){ + + dojo.mixin(this.editor,{ + getAncestorElement: function(tagName){ + return dojo.withGlobal(this.window, "getAncestorElement",dijit._editor.selection, [tagName]); + }, + hasAncestorElement: function(tagName){ + return dojo.withGlobal(this.window, "hasAncestorElement",dijit._editor.selection, [tagName]); + }, + selectElement: function(elem){ + dojo.withGlobal(this.window, "selectElement",dijit._editor.selection, [elem]); + }, + byId: function(id){ + return dojo.withGlobal(this.window, "byId", dojo, [id]); + }, + query: function(arg, scope, returnFirstOnly){ + // this shortcut is dubious - not sure scoping is necessary + var ar = dojo.withGlobal(this.window, "query", dojo, [arg, scope]); + return (returnFirstOnly) ? ar[0] : ar; + } + }); + + }, + initialize: function(editor){ + // summary: + // Initialize the global handler upon a plugin's first instance of setEditor + // + + // All plugins will attempt initialization. We only need to do so once. + // But keep track so that it is cleaned up when all usage of it for an editor has + // been removed. + this.refCount++; + + // Turn on custom undo for all. + editor.customUndo = true; + + if(this.initialized){ return; } + + this.initialized = true; + this.editor = editor; + + this.editor._tablePluginHandler = this; + + //Editor loads async, can't assume doc is ready yet. So, use the deferred of the + //editor to init at the right time. + editor.onLoadDeferred.addCallback(dojo.hitch(this, function(){ + this.editorDomNode = this.editor.editNode || this.editor.iframe.document.body.firstChild; + + // RichText should have a mouseup connection to recognize drag-selections + // Example would be selecting multiple table cells + this._myListeners = []; + this._myListeners.push(dojo.connect(this.editorDomNode , "mouseup", this.editor, "onClick")); + this._myListeners.push(dojo.connect(this.editor, "onDisplayChanged", this, "checkAvailable")); + this._myListeners.push(dojo.connect(this.editor, "onBlur", this, "checkAvailable")); + this.doMixins(); + this.connectDraggable(); + })); + }, + + getTableInfo: function(forceNewData){ + // summary: + // Gets the table in focus + // Collects info on the table - see return params + // + if(forceNewData){ this._tempStoreTableData(false); } + if(this.tableData){ + // tableData is set for a short amount of time, so that all + // plugins get the same return without doing the method over + //console.log("returning current tableData:", this.tableData); + return this.tableData; + } + var tr, trs, td, tds, tbl, cols, tdIndex, trIndex; + + td = this.editor.getAncestorElement("td"); + if(td){ tr = td.parentNode; } + + tbl = this.editor.getAncestorElement("table"); + //console.log("td:", td);console.log("tr:", tr);console.log("tbl:", tbl) + + tds = dojo.query("td", tbl); + tds.forEach(function(d, i){ + if(td==d){tdIndex = i;} + }); + trs = dojo.query("tr", tbl); + trs.forEach(function(r, i){ + if(tr==r){trIndex = i;} + }); + cols = tds.length/trs.length; + var o = { + tbl:tbl, // focused table + td:td, // focused TD + tr:tr, // focused TR + trs:trs, // rows + tds:tds, // cells + rows:trs.length,// row amount + cols:cols, // column amount + tdIndex:tdIndex,// index of focused cell + trIndex:trIndex, // index of focused row + colIndex:tdIndex%cols + }; + //console.log("NEW tableData:",o); + this.tableData = o; + this._tempStoreTableData(500); + return this.tableData; + }, + + connectDraggable: function(){ + // summary: + // Detects drag-n-drop in the editor (could probably be moved to there) + // Currently only checks if item dragged was a TABLE, and removes its align attr + // DOES NOT WORK IN FF - it could - but FF's drag detection is a monster + // + if(!dojo.isIE){ + //console.warn("Drag and Drop is currently only detectable in IE."); + return; + } + + // IE ONLY + this.editorDomNode.ondragstart = dojo.hitch(this, "onDragStart"); + this.editorDomNode.ondragend = dojo.hitch(this, "onDragEnd"); + + //NOTES: + // FF _ Able to detect the drag-over object (the editor.domNode) + // Not able to detect an item's ondrag() event + // Don't know why - I actually got it working when there was an error + // Something to do with different documents or windows I'm sure + // + //console.log("connectDraggable", tbl); + /*tbl.ondragstart=dojo.hitch(this, "onDragStart"); + + tbl.addEventListener("dragstart", dojo.hitch(this, "onDragStart"), false); + tbl.addEventListener("drag", dojo.hitch(this, "onDragStart2"), false); + tbl.addEventListener("dragend", dojo.hitch(this, "onDragStart3"), false); + + dojo.withGlobal(this.editor.window, "selectElement",dijit._editor.selection, [tbl]); + + tbl.ondragstart = function(){ + //console.log("ondragstart"); + }; + tbl.ondrag = function(){ + alert("drag") + //console.log("ondrag"); + */ + }, + onDragStart: function(){ + var e = window.event; + if(!e.srcElement.id){ + e.srcElement.id = "tbl_"+(new Date().getTime()); + } + //console.log("onDragStart", e.srcElement.id); + }, + onDragEnd: function(){ + // summary: + // Detects that an object has been dragged into place + // Currently, this code is only used for when a table is dragged + // and clears the "align" attribute, so that the table will look + // to be more in the place that the user expected. + // TODO: This code can be used for other things, most + // notably UNDO, which currently is not quite usable. + // This code could also find itself in the Editor code when it is + // complete. + + //console.log("onDragEnd"); + var e = window.event; + var node = e.srcElement; + var id = node.id; + var win = this.editor.window; + //console.log("NODE:", node.tagName, node.id, dojo.attr(node, "align")); + + // clearing a table's align attr + // TODO: when ondrag becomes more robust, this code block + // should move to its own method + if(node.tagName.toLowerCase()=="table"){ + setTimeout(function(){ + var node = dojo.withGlobal(win, "byId", dojo, [id]); + dojo.removeAttr(node, "align"); + //console.log("set", node.tagName, dojo.attr(node, "align")) + }, 100); + } + }, + checkAvailable: function(){ + // summary: + // For table plugs + // Checking if a table or part of a table has focus so that + // Plugs can change their status + // + if(this.availableCurrentlySet){ + // availableCurrentlySet is set for a short amount of time, so that all + // plugins get the same return without doing the method over + //console.log("availableCurrentlySet:", this.availableCurrentlySet, "currentlyAvailable:", this.currentlyAvailable) + return this.currentlyAvailable; + } + //console.log("G - checkAvailable..."); + + if(!this.editor) { + //console.log("editor not ready") + return false; + } + if(this.alwaysAvailable) { + //console.log(" return always available") + return true; + } + + // Only return available if the editor is focused. + this.currentlyAvailable = this.editor.focused ? this.editor.hasAncestorElement("table") : false; + + if(this.currentlyAvailable){ + this.connectTableKeys(); + }else{ + this.disconnectTableKeys(); + } + + this._tempAvailability(500); + + dojo.publish(this.editor.id + "_tablePlugins", [ this.currentlyAvailable ]); + return this.currentlyAvailable; + }, + + _prepareTable: function(tbl){ + // For IE's sake, we are adding IDs to the TDs if none is there + // We go ahead and use it for other code for convenience + // + var tds = this.editor.query("td", tbl); + console.log("prep:", tds, tbl); + if(!tds[0].id){ + tds.forEach(function(td, i){ + if(!td.id){ + td.id = "tdid"+i+this.getTimeStamp(); + } + }, this); + } + return tds; + }, + + getTimeStamp: function(){ + return new Date().getTime(); // Fixed the bug that this method always returns the same timestamp +// return Math.floor(new Date().getTime() * 0.00000001); + }, + + _tempStoreTableData: function(type){ + // caching or clearing table data, depending on the arg + // + if(type===true){ + //store indefinitely + }else if(type===false){ + // clear object + this.tableData = null; + }else if(type===undefined){ + console.warn("_tempStoreTableData must be passed an argument"); + }else{ + // type is a number/ms + setTimeout(dojo.hitch(this, function(){ + this.tableData = null; + }), type); + } + }, + + _tempAvailability: function(type){ + // caching or clearing availability, depending on the arg + if(type===true){ + //store indefinitely + this.availableCurrentlySet = true; + }else if(type===false){ + // clear object + this.availableCurrentlySet = false; + }else if(type===undefined){ + console.warn("_tempAvailability must be passed an argument"); + }else{ + // type is a number/ms + this.availableCurrentlySet = true; + setTimeout(dojo.hitch(this, function(){ + this.availableCurrentlySet = false; + }), type); + } + + }, + + connectTableKeys: function(){ + // summary: + // When a table is in focus, start detecting keys + // Mainly checking for the TAB key so user can tab + // through a table (blocking the browser's desire to + // tab away from teh editor completely) + if(this.tablesConnected){ return; } + this.tablesConnected = true; + var node = (this.editor.iframe) ? this.editor.document : this.editor.editNode; + this.cnKeyDn = dojo.connect(node, "onkeydown", this, "onKeyDown"); + this.cnKeyUp = dojo.connect(node, "onkeyup", this, "onKeyUp"); + this._myListeners.push(dojo.connect(node, "onkeypress", this, "onKeyUp")); + }, + + disconnectTableKeys: function(){ + //console.log("disconnect") + dojo.disconnect(this.cnKeyDn); + dojo.disconnect(this.cnKeyUp); + this.tablesConnected = false; + }, + + onKeyDown: function(evt){ + var key = evt.keyCode; + //console.log(" -> DOWN:", key); + if(key == 16){ this.shiftKeyDown = true;} + if(key == 9) { + var o = this.getTableInfo(); + //console.log("TAB ", o.tdIndex, o); + // modifying the o.tdIndex in the tableData directly, because we may save it + // FIXME: tabTo is a global + o.tdIndex = (this.shiftKeyDown) ? o.tdIndex-1 : tabTo = o.tdIndex+1; + if(o.tdIndex>=0 && o.tdIndex<o.tds.length){ + + this.editor.selectElement(o.tds[o.tdIndex]); + + // we know we are still within a table, so block the need + // to run the method + this.currentlyAvailable = true; + this._tempAvailability(true); + // + this._tempStoreTableData(true); + this.stopEvent = true; + }else{ + //tabbed out of table + this.stopEvent = false; + this.onDisplayChanged(); + } + if(this.stopEvent) { + dojo.stopEvent(evt); + } + } + }, + + onKeyUp: function(evt){ + var key = evt.keyCode; + //console.log(" -> UP:", key) + if(key == 16){ this.shiftKeyDown = false;} + if(key == 37 || key == 38 || key == 39 || key == 40 ){ + // user can arrow or tab out of table - need to recheck + this.onDisplayChanged(); + } + if(key == 9 && this.stopEvent){ dojo.stopEvent(evt);} + }, + + onDisplayChanged: function(){ + //console.log("onDisplayChanged") + this.currentlyAvailable = false; + this._tempStoreTableData(false); + this._tempAvailability(false); + this.checkAvailable(); + }, + + uninitialize: function(editor){ + // summary: + // Function to handle cleaning up of connects + // and such. It only finally destroys everything once + // all 'references' to it have gone. As in all plugins + // that called init on it destroyed their refs in their + // cleanup calls. + // editor: + // The editor to detach from. + if(this.editor == editor){ + this.refCount--; + if(!this.refCount && this.initialized){ + if(this.tablesConnected){ + this.disconnectTableKeys(); + } + this.initialized = false; + dojo.forEach(this._myListeners, function(l){ + dojo.disconnect(l); + }); + delete this._myListeners; + delete this.editor._tablePluginHandler; + delete this.editor; + } + this.inherited(arguments); + } + } +}); + +dojo.declare("dojox.editor.plugins.TablePlugins", + dijit._editor._Plugin, + { + //summary: + // A collection of Plugins for inserting and modifying tables in the Editor + // See end of this document for all avaiable plugs + // and dojox/editorPlugins/tests/editorTablePlugs.html for an example + // + // NOT IMPLEMENTED: Not handling cell merge, span or split + // + + iconClassPrefix: "editorIcon", + useDefaultCommand: false, + buttonClass: dijit.form.Button, + commandName:"", + label:"", + alwaysAvailable:false, + undoEnabled:true, + + onDisplayChanged: function(withinTable){ + // subscribed to from the global object's publish method + // + //console.log("onDisplayChanged", this.commandName); + if(!this.alwaysAvailable){ + this.available = withinTable; + this.button.set('disabled', !this.available); + } + }, + + setEditor: function(editor){ + this.editor = editor; + this.editor.customUndo = true; + this.inherited(arguments); + this._availableTopic = dojo.subscribe(this.editor.id + "_tablePlugins", this, "onDisplayChanged"); + this.onEditorLoaded(); + }, + onEditorLoaded: function(){ + if(!this.editor._tablePluginHandler){ + // Create it and init it off the editor. This + // will create the _tablePluginHandler reference on + // the dijit.Editor instance. This avoids a global. + var tablePluginHandler = new dojox.editor.plugins._TableHandler(); + tablePluginHandler.initialize(this.editor); + }else{ + this.editor._tablePluginHandler.initialize(this.editor); + } + }, + + selectTable: function(){ + // selects table that is in focus + var o = this.getTableInfo(); + if(o && o.tbl){ + dojo.withGlobal(this.editor.window, "selectElement",dijit._editor.selection, [o.tbl]); + } + }, + + _initButton: function(){ + this.command = this.commandName; + + this.label = this.editor.commands[this.command] = this._makeTitle(this.command); + this.inherited(arguments); + delete this.command; + + this.connect(this.button, "onClick", "modTable"); + + this.onDisplayChanged(false); + }, + + modTable: function(cmd, args){ + // summary: + // Where each plugin performs its action + // Note: not using execCommand. In spite of their presence in the + // Editor as query-able plugins, I was not able to find any evidence + // that they are supported (especially in NOT IE). If they are + // supported in other browsers, it may help with the undo problem. + // + this.begEdit(); + var o = this.getTableInfo(); + var sw = (dojo.isString(cmd))?cmd : this.commandName; + var r, c, i; + var adjustColWidth = false; + //console.log("modTable:", sw) + + if(dojo.isIE){ + // IE can lose selections on focus changes, so focus back + // in order to restore it. + this.editor.focus(); + } + switch(sw){ + case "insertTableRowBefore": + r = o.tbl.insertRow(o.trIndex); + for(i=0;i<o.cols;i++){ + c = r.insertCell(-1); + c.innerHTML = " "; + } + break; + case "insertTableRowAfter": + r = o.tbl.insertRow(o.trIndex+1); + for(i=0;i<o.cols;i++){ + c = r.insertCell(-1); + c.innerHTML = " "; + } + break; + case "insertTableColumnBefore": + o.trs.forEach(function(r){ + c = r.insertCell(o.colIndex); + c.innerHTML = " "; + }); + adjustColWidth = true; + break; + case "insertTableColumnAfter": + o.trs.forEach(function(r){ + c = r.insertCell(o.colIndex+1); + c.innerHTML = " "; + }); + adjustColWidth = true; + break; + case "deleteTableRow": + o.tbl.deleteRow(o.trIndex); + console.log("TableInfo:", this.getTableInfo()); + break; + case "deleteTableColumn": + o.trs.forEach(function(tr){ + tr.deleteCell(o.colIndex); + }); + adjustColWidth = true; + break; + + case "modifyTable": + break; + case "insertTable": + break; + + } + if(adjustColWidth){ + this.makeColumnsEven(); + } + this.endEdit(); + }, + + begEdit: function(){ + if(this.editor._tablePluginHandler.undoEnabled){ + //console.log("UNDO:", this.editor.customUndo); + if(this.editor.customUndo){ + this.editor.beginEditing(); + }else{ + this.valBeforeUndo = this.editor.getValue(); + //console.log("VAL:", this.valBeforeUndo); + + } + } + }, + endEdit: function(){ + if(this.editor._tablePluginHandler.undoEnabled){ + if(this.editor.customUndo){ + this.editor.endEditing(); + }else{ + // This code ALMOST works for undo - + // It seems to only work for one step + // back in history however + var afterUndo = this.editor.getValue(); + //this.editor.execCommand("inserthtml", "<p>mike</p>"); + this.editor.setValue(this.valBeforeUndo); + this.editor.replaceValue(afterUndo); + } + + this.editor.onDisplayChanged(); + } + }, + + makeColumnsEven: function(){ + //summary: + // After changing column amount, change widths to + // keep columns even + // + // the timeout helps prevent an occasional snafu + setTimeout(dojo.hitch(this, function(){ + var o = this.getTableInfo(true); + var w = Math.floor(100/o.cols); + o.tds.forEach(function(d){ + dojo.attr(d, "width", w+"%"); + }); + }), 10); + }, + + getTableInfo: function(forceNewData){ + // summary: + // Gets the table in focus + // Collects info on the table - see return params + // + return this.editor._tablePluginHandler.getTableInfo(forceNewData); + }, + _makeTitle: function(str){ + // Parses the commandName into a Title + // based on camelCase + var ns = []; + dojo.forEach(str, function(c, i){ + if(c.charCodeAt(0)<91 && i>0 && ns[i-1].charCodeAt(0)!=32){ + ns.push(" "); + } + if(i===0){ c = c.toUpperCase();} + ns.push(c); + }); + return ns.join(""); + }, + + + + getSelectedCells: function(){ + // summary: + // Gets the selected cells from the passed table + // Returns: array of TDs or empty array + var cells = []; + var tbl = this.getTableInfo().tbl; + this.editor._tablePluginHandler._prepareTable(tbl); + var e = this.editor; + + // Lets do this the way IE originally was (Looking up ids). Walking the selection + // is inconsistent in the browsers (and painful), so going by ids is simpler. + var text = dojo.withGlobal(e.window, "getSelectedHtml",dijit._editor.selection, [null]); + var str = text.match(/id="*\w*"*/g); + dojo.forEach(str, function(a){ + var id = a.substring(3, a.length); + if(id.charAt(0) == "\"" && id.charAt(id.length - 1) == "\""){ + id = id.substring(1, id.length - 1); + } + var node = e.byId(id); + if(node && node.tagName.toLowerCase() == "td"){ + cells.push(node); + } + }, this); + + if(!cells.length){ + //May just be in a cell (cursor point, or selection in a cell), so look upwards. + //for a cell container. + var sel = dijit.range.getSelection(e.window); + if(sel.rangeCount){ + var r = sel.getRangeAt(0); + var node = r.startContainer; + while(node && node != e.editNode && node != e.document){ + if(node.nodeType === 1){ + var tg = node.tagName ? node.tagName.toLowerCase() : ""; + if(tg === "td"){ + return [node]; + } + } + node = node.parentNode; + } + } + } + return cells; + }, + + updateState: function(){ + // summary: + // Over-ride for button state control for disabled to work. + if(this.button){ + if((this.available || this.alwaysAvailable) && !this.get("disabled")){ + this.button.set("disabled",false); + }else{ + this.button.set("disabled",true); + } + } + }, + + destroy: function(){ + // summary: + // Over-ridden destroy to do some cleanup. + this.inherited(arguments); + dojo.unsubscribe(this._availableTopic); + + // Disconnect the editor from the handler + // to clean up refs. Moved to using a per-editor + // 'handler' to avoid collisions on the old global. + this.editor._tablePluginHandler.uninitialize(this.editor); + } + + } +); + +dojo.declare("dojox.editor.plugins.TableContextMenu", + dojox.editor.plugins.TablePlugins, + { + constructor: function(){ + // summary: + // Initialize certain plugins + // + this.connect(this, "setEditor", function(editor){ + editor.onLoadDeferred.addCallback(dojo.hitch(this, function() { + this._createContextMenu(); + })); + this.button.domNode.style.display = "none"; + }); + }, + + destroy: function(){ + // summary: + // Over-ride to do menu cleanup. + if(this.menu){ + this.menu.destroyRecursive(); + delete this.menu; + } + this.inherited(arguments); + }, + + + _initButton: function(){ + this.inherited(arguments); + if(this.commandName=="tableContextMenu"){ this.button.domNode.display = "none";} + }, + + _createContextMenu: function(){ + // summary + // Building context menu for right-click shortcuts within a table + // + + var pMenu = new dijit.Menu({targetNodeIds:[this.editor.iframe]}); + var messages = dojo.i18n.getLocalization("dojox.editor.plugins", "TableDialog", this.lang); + pMenu.addChild(new dijit.MenuItem({label: messages.selectTableLabel, onClick: dojo.hitch(this, "selectTable")})); + pMenu.addChild(new dijit.MenuSeparator()); + + pMenu.addChild(new dijit.MenuItem({label: messages.insertTableRowBeforeLabel, onClick: dojo.hitch(this, "modTable", "insertTableRowBefore" )})); + pMenu.addChild(new dijit.MenuItem({label: messages.insertTableRowAfterLabel, onClick: dojo.hitch(this, "modTable", "insertTableRowAfter" )})); + pMenu.addChild(new dijit.MenuItem({label: messages.insertTableColumnBeforeLabel, onClick: dojo.hitch(this, "modTable", "insertTableColumnBefore" )})); + pMenu.addChild(new dijit.MenuItem({label: messages.insertTableColumnAfterLabel, onClick: dojo.hitch(this, "modTable", "insertTableColumnAfter" )})); + pMenu.addChild(new dijit.MenuSeparator()); + pMenu.addChild(new dijit.MenuItem({label: messages.deleteTableRowLabel, onClick: dojo.hitch(this, "modTable", "deleteTableRow" )})); + pMenu.addChild(new dijit.MenuItem({label: messages.deleteTableColumnLabel, onClick: dojo.hitch(this, "modTable", "deleteTableColumn" )})); + + this.menu = pMenu; + } +}); + +dojo.declare("dojox.editor.plugins.InsertTable", + dojox.editor.plugins.TablePlugins, + { + alwaysAvailable: true, + + modTable: function(){ + var w = new dojox.editor.plugins.EditorTableDialog({}); + w.show(); + var c = dojo.connect(w, "onBuildTable", this, function(obj){ + dojo.disconnect(c); + + var res = this.editor.execCommand('inserthtml', obj.htmlText); + + // commenting this line, due to msg below + //var td = this.editor.query("td", this.editor.byId(obj.id)); + + //HMMMM.... This throws a security error now. didn't used to. + //this.editor.selectElement(td); + }); + } +}); + +dojo.declare("dojox.editor.plugins.ModifyTable", + dojox.editor.plugins.TablePlugins, + { + modTable: function(){ + if (!this.editor._tablePluginHandler.checkAvailable()) {return;} + var o = this.getTableInfo(); + //console.log("LAUNCH DIALOG"); + var w = new dojox.editor.plugins.EditorModifyTableDialog({table:o.tbl}); + w.show(); + this.connect(w, "onSetTable", function(color){ + // uhm... not sure whats going on here... + var o = this.getTableInfo(); + //console.log("set color:", color); + dojo.attr(o.td, "bgcolor", color); + }); + } +}); + +dojo.declare("dojox.editor.plugins._CellColorDropDown", [dijit._Widget, dijit._TemplatedMixin, dijit._WidgetsInTemplateMixin], { + // summary: + // A smple widget that uses/creates a dropdown with a dojox.widget.ColorPicker. Also provides + // passthroughs to the value of the color picker and convenient hook points. + // tags: + // private + + // templateString: String + // The template used to create the ColorPicker. + templateString: + "<div style='display: none; position: absolute; top: -10000; z-index: -10000'>" + + "<div dojoType='dijit.TooltipDialog' dojoAttachPoint='dialog' class='dojoxEditorColorPicker'>" + + "<div dojoType='dojox.widget.ColorPicker' dojoAttachPoint='_colorPicker'></div>" + + "<div style='margin: 0.5em 0em 0em 0em'>" + + "<button dojoType='dijit.form.Button' type='button' dojoAttachPoint='_setButton'>${buttonSet}</button>" + + " " + + "<button dojoType='dijit.form.Button' type='button' dojoAttachPoint='_cancelButton'>${buttonCancel}</button>" + + "</div>" + + "</div>" + + "</div>", + + // widgetsInTemplate: Boolean + // Flag denoting widgets are contained in the template. + widgetsInTemplate: true, + + constructor: function(){ + // summary: + // Constructor over-ride so that the translated strings are mixsed in so + // the template fills out. + var strings = dojo.i18n.getLocalization("dojox.editor.plugins", "TableDialog"); + dojo.mixin(this, strings); + }, + + startup: function(){ + // summary: + // Over-ride of startup to do the basic connect setups and such. + if(!this._started){ + this.inherited(arguments); + this.connect(this._setButton, "onClick", function(){ + this.onChange(this.get("value")); + }); + this.connect(this._cancelButton, "onClick", function(){ + dijit.popup.close(this.dialog); + this.onCancel(); + }); + // Fully statred, so go ahead and remove the hide. + dojo.style(this.domNode, "display", "block"); + } + }, + + _setValueAttr: function(value, priorityChange){ + // summary: + // Passthrough function for the color picker value. + // value: String + // The value to set in the color picker + // priorityChange: + // Value to indicate whether or not to trigger an onChange event. + this._colorPicker.set("value", value, priorityChange); + }, + + _getValueAttr: function(){ + // summary: + // Passthrough function for the color picker value. + return this._colorPicker.get("value"); + }, + + setColor: function(/*String*/ color){ + this._colorPicker.setColor(color, false); + }, + + onChange: function(value){ + // summary: + // Hook point to get the value when the color picker value is selected. + // value: String + // The value from the color picker. + }, + + onCancel: function(){ + // summary: + // Hook point to get when the dialog is canceled. + } +}); + +dojo.declare("dojox.editor.plugins.ColorTableCell", dojox.editor.plugins.TablePlugins, { + constructor: function(){ + // summary: + // Initialize ColorTableCell plugin + this.closable = true; + this.buttonClass = dijit.form.DropDownButton; + var picker = new dojox.editor.plugins._CellColorDropDown(); + dojo.body().appendChild(picker.domNode); + picker.startup(); + this.dropDown = picker.dialog; + this.connect(picker, "onChange", function(color){ + this.modTable(null, color); + this.editor.focus(); + }); + this.connect(picker, "onCancel", function(color){ + this.editor.focus(); + }); + this.connect(picker.dialog, "onOpen", function(){ + var o = this.getTableInfo(), + tds = this.getSelectedCells(o.tbl); + if(tds && tds.length > 0){ + var t = tds[0] == this.lastObject ? tds[0] : tds[tds.length - 1], + color; + while(t && ((color = dojo.style(t, "backgroundColor")) == "transparent" || color.indexOf("rgba") == 0)){ + t = t.parentNode; + } + color = dojo.style(t, "backgroundColor"); + if(color != "transparent" && color.indexOf("rgba") != 0){ + picker.setColor(color); + } + } + }); + this.connect(this, "setEditor", function(editor){ + editor.onLoadDeferred.addCallback(dojo.hitch(this, function(){ + this.connect(this.editor.editNode, "onmouseup", function(evt){ + this.lastObject = evt.target; + }); + })); + }); + }, + + _initButton: function(){ + this.command = this.commandName; + + this.label = this.editor.commands[this.command] = this._makeTitle(this.command); + this.inherited(arguments); + delete this.command; + + this.onDisplayChanged(false); + }, + + modTable: function(cmd, args){ + // summary + // Where each plugin performs its action + // Note: not using execCommand. In spite of their presence in the + // Editor as query-able plugins, I was not able to find any evidence + // that they are supported (especially in NOT IE). If they are + // supported in other browsers, it may help with the undo problem. + // + this.begEdit(); + var o = this.getTableInfo(); + // The one plugin that really needs use of the very verbose + // getSelectedCells() + var tds = this.getSelectedCells(o.tbl); + //console.debug("SELECTED CELLS ", tds , " FOR ", o); + dojo.forEach(tds, function(td){ + dojo.style(td, "backgroundColor", args); + }); + this.endEdit(); + } +}); + +dojo.declare("dojox.editor.plugins.EditorTableDialog", [dijit.Dialog, dijit._TemplatedMixin, dijit._WidgetsInTemplateMixin], { + // summary: + // Dialog box with options for table creation + + baseClass:"EditorTableDialog", + + templateString: dojo.cache("dojox.editor.plugins", "resources/insertTable.html"), + + postMixInProperties: function(){ + var messages = dojo.i18n.getLocalization("dojox.editor.plugins", "TableDialog", this.lang); + dojo.mixin(this, messages); + this.inherited(arguments); + }, + + postCreate: function(){ + dojo.addClass(this.domNode, this.baseClass); //FIXME - why isn't Dialog accepting the baseClass? + this.inherited(arguments); + }, + + onInsert: function(){ + console.log("insert"); + + var rows = this.selectRow.get("value") || 1, + cols = this.selectCol.get("value") || 1, + width = this.selectWidth.get("value"), + widthType = this.selectWidthType.get("value"), + border = this.selectBorder.get("value"), + pad = this.selectPad.get("value"), + space = this.selectSpace.get("value"), + _id = "tbl_"+(new Date().getTime()), + t = '<table id="'+_id+'"width="'+width+((widthType=="percent")?'%':'')+'" border="'+border+'" cellspacing="'+space+'" cellpadding="'+pad+'">\n'; + + for(var r=0;r<rows;r++){ + t += '\t<tr>\n'; + for(var c=0;c<cols;c++){ + t += '\t\t<td width="'+(Math.floor(100/cols))+'%"> </td>\n'; + } + t += '\t</tr>\n'; + } + t += '</table><br />'; + + //console.log(t); + this.onBuildTable({htmlText:t, id:_id}); + var cl = dojo.connect(this, "onHide", function(){ + dojo.disconnect(cl); + var self = this; + setTimeout(function(){ + self.destroyRecursive(); + }, 10); + }); + this.hide(); + }, + + onCancel: function(){ + // summary: + // Function to clean up memory so that the dialog is destroyed + // when closed. + var c = dojo.connect(this, "onHide", function(){ + dojo.disconnect(c); + var self = this; + setTimeout(function(){ + self.destroyRecursive(); + }, 10); + }); + }, + + onBuildTable: function(tableText){ + //stub + } +}); + +dojo.declare("dojox.editor.plugins.EditorModifyTableDialog", [dijit.Dialog, dijit._TemplatedMixin, dijit._WidgetsInTemplateMixin], { + + // summary: + // Dialog box with options for editing a table + // + + baseClass:"EditorTableDialog", + + table:null, //html table to be modified + tableAtts:{}, + templateString: dojo.cache("dojox.editor.plugins", "resources/modifyTable.html"), + + postMixInProperties: function(){ + var messages = dojo.i18n.getLocalization("dojox.editor.plugins", "TableDialog", this.lang); + dojo.mixin(this, messages); + this.inherited(arguments); + }, + + postCreate: function(){ + dojo.addClass(this.domNode, this.baseClass); //FIXME - why isn't Dialog accepting the baseClass? + this.inherited(arguments); + this._cleanupWidgets = []; + var w1 = new dijit.ColorPalette({}); + this.connect(w1, "onChange", function(color){ + dijit.popup.close(w1); + this.setBrdColor(color); + }); + this.connect(w1, "onBlur", function(){ + dijit.popup.close(w1); + }); + this.connect(this.borderCol, "click", function(){ + dijit.popup.open({popup:w1, around:this.borderCol}); + w1.focus(); + }); + var w2 = new dijit.ColorPalette({}); + this.connect(w2, "onChange", function(color){ + dijit.popup.close(w2); + this.setBkColor(color); + }); + this.connect(w2, "onBlur", function(){ + dijit.popup.close(w2); + }); + this.connect(this.backgroundCol, "click", function(){ + dijit.popup.open({popup:w2, around:this.backgroundCol}); + w2.focus(); + }); + this._cleanupWidgets.push(w1); + this._cleanupWidgets.push(w2); + + this.setBrdColor(dojo.attr(this.table, "bordercolor")); + this.setBkColor(dojo.attr(this.table, "bgcolor")); + var w = dojo.attr(this.table, "width"); + if(!w){ + w = this.table.style.width; + } + var p = "pixels"; + if(dojo.isString(w) && w.indexOf("%")>-1){ + p = "percent"; + w = w.replace(/%/, ""); + } + + if(w){ + this.selectWidth.set("value", w); + this.selectWidthType.set("value", p); + }else{ + this.selectWidth.set("value", ""); + this.selectWidthType.set("value", "percent"); + } + + this.selectBorder.set("value", dojo.attr(this.table, "border")); + this.selectPad.set("value", dojo.attr(this.table, "cellPadding")); + this.selectSpace.set("value", dojo.attr(this.table, "cellSpacing")); + this.selectAlign.set("value", dojo.attr(this.table, "align")); + }, + + setBrdColor: function(color){ + this.brdColor = color; + dojo.style(this.borderCol, "backgroundColor", color); + }, + + setBkColor: function(color){ + this.bkColor = color; + dojo.style(this.backgroundCol, "backgroundColor", color); + }, + onSet: function(){ + dojo.attr(this.table, "borderColor", this.brdColor); + dojo.attr(this.table, "bgColor", this.bkColor); + if(this.selectWidth.get("value")){ + // Just in case, remove it from style since we're setting it as a table attribute. + dojo.style(this.table, "width", ""); + dojo.attr(this.table, "width", (this.selectWidth.get("value") + ((this.selectWidthType.get("value")=="pixels")?"":"%") )); + } + dojo.attr(this.table, "border", this.selectBorder.get("value")); + dojo.attr(this.table, "cellPadding", this.selectPad.get("value")); + dojo.attr(this.table, "cellSpacing", this.selectSpace.get("value")); + dojo.attr(this.table, "align", this.selectAlign.get("value")); + var c = dojo.connect(this, "onHide", function(){ + dojo.disconnect(c); + var self = this; + setTimeout(function(){ + self.destroyRecursive(); + }, 10); + }); + this.hide(); + }, + + onCancel: function(){ + // summary: + // Function to clean up memory so that the dialog is destroyed + // when closed. + var c = dojo.connect(this, "onHide", function(){ + dojo.disconnect(c); + var self = this; + setTimeout(function(){ + self.destroyRecursive(); + }, 10); + }); + }, + + onSetTable: function(tableText){ + //stub + }, + + destroy: function(){ + // summary: + // Cleanup function. + this.inherited(arguments); + dojo.forEach(this._cleanupWidgets, function(w){ + if(w && w.destroy){ + w.destroy(); + } + }); + delete this._cleanupWidgets; + } +}); + +dojo.subscribe(dijit._scopeName + ".Editor.getPlugin",null,function(o){ + if(o.plugin){ return; } + // make first character lower case + if(o.args && o.args.command){ + var cmd = o.args.command.charAt(0).toLowerCase()+o.args.command.substring(1,o.args.command.length); + + switch(cmd){ + case "insertTableRowBefore": + case "insertTableRowAfter": + case "insertTableColumnBefore": + case "insertTableColumnAfter": + case "deleteTableRow": + case "deleteTableColumn": + o.plugin = new dojox.editor.plugins.TablePlugins({commandName: cmd}); + break; + + case "colorTableCell": + o.plugin = new dojox.editor.plugins.ColorTableCell({commandName: cmd}); + break; + + case "modifyTable": + o.plugin = new dojox.editor.plugins.ModifyTable({commandName: cmd}); + break; + + case "insertTable": + o.plugin = new dojox.editor.plugins.InsertTable({commandName: cmd}); + break; + + case "tableContextMenu": + o.plugin = new dojox.editor.plugins.TableContextMenu({commandName: cmd}); + break; + } + } +}); + +return dojox.editor.plugins.TablePlugins; + +}); |
