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