eads@29
|
1 /** |
eads@29
|
2 * |
eads@29
|
3 * @author Sander Kruger |
eads@29
|
4 * @copyright Copyright � 2009, Sander Kruger, All rights reserved. |
eads@29
|
5 */ |
eads@29
|
6 |
eads@29
|
7 (function() { |
eads@29
|
8 var Event = tinymce.dom.Event; |
eads@29
|
9 var direction = 0; // Track cursor direction for skipping |
eads@29
|
10 var hasClicked = false; // Track mouseclicks for selecting |
eads@29
|
11 var atStart = null; // Cache if the cursor is at the start or at the end of |
eads@29
|
12 var atEnd = null; // an atom. |
eads@29
|
13 |
eads@29
|
14 tinymce.create('tinymce.plugins.AtomicPlugin', { |
eads@29
|
15 init : function(ed, url) { |
eads@29
|
16 var t = this, atomicClass; |
eads@29
|
17 |
eads@29
|
18 t.editor = ed; |
eads@29
|
19 atomicClass = ed.getParam("atomic_atomic_class", "mceAtomic"); |
eads@29
|
20 |
eads@29
|
21 ed.onNodeChange.addToTop(function(ed, cm, n) { |
eads@29
|
22 var sc, ec, wasEnd=false; |
eads@29
|
23 |
eads@29
|
24 // Check if the start or end of the selection is in an atom |
eads@29
|
25 sc = ed.dom.getParent(ed.selection.getStart(), function(n) { |
eads@29
|
26 return ed.dom.hasClass(n, atomicClass); |
eads@29
|
27 }); |
eads@29
|
28 |
eads@29
|
29 ec = ed.dom.getParent(ed.selection.getEnd(), function(n) { |
eads@29
|
30 return ed.dom.hasClass(n, atomicClass); |
eads@29
|
31 }); |
eads@29
|
32 if (atEnd) |
eads@29
|
33 { |
eads@29
|
34 wasEnd = true; |
eads@29
|
35 } |
eads@29
|
36 atStart = null; |
eads@29
|
37 atEnd = null; |
eads@29
|
38 // Check situation to move the cursor or selection. |
eads@29
|
39 if (sc || ec) |
eads@29
|
40 { |
eads@29
|
41 var s = ed.selection.getSel(); |
eads@29
|
42 var r = ed.selection.getRng(); |
eads@29
|
43 var select = s.type?(s.type!="None"):(s.anchorNode != s.focusNode || s.anchorOffset != s.focusOffset); |
eads@29
|
44 var move = false; |
eads@29
|
45 if (!select) |
eads@29
|
46 { |
eads@29
|
47 // The user has not selected anything but is moving the |
eads@29
|
48 // cursor or clicked on an atom. |
eads@29
|
49 if (direction == -1) |
eads@29
|
50 { |
eads@29
|
51 if (r.setStart) |
eads@29
|
52 { |
eads@29
|
53 var lc = t._leftNeighbour( ed, sc ); |
eads@29
|
54 if (lc) |
eads@29
|
55 { |
eads@29
|
56 // Make sure that when skipping to the left, |
eads@29
|
57 // the next input doesn't go into the atom. |
eads@29
|
58 var offset = lc.nodeType==3?lc.length:1; |
eads@29
|
59 r.setStart( lc, offset ); |
eads@29
|
60 r.setEnd( lc, offset ); |
eads@29
|
61 } |
eads@29
|
62 else |
eads@29
|
63 { |
eads@29
|
64 r.setStart( sc, 0 ); |
eads@29
|
65 r.setEnd( sc, 0 ); |
eads@29
|
66 } |
eads@29
|
67 atStart = sc; |
eads@29
|
68 move = true; |
eads@29
|
69 } |
eads@29
|
70 else |
eads@29
|
71 { |
eads@29
|
72 // ie (check if the caret is not just after the |
eads@29
|
73 // atom) |
eads@29
|
74 var r2 = ed.getBody().createTextRange(); |
eads@29
|
75 r2.moveToElementText( ec ); |
eads@29
|
76 r2.collapse(false); |
eads@29
|
77 if (!r2.isEqual( r )) |
eads@29
|
78 { |
eads@29
|
79 r.moveToElementText( sc ); |
eads@29
|
80 r.collapse(); |
eads@29
|
81 atStart = sc; |
eads@29
|
82 move = true; |
eads@29
|
83 } |
eads@29
|
84 else |
eads@29
|
85 { |
eads@29
|
86 var tempEl = ed.dom.create("span", null, "­"); |
eads@29
|
87 ec.insertAdjacentElement("afterEnd", tempEl); |
eads@29
|
88 |
eads@29
|
89 r.moveToElementText(tempEl); |
eads@29
|
90 r.collapse(false); |
eads@29
|
91 ed.selection.setRng(r); |
eads@29
|
92 |
eads@29
|
93 ed.dom.remove(tempEl); |
eads@29
|
94 atEnd = ec; |
eads@29
|
95 } |
eads@29
|
96 } |
eads@29
|
97 } |
eads@29
|
98 else if (direction == 1) |
eads@29
|
99 { |
eads@29
|
100 if (r.setStartAfter) |
eads@29
|
101 { |
eads@29
|
102 r.setStartAfter( ec ); |
eads@29
|
103 r.setEndAfter( ec ); |
eads@29
|
104 move = true; |
eads@29
|
105 } |
eads@29
|
106 else |
eads@29
|
107 { |
eads@29
|
108 if (wasEnd) |
eads@29
|
109 { |
eads@29
|
110 r.move( 'character' ); |
eads@29
|
111 ed.selection.setRng(r); |
eads@29
|
112 ec = null; |
eads@29
|
113 } |
eads@29
|
114 else |
eads@29
|
115 { |
eads@29
|
116 var tempEl = ed.dom.create("span", null, "­"); |
eads@29
|
117 ec.insertAdjacentElement("afterEnd", tempEl); |
eads@29
|
118 |
eads@29
|
119 r.moveToElementText(tempEl); |
eads@29
|
120 r.collapse(false); |
eads@29
|
121 ed.selection.setRng(r); |
eads@29
|
122 |
eads@29
|
123 ed.dom.remove(tempEl); |
eads@29
|
124 } |
eads@29
|
125 } |
eads@29
|
126 atEnd = ec; |
eads@29
|
127 } |
eads@29
|
128 else if (hasClicked) |
eads@29
|
129 { |
eads@29
|
130 if (r.setStart) |
eads@29
|
131 { |
eads@29
|
132 r.setStart( sc, 0 ); |
eads@29
|
133 r.setEnd( ec, ec.childNodes.length ); |
eads@29
|
134 } |
eads@29
|
135 else |
eads@29
|
136 { |
eads@29
|
137 // ie |
eads@29
|
138 r.moveToElementText( sc ); |
eads@29
|
139 } |
eads@29
|
140 move = true; |
eads@29
|
141 } |
eads@29
|
142 else if (wasEnd && !r.setStart) |
eads@29
|
143 { |
eads@29
|
144 // ie |
eads@29
|
145 var tempEl = ed.dom.create("span", null, "­"); |
eads@29
|
146 ec.insertAdjacentElement("afterEnd", tempEl); |
eads@29
|
147 |
eads@29
|
148 r.moveToElementText(tempEl); |
eads@29
|
149 r.collapse(false); |
eads@29
|
150 ed.selection.setRng(r); |
eads@29
|
151 |
eads@29
|
152 ed.dom.remove(tempEl); |
eads@29
|
153 atEnd = ec; |
eads@29
|
154 } |
eads@29
|
155 } |
eads@29
|
156 else |
eads@29
|
157 { |
eads@29
|
158 // Reverse selections have the anchor at the end and the |
eads@29
|
159 // focus at the start. This happens when selecting |
eads@29
|
160 // backwards. Make sure the extended selection keeps the |
eads@29
|
161 // same direction. |
eads@29
|
162 // *** Issue: ie doesn't support backward selections |
eads@29
|
163 // programmatically (or at least I have not found how to |
eads@29
|
164 // do this). |
eads@29
|
165 var reverse = false; |
eads@29
|
166 if (s.anchorNode && s.anchorNode == r.endContainer && s.anchorOffset == r.endOffset) |
eads@29
|
167 { |
eads@29
|
168 reverse = true; |
eads@29
|
169 } |
eads@29
|
170 var moveStart = false; |
eads@29
|
171 var moveEnd = false; |
eads@29
|
172 var rsc, rec; |
eads@29
|
173 if (sc) |
eads@29
|
174 { |
eads@29
|
175 if (s.anchorNode) |
eads@29
|
176 { |
eads@29
|
177 if (sc != r.startContainer || (r.startOffset != 0 && r.startOffset != sc.childNodes.length)) |
eads@29
|
178 { |
eads@29
|
179 // The start pos is not where it should be. |
eads@29
|
180 moveStart = true; |
eads@29
|
181 } |
eads@29
|
182 } |
eads@29
|
183 else |
eads@29
|
184 { |
eads@29
|
185 // ie |
eads@29
|
186 rsc = ed.getBody().createTextRange(); |
eads@29
|
187 rsc.moveToElementText( sc ); |
eads@29
|
188 moveStart = (r.compareEndPoints( "StartToStart", rsc ) != 0); |
eads@29
|
189 } |
eads@29
|
190 } |
eads@29
|
191 if (ec) |
eads@29
|
192 { |
eads@29
|
193 if (s.anchorNode) |
eads@29
|
194 { |
eads@29
|
195 if (ec != r.endContainer || (r.endOffset != 0 && r.endOffset != ec.childNodes.length)) |
eads@29
|
196 { |
eads@29
|
197 // The end pos is not where it should be |
eads@29
|
198 moveEnd = true; |
eads@29
|
199 } |
eads@29
|
200 } |
eads@29
|
201 else |
eads@29
|
202 { |
eads@29
|
203 // ie |
eads@29
|
204 rec = ed.getBody().createTextRange(); |
eads@29
|
205 rec.moveToElementText( ec ); |
eads@29
|
206 moveEnd = (r.compareEndPoints( "EndToEnd", rec ) != 0); |
eads@29
|
207 } |
eads@29
|
208 } |
eads@29
|
209 if (reverse) |
eads@29
|
210 { |
eads@29
|
211 // Start with the end. Since 'selection direction detection' |
eads@29
|
212 // doesn't work on IE, don't bother with the IE code here. |
eads@29
|
213 if (moveEnd) |
eads@29
|
214 { |
eads@29
|
215 // If both start and end move and they move leftwards, set start first and then extend instead of starting with setend |
eads@29
|
216 if (direction == -1) |
eads@29
|
217 { |
eads@29
|
218 r.setEnd( ec, 0 ); |
eads@29
|
219 } |
eads@29
|
220 else |
eads@29
|
221 { |
eads@29
|
222 r.setEnd( ec, ec.childNodes.length ); |
eads@29
|
223 } |
eads@29
|
224 move = true; |
eads@29
|
225 } |
eads@29
|
226 if (moveStart) |
eads@29
|
227 { |
eads@29
|
228 // Use the extend method to advance the focus |
eads@29
|
229 // position of the selection. |
eads@29
|
230 if (direction == 1) |
eads@29
|
231 { |
eads@29
|
232 s.extend( sc, sc.childNodes.length ); |
eads@29
|
233 move = false; |
eads@29
|
234 } |
eads@29
|
235 else |
eads@29
|
236 { |
eads@29
|
237 s.extend( sc, 0 ); |
eads@29
|
238 move = false; |
eads@29
|
239 } |
eads@29
|
240 } |
eads@29
|
241 } |
eads@29
|
242 else |
eads@29
|
243 { |
eads@29
|
244 if (moveStart) |
eads@29
|
245 { |
eads@29
|
246 if (direction == 1) |
eads@29
|
247 { |
eads@29
|
248 if (r.setStart) |
eads@29
|
249 { |
eads@29
|
250 r.setStart( sc, sc.childNodes.length ); |
eads@29
|
251 } |
eads@29
|
252 else |
eads@29
|
253 { |
eads@29
|
254 // ie |
eads@29
|
255 r.setEndPoint( "StartToEnd", rsc ); |
eads@29
|
256 } |
eads@29
|
257 } |
eads@29
|
258 else |
eads@29
|
259 { |
eads@29
|
260 if (r.setStart) |
eads@29
|
261 { |
eads@29
|
262 r.setStart( sc, 0 ); |
eads@29
|
263 } |
eads@29
|
264 else |
eads@29
|
265 { |
eads@29
|
266 // ie |
eads@29
|
267 r.setEndPoint( "StartToStart", rsc ); |
eads@29
|
268 } |
eads@29
|
269 } |
eads@29
|
270 move = true; |
eads@29
|
271 } |
eads@29
|
272 if (moveEnd) |
eads@29
|
273 { |
eads@29
|
274 if (direction == -1) |
eads@29
|
275 { |
eads@29
|
276 if (r.setEnd) |
eads@29
|
277 { |
eads@29
|
278 s.extend( ec, 0 ); |
eads@29
|
279 } |
eads@29
|
280 else |
eads@29
|
281 { |
eads@29
|
282 // ie |
eads@29
|
283 r.setEndPoint( "EndToStart", rec ); |
eads@29
|
284 move = true; |
eads@29
|
285 } |
eads@29
|
286 } |
eads@29
|
287 else |
eads@29
|
288 { |
eads@29
|
289 if (r.setEnd) |
eads@29
|
290 { |
eads@29
|
291 s.extend( ec, ec.childNodes.length ); |
eads@29
|
292 } |
eads@29
|
293 else |
eads@29
|
294 { |
eads@29
|
295 // ie |
eads@29
|
296 r.setEndPoint( "EndToEnd", rec ); |
eads@29
|
297 move = true; |
eads@29
|
298 } |
eads@29
|
299 } |
eads@29
|
300 // move = false; |
eads@29
|
301 } |
eads@29
|
302 } |
eads@29
|
303 } |
eads@29
|
304 if (move) |
eads@29
|
305 { |
eads@29
|
306 // Make sure other modules can react to this event. |
eads@29
|
307 ed.selection.setRng( r ); |
eads@29
|
308 } |
eads@29
|
309 } |
eads@29
|
310 }); |
eads@29
|
311 |
eads@29
|
312 ed.onKeyDown.addToTop( function(ed, e) { |
eads@29
|
313 var k = e.keyCode, atomicClass; |
eads@29
|
314 atomicClass = ed.getParam("atomic_atomic_class", "mceAtomic"); |
eads@29
|
315 hasClicked = false; |
eads@29
|
316 direction = 0; |
eads@29
|
317 if (k == 37 || k == 38) |
eads@29
|
318 { |
eads@29
|
319 direction = -1; |
eads@29
|
320 } |
eads@29
|
321 else if (k == 39 || k == 40) |
eads@29
|
322 { |
eads@29
|
323 direction = 1; |
eads@29
|
324 } |
eads@29
|
325 else if (k == 8) |
eads@29
|
326 { |
eads@29
|
327 // Check if an atom is being 'backspace'd |
eads@29
|
328 if (!atEnd) |
eads@29
|
329 { |
eads@29
|
330 var s = ed.selection.getSel(); |
eads@29
|
331 var select = s.type?(s.type!="None"):(s.anchorNode != s.focusNode || s.anchorOffset != s.focusOffset); |
eads@29
|
332 if (!select) |
eads@29
|
333 { |
eads@29
|
334 var ep = s.focusNode?((s.focusNode.nodeType == 3 && s.focusOffset != 0)?null:s.focusNode):ed.selection.getStart(); |
eads@29
|
335 if (ed.dom.hasClass(ep, atomicClass)) |
eads@29
|
336 { |
eads@29
|
337 atEnd = ep; |
eads@29
|
338 } |
eads@29
|
339 else if (ep) |
eads@29
|
340 { |
eads@29
|
341 var rc; |
eads@29
|
342 if (!s.focusNode) |
eads@29
|
343 { |
eads@29
|
344 // ie |
eads@29
|
345 // focusOffset is not given. So, we need to find |
eads@29
|
346 // it by walking through the children and comparing |
eads@29
|
347 // end points. |
eads@29
|
348 var r = ed.selection.getRng(); |
eads@29
|
349 var r2 = ed.getBody().createTextRange(); |
eads@29
|
350 r2.moveToElementText( ep ); |
eads@29
|
351 if (r2.compareEndPoints( "StartToStart", r ) == 0) |
eads@29
|
352 { |
eads@29
|
353 // The caret is at the start of this element. |
eads@29
|
354 // Find the left neighbouring element |
eads@29
|
355 rc = t._leftNeighbour( ed, ep ); |
eads@29
|
356 } |
eads@29
|
357 else |
eads@29
|
358 { |
eads@29
|
359 // The focus is not at the start of the parent. |
eads@29
|
360 // Find the child left of the caret. |
eads@29
|
361 rc = ep.firstChild; |
eads@29
|
362 while (rc) |
eads@29
|
363 { |
eads@29
|
364 // We are not interested in text nodes |
eads@29
|
365 // because they cannot be atoms (all by |
eads@29
|
366 // themselves) |
eads@29
|
367 if (rc.nodeType == 1) |
eads@29
|
368 { |
eads@29
|
369 r2.moveToElementText( rc ); |
eads@29
|
370 if (r.compareEndPoints( "EndToEnd", r2 ) == 0) |
eads@29
|
371 { |
eads@29
|
372 break; |
eads@29
|
373 } |
eads@29
|
374 } |
eads@29
|
375 rc = rc.nextSibling; |
eads@29
|
376 } |
eads@29
|
377 } |
eads@29
|
378 } |
eads@29
|
379 else |
eads@29
|
380 { |
eads@29
|
381 if (ep.nodeType == 1 && s.focusOffset != 0) |
eads@29
|
382 { |
eads@29
|
383 // ep encloses the current caret position. |
eads@29
|
384 // select the child to the left of the caret. |
eads@29
|
385 rc = ep.childNodes[s.focusOffset-1]; |
eads@29
|
386 } |
eads@29
|
387 else |
eads@29
|
388 { |
eads@29
|
389 // The caret is on the left-most end of ep. |
eads@29
|
390 // Find it's left neighbour. |
eads@29
|
391 rc = t._leftNeighbour( ed, ep ); |
eads@29
|
392 } |
eads@29
|
393 } |
eads@29
|
394 if (rc) |
eads@29
|
395 { |
eads@29
|
396 // Now see if this element has a right-most |
eads@29
|
397 // descendent that is an atom |
eads@29
|
398 while (rc && !ed.dom.hasClass(rc, atomicClass)) |
eads@29
|
399 { |
eads@29
|
400 rc = rc.lastChild; |
eads@29
|
401 } |
eads@29
|
402 if (rc) |
eads@29
|
403 { |
eads@29
|
404 atEnd = rc; |
eads@29
|
405 } |
eads@29
|
406 } |
eads@29
|
407 } |
eads@29
|
408 } |
eads@29
|
409 } |
eads@29
|
410 if (atEnd) |
eads@29
|
411 { |
eads@29
|
412 ed.dom.remove( atEnd ); |
eads@29
|
413 atEnd = null; |
eads@29
|
414 return Event.cancel(e); |
eads@29
|
415 } |
eads@29
|
416 } |
eads@29
|
417 else if (k == 46) |
eads@29
|
418 { |
eads@29
|
419 // Check if an atom is being 'delete'd |
eads@29
|
420 if (!atStart) |
eads@29
|
421 { |
eads@29
|
422 var s = ed.selection.getSel(); |
eads@29
|
423 var select = s.type?(s.type!="None"):(s.anchorNode != s.focusNode || s.anchorOffset != s.focusOffset); |
eads@29
|
424 if (!select) |
eads@29
|
425 { |
eads@29
|
426 var ep = s.focusNode?((s.focusNode.nodeType == 3 && s.focusOffset != s.focusNode.length)?null:s.focusNode):ed.selection.getEnd(); |
eads@29
|
427 if (ed.dom.hasClass(ep, atomicClass)) |
eads@29
|
428 { |
eads@29
|
429 atStart = ep; |
eads@29
|
430 } |
eads@29
|
431 else if (ep) |
eads@29
|
432 { |
eads@29
|
433 var lc; |
eads@29
|
434 if (!s.focusNode) |
eads@29
|
435 { |
eads@29
|
436 // ie |
eads@29
|
437 // focusOffset is not given. So, we need to find |
eads@29
|
438 // it by walking through the children and comparing |
eads@29
|
439 // end points. |
eads@29
|
440 var r = ed.selection.getRng(); |
eads@29
|
441 var r2 = ed.getBody().createTextRange(); |
eads@29
|
442 r2.moveToElementText( ep ); |
eads@29
|
443 if (r2.compareEndPoints( "EndToEnd", r ) == 0) |
eads@29
|
444 { |
eads@29
|
445 // The caret is at the start of this element. |
eads@29
|
446 // Find the right neighbouring element |
eads@29
|
447 lc = t._rightNeighbour( ed, ep ); |
eads@29
|
448 } |
eads@29
|
449 else |
eads@29
|
450 { |
eads@29
|
451 // The focus is not at the end of the parent. |
eads@29
|
452 // Find the child right of the caret. |
eads@29
|
453 lc = ep.firstChild; |
eads@29
|
454 while (lc) |
eads@29
|
455 { |
eads@29
|
456 // We are not interested in text nodes |
eads@29
|
457 // because they cannot be atoms (all by |
eads@29
|
458 // themselves) |
eads@29
|
459 if (lc.nodeType == 1) |
eads@29
|
460 { |
eads@29
|
461 r2.moveToElementText( lc ); |
eads@29
|
462 if (r.compareEndPoints( "StartToStart", r2 ) == 0) |
eads@29
|
463 { |
eads@29
|
464 break; |
eads@29
|
465 } |
eads@29
|
466 } |
eads@29
|
467 lc = lc.nextSibling; |
eads@29
|
468 } |
eads@29
|
469 } |
eads@29
|
470 } |
eads@29
|
471 else |
eads@29
|
472 { |
eads@29
|
473 if (ep.nodeType == 1 && s.focusOffset != ep.childNodes.length) |
eads@29
|
474 { |
eads@29
|
475 // ep encloses the current caret position. |
eads@29
|
476 // select the child to the right of the caret. |
eads@29
|
477 lc = ep.childNodes[s.focusOffset]; |
eads@29
|
478 } |
eads@29
|
479 else |
eads@29
|
480 { |
eads@29
|
481 // The caret is on the right-most end of ep. |
eads@29
|
482 // Find it's right neighbour. |
eads@29
|
483 lc = t._rightNeighbour( ed, ep ); |
eads@29
|
484 } |
eads@29
|
485 } |
eads@29
|
486 if (lc) |
eads@29
|
487 { |
eads@29
|
488 // Now see if this element has a left-most |
eads@29
|
489 // descendent that is an atom |
eads@29
|
490 while (lc && !ed.dom.hasClass(lc, atomicClass)) |
eads@29
|
491 { |
eads@29
|
492 lc = lc.firstChild; |
eads@29
|
493 } |
eads@29
|
494 if (lc) |
eads@29
|
495 { |
eads@29
|
496 atStart = lc; |
eads@29
|
497 } |
eads@29
|
498 } |
eads@29
|
499 } |
eads@29
|
500 } |
eads@29
|
501 } |
eads@29
|
502 if (atStart) |
eads@29
|
503 { |
eads@29
|
504 ed.dom.remove( atStart ); |
eads@29
|
505 atStart = null; |
eads@29
|
506 return Event.cancel(e); |
eads@29
|
507 } |
eads@29
|
508 } |
eads@29
|
509 }); |
eads@29
|
510 |
eads@29
|
511 ed.onMouseDown.addToTop(t._onClick); |
eads@29
|
512 ed.onMouseUp.addToTop(t._onClick); |
eads@29
|
513 }, |
eads@29
|
514 |
eads@29
|
515 getInfo : function() { |
eads@29
|
516 return { |
eads@29
|
517 longname : 'Atomic elements', |
eads@29
|
518 author : 'Sander Kruger', |
eads@29
|
519 authorurl : 'http://www.3gsp.eu', |
eads@29
|
520 infourl : 'http://wiki.moxiecode.com/index.php/TinyMCE:Plugins/atomic', |
eads@29
|
521 version : tinymce.majorVersion + "." + tinymce.minorVersion |
eads@29
|
522 }; |
eads@29
|
523 }, |
eads@29
|
524 |
eads@29
|
525 _onClick : function(ed, e) { |
eads@29
|
526 direction = 0; |
eads@29
|
527 hasClicked = true; |
eads@29
|
528 atStart = null; |
eads@29
|
529 atEnd = null; |
eads@29
|
530 }, |
eads@29
|
531 |
eads@29
|
532 // Helper methods |
eads@29
|
533 _leftNeighbour : function( ed, e ) { |
eads@29
|
534 var l = ed.dom.getParent(e, function(n) { |
eads@29
|
535 return e.previousSibling != null; |
eads@29
|
536 }); |
eads@29
|
537 if (l) |
eads@29
|
538 { |
eads@29
|
539 return l.previousSibling; |
eads@29
|
540 } |
eads@29
|
541 return null; |
eads@29
|
542 }, |
eads@29
|
543 |
eads@29
|
544 _rightNeighbour : function( ed, e ) { |
eads@29
|
545 var r = ed.dom.getParent(e, function(n) { |
eads@29
|
546 return e.nextSibling != null; |
eads@29
|
547 }); |
eads@29
|
548 if (r) |
eads@29
|
549 { |
eads@29
|
550 return r.nextSibling; |
eads@29
|
551 } |
eads@29
|
552 return null; |
eads@29
|
553 } |
eads@29
|
554 }); |
eads@29
|
555 |
eads@29
|
556 // Register plugin |
eads@29
|
557 tinymce.PluginManager.add('atomic', tinymce.plugins.AtomicPlugin); |
eads@29
|
558 })(); |