12345678910111213141516171819202122232425262728293031323334353637383940414243444546474849505152535455565758596061626364656667686970717273747576777879808182838485868788899091929394959697989910010110210310410510610710810911011111211311411511611711811912012112212312412512612712812913013113213313413513613713813914014114214314414514614714814915015115215315415515615715815916016116216316416516616716816917017117217317417517617717817918018118218318418518618718818919019119219319419519619719819920020120220320420520620720820921021121221321421521621721821922022122222322422522622722822923023123223323423523623723823924024124224324424524624724824925025125225325425525625725825926026126226326426526626726826927027127227327427527627727827928028128228328428528628728828929029129229329429529629729829930030130230330430530630730830931031131231331431531631731831932032132232332432532632732832933033133233333433533633733833934034134234334434534634734834935035135235335435535635735835936036136236336436536636736836937037137237337437537637737837938038138238338438538638738838939039139239339439539639739839940040140240340440540640740840941041141241341441541641741841942042142242342442542642742842943043143243343443543643743843944044144244344444544644744844945045145245345445545645745845946046146246346446546646746846947047147247347447547647747847948048148248348448548648748848949049149249349449549649749849950050150250350450550650750850951051151251351451551651751851952052152252352452552652752852953053153253353453553653753853954054154254354454554654754854955055155255355455555655755855956056156256356456556656756856957057157257357457557657757857958058158258358458558658758858959059159259359459559659759859960060160260360460560660760860961061161261361461561661761861962062162262362462562662762862963063163263363463563663763863964064164264364464564664764864965065165265365465565665765865966066166266366466566666766866967067167267367467567667767867968068168268368468568668768868969069169269369469569669769869970070170270370470570670770870971071171271371471571671771871972072172272372472572672772872973073173273373473573673773873974074174274374474574674774874975075175275375475575675775875976076176276376476576676776876977077177277377477577677777877978078178278378478578678778878979079179279379479579679779879980080180280380480580680780880981081181281381481581681781881982082182282382482582682782882983083183283383483583683783883984084184284384484584684784884985085185285385485585685785885986086186286386486586686786886987087187287387487587687787887988088188288388488588688788888989089189289389489589689789889990090190290390490590690790890991091191291391491591691791891992092192292392492592692792892993093193293393493593693793893994094194294394494594694794894995095195295395495595695795895996096196296396496596696796896997097197297397497597697797897998098198298398498598698798898999099199299399499599699799899910001001100210031004100510061007100810091010101110121013101410151016101710181019102010211022102310241025102610271028102910301031103210331034103510361037103810391040104110421043104410451046104710481049105010511052105310541055105610571058105910601061106210631064106510661067106810691070107110721073107410751076107710781079108010811082108310841085108610871088108910901091109210931094109510961097109810991100110111021103110411051106110711081109111011111112111311141115111611171118111911201121112211231124112511261127112811291130113111321133113411351136113711381139114011411142114311441145114611471148114911501151115211531154115511561157115811591160116111621163116411651166116711681169117011711172117311741175117611771178117911801181118211831184118511861187118811891190119111921193119411951196119711981199120012011202120312041205120612071208120912101211121212131214121512161217 |
- /*
- Copyright (c) 2004-2012, The Dojo Foundation All Rights Reserved.
- Available via Academic Free License >= 2.1 OR the modified BSD license.
- see: http://dojotoolkit.org/license for details
- */
- if(!dojo._hasResource["dojox.editor.plugins.TablePlugins"]){ //_hasResource checks added by build. Do not use _hasResource directly in your code.
- dojo._hasResource["dojox.editor.plugins.TablePlugins"] = true;
- dojo.provide("dojox.editor.plugins.TablePlugins");
- dojo.require("dijit.form.Button");
- dojo.require("dijit.Dialog");
- dojo.require("dijit.form.TextBox");
- dojo.require("dijit.form.FilteringSelect");
- dojo.require("dijit._editor._Plugin");
- dojo.require("dijit._editor.selection");
- dojo.require("dijit.Menu");
- dojo.require("dijit.ColorPalette");
- dojo.require("dojox.widget.ColorPicker");
- dojo.require("dojo.i18n");
- dojo.requireLocalization("dojox.editor.plugins", "TableDialog", null, "ROOT,ar,az,bg,ca,cs,da,de,el,es,fi,fr,he,hr,hu,it,ja,kk,ko,nb,nl,pl,pt,pt-pt,ro,ru,sk,sl,sv,th,tr,zh,zh-tw");
- 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 avalable 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._Templated], {
- // 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], {
- // summary:
- // Dialog box with options for table creation
- //
- baseClass:"EditorTableDialog",
-
- widgetsInTemplate:true,
- templateString: dojo.cache("dojox.editor.plugins", "resources/insertTable.html", "<div class=\"dijitDialog\" tabindex=\"-1\" role=\"dialog\" aria-labelledby=\"${id}_title\">\n\t<div dojoAttachPoint=\"titleBar\" class=\"dijitDialogTitleBar\">\n\t<span dojoAttachPoint=\"titleNode\" class=\"dijitDialogTitle\" id=\"${id}_title\">${insertTableTitle}</span>\n\t<span dojoAttachPoint=\"closeButtonNode\" class=\"dijitDialogCloseIcon\" dojoAttachEvent=\"onclick: onCancel\" title=\"${buttonCancel}\">\n\t\t<span dojoAttachPoint=\"closeText\" class=\"closeText\" title=\"${buttonCancel}\">x</span>\n\t</span>\n\t</div>\n <div dojoAttachPoint=\"containerNode\" class=\"dijitDialogPaneContent\">\n <table class=\"etdTable\"><tr>\n <td>\n <label>${rows}</label>\n\t\t\t</td><td>\n <span dojoAttachPoint=\"selectRow\" dojoType=\"dijit.form.TextBox\" value=\"2\"></span>\n </td><td><table><tr><td class=\"inner\">\n <label>${columns}</label>\n\t\t\t</td><td class=\"inner\">\n <span dojoAttachPoint=\"selectCol\" dojoType=\"dijit.form.TextBox\" value=\"2\"></span>\n </td></tr></table></td></tr>\t\t\n\t\t\t<tr><td>\n <label>${tableWidth}</label>\n </td><td>\n <span dojoAttachPoint=\"selectWidth\" dojoType=\"dijit.form.TextBox\" value=\"100\"></span>\n\t\t\t</td><td>\n <select dojoAttachPoint=\"selectWidthType\" hasDownArrow=\"true\" dojoType=\"dijit.form.FilteringSelect\">\n <option value=\"percent\">${percent}</option>\n <option value=\"pixels\">${pixels}</option>\n </select></td></tr>\t\n <tr><td>\n <label>${borderThickness}</label></td>\n </td><td>\n <span dojoAttachPoint=\"selectBorder\" dojoType=\"dijit.form.TextBox\" value=\"1\"></span>\n </td><td>\n ${pixels}\n </td></tr><tr><td>\n <label>${cellPadding}</label></td>\n </td><td>\n <span dojoAttachPoint=\"selectPad\" dojoType=\"dijit.form.TextBox\" value=\"0\"></span>\n </td><td class=\"cellpad\"></td></tr><tr><td>\n <label>${cellSpacing}</label>\n </td><td>\n <span dojoAttachPoint=\"selectSpace\" dojoType=\"dijit.form.TextBox\" value=\"0\"></span>\n </td><td class=\"cellspace\"></td></tr></table>\n <div class=\"dialogButtonContainer\">\n <div dojoType=\"dijit.form.Button\" dojoAttachEvent=\"onClick: onInsert\">${buttonInsert}</div>\n <div dojoType=\"dijit.form.Button\" dojoAttachEvent=\"onClick: onCancel\">${buttonCancel}</div>\n </div>\n\t</div>\n</div>\n"),
- 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>';
-
- //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], {
-
- // summary:
- // Dialog box with options for editing a table
- //
-
- baseClass:"EditorTableDialog",
- widgetsInTemplate:true,
- table:null, //html table to be modified
- tableAtts:{},
- templateString: dojo.cache("dojox.editor.plugins", "resources/modifyTable.html", "<div class=\"dijitDialog\" tabindex=\"-1\" role=\"dialog\" aria-labelledby=\"${id}_title\">\n\t<div dojoAttachPoint=\"titleBar\" class=\"dijitDialogTitleBar\">\n\t<span dojoAttachPoint=\"titleNode\" class=\"dijitDialogTitle\" id=\"${id}_title\">${modifyTableTitle}</span>\n\t<span dojoAttachPoint=\"closeButtonNode\" class=\"dijitDialogCloseIcon\" dojoAttachEvent=\"onclick: onCancel\" title=\"${buttonCancel}\">\n\t\t<span dojoAttachPoint=\"closeText\" class=\"closeText\" title=\"${buttonCancel}\">x</span>\n\t</span>\n\t</div>\n <div dojoAttachPoint=\"containerNode\" class=\"dijitDialogPaneContent\">\n <table class=\"etdTable\">\n <tr><td>\n <label>${backgroundColor}</label>\n </td><td colspan=\"2\">\n <span class=\"colorSwatchBtn\" dojoAttachPoint=\"backgroundCol\"></span>\n </td></tr><tr><td>\n <label>${borderColor}</label>\n </td><td colspan=\"2\">\n <span class=\"colorSwatchBtn\" dojoAttachPoint=\"borderCol\"></span>\n </td></tr><tr><td>\n <label>${align}</label>\n </td><td colspan=\"2\">\t\n <select dojoAttachPoint=\"selectAlign\" dojoType=\"dijit.form.FilteringSelect\">\n <option value=\"default\">${default}</option>\n <option value=\"left\">${left}</option>\n <option value=\"center\">${center}</option>\n <option value=\"right\">${right}</option>\n </select>\n </td></tr>\n <tr><td>\n <label>${tableWidth}</label>\n </td><td>\n <span dojoAttachPoint=\"selectWidth\" dojoType=\"dijit.form.TextBox\" value=\"100\"></span>\n </td><td>\n <select dojoAttachPoint=\"selectWidthType\" hasDownArrow=\"true\" dojoType=\"dijit.form.FilteringSelect\">\n <option value=\"percent\">${percent}</option>\n <option value=\"pixels\">${pixels}</option>\n </select></td></tr>\t\n <tr><td>\n <label>${borderThickness}</label></td>\n </td><td>\n <span dojoAttachPoint=\"selectBorder\" dojoType=\"dijit.form.TextBox\" value=\"1\"></span>\n </td><td>\n ${pixels}\n </td></tr><tr><td>\n <label>${cellPadding}</label></td>\n </td><td>\n <span dojoAttachPoint=\"selectPad\" dojoType=\"dijit.form.TextBox\" value=\"0\"></span>\n </td><td class=\"cellpad\"></td></tr><tr><td>\n <label>${cellSpacing}</label>\n </td><td>\n <span dojoAttachPoint=\"selectSpace\" dojoType=\"dijit.form.TextBox\" value=\"0\"></span>\n </td><td class=\"cellspace\"></td></tr>\n </table>\n <div class=\"dialogButtonContainer\">\n <div dojoType=\"dijit.form.Button\" dojoAttachEvent=\"onClick: onSet\">${buttonSet}</div>\n <div dojoType=\"dijit.form.Button\" dojoAttachEvent=\"onClick: onCancel\">${buttonCancel}</div>\n </div>\n\t</div>\n</div>\n"),
- 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;
- }
- }
- });
- }
|