TablePlugins.js 43 KB

12345678910111213141516171819202122232425262728293031323334353637383940414243444546474849505152535455565758596061626364656667686970717273747576777879808182838485868788899091929394959697989910010110210310410510610710810911011111211311411511611711811912012112212312412512612712812913013113213313413513613713813914014114214314414514614714814915015115215315415515615715815916016116216316416516616716816917017117217317417517617717817918018118218318418518618718818919019119219319419519619719819920020120220320420520620720820921021121221321421521621721821922022122222322422522622722822923023123223323423523623723823924024124224324424524624724824925025125225325425525625725825926026126226326426526626726826927027127227327427527627727827928028128228328428528628728828929029129229329429529629729829930030130230330430530630730830931031131231331431531631731831932032132232332432532632732832933033133233333433533633733833934034134234334434534634734834935035135235335435535635735835936036136236336436536636736836937037137237337437537637737837938038138238338438538638738838939039139239339439539639739839940040140240340440540640740840941041141241341441541641741841942042142242342442542642742842943043143243343443543643743843944044144244344444544644744844945045145245345445545645745845946046146246346446546646746846947047147247347447547647747847948048148248348448548648748848949049149249349449549649749849950050150250350450550650750850951051151251351451551651751851952052152252352452552652752852953053153253353453553653753853954054154254354454554654754854955055155255355455555655755855956056156256356456556656756856957057157257357457557657757857958058158258358458558658758858959059159259359459559659759859960060160260360460560660760860961061161261361461561661761861962062162262362462562662762862963063163263363463563663763863964064164264364464564664764864965065165265365465565665765865966066166266366466566666766866967067167267367467567667767867968068168268368468568668768868969069169269369469569669769869970070170270370470570670770870971071171271371471571671771871972072172272372472572672772872973073173273373473573673773873974074174274374474574674774874975075175275375475575675775875976076176276376476576676776876977077177277377477577677777877978078178278378478578678778878979079179279379479579679779879980080180280380480580680780880981081181281381481581681781881982082182282382482582682782882983083183283383483583683783883984084184284384484584684784884985085185285385485585685785885986086186286386486586686786886987087187287387487587687787887988088188288388488588688788888989089189289389489589689789889990090190290390490590690790890991091191291391491591691791891992092192292392492592692792892993093193293393493593693793893994094194294394494594694794894995095195295395495595695795895996096196296396496596696796896997097197297397497597697797897998098198298398498598698798898999099199299399499599699799899910001001100210031004100510061007100810091010101110121013101410151016101710181019102010211022102310241025102610271028102910301031103210331034103510361037103810391040104110421043104410451046104710481049105010511052105310541055105610571058105910601061106210631064106510661067106810691070107110721073107410751076107710781079108010811082108310841085108610871088108910901091109210931094109510961097109810991100110111021103110411051106110711081109111011111112111311141115111611171118111911201121112211231124112511261127112811291130113111321133113411351136113711381139114011411142114311441145114611471148114911501151115211531154115511561157115811591160116111621163116411651166116711681169117011711172117311741175117611771178117911801181118211831184118511861187118811891190119111921193119411951196119711981199120012011202120312041205120612071208120912101211121212131214121512161217
  1. /*
  2. Copyright (c) 2004-2012, The Dojo Foundation All Rights Reserved.
  3. Available via Academic Free License >= 2.1 OR the modified BSD license.
  4. see: http://dojotoolkit.org/license for details
  5. */
  6. if(!dojo._hasResource["dojox.editor.plugins.TablePlugins"]){ //_hasResource checks added by build. Do not use _hasResource directly in your code.
  7. dojo._hasResource["dojox.editor.plugins.TablePlugins"] = true;
  8. dojo.provide("dojox.editor.plugins.TablePlugins");
  9. dojo.require("dijit.form.Button");
  10. dojo.require("dijit.Dialog");
  11. dojo.require("dijit.form.TextBox");
  12. dojo.require("dijit.form.FilteringSelect");
  13. dojo.require("dijit._editor._Plugin");
  14. dojo.require("dijit._editor.selection");
  15. dojo.require("dijit.Menu");
  16. dojo.require("dijit.ColorPalette");
  17. dojo.require("dojox.widget.ColorPicker");
  18. dojo.require("dojo.i18n");
  19. 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");
  20. dojo.experimental("dojox.editor.plugins.TablePlugins");
  21. // summary:
  22. // A series of plugins that give the Editor the ability to create and edit
  23. // HTML tables. See the end of this document for all avaiable plugins
  24. // and dojox/editorPlugins/tests/editorTablePlugs.html for an example
  25. //
  26. // example:
  27. // | <div dojoType="dijit.Editor" plugins="[
  28. // | 'bold','italic','|',
  29. // | {name: 'dojox.editor.plugins.TablePlugins', command: 'insertTable'},
  30. // | {name: 'dojox.editor.plugins.TablePlugins', command: 'modifyTable'}
  31. // | ]">
  32. // | Editor text is here
  33. // | </div>
  34. //
  35. // TODO:
  36. // Currently not supporting merging or splitting cells
  37. //
  38. // FIXME: Undo is very buggy, and therefore unimeplented in all browsers
  39. // except IE - which itself has only been lightly tested.
  40. //
  41. // FIXME: Selecting multiple table cells in Firefox looks to be impossible.
  42. // This affect the 'colorTableCell' plugin. Cells can still be
  43. // colored individually or in rows.
  44. dojo.declare("dojox.editor.plugins._TableHandler", dijit._editor._Plugin,{
  45. // summary:
  46. // A global object that handles common tasks for all the plugins. Since
  47. // there are several plugins that are all calling common methods, it's preferable
  48. // that they call a centralized location that either has a set variable or a
  49. // timeout to only repeat code-heavy calls when necessary.
  50. //
  51. tablesConnected:false,
  52. currentlyAvailable: false,
  53. alwaysAvailable:false,
  54. availableCurrentlySet:false,
  55. initialized:false,
  56. tableData: null,
  57. shiftKeyDown:false,
  58. editorDomNode: null,
  59. undoEnabled: true, //Using custom undo for all browsers.
  60. refCount: 0,
  61. doMixins: function(){
  62. dojo.mixin(this.editor,{
  63. getAncestorElement: function(tagName){
  64. return dojo.withGlobal(this.window, "getAncestorElement",dijit._editor.selection, [tagName]);
  65. },
  66. hasAncestorElement: function(tagName){
  67. return dojo.withGlobal(this.window, "hasAncestorElement",dijit._editor.selection, [tagName]);
  68. },
  69. selectElement: function(elem){
  70. dojo.withGlobal(this.window, "selectElement",dijit._editor.selection, [elem]);
  71. },
  72. byId: function(id){
  73. return dojo.withGlobal(this.window, "byId", dojo, [id]);
  74. },
  75. query: function(arg, scope, returnFirstOnly){
  76. // this shortcut is dubious - not sure scoping is necessary
  77. var ar = dojo.withGlobal(this.window, "query", dojo, [arg, scope]);
  78. return (returnFirstOnly) ? ar[0] : ar;
  79. }
  80. });
  81. },
  82. initialize: function(editor){
  83. // summary:
  84. // Initialize the global handler upon a plugin's first instance of setEditor
  85. //
  86. // All plugins will attempt initialization. We only need to do so once.
  87. // But keep track so that it is cleaned up when all usage of it for an editor has
  88. // been removed.
  89. this.refCount++;
  90. // Turn on custom undo for all.
  91. editor.customUndo = true;
  92. if(this.initialized){ return; }
  93. this.initialized = true;
  94. this.editor = editor;
  95. this.editor._tablePluginHandler = this;
  96. //Editor loads async, can't assume doc is ready yet. So, use the deferred of the
  97. //editor to init at the right time.
  98. editor.onLoadDeferred.addCallback(dojo.hitch(this, function(){
  99. this.editorDomNode = this.editor.editNode || this.editor.iframe.document.body.firstChild;
  100. // RichText should have a mouseup connection to recognize drag-selections
  101. // Example would be selecting multiple table cells
  102. this._myListeners = [];
  103. this._myListeners.push(dojo.connect(this.editorDomNode , "mouseup", this.editor, "onClick"));
  104. this._myListeners.push(dojo.connect(this.editor, "onDisplayChanged", this, "checkAvailable"));
  105. this._myListeners.push(dojo.connect(this.editor, "onBlur", this, "checkAvailable"));
  106. this.doMixins();
  107. this.connectDraggable();
  108. }));
  109. },
  110. getTableInfo: function(forceNewData){
  111. // summary:
  112. // Gets the table in focus
  113. // Collects info on the table - see return params
  114. //
  115. if(forceNewData){ this._tempStoreTableData(false); }
  116. if(this.tableData){
  117. // tableData is set for a short amount of time, so that all
  118. // plugins get the same return without doing the method over
  119. //console.log("returning current tableData:", this.tableData);
  120. return this.tableData;
  121. }
  122. var tr, trs, td, tds, tbl, cols, tdIndex, trIndex;
  123. td = this.editor.getAncestorElement("td");
  124. if(td){ tr = td.parentNode; }
  125. tbl = this.editor.getAncestorElement("table");
  126. //console.log("td:", td);console.log("tr:", tr);console.log("tbl:", tbl)
  127. tds = dojo.query("td", tbl);
  128. tds.forEach(function(d, i){
  129. if(td==d){tdIndex = i;}
  130. });
  131. trs = dojo.query("tr", tbl);
  132. trs.forEach(function(r, i){
  133. if(tr==r){trIndex = i;}
  134. });
  135. cols = tds.length/trs.length;
  136. var o = {
  137. tbl:tbl, // focused table
  138. td:td, // focused TD
  139. tr:tr, // focused TR
  140. trs:trs, // rows
  141. tds:tds, // cells
  142. rows:trs.length,// row amount
  143. cols:cols, // column amount
  144. tdIndex:tdIndex,// index of focused cell
  145. trIndex:trIndex, // index of focused row
  146. colIndex:tdIndex%cols
  147. };
  148. //console.log("NEW tableData:",o);
  149. this.tableData = o;
  150. this._tempStoreTableData(500);
  151. return this.tableData;
  152. },
  153. connectDraggable: function(){
  154. // summary:
  155. // Detects drag-n-drop in the editor (could probably be moved to there)
  156. // Currently only checks if item dragged was a TABLE, and removes its align attr
  157. // DOES NOT WORK IN FF - it could - but FF's drag detection is a monster
  158. //
  159. if(!dojo.isIE){
  160. //console.warn("Drag and Drop is currently only detectable in IE.");
  161. return;
  162. }
  163. // IE ONLY
  164. this.editorDomNode.ondragstart = dojo.hitch(this, "onDragStart");
  165. this.editorDomNode.ondragend = dojo.hitch(this, "onDragEnd");
  166. //NOTES:
  167. // FF _ Able to detect the drag-over object (the editor.domNode)
  168. // Not able to detect an item's ondrag() event
  169. // Don't know why - I actually got it working when there was an error
  170. // Something to do with different documents or windows I'm sure
  171. //
  172. //console.log("connectDraggable", tbl);
  173. /*tbl.ondragstart=dojo.hitch(this, "onDragStart");
  174. tbl.addEventListener("dragstart", dojo.hitch(this, "onDragStart"), false);
  175. tbl.addEventListener("drag", dojo.hitch(this, "onDragStart2"), false);
  176. tbl.addEventListener("dragend", dojo.hitch(this, "onDragStart3"), false);
  177. dojo.withGlobal(this.editor.window, "selectElement",dijit._editor.selection, [tbl]);
  178. tbl.ondragstart = function(){
  179. //console.log("ondragstart");
  180. };
  181. tbl.ondrag = function(){
  182. alert("drag")
  183. //console.log("ondrag");
  184. */
  185. },
  186. onDragStart: function(){
  187. var e = window.event;
  188. if(!e.srcElement.id){
  189. e.srcElement.id = "tbl_"+(new Date().getTime());
  190. }
  191. //console.log("onDragStart", e.srcElement.id);
  192. },
  193. onDragEnd: function(){
  194. // summary:
  195. // Detects that an object has been dragged into place
  196. // Currently, this code is only used for when a table is dragged
  197. // and clears the "align" attribute, so that the table will look
  198. // to be more in the place that the user expected.
  199. // TODO: This code can be used for other things, most
  200. // notably UNDO, which currently is not quite usable.
  201. // This code could also find itself in the Editor code when it is
  202. // complete.
  203. //console.log("onDragEnd");
  204. var e = window.event;
  205. var node = e.srcElement;
  206. var id = node.id;
  207. var win = this.editor.window;
  208. //console.log("NODE:", node.tagName, node.id, dojo.attr(node, "align"));
  209. // clearing a table's align attr
  210. // TODO: when ondrag becomes more robust, this code block
  211. // should move to its own method
  212. if(node.tagName.toLowerCase()=="table"){
  213. setTimeout(function(){
  214. var node = dojo.withGlobal(win, "byId", dojo, [id]);
  215. dojo.removeAttr(node, "align");
  216. //console.log("set", node.tagName, dojo.attr(node, "align"))
  217. }, 100);
  218. }
  219. },
  220. checkAvailable: function(){
  221. // summary:
  222. // For table plugs
  223. // Checking if a table or part of a table has focus so that
  224. // Plugs can change their status
  225. //
  226. if(this.availableCurrentlySet){
  227. // availableCurrentlySet is set for a short amount of time, so that all
  228. // plugins get the same return without doing the method over
  229. //console.log("availableCurrentlySet:", this.availableCurrentlySet, "currentlyAvailable:", this.currentlyAvailable)
  230. return this.currentlyAvailable;
  231. }
  232. //console.log("G - checkAvailable...");
  233. if(!this.editor) {
  234. //console.log("editor not ready")
  235. return false;
  236. }
  237. if(this.alwaysAvailable) {
  238. //console.log(" return always available")
  239. return true;
  240. }
  241. // Only return avalable if the editor is focused.
  242. this.currentlyAvailable = this.editor._focused ? this.editor.hasAncestorElement("table") : false;
  243. if(this.currentlyAvailable){
  244. this.connectTableKeys();
  245. }else{
  246. this.disconnectTableKeys();
  247. }
  248. this._tempAvailability(500);
  249. dojo.publish(this.editor.id + "_tablePlugins", [ this.currentlyAvailable ]);
  250. return this.currentlyAvailable;
  251. },
  252. _prepareTable: function(tbl){
  253. // For IE's sake, we are adding IDs to the TDs if none is there
  254. // We go ahead and use it for other code for convenience
  255. //
  256. var tds = this.editor.query("td", tbl);
  257. console.log("prep:", tds, tbl);
  258. if(!tds[0].id){
  259. tds.forEach(function(td, i){
  260. if(!td.id){
  261. td.id = "tdid"+i+this.getTimeStamp();
  262. }
  263. }, this);
  264. }
  265. return tds;
  266. },
  267. getTimeStamp: function(){
  268. return new Date().getTime(); // Fixed the bug that this method always returns the same timestamp
  269. // return Math.floor(new Date().getTime() * 0.00000001);
  270. },
  271. _tempStoreTableData: function(type){
  272. // caching or clearing table data, depending on the arg
  273. //
  274. if(type===true){
  275. //store indefinitely
  276. }else if(type===false){
  277. // clear object
  278. this.tableData = null;
  279. }else if(type===undefined){
  280. console.warn("_tempStoreTableData must be passed an argument");
  281. }else{
  282. // type is a number/ms
  283. setTimeout(dojo.hitch(this, function(){
  284. this.tableData = null;
  285. }), type);
  286. }
  287. },
  288. _tempAvailability: function(type){
  289. // caching or clearing availability, depending on the arg
  290. if(type===true){
  291. //store indefinitely
  292. this.availableCurrentlySet = true;
  293. }else if(type===false){
  294. // clear object
  295. this.availableCurrentlySet = false;
  296. }else if(type===undefined){
  297. console.warn("_tempAvailability must be passed an argument");
  298. }else{
  299. // type is a number/ms
  300. this.availableCurrentlySet = true;
  301. setTimeout(dojo.hitch(this, function(){
  302. this.availableCurrentlySet = false;
  303. }), type);
  304. }
  305. },
  306. connectTableKeys: function(){
  307. // summary:
  308. // When a table is in focus, start detecting keys
  309. // Mainly checking for the TAB key so user can tab
  310. // through a table (blocking the browser's desire to
  311. // tab away from teh editor completely)
  312. if(this.tablesConnected){ return; }
  313. this.tablesConnected = true;
  314. var node = (this.editor.iframe) ? this.editor.document : this.editor.editNode;
  315. this.cnKeyDn = dojo.connect(node, "onkeydown", this, "onKeyDown");
  316. this.cnKeyUp = dojo.connect(node, "onkeyup", this, "onKeyUp");
  317. this._myListeners.push(dojo.connect(node, "onkeypress", this, "onKeyUp"));
  318. },
  319. disconnectTableKeys: function(){
  320. //console.log("disconnect")
  321. dojo.disconnect(this.cnKeyDn);
  322. dojo.disconnect(this.cnKeyUp);
  323. this.tablesConnected = false;
  324. },
  325. onKeyDown: function(evt){
  326. var key = evt.keyCode;
  327. //console.log(" -> DOWN:", key);
  328. if(key == 16){ this.shiftKeyDown = true;}
  329. if(key == 9) {
  330. var o = this.getTableInfo();
  331. //console.log("TAB ", o.tdIndex, o);
  332. // modifying the o.tdIndex in the tableData directly, because we may save it
  333. // FIXME: tabTo is a global
  334. o.tdIndex = (this.shiftKeyDown) ? o.tdIndex-1 : tabTo = o.tdIndex+1;
  335. if(o.tdIndex>=0 && o.tdIndex<o.tds.length){
  336. this.editor.selectElement(o.tds[o.tdIndex]);
  337. // we know we are still within a table, so block the need
  338. // to run the method
  339. this.currentlyAvailable = true;
  340. this._tempAvailability(true);
  341. //
  342. this._tempStoreTableData(true);
  343. this.stopEvent = true;
  344. }else{
  345. //tabbed out of table
  346. this.stopEvent = false;
  347. this.onDisplayChanged();
  348. }
  349. if(this.stopEvent) {
  350. dojo.stopEvent(evt);
  351. }
  352. }
  353. },
  354. onKeyUp: function(evt){
  355. var key = evt.keyCode;
  356. //console.log(" -> UP:", key)
  357. if(key == 16){ this.shiftKeyDown = false;}
  358. if(key == 37 || key == 38 || key == 39 || key == 40 ){
  359. // user can arrow or tab out of table - need to recheck
  360. this.onDisplayChanged();
  361. }
  362. if(key == 9 && this.stopEvent){ dojo.stopEvent(evt);}
  363. },
  364. onDisplayChanged: function(){
  365. //console.log("onDisplayChanged")
  366. this.currentlyAvailable = false;
  367. this._tempStoreTableData(false);
  368. this._tempAvailability(false);
  369. this.checkAvailable();
  370. },
  371. uninitialize: function(editor){
  372. // summary:
  373. // Function to handle cleaning up of connects
  374. // and such. It only finally destroys everything once
  375. // all 'references' to it have gone. As in all plugins
  376. // that called init on it destroyed their refs in their
  377. // cleanup calls.
  378. // editor:
  379. // The editor to detach from.
  380. if(this.editor == editor){
  381. this.refCount--;
  382. if(!this.refCount && this.initialized){
  383. if(this.tablesConnected){
  384. this.disconnectTableKeys();
  385. }
  386. this.initialized = false;
  387. dojo.forEach(this._myListeners, function(l){
  388. dojo.disconnect(l);
  389. });
  390. delete this._myListeners;
  391. delete this.editor._tablePluginHandler;
  392. delete this.editor;
  393. }
  394. this.inherited(arguments);
  395. }
  396. }
  397. });
  398. dojo.declare("dojox.editor.plugins.TablePlugins",
  399. dijit._editor._Plugin,
  400. {
  401. //summary:
  402. // A collection of Plugins for inserting and modifying tables in the Editor
  403. // See end of this document for all avaiable plugs
  404. // and dojox/editorPlugins/tests/editorTablePlugs.html for an example
  405. //
  406. // NOT IMPLEMENTED: Not handling cell merge, span or split
  407. //
  408. iconClassPrefix: "editorIcon",
  409. useDefaultCommand: false,
  410. buttonClass: dijit.form.Button,
  411. commandName:"",
  412. label:"",
  413. alwaysAvailable:false,
  414. undoEnabled:true,
  415. onDisplayChanged: function(withinTable){
  416. // subscribed to from the global object's publish method
  417. //
  418. //console.log("onDisplayChanged", this.commandName);
  419. if(!this.alwaysAvailable){
  420. this.available = withinTable;
  421. this.button.set('disabled', !this.available);
  422. }
  423. },
  424. setEditor: function(editor){
  425. this.editor = editor;
  426. this.editor.customUndo = true;
  427. this.inherited(arguments);
  428. this._availableTopic = dojo.subscribe(this.editor.id + "_tablePlugins", this, "onDisplayChanged");
  429. this.onEditorLoaded();
  430. },
  431. onEditorLoaded: function(){
  432. if(!this.editor._tablePluginHandler){
  433. // Create it and init it off the editor. This
  434. // will create the _tablePluginHandler reference on
  435. // the dijit.Editor instance. This avoids a global.
  436. var tablePluginHandler = new dojox.editor.plugins._TableHandler();
  437. tablePluginHandler.initialize(this.editor);
  438. }else{
  439. this.editor._tablePluginHandler.initialize(this.editor);
  440. }
  441. },
  442. selectTable: function(){
  443. // selects table that is in focus
  444. var o = this.getTableInfo();
  445. if(o && o.tbl){
  446. dojo.withGlobal(this.editor.window, "selectElement",dijit._editor.selection, [o.tbl]);
  447. }
  448. },
  449. _initButton: function(){
  450. this.command = this.commandName;
  451. this.label = this.editor.commands[this.command] = this._makeTitle(this.command);
  452. this.inherited(arguments);
  453. delete this.command;
  454. this.connect(this.button, "onClick", "modTable");
  455. this.onDisplayChanged(false);
  456. },
  457. modTable: function(cmd, args){
  458. // summary:
  459. // Where each plugin performs its action
  460. // Note: not using execCommand. In spite of their presence in the
  461. // Editor as query-able plugins, I was not able to find any evidence
  462. // that they are supported (especially in NOT IE). If they are
  463. // supported in other browsers, it may help with the undo problem.
  464. //
  465. this.begEdit();
  466. var o = this.getTableInfo();
  467. var sw = (dojo.isString(cmd))?cmd : this.commandName;
  468. var r, c, i;
  469. var adjustColWidth = false;
  470. //console.log("modTable:", sw)
  471. if(dojo.isIE){
  472. // IE can lose selections on focus changes, so focus back
  473. // in order to restore it.
  474. this.editor.focus();
  475. }
  476. switch(sw){
  477. case "insertTableRowBefore":
  478. r = o.tbl.insertRow(o.trIndex);
  479. for(i=0;i<o.cols;i++){
  480. c = r.insertCell(-1);
  481. c.innerHTML = "&nbsp;";
  482. }
  483. break;
  484. case "insertTableRowAfter":
  485. r = o.tbl.insertRow(o.trIndex+1);
  486. for(i=0;i<o.cols;i++){
  487. c = r.insertCell(-1);
  488. c.innerHTML = "&nbsp;";
  489. }
  490. break;
  491. case "insertTableColumnBefore":
  492. o.trs.forEach(function(r){
  493. c = r.insertCell(o.colIndex);
  494. c.innerHTML = "&nbsp;";
  495. });
  496. adjustColWidth = true;
  497. break;
  498. case "insertTableColumnAfter":
  499. o.trs.forEach(function(r){
  500. c = r.insertCell(o.colIndex+1);
  501. c.innerHTML = "&nbsp;";
  502. });
  503. adjustColWidth = true;
  504. break;
  505. case "deleteTableRow":
  506. o.tbl.deleteRow(o.trIndex);
  507. console.log("TableInfo:", this.getTableInfo());
  508. break;
  509. case "deleteTableColumn":
  510. o.trs.forEach(function(tr){
  511. tr.deleteCell(o.colIndex);
  512. });
  513. adjustColWidth = true;
  514. break;
  515. case "modifyTable":
  516. break;
  517. case "insertTable":
  518. break;
  519. }
  520. if(adjustColWidth){
  521. this.makeColumnsEven();
  522. }
  523. this.endEdit();
  524. },
  525. begEdit: function(){
  526. if(this.editor._tablePluginHandler.undoEnabled){
  527. //console.log("UNDO:", this.editor.customUndo);
  528. if(this.editor.customUndo){
  529. this.editor.beginEditing();
  530. }else{
  531. this.valBeforeUndo = this.editor.getValue();
  532. //console.log("VAL:", this.valBeforeUndo);
  533. }
  534. }
  535. },
  536. endEdit: function(){
  537. if(this.editor._tablePluginHandler.undoEnabled){
  538. if(this.editor.customUndo){
  539. this.editor.endEditing();
  540. }else{
  541. // This code ALMOST works for undo -
  542. // It seems to only work for one step
  543. // back in history however
  544. var afterUndo = this.editor.getValue();
  545. //this.editor.execCommand("inserthtml", "<p>mike</p>");
  546. this.editor.setValue(this.valBeforeUndo);
  547. this.editor.replaceValue(afterUndo);
  548. }
  549. this.editor.onDisplayChanged();
  550. }
  551. },
  552. makeColumnsEven: function(){
  553. //summary:
  554. // After changing column amount, change widths to
  555. // keep columns even
  556. //
  557. // the timeout helps prevent an occasional snafu
  558. setTimeout(dojo.hitch(this, function(){
  559. var o = this.getTableInfo(true);
  560. var w = Math.floor(100/o.cols);
  561. o.tds.forEach(function(d){
  562. dojo.attr(d, "width", w+"%");
  563. });
  564. }), 10);
  565. },
  566. getTableInfo: function(forceNewData){
  567. // summary:
  568. // Gets the table in focus
  569. // Collects info on the table - see return params
  570. //
  571. return this.editor._tablePluginHandler.getTableInfo(forceNewData);
  572. },
  573. _makeTitle: function(str){
  574. // Parses the commandName into a Title
  575. // based on camelCase
  576. var ns = [];
  577. dojo.forEach(str, function(c, i){
  578. if(c.charCodeAt(0)<91 && i>0 && ns[i-1].charCodeAt(0)!=32){
  579. ns.push(" ");
  580. }
  581. if(i===0){ c = c.toUpperCase();}
  582. ns.push(c);
  583. });
  584. return ns.join("");
  585. },
  586. getSelectedCells: function(){
  587. // summary:
  588. // Gets the selected cells from the passed table
  589. // Returns: array of TDs or empty array
  590. var cells = [];
  591. var tbl = this.getTableInfo().tbl;
  592. this.editor._tablePluginHandler._prepareTable(tbl);
  593. var e = this.editor;
  594. // Lets do this the way IE originally was (Looking up ids). Walking the selection
  595. // is inconsistent in the browsers (and painful), so going by ids is simpler.
  596. var text = dojo.withGlobal(e.window, "getSelectedHtml",dijit._editor.selection, [null]);
  597. var str = text.match(/id="*\w*"*/g);
  598. dojo.forEach(str, function(a){
  599. var id = a.substring(3, a.length);
  600. if(id.charAt(0) == "\"" && id.charAt(id.length - 1) == "\""){
  601. id = id.substring(1, id.length - 1);
  602. }
  603. var node = e.byId(id);
  604. if(node && node.tagName.toLowerCase() == "td"){
  605. cells.push(node);
  606. }
  607. }, this);
  608. if(!cells.length){
  609. //May just be in a cell (cursor point, or selection in a cell), so look upwards.
  610. //for a cell container.
  611. var sel = dijit.range.getSelection(e.window);
  612. if(sel.rangeCount){
  613. var r = sel.getRangeAt(0);
  614. var node = r.startContainer;
  615. while(node && node != e.editNode && node != e.document){
  616. if(node.nodeType === 1){
  617. var tg = node.tagName ? node.tagName.toLowerCase() : "";
  618. if(tg === "td"){
  619. return [node];
  620. }
  621. }
  622. node = node.parentNode;
  623. }
  624. }
  625. }
  626. return cells;
  627. },
  628. updateState: function(){
  629. // summary:
  630. // Over-ride for button state control for disabled to work.
  631. if(this.button){
  632. if((this.available || this.alwaysAvailable) && !this.get("disabled")){
  633. this.button.set("disabled",false);
  634. }else{
  635. this.button.set("disabled",true);
  636. }
  637. }
  638. },
  639. destroy: function(){
  640. // summary:
  641. // Over-ridden destroy to do some cleanup.
  642. this.inherited(arguments);
  643. dojo.unsubscribe(this._availableTopic);
  644. // Disconnect the editor from the handler
  645. // to clean up refs. Moved to using a per-editor
  646. // 'handler' to avoid collisions on the old global.
  647. this.editor._tablePluginHandler.uninitialize(this.editor);
  648. }
  649. }
  650. );
  651. dojo.declare("dojox.editor.plugins.TableContextMenu",
  652. dojox.editor.plugins.TablePlugins,
  653. {
  654. constructor: function(){
  655. // summary:
  656. // Initialize certain plugins
  657. //
  658. this.connect(this, "setEditor", function(editor){
  659. editor.onLoadDeferred.addCallback(dojo.hitch(this, function() {
  660. this._createContextMenu();
  661. }));
  662. this.button.domNode.style.display = "none";
  663. });
  664. },
  665. destroy: function(){
  666. // summary:
  667. // Over-ride to do menu cleanup.
  668. if(this.menu){
  669. this.menu.destroyRecursive();
  670. delete this.menu;
  671. }
  672. this.inherited(arguments);
  673. },
  674. _initButton: function(){
  675. this.inherited(arguments);
  676. if(this.commandName=="tableContextMenu"){ this.button.domNode.display = "none";}
  677. },
  678. _createContextMenu: function(){
  679. // summary
  680. // Building context menu for right-click shortcuts within a table
  681. //
  682. var pMenu = new dijit.Menu({targetNodeIds:[this.editor.iframe]});
  683. var messages = dojo.i18n.getLocalization("dojox.editor.plugins", "TableDialog", this.lang);
  684. pMenu.addChild(new dijit.MenuItem({label: messages.selectTableLabel, onClick: dojo.hitch(this, "selectTable")}));
  685. pMenu.addChild(new dijit.MenuSeparator());
  686. pMenu.addChild(new dijit.MenuItem({label: messages.insertTableRowBeforeLabel, onClick: dojo.hitch(this, "modTable", "insertTableRowBefore" )}));
  687. pMenu.addChild(new dijit.MenuItem({label: messages.insertTableRowAfterLabel, onClick: dojo.hitch(this, "modTable", "insertTableRowAfter" )}));
  688. pMenu.addChild(new dijit.MenuItem({label: messages.insertTableColumnBeforeLabel, onClick: dojo.hitch(this, "modTable", "insertTableColumnBefore" )}));
  689. pMenu.addChild(new dijit.MenuItem({label: messages.insertTableColumnAfterLabel, onClick: dojo.hitch(this, "modTable", "insertTableColumnAfter" )}));
  690. pMenu.addChild(new dijit.MenuSeparator());
  691. pMenu.addChild(new dijit.MenuItem({label: messages.deleteTableRowLabel, onClick: dojo.hitch(this, "modTable", "deleteTableRow" )}));
  692. pMenu.addChild(new dijit.MenuItem({label: messages.deleteTableColumnLabel, onClick: dojo.hitch(this, "modTable", "deleteTableColumn" )}));
  693. this.menu = pMenu;
  694. }
  695. });
  696. dojo.declare("dojox.editor.plugins.InsertTable",
  697. dojox.editor.plugins.TablePlugins,
  698. {
  699. alwaysAvailable: true,
  700. modTable: function(){
  701. var w = new dojox.editor.plugins.EditorTableDialog({});
  702. w.show();
  703. var c = dojo.connect(w, "onBuildTable", this, function(obj){
  704. dojo.disconnect(c);
  705. var res = this.editor.execCommand('inserthtml', obj.htmlText);
  706. // commenting this line, due to msg below
  707. //var td = this.editor.query("td", this.editor.byId(obj.id));
  708. //HMMMM.... This throws a security error now. didn't used to.
  709. //this.editor.selectElement(td);
  710. });
  711. }
  712. });
  713. dojo.declare("dojox.editor.plugins.ModifyTable",
  714. dojox.editor.plugins.TablePlugins,
  715. {
  716. modTable: function(){
  717. if (!this.editor._tablePluginHandler.checkAvailable()) {return;}
  718. var o = this.getTableInfo();
  719. //console.log("LAUNCH DIALOG");
  720. var w = new dojox.editor.plugins.EditorModifyTableDialog({table:o.tbl});
  721. w.show();
  722. this.connect(w, "onSetTable", function(color){
  723. // uhm... not sure whats going on here...
  724. var o = this.getTableInfo();
  725. //console.log("set color:", color);
  726. dojo.attr(o.td, "bgcolor", color);
  727. });
  728. }
  729. });
  730. dojo.declare("dojox.editor.plugins._CellColorDropDown", [dijit._Widget, dijit._Templated], {
  731. // summary:
  732. // A smple widget that uses/creates a dropdown with a dojox.widget.ColorPicker. Also provides
  733. // passthroughs to the value of the color picker and convenient hook points.
  734. // tags:
  735. // private
  736. // templateString: String
  737. // The template used to create the ColorPicker.
  738. templateString:
  739. "<div style='display: none; position: absolute; top: -10000; z-index: -10000'>" +
  740. "<div dojoType='dijit.TooltipDialog' dojoAttachPoint='dialog' class='dojoxEditorColorPicker'>" +
  741. "<div dojoType='dojox.widget.ColorPicker' dojoAttachPoint='_colorPicker'></div>" +
  742. "<div style='margin: 0.5em 0em 0em 0em'>" +
  743. "<button dojoType='dijit.form.Button' type='button' dojoAttachPoint='_setButton'>${buttonSet}</button>" +
  744. "&nbsp;" +
  745. "<button dojoType='dijit.form.Button' type='button' dojoAttachPoint='_cancelButton'>${buttonCancel}</button>" +
  746. "</div>" +
  747. "</div>" +
  748. "</div>",
  749. // widgetsInTemplate: Boolean
  750. // Flag denoting widgets are contained in the template.
  751. widgetsInTemplate: true,
  752. constructor: function(){
  753. // summary:
  754. // Constructor over-ride so that the translated strings are mixsed in so
  755. // the template fills out.
  756. var strings = dojo.i18n.getLocalization("dojox.editor.plugins", "TableDialog");
  757. dojo.mixin(this, strings);
  758. },
  759. startup: function(){
  760. // summary:
  761. // Over-ride of startup to do the basic connect setups and such.
  762. if(!this._started){
  763. this.inherited(arguments);
  764. this.connect(this._setButton, "onClick", function(){
  765. this.onChange(this.get("value"));
  766. });
  767. this.connect(this._cancelButton, "onClick", function(){
  768. dijit.popup.close(this.dialog);
  769. this.onCancel();
  770. });
  771. // Fully statred, so go ahead and remove the hide.
  772. dojo.style(this.domNode, "display", "block");
  773. }
  774. },
  775. _setValueAttr: function(value, priorityChange){
  776. // summary:
  777. // Passthrough function for the color picker value.
  778. // value: String
  779. // The value to set in the color picker
  780. // priorityChange:
  781. // Value to indicate whether or not to trigger an onChange event.
  782. this._colorPicker.set("value", value, priorityChange);
  783. },
  784. _getValueAttr: function(){
  785. // summary:
  786. // Passthrough function for the color picker value.
  787. return this._colorPicker.get("value");
  788. },
  789. setColor: function(/*String*/ color){
  790. this._colorPicker.setColor(color, false);
  791. },
  792. onChange: function(value){
  793. // summary:
  794. // Hook point to get the value when the color picker value is selected.
  795. // value: String
  796. // The value from the color picker.
  797. },
  798. onCancel: function(){
  799. // summary:
  800. // Hook point to get when the dialog is canceled.
  801. }
  802. });
  803. dojo.declare("dojox.editor.plugins.ColorTableCell", dojox.editor.plugins.TablePlugins, {
  804. constructor: function(){
  805. // summary:
  806. // Initialize ColorTableCell plugin
  807. this.closable = true;
  808. this.buttonClass = dijit.form.DropDownButton;
  809. var picker = new dojox.editor.plugins._CellColorDropDown();
  810. dojo.body().appendChild(picker.domNode);
  811. picker.startup();
  812. this.dropDown = picker.dialog;
  813. this.connect(picker, "onChange", function(color){
  814. this.modTable(null, color);
  815. this.editor.focus();
  816. });
  817. this.connect(picker, "onCancel", function(color){
  818. this.editor.focus();
  819. });
  820. this.connect(picker.dialog, "onOpen", function(){
  821. var o = this.getTableInfo(),
  822. tds = this.getSelectedCells(o.tbl);
  823. if(tds && tds.length > 0){
  824. var t = tds[0] == this.lastObject ? tds[0] : tds[tds.length - 1],
  825. color;
  826. while(t && ((color = dojo.style(t, "backgroundColor")) == "transparent" || color.indexOf("rgba") == 0)){
  827. t = t.parentNode;
  828. }
  829. color = dojo.style(t, "backgroundColor");
  830. if(color != "transparent" && color.indexOf("rgba") != 0){
  831. picker.setColor(color);
  832. }
  833. }
  834. });
  835. this.connect(this, "setEditor", function(editor){
  836. editor.onLoadDeferred.addCallback(dojo.hitch(this, function(){
  837. this.connect(this.editor.editNode, "onmouseup", function(evt){
  838. this.lastObject = evt.target;
  839. });
  840. }));
  841. });
  842. },
  843. _initButton: function(){
  844. this.command = this.commandName;
  845. this.label = this.editor.commands[this.command] = this._makeTitle(this.command);
  846. this.inherited(arguments);
  847. delete this.command;
  848. this.onDisplayChanged(false);
  849. },
  850. modTable: function(cmd, args){
  851. // summary
  852. // Where each plugin performs its action
  853. // Note: not using execCommand. In spite of their presence in the
  854. // Editor as query-able plugins, I was not able to find any evidence
  855. // that they are supported (especially in NOT IE). If they are
  856. // supported in other browsers, it may help with the undo problem.
  857. //
  858. this.begEdit();
  859. var o = this.getTableInfo();
  860. // The one plugin that really needs use of the very verbose
  861. // getSelectedCells()
  862. var tds = this.getSelectedCells(o.tbl);
  863. //console.debug("SELECTED CELLS ", tds , " FOR ", o);
  864. dojo.forEach(tds, function(td){
  865. dojo.style(td, "backgroundColor", args);
  866. });
  867. this.endEdit();
  868. }
  869. });
  870. dojo.declare("dojox.editor.plugins.EditorTableDialog", [dijit.Dialog], {
  871. // summary:
  872. // Dialog box with options for table creation
  873. //
  874. baseClass:"EditorTableDialog",
  875. widgetsInTemplate:true,
  876. 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"),
  877. postMixInProperties: function(){
  878. var messages = dojo.i18n.getLocalization("dojox.editor.plugins", "TableDialog", this.lang);
  879. dojo.mixin(this, messages);
  880. this.inherited(arguments);
  881. },
  882. postCreate: function(){
  883. dojo.addClass(this.domNode, this.baseClass); //FIXME - why isn't Dialog accepting the baseClass?
  884. this.inherited(arguments);
  885. },
  886. onInsert: function(){
  887. console.log("insert");
  888. var rows = this.selectRow.get("value") || 1,
  889. cols = this.selectCol.get("value") || 1,
  890. width = this.selectWidth.get("value"),
  891. widthType = this.selectWidthType.get("value"),
  892. border = this.selectBorder.get("value"),
  893. pad = this.selectPad.get("value"),
  894. space = this.selectSpace.get("value"),
  895. _id = "tbl_"+(new Date().getTime()),
  896. t = '<table id="'+_id+'"width="'+width+((widthType=="percent")?'%':'')+'" border="'+border+'" cellspacing="'+space+'" cellpadding="'+pad+'">\n';
  897. for(var r=0;r<rows;r++){
  898. t += '\t<tr>\n';
  899. for(var c=0;c<cols;c++){
  900. t += '\t\t<td width="'+(Math.floor(100/cols))+'%">&nbsp;</td>\n';
  901. }
  902. t += '\t</tr>\n';
  903. }
  904. t += '</table>';
  905. //console.log(t);
  906. this.onBuildTable({htmlText:t, id:_id});
  907. var cl = dojo.connect(this, "onHide", function(){
  908. dojo.disconnect(cl);
  909. var self = this;
  910. setTimeout(function(){
  911. self.destroyRecursive();
  912. }, 10);
  913. });
  914. this.hide();
  915. },
  916. onCancel: function(){
  917. // summary:
  918. // Function to clean up memory so that the dialog is destroyed
  919. // when closed.
  920. var c = dojo.connect(this, "onHide", function(){
  921. dojo.disconnect(c);
  922. var self = this;
  923. setTimeout(function(){
  924. self.destroyRecursive();
  925. }, 10);
  926. });
  927. },
  928. onBuildTable: function(tableText){
  929. //stub
  930. }
  931. });
  932. dojo.declare("dojox.editor.plugins.EditorModifyTableDialog", [dijit.Dialog], {
  933. // summary:
  934. // Dialog box with options for editing a table
  935. //
  936. baseClass:"EditorTableDialog",
  937. widgetsInTemplate:true,
  938. table:null, //html table to be modified
  939. tableAtts:{},
  940. 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"),
  941. postMixInProperties: function(){
  942. var messages = dojo.i18n.getLocalization("dojox.editor.plugins", "TableDialog", this.lang);
  943. dojo.mixin(this, messages);
  944. this.inherited(arguments);
  945. },
  946. postCreate: function(){
  947. dojo.addClass(this.domNode, this.baseClass); //FIXME - why isn't Dialog accepting the baseClass?
  948. this.inherited(arguments);
  949. this._cleanupWidgets = [];
  950. var w1 = new dijit.ColorPalette({});
  951. this.connect(w1, "onChange", function(color){
  952. dijit.popup.close(w1);
  953. this.setBrdColor(color);
  954. });
  955. this.connect(w1, "onBlur", function(){
  956. dijit.popup.close(w1);
  957. });
  958. this.connect(this.borderCol, "click", function(){
  959. dijit.popup.open({popup:w1, around:this.borderCol});
  960. w1.focus();
  961. });
  962. var w2 = new dijit.ColorPalette({});
  963. this.connect(w2, "onChange", function(color){
  964. dijit.popup.close(w2);
  965. this.setBkColor(color);
  966. });
  967. this.connect(w2, "onBlur", function(){
  968. dijit.popup.close(w2);
  969. });
  970. this.connect(this.backgroundCol, "click", function(){
  971. dijit.popup.open({popup:w2, around:this.backgroundCol});
  972. w2.focus();
  973. });
  974. this._cleanupWidgets.push(w1);
  975. this._cleanupWidgets.push(w2);
  976. this.setBrdColor(dojo.attr(this.table, "bordercolor"));
  977. this.setBkColor(dojo.attr(this.table, "bgcolor"));
  978. var w = dojo.attr(this.table, "width");
  979. if(!w){
  980. w = this.table.style.width;
  981. }
  982. var p = "pixels";
  983. if(dojo.isString(w) && w.indexOf("%")>-1){
  984. p = "percent";
  985. w = w.replace(/%/, "");
  986. }
  987. if(w){
  988. this.selectWidth.set("value", w);
  989. this.selectWidthType.set("value", p);
  990. }else{
  991. this.selectWidth.set("value", "");
  992. this.selectWidthType.set("value", "percent");
  993. }
  994. this.selectBorder.set("value", dojo.attr(this.table, "border"));
  995. this.selectPad.set("value", dojo.attr(this.table, "cellPadding"));
  996. this.selectSpace.set("value", dojo.attr(this.table, "cellSpacing"));
  997. this.selectAlign.set("value", dojo.attr(this.table, "align"));
  998. },
  999. setBrdColor: function(color){
  1000. this.brdColor = color;
  1001. dojo.style(this.borderCol, "backgroundColor", color);
  1002. },
  1003. setBkColor: function(color){
  1004. this.bkColor = color;
  1005. dojo.style(this.backgroundCol, "backgroundColor", color);
  1006. },
  1007. onSet: function(){
  1008. dojo.attr(this.table, "borderColor", this.brdColor);
  1009. dojo.attr(this.table, "bgColor", this.bkColor);
  1010. if(this.selectWidth.get("value")){
  1011. // Just in case, remove it from style since we're setting it as a table attribute.
  1012. dojo.style(this.table, "width", "");
  1013. dojo.attr(this.table, "width", (this.selectWidth.get("value") + ((this.selectWidthType.get("value")=="pixels")?"":"%") ));
  1014. }
  1015. dojo.attr(this.table, "border", this.selectBorder.get("value"));
  1016. dojo.attr(this.table, "cellPadding", this.selectPad.get("value"));
  1017. dojo.attr(this.table, "cellSpacing", this.selectSpace.get("value"));
  1018. dojo.attr(this.table, "align", this.selectAlign.get("value"));
  1019. var c = dojo.connect(this, "onHide", function(){
  1020. dojo.disconnect(c);
  1021. var self = this;
  1022. setTimeout(function(){
  1023. self.destroyRecursive();
  1024. }, 10);
  1025. });
  1026. this.hide();
  1027. },
  1028. onCancel: function(){
  1029. // summary:
  1030. // Function to clean up memory so that the dialog is destroyed
  1031. // when closed.
  1032. var c = dojo.connect(this, "onHide", function(){
  1033. dojo.disconnect(c);
  1034. var self = this;
  1035. setTimeout(function(){
  1036. self.destroyRecursive();
  1037. }, 10);
  1038. });
  1039. },
  1040. onSetTable: function(tableText){
  1041. //stub
  1042. },
  1043. destroy: function(){
  1044. // summary:
  1045. // Cleanup function.
  1046. this.inherited(arguments);
  1047. dojo.forEach(this._cleanupWidgets, function(w){
  1048. if(w && w.destroy){
  1049. w.destroy();
  1050. }
  1051. });
  1052. delete this._cleanupWidgets;
  1053. }
  1054. });
  1055. dojo.subscribe(dijit._scopeName + ".Editor.getPlugin",null,function(o){
  1056. if(o.plugin){ return; }
  1057. // make first character lower case
  1058. if(o.args && o.args.command){
  1059. var cmd = o.args.command.charAt(0).toLowerCase()+o.args.command.substring(1,o.args.command.length);
  1060. switch(cmd){
  1061. case "insertTableRowBefore":
  1062. case "insertTableRowAfter":
  1063. case "insertTableColumnBefore":
  1064. case "insertTableColumnAfter":
  1065. case "deleteTableRow":
  1066. case "deleteTableColumn":
  1067. o.plugin = new dojox.editor.plugins.TablePlugins({commandName: cmd});
  1068. break;
  1069. case "colorTableCell":
  1070. o.plugin = new dojox.editor.plugins.ColorTableCell({commandName: cmd});
  1071. break;
  1072. case "modifyTable":
  1073. o.plugin = new dojox.editor.plugins.ModifyTable({commandName: cmd});
  1074. break;
  1075. case "insertTable":
  1076. o.plugin = new dojox.editor.plugins.InsertTable({commandName: cmd});
  1077. break;
  1078. case "tableContextMenu":
  1079. o.plugin = new dojox.editor.plugins.TableContextMenu({commandName: cmd});
  1080. break;
  1081. }
  1082. }
  1083. });
  1084. }