tinymce-rails 3.5.2 → 3.5.4.1

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (33) hide show
  1. data/lib/tinymce/rails/version.rb +2 -2
  2. data/vendor/assets/javascripts/tinymce/jquery.tinymce.js +1 -1
  3. data/vendor/assets/javascripts/tinymce/plugins/autolink/editor_plugin_src.js +181 -181
  4. data/vendor/assets/javascripts/tinymce/plugins/autoresize/editor_plugin_src.js +119 -119
  5. data/vendor/assets/javascripts/tinymce/plugins/autosave/editor_plugin.js +1 -1
  6. data/vendor/assets/javascripts/tinymce/plugins/autosave/editor_plugin_src.js +4 -2
  7. data/vendor/assets/javascripts/tinymce/plugins/contextmenu/editor_plugin.js +1 -1
  8. data/vendor/assets/javascripts/tinymce/plugins/contextmenu/editor_plugin_src.js +9 -7
  9. data/vendor/assets/javascripts/tinymce/plugins/emotions/langs/en_dlg.js +1 -1
  10. data/vendor/assets/javascripts/tinymce/plugins/example_dependency/editor_plugin_src.js +50 -50
  11. data/vendor/assets/javascripts/tinymce/plugins/lists/editor_plugin.js +1 -1
  12. data/vendor/assets/javascripts/tinymce/plugins/lists/editor_plugin_src.js +952 -951
  13. data/vendor/assets/javascripts/tinymce/plugins/media/editor_plugin.js +1 -1
  14. data/vendor/assets/javascripts/tinymce/plugins/media/editor_plugin_src.js +22 -14
  15. data/vendor/assets/javascripts/tinymce/plugins/media/langs/en_dlg.js +1 -1
  16. data/vendor/assets/javascripts/tinymce/plugins/style/langs/en_dlg.js +1 -1
  17. data/vendor/assets/javascripts/tinymce/plugins/style/props.htm +845 -845
  18. data/vendor/assets/javascripts/tinymce/plugins/style/readme.txt +19 -19
  19. data/vendor/assets/javascripts/tinymce/plugins/tabfocus/editor_plugin_src.js +122 -122
  20. data/vendor/assets/javascripts/tinymce/plugins/table/editor_plugin.js +1 -1
  21. data/vendor/assets/javascripts/tinymce/plugins/table/editor_plugin_src.js +1449 -1446
  22. data/vendor/assets/javascripts/tinymce/plugins/table/js/table.js +4 -1
  23. data/vendor/assets/javascripts/tinymce/themes/advanced/js/color_picker.js +345 -345
  24. data/vendor/assets/javascripts/tinymce/themes/advanced/langs/en_dlg.js +1 -1
  25. data/vendor/assets/javascripts/tinymce/themes/advanced/skins/default/content.css +0 -1
  26. data/vendor/assets/javascripts/tinymce/themes/advanced/skins/highcontrast/content.css +0 -1
  27. data/vendor/assets/javascripts/tinymce/themes/advanced/skins/o2k7/content.css +0 -1
  28. data/vendor/assets/javascripts/tinymce/themes/advanced/source_editor.htm +1 -1
  29. data/vendor/assets/javascripts/tinymce/tiny_mce.js +1 -1
  30. data/vendor/assets/javascripts/tinymce/tiny_mce_jquery.js +1 -1
  31. data/vendor/assets/javascripts/tinymce/tiny_mce_jquery_src.js +394 -158
  32. data/vendor/assets/javascripts/tinymce/tiny_mce_src.js +394 -158
  33. metadata +5 -4
