1 /** |
|
2 * plugin.js |
|
3 * |
|
4 * Copyright, Moxiecode Systems AB |
|
5 * Released under LGPL License. |
|
6 * |
|
7 * License: http://www.tinymce.com/license |
|
8 * Contributing: http://www.tinymce.com/contributing |
|
9 */ |
|
10 |
|
11 /*global tinymce:true */ |
|
12 |
|
13 tinymce.PluginManager.add('layer', function(editor) { |
|
14 function getParentLayer(node) { |
|
15 do { |
|
16 if (node.className && node.className.indexOf('mceItemLayer') != -1) { |
|
17 return node; |
|
18 } |
|
19 } while ((node = node.parentNode)); |
|
20 } |
|
21 |
|
22 function visualAid(e) { |
|
23 var dom = editor.dom; |
|
24 |
|
25 tinymce.each(dom.select('div,p', e), function(e) { |
|
26 if (/^(absolute|relative|fixed)$/i.test(e.style.position)) { |
|
27 if (e.hasVisual) { |
|
28 dom.addClass(e, 'mceItemVisualAid'); |
|
29 } else { |
|
30 dom.removeClass(e, 'mceItemVisualAid'); |
|
31 } |
|
32 |
|
33 dom.addClass(e, 'mceItemLayer'); |
|
34 } |
|
35 }); |
|
36 } |
|
37 |
|
38 function move(d) { |
|
39 var i, z = [], le = getParentLayer(editor.selection.getNode()), ci = -1, fi = -1, nl; |
|
40 |
|
41 nl = []; |
|
42 tinymce.walk(editor.getBody(), function(n) { |
|
43 if (n.nodeType == 1 && /^(absolute|relative|static)$/i.test(n.style.position)) { |
|
44 nl.push(n); |
|
45 } |
|
46 }, 'childNodes'); |
|
47 |
|
48 // Find z-indexes |
|
49 for (i = 0; i < nl.length; i++) { |
|
50 z[i] = nl[i].style.zIndex ? parseInt(nl[i].style.zIndex, 10) : 0; |
|
51 |
|
52 if (ci < 0 && nl[i] == le) { |
|
53 ci = i; |
|
54 } |
|
55 } |
|
56 |
|
57 if (d < 0) { |
|
58 // Move back |
|
59 |
|
60 // Try find a lower one |
|
61 for (i = 0; i < z.length; i++) { |
|
62 if (z[i] < z[ci]) { |
|
63 fi = i; |
|
64 break; |
|
65 } |
|
66 } |
|
67 |
|
68 if (fi > -1) { |
|
69 nl[ci].style.zIndex = z[fi]; |
|
70 nl[fi].style.zIndex = z[ci]; |
|
71 } else { |
|
72 if (z[ci] > 0) { |
|
73 nl[ci].style.zIndex = z[ci] - 1; |
|
74 } |
|
75 } |
|
76 } else { |
|
77 // Move forward |
|
78 |
|
79 // Try find a higher one |
|
80 for (i = 0; i < z.length; i++) { |
|
81 if (z[i] > z[ci]) { |
|
82 fi = i; |
|
83 break; |
|
84 } |
|
85 } |
|
86 |
|
87 if (fi > -1) { |
|
88 nl[ci].style.zIndex = z[fi]; |
|
89 nl[fi].style.zIndex = z[ci]; |
|
90 } else { |
|
91 nl[ci].style.zIndex = z[ci] + 1; |
|
92 } |
|
93 } |
|
94 |
|
95 editor.execCommand('mceRepaint'); |
|
96 } |
|
97 |
|
98 function insertLayer() { |
|
99 var dom = editor.dom, p = dom.getPos(dom.getParent(editor.selection.getNode(), '*')); |
|
100 var body = editor.getBody(); |
|
101 |
|
102 editor.dom.add(body, 'div', { |
|
103 style: { |
|
104 position: 'absolute', |
|
105 left: p.x, |
|
106 top: (p.y > 20 ? p.y : 20), |
|
107 width: 100, |
|
108 height: 100 |
|
109 }, |
|
110 'class': 'mceItemVisualAid mceItemLayer' |
|
111 }, editor.selection.getContent() || editor.getLang('layer.content')); |
|
112 |
|
113 // Workaround for IE where it messes up the JS engine if you insert a layer on IE 6,7 |
|
114 if (tinymce.Env.ie) { |
|
115 dom.setHTML(body, body.innerHTML); |
|
116 } |
|
117 } |
|
118 |
|
119 function toggleAbsolute() { |
|
120 var le = getParentLayer(editor.selection.getNode()); |
|
121 |
|
122 if (!le) { |
|
123 le = editor.dom.getParent(editor.selection.getNode(), 'DIV,P,IMG'); |
|
124 } |
|
125 |
|
126 if (le) { |
|
127 if (le.style.position.toLowerCase() == "absolute") { |
|
128 editor.dom.setStyles(le, { |
|
129 position: '', |
|
130 left: '', |
|
131 top: '', |
|
132 width: '', |
|
133 height: '' |
|
134 }); |
|
135 |
|
136 editor.dom.removeClass(le, 'mceItemVisualAid'); |
|
137 editor.dom.removeClass(le, 'mceItemLayer'); |
|
138 } else { |
|
139 if (!le.style.left) { |
|
140 le.style.left = 20 + 'px'; |
|
141 } |
|
142 |
|
143 if (!le.style.top) { |
|
144 le.style.top = 20 + 'px'; |
|
145 } |
|
146 |
|
147 if (!le.style.width) { |
|
148 le.style.width = le.width ? (le.width + 'px') : '100px'; |
|
149 } |
|
150 |
|
151 if (!le.style.height) { |
|
152 le.style.height = le.height ? (le.height + 'px') : '100px'; |
|
153 } |
|
154 |
|
155 le.style.position = "absolute"; |
|
156 |
|
157 editor.dom.setAttrib(le, 'data-mce-style', ''); |
|
158 editor.addVisual(editor.getBody()); |
|
159 } |
|
160 |
|
161 editor.execCommand('mceRepaint'); |
|
162 editor.nodeChanged(); |
|
163 } |
|
164 } |
|
165 |
|
166 // Register commands |
|
167 editor.addCommand('mceInsertLayer', insertLayer); |
|
168 |
|
169 editor.addCommand('mceMoveForward', function() { |
|
170 move(1); |
|
171 }); |
|
172 |
|
173 editor.addCommand('mceMoveBackward', function() { |
|
174 move(-1); |
|
175 }); |
|
176 |
|
177 editor.addCommand('mceMakeAbsolute', function() { |
|
178 toggleAbsolute(); |
|
179 }); |
|
180 |
|
181 // Register buttons |
|
182 editor.addButton('moveforward', {title: 'layer.forward_desc', cmd: 'mceMoveForward'}); |
|
183 editor.addButton('movebackward', {title: 'layer.backward_desc', cmd: 'mceMoveBackward'}); |
|
184 editor.addButton('absolute', {title: 'layer.absolute_desc', cmd: 'mceMakeAbsolute'}); |
|
185 editor.addButton('insertlayer', {title: 'layer.insertlayer_desc', cmd: 'mceInsertLayer'}); |
|
186 |
|
187 editor.on('init', function() { |
|
188 if (tinymce.Env.ie) { |
|
189 editor.getDoc().execCommand('2D-Position', false, true); |
|
190 } |
|
191 }); |
|
192 |
|
193 // Remove serialized styles when selecting a layer since it might be changed by a drag operation |
|
194 editor.on('mouseup', function(e) { |
|
195 var layer = getParentLayer(e.target); |
|
196 |
|
197 if (layer) { |
|
198 editor.dom.setAttrib(layer, 'data-mce-style', ''); |
|
199 } |
|
200 }); |
|
201 |
|
202 // Fixes edit focus issues with layers on Gecko |
|
203 // This will enable designMode while inside a layer and disable it when outside |
|
204 editor.on('mousedown', function(e) { |
|
205 var node = e.target, doc = editor.getDoc(), parent; |
|
206 |
|
207 if (tinymce.Env.gecko) { |
|
208 if (getParentLayer(node)) { |
|
209 if (doc.designMode !== 'on') { |
|
210 doc.designMode = 'on'; |
|
211 |
|
212 // Repaint caret |
|
213 node = doc.body; |
|
214 parent = node.parentNode; |
|
215 parent.removeChild(node); |
|
216 parent.appendChild(node); |
|
217 } |
|
218 } else if (doc.designMode == 'on') { |
|
219 doc.designMode = 'off'; |
|
220 } |
|
221 } |
|
222 }); |
|
223 |
|
224 editor.on('NodeChange', visualAid); |
|
225 }); |
|