Mercurial > public > sg101
comparison media/js/tiny_mce/plugins/safari/editor_plugin_src.js @ 45:a5b4c5ce0658
Breaking down and controlling all media files, including javascript libraries.
author | Brian Neal <bgneal@gmail.com> |
---|---|
date | Fri, 19 Jun 2009 03:16:03 +0000 |
parents | |
children |
comparison
equal
deleted
inserted
replaced
44:08cd19c1ee50 | 45:a5b4c5ce0658 |
---|---|
1 /** | |
2 * $Id: editor_plugin_src.js 264 2007-04-26 20:53:09Z spocke $ | |
3 * | |
4 * @author Moxiecode | |
5 * @copyright Copyright © 2004-2008, Moxiecode Systems AB, All rights reserved. | |
6 */ | |
7 | |
8 (function() { | |
9 var Event = tinymce.dom.Event, grep = tinymce.grep, each = tinymce.each, inArray = tinymce.inArray; | |
10 | |
11 function isEmpty(d, e, f) { | |
12 var w, n; | |
13 | |
14 w = d.createTreeWalker(e, NodeFilter.SHOW_ALL, null, false); | |
15 while (n = w.nextNode()) { | |
16 // Filter func | |
17 if (f) { | |
18 if (!f(n)) | |
19 return false; | |
20 } | |
21 | |
22 // Non whitespace text node | |
23 if (n.nodeType == 3 && n.nodeValue && /[^\s\u00a0]+/.test(n.nodeValue)) | |
24 return false; | |
25 | |
26 // Is non text element byt still content | |
27 if (n.nodeType == 1 && /^(HR|IMG|TABLE)$/.test(n.nodeName)) | |
28 return false; | |
29 } | |
30 | |
31 return true; | |
32 }; | |
33 | |
34 tinymce.create('tinymce.plugins.Safari', { | |
35 init : function(ed) { | |
36 var t = this, dom; | |
37 | |
38 // Ignore on non webkit | |
39 if (!tinymce.isWebKit) | |
40 return; | |
41 | |
42 t.editor = ed; | |
43 t.webKitFontSizes = ['x-small', 'small', 'medium', 'large', 'x-large', 'xx-large', '-webkit-xxx-large']; | |
44 t.namedFontSizes = ['xx-small', 'x-small','small','medium','large','x-large', 'xx-large']; | |
45 | |
46 // Safari CreateLink command will not work correctly on images that is aligned | |
47 ed.addCommand('CreateLink', function(u, v) { | |
48 var n = ed.selection.getNode(), dom = ed.dom, a; | |
49 | |
50 if (n && (/^(left|right)$/i.test(dom.getStyle(n, 'float', 1)) || /^(left|right)$/i.test(dom.getAttrib(n, 'align')))) { | |
51 a = dom.create('a', {href : v}, n.cloneNode()); | |
52 n.parentNode.replaceChild(a, n); | |
53 ed.selection.select(a); | |
54 } else | |
55 ed.getDoc().execCommand("CreateLink", false, v); | |
56 }); | |
57 | |
58 ed.onPaste.add(function(ed, e) { | |
59 function removeStyles(e) { | |
60 e = e.target; | |
61 | |
62 if (e.nodeType == 1) { | |
63 e.style.cssText = ''; | |
64 | |
65 each(ed.dom.select('*', e), function(e) { | |
66 e.style.cssText = ''; | |
67 }); | |
68 } | |
69 }; | |
70 | |
71 Event.add(ed.getDoc(), 'DOMNodeInserted', removeStyles); | |
72 | |
73 window.setTimeout(function() { | |
74 Event.remove(ed.getDoc(), 'DOMNodeInserted', removeStyles); | |
75 }, 0); | |
76 }); | |
77 | |
78 ed.onKeyUp.add(function(ed, e) { | |
79 var h, b, r, n, s; | |
80 | |
81 // If backspace or delete key | |
82 if (e.keyCode == 46 || e.keyCode == 8) { | |
83 b = ed.getBody(); | |
84 h = b.innerHTML; | |
85 s = ed.selection; | |
86 | |
87 // If there is no text content or images or hr elements then remove everything | |
88 if (b.childNodes.length == 1 && !/<(img|hr)/.test(h) && tinymce.trim(h.replace(/<[^>]+>/g, '')).length == 0) { | |
89 // Inject paragrah and bogus br | |
90 ed.setContent('<p><br mce_bogus="1" /></p>', {format : 'raw'}); | |
91 | |
92 // Move caret before bogus br | |
93 n = b.firstChild; | |
94 r = s.getRng(); | |
95 r.setStart(n, 0); | |
96 r.setEnd(n, 0); | |
97 s.setRng(r); | |
98 } | |
99 } | |
100 }); | |
101 | |
102 // Workaround for FormatBlock bug, http://bugs.webkit.org/show_bug.cgi?id=16004 | |
103 ed.addCommand('FormatBlock', function(u, v) { | |
104 var dom = ed.dom, e = dom.getParent(ed.selection.getNode(), dom.isBlock); | |
105 | |
106 if (e) | |
107 dom.replace(dom.create(v), e, 1); | |
108 else | |
109 ed.getDoc().execCommand("FormatBlock", false, v); | |
110 }); | |
111 | |
112 // Workaround for InsertHTML bug, http://bugs.webkit.org/show_bug.cgi?id=16382 | |
113 ed.addCommand('mceInsertContent', function(u, v) { | |
114 ed.getDoc().execCommand("InsertText", false, 'mce_marker'); | |
115 ed.getBody().innerHTML = ed.getBody().innerHTML.replace(/mce_marker/g, ed.dom.processHTML(v) + '<span id="_mce_tmp">XX</span>'); | |
116 ed.selection.select(ed.dom.get('_mce_tmp')); | |
117 ed.getDoc().execCommand("Delete", false, ' '); | |
118 }); | |
119 | |
120 ed.onKeyPress.add(function(ed, e) { | |
121 var se, li, lic, r1, r2, n, sel, doc, be, af, pa; | |
122 | |
123 if (e.keyCode == 13) { | |
124 sel = ed.selection; | |
125 se = sel.getNode(); | |
126 | |
127 // Workaround for missing shift+enter support, http://bugs.webkit.org/show_bug.cgi?id=16973 | |
128 if (e.shiftKey || ed.settings.force_br_newlines && se.nodeName != 'LI') { | |
129 t._insertBR(ed); | |
130 Event.cancel(e); | |
131 } | |
132 | |
133 // Workaround for DIV elements produced by Safari | |
134 if (li = dom.getParent(se, 'LI')) { | |
135 lic = dom.getParent(li, 'OL,UL'); | |
136 doc = ed.getDoc(); | |
137 | |
138 pa = dom.create('p'); | |
139 dom.add(pa, 'br', {mce_bogus : "1"}); | |
140 | |
141 if (isEmpty(doc, li)) { | |
142 // If list in list then use browser default behavior | |
143 if (n = dom.getParent(lic.parentNode, 'LI,OL,UL')) | |
144 return; | |
145 | |
146 n = dom.getParent(lic, 'p,h1,h2,h3,h4,h5,h6,div') || lic; | |
147 | |
148 // Create range from the start of block element to the list item | |
149 r1 = doc.createRange(); | |
150 r1.setStartBefore(n); | |
151 r1.setEndBefore(li); | |
152 | |
153 // Create range after the list to the end of block element | |
154 r2 = doc.createRange(); | |
155 r2.setStartAfter(li); | |
156 r2.setEndAfter(n); | |
157 | |
158 be = r1.cloneContents(); | |
159 af = r2.cloneContents(); | |
160 | |
161 if (!isEmpty(doc, af)) | |
162 dom.insertAfter(af, n); | |
163 | |
164 dom.insertAfter(pa, n); | |
165 | |
166 if (!isEmpty(doc, be)) | |
167 dom.insertAfter(be, n); | |
168 | |
169 dom.remove(n); | |
170 | |
171 n = pa.firstChild; | |
172 r1 = doc.createRange(); | |
173 r1.setStartBefore(n); | |
174 r1.setEndBefore(n); | |
175 sel.setRng(r1); | |
176 | |
177 return Event.cancel(e); | |
178 } | |
179 } | |
180 } | |
181 }); | |
182 | |
183 // Safari doesn't place lists outside block elements | |
184 ed.onExecCommand.add(function(ed, cmd) { | |
185 var sel, dom, bl, bm; | |
186 | |
187 if (cmd == 'InsertUnorderedList' || cmd == 'InsertOrderedList') { | |
188 sel = ed.selection; | |
189 dom = ed.dom; | |
190 | |
191 if (bl = dom.getParent(sel.getNode(), function(n) {return /^(H[1-6]|P|ADDRESS|PRE)$/.test(n.nodeName);})) { | |
192 bm = sel.getBookmark(); | |
193 dom.remove(bl, 1); | |
194 sel.moveToBookmark(bm); | |
195 } | |
196 } | |
197 }); | |
198 | |
199 // Workaround for bug, http://bugs.webkit.org/show_bug.cgi?id=12250 | |
200 ed.onClick.add(function(ed, e) { | |
201 e = e.target; | |
202 | |
203 if (e.nodeName == 'IMG') { | |
204 t.selElm = e; | |
205 ed.selection.select(e); | |
206 } else | |
207 t.selElm = null; | |
208 }); | |
209 | |
210 ed.onInit.add(function() { | |
211 t._fixWebKitSpans(); | |
212 }); | |
213 | |
214 ed.onSetContent.add(function() { | |
215 dom = ed.dom; | |
216 | |
217 // Convert strong,b,em,u,strike to spans | |
218 each(['strong','b','em','u','strike','sub','sup','a'], function(v) { | |
219 each(grep(dom.select(v)).reverse(), function(n) { | |
220 var nn = n.nodeName.toLowerCase(), st; | |
221 | |
222 // Convert anchors into images | |
223 if (nn == 'a') { | |
224 if (n.name) | |
225 dom.replace(dom.create('img', {mce_name : 'a', name : n.name, 'class' : 'mceItemAnchor'}), n); | |
226 | |
227 return; | |
228 } | |
229 | |
230 switch (nn) { | |
231 case 'b': | |
232 case 'strong': | |
233 if (nn == 'b') | |
234 nn = 'strong'; | |
235 | |
236 st = 'font-weight: bold;'; | |
237 break; | |
238 | |
239 case 'em': | |
240 st = 'font-style: italic;'; | |
241 break; | |
242 | |
243 case 'u': | |
244 st = 'text-decoration: underline;'; | |
245 break; | |
246 | |
247 case 'sub': | |
248 st = 'vertical-align: sub;'; | |
249 break; | |
250 | |
251 case 'sup': | |
252 st = 'vertical-align: super;'; | |
253 break; | |
254 | |
255 case 'strike': | |
256 st = 'text-decoration: line-through;'; | |
257 break; | |
258 } | |
259 | |
260 dom.replace(dom.create('span', {mce_name : nn, style : st, 'class' : 'Apple-style-span'}), n, 1); | |
261 }); | |
262 }); | |
263 }); | |
264 | |
265 ed.onPreProcess.add(function(ed, o) { | |
266 dom = ed.dom; | |
267 | |
268 each(grep(o.node.getElementsByTagName('span')).reverse(), function(n) { | |
269 var v, bg; | |
270 | |
271 if (o.get) { | |
272 if (dom.hasClass(n, 'Apple-style-span')) { | |
273 bg = n.style.backgroundColor; | |
274 | |
275 switch (dom.getAttrib(n, 'mce_name')) { | |
276 case 'font': | |
277 if (!ed.settings.convert_fonts_to_spans) | |
278 dom.setAttrib(n, 'style', ''); | |
279 break; | |
280 | |
281 case 'strong': | |
282 case 'em': | |
283 case 'sub': | |
284 case 'sup': | |
285 dom.setAttrib(n, 'style', ''); | |
286 break; | |
287 | |
288 case 'strike': | |
289 case 'u': | |
290 if (!ed.settings.inline_styles) | |
291 dom.setAttrib(n, 'style', ''); | |
292 else | |
293 dom.setAttrib(n, 'mce_name', ''); | |
294 | |
295 break; | |
296 | |
297 default: | |
298 if (!ed.settings.inline_styles) | |
299 dom.setAttrib(n, 'style', ''); | |
300 } | |
301 | |
302 | |
303 if (bg) | |
304 n.style.backgroundColor = bg; | |
305 } | |
306 } | |
307 | |
308 if (dom.hasClass(n, 'mceItemRemoved')) | |
309 dom.remove(n, 1); | |
310 }); | |
311 }); | |
312 | |
313 ed.onPostProcess.add(function(ed, o) { | |
314 // Safari adds BR at end of all block elements | |
315 o.content = o.content.replace(/<br \/><\/(h[1-6]|div|p|address|pre)>/g, '</$1>'); | |
316 | |
317 // Safari adds id="undefined" to HR elements | |
318 o.content = o.content.replace(/ id=\"undefined\"/g, ''); | |
319 }); | |
320 }, | |
321 | |
322 getInfo : function() { | |
323 return { | |
324 longname : 'Safari compatibility', | |
325 author : 'Moxiecode Systems AB', | |
326 authorurl : 'http://tinymce.moxiecode.com', | |
327 infourl : 'http://wiki.moxiecode.com/index.php/TinyMCE:Plugins/safari', | |
328 version : tinymce.majorVersion + "." + tinymce.minorVersion | |
329 }; | |
330 }, | |
331 | |
332 // Internal methods | |
333 | |
334 _fixWebKitSpans : function() { | |
335 var t = this, ed = t.editor; | |
336 | |
337 // Use mutator events on new WebKit | |
338 Event.add(ed.getDoc(), 'DOMNodeInserted', function(e) { | |
339 e = e.target; | |
340 | |
341 if (e && e.nodeType == 1) | |
342 t._fixAppleSpan(e); | |
343 }); | |
344 }, | |
345 | |
346 _fixAppleSpan : function(e) { | |
347 var ed = this.editor, dom = ed.dom, fz = this.webKitFontSizes, fzn = this.namedFontSizes, s = ed.settings, st, p; | |
348 | |
349 if (dom.getAttrib(e, 'mce_fixed')) | |
350 return; | |
351 | |
352 // Handle Apple style spans | |
353 if (e.nodeName == 'SPAN' && e.className == 'Apple-style-span') { | |
354 st = e.style; | |
355 | |
356 if (!s.convert_fonts_to_spans) { | |
357 if (st.fontSize) { | |
358 dom.setAttrib(e, 'mce_name', 'font'); | |
359 dom.setAttrib(e, 'size', inArray(fz, st.fontSize) + 1); | |
360 } | |
361 | |
362 if (st.fontFamily) { | |
363 dom.setAttrib(e, 'mce_name', 'font'); | |
364 dom.setAttrib(e, 'face', st.fontFamily); | |
365 } | |
366 | |
367 if (st.color) { | |
368 dom.setAttrib(e, 'mce_name', 'font'); | |
369 dom.setAttrib(e, 'color', dom.toHex(st.color)); | |
370 } | |
371 | |
372 if (st.backgroundColor) { | |
373 dom.setAttrib(e, 'mce_name', 'font'); | |
374 dom.setStyle(e, 'background-color', st.backgroundColor); | |
375 } | |
376 } else { | |
377 if (st.fontSize) | |
378 dom.setStyle(e, 'fontSize', fzn[inArray(fz, st.fontSize)]); | |
379 } | |
380 | |
381 if (st.fontWeight == 'bold') | |
382 dom.setAttrib(e, 'mce_name', 'strong'); | |
383 | |
384 if (st.fontStyle == 'italic') | |
385 dom.setAttrib(e, 'mce_name', 'em'); | |
386 | |
387 if (st.textDecoration == 'underline') | |
388 dom.setAttrib(e, 'mce_name', 'u'); | |
389 | |
390 if (st.textDecoration == 'line-through') | |
391 dom.setAttrib(e, 'mce_name', 'strike'); | |
392 | |
393 if (st.verticalAlign == 'super') | |
394 dom.setAttrib(e, 'mce_name', 'sup'); | |
395 | |
396 if (st.verticalAlign == 'sub') | |
397 dom.setAttrib(e, 'mce_name', 'sub'); | |
398 | |
399 dom.setAttrib(e, 'mce_fixed', '1'); | |
400 } | |
401 }, | |
402 | |
403 _insertBR : function(ed) { | |
404 var dom = ed.dom, s = ed.selection, r = s.getRng(), br; | |
405 | |
406 // Insert BR element | |
407 r.insertNode(br = dom.create('br')); | |
408 | |
409 // Place caret after BR | |
410 r.setStartAfter(br); | |
411 r.setEndAfter(br); | |
412 s.setRng(r); | |
413 | |
414 // Could not place caret after BR then insert an nbsp entity and move the caret | |
415 if (s.getSel().focusNode == br.previousSibling) { | |
416 s.select(dom.insertAfter(dom.doc.createTextNode('\u00a0'), br)); | |
417 s.collapse(1); | |
418 } | |
419 | |
420 // Scroll to new position, scrollIntoView can't be used due to bug: http://bugs.webkit.org/show_bug.cgi?id=16117 | |
421 ed.getWin().scrollTo(0, dom.getPos(s.getRng().startContainer).y); | |
422 } | |
423 }); | |
424 | |
425 // Register plugin | |
426 tinymce.PluginManager.add('safari', tinymce.plugins.Safari); | |
427 })(); | |
428 |