@@ -1,19 +1,19 @@
1
- Edit CSS Style plug-in notes
2
- ~~~~~~~~~~~~~~~~~~~~~~~~~~~~
3
- Unlike WYSIWYG editor functionality that operates only on the selected text,
4
- typically by inserting new HTML elements with the specified styles.
5
- This plug-in operates on the HTML blocks surrounding the selected text.
6
- No new HTML elements are created.
7
-
8
- This plug-in only operates on the surrounding blocks and not the nearest
9
- parent node. This means that if a block encapsulates a node,
10
- e.g <p><span>text</span></p>, then only the styles in the block are
11
- recognized, not those in the span.
12
-
13
- When selecting text that includes multiple blocks at the same level (peers),
14
- this plug-in accumulates the specified styles in all of the surrounding blocks
15
- and populates the dialogue checkboxes accordingly. There is no differentiation
16
- between styles set in all the blocks versus styles set in some of the blocks.
17
-
18
- When the [Update] or [Apply] buttons are pressed, the styles selected in the
19
- checkboxes are applied to all blocks that surround the selected text.
1
+ Edit CSS Style plug-in notes
2
+ ~~~~~~~~~~~~~~~~~~~~~~~~~~~~
3
+ Unlike WYSIWYG editor functionality that operates only on the selected text,
4
+ typically by inserting new HTML elements with the specified styles.
5
+ This plug-in operates on the HTML blocks surrounding the selected text.
6
+ No new HTML elements are created.
7
+
8
+ This plug-in only operates on the surrounding blocks and not the nearest
9
+ parent node. This means that if a block encapsulates a node,
10
+ e.g <p><span>text</span></p>, then only the styles in the block are
11
+ recognized, not those in the span.
12
+
13
+ When selecting text that includes multiple blocks at the same level (peers),
14
+ this plug-in accumulates the specified styles in all of the surrounding blocks
15
+ and populates the dialogue checkboxes accordingly. There is no differentiation
16
+ between styles set in all the blocks versus styles set in some of the blocks.
17
+
18
+ When the [Update] or [Apply] buttons are pressed, the styles selected in the
19
+ checkboxes are applied to all blocks that surround the selected text.
@@ -1,122 +1,122 @@
1
- /**
2
- * editor_plugin_src.js
3
- *
4
- * Copyright 2009, Moxiecode Systems AB
5
- * Released under LGPL License.
6
- *
7
- * License: http://tinymce.moxiecode.com/license
8
- * Contributing: http://tinymce.moxiecode.com/contributing
9
- */
10
-
11
- (function() {
12
- var DOM = tinymce.DOM, Event = tinymce.dom.Event, each = tinymce.each, explode = tinymce.explode;
13
-
14
- tinymce.create('tinymce.plugins.TabFocusPlugin', {
15
- init : function(ed, url) {
16
- function tabCancel(ed, e) {
17
- if (e.keyCode === 9)
18
- return Event.cancel(e);
19
- }
20
-
21
- function tabHandler(ed, e) {
22
- var x, i, f, el, v;
23
-
24
- function find(d) {
25
- el = DOM.select(':input:enabled,*[tabindex]:not(iframe)');
26
-
27
- function canSelectRecursive(e) {
28
- return e.nodeName==="BODY" || (e.type != 'hidden' &&
29
- !(e.style.display == "none") &&
30
- !(e.style.visibility == "hidden") && canSelectRecursive(e.parentNode));
31
- }
32
- function canSelectInOldIe(el) {
33
- return el.attributes["tabIndex"].specified || el.nodeName == "INPUT" || el.nodeName == "TEXTAREA";
34
- }
35
- function isOldIe() {
36
- return tinymce.isIE6 || tinymce.isIE7;
37
- }
38
- function canSelect(el) {
39
- return ((!isOldIe() || canSelectInOldIe(el))) && el.getAttribute("tabindex") != '-1' && canSelectRecursive(el);
40
- }
41
-
42
- each(el, function(e, i) {
43
- if (e.id == ed.id) {
44
- x = i;
45
- return false;
46
- }
47
- });
48
- if (d > 0) {
49
- for (i = x + 1; i < el.length; i++) {
50
- if (canSelect(el[i]))
51
- return el[i];
52
- }
53
- } else {
54
- for (i = x - 1; i >= 0; i--) {
55
- if (canSelect(el[i]))
56
- return el[i];
57
- }
58
- }
59
-
60
- return null;
61
- }
62
-
63
- if (e.keyCode === 9) {
64
- v = explode(ed.getParam('tab_focus', ed.getParam('tabfocus_elements', ':prev,:next')));
65
-
66
- if (v.length == 1) {
67
- v[1] = v[0];
68
- v[0] = ':prev';
69
- }
70
-
71
- // Find element to focus
72
- if (e.shiftKey) {
73
- if (v[0] == ':prev')
74
- el = find(-1);
75
- else
76
- el = DOM.get(v[0]);
77
- } else {
78
- if (v[1] == ':next')
79
- el = find(1);
80
- else
81
- el = DOM.get(v[1]);
82
- }
83
-
84
- if (el) {
85
- if (el.id && (ed = tinymce.get(el.id || el.name)))
86
- ed.focus();
87
- else
88
- window.setTimeout(function() {
89
- if (!tinymce.isWebKit)
90
- window.focus();
91
- el.focus();
92
- }, 10);
93
-
94
- return Event.cancel(e);
95
- }
96
- }
97
- }
98
-
99
- ed.onKeyUp.add(tabCancel);
100
-
101
- if (tinymce.isGecko) {
102
- ed.onKeyPress.add(tabHandler);
103
- ed.onKeyDown.add(tabCancel);
104
- } else
105
- ed.onKeyDown.add(tabHandler);
106
-
107
- },
108
-
109
- getInfo : function() {
110
- return {
111
- longname : 'Tabfocus',
112
- author : 'Moxiecode Systems AB',
113
- authorurl : 'http://tinymce.moxiecode.com',
114
- infourl : 'http://wiki.moxiecode.com/index.php/TinyMCE:Plugins/tabfocus',
115
- version : tinymce.majorVersion + "." + tinymce.minorVersion
116
- };
117
- }
118
- });
119
-
120
- // Register plugin
121
- tinymce.PluginManager.add('tabfocus', tinymce.plugins.TabFocusPlugin);
122
- })();
1
+ /**
2
+ * editor_plugin_src.js
3
+ *
4
+ * Copyright 2009, Moxiecode Systems AB
5
+ * Released under LGPL License.
6
+ *
7
+ * License: http://tinymce.moxiecode.com/license
8
+ * Contributing: http://tinymce.moxiecode.com/contributing
9
+ */
10
+
11
+ (function() {
12
+ var DOM = tinymce.DOM, Event = tinymce.dom.Event, each = tinymce.each, explode = tinymce.explode;
13
+
14
+ tinymce.create('tinymce.plugins.TabFocusPlugin', {
15
+ init : function(ed, url) {
16
+ function tabCancel(ed, e) {
17
+ if (e.keyCode === 9)
18
+ return Event.cancel(e);
19
+ }
20
+
21
+ function tabHandler(ed, e) {
22
+ var x, i, f, el, v;
23
+
24
+ function find(d) {
25
+ el = DOM.select(':input:enabled,*[tabindex]:not(iframe)');
26
+
27
+ function canSelectRecursive(e) {
28
+ return e.nodeName==="BODY" || (e.type != 'hidden' &&
29
+ !(e.style.display == "none") &&
30
+ !(e.style.visibility == "hidden") && canSelectRecursive(e.parentNode));
31
+ }
32
+ function canSelectInOldIe(el) {
33
+ return el.attributes["tabIndex"].specified || el.nodeName == "INPUT" || el.nodeName == "TEXTAREA";
34
+ }
35
+ function isOldIe() {
36
+ return tinymce.isIE6 || tinymce.isIE7;
37
+ }
38
+ function canSelect(el) {
39
+ return ((!isOldIe() || canSelectInOldIe(el))) && el.getAttribute("tabindex") != '-1' && canSelectRecursive(el);
40
+ }
41
+
42
+ each(el, function(e, i) {
43
+ if (e.id == ed.id) {
44
+ x = i;
45
+ return false;
46
+ }
47
+ });
48
+ if (d > 0) {
49
+ for (i = x + 1; i < el.length; i++) {
50
+ if (canSelect(el[i]))
51
+ return el[i];
52
+ }
53
+ } else {
54
+ for (i = x - 1; i >= 0; i--) {
55
+ if (canSelect(el[i]))
56
+ return el[i];
57
+ }
58
+ }
59
+
60
+ return null;
61
+ }
62
+
63
+ if (e.keyCode === 9) {
64
+ v = explode(ed.getParam('tab_focus', ed.getParam('tabfocus_elements', ':prev,:next')));
65
+
66
+ if (v.length == 1) {
67
+ v[1] = v[0];
68
+ v[0] = ':prev';
69
+ }
70
+
71
+ // Find element to focus
72
+ if (e.shiftKey) {
73
+ if (v[0] == ':prev')
74
+ el = find(-1);
75
+ else
76
+ el = DOM.get(v[0]);
77
+ } else {
78
+ if (v[1] == ':next')
79
+ el = find(1);
80
+ else
81
+ el = DOM.get(v[1]);
82
+ }
83
+
84
+ if (el) {
85
+ if (el.id && (ed = tinymce.get(el.id || el.name)))
86
+ ed.focus();
87
+ else
88
+ window.setTimeout(function() {
89
+ if (!tinymce.isWebKit)
90
+ window.focus();
91
+ el.focus();
92
+ }, 10);
93
+
94
+ return Event.cancel(e);
95
+ }
96
+ }
97
+ }
98
+
99
+ ed.onKeyUp.add(tabCancel);
100
+
101
+ if (tinymce.isGecko) {
102
+ ed.onKeyPress.add(tabHandler);
103
+ ed.onKeyDown.add(tabCancel);
104
+ } else
105
+ ed.onKeyDown.add(tabHandler);
106
+
107
+ },
108
+
109
+ getInfo : function() {
110
+ return {
111
+ longname : 'Tabfocus',
112
+ author : 'Moxiecode Systems AB',
113
+ authorurl : 'http://tinymce.moxiecode.com',
114
+ infourl : 'http://wiki.moxiecode.com/index.php/TinyMCE:Plugins/tabfocus',
115
+ version : tinymce.majorVersion + "." + tinymce.minorVersion
116
+ };
117
+ }
118
+ });
119
+
120
+ // Register plugin
121
+ tinymce.PluginManager.add('tabfocus', tinymce.plugins.TabFocusPlugin);
122
+ })();
@@ -1 +1 @@
1
- (function(d){var e=d.each;function c(g,h){var j=h.ownerDocument,f=j.createRange(),k;f.setStartBefore(h);f.setEnd(g.endContainer,g.endOffset);k=j.createElement("body");k.appendChild(f.cloneContents());return k.innerHTML.replace(/<(br|img|object|embed|input|textarea)[^>]*>/gi,"-").replace(/<[^>]+>/g,"").length==0}function a(g,f){return parseInt(g.getAttribute(f)||1)}function b(H,G,K){var g,L,D,o;t();o=G.getParent(K.getStart(),"th,td");if(o){L=F(o);D=I();o=z(L.x,L.y)}function A(N,M){N=N.cloneNode(M);N.removeAttribute("id");return N}function t(){var M=0;g=[];e(["thead","tbody","tfoot"],function(N){var O=G.select("> "+N+" tr",H);e(O,function(P,Q){Q+=M;e(G.select("> td, > th",P),function(W,R){var S,T,U,V;if(g[Q]){while(g[Q][R]){R++}}U=a(W,"rowspan");V=a(W,"colspan");for(T=Q;T<Q+U;T++){if(!g[T]){g[T]=[]}for(S=R;S<R+V;S++){g[T][S]={part:N,real:T==Q&&S==R,elm:W,rowspan:U,colspan:V}}}})});M+=O.length})}function z(M,O){var N;N=g[O];if(N){return N[M]}}function s(O,M,N){if(O){N=parseInt(N);if(N===1){O.removeAttribute(M,1)}else{O.setAttribute(M,N,1)}}}function j(M){return M&&(G.hasClass(M.elm,"mceSelected")||M==o)}function k(){var M=[];e(H.rows,function(N){e(N.cells,function(O){if(G.hasClass(O,"mceSelected")||O==o.elm){M.push(N);return false}})});return M}function r(){var M=G.createRng();M.setStartAfter(H);M.setEndAfter(H);K.setRng(M);G.remove(H)}function f(M){var N;d.walk(M,function(P){var O;if(P.nodeType==3){e(G.getParents(P.parentNode,null,M).reverse(),function(Q){Q=A(Q,false);if(!N){N=O=Q}else{if(O){O.appendChild(Q)}}O=Q});if(O){O.innerHTML=d.isIE?"&nbsp;":'<br data-mce-bogus="1" />'}return false}},"childNodes");M=A(M,false);s(M,"rowSpan",1);s(M,"colSpan",1);if(N){M.appendChild(N)}else{if(!d.isIE){M.innerHTML='<br data-mce-bogus="1" />'}}return M}function q(){var M=G.createRng();e(G.select("tr",H),function(N){if(N.cells.length==0){G.remove(N)}});if(G.select("tr",H).length==0){M.setStartAfter(H);M.setEndAfter(H);K.setRng(M);G.remove(H);return}e(G.select("thead,tbody,tfoot",H),function(N){if(N.rows.length==0){G.remove(N)}});t();row=g[Math.min(g.length-1,L.y)];if(row){K.select(row[Math.min(row.length-1,L.x)].elm,true);K.collapse(true)}}function u(S,Q,U,R){var P,N,M,O,T;P=g[Q][S].elm.parentNode;for(M=1;M<=U;M++){P=G.getNext(P,"tr");if(P){for(N=S;N>=0;N--){T=g[Q+M][N].elm;if(T.parentNode==P){for(O=1;O<=R;O++){G.insertAfter(f(T),T)}break}}if(N==-1){for(O=1;O<=R;O++){P.insertBefore(f(P.cells[0]),P.cells[0])}}}}}function C(){e(g,function(M,N){e(M,function(P,O){var S,R,T,Q;if(j(P)){P=P.elm;S=a(P,"colspan");R=a(P,"rowspan");if(S>1||R>1){s(P,"rowSpan",1);s(P,"colSpan",1);for(Q=0;Q<S-1;Q++){G.insertAfter(f(P),P)}u(O,N,R-1,S)}}})})}function p(V,S,Y){var P,O,X,W,U,R,T,M,V,N,Q;if(V){pos=F(V);P=pos.x;O=pos.y;X=P+(S-1);W=O+(Y-1)}else{L=D=null;e(g,function(Z,aa){e(Z,function(ac,ab){if(j(ac)){if(!L){L={x:ab,y:aa}}D={x:ab,y:aa}}})});P=L.x;O=L.y;X=D.x;W=D.y}T=z(P,O);M=z(X,W);if(T&&M&&T.part==M.part){C();t();T=z(P,O).elm;s(T,"colSpan",(X-P)+1);s(T,"rowSpan",(W-O)+1);for(R=O;R<=W;R++){for(U=P;U<=X;U++){if(!g[R]||!g[R][U]){continue}V=g[R][U].elm;if(V!=T){N=d.grep(V.childNodes);e(N,function(Z){T.appendChild(Z)});if(N.length){N=d.grep(T.childNodes);Q=0;e(N,function(Z){if(Z.nodeName=="BR"&&G.getAttrib(Z,"data-mce-bogus")&&Q++<N.length-1){T.removeChild(Z)}})}G.remove(V)}}}q()}}function l(Q){var M,S,P,R,T,U,N,V,O;e(g,function(W,X){e(W,function(Z,Y){if(j(Z)){Z=Z.elm;T=Z.parentNode;U=A(T,false);M=X;if(Q){return false}}});if(Q){return !M}});for(R=0;R<g[0].length;R++){if(!g[M][R]){continue}S=g[M][R].elm;if(S!=P){if(!Q){O=a(S,"rowspan");if(O>1){s(S,"rowSpan",O+1);continue}}else{if(M>0&&g[M-1][R]){V=g[M-1][R].elm;O=a(V,"rowSpan");if(O>1){s(V,"rowSpan",O+1);continue}}}N=f(S);s(N,"colSpan",S.colSpan);U.appendChild(N);P=S}}if(U.hasChildNodes()){if(!Q){G.insertAfter(U,T)}else{T.parentNode.insertBefore(U,T)}}}function h(N){var O,M;e(g,function(P,Q){e(P,function(S,R){if(j(S)){O=R;if(N){return false}}});if(N){return !O}});e(g,function(S,T){var P,Q,R;if(!S[O]){return}P=S[O].elm;if(P!=M){R=a(P,"colspan");Q=a(P,"rowspan");if(R==1){if(!N){G.insertAfter(f(P),P);u(O,T,Q-1,R)}else{P.parentNode.insertBefore(f(P),P);u(O,T,Q-1,R)}}else{s(P,"colSpan",P.colSpan+1)}M=P}})}function n(){var M=[];e(g,function(N,O){e(N,function(Q,P){if(j(Q)&&d.inArray(M,P)===-1){e(g,function(T){var R=T[P].elm,S;S=a(R,"colSpan");if(S>1){s(R,"colSpan",S-1)}else{G.remove(R)}});M.push(P)}})});q()}function m(){var N;function M(Q){var P,R,O;P=G.getNext(Q,"tr");e(Q.cells,function(S){var T=a(S,"rowSpan");if(T>1){s(S,"rowSpan",T-1);R=F(S);u(R.x,R.y,1,1)}});R=F(Q.cells[0]);e(g[R.y],function(S){var T;S=S.elm;if(S!=O){T=a(S,"rowSpan");if(T<=1){G.remove(S)}else{s(S,"rowSpan",T-1)}O=S}})}N=k();e(N.reverse(),function(O){M(O)});q()}function E(){var M=k();G.remove(M);q();return M}function J(){var M=k();e(M,function(O,N){M[N]=A(O,true)});return M}function B(O,N){var P=k(),M=P[N?0:P.length-1],Q=M.cells.length;e(g,function(S){var R;Q=0;e(S,function(U,T){if(U.real){Q+=U.colspan}if(U.elm.parentNode==M){R=1}});if(R){return false}});if(!N){O.reverse()}e(O,function(T){var S=T.cells.length,R;for(i=0;i<S;i++){R=T.cells[i];s(R,"colSpan",1);s(R,"rowSpan",1)}for(i=S;i<Q;i++){T.appendChild(f(T.cells[S-1]))}for(i=Q;i<S;i++){G.remove(T.cells[i])}if(N){M.parentNode.insertBefore(T,M)}else{G.insertAfter(T,M)}});G.removeClass(G.select("td.mceSelected,th.mceSelected"),"mceSelected")}function F(M){var N;e(g,function(O,P){e(O,function(R,Q){if(R.elm==M){N={x:Q,y:P};return false}});return !N});return N}function w(M){L=F(M)}function I(){var O,N,M;N=M=0;e(g,function(P,Q){e(P,function(S,R){var U,T;if(j(S)){S=g[Q][R];if(R>N){N=R}if(Q>M){M=Q}if(S.real){U=S.colspan-1;T=S.rowspan-1;if(U){if(R+U>N){N=R+U}}if(T){if(Q+T>M){M=Q+T}}}}})});return{x:N,y:M}}function v(S){var P,O,U,T,N,M,Q,R;D=F(S);if(L&&D){P=Math.min(L.x,D.x);O=Math.min(L.y,D.y);U=Math.max(L.x,D.x);T=Math.max(L.y,D.y);N=U;M=T;for(y=O;y<=M;y++){S=g[y][P];if(!S.real){if(P-(S.colspan-1)<P){P-=S.colspan-1}}}for(x=P;x<=N;x++){S=g[O][x];if(!S.real){if(O-(S.rowspan-1)<O){O-=S.rowspan-1}}}for(y=O;y<=T;y++){for(x=P;x<=U;x++){S=g[y][x];if(S.real){Q=S.colspan-1;R=S.rowspan-1;if(Q){if(x+Q>N){N=x+Q}}if(R){if(y+R>M){M=y+R}}}}}G.removeClass(G.select("td.mceSelected,th.mceSelected"),"mceSelected");for(y=O;y<=M;y++){for(x=P;x<=N;x++){if(g[y][x]){G.addClass(g[y][x].elm,"mceSelected")}}}}}d.extend(this,{deleteTable:r,split:C,merge:p,insertRow:l,insertCol:h,deleteCols:n,deleteRows:m,cutRows:E,copyRows:J,pasteRows:B,getPos:F,setStartCell:w,setEndCell:v})}d.create("tinymce.plugins.TablePlugin",{init:function(g,h){var f,m,j=true;function l(p){var o=g.selection,n=g.dom.getParent(p||o.getNode(),"table");if(n){return new b(n,g.dom,o)}}function k(){g.getBody().style.webkitUserSelect="";if(j){g.dom.removeClass(g.dom.select("td.mceSelected,th.mceSelected"),"mceSelected");j=false}}e([["table","table.desc","mceInsertTable",true],["delete_table","table.del","mceTableDelete"],["delete_col","table.delete_col_desc","mceTableDeleteCol"],["delete_row","table.delete_row_desc","mceTableDeleteRow"],["col_after","table.col_after_desc","mceTableInsertColAfter"],["col_before","table.col_before_desc","mceTableInsertColBefore"],["row_after","table.row_after_desc","mceTableInsertRowAfter"],["row_before","table.row_before_desc","mceTableInsertRowBefore"],["row_props","table.row_desc","mceTableRowProps",true],["cell_props","table.cell_desc","mceTableCellProps",true],["split_cells","table.split_cells_desc","mceTableSplitCells",true],["merge_cells","table.merge_cells_desc","mceTableMergeCells",true]],function(n){g.addButton(n[0],{title:n[1],cmd:n[2],ui:n[3]})});if(!d.isIE){g.onClick.add(function(n,o){o=o.target;if(o.nodeName==="TABLE"){n.selection.select(o);n.nodeChanged()}})}g.onPreProcess.add(function(o,p){var n,q,r,t=o.dom,s;n=t.select("table",p.node);q=n.length;while(q--){r=n[q];t.setAttrib(r,"data-mce-style","");if((s=t.getAttrib(r,"width"))){t.setStyle(r,"width",s);t.setAttrib(r,"width","")}if((s=t.getAttrib(r,"height"))){t.setStyle(r,"height",s);t.setAttrib(r,"height","")}}});g.onNodeChange.add(function(q,o,s){var r;s=q.selection.getStart();r=q.dom.getParent(s,"td,th,caption");o.setActive("table",s.nodeName==="TABLE"||!!r);if(r&&r.nodeName==="CAPTION"){r=0}o.setDisabled("delete_table",!r);o.setDisabled("delete_col",!r);o.setDisabled("delete_table",!r);o.setDisabled("delete_row",!r);o.setDisabled("col_after",!r);o.setDisabled("col_before",!r);o.setDisabled("row_after",!r);o.setDisabled("row_before",!r);o.setDisabled("row_props",!r);o.setDisabled("cell_props",!r);o.setDisabled("split_cells",!r);o.setDisabled("merge_cells",!r)});g.onInit.add(function(r){var p,t,q=r.dom,u;f=r.windowManager;r.onMouseDown.add(function(w,z){if(z.button!=2){k();t=q.getParent(z.target,"td,th");p=q.getParent(t,"table")}});q.bind(r.getDoc(),"mouseover",function(C){var A,z,B=C.target;if(t&&(u||B!=t)&&(B.nodeName=="TD"||B.nodeName=="TH")){z=q.getParent(B,"table");if(z==p){if(!u){u=l(z);u.setStartCell(t);r.getBody().style.webkitUserSelect="none"}u.setEndCell(B);j=true}A=r.selection.getSel();try{if(A.removeAllRanges){A.removeAllRanges()}else{A.empty()}}catch(w){}C.preventDefault()}});r.onMouseUp.add(function(F,G){var z,B=F.selection,H,I=B.getSel(),w,C,A,E;if(t){if(u){F.getBody().style.webkitUserSelect=""}function D(J,L){var K=new d.dom.TreeWalker(J,J);do{if(J.nodeType==3&&d.trim(J.nodeValue).length!=0){if(L){z.setStart(J,0)}else{z.setEnd(J,J.nodeValue.length)}return}if(J.nodeName=="BR"){if(L){z.setStartBefore(J)}else{z.setEndBefore(J)}return}}while(J=(L?K.next():K.prev()))}H=q.select("td.mceSelected,th.mceSelected");if(H.length>0){z=q.createRng();C=H[0];E=H[H.length-1];z.setStartBefore(C);z.setEndAfter(C);D(C,1);w=new d.dom.TreeWalker(C,q.getParent(H[0],"table"));do{if(C.nodeName=="TD"||C.nodeName=="TH"){if(!q.hasClass(C,"mceSelected")){break}A=C}}while(C=w.next());D(A);B.setRng(z)}F.nodeChanged();t=u=p=null}});r.onKeyUp.add(function(w,z){k()});r.onKeyDown.add(function(w,z){n(w)});r.onMouseDown.add(function(w,z){if(z.button!=2){n(w)}});function o(D,z,A,F){var B=3,G=D.dom.getParent(z.startContainer,"TABLE"),C,w,E;if(G){C=G.parentNode}w=z.startContainer.nodeType==B&&z.startOffset==0&&z.endOffset==0&&F&&(A.nodeName=="TR"||A==C);E=(A.nodeName=="TD"||A.nodeName=="TH")&&!F;return w||E}function n(A){if(!d.isWebKit){return}var z=A.selection.getRng();var C=A.selection.getNode();var B=A.dom.getParent(z.startContainer,"TD,TH");if(!o(A,z,C,B)){return}if(!B){B=C}var w=B.lastChild;while(w.lastChild){w=w.lastChild}z.setEnd(w,w.nodeValue.length);A.selection.setRng(z)}r.plugins.table.fixTableCellSelection=n;if(r&&r.plugins.contextmenu){r.plugins.contextmenu.onContextMenu.add(function(A,w,C){var D,B=r.selection,z=B.getNode()||r.getBody();if(r.dom.getParent(C,"td")||r.dom.getParent(C,"th")||r.dom.select("td.mceSelected,th.mceSelected").length){w.removeAll();if(z.nodeName=="A"&&!r.dom.getAttrib(z,"name")){w.add({title:"advanced.link_desc",icon:"link",cmd:r.plugins.advlink?"mceAdvLink":"mceLink",ui:true});w.add({title:"advanced.unlink_desc",icon:"unlink",cmd:"UnLink"});w.addSeparator()}if(z.nodeName=="IMG"&&z.className.indexOf("mceItem")==-1){w.add({title:"advanced.image_desc",icon:"image",cmd:r.plugins.advimage?"mceAdvImage":"mceImage",ui:true});w.addSeparator()}w.add({title:"table.desc",icon:"table",cmd:"mceInsertTable",value:{action:"insert"}});w.add({title:"table.props_desc",icon:"table_props",cmd:"mceInsertTable"});w.add({title:"table.del",icon:"delete_table",cmd:"mceTableDelete"});w.addSeparator();D=w.addMenu({title:"table.cell"});D.add({title:"table.cell_desc",icon:"cell_props",cmd:"mceTableCellProps"});D.add({title:"table.split_cells_desc",icon:"split_cells",cmd:"mceTableSplitCells"});D.add({title:"table.merge_cells_desc",icon:"merge_cells",cmd:"mceTableMergeCells"});D=w.addMenu({title:"table.row"});D.add({title:"table.row_desc",icon:"row_props",cmd:"mceTableRowProps"});D.add({title:"table.row_before_desc",icon:"row_before",cmd:"mceTableInsertRowBefore"});D.add({title:"table.row_after_desc",icon:"row_after",cmd:"mceTableInsertRowAfter"});D.add({title:"table.delete_row_desc",icon:"delete_row",cmd:"mceTableDeleteRow"});D.addSeparator();D.add({title:"table.cut_row_desc",icon:"cut",cmd:"mceTableCutRow"});D.add({title:"table.copy_row_desc",icon:"copy",cmd:"mceTableCopyRow"});D.add({title:"table.paste_row_before_desc",icon:"paste",cmd:"mceTablePasteRowBefore"}).setDisabled(!m);D.add({title:"table.paste_row_after_desc",icon:"paste",cmd:"mceTablePasteRowAfter"}).setDisabled(!m);D=w.addMenu({title:"table.col"});D.add({title:"table.col_before_desc",icon:"col_before",cmd:"mceTableInsertColBefore"});D.add({title:"table.col_after_desc",icon:"col_after",cmd:"mceTableInsertColAfter"});D.add({title:"table.delete_col_desc",icon:"delete_col",cmd:"mceTableDeleteCol"})}else{w.add({title:"table.desc",icon:"table",cmd:"mceInsertTable"})}})}if(d.isWebKit){function v(C,N){var L=d.VK;var Q=N.keyCode;function O(Y,U,S){var T=Y?"previousSibling":"nextSibling";var Z=C.dom.getParent(U,"tr");var X=Z[T];if(X){z(C,U,X,Y);d.dom.Event.cancel(S);return true}else{var aa=C.dom.getParent(Z,"table");var W=Z.parentNode;var R=W.nodeName.toLowerCase();if(R==="tbody"||R===(Y?"tfoot":"thead")){var V=w(Y,aa,W,"tbody");if(V!==null){return K(Y,V,U,S)}}return M(Y,Z,T,aa,S)}}function w(V,T,U,X){var S=C.dom.select(">"+X,T);var R=S.indexOf(U);if(V&&R===0||!V&&R===S.length-1){return B(V,T)}else{if(R===-1){var W=U.tagName.toLowerCase()==="thead"?0:S.length-1;return S[W]}else{return S[R+(V?-1:1)]}}}function B(U,T){var S=U?"thead":"tfoot";var R=C.dom.select(">"+S,T);return R.length!==0?R[0]:null}function K(V,T,S,U){var R=J(T,V);R&&z(C,S,R,V);d.dom.Event.cancel(U);return true}function M(Y,U,R,X,W){var S=X[R];if(S){F(S);return true}else{var V=C.dom.getParent(X,"td,th");if(V){return O(Y,V,W)}else{var T=J(U,!Y);F(T);return d.dom.Event.cancel(W)}}}function J(S,R){var T=S&&S[R?"lastChild":"firstChild"];return T&&T.nodeName==="BR"?C.dom.getParent(T,"td,th"):T}function F(R){C.selection.setCursorLocation(R,0)}function A(){return Q==L.UP||Q==L.DOWN}function D(R){var T=R.selection.getNode();var S=R.dom.getParent(T,"tr");return S!==null}function P(S){var R=0;var T=S;while(T.previousSibling){T=T.previousSibling;R=R+a(T,"colspan")}return R}function E(T,R){var U=0;var S=0;e(T.children,function(V,W){U=U+a(V,"colspan");S=W;if(U>R){return false}});return S}function z(T,W,Y,V){var X=P(T.dom.getParent(W,"td,th"));var S=E(Y,X);var R=Y.childNodes[S];var U=J(R,V);F(U||R)}function H(R){var T=C.selection.getNode();var U=C.dom.getParent(T,"td,th");var S=C.dom.getParent(R,"td,th");return U&&U!==S&&I(U,S)}function I(S,R){return C.dom.getParent(S,"TABLE")===C.dom.getParent(R,"TABLE")}if(A()&&D(C)){var G=C.selection.getNode();setTimeout(function(){if(H(G)){O(!N.shiftKey&&Q===L.UP,G,N)}},0)}}r.onKeyDown.add(v)}if(!d.isIE){function s(){var w;for(w=r.getBody().lastChild;w&&w.nodeType==3&&!w.nodeValue.length;w=w.previousSibling){}if(w&&w.nodeName=="TABLE"){r.dom.add(r.getBody(),"p",null,'<br data-mce-bogus="1" />')}}if(d.isGecko){r.onKeyDown.add(function(z,B){var w,A,C=z.dom;if(B.keyCode==37||B.keyCode==38){w=z.selection.getRng();A=C.getParent(w.startContainer,"table");if(A&&z.getBody().firstChild==A){if(c(w,A)){w=C.createRng();w.setStartBefore(A);w.setEndBefore(A);z.selection.setRng(w);B.preventDefault()}}}})}r.onKeyUp.add(s);r.onSetContent.add(s);r.onVisualAid.add(s);r.onPreProcess.add(function(w,A){var z=A.node.lastChild;if(z&&z.childNodes.length==1&&z.firstChild.nodeName=="BR"&&z.previousSibling&&z.previousSibling.nodeName=="TABLE"){w.dom.remove(z)}});if(d.isGecko){r.onKeyDown.add(function(z,B){if(B.keyCode===d.VK.ENTER&&B.shiftKey){var A=z.selection.getRng().startContainer;var C=q.getParent(A,"td,th");if(C){var w=z.getDoc().createTextNode("\uFEFF");q.insertAfter(w,A)}}})}s();r.startContent=r.getContent({format:"raw"})}});e({mceTableSplitCells:function(n){n.split()},mceTableMergeCells:function(o){var p,q,n;n=g.dom.getParent(g.selection.getNode(),"th,td");if(n){p=n.rowSpan;q=n.colSpan}if(!g.dom.select("td.mceSelected,th.mceSelected").length){f.open({url:h+"/merge_cells.htm",width:240+parseInt(g.getLang("table.merge_cells_delta_width",0)),height:110+parseInt(g.getLang("table.merge_cells_delta_height",0)),inline:1},{rows:p,cols:q,onaction:function(r){o.merge(n,r.cols,r.rows)},plugin_url:h})}else{o.merge()}},mceTableInsertRowBefore:function(n){n.insertRow(true)},mceTableInsertRowAfter:function(n){n.insertRow()},mceTableInsertColBefore:function(n){n.insertCol(true)},mceTableInsertColAfter:function(n){n.insertCol()},mceTableDeleteCol:function(n){n.deleteCols()},mceTableDeleteRow:function(n){n.deleteRows()},mceTableCutRow:function(n){m=n.cutRows()},mceTableCopyRow:function(n){m=n.copyRows()},mceTablePasteRowBefore:function(n){n.pasteRows(m,true)},mceTablePasteRowAfter:function(n){n.pasteRows(m)},mceTableDelete:function(n){n.deleteTable()}},function(o,n){g.addCommand(n,function(){var p=l();if(p){o(p);g.execCommand("mceRepaint");k()}})});e({mceInsertTable:function(n){f.open({url:h+"/table.htm",width:400+parseInt(g.getLang("table.table_delta_width",0)),height:320+parseInt(g.getLang("table.table_delta_height",0)),inline:1},{plugin_url:h,action:n?n.action:0})},mceTableRowProps:function(){f.open({url:h+"/row.htm",width:400+parseInt(g.getLang("table.rowprops_delta_width",0)),height:295+parseInt(g.getLang("table.rowprops_delta_height",0)),inline:1},{plugin_url:h})},mceTableCellProps:function(){f.open({url:h+"/cell.htm",width:400+parseInt(g.getLang("table.cellprops_delta_width",0)),height:295+parseInt(g.getLang("table.cellprops_delta_height",0)),inline:1},{plugin_url:h})}},function(o,n){g.addCommand(n,function(p,q){o(q)})})}});d.PluginManager.add("table",d.plugins.TablePlugin)})(tinymce);
1
+ (function(d){var e=d.each;function c(g,h){var j=h.ownerDocument,f=j.createRange(),k;f.setStartBefore(h);f.setEnd(g.endContainer,g.endOffset);k=j.createElement("body");k.appendChild(f.cloneContents());return k.innerHTML.replace(/<(br|img|object|embed|input|textarea)[^>]*>/gi,"-").replace(/<[^>]+>/g,"").length==0}function a(g,f){return parseInt(g.getAttribute(f)||1)}function b(H,G,K){var g,L,D,o;t();o=G.getParent(K.getStart(),"th,td");if(o){L=F(o);D=I();o=z(L.x,L.y)}function A(N,M){N=N.cloneNode(M);N.removeAttribute("id");return N}function t(){var M=0;g=[];e(["thead","tbody","tfoot"],function(N){var O=G.select("> "+N+" tr",H);e(O,function(P,Q){Q+=M;e(G.select("> td, > th",P),function(W,R){var S,T,U,V;if(g[Q]){while(g[Q][R]){R++}}U=a(W,"rowspan");V=a(W,"colspan");for(T=Q;T<Q+U;T++){if(!g[T]){g[T]=[]}for(S=R;S<R+V;S++){g[T][S]={part:N,real:T==Q&&S==R,elm:W,rowspan:U,colspan:V}}}})});M+=O.length})}function z(M,O){var N;N=g[O];if(N){return N[M]}}function s(O,M,N){if(O){N=parseInt(N);if(N===1){O.removeAttribute(M,1)}else{O.setAttribute(M,N,1)}}}function j(M){return M&&(G.hasClass(M.elm,"mceSelected")||M==o)}function k(){var M=[];e(H.rows,function(N){e(N.cells,function(O){if(G.hasClass(O,"mceSelected")||O==o.elm){M.push(N);return false}})});return M}function r(){var M=G.createRng();M.setStartAfter(H);M.setEndAfter(H);K.setRng(M);G.remove(H)}function f(M){var N;d.walk(M,function(P){var O;if(P.nodeType==3){e(G.getParents(P.parentNode,null,M).reverse(),function(Q){Q=A(Q,false);if(!N){N=O=Q}else{if(O){O.appendChild(Q)}}O=Q});if(O){O.innerHTML=d.isIE?"&nbsp;":'<br data-mce-bogus="1" />'}return false}},"childNodes");M=A(M,false);s(M,"rowSpan",1);s(M,"colSpan",1);if(N){M.appendChild(N)}else{if(!d.isIE){M.innerHTML='<br data-mce-bogus="1" />'}}return M}function q(){var M=G.createRng();e(G.select("tr",H),function(N){if(N.cells.length==0){G.remove(N)}});if(G.select("tr",H).length==0){M.setStartAfter(H);M.setEndAfter(H);K.setRng(M);G.remove(H);return}e(G.select("thead,tbody,tfoot",H),function(N){if(N.rows.length==0){G.remove(N)}});t();row=g[Math.min(g.length-1,L.y)];if(row){K.select(row[Math.min(row.length-1,L.x)].elm,true);K.collapse(true)}}function u(S,Q,U,R){var P,N,M,O,T;P=g[Q][S].elm.parentNode;for(M=1;M<=U;M++){P=G.getNext(P,"tr");if(P){for(N=S;N>=0;N--){T=g[Q+M][N].elm;if(T.parentNode==P){for(O=1;O<=R;O++){G.insertAfter(f(T),T)}break}}if(N==-1){for(O=1;O<=R;O++){P.insertBefore(f(P.cells[0]),P.cells[0])}}}}}function C(){e(g,function(M,N){e(M,function(P,O){var S,R,T,Q;if(j(P)){P=P.elm;S=a(P,"colspan");R=a(P,"rowspan");if(S>1||R>1){s(P,"rowSpan",1);s(P,"colSpan",1);for(Q=0;Q<S-1;Q++){G.insertAfter(f(P),P)}u(O,N,R-1,S)}}})})}function p(V,S,Y){var P,O,X,W,U,R,T,M,V,N,Q;if(V){pos=F(V);P=pos.x;O=pos.y;X=P+(S-1);W=O+(Y-1)}else{L=D=null;e(g,function(Z,aa){e(Z,function(ac,ab){if(j(ac)){if(!L){L={x:ab,y:aa}}D={x:ab,y:aa}}})});P=L.x;O=L.y;X=D.x;W=D.y}T=z(P,O);M=z(X,W);if(T&&M&&T.part==M.part){C();t();T=z(P,O).elm;s(T,"colSpan",(X-P)+1);s(T,"rowSpan",(W-O)+1);for(R=O;R<=W;R++){for(U=P;U<=X;U++){if(!g[R]||!g[R][U]){continue}V=g[R][U].elm;if(V!=T){N=d.grep(V.childNodes);e(N,function(Z){T.appendChild(Z)});if(N.length){N=d.grep(T.childNodes);Q=0;e(N,function(Z){if(Z.nodeName=="BR"&&G.getAttrib(Z,"data-mce-bogus")&&Q++<N.length-1){T.removeChild(Z)}})}G.remove(V)}}}q()}}function l(Q){var M,S,P,R,T,U,N,V,O;e(g,function(W,X){e(W,function(Z,Y){if(j(Z)){Z=Z.elm;T=Z.parentNode;U=A(T,false);M=X;if(Q){return false}}});if(Q){return !M}});for(R=0;R<g[0].length;R++){if(!g[M][R]){continue}S=g[M][R].elm;if(S!=P){if(!Q){O=a(S,"rowspan");if(O>1){s(S,"rowSpan",O+1);continue}}else{if(M>0&&g[M-1][R]){V=g[M-1][R].elm;O=a(V,"rowSpan");if(O>1){s(V,"rowSpan",O+1);continue}}}N=f(S);s(N,"colSpan",S.colSpan);U.appendChild(N);P=S}}if(U.hasChildNodes()){if(!Q){G.insertAfter(U,T)}else{T.parentNode.insertBefore(U,T)}}}function h(N){var O,M;e(g,function(P,Q){e(P,function(S,R){if(j(S)){O=R;if(N){return false}}});if(N){return !O}});e(g,function(S,T){var P,Q,R;if(!S[O]){return}P=S[O].elm;if(P!=M){R=a(P,"colspan");Q=a(P,"rowspan");if(R==1){if(!N){G.insertAfter(f(P),P);u(O,T,Q-1,R)}else{P.parentNode.insertBefore(f(P),P);u(O,T,Q-1,R)}}else{s(P,"colSpan",P.colSpan+1)}M=P}})}function n(){var M=[];e(g,function(N,O){e(N,function(Q,P){if(j(Q)&&d.inArray(M,P)===-1){e(g,function(T){var R=T[P].elm,S;S=a(R,"colSpan");if(S>1){s(R,"colSpan",S-1)}else{G.remove(R)}});M.push(P)}})});q()}function m(){var N;function M(Q){var P,R,O;P=G.getNext(Q,"tr");e(Q.cells,function(S){var T=a(S,"rowSpan");if(T>1){s(S,"rowSpan",T-1);R=F(S);u(R.x,R.y,1,1)}});R=F(Q.cells[0]);e(g[R.y],function(S){var T;S=S.elm;if(S!=O){T=a(S,"rowSpan");if(T<=1){G.remove(S)}else{s(S,"rowSpan",T-1)}O=S}})}N=k();e(N.reverse(),function(O){M(O)});q()}function E(){var M=k();G.remove(M);q();return M}function J(){var M=k();e(M,function(O,N){M[N]=A(O,true)});return M}function B(O,N){var P=k(),M=P[N?0:P.length-1],Q=M.cells.length;e(g,function(S){var R;Q=0;e(S,function(U,T){if(U.real){Q+=U.colspan}if(U.elm.parentNode==M){R=1}});if(R){return false}});if(!N){O.reverse()}e(O,function(T){var S=T.cells.length,R;for(i=0;i<S;i++){R=T.cells[i];s(R,"colSpan",1);s(R,"rowSpan",1)}for(i=S;i<Q;i++){T.appendChild(f(T.cells[S-1]))}for(i=Q;i<S;i++){G.remove(T.cells[i])}if(N){M.parentNode.insertBefore(T,M)}else{G.insertAfter(T,M)}});G.removeClass(G.select("td.mceSelected,th.mceSelected"),"mceSelected")}function F(M){var N;e(g,function(O,P){e(O,function(R,Q){if(R.elm==M){N={x:Q,y:P};return false}});return !N});return N}function w(M){L=F(M)}function I(){var O,N,M;N=M=0;e(g,function(P,Q){e(P,function(S,R){var U,T;if(j(S)){S=g[Q][R];if(R>N){N=R}if(Q>M){M=Q}if(S.real){U=S.colspan-1;T=S.rowspan-1;if(U){if(R+U>N){N=R+U}}if(T){if(Q+T>M){M=Q+T}}}}})});return{x:N,y:M}}function v(S){var P,O,U,T,N,M,Q,R;D=F(S);if(L&&D){P=Math.min(L.x,D.x);O=Math.min(L.y,D.y);U=Math.max(L.x,D.x);T=Math.max(L.y,D.y);N=U;M=T;for(y=O;y<=M;y++){S=g[y][P];if(!S.real){if(P-(S.colspan-1)<P){P-=S.colspan-1}}}for(x=P;x<=N;x++){S=g[O][x];if(!S.real){if(O-(S.rowspan-1)<O){O-=S.rowspan-1}}}for(y=O;y<=T;y++){for(x=P;x<=U;x++){S=g[y][x];if(S.real){Q=S.colspan-1;R=S.rowspan-1;if(Q){if(x+Q>N){N=x+Q}}if(R){if(y+R>M){M=y+R}}}}}G.removeClass(G.select("td.mceSelected,th.mceSelected"),"mceSelected");for(y=O;y<=M;y++){for(x=P;x<=N;x++){if(g[y][x]){G.addClass(g[y][x].elm,"mceSelected")}}}}}d.extend(this,{deleteTable:r,split:C,merge:p,insertRow:l,insertCol:h,deleteCols:n,deleteRows:m,cutRows:E,copyRows:J,pasteRows:B,getPos:F,setStartCell:w,setEndCell:v})}d.create("tinymce.plugins.TablePlugin",{init:function(g,h){var f,m,j=true;function l(p){var o=g.selection,n=g.dom.getParent(p||o.getNode(),"table");if(n){return new b(n,g.dom,o)}}function k(){g.getBody().style.webkitUserSelect="";if(j){g.dom.removeClass(g.dom.select("td.mceSelected,th.mceSelected"),"mceSelected");j=false}}e([["table","table.desc","mceInsertTable",true],["delete_table","table.del","mceTableDelete"],["delete_col","table.delete_col_desc","mceTableDeleteCol"],["delete_row","table.delete_row_desc","mceTableDeleteRow"],["col_after","table.col_after_desc","mceTableInsertColAfter"],["col_before","table.col_before_desc","mceTableInsertColBefore"],["row_after","table.row_after_desc","mceTableInsertRowAfter"],["row_before","table.row_before_desc","mceTableInsertRowBefore"],["row_props","table.row_desc","mceTableRowProps",true],["cell_props","table.cell_desc","mceTableCellProps",true],["split_cells","table.split_cells_desc","mceTableSplitCells",true],["merge_cells","table.merge_cells_desc","mceTableMergeCells",true]],function(n){g.addButton(n[0],{title:n[1],cmd:n[2],ui:n[3]})});if(!d.isIE){g.onClick.add(function(n,o){o=o.target;if(o.nodeName==="TABLE"){n.selection.select(o);n.nodeChanged()}})}g.onPreProcess.add(function(o,p){var n,q,r,t=o.dom,s;n=t.select("table",p.node);q=n.length;while(q--){r=n[q];t.setAttrib(r,"data-mce-style","");if((s=t.getAttrib(r,"width"))){t.setStyle(r,"width",s);t.setAttrib(r,"width","")}if((s=t.getAttrib(r,"height"))){t.setStyle(r,"height",s);t.setAttrib(r,"height","")}}});g.onNodeChange.add(function(q,o,s){var r;s=q.selection.getStart();r=q.dom.getParent(s,"td,th,caption");o.setActive("table",s.nodeName==="TABLE"||!!r);if(r&&r.nodeName==="CAPTION"){r=0}o.setDisabled("delete_table",!r);o.setDisabled("delete_col",!r);o.setDisabled("delete_table",!r);o.setDisabled("delete_row",!r);o.setDisabled("col_after",!r);o.setDisabled("col_before",!r);o.setDisabled("row_after",!r);o.setDisabled("row_before",!r);o.setDisabled("row_props",!r);o.setDisabled("cell_props",!r);o.setDisabled("split_cells",!r);o.setDisabled("merge_cells",!r)});g.onInit.add(function(r){var p,t,q=r.dom,u;f=r.windowManager;r.onMouseDown.add(function(w,z){if(z.button!=2){k();t=q.getParent(z.target,"td,th");p=q.getParent(t,"table")}});q.bind(r.getDoc(),"mouseover",function(C){var A,z,B=C.target;if(t&&(u||B!=t)&&(B.nodeName=="TD"||B.nodeName=="TH")){z=q.getParent(B,"table");if(z==p){if(!u){u=l(z);u.setStartCell(t);r.getBody().style.webkitUserSelect="none"}u.setEndCell(B);j=true}A=r.selection.getSel();try{if(A.removeAllRanges){A.removeAllRanges()}else{A.empty()}}catch(w){}C.preventDefault()}});r.onMouseUp.add(function(F,G){var z,B=F.selection,H,I=B.getSel(),w,C,A,E;if(t){if(u){F.getBody().style.webkitUserSelect=""}function D(J,L){var K=new d.dom.TreeWalker(J,J);do{if(J.nodeType==3&&d.trim(J.nodeValue).length!=0){if(L){z.setStart(J,0)}else{z.setEnd(J,J.nodeValue.length)}return}if(J.nodeName=="BR"){if(L){z.setStartBefore(J)}else{z.setEndBefore(J)}return}}while(J=(L?K.next():K.prev()))}H=q.select("td.mceSelected,th.mceSelected");if(H.length>0){z=q.createRng();C=H[0];E=H[H.length-1];z.setStartBefore(C);z.setEndAfter(C);D(C,1);w=new d.dom.TreeWalker(C,q.getParent(H[0],"table"));do{if(C.nodeName=="TD"||C.nodeName=="TH"){if(!q.hasClass(C,"mceSelected")){break}A=C}}while(C=w.next());D(A);B.setRng(z)}F.nodeChanged();t=u=p=null}});r.onKeyUp.add(function(w,z){k()});r.onKeyDown.add(function(w,z){n(w)});r.onMouseDown.add(function(w,z){if(z.button!=2){n(w)}});function o(D,z,A,F){var B=3,G=D.dom.getParent(z.startContainer,"TABLE"),C,w,E;if(G){C=G.parentNode}w=z.startContainer.nodeType==B&&z.startOffset==0&&z.endOffset==0&&F&&(A.nodeName=="TR"||A==C);E=(A.nodeName=="TD"||A.nodeName=="TH")&&!F;return w||E}function n(A){if(!d.isWebKit){return}var z=A.selection.getRng();var C=A.selection.getNode();var B=A.dom.getParent(z.startContainer,"TD,TH");if(!o(A,z,C,B)){return}if(!B){B=C}var w=B.lastChild;while(w.lastChild){w=w.lastChild}z.setEnd(w,w.nodeValue.length);A.selection.setRng(z)}r.plugins.table.fixTableCellSelection=n;if(r&&r.plugins.contextmenu){r.plugins.contextmenu.onContextMenu.add(function(A,w,C){var D,B=r.selection,z=B.getNode()||r.getBody();if(r.dom.getParent(C,"td")||r.dom.getParent(C,"th")||r.dom.select("td.mceSelected,th.mceSelected").length){w.removeAll();if(z.nodeName=="A"&&!r.dom.getAttrib(z,"name")){w.add({title:"advanced.link_desc",icon:"link",cmd:r.plugins.advlink?"mceAdvLink":"mceLink",ui:true});w.add({title:"advanced.unlink_desc",icon:"unlink",cmd:"UnLink"});w.addSeparator()}if(z.nodeName=="IMG"&&z.className.indexOf("mceItem")==-1){w.add({title:"advanced.image_desc",icon:"image",cmd:r.plugins.advimage?"mceAdvImage":"mceImage",ui:true});w.addSeparator()}w.add({title:"table.desc",icon:"table",cmd:"mceInsertTable",value:{action:"insert"}});w.add({title:"table.props_desc",icon:"table_props",cmd:"mceInsertTable"});w.add({title:"table.del",icon:"delete_table",cmd:"mceTableDelete"});w.addSeparator();D=w.addMenu({title:"table.cell"});D.add({title:"table.cell_desc",icon:"cell_props",cmd:"mceTableCellProps"});D.add({title:"table.split_cells_desc",icon:"split_cells",cmd:"mceTableSplitCells"});D.add({title:"table.merge_cells_desc",icon:"merge_cells",cmd:"mceTableMergeCells"});D=w.addMenu({title:"table.row"});D.add({title:"table.row_desc",icon:"row_props",cmd:"mceTableRowProps"});D.add({title:"table.row_before_desc",icon:"row_before",cmd:"mceTableInsertRowBefore"});D.add({title:"table.row_after_desc",icon:"row_after",cmd:"mceTableInsertRowAfter"});D.add({title:"table.delete_row_desc",icon:"delete_row",cmd:"mceTableDeleteRow"});D.addSeparator();D.add({title:"table.cut_row_desc",icon:"cut",cmd:"mceTableCutRow"});D.add({title:"table.copy_row_desc",icon:"copy",cmd:"mceTableCopyRow"});D.add({title:"table.paste_row_before_desc",icon:"paste",cmd:"mceTablePasteRowBefore"}).setDisabled(!m);D.add({title:"table.paste_row_after_desc",icon:"paste",cmd:"mceTablePasteRowAfter"}).setDisabled(!m);D=w.addMenu({title:"table.col"});D.add({title:"table.col_before_desc",icon:"col_before",cmd:"mceTableInsertColBefore"});D.add({title:"table.col_after_desc",icon:"col_after",cmd:"mceTableInsertColAfter"});D.add({title:"table.delete_col_desc",icon:"delete_col",cmd:"mceTableDeleteCol"})}else{w.add({title:"table.desc",icon:"table",cmd:"mceInsertTable"})}})}if(d.isWebKit){function v(C,N){var L=d.VK;var Q=N.keyCode;function O(Y,U,S){var T=Y?"previousSibling":"nextSibling";var Z=C.dom.getParent(U,"tr");var X=Z[T];if(X){z(C,U,X,Y);d.dom.Event.cancel(S);return true}else{var aa=C.dom.getParent(Z,"table");var W=Z.parentNode;var R=W.nodeName.toLowerCase();if(R==="tbody"||R===(Y?"tfoot":"thead")){var V=w(Y,aa,W,"tbody");if(V!==null){return K(Y,V,U,S)}}return M(Y,Z,T,aa,S)}}function w(V,T,U,X){var S=C.dom.select(">"+X,T);var R=S.indexOf(U);if(V&&R===0||!V&&R===S.length-1){return B(V,T)}else{if(R===-1){var W=U.tagName.toLowerCase()==="thead"?0:S.length-1;return S[W]}else{return S[R+(V?-1:1)]}}}function B(U,T){var S=U?"thead":"tfoot";var R=C.dom.select(">"+S,T);return R.length!==0?R[0]:null}function K(V,T,S,U){var R=J(T,V);R&&z(C,S,R,V);d.dom.Event.cancel(U);return true}function M(Y,U,R,X,W){var S=X[R];if(S){F(S);return true}else{var V=C.dom.getParent(X,"td,th");if(V){return O(Y,V,W)}else{var T=J(U,!Y);F(T);return d.dom.Event.cancel(W)}}}function J(S,R){var T=S&&S[R?"lastChild":"firstChild"];return T&&T.nodeName==="BR"?C.dom.getParent(T,"td,th"):T}function F(R){C.selection.setCursorLocation(R,0)}function A(){return Q==L.UP||Q==L.DOWN}function D(R){var T=R.selection.getNode();var S=R.dom.getParent(T,"tr");return S!==null}function P(S){var R=0;var T=S;while(T.previousSibling){T=T.previousSibling;R=R+a(T,"colspan")}return R}function E(T,R){var U=0;var S=0;e(T.children,function(V,W){U=U+a(V,"colspan");S=W;if(U>R){return false}});return S}function z(T,W,Y,V){var X=P(T.dom.getParent(W,"td,th"));var S=E(Y,X);var R=Y.childNodes[S];var U=J(R,V);F(U||R)}function H(R){var T=C.selection.getNode();var U=C.dom.getParent(T,"td,th");var S=C.dom.getParent(R,"td,th");return U&&U!==S&&I(U,S)}function I(S,R){return C.dom.getParent(S,"TABLE")===C.dom.getParent(R,"TABLE")}if(A()&&D(C)){var G=C.selection.getNode();setTimeout(function(){if(H(G)){O(!N.shiftKey&&Q===L.UP,G,N)}},0)}}r.onKeyDown.add(v)}function s(){var w;for(w=r.getBody().lastChild;w&&w.nodeType==3&&!w.nodeValue.length;w=w.previousSibling){}if(w&&w.nodeName=="TABLE"){if(r.settings.forced_root_block){r.dom.add(r.getBody(),r.settings.forced_root_block,null,d.isIE?"&nbsp;":'<br data-mce-bogus="1" />')}else{r.dom.add(r.getBody(),"br",{"data-mce-bogus":"1"})}}}if(d.isGecko){r.onKeyDown.add(function(z,B){var w,A,C=z.dom;if(B.keyCode==37||B.keyCode==38){w=z.selection.getRng();A=C.getParent(w.startContainer,"table");if(A&&z.getBody().firstChild==A){if(c(w,A)){w=C.createRng();w.setStartBefore(A);w.setEndBefore(A);z.selection.setRng(w);B.preventDefault()}}}})}r.onKeyUp.add(s);r.onSetContent.add(s);r.onVisualAid.add(s);r.onPreProcess.add(function(w,A){var z=A.node.lastChild;if(z&&(z.nodeName=="BR"||(z.childNodes.length==1&&(z.firstChild.nodeName=="BR"||z.firstChild.nodeValue=="\u00a0")))&&z.previousSibling&&z.previousSibling.nodeName=="TABLE"){w.dom.remove(z)}});if(d.isGecko){r.onKeyDown.add(function(z,B){if(B.keyCode===d.VK.ENTER&&B.shiftKey){var A=z.selection.getRng().startContainer;var C=q.getParent(A,"td,th");if(C){var w=z.getDoc().createTextNode("\uFEFF");q.insertAfter(w,A)}}})}s();r.startContent=r.getContent({format:"raw"})});e({mceTableSplitCells:function(n){n.split()},mceTableMergeCells:function(o){var p,q,n;n=g.dom.getParent(g.selection.getNode(),"th,td");if(n){p=n.rowSpan;q=n.colSpan}if(!g.dom.select("td.mceSelected,th.mceSelected").length){f.open({url:h+"/merge_cells.htm",width:240+parseInt(g.getLang("table.merge_cells_delta_width",0)),height:110+parseInt(g.getLang("table.merge_cells_delta_height",0)),inline:1},{rows:p,cols:q,onaction:function(r){o.merge(n,r.cols,r.rows)},plugin_url:h})}else{o.merge()}},mceTableInsertRowBefore:function(n){n.insertRow(true)},mceTableInsertRowAfter:function(n){n.insertRow()},mceTableInsertColBefore:function(n){n.insertCol(true)},mceTableInsertColAfter:function(n){n.insertCol()},mceTableDeleteCol:function(n){n.deleteCols()},mceTableDeleteRow:function(n){n.deleteRows()},mceTableCutRow:function(n){m=n.cutRows()},mceTableCopyRow:function(n){m=n.copyRows()},mceTablePasteRowBefore:function(n){n.pasteRows(m,true)},mceTablePasteRowAfter:function(n){n.pasteRows(m)},mceTableDelete:function(n){n.deleteTable()}},function(o,n){g.addCommand(n,function(){var p=l();if(p){o(p);g.execCommand("mceRepaint");k()}})});e({mceInsertTable:function(n){f.open({url:h+"/table.htm",width:400+parseInt(g.getLang("table.table_delta_width",0)),height:320+parseInt(g.getLang("table.table_delta_height",0)),inline:1},{plugin_url:h,action:n?n.action:0})},mceTableRowProps:function(){f.open({url:h+"/row.htm",width:400+parseInt(g.getLang("table.rowprops_delta_width",0)),height:295+parseInt(g.getLang("table.rowprops_delta_height",0)),inline:1},{plugin_url:h})},mceTableCellProps:function(){f.open({url:h+"/cell.htm",width:400+parseInt(g.getLang("table.cellprops_delta_width",0)),height:295+parseInt(g.getLang("table.cellprops_delta_height",0)),inline:1},{plugin_url:h})}},function(o,n){g.addCommand(n,function(p,q){o(q)})})}});d.PluginManager.add("table",d.plugins.TablePlugin)})(tinymce);
@@ -1,1446 +1,1449 @@
1
- /**
2
- * editor_plugin_src.js
3
- *
4
- * Copyright 2009, Moxiecode Systems AB
5
- * Released under LGPL License.
6
- *
7
- * License: http://tinymce.moxiecode.com/license
8
- * Contributing: http://tinymce.moxiecode.com/contributing
9
- */
10
-
11
- (function(tinymce) {
12
- var each = tinymce.each;
13
-
14
- // Checks if the selection/caret is at the start of the specified block element
15
- function isAtStart(rng, par) {
16
- var doc = par.ownerDocument, rng2 = doc.createRange(), elm;
17
-
18
- rng2.setStartBefore(par);
19
- rng2.setEnd(rng.endContainer, rng.endOffset);
20
-
21
- elm = doc.createElement('body');
22
- elm.appendChild(rng2.cloneContents());
23
-
24
- // Check for text characters of other elements that should be treated as content
25
- return elm.innerHTML.replace(/<(br|img|object|embed|input|textarea)[^>]*>/gi, '-').replace(/<[^>]+>/g, '').length == 0;
26
- };
27
-
28
- function getSpanVal(td, name) {
29
- return parseInt(td.getAttribute(name) || 1);
30
- }
31
-
32
- /**
33
- * Table Grid class.
34
- */
35
- function TableGrid(table, dom, selection) {
36
- var grid, startPos, endPos, selectedCell;
37
-
38
- buildGrid();
39
- selectedCell = dom.getParent(selection.getStart(), 'th,td');
40
- if (selectedCell) {
41
- startPos = getPos(selectedCell);
42
- endPos = findEndPos();
43
- selectedCell = getCell(startPos.x, startPos.y);
44
- }
45
-
46
- function cloneNode(node, children) {
47
- node = node.cloneNode(children);
48
- node.removeAttribute('id');
49
-
50
- return node;
51
- }
52
-
53
- function buildGrid() {
54
- var startY = 0;
55
-
56
- grid = [];
57
-
58
- each(['thead', 'tbody', 'tfoot'], function(part) {
59
- var rows = dom.select('> ' + part + ' tr', table);
60
-
61
- each(rows, function(tr, y) {
62
- y += startY;
63
-
64
- each(dom.select('> td, > th', tr), function(td, x) {
65
- var x2, y2, rowspan, colspan;
66
-
67
- // Skip over existing cells produced by rowspan
68
- if (grid[y]) {
69
- while (grid[y][x])
70
- x++;
71
- }
72
-
73
- // Get col/rowspan from cell
74
- rowspan = getSpanVal(td, 'rowspan');
75
- colspan = getSpanVal(td, 'colspan');
76
-
77
- // Fill out rowspan/colspan right and down
78
- for (y2 = y; y2 < y + rowspan; y2++) {
79
- if (!grid[y2])
80
- grid[y2] = [];
81
-
82
- for (x2 = x; x2 < x + colspan; x2++) {
83
- grid[y2][x2] = {
84
- part : part,
85
- real : y2 == y && x2 == x,
86
- elm : td,
87
- rowspan : rowspan,
88
- colspan : colspan
89
- };
90
- }
91
- }
92
- });
93
- });
94
-
95
- startY += rows.length;
96
- });
97
- };
98
-
99
- function getCell(x, y) {
100
- var row;
101
-
102
- row = grid[y];
103
- if (row)
104
- return row[x];
105
- };
106
-
107
- function setSpanVal(td, name, val) {
108
- if (td) {
109
- val = parseInt(val);
110
-
111
- if (val === 1)
112
- td.removeAttribute(name, 1);
113
- else
114
- td.setAttribute(name, val, 1);
115
- }
116
- }
117
-
118
- function isCellSelected(cell) {
119
- return cell && (dom.hasClass(cell.elm, 'mceSelected') || cell == selectedCell);
120
- };
121
-
122
- function getSelectedRows() {
123
- var rows = [];
124
-
125
- each(table.rows, function(row) {
126
- each(row.cells, function(cell) {
127
- if (dom.hasClass(cell, 'mceSelected') || cell == selectedCell.elm) {
128
- rows.push(row);
129
- return false;
130
- }
131
- });
132
- });
133
-
134
- return rows;
135
- };
136
-
137
- function deleteTable() {
138
- var rng = dom.createRng();
139
-
140
- rng.setStartAfter(table);
141
- rng.setEndAfter(table);
142
-
143
- selection.setRng(rng);
144
-
145
- dom.remove(table);
146
- };
147
-
148
- function cloneCell(cell) {
149
- var formatNode;
150
-
151
- // Clone formats
152
- tinymce.walk(cell, function(node) {
153
- var curNode;
154
-
155
- if (node.nodeType == 3) {
156
- each(dom.getParents(node.parentNode, null, cell).reverse(), function(node) {
157
- node = cloneNode(node, false);
158
-
159
- if (!formatNode)
160
- formatNode = curNode = node;
161
- else if (curNode)
162
- curNode.appendChild(node);
163
-
164
- curNode = node;
165
- });
166
-
167
- // Add something to the inner node
168
- if (curNode)
169
- curNode.innerHTML = tinymce.isIE ? '&nbsp;' : '<br data-mce-bogus="1" />';
170
-
171
- return false;
172
- }
173
- }, 'childNodes');
174
-
175
- cell = cloneNode(cell, false);
176
- setSpanVal(cell, 'rowSpan', 1);
177
- setSpanVal(cell, 'colSpan', 1);
178
-
179
- if (formatNode) {
180
- cell.appendChild(formatNode);
181
- } else {
182
- if (!tinymce.isIE)
183
- cell.innerHTML = '<br data-mce-bogus="1" />';
184
- }
185
-
186
- return cell;
187
- };
188
-
189
- function cleanup() {
190
- var rng = dom.createRng();
191
-
192
- // Empty rows
193
- each(dom.select('tr', table), function(tr) {
194
- if (tr.cells.length == 0)
195
- dom.remove(tr);
196
- });
197
-
198
- // Empty table
199
- if (dom.select('tr', table).length == 0) {
200
- rng.setStartAfter(table);
201
- rng.setEndAfter(table);
202
- selection.setRng(rng);
203
- dom.remove(table);
204
- return;
205
- }
206
-
207
- // Empty header/body/footer
208
- each(dom.select('thead,tbody,tfoot', table), function(part) {
209
- if (part.rows.length == 0)
210
- dom.remove(part);
211
- });
212
-
213
- // Restore selection to start position if it still exists
214
- buildGrid();
215
-
216
- // Restore the selection to the closest table position
217
- row = grid[Math.min(grid.length - 1, startPos.y)];
218
- if (row) {
219
- selection.select(row[Math.min(row.length - 1, startPos.x)].elm, true);
220
- selection.collapse(true);
221
- }
222
- };
223
-
224
- function fillLeftDown(x, y, rows, cols) {
225
- var tr, x2, r, c, cell;
226
-
227
- tr = grid[y][x].elm.parentNode;
228
- for (r = 1; r <= rows; r++) {
229
- tr = dom.getNext(tr, 'tr');
230
-
231
- if (tr) {
232
- // Loop left to find real cell
233
- for (x2 = x; x2 >= 0; x2--) {
234
- cell = grid[y + r][x2].elm;
235
-
236
- if (cell.parentNode == tr) {
237
- // Append clones after
238
- for (c = 1; c <= cols; c++)
239
- dom.insertAfter(cloneCell(cell), cell);
240
-
241
- break;
242
- }
243
- }
244
-
245
- if (x2 == -1) {
246
- // Insert nodes before first cell
247
- for (c = 1; c <= cols; c++)
248
- tr.insertBefore(cloneCell(tr.cells[0]), tr.cells[0]);
249
- }
250
- }
251
- }
252
- };
253
-
254
- function split() {
255
- each(grid, function(row, y) {
256
- each(row, function(cell, x) {
257
- var colSpan, rowSpan, newCell, i;
258
-
259
- if (isCellSelected(cell)) {
260
- cell = cell.elm;
261
- colSpan = getSpanVal(cell, 'colspan');
262
- rowSpan = getSpanVal(cell, 'rowspan');
263
-
264
- if (colSpan > 1 || rowSpan > 1) {
265
- setSpanVal(cell, 'rowSpan', 1);
266
- setSpanVal(cell, 'colSpan', 1);
267
-
268
- // Insert cells right
269
- for (i = 0; i < colSpan - 1; i++)
270
- dom.insertAfter(cloneCell(cell), cell);
271
-
272
- fillLeftDown(x, y, rowSpan - 1, colSpan);
273
- }
274
- }
275
- });
276
- });
277
- };
278
-
279
- function merge(cell, cols, rows) {
280
- var startX, startY, endX, endY, x, y, startCell, endCell, cell, children, count;
281
-
282
- // Use specified cell and cols/rows
283
- if (cell) {
284
- pos = getPos(cell);
285
- startX = pos.x;
286
- startY = pos.y;
287
- endX = startX + (cols - 1);
288
- endY = startY + (rows - 1);
289
- } else {
290
- startPos = endPos = null;
291
-
292
- // Calculate start/end pos by checking for selected cells in grid works better with context menu
293
- each(grid, function(row, y) {
294
- each(row, function(cell, x) {
295
- if (isCellSelected(cell)) {
296
- if (!startPos) {
297
- startPos = {x: x, y: y};
298
- }
299
-
300
- endPos = {x: x, y: y};
301
- }
302
- });
303
- });
304
-
305
- // Use selection
306
- startX = startPos.x;
307
- startY = startPos.y;
308
- endX = endPos.x;
309
- endY = endPos.y;
310
- }
311
-
312
- // Find start/end cells
313
- startCell = getCell(startX, startY);
314
- endCell = getCell(endX, endY);
315
-
316
- // Check if the cells exists and if they are of the same part for example tbody = tbody
317
- if (startCell && endCell && startCell.part == endCell.part) {
318
- // Split and rebuild grid
319
- split();
320
- buildGrid();
321
-
322
- // Set row/col span to start cell
323
- startCell = getCell(startX, startY).elm;
324
- setSpanVal(startCell, 'colSpan', (endX - startX) + 1);
325
- setSpanVal(startCell, 'rowSpan', (endY - startY) + 1);
326
-
327
- // Remove other cells and add it's contents to the start cell
328
- for (y = startY; y <= endY; y++) {
329
- for (x = startX; x <= endX; x++) {
330
- if (!grid[y] || !grid[y][x])
331
- continue;
332
-
333
- cell = grid[y][x].elm;
334
-
335
- if (cell != startCell) {
336
- // Move children to startCell
337
- children = tinymce.grep(cell.childNodes);
338
- each(children, function(node) {
339
- startCell.appendChild(node);
340
- });
341
-
342
- // Remove bogus nodes if there is children in the target cell
343
- if (children.length) {
344
- children = tinymce.grep(startCell.childNodes);
345
- count = 0;
346
- each(children, function(node) {
347
- if (node.nodeName == 'BR' && dom.getAttrib(node, 'data-mce-bogus') && count++ < children.length - 1)
348
- startCell.removeChild(node);
349
- });
350
- }
351
-
352
- // Remove cell
353
- dom.remove(cell);
354
- }
355
- }
356
- }
357
-
358
- // Remove empty rows etc and restore caret location
359
- cleanup();
360
- }
361
- };
362
-
363
- function insertRow(before) {
364
- var posY, cell, lastCell, x, rowElm, newRow, newCell, otherCell, rowSpan;
365
-
366
- // Find first/last row
367
- each(grid, function(row, y) {
368
- each(row, function(cell, x) {
369
- if (isCellSelected(cell)) {
370
- cell = cell.elm;
371
- rowElm = cell.parentNode;
372
- newRow = cloneNode(rowElm, false);
373
- posY = y;
374
-
375
- if (before)
376
- return false;
377
- }
378
- });
379
-
380
- if (before)
381
- return !posY;
382
- });
383
-
384
- for (x = 0; x < grid[0].length; x++) {
385
- // Cell not found could be because of an invalid table structure
386
- if (!grid[posY][x])
387
- continue;
388
-
389
- cell = grid[posY][x].elm;
390
-
391
- if (cell != lastCell) {
392
- if (!before) {
393
- rowSpan = getSpanVal(cell, 'rowspan');
394
- if (rowSpan > 1) {
395
- setSpanVal(cell, 'rowSpan', rowSpan + 1);
396
- continue;
397
- }
398
- } else {
399
- // Check if cell above can be expanded
400
- if (posY > 0 && grid[posY - 1][x]) {
401
- otherCell = grid[posY - 1][x].elm;
402
- rowSpan = getSpanVal(otherCell, 'rowSpan');
403
- if (rowSpan > 1) {
404
- setSpanVal(otherCell, 'rowSpan', rowSpan + 1);
405
- continue;
406
- }
407
- }
408
- }
409
-
410
- // Insert new cell into new row
411
- newCell = cloneCell(cell);
412
- setSpanVal(newCell, 'colSpan', cell.colSpan);
413
-
414
- newRow.appendChild(newCell);
415
-
416
- lastCell = cell;
417
- }
418
- }
419
-
420
- if (newRow.hasChildNodes()) {
421
- if (!before)
422
- dom.insertAfter(newRow, rowElm);
423
- else
424
- rowElm.parentNode.insertBefore(newRow, rowElm);
425
- }
426
- };
427
-
428
- function insertCol(before) {
429
- var posX, lastCell;
430
-
431
- // Find first/last column
432
- each(grid, function(row, y) {
433
- each(row, function(cell, x) {
434
- if (isCellSelected(cell)) {
435
- posX = x;
436
-
437
- if (before)
438
- return false;
439
- }
440
- });
441
-
442
- if (before)
443
- return !posX;
444
- });
445
-
446
- each(grid, function(row, y) {
447
- var cell, rowSpan, colSpan;
448
-
449
- if (!row[posX])
450
- return;
451
-
452
- cell = row[posX].elm;
453
- if (cell != lastCell) {
454
- colSpan = getSpanVal(cell, 'colspan');
455
- rowSpan = getSpanVal(cell, 'rowspan');
456
-
457
- if (colSpan == 1) {
458
- if (!before) {
459
- dom.insertAfter(cloneCell(cell), cell);
460
- fillLeftDown(posX, y, rowSpan - 1, colSpan);
461
- } else {
462
- cell.parentNode.insertBefore(cloneCell(cell), cell);
463
- fillLeftDown(posX, y, rowSpan - 1, colSpan);
464
- }
465
- } else
466
- setSpanVal(cell, 'colSpan', cell.colSpan + 1);
467
-
468
- lastCell = cell;
469
- }
470
- });
471
- };
472
-
473
- function deleteCols() {
474
- var cols = [];
475
-
476
- // Get selected column indexes
477
- each(grid, function(row, y) {
478
- each(row, function(cell, x) {
479
- if (isCellSelected(cell) && tinymce.inArray(cols, x) === -1) {
480
- each(grid, function(row) {
481
- var cell = row[x].elm, colSpan;
482
-
483
- colSpan = getSpanVal(cell, 'colSpan');
484
-
485
- if (colSpan > 1)
486
- setSpanVal(cell, 'colSpan', colSpan - 1);
487
- else
488
- dom.remove(cell);
489
- });
490
-
491
- cols.push(x);
492
- }
493
- });
494
- });
495
-
496
- cleanup();
497
- };
498
-
499
- function deleteRows() {
500
- var rows;
501
-
502
- function deleteRow(tr) {
503
- var nextTr, pos, lastCell;
504
-
505
- nextTr = dom.getNext(tr, 'tr');
506
-
507
- // Move down row spanned cells
508
- each(tr.cells, function(cell) {
509
- var rowSpan = getSpanVal(cell, 'rowSpan');
510
-
511
- if (rowSpan > 1) {
512
- setSpanVal(cell, 'rowSpan', rowSpan - 1);
513
- pos = getPos(cell);
514
- fillLeftDown(pos.x, pos.y, 1, 1);
515
- }
516
- });
517
-
518
- // Delete cells
519
- pos = getPos(tr.cells[0]);
520
- each(grid[pos.y], function(cell) {
521
- var rowSpan;
522
-
523
- cell = cell.elm;
524
-
525
- if (cell != lastCell) {
526
- rowSpan = getSpanVal(cell, 'rowSpan');
527
-
528
- if (rowSpan <= 1)
529
- dom.remove(cell);
530
- else
531
- setSpanVal(cell, 'rowSpan', rowSpan - 1);
532
-
533
- lastCell = cell;
534
- }
535
- });
536
- };
537
-
538
- // Get selected rows and move selection out of scope
539
- rows = getSelectedRows();
540
-
541
- // Delete all selected rows
542
- each(rows.reverse(), function(tr) {
543
- deleteRow(tr);
544
- });
545
-
546
- cleanup();
547
- };
548
-
549
- function cutRows() {
550
- var rows = getSelectedRows();
551
-
552
- dom.remove(rows);
553
- cleanup();
554
-
555
- return rows;
556
- };
557
-
558
- function copyRows() {
559
- var rows = getSelectedRows();
560
-
561
- each(rows, function(row, i) {
562
- rows[i] = cloneNode(row, true);
563
- });
564
-
565
- return rows;
566
- };
567
-
568
- function pasteRows(rows, before) {
569
- var selectedRows = getSelectedRows(),
570
- targetRow = selectedRows[before ? 0 : selectedRows.length - 1],
571
- targetCellCount = targetRow.cells.length;
572
-
573
- // Calc target cell count
574
- each(grid, function(row) {
575
- var match;
576
-
577
- targetCellCount = 0;
578
- each(row, function(cell, x) {
579
- if (cell.real)
580
- targetCellCount += cell.colspan;
581
-
582
- if (cell.elm.parentNode == targetRow)
583
- match = 1;
584
- });
585
-
586
- if (match)
587
- return false;
588
- });
589
-
590
- if (!before)
591
- rows.reverse();
592
-
593
- each(rows, function(row) {
594
- var cellCount = row.cells.length, cell;
595
-
596
- // Remove col/rowspans
597
- for (i = 0; i < cellCount; i++) {
598
- cell = row.cells[i];
599
- setSpanVal(cell, 'colSpan', 1);
600
- setSpanVal(cell, 'rowSpan', 1);
601
- }
602
-
603
- // Needs more cells
604
- for (i = cellCount; i < targetCellCount; i++)
605
- row.appendChild(cloneCell(row.cells[cellCount - 1]));
606
-
607
- // Needs less cells
608
- for (i = targetCellCount; i < cellCount; i++)
609
- dom.remove(row.cells[i]);
610
-
611
- // Add before/after
612
- if (before)
613
- targetRow.parentNode.insertBefore(row, targetRow);
614
- else
615
- dom.insertAfter(row, targetRow);
616
- });
617
-
618
- // Remove current selection
619
- dom.removeClass(dom.select('td.mceSelected,th.mceSelected'), 'mceSelected');
620
- };
621
-
622
- function getPos(target) {
623
- var pos;
624
-
625
- each(grid, function(row, y) {
626
- each(row, function(cell, x) {
627
- if (cell.elm == target) {
628
- pos = {x : x, y : y};
629
- return false;
630
- }
631
- });
632
-
633
- return !pos;
634
- });
635
-
636
- return pos;
637
- };
638
-
639
- function setStartCell(cell) {
640
- startPos = getPos(cell);
641
- };
642
-
643
- function findEndPos() {
644
- var pos, maxX, maxY;
645
-
646
- maxX = maxY = 0;
647
-
648
- each(grid, function(row, y) {
649
- each(row, function(cell, x) {
650
- var colSpan, rowSpan;
651
-
652
- if (isCellSelected(cell)) {
653
- cell = grid[y][x];
654
-
655
- if (x > maxX)
656
- maxX = x;
657
-
658
- if (y > maxY)
659
- maxY = y;
660
-
661
- if (cell.real) {
662
- colSpan = cell.colspan - 1;
663
- rowSpan = cell.rowspan - 1;
664
-
665
- if (colSpan) {
666
- if (x + colSpan > maxX)
667
- maxX = x + colSpan;
668
- }
669
-
670
- if (rowSpan) {
671
- if (y + rowSpan > maxY)
672
- maxY = y + rowSpan;
673
- }
674
- }
675
- }
676
- });
677
- });
678
-
679
- return {x : maxX, y : maxY};
680
- };
681
-
682
- function setEndCell(cell) {
683
- var startX, startY, endX, endY, maxX, maxY, colSpan, rowSpan;
684
-
685
- endPos = getPos(cell);
686
-
687
- if (startPos && endPos) {
688
- // Get start/end positions
689
- startX = Math.min(startPos.x, endPos.x);
690
- startY = Math.min(startPos.y, endPos.y);
691
- endX = Math.max(startPos.x, endPos.x);
692
- endY = Math.max(startPos.y, endPos.y);
693
-
694
- // Expand end positon to include spans
695
- maxX = endX;
696
- maxY = endY;
697
-
698
- // Expand startX
699
- for (y = startY; y <= maxY; y++) {
700
- cell = grid[y][startX];
701
-
702
- if (!cell.real) {
703
- if (startX - (cell.colspan - 1) < startX)
704
- startX -= cell.colspan - 1;
705
- }
706
- }
707
-
708
- // Expand startY
709
- for (x = startX; x <= maxX; x++) {
710
- cell = grid[startY][x];
711
-
712
- if (!cell.real) {
713
- if (startY - (cell.rowspan - 1) < startY)
714
- startY -= cell.rowspan - 1;
715
- }
716
- }
717
-
718
- // Find max X, Y
719
- for (y = startY; y <= endY; y++) {
720
- for (x = startX; x <= endX; x++) {
721
- cell = grid[y][x];
722
-
723
- if (cell.real) {
724
- colSpan = cell.colspan - 1;
725
- rowSpan = cell.rowspan - 1;
726
-
727
- if (colSpan) {
728
- if (x + colSpan > maxX)
729
- maxX = x + colSpan;
730
- }
731
-
732
- if (rowSpan) {
733
- if (y + rowSpan > maxY)
734
- maxY = y + rowSpan;
735
- }
736
- }
737
- }
738
- }
739
-
740
- // Remove current selection
741
- dom.removeClass(dom.select('td.mceSelected,th.mceSelected'), 'mceSelected');
742
-
743
- // Add new selection
744
- for (y = startY; y <= maxY; y++) {
745
- for (x = startX; x <= maxX; x++) {
746
- if (grid[y][x])
747
- dom.addClass(grid[y][x].elm, 'mceSelected');
748
- }
749
- }
750
- }
751
- };
752
-
753
- // Expose to public
754
- tinymce.extend(this, {
755
- deleteTable : deleteTable,
756
- split : split,
757
- merge : merge,
758
- insertRow : insertRow,
759
- insertCol : insertCol,
760
- deleteCols : deleteCols,
761
- deleteRows : deleteRows,
762
- cutRows : cutRows,
763
- copyRows : copyRows,
764
- pasteRows : pasteRows,
765
- getPos : getPos,
766
- setStartCell : setStartCell,
767
- setEndCell : setEndCell
768
- });
769
- };
770
-
771
- tinymce.create('tinymce.plugins.TablePlugin', {
772
- init : function(ed, url) {
773
- var winMan, clipboardRows, hasCellSelection = true; // Might be selected cells on reload
774
-
775
- function createTableGrid(node) {
776
- var selection = ed.selection, tblElm = ed.dom.getParent(node || selection.getNode(), 'table');
777
-
778
- if (tblElm)
779
- return new TableGrid(tblElm, ed.dom, selection);
780
- };
781
-
782
- function cleanup() {
783
- // Restore selection possibilities
784
- ed.getBody().style.webkitUserSelect = '';
785
-
786
- if (hasCellSelection) {
787
- ed.dom.removeClass(ed.dom.select('td.mceSelected,th.mceSelected'), 'mceSelected');
788
- hasCellSelection = false;
789
- }
790
- };
791
-
792
- // Register buttons
793
- each([
794
- ['table', 'table.desc', 'mceInsertTable', true],
795
- ['delete_table', 'table.del', 'mceTableDelete'],
796
- ['delete_col', 'table.delete_col_desc', 'mceTableDeleteCol'],
797
- ['delete_row', 'table.delete_row_desc', 'mceTableDeleteRow'],
798
- ['col_after', 'table.col_after_desc', 'mceTableInsertColAfter'],
799
- ['col_before', 'table.col_before_desc', 'mceTableInsertColBefore'],
800
- ['row_after', 'table.row_after_desc', 'mceTableInsertRowAfter'],
801
- ['row_before', 'table.row_before_desc', 'mceTableInsertRowBefore'],
802
- ['row_props', 'table.row_desc', 'mceTableRowProps', true],
803
- ['cell_props', 'table.cell_desc', 'mceTableCellProps', true],
804
- ['split_cells', 'table.split_cells_desc', 'mceTableSplitCells', true],
805
- ['merge_cells', 'table.merge_cells_desc', 'mceTableMergeCells', true]
806
- ], function(c) {
807
- ed.addButton(c[0], {title : c[1], cmd : c[2], ui : c[3]});
808
- });
809
-
810
- // Select whole table is a table border is clicked
811
- if (!tinymce.isIE) {
812
- ed.onClick.add(function(ed, e) {
813
- e = e.target;
814
-
815
- if (e.nodeName === 'TABLE') {
816
- ed.selection.select(e);
817
- ed.nodeChanged();
818
- }
819
- });
820
- }
821
-
822
- ed.onPreProcess.add(function(ed, args) {
823
- var nodes, i, node, dom = ed.dom, value;
824
-
825
- nodes = dom.select('table', args.node);
826
- i = nodes.length;
827
- while (i--) {
828
- node = nodes[i];
829
- dom.setAttrib(node, 'data-mce-style', '');
830
-
831
- if ((value = dom.getAttrib(node, 'width'))) {
832
- dom.setStyle(node, 'width', value);
833
- dom.setAttrib(node, 'width', '');
834
- }
835
-
836
- if ((value = dom.getAttrib(node, 'height'))) {
837
- dom.setStyle(node, 'height', value);
838
- dom.setAttrib(node, 'height', '');
839
- }
840
- }
841
- });
842
-
843
- // Handle node change updates
844
- ed.onNodeChange.add(function(ed, cm, n) {
845
- var p;
846
-
847
- n = ed.selection.getStart();
848
- p = ed.dom.getParent(n, 'td,th,caption');
849
- cm.setActive('table', n.nodeName === 'TABLE' || !!p);
850
-
851
- // Disable table tools if we are in caption
852
- if (p && p.nodeName === 'CAPTION')
853
- p = 0;
854
-
855
- cm.setDisabled('delete_table', !p);
856
- cm.setDisabled('delete_col', !p);
857
- cm.setDisabled('delete_table', !p);
858
- cm.setDisabled('delete_row', !p);
859
- cm.setDisabled('col_after', !p);
860
- cm.setDisabled('col_before', !p);
861
- cm.setDisabled('row_after', !p);
862
- cm.setDisabled('row_before', !p);
863
- cm.setDisabled('row_props', !p);
864
- cm.setDisabled('cell_props', !p);
865
- cm.setDisabled('split_cells', !p);
866
- cm.setDisabled('merge_cells', !p);
867
- });
868
-
869
- ed.onInit.add(function(ed) {
870
- var startTable, startCell, dom = ed.dom, tableGrid;
871
-
872
- winMan = ed.windowManager;
873
-
874
- // Add cell selection logic
875
- ed.onMouseDown.add(function(ed, e) {
876
- if (e.button != 2) {
877
- cleanup();
878
-
879
- startCell = dom.getParent(e.target, 'td,th');
880
- startTable = dom.getParent(startCell, 'table');
881
- }
882
- });
883
-
884
- dom.bind(ed.getDoc(), 'mouseover', function(e) {
885
- var sel, table, target = e.target;
886
-
887
- if (startCell && (tableGrid || target != startCell) && (target.nodeName == 'TD' || target.nodeName == 'TH')) {
888
- table = dom.getParent(target, 'table');
889
- if (table == startTable) {
890
- if (!tableGrid) {
891
- tableGrid = createTableGrid(table);
892
- tableGrid.setStartCell(startCell);
893
-
894
- ed.getBody().style.webkitUserSelect = 'none';
895
- }
896
-
897
- tableGrid.setEndCell(target);
898
- hasCellSelection = true;
899
- }
900
-
901
- // Remove current selection
902
- sel = ed.selection.getSel();
903
-
904
- try {
905
- if (sel.removeAllRanges)
906
- sel.removeAllRanges();
907
- else
908
- sel.empty();
909
- } catch (ex) {
910
- // IE9 might throw errors here
911
- }
912
-
913
- e.preventDefault();
914
- }
915
- });
916
-
917
- ed.onMouseUp.add(function(ed, e) {
918
- var rng, sel = ed.selection, selectedCells, nativeSel = sel.getSel(), walker, node, lastNode, endNode;
919
-
920
- // Move selection to startCell
921
- if (startCell) {
922
- if (tableGrid)
923
- ed.getBody().style.webkitUserSelect = '';
924
-
925
- function setPoint(node, start) {
926
- var walker = new tinymce.dom.TreeWalker(node, node);
927
-
928
- do {
929
- // Text node
930
- if (node.nodeType == 3 && tinymce.trim(node.nodeValue).length != 0) {
931
- if (start)
932
- rng.setStart(node, 0);
933
- else
934
- rng.setEnd(node, node.nodeValue.length);
935
-
936
- return;
937
- }
938
-
939
- // BR element
940
- if (node.nodeName == 'BR') {
941
- if (start)
942
- rng.setStartBefore(node);
943
- else
944
- rng.setEndBefore(node);
945
-
946
- return;
947
- }
948
- } while (node = (start ? walker.next() : walker.prev()));
949
- }
950
-
951
- // Try to expand text selection as much as we can only Gecko supports cell selection
952
- selectedCells = dom.select('td.mceSelected,th.mceSelected');
953
- if (selectedCells.length > 0) {
954
- rng = dom.createRng();
955
- node = selectedCells[0];
956
- endNode = selectedCells[selectedCells.length - 1];
957
- rng.setStartBefore(node);
958
- rng.setEndAfter(node);
959
-
960
- setPoint(node, 1);
961
- walker = new tinymce.dom.TreeWalker(node, dom.getParent(selectedCells[0], 'table'));
962
-
963
- do {
964
- if (node.nodeName == 'TD' || node.nodeName == 'TH') {
965
- if (!dom.hasClass(node, 'mceSelected'))
966
- break;
967
-
968
- lastNode = node;
969
- }
970
- } while (node = walker.next());
971
-
972
- setPoint(lastNode);
973
-
974
- sel.setRng(rng);
975
- }
976
-
977
- ed.nodeChanged();
978
- startCell = tableGrid = startTable = null;
979
- }
980
- });
981
-
982
- ed.onKeyUp.add(function(ed, e) {
983
- cleanup();
984
- });
985
-
986
- ed.onKeyDown.add(function (ed, e) {
987
- fixTableCellSelection(ed);
988
- });
989
-
990
- ed.onMouseDown.add(function (ed, e) {
991
- if (e.button != 2) {
992
- fixTableCellSelection(ed);
993
- }
994
- });
995
- function tableCellSelected(ed, rng, n, currentCell) {
996
- // The decision of when a table cell is selected is somewhat involved. The fact that this code is
997
- // required is actually a pointer to the root cause of this bug. A cell is selected when the start
998
- // and end offsets are 0, the start container is a text, and the selection node is either a TR (most cases)
999
- // or the parent of the table (in the case of the selection containing the last cell of a table).
1000
- var TEXT_NODE = 3, table = ed.dom.getParent(rng.startContainer, 'TABLE'),
1001
- tableParent, allOfCellSelected, tableCellSelection;
1002
- if (table)
1003
- tableParent = table.parentNode;
1004
- allOfCellSelected =rng.startContainer.nodeType == TEXT_NODE &&
1005
- rng.startOffset == 0 &&
1006
- rng.endOffset == 0 &&
1007
- currentCell &&
1008
- (n.nodeName=="TR" || n==tableParent);
1009
- tableCellSelection = (n.nodeName=="TD"||n.nodeName=="TH")&& !currentCell;
1010
- return allOfCellSelected || tableCellSelection;
1011
- // return false;
1012
- }
1013
-
1014
- // this nasty hack is here to work around some WebKit selection bugs.
1015
- function fixTableCellSelection(ed) {
1016
- if (!tinymce.isWebKit)
1017
- return;
1018
-
1019
- var rng = ed.selection.getRng();
1020
- var n = ed.selection.getNode();
1021
- var currentCell = ed.dom.getParent(rng.startContainer, 'TD,TH');
1022
-
1023
- if (!tableCellSelected(ed, rng, n, currentCell))
1024
- return;
1025
- if (!currentCell) {
1026
- currentCell=n;
1027
- }
1028
-
1029
- // Get the very last node inside the table cell
1030
- var end = currentCell.lastChild;
1031
- while (end.lastChild)
1032
- end = end.lastChild;
1033
-
1034
- // Select the entire table cell. Nothing outside of the table cell should be selected.
1035
- rng.setEnd(end, end.nodeValue.length);
1036
- ed.selection.setRng(rng);
1037
- }
1038
- ed.plugins.table.fixTableCellSelection=fixTableCellSelection;
1039
-
1040
- // Add context menu
1041
- if (ed && ed.plugins.contextmenu) {
1042
- ed.plugins.contextmenu.onContextMenu.add(function(th, m, e) {
1043
- var sm, se = ed.selection, el = se.getNode() || ed.getBody();
1044
-
1045
- if (ed.dom.getParent(e, 'td') || ed.dom.getParent(e, 'th') || ed.dom.select('td.mceSelected,th.mceSelected').length) {
1046
- m.removeAll();
1047
-
1048
- if (el.nodeName == 'A' && !ed.dom.getAttrib(el, 'name')) {
1049
- m.add({title : 'advanced.link_desc', icon : 'link', cmd : ed.plugins.advlink ? 'mceAdvLink' : 'mceLink', ui : true});
1050
- m.add({title : 'advanced.unlink_desc', icon : 'unlink', cmd : 'UnLink'});
1051
- m.addSeparator();
1052
- }
1053
-
1054
- if (el.nodeName == 'IMG' && el.className.indexOf('mceItem') == -1) {
1055
- m.add({title : 'advanced.image_desc', icon : 'image', cmd : ed.plugins.advimage ? 'mceAdvImage' : 'mceImage', ui : true});
1056
- m.addSeparator();
1057
- }
1058
-
1059
- m.add({title : 'table.desc', icon : 'table', cmd : 'mceInsertTable', value : {action : 'insert'}});
1060
- m.add({title : 'table.props_desc', icon : 'table_props', cmd : 'mceInsertTable'});
1061
- m.add({title : 'table.del', icon : 'delete_table', cmd : 'mceTableDelete'});
1062
- m.addSeparator();
1063
-
1064
- // Cell menu
1065
- sm = m.addMenu({title : 'table.cell'});
1066
- sm.add({title : 'table.cell_desc', icon : 'cell_props', cmd : 'mceTableCellProps'});
1067
- sm.add({title : 'table.split_cells_desc', icon : 'split_cells', cmd : 'mceTableSplitCells'});
1068
- sm.add({title : 'table.merge_cells_desc', icon : 'merge_cells', cmd : 'mceTableMergeCells'});
1069
-
1070
- // Row menu
1071
- sm = m.addMenu({title : 'table.row'});
1072
- sm.add({title : 'table.row_desc', icon : 'row_props', cmd : 'mceTableRowProps'});
1073
- sm.add({title : 'table.row_before_desc', icon : 'row_before', cmd : 'mceTableInsertRowBefore'});
1074
- sm.add({title : 'table.row_after_desc', icon : 'row_after', cmd : 'mceTableInsertRowAfter'});
1075
- sm.add({title : 'table.delete_row_desc', icon : 'delete_row', cmd : 'mceTableDeleteRow'});
1076
- sm.addSeparator();
1077
- sm.add({title : 'table.cut_row_desc', icon : 'cut', cmd : 'mceTableCutRow'});
1078
- sm.add({title : 'table.copy_row_desc', icon : 'copy', cmd : 'mceTableCopyRow'});
1079
- sm.add({title : 'table.paste_row_before_desc', icon : 'paste', cmd : 'mceTablePasteRowBefore'}).setDisabled(!clipboardRows);
1080
- sm.add({title : 'table.paste_row_after_desc', icon : 'paste', cmd : 'mceTablePasteRowAfter'}).setDisabled(!clipboardRows);
1081
-
1082
- // Column menu
1083
- sm = m.addMenu({title : 'table.col'});
1084
- sm.add({title : 'table.col_before_desc', icon : 'col_before', cmd : 'mceTableInsertColBefore'});
1085
- sm.add({title : 'table.col_after_desc', icon : 'col_after', cmd : 'mceTableInsertColAfter'});
1086
- sm.add({title : 'table.delete_col_desc', icon : 'delete_col', cmd : 'mceTableDeleteCol'});
1087
- } else
1088
- m.add({title : 'table.desc', icon : 'table', cmd : 'mceInsertTable'});
1089
- });
1090
- }
1091
-
1092
- // Fix to allow navigating up and down in a table in WebKit browsers.
1093
- if (tinymce.isWebKit) {
1094
- function moveSelection(ed, e) {
1095
- var VK = tinymce.VK;
1096
- var key = e.keyCode;
1097
-
1098
- function handle(upBool, sourceNode, event) {
1099
- var siblingDirection = upBool ? 'previousSibling' : 'nextSibling';
1100
- var currentRow = ed.dom.getParent(sourceNode, 'tr');
1101
- var siblingRow = currentRow[siblingDirection];
1102
-
1103
- if (siblingRow) {
1104
- moveCursorToRow(ed, sourceNode, siblingRow, upBool);
1105
- tinymce.dom.Event.cancel(event);
1106
- return true;
1107
- } else {
1108
- var tableNode = ed.dom.getParent(currentRow, 'table');
1109
- var middleNode = currentRow.parentNode;
1110
- var parentNodeName = middleNode.nodeName.toLowerCase();
1111
- if (parentNodeName === 'tbody' || parentNodeName === (upBool ? 'tfoot' : 'thead')) {
1112
- var targetParent = getTargetParent(upBool, tableNode, middleNode, 'tbody');
1113
- if (targetParent !== null) {
1114
- return moveToRowInTarget(upBool, targetParent, sourceNode, event);
1115
- }
1116
- }
1117
- return escapeTable(upBool, currentRow, siblingDirection, tableNode, event);
1118
- }
1119
- }
1120
-
1121
- function getTargetParent(upBool, topNode, secondNode, nodeName) {
1122
- var tbodies = ed.dom.select('>' + nodeName, topNode);
1123
- var position = tbodies.indexOf(secondNode);
1124
- if (upBool && position === 0 || !upBool && position === tbodies.length - 1) {
1125
- return getFirstHeadOrFoot(upBool, topNode);
1126
- } else if (position === -1) {
1127
- var topOrBottom = secondNode.tagName.toLowerCase() === 'thead' ? 0 : tbodies.length - 1;
1128
- return tbodies[topOrBottom];
1129
- } else {
1130
- return tbodies[position + (upBool ? -1 : 1)];
1131
- }
1132
- }
1133
-
1134
- function getFirstHeadOrFoot(upBool, parent) {
1135
- var tagName = upBool ? 'thead' : 'tfoot';
1136
- var headOrFoot = ed.dom.select('>' + tagName, parent);
1137
- return headOrFoot.length !== 0 ? headOrFoot[0] : null;
1138
- }
1139
-
1140
- function moveToRowInTarget(upBool, targetParent, sourceNode, event) {
1141
- var targetRow = getChildForDirection(targetParent, upBool);
1142
- targetRow && moveCursorToRow(ed, sourceNode, targetRow, upBool);
1143
- tinymce.dom.Event.cancel(event);
1144
- return true;
1145
- }
1146
-
1147
- function escapeTable(upBool, currentRow, siblingDirection, table, event) {
1148
- var tableSibling = table[siblingDirection];
1149
- if (tableSibling) {
1150
- moveCursorToStartOfElement(tableSibling);
1151
- return true;
1152
- } else {
1153
- var parentCell = ed.dom.getParent(table, 'td,th');
1154
- if (parentCell) {
1155
- return handle(upBool, parentCell, event);
1156
- } else {
1157
- var backUpSibling = getChildForDirection(currentRow, !upBool);
1158
- moveCursorToStartOfElement(backUpSibling);
1159
- return tinymce.dom.Event.cancel(event);
1160
- }
1161
- }
1162
- }
1163
-
1164
- function getChildForDirection(parent, up) {
1165
- var child = parent && parent[up ? 'lastChild' : 'firstChild'];
1166
- // BR is not a valid table child to return in this case we return the table cell
1167
- return child && child.nodeName === 'BR' ? ed.dom.getParent(child, 'td,th') : child;
1168
- }
1169
-
1170
- function moveCursorToStartOfElement(n) {
1171
- ed.selection.setCursorLocation(n, 0);
1172
- }
1173
-
1174
- function isVerticalMovement() {
1175
- return key == VK.UP || key == VK.DOWN;
1176
- }
1177
-
1178
- function isInTable(ed) {
1179
- var node = ed.selection.getNode();
1180
- var currentRow = ed.dom.getParent(node, 'tr');
1181
- return currentRow !== null;
1182
- }
1183
-
1184
- function columnIndex(column) {
1185
- var colIndex = 0;
1186
- var c = column;
1187
- while (c.previousSibling) {
1188
- c = c.previousSibling;
1189
- colIndex = colIndex + getSpanVal(c, "colspan");
1190
- }
1191
- return colIndex;
1192
- }
1193
-
1194
- function findColumn(rowElement, columnIndex) {
1195
- var c = 0;
1196
- var r = 0;
1197
- each(rowElement.children, function(cell, i) {
1198
- c = c + getSpanVal(cell, "colspan");
1199
- r = i;
1200
- if (c > columnIndex)
1201
- return false;
1202
- });
1203
- return r;
1204
- }
1205
-
1206
- function moveCursorToRow(ed, node, row, upBool) {
1207
- var srcColumnIndex = columnIndex(ed.dom.getParent(node, 'td,th'));
1208
- var tgtColumnIndex = findColumn(row, srcColumnIndex);
1209
- var tgtNode = row.childNodes[tgtColumnIndex];
1210
- var rowCellTarget = getChildForDirection(tgtNode, upBool);
1211
- moveCursorToStartOfElement(rowCellTarget || tgtNode);
1212
- }
1213
-
1214
- function shouldFixCaret(preBrowserNode) {
1215
- var newNode = ed.selection.getNode();
1216
- var newParent = ed.dom.getParent(newNode, 'td,th');
1217
- var oldParent = ed.dom.getParent(preBrowserNode, 'td,th');
1218
- return newParent && newParent !== oldParent && checkSameParentTable(newParent, oldParent)
1219
- }
1220
-
1221
- function checkSameParentTable(nodeOne, NodeTwo) {
1222
- return ed.dom.getParent(nodeOne, 'TABLE') === ed.dom.getParent(NodeTwo, 'TABLE');
1223
- }
1224
-
1225
- if (isVerticalMovement() && isInTable(ed)) {
1226
- var preBrowserNode = ed.selection.getNode();
1227
- setTimeout(function() {
1228
- if (shouldFixCaret(preBrowserNode)) {
1229
- handle(!e.shiftKey && key === VK.UP, preBrowserNode, e);
1230
- }
1231
- }, 0);
1232
- }
1233
- }
1234
-
1235
- ed.onKeyDown.add(moveSelection);
1236
- }
1237
-
1238
- // Fixes an issue on Gecko where it's impossible to place the caret behind a table
1239
- // This fix will force a paragraph element after the table but only when the forced_root_block setting is enabled
1240
- if (!tinymce.isIE) {
1241
- function fixTableCaretPos() {
1242
- var last;
1243
-
1244
- // Skip empty text nodes form the end
1245
- for (last = ed.getBody().lastChild; last && last.nodeType == 3 && !last.nodeValue.length; last = last.previousSibling) ;
1246
-
1247
- if (last && last.nodeName == 'TABLE')
1248
- ed.dom.add(ed.getBody(), 'p', null, '<br data-mce-bogus="1" />');
1249
- };
1250
-
1251
- // Fixes an bug where it's impossible to place the caret before a table in Gecko
1252
- // this fix solves it by detecting when the caret is at the beginning of such a table
1253
- // and then manually moves the caret infront of the table
1254
- if (tinymce.isGecko) {
1255
- ed.onKeyDown.add(function(ed, e) {
1256
- var rng, table, dom = ed.dom;
1257
-
1258
- // On gecko it's not possible to place the caret before a table
1259
- if (e.keyCode == 37 || e.keyCode == 38) {
1260
- rng = ed.selection.getRng();
1261
- table = dom.getParent(rng.startContainer, 'table');
1262
-
1263
- if (table && ed.getBody().firstChild == table) {
1264
- if (isAtStart(rng, table)) {
1265
- rng = dom.createRng();
1266
-
1267
- rng.setStartBefore(table);
1268
- rng.setEndBefore(table);
1269
-
1270
- ed.selection.setRng(rng);
1271
-
1272
- e.preventDefault();
1273
- }
1274
- }
1275
- }
1276
- });
1277
- }
1278
-
1279
- ed.onKeyUp.add(fixTableCaretPos);
1280
- ed.onSetContent.add(fixTableCaretPos);
1281
- ed.onVisualAid.add(fixTableCaretPos);
1282
-
1283
- ed.onPreProcess.add(function(ed, o) {
1284
- var last = o.node.lastChild;
1285
-
1286
- if (last && last.childNodes.length == 1 && last.firstChild.nodeName == 'BR' && last.previousSibling && last.previousSibling.nodeName == "TABLE")
1287
- ed.dom.remove(last);
1288
- });
1289
-
1290
-
1291
- /**
1292
- * Fixes bug in Gecko where shift-enter in table cell does not place caret on new line
1293
- */
1294
- if (tinymce.isGecko) {
1295
- ed.onKeyDown.add(function(ed, e) {
1296
- if (e.keyCode === tinymce.VK.ENTER && e.shiftKey) {
1297
- var node = ed.selection.getRng().startContainer;
1298
- var tableCell = dom.getParent(node, 'td,th');
1299
- if (tableCell) {
1300
- var zeroSizedNbsp = ed.getDoc().createTextNode("\uFEFF");
1301
- dom.insertAfter(zeroSizedNbsp, node);
1302
- }
1303
- }
1304
- });
1305
- }
1306
-
1307
-
1308
- fixTableCaretPos();
1309
- ed.startContent = ed.getContent({format : 'raw'});
1310
- }
1311
- });
1312
-
1313
- // Register action commands
1314
- each({
1315
- mceTableSplitCells : function(grid) {
1316
- grid.split();
1317
- },
1318
-
1319
- mceTableMergeCells : function(grid) {
1320
- var rowSpan, colSpan, cell;
1321
-
1322
- cell = ed.dom.getParent(ed.selection.getNode(), 'th,td');
1323
- if (cell) {
1324
- rowSpan = cell.rowSpan;
1325
- colSpan = cell.colSpan;
1326
- }
1327
-
1328
- if (!ed.dom.select('td.mceSelected,th.mceSelected').length) {
1329
- winMan.open({
1330
- url : url + '/merge_cells.htm',
1331
- width : 240 + parseInt(ed.getLang('table.merge_cells_delta_width', 0)),
1332
- height : 110 + parseInt(ed.getLang('table.merge_cells_delta_height', 0)),
1333
- inline : 1
1334
- }, {
1335
- rows : rowSpan,
1336
- cols : colSpan,
1337
- onaction : function(data) {
1338
- grid.merge(cell, data.cols, data.rows);
1339
- },
1340
- plugin_url : url
1341
- });
1342
- } else
1343
- grid.merge();
1344
- },
1345
-
1346
- mceTableInsertRowBefore : function(grid) {
1347
- grid.insertRow(true);
1348
- },
1349
-
1350
- mceTableInsertRowAfter : function(grid) {
1351
- grid.insertRow();
1352
- },
1353
-
1354
- mceTableInsertColBefore : function(grid) {
1355
- grid.insertCol(true);
1356
- },
1357
-
1358
- mceTableInsertColAfter : function(grid) {
1359
- grid.insertCol();
1360
- },
1361
-
1362
- mceTableDeleteCol : function(grid) {
1363
- grid.deleteCols();
1364
- },
1365
-
1366
- mceTableDeleteRow : function(grid) {
1367
- grid.deleteRows();
1368
- },
1369
-
1370
- mceTableCutRow : function(grid) {
1371
- clipboardRows = grid.cutRows();
1372
- },
1373
-
1374
- mceTableCopyRow : function(grid) {
1375
- clipboardRows = grid.copyRows();
1376
- },
1377
-
1378
- mceTablePasteRowBefore : function(grid) {
1379
- grid.pasteRows(clipboardRows, true);
1380
- },
1381
-
1382
- mceTablePasteRowAfter : function(grid) {
1383
- grid.pasteRows(clipboardRows);
1384
- },
1385
-
1386
- mceTableDelete : function(grid) {
1387
- grid.deleteTable();
1388
- }
1389
- }, function(func, name) {
1390
- ed.addCommand(name, function() {
1391
- var grid = createTableGrid();
1392
-
1393
- if (grid) {
1394
- func(grid);
1395
- ed.execCommand('mceRepaint');
1396
- cleanup();
1397
- }
1398
- });
1399
- });
1400
-
1401
- // Register dialog commands
1402
- each({
1403
- mceInsertTable : function(val) {
1404
- winMan.open({
1405
- url : url + '/table.htm',
1406
- width : 400 + parseInt(ed.getLang('table.table_delta_width', 0)),
1407
- height : 320 + parseInt(ed.getLang('table.table_delta_height', 0)),
1408
- inline : 1
1409
- }, {
1410
- plugin_url : url,
1411
- action : val ? val.action : 0
1412
- });
1413
- },
1414
-
1415
- mceTableRowProps : function() {
1416
- winMan.open({
1417
- url : url + '/row.htm',
1418
- width : 400 + parseInt(ed.getLang('table.rowprops_delta_width', 0)),
1419
- height : 295 + parseInt(ed.getLang('table.rowprops_delta_height', 0)),
1420
- inline : 1
1421
- }, {
1422
- plugin_url : url
1423
- });
1424
- },
1425
-
1426
- mceTableCellProps : function() {
1427
- winMan.open({
1428
- url : url + '/cell.htm',
1429
- width : 400 + parseInt(ed.getLang('table.cellprops_delta_width', 0)),
1430
- height : 295 + parseInt(ed.getLang('table.cellprops_delta_height', 0)),
1431
- inline : 1
1432
- }, {
1433
- plugin_url : url
1434
- });
1435
- }
1436
- }, function(func, name) {
1437
- ed.addCommand(name, function(ui, val) {
1438
- func(val);
1439
- });
1440
- });
1441
- }
1442
- });
1443
-
1444
- // Register plugin
1445
- tinymce.PluginManager.add('table', tinymce.plugins.TablePlugin);
1446
- })(tinymce);
1
+ /**
2
+ * editor_plugin_src.js
3
+ *
4
+ * Copyright 2009, Moxiecode Systems AB
5
+ * Released under LGPL License.
6
+ *
7
+ * License: http://tinymce.moxiecode.com/license
8
+ * Contributing: http://tinymce.moxiecode.com/contributing
9
+ */
10
+
11
+ (function(tinymce) {
12
+ var each = tinymce.each;
13
+
14
+ // Checks if the selection/caret is at the start of the specified block element
15
+ function isAtStart(rng, par) {
16
+ var doc = par.ownerDocument, rng2 = doc.createRange(), elm;
17
+
18
+ rng2.setStartBefore(par);
19
+ rng2.setEnd(rng.endContainer, rng.endOffset);
20
+
21
+ elm = doc.createElement('body');
22
+ elm.appendChild(rng2.cloneContents());
23
+
24
+ // Check for text characters of other elements that should be treated as content
25
+ return elm.innerHTML.replace(/<(br|img|object|embed|input|textarea)[^>]*>/gi, '-').replace(/<[^>]+>/g, '').length == 0;
26
+ };
27
+
28
+ function getSpanVal(td, name) {
29
+ return parseInt(td.getAttribute(name) || 1);
30
+ }
31
+
32
+ /**
33
+ * Table Grid class.
34
+ */
35
+ function TableGrid(table, dom, selection) {
36
+ var grid, startPos, endPos, selectedCell;
37
+
38
+ buildGrid();
39
+ selectedCell = dom.getParent(selection.getStart(), 'th,td');
40
+ if (selectedCell) {
41
+ startPos = getPos(selectedCell);
42
+ endPos = findEndPos();
43
+ selectedCell = getCell(startPos.x, startPos.y);
44
+ }
45
+
46
+ function cloneNode(node, children) {
47
+ node = node.cloneNode(children);
48
+ node.removeAttribute('id');
49
+
50
+ return node;
51
+ }
52
+
53
+ function buildGrid() {
54
+ var startY = 0;
55
+
56
+ grid = [];
57
+
58
+ each(['thead', 'tbody', 'tfoot'], function(part) {
59
+ var rows = dom.select('> ' + part + ' tr', table);
60
+
61
+ each(rows, function(tr, y) {
62
+ y += startY;
63
+
64
+ each(dom.select('> td, > th', tr), function(td, x) {
65
+ var x2, y2, rowspan, colspan;
66
+
67
+ // Skip over existing cells produced by rowspan
68
+ if (grid[y]) {
69
+ while (grid[y][x])
70
+ x++;
71
+ }
72
+
73
+ // Get col/rowspan from cell
74
+ rowspan = getSpanVal(td, 'rowspan');
75
+ colspan = getSpanVal(td, 'colspan');
76
+
77
+ // Fill out rowspan/colspan right and down
78
+ for (y2 = y; y2 < y + rowspan; y2++) {
79
+ if (!grid[y2])
80
+ grid[y2] = [];
81
+
82
+ for (x2 = x; x2 < x + colspan; x2++) {
83
+ grid[y2][x2] = {
84
+ part : part,
85
+ real : y2 == y && x2 == x,
86
+ elm : td,
87
+ rowspan : rowspan,
88
+ colspan : colspan
89
+ };
90
+ }
91
+ }
92
+ });
93
+ });
94
+
95
+ startY += rows.length;
96
+ });
97
+ };
98
+
99
+ function getCell(x, y) {
100
+ var row;
101
+
102
+ row = grid[y];
103
+ if (row)
104
+ return row[x];
105
+ };
106
+
107
+ function setSpanVal(td, name, val) {
108
+ if (td) {
109
+ val = parseInt(val);
110
+
111
+ if (val === 1)
112
+ td.removeAttribute(name, 1);
113
+ else
114
+ td.setAttribute(name, val, 1);
115
+ }
116
+ }
117
+
118
+ function isCellSelected(cell) {
119
+ return cell && (dom.hasClass(cell.elm, 'mceSelected') || cell == selectedCell);
120
+ };
121
+
122
+ function getSelectedRows() {
123
+ var rows = [];
124
+
125
+ each(table.rows, function(row) {
126
+ each(row.cells, function(cell) {
127
+ if (dom.hasClass(cell, 'mceSelected') || cell == selectedCell.elm) {
128
+ rows.push(row);
129
+ return false;
130
+ }
131
+ });
132
+ });
133
+
134
+ return rows;
135
+ };
136
+
137
+ function deleteTable() {
138
+ var rng = dom.createRng();
139
+
140
+ rng.setStartAfter(table);
141
+ rng.setEndAfter(table);
142
+
143
+ selection.setRng(rng);
144
+
145
+ dom.remove(table);
146
+ };
147
+
148
+ function cloneCell(cell) {
149
+ var formatNode;
150
+
151
+ // Clone formats
152
+ tinymce.walk(cell, function(node) {
153
+ var curNode;
154
+
155
+ if (node.nodeType == 3) {
156
+ each(dom.getParents(node.parentNode, null, cell).reverse(), function(node) {
157
+ node = cloneNode(node, false);
158
+
159
+ if (!formatNode)
160
+ formatNode = curNode = node;
161
+ else if (curNode)
162
+ curNode.appendChild(node);
163
+
164
+ curNode = node;
165
+ });
166
+
167
+ // Add something to the inner node
168
+ if (curNode)
169
+ curNode.innerHTML = tinymce.isIE ? '&nbsp;' : '<br data-mce-bogus="1" />';
170
+
171
+ return false;
172
+ }
173
+ }, 'childNodes');
174
+
175
+ cell = cloneNode(cell, false);
176
+ setSpanVal(cell, 'rowSpan', 1);
177
+ setSpanVal(cell, 'colSpan', 1);
178
+
179
+ if (formatNode) {
180
+ cell.appendChild(formatNode);
181
+ } else {
182
+ if (!tinymce.isIE)
183
+ cell.innerHTML = '<br data-mce-bogus="1" />';
184
+ }
185
+
186
+ return cell;
187
+ };
188
+
189
+ function cleanup() {
190
+ var rng = dom.createRng();
191
+
192
+ // Empty rows
193
+ each(dom.select('tr', table), function(tr) {
194
+ if (tr.cells.length == 0)
195
+ dom.remove(tr);
196
+ });
197
+
198
+ // Empty table
199
+ if (dom.select('tr', table).length == 0) {
200
+ rng.setStartAfter(table);
201
+ rng.setEndAfter(table);
202
+ selection.setRng(rng);
203
+ dom.remove(table);
204
+ return;
205
+ }
206
+
207
+ // Empty header/body/footer
208
+ each(dom.select('thead,tbody,tfoot', table), function(part) {
209
+ if (part.rows.length == 0)
210
+ dom.remove(part);
211
+ });
212
+
213
+ // Restore selection to start position if it still exists
214
+ buildGrid();
215
+
216
+ // Restore the selection to the closest table position
217
+ row = grid[Math.min(grid.length - 1, startPos.y)];
218
+ if (row) {
219
+ selection.select(row[Math.min(row.length - 1, startPos.x)].elm, true);
220
+ selection.collapse(true);
221
+ }
222
+ };
223
+
224
+ function fillLeftDown(x, y, rows, cols) {
225
+ var tr, x2, r, c, cell;
226
+
227
+ tr = grid[y][x].elm.parentNode;
228
+ for (r = 1; r <= rows; r++) {
229
+ tr = dom.getNext(tr, 'tr');
230
+
231
+ if (tr) {
232
+ // Loop left to find real cell
233
+ for (x2 = x; x2 >= 0; x2--) {
234
+ cell = grid[y + r][x2].elm;
235
+
236
+ if (cell.parentNode == tr) {
237
+ // Append clones after
238
+ for (c = 1; c <= cols; c++)
239
+ dom.insertAfter(cloneCell(cell), cell);
240
+
241
+ break;
242
+ }
243
+ }
244
+
245
+ if (x2 == -1) {
246
+ // Insert nodes before first cell
247
+ for (c = 1; c <= cols; c++)
248
+ tr.insertBefore(cloneCell(tr.cells[0]), tr.cells[0]);
249
+ }
250
+ }
251
+ }
252
+ };
253
+
254
+ function split() {
255
+ each(grid, function(row, y) {
256
+ each(row, function(cell, x) {
257
+ var colSpan, rowSpan, newCell, i;
258
+
259
+ if (isCellSelected(cell)) {
260
+ cell = cell.elm;
261
+ colSpan = getSpanVal(cell, 'colspan');
262
+ rowSpan = getSpanVal(cell, 'rowspan');
263
+
264
+ if (colSpan > 1 || rowSpan > 1) {
265
+ setSpanVal(cell, 'rowSpan', 1);
266
+ setSpanVal(cell, 'colSpan', 1);
267
+
268
+ // Insert cells right
269
+ for (i = 0; i < colSpan - 1; i++)
270
+ dom.insertAfter(cloneCell(cell), cell);
271
+
272
+ fillLeftDown(x, y, rowSpan - 1, colSpan);
273
+ }
274
+ }
275
+ });
276
+ });
277
+ };
278
+
279
+ function merge(cell, cols, rows) {
280
+ var startX, startY, endX, endY, x, y, startCell, endCell, cell, children, count;
281
+
282
+ // Use specified cell and cols/rows
283
+ if (cell) {
284
+ pos = getPos(cell);
285
+ startX = pos.x;
286
+ startY = pos.y;
287
+ endX = startX + (cols - 1);
288
+ endY = startY + (rows - 1);
289
+ } else {
290
+ startPos = endPos = null;
291
+
292
+ // Calculate start/end pos by checking for selected cells in grid works better with context menu
293
+ each(grid, function(row, y) {
294
+ each(row, function(cell, x) {
295
+ if (isCellSelected(cell)) {
296
+ if (!startPos) {
297
+ startPos = {x: x, y: y};
298
+ }
299
+
300
+ endPos = {x: x, y: y};
301
+ }
302
+ });
303
+ });
304
+
305
+ // Use selection
306
+ startX = startPos.x;
307
+ startY = startPos.y;
308
+ endX = endPos.x;
309
+ endY = endPos.y;
310
+ }
311
+
312
+ // Find start/end cells
313
+ startCell = getCell(startX, startY);
314
+ endCell = getCell(endX, endY);
315
+
316
+ // Check if the cells exists and if they are of the same part for example tbody = tbody
317
+ if (startCell && endCell && startCell.part == endCell.part) {
318
+ // Split and rebuild grid
319
+ split();
320
+ buildGrid();
321
+
322
+ // Set row/col span to start cell
323
+ startCell = getCell(startX, startY).elm;
324
+ setSpanVal(startCell, 'colSpan', (endX - startX) + 1);
325
+ setSpanVal(startCell, 'rowSpan', (endY - startY) + 1);
326
+
327
+ // Remove other cells and add it's contents to the start cell
328
+ for (y = startY; y <= endY; y++) {
329
+ for (x = startX; x <= endX; x++) {
330
+ if (!grid[y] || !grid[y][x])
331
+ continue;
332
+
333
+ cell = grid[y][x].elm;
334
+
335
+ if (cell != startCell) {
336
+ // Move children to startCell
337
+ children = tinymce.grep(cell.childNodes);
338
+ each(children, function(node) {
339
+ startCell.appendChild(node);
340
+ });
341
+
342
+ // Remove bogus nodes if there is children in the target cell
343
+ if (children.length) {
344
+ children = tinymce.grep(startCell.childNodes);
345
+ count = 0;
346
+ each(children, function(node) {
347
+ if (node.nodeName == 'BR' && dom.getAttrib(node, 'data-mce-bogus') && count++ < children.length - 1)
348
+ startCell.removeChild(node);
349
+ });
350
+ }
351
+
352
+ // Remove cell
353
+ dom.remove(cell);
354
+ }
355
+ }
356
+ }
357
+
358
+ // Remove empty rows etc and restore caret location
359
+ cleanup();
360
+ }
361
+ };
362
+
363
+ function insertRow(before) {
364
+ var posY, cell, lastCell, x, rowElm, newRow, newCell, otherCell, rowSpan;
365
+
366
+ // Find first/last row
367
+ each(grid, function(row, y) {
368
+ each(row, function(cell, x) {
369
+ if (isCellSelected(cell)) {
370
+ cell = cell.elm;
371
+ rowElm = cell.parentNode;
372
+ newRow = cloneNode(rowElm, false);
373
+ posY = y;
374
+
375
+ if (before)
376
+ return false;
377
+ }
378
+ });
379
+
380
+ if (before)
381
+ return !posY;
382
+ });
383
+
384
+ for (x = 0; x < grid[0].length; x++) {
385
+ // Cell not found could be because of an invalid table structure
386
+ if (!grid[posY][x])
387
+ continue;
388
+
389
+ cell = grid[posY][x].elm;
390
+
391
+ if (cell != lastCell) {
392
+ if (!before) {
393
+ rowSpan = getSpanVal(cell, 'rowspan');
394
+ if (rowSpan > 1) {
395
+ setSpanVal(cell, 'rowSpan', rowSpan + 1);
396
+ continue;
397
+ }
398
+ } else {
399
+ // Check if cell above can be expanded
400
+ if (posY > 0 && grid[posY - 1][x]) {
401
+ otherCell = grid[posY - 1][x].elm;
402
+ rowSpan = getSpanVal(otherCell, 'rowSpan');
403
+ if (rowSpan > 1) {
404
+ setSpanVal(otherCell, 'rowSpan', rowSpan + 1);
405
+ continue;
406
+ }
407
+ }
408
+ }
409
+
410
+ // Insert new cell into new row
411
+ newCell = cloneCell(cell);
412
+ setSpanVal(newCell, 'colSpan', cell.colSpan);
413
+
414
+ newRow.appendChild(newCell);
415
+
416
+ lastCell = cell;
417
+ }
418
+ }
419
+
420
+ if (newRow.hasChildNodes()) {
421
+ if (!before)
422
+ dom.insertAfter(newRow, rowElm);
423
+ else
424
+ rowElm.parentNode.insertBefore(newRow, rowElm);
425
+ }
426
+ };
427
+
428
+ function insertCol(before) {
429
+ var posX, lastCell;
430
+
431
+ // Find first/last column
432
+ each(grid, function(row, y) {
433
+ each(row, function(cell, x) {
434
+ if (isCellSelected(cell)) {
435
+ posX = x;
436
+
437
+ if (before)
438
+ return false;
439
+ }
440
+ });
441
+
442
+ if (before)
443
+ return !posX;
444
+ });
445
+
446
+ each(grid, function(row, y) {
447
+ var cell, rowSpan, colSpan;
448
+
449
+ if (!row[posX])
450
+ return;
451
+
452
+ cell = row[posX].elm;
453
+ if (cell != lastCell) {
454
+ colSpan = getSpanVal(cell, 'colspan');
455
+ rowSpan = getSpanVal(cell, 'rowspan');
456
+
457
+ if (colSpan == 1) {
458
+ if (!before) {
459
+ dom.insertAfter(cloneCell(cell), cell);
460
+ fillLeftDown(posX, y, rowSpan - 1, colSpan);
461
+ } else {
462
+ cell.parentNode.insertBefore(cloneCell(cell), cell);
463
+ fillLeftDown(posX, y, rowSpan - 1, colSpan);
464
+ }
465
+ } else
466
+ setSpanVal(cell, 'colSpan', cell.colSpan + 1);
467
+
468
+ lastCell = cell;
469
+ }
470
+ });
471
+ };
472
+
473
+ function deleteCols() {
474
+ var cols = [];
475
+
476
+ // Get selected column indexes
477
+ each(grid, function(row, y) {
478
+ each(row, function(cell, x) {
479
+ if (isCellSelected(cell) && tinymce.inArray(cols, x) === -1) {
480
+ each(grid, function(row) {
481
+ var cell = row[x].elm, colSpan;
482
+
483
+ colSpan = getSpanVal(cell, 'colSpan');
484
+
485
+ if (colSpan > 1)
486
+ setSpanVal(cell, 'colSpan', colSpan - 1);
487
+ else
488
+ dom.remove(cell);
489
+ });
490
+
491
+ cols.push(x);
492
+ }
493
+ });
494
+ });
495
+
496
+ cleanup();
497
+ };
498
+
499
+ function deleteRows() {
500
+ var rows;
501
+
502
+ function deleteRow(tr) {
503
+ var nextTr, pos, lastCell;
504
+
505
+ nextTr = dom.getNext(tr, 'tr');
506
+
507
+ // Move down row spanned cells
508
+ each(tr.cells, function(cell) {
509
+ var rowSpan = getSpanVal(cell, 'rowSpan');
510
+
511
+ if (rowSpan > 1) {
512
+ setSpanVal(cell, 'rowSpan', rowSpan - 1);
513
+ pos = getPos(cell);
514
+ fillLeftDown(pos.x, pos.y, 1, 1);
515
+ }
516
+ });
517
+
518
+ // Delete cells
519
+ pos = getPos(tr.cells[0]);
520
+ each(grid[pos.y], function(cell) {
521
+ var rowSpan;
522
+
523
+ cell = cell.elm;
524
+
525
+ if (cell != lastCell) {
526
+ rowSpan = getSpanVal(cell, 'rowSpan');
527
+
528
+ if (rowSpan <= 1)
529
+ dom.remove(cell);
530
+ else
531
+ setSpanVal(cell, 'rowSpan', rowSpan - 1);
532
+
533
+ lastCell = cell;
534
+ }
535
+ });
536
+ };
537
+
538
+ // Get selected rows and move selection out of scope
539
+ rows = getSelectedRows();
540
+
541
+ // Delete all selected rows
542
+ each(rows.reverse(), function(tr) {
543
+ deleteRow(tr);
544
+ });
545
+
546
+ cleanup();
547
+ };
548
+
549
+ function cutRows() {
550
+ var rows = getSelectedRows();
551
+
552
+ dom.remove(rows);
553
+ cleanup();
554
+
555
+ return rows;
556
+ };
557
+
558
+ function copyRows() {
559
+ var rows = getSelectedRows();
560
+
561
+ each(rows, function(row, i) {
562
+ rows[i] = cloneNode(row, true);
563
+ });
564
+
565
+ return rows;
566
+ };
567
+
568
+ function pasteRows(rows, before) {
569
+ var selectedRows = getSelectedRows(),
570
+ targetRow = selectedRows[before ? 0 : selectedRows.length - 1],
571
+ targetCellCount = targetRow.cells.length;
572
+
573
+ // Calc target cell count
574
+ each(grid, function(row) {
575
+ var match;
576
+
577
+ targetCellCount = 0;
578
+ each(row, function(cell, x) {
579
+ if (cell.real)
580
+ targetCellCount += cell.colspan;
581
+
582
+ if (cell.elm.parentNode == targetRow)
583
+ match = 1;
584
+ });
585
+
586
+ if (match)
587
+ return false;
588
+ });
589
+
590
+ if (!before)
591
+ rows.reverse();
592
+
593
+ each(rows, function(row) {
594
+ var cellCount = row.cells.length, cell;
595
+
596
+ // Remove col/rowspans
597
+ for (i = 0; i < cellCount; i++) {
598
+ cell = row.cells[i];
599
+ setSpanVal(cell, 'colSpan', 1);
600
+ setSpanVal(cell, 'rowSpan', 1);
601
+ }
602
+
603
+ // Needs more cells
604
+ for (i = cellCount; i < targetCellCount; i++)
605
+ row.appendChild(cloneCell(row.cells[cellCount - 1]));
606
+
607
+ // Needs less cells
608
+ for (i = targetCellCount; i < cellCount; i++)
609
+ dom.remove(row.cells[i]);
610
+
611
+ // Add before/after
612
+ if (before)
613
+ targetRow.parentNode.insertBefore(row, targetRow);
614
+ else
615
+ dom.insertAfter(row, targetRow);
616
+ });
617
+
618
+ // Remove current selection
619
+ dom.removeClass(dom.select('td.mceSelected,th.mceSelected'), 'mceSelected');
620
+ };
621
+
622
+ function getPos(target) {
623
+ var pos;
624
+
625
+ each(grid, function(row, y) {
626
+ each(row, function(cell, x) {
627
+ if (cell.elm == target) {
628
+ pos = {x : x, y : y};
629
+ return false;
630
+ }
631
+ });
632
+
633
+ return !pos;
634
+ });
635
+
636
+ return pos;
637
+ };
638
+
639
+ function setStartCell(cell) {
640
+ startPos = getPos(cell);
641
+ };
642
+
643
+ function findEndPos() {
644
+ var pos, maxX, maxY;
645
+
646
+ maxX = maxY = 0;
647
+
648
+ each(grid, function(row, y) {
649
+ each(row, function(cell, x) {
650
+ var colSpan, rowSpan;
651
+
652
+ if (isCellSelected(cell)) {
653
+ cell = grid[y][x];
654
+
655
+ if (x > maxX)
656
+ maxX = x;
657
+
658
+ if (y > maxY)
659
+ maxY = y;
660
+
661
+ if (cell.real) {
662
+ colSpan = cell.colspan - 1;
663
+ rowSpan = cell.rowspan - 1;
664
+
665
+ if (colSpan) {
666
+ if (x + colSpan > maxX)
667
+ maxX = x + colSpan;
668
+ }
669
+
670
+ if (rowSpan) {
671
+ if (y + rowSpan > maxY)
672
+ maxY = y + rowSpan;
673
+ }
674
+ }
675
+ }
676
+ });
677
+ });
678
+
679
+ return {x : maxX, y : maxY};
680
+ };
681
+
682
+ function setEndCell(cell) {
683
+ var startX, startY, endX, endY, maxX, maxY, colSpan, rowSpan;
684
+
685
+ endPos = getPos(cell);
686
+
687
+ if (startPos && endPos) {
688
+ // Get start/end positions
689
+ startX = Math.min(startPos.x, endPos.x);
690
+ startY = Math.min(startPos.y, endPos.y);
691
+ endX = Math.max(startPos.x, endPos.x);
692
+ endY = Math.max(startPos.y, endPos.y);
693
+
694
+ // Expand end positon to include spans
695
+ maxX = endX;
696
+ maxY = endY;
697
+
698
+ // Expand startX
699
+ for (y = startY; y <= maxY; y++) {
700
+ cell = grid[y][startX];
701
+
702
+ if (!cell.real) {
703
+ if (startX - (cell.colspan - 1) < startX)
704
+ startX -= cell.colspan - 1;
705
+ }
706
+ }
707
+
708
+ // Expand startY
709
+ for (x = startX; x <= maxX; x++) {
710
+ cell = grid[startY][x];
711
+
712
+ if (!cell.real) {
713
+ if (startY - (cell.rowspan - 1) < startY)
714
+ startY -= cell.rowspan - 1;
715
+ }
716
+ }
717
+
718
+ // Find max X, Y
719
+ for (y = startY; y <= endY; y++) {
720
+ for (x = startX; x <= endX; x++) {
721
+ cell = grid[y][x];
722
+
723
+ if (cell.real) {
724
+ colSpan = cell.colspan - 1;
725
+ rowSpan = cell.rowspan - 1;
726
+
727
+ if (colSpan) {
728
+ if (x + colSpan > maxX)
729
+ maxX = x + colSpan;
730
+ }
731
+
732
+ if (rowSpan) {
733
+ if (y + rowSpan > maxY)
734
+ maxY = y + rowSpan;
735
+ }
736
+ }
737
+ }
738
+ }
739
+
740
+ // Remove current selection
741
+ dom.removeClass(dom.select('td.mceSelected,th.mceSelected'), 'mceSelected');
742
+
743
+ // Add new selection
744
+ for (y = startY; y <= maxY; y++) {
745
+ for (x = startX; x <= maxX; x++) {
746
+ if (grid[y][x])
747
+ dom.addClass(grid[y][x].elm, 'mceSelected');
748
+ }
749
+ }
750
+ }
751
+ };
752
+
753
+ // Expose to public
754
+ tinymce.extend(this, {
755
+ deleteTable : deleteTable,
756
+ split : split,
757
+ merge : merge,
758
+ insertRow : insertRow,
759
+ insertCol : insertCol,
760
+ deleteCols : deleteCols,
761
+ deleteRows : deleteRows,
762
+ cutRows : cutRows,
763
+ copyRows : copyRows,
764
+ pasteRows : pasteRows,
765
+ getPos : getPos,
766
+ setStartCell : setStartCell,
767
+ setEndCell : setEndCell
768
+ });
769
+ };
770
+
771
+ tinymce.create('tinymce.plugins.TablePlugin', {
772
+ init : function(ed, url) {
773
+ var winMan, clipboardRows, hasCellSelection = true; // Might be selected cells on reload
774
+
775
+ function createTableGrid(node) {
776
+ var selection = ed.selection, tblElm = ed.dom.getParent(node || selection.getNode(), 'table');
777
+
778
+ if (tblElm)
779
+ return new TableGrid(tblElm, ed.dom, selection);
780
+ };
781
+
782
+ function cleanup() {
783
+ // Restore selection possibilities
784
+ ed.getBody().style.webkitUserSelect = '';
785
+
786
+ if (hasCellSelection) {
787
+ ed.dom.removeClass(ed.dom.select('td.mceSelected,th.mceSelected'), 'mceSelected');
788
+ hasCellSelection = false;
789
+ }
790
+ };
791
+
792
+ // Register buttons
793
+ each([
794
+ ['table', 'table.desc', 'mceInsertTable', true],
795
+ ['delete_table', 'table.del', 'mceTableDelete'],
796
+ ['delete_col', 'table.delete_col_desc', 'mceTableDeleteCol'],
797
+ ['delete_row', 'table.delete_row_desc', 'mceTableDeleteRow'],
798
+ ['col_after', 'table.col_after_desc', 'mceTableInsertColAfter'],
799
+ ['col_before', 'table.col_before_desc', 'mceTableInsertColBefore'],
800
+ ['row_after', 'table.row_after_desc', 'mceTableInsertRowAfter'],
801
+ ['row_before', 'table.row_before_desc', 'mceTableInsertRowBefore'],
802
+ ['row_props', 'table.row_desc', 'mceTableRowProps', true],
803
+ ['cell_props', 'table.cell_desc', 'mceTableCellProps', true],
804
+ ['split_cells', 'table.split_cells_desc', 'mceTableSplitCells', true],
805
+ ['merge_cells', 'table.merge_cells_desc', 'mceTableMergeCells', true]
806
+ ], function(c) {
807
+ ed.addButton(c[0], {title : c[1], cmd : c[2], ui : c[3]});
808
+ });
809
+
810
+ // Select whole table is a table border is clicked
811
+ if (!tinymce.isIE) {
812
+ ed.onClick.add(function(ed, e) {
813
+ e = e.target;
814
+
815
+ if (e.nodeName === 'TABLE') {
816
+ ed.selection.select(e);
817
+ ed.nodeChanged();
818
+ }
819
+ });
820
+ }
821
+
822
+ ed.onPreProcess.add(function(ed, args) {
823
+ var nodes, i, node, dom = ed.dom, value;
824
+
825
+ nodes = dom.select('table', args.node);
826
+ i = nodes.length;
827
+ while (i--) {
828
+ node = nodes[i];
829
+ dom.setAttrib(node, 'data-mce-style', '');
830
+
831
+ if ((value = dom.getAttrib(node, 'width'))) {
832
+ dom.setStyle(node, 'width', value);
833
+ dom.setAttrib(node, 'width', '');
834
+ }
835
+
836
+ if ((value = dom.getAttrib(node, 'height'))) {
837
+ dom.setStyle(node, 'height', value);
838
+ dom.setAttrib(node, 'height', '');
839
+ }
840
+ }
841
+ });
842
+
843
+ // Handle node change updates
844
+ ed.onNodeChange.add(function(ed, cm, n) {
845
+ var p;
846
+
847
+ n = ed.selection.getStart();
848
+ p = ed.dom.getParent(n, 'td,th,caption');
849
+ cm.setActive('table', n.nodeName === 'TABLE' || !!p);
850
+
851
+ // Disable table tools if we are in caption
852
+ if (p && p.nodeName === 'CAPTION')
853
+ p = 0;
854
+
855
+ cm.setDisabled('delete_table', !p);
856
+ cm.setDisabled('delete_col', !p);
857
+ cm.setDisabled('delete_table', !p);
858
+ cm.setDisabled('delete_row', !p);
859
+ cm.setDisabled('col_after', !p);
860
+ cm.setDisabled('col_before', !p);
861
+ cm.setDisabled('row_after', !p);
862
+ cm.setDisabled('row_before', !p);
863
+ cm.setDisabled('row_props', !p);
864
+ cm.setDisabled('cell_props', !p);
865
+ cm.setDisabled('split_cells', !p);
866
+ cm.setDisabled('merge_cells', !p);
867
+ });
868
+
869
+ ed.onInit.add(function(ed) {
870
+ var startTable, startCell, dom = ed.dom, tableGrid;
871
+
872
+ winMan = ed.windowManager;
873
+
874
+ // Add cell selection logic
875
+ ed.onMouseDown.add(function(ed, e) {
876
+ if (e.button != 2) {
877
+ cleanup();
878
+
879
+ startCell = dom.getParent(e.target, 'td,th');
880
+ startTable = dom.getParent(startCell, 'table');
881
+ }
882
+ });
883
+
884
+ dom.bind(ed.getDoc(), 'mouseover', function(e) {
885
+ var sel, table, target = e.target;
886
+
887
+ if (startCell && (tableGrid || target != startCell) && (target.nodeName == 'TD' || target.nodeName == 'TH')) {
888
+ table = dom.getParent(target, 'table');
889
+ if (table == startTable) {
890
+ if (!tableGrid) {
891
+ tableGrid = createTableGrid(table);
892
+ tableGrid.setStartCell(startCell);
893
+
894
+ ed.getBody().style.webkitUserSelect = 'none';
895
+ }
896
+
897
+ tableGrid.setEndCell(target);
898
+ hasCellSelection = true;
899
+ }
900
+
901
+ // Remove current selection
902
+ sel = ed.selection.getSel();
903
+
904
+ try {
905
+ if (sel.removeAllRanges)
906
+ sel.removeAllRanges();
907
+ else
908
+ sel.empty();
909
+ } catch (ex) {
910
+ // IE9 might throw errors here
911
+ }
912
+
913
+ e.preventDefault();
914
+ }
915
+ });
916
+
917
+ ed.onMouseUp.add(function(ed, e) {
918
+ var rng, sel = ed.selection, selectedCells, nativeSel = sel.getSel(), walker, node, lastNode, endNode;
919
+
920
+ // Move selection to startCell
921
+ if (startCell) {
922
+ if (tableGrid)
923
+ ed.getBody().style.webkitUserSelect = '';
924
+
925
+ function setPoint(node, start) {
926
+ var walker = new tinymce.dom.TreeWalker(node, node);
927
+
928
+ do {
929
+ // Text node
930
+ if (node.nodeType == 3 && tinymce.trim(node.nodeValue).length != 0) {
931
+ if (start)
932
+ rng.setStart(node, 0);
933
+ else
934
+ rng.setEnd(node, node.nodeValue.length);
935
+
936
+ return;
937
+ }
938
+
939
+ // BR element
940
+ if (node.nodeName == 'BR') {
941
+ if (start)
942
+ rng.setStartBefore(node);
943
+ else
944
+ rng.setEndBefore(node);
945
+
946
+ return;
947
+ }
948
+ } while (node = (start ? walker.next() : walker.prev()));
949
+ }
950
+
951
+ // Try to expand text selection as much as we can only Gecko supports cell selection
952
+ selectedCells = dom.select('td.mceSelected,th.mceSelected');
953
+ if (selectedCells.length > 0) {
954
+ rng = dom.createRng();
955
+ node = selectedCells[0];
956
+ endNode = selectedCells[selectedCells.length - 1];
957
+ rng.setStartBefore(node);
958
+ rng.setEndAfter(node);
959
+
960
+ setPoint(node, 1);
961
+ walker = new tinymce.dom.TreeWalker(node, dom.getParent(selectedCells[0], 'table'));
962
+
963
+ do {
964
+ if (node.nodeName == 'TD' || node.nodeName == 'TH') {
965
+ if (!dom.hasClass(node, 'mceSelected'))
966
+ break;
967
+
968
+ lastNode = node;
969
+ }
970
+ } while (node = walker.next());
971
+
972
+ setPoint(lastNode);
973
+
974
+ sel.setRng(rng);
975
+ }
976
+
977
+ ed.nodeChanged();
978
+ startCell = tableGrid = startTable = null;
979
+ }
980
+ });
981
+
982
+ ed.onKeyUp.add(function(ed, e) {
983
+ cleanup();
984
+ });
985
+
986
+ ed.onKeyDown.add(function (ed, e) {
987
+ fixTableCellSelection(ed);
988
+ });
989
+
990
+ ed.onMouseDown.add(function (ed, e) {
991
+ if (e.button != 2) {
992
+ fixTableCellSelection(ed);
993
+ }
994
+ });
995
+ function tableCellSelected(ed, rng, n, currentCell) {
996
+ // The decision of when a table cell is selected is somewhat involved. The fact that this code is
997
+ // required is actually a pointer to the root cause of this bug. A cell is selected when the start
998
+ // and end offsets are 0, the start container is a text, and the selection node is either a TR (most cases)
999
+ // or the parent of the table (in the case of the selection containing the last cell of a table).
1000
+ var TEXT_NODE = 3, table = ed.dom.getParent(rng.startContainer, 'TABLE'),
1001
+ tableParent, allOfCellSelected, tableCellSelection;
1002
+ if (table)
1003
+ tableParent = table.parentNode;
1004
+ allOfCellSelected =rng.startContainer.nodeType == TEXT_NODE &&
1005
+ rng.startOffset == 0 &&
1006
+ rng.endOffset == 0 &&
1007
+ currentCell &&
1008
+ (n.nodeName=="TR" || n==tableParent);
1009
+ tableCellSelection = (n.nodeName=="TD"||n.nodeName=="TH")&& !currentCell;
1010
+ return allOfCellSelected || tableCellSelection;
1011
+ // return false;
1012
+ }
1013
+
1014
+ // this nasty hack is here to work around some WebKit selection bugs.
1015
+ function fixTableCellSelection(ed) {
1016
+ if (!tinymce.isWebKit)
1017
+ return;
1018
+
1019
+ var rng = ed.selection.getRng();
1020
+ var n = ed.selection.getNode();
1021
+ var currentCell = ed.dom.getParent(rng.startContainer, 'TD,TH');
1022
+
1023
+ if (!tableCellSelected(ed, rng, n, currentCell))
1024
+ return;
1025
+ if (!currentCell) {
1026
+ currentCell=n;
1027
+ }
1028
+
1029
+ // Get the very last node inside the table cell
1030
+ var end = currentCell.lastChild;
1031
+ while (end.lastChild)
1032
+ end = end.lastChild;
1033
+
1034
+ // Select the entire table cell. Nothing outside of the table cell should be selected.
1035
+ rng.setEnd(end, end.nodeValue.length);
1036
+ ed.selection.setRng(rng);
1037
+ }
1038
+ ed.plugins.table.fixTableCellSelection=fixTableCellSelection;
1039
+
1040
+ // Add context menu
1041
+ if (ed && ed.plugins.contextmenu) {
1042
+ ed.plugins.contextmenu.onContextMenu.add(function(th, m, e) {
1043
+ var sm, se = ed.selection, el = se.getNode() || ed.getBody();
1044
+
1045
+ if (ed.dom.getParent(e, 'td') || ed.dom.getParent(e, 'th') || ed.dom.select('td.mceSelected,th.mceSelected').length) {
1046
+ m.removeAll();
1047
+
1048
+ if (el.nodeName == 'A' && !ed.dom.getAttrib(el, 'name')) {
1049
+ m.add({title : 'advanced.link_desc', icon : 'link', cmd : ed.plugins.advlink ? 'mceAdvLink' : 'mceLink', ui : true});
1050
+ m.add({title : 'advanced.unlink_desc', icon : 'unlink', cmd : 'UnLink'});
1051
+ m.addSeparator();
1052
+ }
1053
+
1054
+ if (el.nodeName == 'IMG' && el.className.indexOf('mceItem') == -1) {
1055
+ m.add({title : 'advanced.image_desc', icon : 'image', cmd : ed.plugins.advimage ? 'mceAdvImage' : 'mceImage', ui : true});
1056
+ m.addSeparator();
1057
+ }
1058
+
1059
+ m.add({title : 'table.desc', icon : 'table', cmd : 'mceInsertTable', value : {action : 'insert'}});
1060
+ m.add({title : 'table.props_desc', icon : 'table_props', cmd : 'mceInsertTable'});
1061
+ m.add({title : 'table.del', icon : 'delete_table', cmd : 'mceTableDelete'});
1062
+ m.addSeparator();
1063
+
1064
+ // Cell menu
1065
+ sm = m.addMenu({title : 'table.cell'});
1066
+ sm.add({title : 'table.cell_desc', icon : 'cell_props', cmd : 'mceTableCellProps'});
1067
+ sm.add({title : 'table.split_cells_desc', icon : 'split_cells', cmd : 'mceTableSplitCells'});
1068
+ sm.add({title : 'table.merge_cells_desc', icon : 'merge_cells', cmd : 'mceTableMergeCells'});
1069
+
1070
+ // Row menu
1071
+ sm = m.addMenu({title : 'table.row'});
1072
+ sm.add({title : 'table.row_desc', icon : 'row_props', cmd : 'mceTableRowProps'});
1073
+ sm.add({title : 'table.row_before_desc', icon : 'row_before', cmd : 'mceTableInsertRowBefore'});
1074
+ sm.add({title : 'table.row_after_desc', icon : 'row_after', cmd : 'mceTableInsertRowAfter'});
1075
+ sm.add({title : 'table.delete_row_desc', icon : 'delete_row', cmd : 'mceTableDeleteRow'});
1076
+ sm.addSeparator();
1077
+ sm.add({title : 'table.cut_row_desc', icon : 'cut', cmd : 'mceTableCutRow'});
1078
+ sm.add({title : 'table.copy_row_desc', icon : 'copy', cmd : 'mceTableCopyRow'});
1079
+ sm.add({title : 'table.paste_row_before_desc', icon : 'paste', cmd : 'mceTablePasteRowBefore'}).setDisabled(!clipboardRows);
1080
+ sm.add({title : 'table.paste_row_after_desc', icon : 'paste', cmd : 'mceTablePasteRowAfter'}).setDisabled(!clipboardRows);
1081
+
1082
+ // Column menu
1083
+ sm = m.addMenu({title : 'table.col'});
1084
+ sm.add({title : 'table.col_before_desc', icon : 'col_before', cmd : 'mceTableInsertColBefore'});
1085
+ sm.add({title : 'table.col_after_desc', icon : 'col_after', cmd : 'mceTableInsertColAfter'});
1086
+ sm.add({title : 'table.delete_col_desc', icon : 'delete_col', cmd : 'mceTableDeleteCol'});
1087
+ } else
1088
+ m.add({title : 'table.desc', icon : 'table', cmd : 'mceInsertTable'});
1089
+ });
1090
+ }
1091
+
1092
+ // Fix to allow navigating up and down in a table in WebKit browsers.
1093
+ if (tinymce.isWebKit) {
1094
+ function moveSelection(ed, e) {
1095
+ var VK = tinymce.VK;
1096
+ var key = e.keyCode;
1097
+
1098
+ function handle(upBool, sourceNode, event) {
1099
+ var siblingDirection = upBool ? 'previousSibling' : 'nextSibling';
1100
+ var currentRow = ed.dom.getParent(sourceNode, 'tr');
1101
+ var siblingRow = currentRow[siblingDirection];
1102
+
1103
+ if (siblingRow) {
1104
+ moveCursorToRow(ed, sourceNode, siblingRow, upBool);
1105
+ tinymce.dom.Event.cancel(event);
1106
+ return true;
1107
+ } else {
1108
+ var tableNode = ed.dom.getParent(currentRow, 'table');
1109
+ var middleNode = currentRow.parentNode;
1110
+ var parentNodeName = middleNode.nodeName.toLowerCase();
1111
+ if (parentNodeName === 'tbody' || parentNodeName === (upBool ? 'tfoot' : 'thead')) {
1112
+ var targetParent = getTargetParent(upBool, tableNode, middleNode, 'tbody');
1113
+ if (targetParent !== null) {
1114
+ return moveToRowInTarget(upBool, targetParent, sourceNode, event);
1115
+ }
1116
+ }
1117
+ return escapeTable(upBool, currentRow, siblingDirection, tableNode, event);
1118
+ }
1119
+ }
1120
+
1121
+ function getTargetParent(upBool, topNode, secondNode, nodeName) {
1122
+ var tbodies = ed.dom.select('>' + nodeName, topNode);
1123
+ var position = tbodies.indexOf(secondNode);
1124
+ if (upBool && position === 0 || !upBool && position === tbodies.length - 1) {
1125
+ return getFirstHeadOrFoot(upBool, topNode);
1126
+ } else if (position === -1) {
1127
+ var topOrBottom = secondNode.tagName.toLowerCase() === 'thead' ? 0 : tbodies.length - 1;
1128
+ return tbodies[topOrBottom];
1129
+ } else {
1130
+ return tbodies[position + (upBool ? -1 : 1)];
1131
+ }
1132
+ }
1133
+
1134
+ function getFirstHeadOrFoot(upBool, parent) {
1135
+ var tagName = upBool ? 'thead' : 'tfoot';
1136
+ var headOrFoot = ed.dom.select('>' + tagName, parent);
1137
+ return headOrFoot.length !== 0 ? headOrFoot[0] : null;
1138
+ }
1139
+
1140
+ function moveToRowInTarget(upBool, targetParent, sourceNode, event) {
1141
+ var targetRow = getChildForDirection(targetParent, upBool);
1142
+ targetRow && moveCursorToRow(ed, sourceNode, targetRow, upBool);
1143
+ tinymce.dom.Event.cancel(event);
1144
+ return true;
1145
+ }
1146
+
1147
+ function escapeTable(upBool, currentRow, siblingDirection, table, event) {
1148
+ var tableSibling = table[siblingDirection];
1149
+ if (tableSibling) {
1150
+ moveCursorToStartOfElement(tableSibling);
1151
+ return true;
1152
+ } else {
1153
+ var parentCell = ed.dom.getParent(table, 'td,th');
1154
+ if (parentCell) {
1155
+ return handle(upBool, parentCell, event);
1156
+ } else {
1157
+ var backUpSibling = getChildForDirection(currentRow, !upBool);
1158
+ moveCursorToStartOfElement(backUpSibling);
1159
+ return tinymce.dom.Event.cancel(event);
1160
+ }
1161
+ }
1162
+ }
1163
+
1164
+ function getChildForDirection(parent, up) {
1165
+ var child = parent && parent[up ? 'lastChild' : 'firstChild'];
1166
+ // BR is not a valid table child to return in this case we return the table cell
1167
+ return child && child.nodeName === 'BR' ? ed.dom.getParent(child, 'td,th') : child;
1168
+ }
1169
+
1170
+ function moveCursorToStartOfElement(n) {
1171
+ ed.selection.setCursorLocation(n, 0);
1172
+ }
1173
+
1174
+ function isVerticalMovement() {
1175
+ return key == VK.UP || key == VK.DOWN;
1176
+ }
1177
+
1178
+ function isInTable(ed) {
1179
+ var node = ed.selection.getNode();
1180
+ var currentRow = ed.dom.getParent(node, 'tr');
1181
+ return currentRow !== null;
1182
+ }
1183
+
1184
+ function columnIndex(column) {
1185
+ var colIndex = 0;
1186
+ var c = column;
1187
+ while (c.previousSibling) {
1188
+ c = c.previousSibling;
1189
+ colIndex = colIndex + getSpanVal(c, "colspan");
1190
+ }
1191
+ return colIndex;
1192
+ }
1193
+
1194
+ function findColumn(rowElement, columnIndex) {
1195
+ var c = 0;
1196
+ var r = 0;
1197
+ each(rowElement.children, function(cell, i) {
1198
+ c = c + getSpanVal(cell, "colspan");
1199
+ r = i;
1200
+ if (c > columnIndex)
1201
+ return false;
1202
+ });
1203
+ return r;
1204
+ }
1205
+
1206
+ function moveCursorToRow(ed, node, row, upBool) {
1207
+ var srcColumnIndex = columnIndex(ed.dom.getParent(node, 'td,th'));
1208
+ var tgtColumnIndex = findColumn(row, srcColumnIndex);
1209
+ var tgtNode = row.childNodes[tgtColumnIndex];
1210
+ var rowCellTarget = getChildForDirection(tgtNode, upBool);
1211
+ moveCursorToStartOfElement(rowCellTarget || tgtNode);
1212
+ }
1213
+
1214
+ function shouldFixCaret(preBrowserNode) {
1215
+ var newNode = ed.selection.getNode();
1216
+ var newParent = ed.dom.getParent(newNode, 'td,th');
1217
+ var oldParent = ed.dom.getParent(preBrowserNode, 'td,th');
1218
+ return newParent && newParent !== oldParent && checkSameParentTable(newParent, oldParent)
1219
+ }
1220
+
1221
+ function checkSameParentTable(nodeOne, NodeTwo) {
1222
+ return ed.dom.getParent(nodeOne, 'TABLE') === ed.dom.getParent(NodeTwo, 'TABLE');
1223
+ }
1224
+
1225
+ if (isVerticalMovement() && isInTable(ed)) {
1226
+ var preBrowserNode = ed.selection.getNode();
1227
+ setTimeout(function() {
1228
+ if (shouldFixCaret(preBrowserNode)) {
1229
+ handle(!e.shiftKey && key === VK.UP, preBrowserNode, e);
1230
+ }
1231
+ }, 0);
1232
+ }
1233
+ }
1234
+
1235
+ ed.onKeyDown.add(moveSelection);
1236
+ }
1237
+
1238
+ // Fixes an issue on Gecko where it's impossible to place the caret behind a table
1239
+ // This fix will force a paragraph element after the table but only when the forced_root_block setting is enabled
1240
+ function fixTableCaretPos() {
1241
+ var last;
1242
+
1243
+ // Skip empty text nodes form the end
1244
+ for (last = ed.getBody().lastChild; last && last.nodeType == 3 && !last.nodeValue.length; last = last.previousSibling) ;
1245
+
1246
+ if (last && last.nodeName == 'TABLE') {
1247
+ if (ed.settings.forced_root_block)
1248
+ ed.dom.add(ed.getBody(), ed.settings.forced_root_block, null, tinymce.isIE ? '&nbsp;' : '<br data-mce-bogus="1" />');
1249
+ else
1250
+ ed.dom.add(ed.getBody(), 'br', {'data-mce-bogus': '1'});
1251
+ }
1252
+ };
1253
+
1254
+ // Fixes an bug where it's impossible to place the caret before a table in Gecko
1255
+ // this fix solves it by detecting when the caret is at the beginning of such a table
1256
+ // and then manually moves the caret infront of the table
1257
+ if (tinymce.isGecko) {
1258
+ ed.onKeyDown.add(function(ed, e) {
1259
+ var rng, table, dom = ed.dom;
1260
+
1261
+ // On gecko it's not possible to place the caret before a table
1262
+ if (e.keyCode == 37 || e.keyCode == 38) {
1263
+ rng = ed.selection.getRng();
1264
+ table = dom.getParent(rng.startContainer, 'table');
1265
+
1266
+ if (table && ed.getBody().firstChild == table) {
1267
+ if (isAtStart(rng, table)) {
1268
+ rng = dom.createRng();
1269
+
1270
+ rng.setStartBefore(table);
1271
+ rng.setEndBefore(table);
1272
+
1273
+ ed.selection.setRng(rng);
1274
+
1275
+ e.preventDefault();
1276
+ }
1277
+ }
1278
+ }
1279
+ });
1280
+ }
1281
+
1282
+ ed.onKeyUp.add(fixTableCaretPos);
1283
+ ed.onSetContent.add(fixTableCaretPos);
1284
+ ed.onVisualAid.add(fixTableCaretPos);
1285
+
1286
+ ed.onPreProcess.add(function(ed, o) {
1287
+ var last = o.node.lastChild;
1288
+
1289
+ if (last && (last.nodeName == "BR" || (last.childNodes.length == 1 && (last.firstChild.nodeName == 'BR' || last.firstChild.nodeValue == '\u00a0'))) && last.previousSibling && last.previousSibling.nodeName == "TABLE") {
1290
+ ed.dom.remove(last);
1291
+ }
1292
+ });
1293
+
1294
+
1295
+ /**
1296
+ * Fixes bug in Gecko where shift-enter in table cell does not place caret on new line
1297
+ */
1298
+ if (tinymce.isGecko) {
1299
+ ed.onKeyDown.add(function(ed, e) {
1300
+ if (e.keyCode === tinymce.VK.ENTER && e.shiftKey) {
1301
+ var node = ed.selection.getRng().startContainer;
1302
+ var tableCell = dom.getParent(node, 'td,th');
1303
+ if (tableCell) {
1304
+ var zeroSizedNbsp = ed.getDoc().createTextNode("\uFEFF");
1305
+ dom.insertAfter(zeroSizedNbsp, node);
1306
+ }
1307
+ }
1308
+ });
1309
+ }
1310
+
1311
+
1312
+ fixTableCaretPos();
1313
+ ed.startContent = ed.getContent({format : 'raw'});
1314
+ });
1315
+
1316
+ // Register action commands
1317
+ each({
1318
+ mceTableSplitCells : function(grid) {
1319
+ grid.split();
1320
+ },
1321
+
1322
+ mceTableMergeCells : function(grid) {
1323
+ var rowSpan, colSpan, cell;
1324
+
1325
+ cell = ed.dom.getParent(ed.selection.getNode(), 'th,td');
1326
+ if (cell) {
1327
+ rowSpan = cell.rowSpan;
1328
+ colSpan = cell.colSpan;
1329
+ }
1330
+
1331
+ if (!ed.dom.select('td.mceSelected,th.mceSelected').length) {
1332
+ winMan.open({
1333
+ url : url + '/merge_cells.htm',
1334
+ width : 240 + parseInt(ed.getLang('table.merge_cells_delta_width', 0)),
1335
+ height : 110 + parseInt(ed.getLang('table.merge_cells_delta_height', 0)),
1336
+ inline : 1
1337
+ }, {
1338
+ rows : rowSpan,
1339
+ cols : colSpan,
1340
+ onaction : function(data) {
1341
+ grid.merge(cell, data.cols, data.rows);
1342
+ },
1343
+ plugin_url : url
1344
+ });
1345
+ } else
1346
+ grid.merge();
1347
+ },
1348
+
1349
+ mceTableInsertRowBefore : function(grid) {
1350
+ grid.insertRow(true);
1351
+ },
1352
+
1353
+ mceTableInsertRowAfter : function(grid) {
1354
+ grid.insertRow();
1355
+ },
1356
+
1357
+ mceTableInsertColBefore : function(grid) {
1358
+ grid.insertCol(true);
1359
+ },
1360
+
1361
+ mceTableInsertColAfter : function(grid) {
1362
+ grid.insertCol();
1363
+ },
1364
+
1365
+ mceTableDeleteCol : function(grid) {
1366
+ grid.deleteCols();
1367
+ },
1368
+
1369
+ mceTableDeleteRow : function(grid) {
1370
+ grid.deleteRows();
1371
+ },
1372
+
1373
+ mceTableCutRow : function(grid) {
1374
+ clipboardRows = grid.cutRows();
1375
+ },
1376
+
1377
+ mceTableCopyRow : function(grid) {
1378
+ clipboardRows = grid.copyRows();
1379
+ },
1380
+
1381
+ mceTablePasteRowBefore : function(grid) {
1382
+ grid.pasteRows(clipboardRows, true);
1383
+ },
1384
+
1385
+ mceTablePasteRowAfter : function(grid) {
1386
+ grid.pasteRows(clipboardRows);
1387
+ },
1388
+
1389
+ mceTableDelete : function(grid) {
1390
+ grid.deleteTable();
1391
+ }
1392
+ }, function(func, name) {
1393
+ ed.addCommand(name, function() {
1394
+ var grid = createTableGrid();
1395
+
1396
+ if (grid) {
1397
+ func(grid);
1398
+ ed.execCommand('mceRepaint');
1399
+ cleanup();
1400
+ }
1401
+ });
1402
+ });
1403
+
1404
+ // Register dialog commands
1405
+ each({
1406
+ mceInsertTable : function(val) {
1407
+ winMan.open({
1408
+ url : url + '/table.htm',
1409
+ width : 400 + parseInt(ed.getLang('table.table_delta_width', 0)),
1410
+ height : 320 + parseInt(ed.getLang('table.table_delta_height', 0)),
1411
+ inline : 1
1412
+ }, {
1413
+ plugin_url : url,
1414
+ action : val ? val.action : 0
1415
+ });
1416
+ },
1417
+
1418
+ mceTableRowProps : function() {
1419
+ winMan.open({
1420
+ url : url + '/row.htm',
1421
+ width : 400 + parseInt(ed.getLang('table.rowprops_delta_width', 0)),
1422
+ height : 295 + parseInt(ed.getLang('table.rowprops_delta_height', 0)),
1423
+ inline : 1
1424
+ }, {
1425
+ plugin_url : url
1426
+ });
1427
+ },
1428
+
1429
+ mceTableCellProps : function() {
1430
+ winMan.open({
1431
+ url : url + '/cell.htm',
1432
+ width : 400 + parseInt(ed.getLang('table.cellprops_delta_width', 0)),
1433
+ height : 295 + parseInt(ed.getLang('table.cellprops_delta_height', 0)),
1434
+ inline : 1
1435
+ }, {
1436
+ plugin_url : url
1437
+ });
1438
+ }
1439
+ }, function(func, name) {
1440
+ ed.addCommand(name, function(ui, val) {
1441
+ func(val);
1442
+ });
1443
+ });
1444
+ }
1445
+ });
1446
+
1447
+ // Register plugin
1448
+ tinymce.PluginManager.add('table', tinymce.plugins.TablePlugin);
1449
+ })(tinymce);