|
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 /*jshint maxlen:255 */ |
|
12 /*eslint max-len:0 */ |
|
13 /*global tinymce:true */ |
|
14 |
|
15 tinymce.PluginManager.add('media', function(editor, url) { |
|
16 var urlPatterns = [ |
|
17 {regex: /youtu\.be\/([\w\-.]+)/, type: 'iframe', w: 425, h: 350, url: '//www.youtube.com/embed/$1'}, |
|
18 {regex: /youtube\.com(.+)v=([^&]+)/, type: 'iframe', w: 425, h: 350, url: '//www.youtube.com/embed/$2'}, |
|
19 {regex: /vimeo\.com\/([0-9]+)/, type: 'iframe', w: 425, h: 350, url: '//player.vimeo.com/video/$1?title=0&byline=0&portrait=0&color=8dc7dc'}, |
|
20 {regex: /vimeo\.com\/(.*)\/([0-9]+)/, type: "iframe", w: 425, h: 350, url: "//player.vimeo.com/video/$2?title=0&byline=0"}, |
|
21 {regex: /maps\.google\.([a-z]{2,3})\/maps\/(.+)msid=(.+)/, type: 'iframe', w: 425, h: 350, url: '//maps.google.com/maps/ms?msid=$2&output=embed"'} |
|
22 ]; |
|
23 |
|
24 var embedChange = (tinymce.Env.ie && tinymce.Env.ie <= 8) ? 'onChange' : 'onInput'; |
|
25 |
|
26 function guessMime(url) { |
|
27 url = url.toLowerCase(); |
|
28 |
|
29 if (url.indexOf('.mp3') != -1) { |
|
30 return 'audio/mpeg'; |
|
31 } |
|
32 |
|
33 if (url.indexOf('.wav') != -1) { |
|
34 return 'audio/wav'; |
|
35 } |
|
36 |
|
37 if (url.indexOf('.mp4') != -1) { |
|
38 return 'video/mp4'; |
|
39 } |
|
40 |
|
41 if (url.indexOf('.webm') != -1) { |
|
42 return 'video/webm'; |
|
43 } |
|
44 |
|
45 if (url.indexOf('.ogg') != -1) { |
|
46 return 'video/ogg'; |
|
47 } |
|
48 |
|
49 if (url.indexOf('.swf') != -1) { |
|
50 return 'application/x-shockwave-flash'; |
|
51 } |
|
52 |
|
53 return ''; |
|
54 } |
|
55 |
|
56 function getVideoScriptMatch(src) { |
|
57 var prefixes = editor.settings.media_scripts; |
|
58 |
|
59 if (prefixes) { |
|
60 for (var i = 0; i < prefixes.length; i++) { |
|
61 if (src.indexOf(prefixes[i].filter) !== -1) { |
|
62 return prefixes[i]; |
|
63 } |
|
64 } |
|
65 } |
|
66 } |
|
67 |
|
68 function showDialog() { |
|
69 var win, width, height, data; |
|
70 |
|
71 var generalFormItems = [ |
|
72 { |
|
73 name: 'source1', |
|
74 type: 'filepicker', |
|
75 filetype: 'media', |
|
76 size: 40, |
|
77 autofocus: true, |
|
78 label: 'Source', |
|
79 onchange: function(e) { |
|
80 tinymce.each(e.meta, function(value, key) { |
|
81 win.find('#' + key).value(value); |
|
82 }); |
|
83 } |
|
84 } |
|
85 ]; |
|
86 |
|
87 function recalcSize(e) { |
|
88 var widthCtrl, heightCtrl, newWidth, newHeight; |
|
89 |
|
90 widthCtrl = win.find('#width')[0]; |
|
91 heightCtrl = win.find('#height')[0]; |
|
92 |
|
93 newWidth = widthCtrl.value(); |
|
94 newHeight = heightCtrl.value(); |
|
95 |
|
96 if (win.find('#constrain')[0].checked() && width && height && newWidth && newHeight) { |
|
97 if (e.control == widthCtrl) { |
|
98 newHeight = Math.round((newWidth / width) * newHeight); |
|
99 |
|
100 if (!isNaN(newHeight)) { |
|
101 heightCtrl.value(newHeight); |
|
102 } |
|
103 } else { |
|
104 newWidth = Math.round((newHeight / height) * newWidth); |
|
105 |
|
106 if (!isNaN(newWidth)) { |
|
107 widthCtrl.value(newWidth); |
|
108 } |
|
109 } |
|
110 } |
|
111 |
|
112 width = newWidth; |
|
113 height = newHeight; |
|
114 } |
|
115 |
|
116 if (editor.settings.media_alt_source !== false) { |
|
117 generalFormItems.push({name: 'source2', type: 'filepicker', filetype: 'media', size: 40, label: 'Alternative source'}); |
|
118 } |
|
119 |
|
120 if (editor.settings.media_poster !== false) { |
|
121 generalFormItems.push({name: 'poster', type: 'filepicker', filetype: 'image', size: 40, label: 'Poster'}); |
|
122 } |
|
123 |
|
124 if (editor.settings.media_dimensions !== false) { |
|
125 generalFormItems.push({ |
|
126 type: 'container', |
|
127 label: 'Dimensions', |
|
128 layout: 'flex', |
|
129 align: 'center', |
|
130 spacing: 5, |
|
131 items: [ |
|
132 {name: 'width', type: 'textbox', maxLength: 5, size: 3, onchange: recalcSize, ariaLabel: 'Width'}, |
|
133 {type: 'label', text: 'x'}, |
|
134 {name: 'height', type: 'textbox', maxLength: 5, size: 3, onchange: recalcSize, ariaLabel: 'Height'}, |
|
135 {name: 'constrain', type: 'checkbox', checked: true, text: 'Constrain proportions'} |
|
136 ] |
|
137 }); |
|
138 } |
|
139 |
|
140 data = getData(editor.selection.getNode()); |
|
141 width = data.width; |
|
142 height = data.height; |
|
143 |
|
144 var embedTextBox = { |
|
145 id: 'mcemediasource', |
|
146 type: 'textbox', |
|
147 flex: 1, |
|
148 name: 'embed', |
|
149 value: getSource(), |
|
150 multiline: true, |
|
151 label: 'Source' |
|
152 }; |
|
153 |
|
154 function updateValueOnChange() { |
|
155 data = htmlToData(this.value()); |
|
156 this.parent().parent().fromJSON(data); |
|
157 } |
|
158 |
|
159 embedTextBox[embedChange] = updateValueOnChange; |
|
160 |
|
161 win = editor.windowManager.open({ |
|
162 title: 'Insert/edit video', |
|
163 data: data, |
|
164 bodyType: 'tabpanel', |
|
165 body: [ |
|
166 { |
|
167 title: 'General', |
|
168 type: "form", |
|
169 onShowTab: function() { |
|
170 data = htmlToData(this.next().find('#embed').value()); |
|
171 this.fromJSON(data); |
|
172 }, |
|
173 items: generalFormItems |
|
174 }, |
|
175 |
|
176 { |
|
177 title: 'Embed', |
|
178 type: "panel", |
|
179 layout: 'flex', |
|
180 direction: 'column', |
|
181 align: 'stretch', |
|
182 padding: 10, |
|
183 spacing: 10, |
|
184 onShowTab: function() { |
|
185 this.find('#embed').value(dataToHtml(this.parent().toJSON())); |
|
186 }, |
|
187 items: [ |
|
188 { |
|
189 type: 'label', |
|
190 text: 'Paste your embed code below:', |
|
191 forId: 'mcemediasource' |
|
192 }, |
|
193 embedTextBox |
|
194 ] |
|
195 } |
|
196 ], |
|
197 onSubmit: function() { |
|
198 var beforeObjects, afterObjects, i, y; |
|
199 |
|
200 beforeObjects = editor.dom.select('img[data-mce-object]'); |
|
201 editor.insertContent(dataToHtml(this.toJSON())); |
|
202 afterObjects = editor.dom.select('img[data-mce-object]'); |
|
203 |
|
204 // Find new image placeholder so we can select it |
|
205 for (i = 0; i < beforeObjects.length; i++) { |
|
206 for (y = afterObjects.length - 1; y >= 0; y--) { |
|
207 if (beforeObjects[i] == afterObjects[y]) { |
|
208 afterObjects.splice(y, 1); |
|
209 } |
|
210 } |
|
211 } |
|
212 |
|
213 editor.selection.select(afterObjects[0]); |
|
214 editor.nodeChanged(); |
|
215 } |
|
216 }); |
|
217 } |
|
218 |
|
219 function getSource() { |
|
220 var elm = editor.selection.getNode(); |
|
221 |
|
222 if (elm.getAttribute('data-mce-object')) { |
|
223 return editor.selection.getContent(); |
|
224 } |
|
225 } |
|
226 |
|
227 function dataToHtml(data) { |
|
228 var html = ''; |
|
229 |
|
230 if (!data.source1) { |
|
231 tinymce.extend(data, htmlToData(data.embed)); |
|
232 if (!data.source1) { |
|
233 return ''; |
|
234 } |
|
235 } |
|
236 |
|
237 if (!data.source2) { |
|
238 data.source2 = ''; |
|
239 } |
|
240 |
|
241 if (!data.poster) { |
|
242 data.poster = ''; |
|
243 } |
|
244 |
|
245 data.source1 = editor.convertURL(data.source1, "source"); |
|
246 data.source2 = editor.convertURL(data.source2, "source"); |
|
247 data.source1mime = guessMime(data.source1); |
|
248 data.source2mime = guessMime(data.source2); |
|
249 data.poster = editor.convertURL(data.poster, "poster"); |
|
250 data.flashPlayerUrl = editor.convertURL(url + '/moxieplayer.swf', "movie"); |
|
251 |
|
252 tinymce.each(urlPatterns, function(pattern) { |
|
253 var match, i, url; |
|
254 |
|
255 if ((match = pattern.regex.exec(data.source1))) { |
|
256 url = pattern.url; |
|
257 |
|
258 for (i = 0; match[i]; i++) { |
|
259 /*jshint loopfunc:true*/ |
|
260 /*eslint no-loop-func:0 */ |
|
261 url = url.replace('$' + i, function() { |
|
262 return match[i]; |
|
263 }); |
|
264 } |
|
265 |
|
266 data.source1 = url; |
|
267 data.type = pattern.type; |
|
268 data.width = data.width || pattern.w; |
|
269 data.height = data.height || pattern.h; |
|
270 } |
|
271 }); |
|
272 |
|
273 if (data.embed) { |
|
274 html = updateHtml(data.embed, data, true); |
|
275 } else { |
|
276 var videoScript = getVideoScriptMatch(data.source1); |
|
277 if (videoScript) { |
|
278 data.type = 'script'; |
|
279 data.width = videoScript.width; |
|
280 data.height = videoScript.height; |
|
281 } |
|
282 |
|
283 data.width = data.width || 300; |
|
284 data.height = data.height || 150; |
|
285 |
|
286 tinymce.each(data, function(value, key) { |
|
287 data[key] = editor.dom.encode(value); |
|
288 }); |
|
289 |
|
290 if (data.type == "iframe") { |
|
291 html += '<iframe src="' + data.source1 + '" width="' + data.width + '" height="' + data.height + '"></iframe>'; |
|
292 } else if (data.source1mime == "application/x-shockwave-flash") { |
|
293 html += '<object data="' + data.source1 + '" width="' + data.width + '" height="' + data.height + '" type="application/x-shockwave-flash">'; |
|
294 |
|
295 if (data.poster) { |
|
296 html += '<img src="' + data.poster + '" width="' + data.width + '" height="' + data.height + '" />'; |
|
297 } |
|
298 |
|
299 html += '</object>'; |
|
300 } else if (data.source1mime.indexOf('audio') != -1) { |
|
301 if (editor.settings.audio_template_callback) { |
|
302 html = editor.settings.audio_template_callback(data); |
|
303 } else { |
|
304 html += ( |
|
305 '<audio controls="controls" src="' + data.source1 + '">' + |
|
306 (data.source2 ? '\n<source src="' + data.source2 + '"' + (data.source2mime ? ' type="' + data.source2mime + '"' : '') + ' />\n' : '') + |
|
307 '</audio>' |
|
308 ); |
|
309 } |
|
310 } else if (data.type == "script") { |
|
311 html += '<script src="' + data.source1 + '"></script>'; |
|
312 } else { |
|
313 if (editor.settings.video_template_callback) { |
|
314 html = editor.settings.video_template_callback(data); |
|
315 } else { |
|
316 html = ( |
|
317 '<video width="' + data.width + '" height="' + data.height + '"' + (data.poster ? ' poster="' + data.poster + '"' : '') + ' controls="controls">\n' + |
|
318 '<source src="' + data.source1 + '"' + (data.source1mime ? ' type="' + data.source1mime + '"' : '') + ' />\n' + |
|
319 (data.source2 ? '<source src="' + data.source2 + '"' + (data.source2mime ? ' type="' + data.source2mime + '"' : '') + ' />\n' : '') + |
|
320 '</video>' |
|
321 ); |
|
322 } |
|
323 } |
|
324 } |
|
325 |
|
326 return html; |
|
327 } |
|
328 |
|
329 function htmlToData(html) { |
|
330 var data = {}; |
|
331 |
|
332 new tinymce.html.SaxParser({ |
|
333 validate: false, |
|
334 allow_conditional_comments: true, |
|
335 special: 'script,noscript', |
|
336 start: function(name, attrs) { |
|
337 if (!data.source1 && name == "param") { |
|
338 data.source1 = attrs.map.movie; |
|
339 } |
|
340 |
|
341 if (name == "iframe" || name == "object" || name == "embed" || name == "video" || name == "audio") { |
|
342 if (!data.type) { |
|
343 data.type = name; |
|
344 } |
|
345 |
|
346 data = tinymce.extend(attrs.map, data); |
|
347 } |
|
348 |
|
349 if (name == "script") { |
|
350 var videoScript = getVideoScriptMatch(attrs.map.src); |
|
351 if (!videoScript) { |
|
352 return; |
|
353 } |
|
354 |
|
355 data = { |
|
356 type: "script", |
|
357 source1: attrs.map.src, |
|
358 width: videoScript.width, |
|
359 height: videoScript.height |
|
360 }; |
|
361 } |
|
362 |
|
363 if (name == "source") { |
|
364 if (!data.source1) { |
|
365 data.source1 = attrs.map.src; |
|
366 } else if (!data.source2) { |
|
367 data.source2 = attrs.map.src; |
|
368 } |
|
369 } |
|
370 |
|
371 if (name == "img" && !data.poster) { |
|
372 data.poster = attrs.map.src; |
|
373 } |
|
374 } |
|
375 }).parse(html); |
|
376 |
|
377 data.source1 = data.source1 || data.src || data.data; |
|
378 data.source2 = data.source2 || ''; |
|
379 data.poster = data.poster || ''; |
|
380 |
|
381 return data; |
|
382 } |
|
383 |
|
384 function getData(element) { |
|
385 if (element.getAttribute('data-mce-object')) { |
|
386 return htmlToData(editor.serializer.serialize(element, {selection: true})); |
|
387 } |
|
388 |
|
389 return {}; |
|
390 } |
|
391 |
|
392 function sanitize(html) { |
|
393 if (editor.settings.media_filter_html === false) { |
|
394 return html; |
|
395 } |
|
396 |
|
397 var writer = new tinymce.html.Writer(); |
|
398 |
|
399 new tinymce.html.SaxParser({ |
|
400 validate: false, |
|
401 allow_conditional_comments: false, |
|
402 special: 'script,noscript', |
|
403 |
|
404 comment: function(text) { |
|
405 writer.comment(text); |
|
406 }, |
|
407 |
|
408 cdata: function(text) { |
|
409 writer.cdata(text); |
|
410 }, |
|
411 |
|
412 text: function(text, raw) { |
|
413 writer.text(text, raw); |
|
414 }, |
|
415 |
|
416 start: function(name, attrs, empty) { |
|
417 if (name == 'script' || name == 'noscript') { |
|
418 return; |
|
419 } |
|
420 |
|
421 for (var i = 0; i < attrs.length; i++) { |
|
422 if (attrs[i].name.indexOf('on') === 0) { |
|
423 return; |
|
424 } |
|
425 } |
|
426 |
|
427 writer.start(name, attrs, empty); |
|
428 }, |
|
429 |
|
430 end: function(name) { |
|
431 if (name == 'script' || name == 'noscript') { |
|
432 return; |
|
433 } |
|
434 |
|
435 writer.end(name); |
|
436 } |
|
437 }, new tinymce.html.Schema({})).parse(html); |
|
438 |
|
439 return writer.getContent(); |
|
440 } |
|
441 |
|
442 function updateHtml(html, data, updateAll) { |
|
443 var writer = new tinymce.html.Writer(); |
|
444 var sourceCount = 0, hasImage; |
|
445 |
|
446 function setAttributes(attrs, updatedAttrs) { |
|
447 var name, i, value, attr; |
|
448 |
|
449 for (name in updatedAttrs) { |
|
450 value = "" + updatedAttrs[name]; |
|
451 |
|
452 if (attrs.map[name]) { |
|
453 i = attrs.length; |
|
454 while (i--) { |
|
455 attr = attrs[i]; |
|
456 |
|
457 if (attr.name == name) { |
|
458 if (value) { |
|
459 attrs.map[name] = value; |
|
460 attr.value = value; |
|
461 } else { |
|
462 delete attrs.map[name]; |
|
463 attrs.splice(i, 1); |
|
464 } |
|
465 } |
|
466 } |
|
467 } else if (value) { |
|
468 attrs.push({ |
|
469 name: name, |
|
470 value: value |
|
471 }); |
|
472 |
|
473 attrs.map[name] = value; |
|
474 } |
|
475 } |
|
476 } |
|
477 |
|
478 new tinymce.html.SaxParser({ |
|
479 validate: false, |
|
480 allow_conditional_comments: true, |
|
481 special: 'script,noscript', |
|
482 |
|
483 comment: function(text) { |
|
484 writer.comment(text); |
|
485 }, |
|
486 |
|
487 cdata: function(text) { |
|
488 writer.cdata(text); |
|
489 }, |
|
490 |
|
491 text: function(text, raw) { |
|
492 writer.text(text, raw); |
|
493 }, |
|
494 |
|
495 start: function(name, attrs, empty) { |
|
496 switch (name) { |
|
497 case "video": |
|
498 case "object": |
|
499 case "embed": |
|
500 case "img": |
|
501 case "iframe": |
|
502 setAttributes(attrs, { |
|
503 width: data.width, |
|
504 height: data.height |
|
505 }); |
|
506 break; |
|
507 } |
|
508 |
|
509 if (updateAll) { |
|
510 switch (name) { |
|
511 case "video": |
|
512 setAttributes(attrs, { |
|
513 poster: data.poster, |
|
514 src: "" |
|
515 }); |
|
516 |
|
517 if (data.source2) { |
|
518 setAttributes(attrs, { |
|
519 src: "" |
|
520 }); |
|
521 } |
|
522 break; |
|
523 |
|
524 case "iframe": |
|
525 setAttributes(attrs, { |
|
526 src: data.source1 |
|
527 }); |
|
528 break; |
|
529 |
|
530 case "source": |
|
531 sourceCount++; |
|
532 |
|
533 if (sourceCount <= 2) { |
|
534 setAttributes(attrs, { |
|
535 src: data["source" + sourceCount], |
|
536 type: data["source" + sourceCount + "mime"] |
|
537 }); |
|
538 |
|
539 if (!data["source" + sourceCount]) { |
|
540 return; |
|
541 } |
|
542 } |
|
543 break; |
|
544 |
|
545 case "img": |
|
546 if (!data.poster) { |
|
547 return; |
|
548 } |
|
549 |
|
550 hasImage = true; |
|
551 break; |
|
552 } |
|
553 } |
|
554 |
|
555 writer.start(name, attrs, empty); |
|
556 }, |
|
557 |
|
558 end: function(name) { |
|
559 if (name == "video" && updateAll) { |
|
560 for (var index = 1; index <= 2; index++) { |
|
561 if (data["source" + index]) { |
|
562 var attrs = []; |
|
563 attrs.map = {}; |
|
564 |
|
565 if (sourceCount < index) { |
|
566 setAttributes(attrs, { |
|
567 src: data["source" + index], |
|
568 type: data["source" + index + "mime"] |
|
569 }); |
|
570 |
|
571 writer.start("source", attrs, true); |
|
572 } |
|
573 } |
|
574 } |
|
575 } |
|
576 |
|
577 if (data.poster && name == "object" && updateAll && !hasImage) { |
|
578 var imgAttrs = []; |
|
579 imgAttrs.map = {}; |
|
580 |
|
581 setAttributes(imgAttrs, { |
|
582 src: data.poster, |
|
583 width: data.width, |
|
584 height: data.height |
|
585 }); |
|
586 |
|
587 writer.start("img", imgAttrs, true); |
|
588 } |
|
589 |
|
590 writer.end(name); |
|
591 } |
|
592 }, new tinymce.html.Schema({})).parse(html); |
|
593 |
|
594 return writer.getContent(); |
|
595 } |
|
596 |
|
597 editor.on('ResolveName', function(e) { |
|
598 var name; |
|
599 |
|
600 if (e.target.nodeType == 1 && (name = e.target.getAttribute("data-mce-object"))) { |
|
601 e.name = name; |
|
602 } |
|
603 }); |
|
604 |
|
605 editor.on('preInit', function() { |
|
606 // Make sure that any messy HTML is retained inside these |
|
607 var specialElements = editor.schema.getSpecialElements(); |
|
608 tinymce.each('video audio iframe object'.split(' '), function(name) { |
|
609 specialElements[name] = new RegExp('<\/' + name + '[^>]*>', 'gi'); |
|
610 }); |
|
611 |
|
612 // Allow elements |
|
613 //editor.schema.addValidElements('object[id|style|width|height|classid|codebase|*],embed[id|style|width|height|type|src|*],video[*],audio[*]'); |
|
614 |
|
615 // Set allowFullscreen attribs as boolean |
|
616 var boolAttrs = editor.schema.getBoolAttrs(); |
|
617 tinymce.each('webkitallowfullscreen mozallowfullscreen allowfullscreen'.split(' '), function(name) { |
|
618 boolAttrs[name] = {}; |
|
619 }); |
|
620 |
|
621 // Converts iframe, video etc into placeholder images |
|
622 editor.parser.addNodeFilter('iframe,video,audio,object,embed,script', function(nodes, name) { |
|
623 var i = nodes.length, ai, node, placeHolder, attrName, attrValue, attribs, innerHtml; |
|
624 var videoScript; |
|
625 |
|
626 while (i--) { |
|
627 node = nodes[i]; |
|
628 if (!node.parent) { |
|
629 continue; |
|
630 } |
|
631 |
|
632 if (node.name == 'script') { |
|
633 videoScript = getVideoScriptMatch(node.attr('src')); |
|
634 if (!videoScript) { |
|
635 continue; |
|
636 } |
|
637 } |
|
638 |
|
639 placeHolder = new tinymce.html.Node('img', 1); |
|
640 placeHolder.shortEnded = true; |
|
641 |
|
642 if (videoScript) { |
|
643 if (videoScript.width) { |
|
644 node.attr('width', videoScript.width.toString()); |
|
645 } |
|
646 |
|
647 if (videoScript.height) { |
|
648 node.attr('height', videoScript.height.toString()); |
|
649 } |
|
650 } |
|
651 |
|
652 // Prefix all attributes except width, height and style since we |
|
653 // will add these to the placeholder |
|
654 attribs = node.attributes; |
|
655 ai = attribs.length; |
|
656 while (ai--) { |
|
657 attrName = attribs[ai].name; |
|
658 attrValue = attribs[ai].value; |
|
659 |
|
660 if (attrName !== "width" && attrName !== "height" && attrName !== "style") { |
|
661 if (attrName == "data" || attrName == "src") { |
|
662 attrValue = editor.convertURL(attrValue, attrName); |
|
663 } |
|
664 |
|
665 placeHolder.attr('data-mce-p-' + attrName, attrValue); |
|
666 } |
|
667 } |
|
668 |
|
669 // Place the inner HTML contents inside an escaped attribute |
|
670 // This enables us to copy/paste the fake object |
|
671 innerHtml = node.firstChild && node.firstChild.value; |
|
672 if (innerHtml) { |
|
673 placeHolder.attr("data-mce-html", escape(innerHtml)); |
|
674 placeHolder.firstChild = null; |
|
675 } |
|
676 |
|
677 placeHolder.attr({ |
|
678 width: node.attr('width') || "300", |
|
679 height: node.attr('height') || (name == "audio" ? "30" : "150"), |
|
680 style: node.attr('style'), |
|
681 src: tinymce.Env.transparentSrc, |
|
682 "data-mce-object": name, |
|
683 "class": "mce-object mce-object-" + name |
|
684 }); |
|
685 |
|
686 node.replace(placeHolder); |
|
687 } |
|
688 }); |
|
689 |
|
690 // Replaces placeholder images with real elements for video, object, iframe etc |
|
691 editor.serializer.addAttributeFilter('data-mce-object', function(nodes, name) { |
|
692 var i = nodes.length, node, realElm, ai, attribs, innerHtml, innerNode, realElmName; |
|
693 |
|
694 while (i--) { |
|
695 node = nodes[i]; |
|
696 if (!node.parent) { |
|
697 continue; |
|
698 } |
|
699 |
|
700 realElmName = node.attr(name); |
|
701 realElm = new tinymce.html.Node(realElmName, 1); |
|
702 |
|
703 // Add width/height to everything but audio |
|
704 if (realElmName != "audio" && realElmName != "script") { |
|
705 realElm.attr({ |
|
706 width: node.attr('width'), |
|
707 height: node.attr('height') |
|
708 }); |
|
709 } |
|
710 |
|
711 realElm.attr({ |
|
712 style: node.attr('style') |
|
713 }); |
|
714 |
|
715 // Unprefix all placeholder attributes |
|
716 attribs = node.attributes; |
|
717 ai = attribs.length; |
|
718 while (ai--) { |
|
719 var attrName = attribs[ai].name; |
|
720 |
|
721 if (attrName.indexOf('data-mce-p-') === 0) { |
|
722 realElm.attr(attrName.substr(11), attribs[ai].value); |
|
723 } |
|
724 } |
|
725 |
|
726 if (realElmName == "script") { |
|
727 realElm.attr('type', 'text/javascript'); |
|
728 } |
|
729 |
|
730 // Inject innerhtml |
|
731 innerHtml = node.attr('data-mce-html'); |
|
732 if (innerHtml) { |
|
733 innerNode = new tinymce.html.Node('#text', 3); |
|
734 innerNode.raw = true; |
|
735 innerNode.value = sanitize(unescape(innerHtml)); |
|
736 realElm.append(innerNode); |
|
737 } |
|
738 |
|
739 node.replace(realElm); |
|
740 } |
|
741 }); |
|
742 }); |
|
743 |
|
744 editor.on('ObjectSelected', function(e) { |
|
745 var objectType = e.target.getAttribute('data-mce-object'); |
|
746 |
|
747 if (objectType == "audio" || objectType == "script") { |
|
748 e.preventDefault(); |
|
749 } |
|
750 }); |
|
751 |
|
752 editor.on('objectResized', function(e) { |
|
753 var target = e.target, html; |
|
754 |
|
755 if (target.getAttribute('data-mce-object')) { |
|
756 html = target.getAttribute('data-mce-html'); |
|
757 if (html) { |
|
758 html = unescape(html); |
|
759 target.setAttribute('data-mce-html', escape( |
|
760 updateHtml(html, { |
|
761 width: e.width, |
|
762 height: e.height |
|
763 }) |
|
764 )); |
|
765 } |
|
766 } |
|
767 }); |
|
768 |
|
769 editor.addButton('media', { |
|
770 tooltip: 'Insert/edit video', |
|
771 onclick: showDialog, |
|
772 stateSelector: ['img[data-mce-object=video]', 'img[data-mce-object=iframe]'] |
|
773 }); |
|
774 |
|
775 editor.addMenuItem('media', { |
|
776 icon: 'media', |
|
777 text: 'Insert/edit video', |
|
778 onclick: showDialog, |
|
779 context: 'insert', |
|
780 prependToContext: true |
|
781 }); |
|
782 }); |