plugin.js 42 KB

12345678910111213141516171819202122232425262728293031323334353637383940414243444546474849505152535455565758596061626364656667686970717273747576777879808182838485868788899091929394959697989910010110210310410510610710810911011111211311411511611711811912012112212312412512612712812913013113213313413513613713813914014114214314414514614714814915015115215315415515615715815916016116216316416516616716816917017117217317417517617717817918018118218318418518618718818919019119219319419519619719819920020120220320420520620720820921021121221321421521621721821922022122222322422522622722822923023123223323423523623723823924024124224324424524624724824925025125225325425525625725825926026126226326426526626726826927027127227327427527627727827928028128228328428528628728828929029129229329429529629729829930030130230330430530630730830931031131231331431531631731831932032132232332432532632732832933033133233333433533633733833934034134234334434534634734834935035135235335435535635735835936036136236336436536636736836937037137237337437537637737837938038138238338438538638738838939039139239339439539639739839940040140240340440540640740840941041141241341441541641741841942042142242342442542642742842943043143243343443543643743843944044144244344444544644744844945045145245345445545645745845946046146246346446546646746846947047147247347447547647747847948048148248348448548648748848949049149249349449549649749849950050150250350450550650750850951051151251351451551651751851952052152252352452552652752852953053153253353453553653753853954054154254354454554654754854955055155255355455555655755855956056156256356456556656756856957057157257357457557657757857958058158258358458558658758858959059159259359459559659759859960060160260360460560660760860961061161261361461561661761861962062162262362462562662762862963063163263363463563663763863964064164264364464564664764864965065165265365465565665765865966066166266366466566666766866967067167267367467567667767867968068168268368468568668768868969069169269369469569669769869970070170270370470570670770870971071171271371471571671771871972072172272372472572672772872973073173273373473573673773873974074174274374474574674774874975075175275375475575675775875976076176276376476576676776876977077177277377477577677777877978078178278378478578678778878979079179279379479579679779879980080180280380480580680780880981081181281381481581681781881982082182282382482582682782882983083183283383483583683783883984084184284384484584684784884985085185285385485585685785885986086186286386486586686786886987087187287387487587687787887988088188288388488588688788888989089189289389489589689789889990090190290390490590690790890991091191291391491591691791891992092192292392492592692792892993093193293393493593693793893994094194294394494594694794894995095195295395495595695795895996096196296396496596696796896997097197297397497597697797897998098198298398498598698798898999099199299399499599699799899910001001100210031004100510061007100810091010101110121013101410151016101710181019102010211022102310241025102610271028102910301031103210331034103510361037103810391040104110421043104410451046104710481049105010511052105310541055105610571058105910601061106210631064106510661067106810691070107110721073107410751076107710781079108010811082108310841085108610871088108910901091109210931094109510961097109810991100110111021103110411051106110711081109111011111112111311141115111611171118111911201121112211231124112511261127112811291130113111321133113411351136113711381139114011411142114311441145114611471148114911501151115211531154115511561157115811591160116111621163116411651166116711681169117011711172117311741175117611771178117911801181118211831184118511861187118811891190119111921193119411951196119711981199120012011202120312041205120612071208120912101211121212131214121512161217121812191220122112221223122412251226122712281229123012311232123312341235123612371238123912401241124212431244124512461247124812491250125112521253125412551256125712581259126012611262126312641265126612671268126912701271127212731274127512761277127812791280128112821283128412851286128712881289129012911292129312941295129612971298129913001301130213031304130513061307130813091310131113121313131413151316131713181319132013211322132313241325132613271328132913301331133213331334133513361337133813391340134113421343134413451346134713481349
  1. /**
  2. * Copyright (c) Tiny Technologies, Inc. All rights reserved.
  3. * Licensed under the LGPL or a commercial license.
  4. * For LGPL see License.txt in the project root for license information.
  5. * For commercial licenses see https://www.tiny.cloud/
  6. *
  7. * Version: 5.0.7 (2019-06-05)
  8. */
  9. (function () {
  10. var media = (function () {
  11. 'use strict';
  12. var global = tinymce.util.Tools.resolve('tinymce.PluginManager');
  13. var typeOf = function (x) {
  14. if (x === null)
  15. return 'null';
  16. var t = typeof x;
  17. if (t === 'object' && Array.prototype.isPrototypeOf(x))
  18. return 'array';
  19. if (t === 'object' && String.prototype.isPrototypeOf(x))
  20. return 'string';
  21. return t;
  22. };
  23. var isType = function (type) {
  24. return function (value) {
  25. return typeOf(value) === type;
  26. };
  27. };
  28. var isString = isType('string');
  29. var isFunction = isType('function');
  30. var hasOwnProperty = Object.prototype.hasOwnProperty;
  31. var shallow = function (old, nu) {
  32. return nu;
  33. };
  34. var baseMerge = function (merger) {
  35. return function () {
  36. var objects = new Array(arguments.length);
  37. for (var i = 0; i < objects.length; i++)
  38. objects[i] = arguments[i];
  39. if (objects.length === 0)
  40. throw new Error('Can\'t merge zero objects');
  41. var ret = {};
  42. for (var j = 0; j < objects.length; j++) {
  43. var curObject = objects[j];
  44. for (var key in curObject)
  45. if (hasOwnProperty.call(curObject, key)) {
  46. ret[key] = merger(ret[key], curObject[key]);
  47. }
  48. }
  49. return ret;
  50. };
  51. };
  52. var merge = baseMerge(shallow);
  53. var constant = function (value) {
  54. return function () {
  55. return value;
  56. };
  57. };
  58. var never = constant(false);
  59. var always = constant(true);
  60. var never$1 = never;
  61. var always$1 = always;
  62. var none = function () {
  63. return NONE;
  64. };
  65. var NONE = function () {
  66. var eq = function (o) {
  67. return o.isNone();
  68. };
  69. var call = function (thunk) {
  70. return thunk();
  71. };
  72. var id = function (n) {
  73. return n;
  74. };
  75. var noop = function () {
  76. };
  77. var nul = function () {
  78. return null;
  79. };
  80. var undef = function () {
  81. return undefined;
  82. };
  83. var me = {
  84. fold: function (n, s) {
  85. return n();
  86. },
  87. is: never$1,
  88. isSome: never$1,
  89. isNone: always$1,
  90. getOr: id,
  91. getOrThunk: call,
  92. getOrDie: function (msg) {
  93. throw new Error(msg || 'error: getOrDie called on none.');
  94. },
  95. getOrNull: nul,
  96. getOrUndefined: undef,
  97. or: id,
  98. orThunk: call,
  99. map: none,
  100. ap: none,
  101. each: noop,
  102. bind: none,
  103. flatten: none,
  104. exists: never$1,
  105. forall: always$1,
  106. filter: none,
  107. equals: eq,
  108. equals_: eq,
  109. toArray: function () {
  110. return [];
  111. },
  112. toString: constant('none()')
  113. };
  114. if (Object.freeze)
  115. Object.freeze(me);
  116. return me;
  117. }();
  118. var some = function (a) {
  119. var constant_a = function () {
  120. return a;
  121. };
  122. var self = function () {
  123. return me;
  124. };
  125. var map = function (f) {
  126. return some(f(a));
  127. };
  128. var bind = function (f) {
  129. return f(a);
  130. };
  131. var me = {
  132. fold: function (n, s) {
  133. return s(a);
  134. },
  135. is: function (v) {
  136. return a === v;
  137. },
  138. isSome: always$1,
  139. isNone: never$1,
  140. getOr: constant_a,
  141. getOrThunk: constant_a,
  142. getOrDie: constant_a,
  143. getOrNull: constant_a,
  144. getOrUndefined: constant_a,
  145. or: self,
  146. orThunk: self,
  147. map: map,
  148. ap: function (optfab) {
  149. return optfab.fold(none, function (fab) {
  150. return some(fab(a));
  151. });
  152. },
  153. each: function (f) {
  154. f(a);
  155. },
  156. bind: bind,
  157. flatten: constant_a,
  158. exists: bind,
  159. forall: bind,
  160. filter: function (f) {
  161. return f(a) ? me : NONE;
  162. },
  163. equals: function (o) {
  164. return o.is(a);
  165. },
  166. equals_: function (o, elementEq) {
  167. return o.fold(never$1, function (b) {
  168. return elementEq(a, b);
  169. });
  170. },
  171. toArray: function () {
  172. return [a];
  173. },
  174. toString: function () {
  175. return 'some(' + a + ')';
  176. }
  177. };
  178. return me;
  179. };
  180. var from = function (value) {
  181. return value === null || value === undefined ? NONE : some(value);
  182. };
  183. var Option = {
  184. some: some,
  185. none: none,
  186. from: from
  187. };
  188. var hasOwnProperty$1 = Object.hasOwnProperty;
  189. var get = function (obj, key) {
  190. return has(obj, key) ? Option.from(obj[key]) : Option.none();
  191. };
  192. var has = function (obj, key) {
  193. return hasOwnProperty$1.call(obj, key);
  194. };
  195. var slice = Array.prototype.slice;
  196. var each = function (xs, f) {
  197. for (var i = 0, len = xs.length; i < len; i++) {
  198. var x = xs[i];
  199. f(x, i, xs);
  200. }
  201. };
  202. var push = Array.prototype.push;
  203. var flatten = function (xs) {
  204. var r = [];
  205. for (var i = 0, len = xs.length; i < len; ++i) {
  206. if (!Array.prototype.isPrototypeOf(xs[i]))
  207. throw new Error('Arr.flatten item ' + i + ' was not an array, input: ' + xs);
  208. push.apply(r, xs[i]);
  209. }
  210. return r;
  211. };
  212. var from$1 = isFunction(Array.from) ? Array.from : function (x) {
  213. return slice.call(x);
  214. };
  215. var global$1 = tinymce.util.Tools.resolve('tinymce.util.Tools');
  216. var getScripts = function (editor) {
  217. return editor.getParam('media_scripts');
  218. };
  219. var getAudioTemplateCallback = function (editor) {
  220. return editor.getParam('audio_template_callback');
  221. };
  222. var getVideoTemplateCallback = function (editor) {
  223. return editor.getParam('video_template_callback');
  224. };
  225. var hasLiveEmbeds = function (editor) {
  226. return editor.getParam('media_live_embeds', true);
  227. };
  228. var shouldFilterHtml = function (editor) {
  229. return editor.getParam('media_filter_html', true);
  230. };
  231. var getUrlResolver = function (editor) {
  232. return editor.getParam('media_url_resolver');
  233. };
  234. var hasAltSource = function (editor) {
  235. return editor.getParam('media_alt_source', true);
  236. };
  237. var hasPoster = function (editor) {
  238. return editor.getParam('media_poster', true);
  239. };
  240. var hasDimensions = function (editor) {
  241. return editor.getParam('media_dimensions', true);
  242. };
  243. var Settings = {
  244. getScripts: getScripts,
  245. getAudioTemplateCallback: getAudioTemplateCallback,
  246. getVideoTemplateCallback: getVideoTemplateCallback,
  247. hasLiveEmbeds: hasLiveEmbeds,
  248. shouldFilterHtml: shouldFilterHtml,
  249. getUrlResolver: getUrlResolver,
  250. hasAltSource: hasAltSource,
  251. hasPoster: hasPoster,
  252. hasDimensions: hasDimensions
  253. };
  254. var global$2 = tinymce.util.Tools.resolve('tinymce.html.SaxParser');
  255. var global$3 = tinymce.util.Tools.resolve('tinymce.dom.DOMUtils');
  256. var getVideoScriptMatch = function (prefixes, src) {
  257. if (prefixes) {
  258. for (var i = 0; i < prefixes.length; i++) {
  259. if (src.indexOf(prefixes[i].filter) !== -1) {
  260. return prefixes[i];
  261. }
  262. }
  263. }
  264. };
  265. var VideoScript = { getVideoScriptMatch: getVideoScriptMatch };
  266. var trimPx = function (value) {
  267. return value.replace(/px$/, '');
  268. };
  269. var addPx = function (value) {
  270. return /^[0-9.]+$/.test(value) ? value + 'px' : value;
  271. };
  272. var getSize = function (name) {
  273. return function (elm) {
  274. return elm ? trimPx(elm.style[name]) : '';
  275. };
  276. };
  277. var setSize = function (name) {
  278. return function (elm, value) {
  279. if (elm) {
  280. elm.style[name] = addPx(value);
  281. }
  282. };
  283. };
  284. var Size = {
  285. getMaxWidth: getSize('maxWidth'),
  286. getMaxHeight: getSize('maxHeight'),
  287. setMaxWidth: setSize('maxWidth'),
  288. setMaxHeight: setSize('maxHeight')
  289. };
  290. var DOM = global$3.DOM;
  291. var getEphoxEmbedIri = function (elm) {
  292. return DOM.getAttrib(elm, 'data-ephox-embed-iri');
  293. };
  294. var isEphoxEmbed = function (html) {
  295. var fragment = DOM.createFragment(html);
  296. return getEphoxEmbedIri(fragment.firstChild) !== '';
  297. };
  298. var htmlToDataSax = function (prefixes, html) {
  299. var data = {};
  300. global$2({
  301. validate: false,
  302. allow_conditional_comments: true,
  303. start: function (name, attrs) {
  304. if (!data.source1 && name === 'param') {
  305. data.source1 = attrs.map.movie;
  306. }
  307. if (name === 'iframe' || name === 'object' || name === 'embed' || name === 'video' || name === 'audio') {
  308. if (!data.type) {
  309. data.type = name;
  310. }
  311. data = global$1.extend(attrs.map, data);
  312. }
  313. if (name === 'script') {
  314. var videoScript = VideoScript.getVideoScriptMatch(prefixes, attrs.map.src);
  315. if (!videoScript) {
  316. return;
  317. }
  318. data = {
  319. type: 'script',
  320. source1: attrs.map.src,
  321. width: videoScript.width,
  322. height: videoScript.height
  323. };
  324. }
  325. if (name === 'source') {
  326. if (!data.source1) {
  327. data.source1 = attrs.map.src;
  328. } else if (!data.source2) {
  329. data.source2 = attrs.map.src;
  330. }
  331. }
  332. if (name === 'img' && !data.poster) {
  333. data.poster = attrs.map.src;
  334. }
  335. }
  336. }).parse(html);
  337. data.source1 = data.source1 || data.src || data.data;
  338. data.source2 = data.source2 || '';
  339. data.poster = data.poster || '';
  340. return data;
  341. };
  342. var ephoxEmbedHtmlToData = function (html) {
  343. var fragment = DOM.createFragment(html);
  344. var div = fragment.firstChild;
  345. return {
  346. type: 'ephox-embed-iri',
  347. source1: getEphoxEmbedIri(div),
  348. source2: '',
  349. poster: '',
  350. width: Size.getMaxWidth(div),
  351. height: Size.getMaxHeight(div)
  352. };
  353. };
  354. var htmlToData = function (prefixes, html) {
  355. return isEphoxEmbed(html) ? ephoxEmbedHtmlToData(html) : htmlToDataSax(prefixes, html);
  356. };
  357. var HtmlToData = { htmlToData: htmlToData };
  358. var global$4 = tinymce.util.Tools.resolve('tinymce.util.Promise');
  359. var guess = function (url) {
  360. var mimes = {
  361. mp3: 'audio/mpeg',
  362. wav: 'audio/wav',
  363. mp4: 'video/mp4',
  364. webm: 'video/webm',
  365. ogg: 'video/ogg',
  366. swf: 'application/x-shockwave-flash'
  367. };
  368. var fileEnd = url.toLowerCase().split('.').pop();
  369. var mime = mimes[fileEnd];
  370. return mime ? mime : '';
  371. };
  372. var Mime = { guess: guess };
  373. var global$5 = tinymce.util.Tools.resolve('tinymce.html.Writer');
  374. var global$6 = tinymce.util.Tools.resolve('tinymce.html.Schema');
  375. var DOM$1 = global$3.DOM;
  376. var setAttributes = function (attrs, updatedAttrs) {
  377. var name;
  378. var i;
  379. var value;
  380. var attr;
  381. for (name in updatedAttrs) {
  382. value = '' + updatedAttrs[name];
  383. if (attrs.map[name]) {
  384. i = attrs.length;
  385. while (i--) {
  386. attr = attrs[i];
  387. if (attr.name === name) {
  388. if (value) {
  389. attrs.map[name] = value;
  390. attr.value = value;
  391. } else {
  392. delete attrs.map[name];
  393. attrs.splice(i, 1);
  394. }
  395. }
  396. }
  397. } else if (value) {
  398. attrs.push({
  399. name: name,
  400. value: value
  401. });
  402. attrs.map[name] = value;
  403. }
  404. }
  405. };
  406. var normalizeHtml = function (html) {
  407. var writer = global$5();
  408. var parser = global$2(writer);
  409. parser.parse(html);
  410. return writer.getContent();
  411. };
  412. var updateHtmlSax = function (html, data, updateAll) {
  413. var writer = global$5();
  414. var sourceCount = 0;
  415. var hasImage;
  416. global$2({
  417. validate: false,
  418. allow_conditional_comments: true,
  419. comment: function (text) {
  420. writer.comment(text);
  421. },
  422. cdata: function (text) {
  423. writer.cdata(text);
  424. },
  425. text: function (text, raw) {
  426. writer.text(text, raw);
  427. },
  428. start: function (name, attrs, empty) {
  429. switch (name) {
  430. case 'video':
  431. case 'object':
  432. case 'embed':
  433. case 'img':
  434. case 'iframe':
  435. if (data.height !== undefined && data.width !== undefined) {
  436. setAttributes(attrs, {
  437. width: data.width,
  438. height: data.height
  439. });
  440. }
  441. break;
  442. }
  443. if (updateAll) {
  444. switch (name) {
  445. case 'video':
  446. setAttributes(attrs, {
  447. poster: data.poster,
  448. src: ''
  449. });
  450. if (data.source2) {
  451. setAttributes(attrs, { src: '' });
  452. }
  453. break;
  454. case 'iframe':
  455. setAttributes(attrs, { src: data.source1 });
  456. break;
  457. case 'source':
  458. sourceCount++;
  459. if (sourceCount <= 2) {
  460. setAttributes(attrs, {
  461. src: data['source' + sourceCount],
  462. type: data['source' + sourceCount + 'mime']
  463. });
  464. if (!data['source' + sourceCount]) {
  465. return;
  466. }
  467. }
  468. break;
  469. case 'img':
  470. if (!data.poster) {
  471. return;
  472. }
  473. hasImage = true;
  474. break;
  475. }
  476. }
  477. writer.start(name, attrs, empty);
  478. },
  479. end: function (name) {
  480. if (name === 'video' && updateAll) {
  481. for (var index = 1; index <= 2; index++) {
  482. if (data['source' + index]) {
  483. var attrs = [];
  484. attrs.map = {};
  485. if (sourceCount < index) {
  486. setAttributes(attrs, {
  487. src: data['source' + index],
  488. type: data['source' + index + 'mime']
  489. });
  490. writer.start('source', attrs, true);
  491. }
  492. }
  493. }
  494. }
  495. if (data.poster && name === 'object' && updateAll && !hasImage) {
  496. var imgAttrs = [];
  497. imgAttrs.map = {};
  498. setAttributes(imgAttrs, {
  499. src: data.poster,
  500. width: data.width,
  501. height: data.height
  502. });
  503. writer.start('img', imgAttrs, true);
  504. }
  505. writer.end(name);
  506. }
  507. }, global$6({})).parse(html);
  508. return writer.getContent();
  509. };
  510. var isEphoxEmbed$1 = function (html) {
  511. var fragment = DOM$1.createFragment(html);
  512. return DOM$1.getAttrib(fragment.firstChild, 'data-ephox-embed-iri') !== '';
  513. };
  514. var updateEphoxEmbed = function (html, data) {
  515. var fragment = DOM$1.createFragment(html);
  516. var div = fragment.firstChild;
  517. Size.setMaxWidth(div, data.width);
  518. Size.setMaxHeight(div, data.height);
  519. return normalizeHtml(div.outerHTML);
  520. };
  521. var updateHtml = function (html, data, updateAll) {
  522. return isEphoxEmbed$1(html) ? updateEphoxEmbed(html, data) : updateHtmlSax(html, data, updateAll);
  523. };
  524. var UpdateHtml = { updateHtml: updateHtml };
  525. var urlPatterns = [
  526. {
  527. regex: /youtu\.be\/([\w\-_\?&=.]+)/i,
  528. type: 'iframe',
  529. w: 560,
  530. h: 314,
  531. url: '//www.youtube.com/embed/$1',
  532. allowFullscreen: true
  533. },
  534. {
  535. regex: /youtube\.com(.+)v=([^&]+)(&([a-z0-9&=\-_]+))?/i,
  536. type: 'iframe',
  537. w: 560,
  538. h: 314,
  539. url: '//www.youtube.com/embed/$2?$4',
  540. allowFullscreen: true
  541. },
  542. {
  543. regex: /youtube.com\/embed\/([a-z0-9\?&=\-_]+)/i,
  544. type: 'iframe',
  545. w: 560,
  546. h: 314,
  547. url: '//www.youtube.com/embed/$1',
  548. allowFullscreen: true
  549. },
  550. {
  551. regex: /vimeo\.com\/([0-9]+)/,
  552. type: 'iframe',
  553. w: 425,
  554. h: 350,
  555. url: '//player.vimeo.com/video/$1?title=0&byline=0&portrait=0&color=8dc7dc',
  556. allowFullscreen: true
  557. },
  558. {
  559. regex: /vimeo\.com\/(.*)\/([0-9]+)/,
  560. type: 'iframe',
  561. w: 425,
  562. h: 350,
  563. url: '//player.vimeo.com/video/$2?title=0&amp;byline=0',
  564. allowFullscreen: true
  565. },
  566. {
  567. regex: /maps\.google\.([a-z]{2,3})\/maps\/(.+)msid=(.+)/,
  568. type: 'iframe',
  569. w: 425,
  570. h: 350,
  571. url: '//maps.google.com/maps/ms?msid=$2&output=embed"',
  572. allowFullscreen: false
  573. },
  574. {
  575. regex: /dailymotion\.com\/video\/([^_]+)/,
  576. type: 'iframe',
  577. w: 480,
  578. h: 270,
  579. url: '//www.dailymotion.com/embed/video/$1',
  580. allowFullscreen: true
  581. },
  582. {
  583. regex: /dai\.ly\/([^_]+)/,
  584. type: 'iframe',
  585. w: 480,
  586. h: 270,
  587. url: '//www.dailymotion.com/embed/video/$1',
  588. allowFullscreen: true
  589. }
  590. ];
  591. var getUrl = function (pattern, url) {
  592. var match = pattern.regex.exec(url);
  593. var newUrl = pattern.url;
  594. var _loop_1 = function (i) {
  595. newUrl = newUrl.replace('$' + i, function () {
  596. return match[i] ? match[i] : '';
  597. });
  598. };
  599. for (var i = 0; i < match.length; i++) {
  600. _loop_1(i);
  601. }
  602. return newUrl.replace(/\?$/, '');
  603. };
  604. var matchPattern = function (url) {
  605. var pattern = urlPatterns.filter(function (pattern) {
  606. return pattern.regex.test(url);
  607. });
  608. if (pattern.length > 0) {
  609. return global$1.extend({}, pattern[0], { url: getUrl(pattern[0], url) });
  610. } else {
  611. return null;
  612. }
  613. };
  614. var getIframeHtml = function (data) {
  615. var allowFullscreen = data.allowFullscreen ? ' allowFullscreen="1"' : '';
  616. return '<iframe src="' + data.source1 + '" width="' + data.width + '" height="' + data.height + '"' + allowFullscreen + '></iframe>';
  617. };
  618. var getFlashHtml = function (data) {
  619. var html = '<object data="' + data.source1 + '" width="' + data.width + '" height="' + data.height + '" type="application/x-shockwave-flash">';
  620. if (data.poster) {
  621. html += '<img src="' + data.poster + '" width="' + data.width + '" height="' + data.height + '" />';
  622. }
  623. html += '</object>';
  624. return html;
  625. };
  626. var getAudioHtml = function (data, audioTemplateCallback) {
  627. if (audioTemplateCallback) {
  628. return audioTemplateCallback(data);
  629. } else {
  630. return '<audio controls="controls" src="' + data.source1 + '">' + (data.source2 ? '\n<source src="' + data.source2 + '"' + (data.source2mime ? ' type="' + data.source2mime + '"' : '') + ' />\n' : '') + '</audio>';
  631. }
  632. };
  633. var getVideoHtml = function (data, videoTemplateCallback) {
  634. if (videoTemplateCallback) {
  635. return videoTemplateCallback(data);
  636. } else {
  637. return '<video width="' + data.width + '" height="' + data.height + '"' + (data.poster ? ' poster="' + data.poster + '"' : '') + ' controls="controls">\n' + '<source src="' + data.source1 + '"' + (data.source1mime ? ' type="' + data.source1mime + '"' : '') + ' />\n' + (data.source2 ? '<source src="' + data.source2 + '"' + (data.source2mime ? ' type="' + data.source2mime + '"' : '') + ' />\n' : '') + '</video>';
  638. }
  639. };
  640. var getScriptHtml = function (data) {
  641. return '<script src="' + data.source1 + '"></script>';
  642. };
  643. var dataToHtml = function (editor, dataIn) {
  644. var data = global$1.extend({}, dataIn);
  645. if (!data.source1) {
  646. global$1.extend(data, HtmlToData.htmlToData(Settings.getScripts(editor), data.embed));
  647. if (!data.source1) {
  648. return '';
  649. }
  650. }
  651. if (!data.source2) {
  652. data.source2 = '';
  653. }
  654. if (!data.poster) {
  655. data.poster = '';
  656. }
  657. data.source1 = editor.convertURL(data.source1, 'source');
  658. data.source2 = editor.convertURL(data.source2, 'source');
  659. data.source1mime = Mime.guess(data.source1);
  660. data.source2mime = Mime.guess(data.source2);
  661. data.poster = editor.convertURL(data.poster, 'poster');
  662. var pattern = matchPattern(data.source1);
  663. if (pattern) {
  664. data.source1 = pattern.url;
  665. data.type = pattern.type;
  666. data.allowFullscreen = pattern.allowFullscreen;
  667. data.width = data.width || pattern.w;
  668. data.height = data.height || pattern.h;
  669. }
  670. if (data.embed) {
  671. return UpdateHtml.updateHtml(data.embed, data, true);
  672. } else {
  673. var videoScript = VideoScript.getVideoScriptMatch(Settings.getScripts(editor), data.source1);
  674. if (videoScript) {
  675. data.type = 'script';
  676. data.width = videoScript.width;
  677. data.height = videoScript.height;
  678. }
  679. var audioTemplateCallback = Settings.getAudioTemplateCallback(editor);
  680. var videoTemplateCallback = Settings.getVideoTemplateCallback(editor);
  681. data.width = data.width || 300;
  682. data.height = data.height || 150;
  683. global$1.each(data, function (value, key) {
  684. data[key] = editor.dom.encode('' + value);
  685. });
  686. if (data.type === 'iframe') {
  687. return getIframeHtml(data);
  688. } else if (data.source1mime === 'application/x-shockwave-flash') {
  689. return getFlashHtml(data);
  690. } else if (data.source1mime.indexOf('audio') !== -1) {
  691. return getAudioHtml(data, audioTemplateCallback);
  692. } else if (data.type === 'script') {
  693. return getScriptHtml(data);
  694. } else {
  695. return getVideoHtml(data, videoTemplateCallback);
  696. }
  697. }
  698. };
  699. var DataToHtml = { dataToHtml: dataToHtml };
  700. var cache = {};
  701. var embedPromise = function (data, dataToHtml, handler) {
  702. return new global$4(function (res, rej) {
  703. var wrappedResolve = function (response) {
  704. if (response.html) {
  705. cache[data.source1] = response;
  706. }
  707. return res({
  708. url: data.source1,
  709. html: response.html ? response.html : dataToHtml(data)
  710. });
  711. };
  712. if (cache[data.source1]) {
  713. wrappedResolve(cache[data.source1]);
  714. } else {
  715. handler({ url: data.source1 }, wrappedResolve, rej);
  716. }
  717. });
  718. };
  719. var defaultPromise = function (data, dataToHtml) {
  720. return new global$4(function (res) {
  721. res({
  722. html: dataToHtml(data),
  723. url: data.source1
  724. });
  725. });
  726. };
  727. var loadedData = function (editor) {
  728. return function (data) {
  729. return DataToHtml.dataToHtml(editor, data);
  730. };
  731. };
  732. var getEmbedHtml = function (editor, data) {
  733. var embedHandler = Settings.getUrlResolver(editor);
  734. return embedHandler ? embedPromise(data, loadedData(editor), embedHandler) : defaultPromise(data, loadedData(editor));
  735. };
  736. var isCached = function (url) {
  737. return cache.hasOwnProperty(url);
  738. };
  739. var Service = {
  740. getEmbedHtml: getEmbedHtml,
  741. isCached: isCached
  742. };
  743. var unwrap = function (data) {
  744. return merge(data, {
  745. source1: data.source1.value,
  746. source2: get(data, 'source2').bind(function (source2) {
  747. return get(source2, 'value');
  748. }).getOr(''),
  749. poster: get(data, 'poster').bind(function (poster) {
  750. return get(poster, 'value');
  751. }).getOr('')
  752. });
  753. };
  754. var wrap = function (data) {
  755. return merge(data, {
  756. source1: { value: get(data, 'source1').getOr('') },
  757. source2: { value: get(data, 'source2').getOr('') },
  758. poster: { value: get(data, 'poster').getOr('') }
  759. });
  760. };
  761. var handleError = function (editor) {
  762. return function (error) {
  763. var errorMessage = error && error.msg ? 'Media embed handler error: ' + error.msg : 'Media embed handler threw unknown error.';
  764. editor.notificationManager.open({
  765. type: 'error',
  766. text: errorMessage
  767. });
  768. };
  769. };
  770. var snippetToData = function (editor, embedSnippet) {
  771. return global$1.extend({}, HtmlToData.htmlToData(Settings.getScripts(editor), embedSnippet));
  772. };
  773. var getEditorData = function (editor) {
  774. var element = editor.selection.getNode();
  775. var dataEmbed = element.getAttribute('data-ephox-embed-iri');
  776. if (dataEmbed) {
  777. return {
  778. source1: dataEmbed,
  779. width: Size.getMaxWidth(element),
  780. height: Size.getMaxHeight(element)
  781. };
  782. }
  783. return element.getAttribute('data-mce-object') ? HtmlToData.htmlToData(Settings.getScripts(editor), editor.serializer.serialize(element, { selection: true })) : {};
  784. };
  785. var getSource = function (editor) {
  786. var elm = editor.selection.getNode();
  787. return elm.getAttribute('data-mce-object') || elm.getAttribute('data-ephox-embed-iri') ? editor.selection.getContent() : '';
  788. };
  789. var addEmbedHtml = function (win, editor) {
  790. return function (response) {
  791. if (isString(response.url) && response.url.trim().length > 0) {
  792. var html = response.html;
  793. var snippetData_1 = snippetToData(editor, html);
  794. var nuData_1 = {
  795. source1: response.url,
  796. embed: html
  797. };
  798. each([
  799. 'width',
  800. 'height'
  801. ], function (prop) {
  802. get(snippetData_1, prop).each(function (value) {
  803. var dimensions = nuData_1.dimensions || {};
  804. dimensions[prop] = value;
  805. nuData_1.dimensions = dimensions;
  806. });
  807. });
  808. win.setData(wrap(nuData_1));
  809. }
  810. };
  811. };
  812. var selectPlaceholder = function (editor, beforeObjects) {
  813. var i;
  814. var y;
  815. var afterObjects = editor.dom.select('img[data-mce-object]');
  816. for (i = 0; i < beforeObjects.length; i++) {
  817. for (y = afterObjects.length - 1; y >= 0; y--) {
  818. if (beforeObjects[i] === afterObjects[y]) {
  819. afterObjects.splice(y, 1);
  820. }
  821. }
  822. }
  823. editor.selection.select(afterObjects[0]);
  824. };
  825. var handleInsert = function (editor, html) {
  826. var beforeObjects = editor.dom.select('img[data-mce-object]');
  827. editor.insertContent(html);
  828. selectPlaceholder(editor, beforeObjects);
  829. editor.nodeChanged();
  830. };
  831. var submitForm = function (data, editor) {
  832. data.embed = UpdateHtml.updateHtml(data.embed, data);
  833. if (data.embed && Service.isCached(data.source1)) {
  834. handleInsert(editor, data.embed);
  835. } else {
  836. Service.getEmbedHtml(editor, data).then(function (response) {
  837. handleInsert(editor, response.html);
  838. }).catch(handleError(editor));
  839. }
  840. };
  841. var showDialog = function (editor) {
  842. var editorData = getEditorData(editor);
  843. var defaultData = {
  844. source1: '',
  845. source2: '',
  846. embed: getSource(editor),
  847. poster: '',
  848. dimensions: {
  849. height: editorData.height ? editorData.height : '',
  850. width: editorData.width ? editorData.width : ''
  851. }
  852. };
  853. var initialData = wrap(merge(defaultData, editorData));
  854. var getSourceData = function (api) {
  855. var data = unwrap(api.getData());
  856. return Settings.hasDimensions(editor) ? merge(data, {
  857. width: data.dimensions.width,
  858. height: data.dimensions.height
  859. }) : data;
  860. };
  861. var handleSource1 = function (api) {
  862. var serviceData = getSourceData(api);
  863. Service.getEmbedHtml(editor, serviceData).then(addEmbedHtml(win, editor)).catch(handleError(editor));
  864. };
  865. var handleEmbed = function (api) {
  866. var data = unwrap(api.getData());
  867. var dataFromEmbed = snippetToData(editor, data.embed);
  868. dataFromEmbed.dimensions = {
  869. width: dataFromEmbed.width ? dataFromEmbed.width : data.dimensions.width,
  870. height: dataFromEmbed.height ? dataFromEmbed.height : data.dimensions.height
  871. };
  872. api.setData(wrap(dataFromEmbed));
  873. };
  874. var mediaInput = [{
  875. name: 'source1',
  876. type: 'urlinput',
  877. filetype: 'media',
  878. label: 'Source'
  879. }];
  880. var sizeInput = !Settings.hasDimensions(editor) ? [] : [{
  881. type: 'sizeinput',
  882. name: 'dimensions',
  883. label: 'Constrain proportions',
  884. constrain: true
  885. }];
  886. var generalTab = {
  887. title: 'General',
  888. name: 'general',
  889. items: flatten([
  890. mediaInput,
  891. sizeInput
  892. ])
  893. };
  894. var embedTextarea = {
  895. type: 'textarea',
  896. name: 'embed',
  897. label: 'Paste your embed code below:'
  898. };
  899. var embedTab = {
  900. title: 'Embed',
  901. items: [embedTextarea]
  902. };
  903. var advancedFormItems = [];
  904. if (Settings.hasAltSource(editor)) {
  905. advancedFormItems.push({
  906. name: 'source2',
  907. type: 'urlinput',
  908. filetype: 'media',
  909. label: 'Alternative source URL'
  910. });
  911. }
  912. if (Settings.hasPoster(editor)) {
  913. advancedFormItems.push({
  914. name: 'poster',
  915. type: 'urlinput',
  916. filetype: 'image',
  917. label: 'Media poster (Image URL)'
  918. });
  919. }
  920. var advancedTab = {
  921. title: 'Advanced',
  922. name: 'advanced',
  923. items: advancedFormItems
  924. };
  925. var tabs = [
  926. generalTab,
  927. embedTab
  928. ];
  929. if (advancedFormItems.length > 0) {
  930. tabs.push(advancedTab);
  931. }
  932. var body = {
  933. type: 'tabpanel',
  934. tabs: tabs
  935. };
  936. var win = editor.windowManager.open({
  937. title: 'Insert/Edit Media',
  938. size: 'normal',
  939. body: body,
  940. buttons: [
  941. {
  942. type: 'cancel',
  943. name: 'cancel',
  944. text: 'Cancel'
  945. },
  946. {
  947. type: 'submit',
  948. name: 'save',
  949. text: 'Save',
  950. primary: true
  951. }
  952. ],
  953. onSubmit: function (api) {
  954. var serviceData = getSourceData(api);
  955. submitForm(serviceData, editor);
  956. api.close();
  957. },
  958. onChange: function (api, detail) {
  959. switch (detail.name) {
  960. case 'source1':
  961. handleSource1(api);
  962. break;
  963. case 'embed':
  964. handleEmbed(api);
  965. break;
  966. default:
  967. break;
  968. }
  969. },
  970. initialData: initialData
  971. });
  972. };
  973. var Dialog = { showDialog: showDialog };
  974. var get$1 = function (editor) {
  975. var showDialog = function () {
  976. Dialog.showDialog(editor);
  977. };
  978. return { showDialog: showDialog };
  979. };
  980. var Api = { get: get$1 };
  981. var register = function (editor) {
  982. var showDialog = function () {
  983. Dialog.showDialog(editor);
  984. };
  985. editor.addCommand('mceMedia', showDialog);
  986. };
  987. var Commands = { register: register };
  988. var global$7 = tinymce.util.Tools.resolve('tinymce.html.Node');
  989. var global$8 = tinymce.util.Tools.resolve('tinymce.Env');
  990. var sanitize = function (editor, html) {
  991. if (Settings.shouldFilterHtml(editor) === false) {
  992. return html;
  993. }
  994. var writer = global$5();
  995. var blocked;
  996. global$2({
  997. validate: false,
  998. allow_conditional_comments: false,
  999. comment: function (text) {
  1000. writer.comment(text);
  1001. },
  1002. cdata: function (text) {
  1003. writer.cdata(text);
  1004. },
  1005. text: function (text, raw) {
  1006. writer.text(text, raw);
  1007. },
  1008. start: function (name, attrs, empty) {
  1009. blocked = true;
  1010. if (name === 'script' || name === 'noscript') {
  1011. return;
  1012. }
  1013. for (var i = 0; i < attrs.length; i++) {
  1014. if (attrs[i].name.indexOf('on') === 0) {
  1015. return;
  1016. }
  1017. if (attrs[i].name === 'style') {
  1018. attrs[i].value = editor.dom.serializeStyle(editor.dom.parseStyle(attrs[i].value), name);
  1019. }
  1020. }
  1021. writer.start(name, attrs, empty);
  1022. blocked = false;
  1023. },
  1024. end: function (name) {
  1025. if (blocked) {
  1026. return;
  1027. }
  1028. writer.end(name);
  1029. }
  1030. }, global$6({})).parse(html);
  1031. return writer.getContent();
  1032. };
  1033. var Sanitize = { sanitize: sanitize };
  1034. var createPlaceholderNode = function (editor, node) {
  1035. var placeHolder;
  1036. var name = node.name;
  1037. placeHolder = new global$7('img', 1);
  1038. placeHolder.shortEnded = true;
  1039. retainAttributesAndInnerHtml(editor, node, placeHolder);
  1040. placeHolder.attr({
  1041. 'width': node.attr('width') || '300',
  1042. 'height': node.attr('height') || (name === 'audio' ? '30' : '150'),
  1043. 'style': node.attr('style'),
  1044. 'src': global$8.transparentSrc,
  1045. 'data-mce-object': name,
  1046. 'class': 'mce-object mce-object-' + name
  1047. });
  1048. return placeHolder;
  1049. };
  1050. var createPreviewIframeNode = function (editor, node) {
  1051. var previewWrapper;
  1052. var previewNode;
  1053. var shimNode;
  1054. var name = node.name;
  1055. previewWrapper = new global$7('span', 1);
  1056. previewWrapper.attr({
  1057. 'contentEditable': 'false',
  1058. 'style': node.attr('style'),
  1059. 'data-mce-object': name,
  1060. 'class': 'mce-preview-object mce-object-' + name
  1061. });
  1062. retainAttributesAndInnerHtml(editor, node, previewWrapper);
  1063. previewNode = new global$7(name, 1);
  1064. previewNode.attr({
  1065. src: node.attr('src'),
  1066. allowfullscreen: node.attr('allowfullscreen'),
  1067. style: node.attr('style'),
  1068. class: node.attr('class'),
  1069. width: node.attr('width'),
  1070. height: node.attr('height'),
  1071. frameborder: '0'
  1072. });
  1073. shimNode = new global$7('span', 1);
  1074. shimNode.attr('class', 'mce-shim');
  1075. previewWrapper.append(previewNode);
  1076. previewWrapper.append(shimNode);
  1077. return previewWrapper;
  1078. };
  1079. var retainAttributesAndInnerHtml = function (editor, sourceNode, targetNode) {
  1080. var attrName;
  1081. var attrValue;
  1082. var attribs;
  1083. var ai;
  1084. var innerHtml;
  1085. attribs = sourceNode.attributes;
  1086. ai = attribs.length;
  1087. while (ai--) {
  1088. attrName = attribs[ai].name;
  1089. attrValue = attribs[ai].value;
  1090. if (attrName !== 'width' && attrName !== 'height' && attrName !== 'style') {
  1091. if (attrName === 'data' || attrName === 'src') {
  1092. attrValue = editor.convertURL(attrValue, attrName);
  1093. }
  1094. targetNode.attr('data-mce-p-' + attrName, attrValue);
  1095. }
  1096. }
  1097. innerHtml = sourceNode.firstChild && sourceNode.firstChild.value;
  1098. if (innerHtml) {
  1099. targetNode.attr('data-mce-html', escape(Sanitize.sanitize(editor, innerHtml)));
  1100. targetNode.firstChild = null;
  1101. }
  1102. };
  1103. var isPageEmbedWrapper = function (node) {
  1104. var nodeClass = node.attr('class');
  1105. return nodeClass && /\btiny-pageembed\b/.test(nodeClass);
  1106. };
  1107. var isWithinEmbedWrapper = function (node) {
  1108. while (node = node.parent) {
  1109. if (node.attr('data-ephox-embed-iri') || isPageEmbedWrapper(node)) {
  1110. return true;
  1111. }
  1112. }
  1113. return false;
  1114. };
  1115. var placeHolderConverter = function (editor) {
  1116. return function (nodes) {
  1117. var i = nodes.length;
  1118. var node;
  1119. var videoScript;
  1120. while (i--) {
  1121. node = nodes[i];
  1122. if (!node.parent) {
  1123. continue;
  1124. }
  1125. if (node.parent.attr('data-mce-object')) {
  1126. continue;
  1127. }
  1128. if (node.name === 'script') {
  1129. videoScript = VideoScript.getVideoScriptMatch(Settings.getScripts(editor), node.attr('src'));
  1130. if (!videoScript) {
  1131. continue;
  1132. }
  1133. }
  1134. if (videoScript) {
  1135. if (videoScript.width) {
  1136. node.attr('width', videoScript.width.toString());
  1137. }
  1138. if (videoScript.height) {
  1139. node.attr('height', videoScript.height.toString());
  1140. }
  1141. }
  1142. if (node.name === 'iframe' && Settings.hasLiveEmbeds(editor) && global$8.ceFalse) {
  1143. if (!isWithinEmbedWrapper(node)) {
  1144. node.replace(createPreviewIframeNode(editor, node));
  1145. }
  1146. } else {
  1147. if (!isWithinEmbedWrapper(node)) {
  1148. node.replace(createPlaceholderNode(editor, node));
  1149. }
  1150. }
  1151. }
  1152. };
  1153. };
  1154. var Nodes = {
  1155. createPreviewIframeNode: createPreviewIframeNode,
  1156. createPlaceholderNode: createPlaceholderNode,
  1157. placeHolderConverter: placeHolderConverter
  1158. };
  1159. var setup = function (editor) {
  1160. editor.on('preInit', function () {
  1161. var specialElements = editor.schema.getSpecialElements();
  1162. global$1.each('video audio iframe object'.split(' '), function (name) {
  1163. specialElements[name] = new RegExp('</' + name + '[^>]*>', 'gi');
  1164. });
  1165. var boolAttrs = editor.schema.getBoolAttrs();
  1166. global$1.each('webkitallowfullscreen mozallowfullscreen allowfullscreen'.split(' '), function (name) {
  1167. boolAttrs[name] = {};
  1168. });
  1169. editor.parser.addNodeFilter('iframe,video,audio,object,embed,script', Nodes.placeHolderConverter(editor));
  1170. editor.serializer.addAttributeFilter('data-mce-object', function (nodes, name) {
  1171. var i = nodes.length;
  1172. var node;
  1173. var realElm;
  1174. var ai;
  1175. var attribs;
  1176. var innerHtml;
  1177. var innerNode;
  1178. var realElmName;
  1179. var className;
  1180. while (i--) {
  1181. node = nodes[i];
  1182. if (!node.parent) {
  1183. continue;
  1184. }
  1185. realElmName = node.attr(name);
  1186. realElm = new global$7(realElmName, 1);
  1187. if (realElmName !== 'audio' && realElmName !== 'script') {
  1188. className = node.attr('class');
  1189. if (className && className.indexOf('mce-preview-object') !== -1) {
  1190. realElm.attr({
  1191. width: node.firstChild.attr('width'),
  1192. height: node.firstChild.attr('height')
  1193. });
  1194. } else {
  1195. realElm.attr({
  1196. width: node.attr('width'),
  1197. height: node.attr('height')
  1198. });
  1199. }
  1200. }
  1201. realElm.attr({ style: node.attr('style') });
  1202. attribs = node.attributes;
  1203. ai = attribs.length;
  1204. while (ai--) {
  1205. var attrName = attribs[ai].name;
  1206. if (attrName.indexOf('data-mce-p-') === 0) {
  1207. realElm.attr(attrName.substr(11), attribs[ai].value);
  1208. }
  1209. }
  1210. if (realElmName === 'script') {
  1211. realElm.attr('type', 'text/javascript');
  1212. }
  1213. innerHtml = node.attr('data-mce-html');
  1214. if (innerHtml) {
  1215. innerNode = new global$7('#text', 3);
  1216. innerNode.raw = true;
  1217. innerNode.value = Sanitize.sanitize(editor, unescape(innerHtml));
  1218. realElm.append(innerNode);
  1219. }
  1220. node.replace(realElm);
  1221. }
  1222. });
  1223. });
  1224. editor.on('SetContent', function () {
  1225. editor.$('span.mce-preview-object').each(function (index, elm) {
  1226. var $elm = editor.$(elm);
  1227. if ($elm.find('span.mce-shim', elm).length === 0) {
  1228. $elm.append('<span class="mce-shim"></span>');
  1229. }
  1230. });
  1231. });
  1232. };
  1233. var FilterContent = { setup: setup };
  1234. var setup$1 = function (editor) {
  1235. editor.on('ResolveName', function (e) {
  1236. var name;
  1237. if (e.target.nodeType === 1 && (name = e.target.getAttribute('data-mce-object'))) {
  1238. e.name = name;
  1239. }
  1240. });
  1241. };
  1242. var ResolveName = { setup: setup$1 };
  1243. var setup$2 = function (editor) {
  1244. editor.on('click keyup', function () {
  1245. var selectedNode = editor.selection.getNode();
  1246. if (selectedNode && editor.dom.hasClass(selectedNode, 'mce-preview-object')) {
  1247. if (editor.dom.getAttrib(selectedNode, 'data-mce-selected')) {
  1248. selectedNode.setAttribute('data-mce-selected', '2');
  1249. }
  1250. }
  1251. });
  1252. editor.on('ObjectSelected', function (e) {
  1253. var objectType = e.target.getAttribute('data-mce-object');
  1254. if (objectType === 'audio' || objectType === 'script') {
  1255. e.preventDefault();
  1256. }
  1257. });
  1258. editor.on('ObjectResized', function (e) {
  1259. var target = e.target;
  1260. var html;
  1261. if (target.getAttribute('data-mce-object')) {
  1262. html = target.getAttribute('data-mce-html');
  1263. if (html) {
  1264. html = unescape(html);
  1265. target.setAttribute('data-mce-html', escape(UpdateHtml.updateHtml(html, {
  1266. width: e.width,
  1267. height: e.height
  1268. })));
  1269. }
  1270. }
  1271. });
  1272. };
  1273. var Selection = { setup: setup$2 };
  1274. var stateSelectorAdapter = function (editor, selector) {
  1275. return function (buttonApi) {
  1276. return editor.selection.selectorChangedWithUnbind(selector.join(','), buttonApi.setActive).unbind;
  1277. };
  1278. };
  1279. var register$1 = function (editor) {
  1280. editor.ui.registry.addToggleButton('media', {
  1281. tooltip: 'Insert/edit media',
  1282. icon: 'embed',
  1283. onAction: function () {
  1284. editor.execCommand('mceMedia');
  1285. },
  1286. onSetup: stateSelectorAdapter(editor, [
  1287. 'img[data-mce-object]',
  1288. 'span[data-mce-object]',
  1289. 'div[data-ephox-embed-iri]'
  1290. ])
  1291. });
  1292. editor.ui.registry.addMenuItem('media', {
  1293. icon: 'embed',
  1294. text: 'Media...',
  1295. onAction: function () {
  1296. editor.execCommand('mceMedia');
  1297. }
  1298. });
  1299. };
  1300. var Buttons = { register: register$1 };
  1301. global.add('media', function (editor) {
  1302. Commands.register(editor);
  1303. Buttons.register(editor);
  1304. ResolveName.setup(editor);
  1305. FilterContent.setup(editor);
  1306. Selection.setup(editor);
  1307. return Api.get(editor);
  1308. });
  1309. function Plugin () {
  1310. }
  1311. return Plugin;
  1312. }());
  1313. })();