plugin.js 42 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813814815816817818819820821822823824825826827828829830831832833834835836837838839840841842843844845846847848849850851852853854855856857858859860861862863864865866867868869870871872873874875876877878879880881882883884885886887888889890891892893894895896897898899900901902903904905906907908909910911912913914915916917918919920921922923924925926927928929930931932933934935936937938939940941942943944945946947948949950951952953954955956957958959960961962963964965966967968969970971972973974975976977978979980981982983984985986987988989990991992993994995996997998999100010011002100310041005100610071008100910101011101210131014101510161017101810191020102110221023102410251026102710281029103010311032103310341035103610371038103910401041104210431044104510461047104810491050105110521053105410551056105710581059106010611062106310641065106610671068106910701071107210731074107510761077107810791080108110821083108410851086108710881089109010911092109310941095109610971098109911001101110211031104110511061107110811091110111111121113111411151116111711181119112011211122112311241125112611271128112911301131113211331134113511361137113811391140114111421143114411451146114711481149115011511152115311541155115611571158115911601161116211631164116511661167116811691170117111721173117411751176117711781179118011811182118311841185118611871188118911901191119211931194119511961197119811991200120112021203120412051206120712081209121012111212121312141215121612171218121912201221122212231224122512261227122812291230123112321233123412351236123712381239124012411242124312441245124612471248124912501251125212531254125512561257125812591260126112621263126412651266126712681269127012711272127312741275127612771278127912801281128212831284128512861287128812891290129112921293129412951296129712981299130013011302130313041305130613071308130913101311131213131314131513161317131813191320132113221323132413251326132713281329133013311332133313341335133613371338133913401341134213431344134513461347134813491350
  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.1 (2019-02-21)
  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.some(obj[key]) : Option.none();
  191. };
  192. var has = function (obj, key) {
  193. return hasOwnProperty$1.call(obj, key);
  194. };
  195. var each = function (xs, f) {
  196. for (var i = 0, len = xs.length; i < len; i++) {
  197. var x = xs[i];
  198. f(x, i, xs);
  199. }
  200. };
  201. var push = Array.prototype.push;
  202. var flatten = function (xs) {
  203. var r = [];
  204. for (var i = 0, len = xs.length; i < len; ++i) {
  205. if (!Array.prototype.isPrototypeOf(xs[i]))
  206. throw new Error('Arr.flatten item ' + i + ' was not an array, input: ' + xs);
  207. push.apply(r, xs[i]);
  208. }
  209. return r;
  210. };
  211. var slice = Array.prototype.slice;
  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. special: 'script,noscript',
  304. start: function (name, attrs) {
  305. if (!data.source1 && name === 'param') {
  306. data.source1 = attrs.map.movie;
  307. }
  308. if (name === 'iframe' || name === 'object' || name === 'embed' || name === 'video' || name === 'audio') {
  309. if (!data.type) {
  310. data.type = name;
  311. }
  312. data = global$1.extend(attrs.map, data);
  313. }
  314. if (name === 'script') {
  315. var videoScript = VideoScript.getVideoScriptMatch(prefixes, attrs.map.src);
  316. if (!videoScript) {
  317. return;
  318. }
  319. data = {
  320. type: 'script',
  321. source1: attrs.map.src,
  322. width: videoScript.width,
  323. height: videoScript.height
  324. };
  325. }
  326. if (name === 'source') {
  327. if (!data.source1) {
  328. data.source1 = attrs.map.src;
  329. } else if (!data.source2) {
  330. data.source2 = attrs.map.src;
  331. }
  332. }
  333. if (name === 'img' && !data.poster) {
  334. data.poster = attrs.map.src;
  335. }
  336. }
  337. }).parse(html);
  338. data.source1 = data.source1 || data.src || data.data;
  339. data.source2 = data.source2 || '';
  340. data.poster = data.poster || '';
  341. return data;
  342. };
  343. var ephoxEmbedHtmlToData = function (html) {
  344. var fragment = DOM.createFragment(html);
  345. var div = fragment.firstChild;
  346. return {
  347. type: 'ephox-embed-iri',
  348. source1: getEphoxEmbedIri(div),
  349. source2: '',
  350. poster: '',
  351. width: Size.getMaxWidth(div),
  352. height: Size.getMaxHeight(div)
  353. };
  354. };
  355. var htmlToData = function (prefixes, html) {
  356. return isEphoxEmbed(html) ? ephoxEmbedHtmlToData(html) : htmlToDataSax(prefixes, html);
  357. };
  358. var HtmlToData = { htmlToData: htmlToData };
  359. var global$4 = tinymce.util.Tools.resolve('tinymce.util.Promise');
  360. var guess = function (url) {
  361. var mimes = {
  362. mp3: 'audio/mpeg',
  363. wav: 'audio/wav',
  364. mp4: 'video/mp4',
  365. webm: 'video/webm',
  366. ogg: 'video/ogg',
  367. swf: 'application/x-shockwave-flash'
  368. };
  369. var fileEnd = url.toLowerCase().split('.').pop();
  370. var mime = mimes[fileEnd];
  371. return mime ? mime : '';
  372. };
  373. var Mime = { guess: guess };
  374. var global$5 = tinymce.util.Tools.resolve('tinymce.html.Writer');
  375. var global$6 = tinymce.util.Tools.resolve('tinymce.html.Schema');
  376. var DOM$1 = global$3.DOM;
  377. var setAttributes = function (attrs, updatedAttrs) {
  378. var name;
  379. var i;
  380. var value;
  381. var attr;
  382. for (name in updatedAttrs) {
  383. value = '' + updatedAttrs[name];
  384. if (attrs.map[name]) {
  385. i = attrs.length;
  386. while (i--) {
  387. attr = attrs[i];
  388. if (attr.name === name) {
  389. if (value) {
  390. attrs.map[name] = value;
  391. attr.value = value;
  392. } else {
  393. delete attrs.map[name];
  394. attrs.splice(i, 1);
  395. }
  396. }
  397. }
  398. } else if (value) {
  399. attrs.push({
  400. name: name,
  401. value: value
  402. });
  403. attrs.map[name] = value;
  404. }
  405. }
  406. };
  407. var normalizeHtml = function (html) {
  408. var writer = global$5();
  409. var parser = global$2(writer);
  410. parser.parse(html);
  411. return writer.getContent();
  412. };
  413. var updateHtmlSax = function (html, data, updateAll) {
  414. var writer = global$5();
  415. var sourceCount = 0;
  416. var hasImage;
  417. global$2({
  418. validate: false,
  419. allow_conditional_comments: true,
  420. special: 'script,noscript',
  421. comment: function (text) {
  422. writer.comment(text);
  423. },
  424. cdata: function (text) {
  425. writer.cdata(text);
  426. },
  427. text: function (text, raw) {
  428. writer.text(text, raw);
  429. },
  430. start: function (name, attrs, empty) {
  431. switch (name) {
  432. case 'video':
  433. case 'object':
  434. case 'embed':
  435. case 'img':
  436. case 'iframe':
  437. if (data.height !== undefined && data.width !== undefined) {
  438. setAttributes(attrs, {
  439. width: data.width,
  440. height: data.height
  441. });
  442. }
  443. break;
  444. }
  445. if (updateAll) {
  446. switch (name) {
  447. case 'video':
  448. setAttributes(attrs, {
  449. poster: data.poster,
  450. src: ''
  451. });
  452. if (data.source2) {
  453. setAttributes(attrs, { src: '' });
  454. }
  455. break;
  456. case 'iframe':
  457. setAttributes(attrs, { src: data.source1 });
  458. break;
  459. case 'source':
  460. sourceCount++;
  461. if (sourceCount <= 2) {
  462. setAttributes(attrs, {
  463. src: data['source' + sourceCount],
  464. type: data['source' + sourceCount + 'mime']
  465. });
  466. if (!data['source' + sourceCount]) {
  467. return;
  468. }
  469. }
  470. break;
  471. case 'img':
  472. if (!data.poster) {
  473. return;
  474. }
  475. hasImage = true;
  476. break;
  477. }
  478. }
  479. writer.start(name, attrs, empty);
  480. },
  481. end: function (name) {
  482. if (name === 'video' && updateAll) {
  483. for (var index = 1; index <= 2; index++) {
  484. if (data['source' + index]) {
  485. var attrs = [];
  486. attrs.map = {};
  487. if (sourceCount < index) {
  488. setAttributes(attrs, {
  489. src: data['source' + index],
  490. type: data['source' + index + 'mime']
  491. });
  492. writer.start('source', attrs, true);
  493. }
  494. }
  495. }
  496. }
  497. if (data.poster && name === 'object' && updateAll && !hasImage) {
  498. var imgAttrs = [];
  499. imgAttrs.map = {};
  500. setAttributes(imgAttrs, {
  501. src: data.poster,
  502. width: data.width,
  503. height: data.height
  504. });
  505. writer.start('img', imgAttrs, true);
  506. }
  507. writer.end(name);
  508. }
  509. }, global$6({})).parse(html);
  510. return writer.getContent();
  511. };
  512. var isEphoxEmbed$1 = function (html) {
  513. var fragment = DOM$1.createFragment(html);
  514. return DOM$1.getAttrib(fragment.firstChild, 'data-ephox-embed-iri') !== '';
  515. };
  516. var updateEphoxEmbed = function (html, data) {
  517. var fragment = DOM$1.createFragment(html);
  518. var div = fragment.firstChild;
  519. Size.setMaxWidth(div, data.width);
  520. Size.setMaxHeight(div, data.height);
  521. return normalizeHtml(div.outerHTML);
  522. };
  523. var updateHtml = function (html, data, updateAll) {
  524. return isEphoxEmbed$1(html) ? updateEphoxEmbed(html, data) : updateHtmlSax(html, data, updateAll);
  525. };
  526. var UpdateHtml = { updateHtml: updateHtml };
  527. var urlPatterns = [
  528. {
  529. regex: /youtu\.be\/([\w\-_\?&=.]+)/i,
  530. type: 'iframe',
  531. w: 560,
  532. h: 314,
  533. url: '//www.youtube.com/embed/$1',
  534. allowFullscreen: true
  535. },
  536. {
  537. regex: /youtube\.com(.+)v=([^&]+)(&([a-z0-9&=\-_]+))?/i,
  538. type: 'iframe',
  539. w: 560,
  540. h: 314,
  541. url: '//www.youtube.com/embed/$2?$4',
  542. allowFullscreen: true
  543. },
  544. {
  545. regex: /youtube.com\/embed\/([a-z0-9\?&=\-_]+)/i,
  546. type: 'iframe',
  547. w: 560,
  548. h: 314,
  549. url: '//www.youtube.com/embed/$1',
  550. allowFullscreen: true
  551. },
  552. {
  553. regex: /vimeo\.com\/([0-9]+)/,
  554. type: 'iframe',
  555. w: 425,
  556. h: 350,
  557. url: '//player.vimeo.com/video/$1?title=0&byline=0&portrait=0&color=8dc7dc',
  558. allowFullscreen: true
  559. },
  560. {
  561. regex: /vimeo\.com\/(.*)\/([0-9]+)/,
  562. type: 'iframe',
  563. w: 425,
  564. h: 350,
  565. url: '//player.vimeo.com/video/$2?title=0&amp;byline=0',
  566. allowFullscreen: true
  567. },
  568. {
  569. regex: /maps\.google\.([a-z]{2,3})\/maps\/(.+)msid=(.+)/,
  570. type: 'iframe',
  571. w: 425,
  572. h: 350,
  573. url: '//maps.google.com/maps/ms?msid=$2&output=embed"',
  574. allowFullscreen: false
  575. },
  576. {
  577. regex: /dailymotion\.com\/video\/([^_]+)/,
  578. type: 'iframe',
  579. w: 480,
  580. h: 270,
  581. url: '//www.dailymotion.com/embed/video/$1',
  582. allowFullscreen: true
  583. },
  584. {
  585. regex: /dai\.ly\/([^_]+)/,
  586. type: 'iframe',
  587. w: 480,
  588. h: 270,
  589. url: '//www.dailymotion.com/embed/video/$1',
  590. allowFullscreen: true
  591. }
  592. ];
  593. var getUrl = function (pattern, url) {
  594. var match = pattern.regex.exec(url);
  595. var newUrl = pattern.url;
  596. var _loop_1 = function (i) {
  597. newUrl = newUrl.replace('$' + i, function () {
  598. return match[i] ? match[i] : '';
  599. });
  600. };
  601. for (var i = 0; i < match.length; i++) {
  602. _loop_1(i);
  603. }
  604. return newUrl.replace(/\?$/, '');
  605. };
  606. var matchPattern = function (url) {
  607. var pattern = urlPatterns.filter(function (pattern) {
  608. return pattern.regex.test(url);
  609. });
  610. if (pattern.length > 0) {
  611. return global$1.extend({}, pattern[0], { url: getUrl(pattern[0], url) });
  612. } else {
  613. return null;
  614. }
  615. };
  616. var getIframeHtml = function (data) {
  617. var allowFullscreen = data.allowFullscreen ? ' allowFullscreen="1"' : '';
  618. return '<iframe src="' + data.source1 + '" width="' + data.width + '" height="' + data.height + '"' + allowFullscreen + '></iframe>';
  619. };
  620. var getFlashHtml = function (data) {
  621. var html = '<object data="' + data.source1 + '" width="' + data.width + '" height="' + data.height + '" type="application/x-shockwave-flash">';
  622. if (data.poster) {
  623. html += '<img src="' + data.poster + '" width="' + data.width + '" height="' + data.height + '" />';
  624. }
  625. html += '</object>';
  626. return html;
  627. };
  628. var getAudioHtml = function (data, audioTemplateCallback) {
  629. if (audioTemplateCallback) {
  630. return audioTemplateCallback(data);
  631. } else {
  632. return '<audio controls="controls" src="' + data.source1 + '">' + (data.source2 ? '\n<source src="' + data.source2 + '"' + (data.source2mime ? ' type="' + data.source2mime + '"' : '') + ' />\n' : '') + '</audio>';
  633. }
  634. };
  635. var getVideoHtml = function (data, videoTemplateCallback) {
  636. if (videoTemplateCallback) {
  637. return videoTemplateCallback(data);
  638. } else {
  639. 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>';
  640. }
  641. };
  642. var getScriptHtml = function (data) {
  643. return '<script src="' + data.source1 + '"></script>';
  644. };
  645. var dataToHtml = function (editor, dataIn) {
  646. var data = global$1.extend({}, dataIn);
  647. if (!data.source1) {
  648. global$1.extend(data, HtmlToData.htmlToData(Settings.getScripts(editor), data.embed));
  649. if (!data.source1) {
  650. return '';
  651. }
  652. }
  653. if (!data.source2) {
  654. data.source2 = '';
  655. }
  656. if (!data.poster) {
  657. data.poster = '';
  658. }
  659. data.source1 = editor.convertURL(data.source1, 'source');
  660. data.source2 = editor.convertURL(data.source2, 'source');
  661. data.source1mime = Mime.guess(data.source1);
  662. data.source2mime = Mime.guess(data.source2);
  663. data.poster = editor.convertURL(data.poster, 'poster');
  664. var pattern = matchPattern(data.source1);
  665. if (pattern) {
  666. data.source1 = pattern.url;
  667. data.type = pattern.type;
  668. data.allowFullscreen = pattern.allowFullscreen;
  669. data.width = data.width || pattern.w;
  670. data.height = data.height || pattern.h;
  671. }
  672. if (data.embed) {
  673. return UpdateHtml.updateHtml(data.embed, data, true);
  674. } else {
  675. var videoScript = VideoScript.getVideoScriptMatch(Settings.getScripts(editor), data.source1);
  676. if (videoScript) {
  677. data.type = 'script';
  678. data.width = videoScript.width;
  679. data.height = videoScript.height;
  680. }
  681. var audioTemplateCallback = Settings.getAudioTemplateCallback(editor);
  682. var videoTemplateCallback = Settings.getVideoTemplateCallback(editor);
  683. data.width = data.width || 300;
  684. data.height = data.height || 150;
  685. global$1.each(data, function (value, key) {
  686. data[key] = editor.dom.encode(value);
  687. });
  688. if (data.type === 'iframe') {
  689. return getIframeHtml(data);
  690. } else if (data.source1mime === 'application/x-shockwave-flash') {
  691. return getFlashHtml(data);
  692. } else if (data.source1mime.indexOf('audio') !== -1) {
  693. return getAudioHtml(data, audioTemplateCallback);
  694. } else if (data.type === 'script') {
  695. return getScriptHtml(data);
  696. } else {
  697. return getVideoHtml(data, videoTemplateCallback);
  698. }
  699. }
  700. };
  701. var DataToHtml = { dataToHtml: dataToHtml };
  702. var cache = {};
  703. var embedPromise = function (data, dataToHtml, handler) {
  704. return new global$4(function (res, rej) {
  705. var wrappedResolve = function (response) {
  706. if (response.html) {
  707. cache[data.source1] = response;
  708. }
  709. return res({
  710. url: data.source1,
  711. html: response.html ? response.html : dataToHtml(data)
  712. });
  713. };
  714. if (cache[data.source1]) {
  715. wrappedResolve(cache[data.source1]);
  716. } else {
  717. handler({ url: data.source1 }, wrappedResolve, rej);
  718. }
  719. });
  720. };
  721. var defaultPromise = function (data, dataToHtml) {
  722. return new global$4(function (res) {
  723. res({
  724. html: dataToHtml(data),
  725. url: data.source1
  726. });
  727. });
  728. };
  729. var loadedData = function (editor) {
  730. return function (data) {
  731. return DataToHtml.dataToHtml(editor, data);
  732. };
  733. };
  734. var getEmbedHtml = function (editor, data) {
  735. var embedHandler = Settings.getUrlResolver(editor);
  736. return embedHandler ? embedPromise(data, loadedData(editor), embedHandler) : defaultPromise(data, loadedData(editor));
  737. };
  738. var isCached = function (url) {
  739. return cache.hasOwnProperty(url);
  740. };
  741. var Service = {
  742. getEmbedHtml: getEmbedHtml,
  743. isCached: isCached
  744. };
  745. var unwrap = function (data) {
  746. return merge(data, {
  747. source1: data.source1.value,
  748. source2: get(data, 'source2').bind(function (source2) {
  749. return get(source2, 'value');
  750. }).getOr(''),
  751. poster: get(data, 'poster').bind(function (poster) {
  752. return get(poster, 'value');
  753. }).getOr('')
  754. });
  755. };
  756. var wrap = function (data) {
  757. return merge(data, {
  758. source1: { value: get(data, 'source1').getOr('') },
  759. source2: { value: get(data, 'source2').getOr('') },
  760. poster: { value: get(data, 'poster').getOr('') }
  761. });
  762. };
  763. var handleError = function (editor) {
  764. return function (error) {
  765. var errorMessage = error && error.msg ? 'Media embed handler error: ' + error.msg : 'Media embed handler threw unknown error.';
  766. editor.notificationManager.open({
  767. type: 'error',
  768. text: errorMessage
  769. });
  770. };
  771. };
  772. var snippetToData = function (editor, embedSnippet) {
  773. return global$1.extend({}, HtmlToData.htmlToData(Settings.getScripts(editor), embedSnippet));
  774. };
  775. var getEditorData = function (editor) {
  776. var element = editor.selection.getNode();
  777. var dataEmbed = element.getAttribute('data-ephox-embed-iri');
  778. if (dataEmbed) {
  779. return {
  780. source1: dataEmbed,
  781. width: Size.getMaxWidth(element),
  782. height: Size.getMaxHeight(element)
  783. };
  784. }
  785. return element.getAttribute('data-mce-object') ? HtmlToData.htmlToData(Settings.getScripts(editor), editor.serializer.serialize(element, { selection: true })) : {};
  786. };
  787. var getSource = function (editor) {
  788. var elm = editor.selection.getNode();
  789. return elm.getAttribute('data-mce-object') || elm.getAttribute('data-ephox-embed-iri') ? editor.selection.getContent() : '';
  790. };
  791. var addEmbedHtml = function (win, editor) {
  792. return function (response) {
  793. if (isString(response.url) && response.url.trim().length > 0) {
  794. var html = response.html;
  795. var snippetData_1 = snippetToData(editor, html);
  796. var nuData_1 = {
  797. source1: response.url,
  798. embed: html
  799. };
  800. each([
  801. 'width',
  802. 'height'
  803. ], function (prop) {
  804. get(snippetData_1, prop).each(function (value) {
  805. var dimensions = nuData_1.dimensions || {};
  806. dimensions[prop] = value;
  807. nuData_1.dimensions = dimensions;
  808. });
  809. });
  810. win.setData(wrap(nuData_1));
  811. }
  812. };
  813. };
  814. var selectPlaceholder = function (editor, beforeObjects) {
  815. var i;
  816. var y;
  817. var afterObjects = editor.dom.select('img[data-mce-object]');
  818. for (i = 0; i < beforeObjects.length; i++) {
  819. for (y = afterObjects.length - 1; y >= 0; y--) {
  820. if (beforeObjects[i] === afterObjects[y]) {
  821. afterObjects.splice(y, 1);
  822. }
  823. }
  824. }
  825. editor.selection.select(afterObjects[0]);
  826. };
  827. var handleInsert = function (editor, html) {
  828. var beforeObjects = editor.dom.select('img[data-mce-object]');
  829. editor.insertContent(html);
  830. selectPlaceholder(editor, beforeObjects);
  831. editor.nodeChanged();
  832. };
  833. var submitForm = function (data, editor) {
  834. data.embed = UpdateHtml.updateHtml(data.embed, data);
  835. if (data.embed && Service.isCached(data.source1)) {
  836. handleInsert(editor, data.embed);
  837. } else {
  838. Service.getEmbedHtml(editor, data).then(function (response) {
  839. handleInsert(editor, response.html);
  840. }).catch(handleError(editor));
  841. }
  842. };
  843. var showDialog = function (editor) {
  844. var editorData = getEditorData(editor);
  845. var defaultData = {
  846. source1: '',
  847. source2: '',
  848. embed: getSource(editor),
  849. poster: '',
  850. dimensions: {
  851. height: editorData.height ? editorData.height : '',
  852. width: editorData.width ? editorData.width : ''
  853. }
  854. };
  855. var initialData = wrap(merge(defaultData, editorData));
  856. var getSourceData = function (api) {
  857. var data = unwrap(api.getData());
  858. return Settings.hasDimensions(editor) ? merge(data, {
  859. width: data.dimensions.width,
  860. height: data.dimensions.height
  861. }) : data;
  862. };
  863. var handleSource1 = function (api) {
  864. var serviceData = getSourceData(api);
  865. Service.getEmbedHtml(editor, serviceData).then(addEmbedHtml(win, editor)).catch(handleError(editor));
  866. };
  867. var handleEmbed = function (api) {
  868. var data = unwrap(api.getData());
  869. var dataFromEmbed = snippetToData(editor, data.embed);
  870. dataFromEmbed.dimensions = {
  871. width: dataFromEmbed.width ? dataFromEmbed.width : data.dimensions.width,
  872. height: dataFromEmbed.height ? dataFromEmbed.height : data.dimensions.height
  873. };
  874. api.setData(wrap(dataFromEmbed));
  875. };
  876. var mediaInput = [{
  877. name: 'source1',
  878. type: 'urlinput',
  879. filetype: 'media',
  880. label: 'Source'
  881. }];
  882. var sizeInput = !Settings.hasDimensions(editor) ? [] : [{
  883. type: 'sizeinput',
  884. name: 'dimensions',
  885. label: 'Constrain proportions',
  886. constrain: true
  887. }];
  888. var generalTab = {
  889. title: 'General',
  890. items: flatten([
  891. mediaInput,
  892. sizeInput
  893. ])
  894. };
  895. var embedTextarea = {
  896. type: 'textarea',
  897. name: 'embed',
  898. label: 'Paste your embed code below:'
  899. };
  900. var embedTab = {
  901. title: 'Embed',
  902. items: [embedTextarea]
  903. };
  904. var advancedFormItems = [];
  905. if (Settings.hasAltSource(editor)) {
  906. advancedFormItems.push({
  907. name: 'source2',
  908. type: 'urlinput',
  909. filetype: 'media',
  910. label: 'Alternative source URL'
  911. });
  912. }
  913. if (Settings.hasPoster(editor)) {
  914. advancedFormItems.push({
  915. name: 'poster',
  916. type: 'urlinput',
  917. filetype: 'image',
  918. label: 'Media poster (Image URL)'
  919. });
  920. }
  921. var advancedTab = {
  922. title: '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. special: 'script,noscript',
  1000. comment: function (text) {
  1001. writer.comment(text);
  1002. },
  1003. cdata: function (text) {
  1004. writer.cdata(text);
  1005. },
  1006. text: function (text, raw) {
  1007. writer.text(text, raw);
  1008. },
  1009. start: function (name, attrs, empty) {
  1010. blocked = true;
  1011. if (name === 'script' || name === 'noscript') {
  1012. return;
  1013. }
  1014. for (var i = 0; i < attrs.length; i++) {
  1015. if (attrs[i].name.indexOf('on') === 0) {
  1016. return;
  1017. }
  1018. if (attrs[i].name === 'style') {
  1019. attrs[i].value = editor.dom.serializeStyle(editor.dom.parseStyle(attrs[i].value), name);
  1020. }
  1021. }
  1022. writer.start(name, attrs, empty);
  1023. blocked = false;
  1024. },
  1025. end: function (name) {
  1026. if (blocked) {
  1027. return;
  1028. }
  1029. writer.end(name);
  1030. }
  1031. }, global$6({})).parse(html);
  1032. return writer.getContent();
  1033. };
  1034. var Sanitize = { sanitize: sanitize };
  1035. var createPlaceholderNode = function (editor, node) {
  1036. var placeHolder;
  1037. var name = node.name;
  1038. placeHolder = new global$7('img', 1);
  1039. placeHolder.shortEnded = true;
  1040. retainAttributesAndInnerHtml(editor, node, placeHolder);
  1041. placeHolder.attr({
  1042. 'width': node.attr('width') || '300',
  1043. 'height': node.attr('height') || (name === 'audio' ? '30' : '150'),
  1044. 'style': node.attr('style'),
  1045. 'src': global$8.transparentSrc,
  1046. 'data-mce-object': name,
  1047. 'class': 'mce-object mce-object-' + name
  1048. });
  1049. return placeHolder;
  1050. };
  1051. var createPreviewIframeNode = function (editor, node) {
  1052. var previewWrapper;
  1053. var previewNode;
  1054. var shimNode;
  1055. var name = node.name;
  1056. previewWrapper = new global$7('span', 1);
  1057. previewWrapper.attr({
  1058. 'contentEditable': 'false',
  1059. 'style': node.attr('style'),
  1060. 'data-mce-object': name,
  1061. 'class': 'mce-preview-object mce-object-' + name
  1062. });
  1063. retainAttributesAndInnerHtml(editor, node, previewWrapper);
  1064. previewNode = new global$7(name, 1);
  1065. previewNode.attr({
  1066. src: node.attr('src'),
  1067. allowfullscreen: node.attr('allowfullscreen'),
  1068. style: node.attr('style'),
  1069. class: node.attr('class'),
  1070. width: node.attr('width'),
  1071. height: node.attr('height'),
  1072. frameborder: '0'
  1073. });
  1074. shimNode = new global$7('span', 1);
  1075. shimNode.attr('class', 'mce-shim');
  1076. previewWrapper.append(previewNode);
  1077. previewWrapper.append(shimNode);
  1078. return previewWrapper;
  1079. };
  1080. var retainAttributesAndInnerHtml = function (editor, sourceNode, targetNode) {
  1081. var attrName;
  1082. var attrValue;
  1083. var attribs;
  1084. var ai;
  1085. var innerHtml;
  1086. attribs = sourceNode.attributes;
  1087. ai = attribs.length;
  1088. while (ai--) {
  1089. attrName = attribs[ai].name;
  1090. attrValue = attribs[ai].value;
  1091. if (attrName !== 'width' && attrName !== 'height' && attrName !== 'style') {
  1092. if (attrName === 'data' || attrName === 'src') {
  1093. attrValue = editor.convertURL(attrValue, attrName);
  1094. }
  1095. targetNode.attr('data-mce-p-' + attrName, attrValue);
  1096. }
  1097. }
  1098. innerHtml = sourceNode.firstChild && sourceNode.firstChild.value;
  1099. if (innerHtml) {
  1100. targetNode.attr('data-mce-html', escape(Sanitize.sanitize(editor, innerHtml)));
  1101. targetNode.firstChild = null;
  1102. }
  1103. };
  1104. var isPageEmbedWrapper = function (node) {
  1105. var nodeClass = node.attr('class');
  1106. return nodeClass && /\btiny-pageembed\b/.test(nodeClass);
  1107. };
  1108. var isWithinEmbedWrapper = function (node) {
  1109. while (node = node.parent) {
  1110. if (node.attr('data-ephox-embed-iri') || isPageEmbedWrapper(node)) {
  1111. return true;
  1112. }
  1113. }
  1114. return false;
  1115. };
  1116. var placeHolderConverter = function (editor) {
  1117. return function (nodes) {
  1118. var i = nodes.length;
  1119. var node;
  1120. var videoScript;
  1121. while (i--) {
  1122. node = nodes[i];
  1123. if (!node.parent) {
  1124. continue;
  1125. }
  1126. if (node.parent.attr('data-mce-object')) {
  1127. continue;
  1128. }
  1129. if (node.name === 'script') {
  1130. videoScript = VideoScript.getVideoScriptMatch(Settings.getScripts(editor), node.attr('src'));
  1131. if (!videoScript) {
  1132. continue;
  1133. }
  1134. }
  1135. if (videoScript) {
  1136. if (videoScript.width) {
  1137. node.attr('width', videoScript.width.toString());
  1138. }
  1139. if (videoScript.height) {
  1140. node.attr('height', videoScript.height.toString());
  1141. }
  1142. }
  1143. if (node.name === 'iframe' && Settings.hasLiveEmbeds(editor) && global$8.ceFalse) {
  1144. if (!isWithinEmbedWrapper(node)) {
  1145. node.replace(createPreviewIframeNode(editor, node));
  1146. }
  1147. } else {
  1148. if (!isWithinEmbedWrapper(node)) {
  1149. node.replace(createPlaceholderNode(editor, node));
  1150. }
  1151. }
  1152. }
  1153. };
  1154. };
  1155. var Nodes = {
  1156. createPreviewIframeNode: createPreviewIframeNode,
  1157. createPlaceholderNode: createPlaceholderNode,
  1158. placeHolderConverter: placeHolderConverter
  1159. };
  1160. var setup = function (editor) {
  1161. editor.on('preInit', function () {
  1162. var specialElements = editor.schema.getSpecialElements();
  1163. global$1.each('video audio iframe object'.split(' '), function (name) {
  1164. specialElements[name] = new RegExp('</' + name + '[^>]*>', 'gi');
  1165. });
  1166. var boolAttrs = editor.schema.getBoolAttrs();
  1167. global$1.each('webkitallowfullscreen mozallowfullscreen allowfullscreen'.split(' '), function (name) {
  1168. boolAttrs[name] = {};
  1169. });
  1170. editor.parser.addNodeFilter('iframe,video,audio,object,embed,script', Nodes.placeHolderConverter(editor));
  1171. editor.serializer.addAttributeFilter('data-mce-object', function (nodes, name) {
  1172. var i = nodes.length;
  1173. var node;
  1174. var realElm;
  1175. var ai;
  1176. var attribs;
  1177. var innerHtml;
  1178. var innerNode;
  1179. var realElmName;
  1180. var className;
  1181. while (i--) {
  1182. node = nodes[i];
  1183. if (!node.parent) {
  1184. continue;
  1185. }
  1186. realElmName = node.attr(name);
  1187. realElm = new global$7(realElmName, 1);
  1188. if (realElmName !== 'audio' && realElmName !== 'script') {
  1189. className = node.attr('class');
  1190. if (className && className.indexOf('mce-preview-object') !== -1) {
  1191. realElm.attr({
  1192. width: node.firstChild.attr('width'),
  1193. height: node.firstChild.attr('height')
  1194. });
  1195. } else {
  1196. realElm.attr({
  1197. width: node.attr('width'),
  1198. height: node.attr('height')
  1199. });
  1200. }
  1201. }
  1202. realElm.attr({ style: node.attr('style') });
  1203. attribs = node.attributes;
  1204. ai = attribs.length;
  1205. while (ai--) {
  1206. var attrName = attribs[ai].name;
  1207. if (attrName.indexOf('data-mce-p-') === 0) {
  1208. realElm.attr(attrName.substr(11), attribs[ai].value);
  1209. }
  1210. }
  1211. if (realElmName === 'script') {
  1212. realElm.attr('type', 'text/javascript');
  1213. }
  1214. innerHtml = node.attr('data-mce-html');
  1215. if (innerHtml) {
  1216. innerNode = new global$7('#text', 3);
  1217. innerNode.raw = true;
  1218. innerNode.value = Sanitize.sanitize(editor, unescape(innerHtml));
  1219. realElm.append(innerNode);
  1220. }
  1221. node.replace(realElm);
  1222. }
  1223. });
  1224. });
  1225. editor.on('setContent', function () {
  1226. editor.$('span.mce-preview-object').each(function (index, elm) {
  1227. var $elm = editor.$(elm);
  1228. if ($elm.find('span.mce-shim', elm).length === 0) {
  1229. $elm.append('<span class="mce-shim"></span>');
  1230. }
  1231. });
  1232. });
  1233. };
  1234. var FilterContent = { setup: setup };
  1235. var setup$1 = function (editor) {
  1236. editor.on('ResolveName', function (e) {
  1237. var name;
  1238. if (e.target.nodeType === 1 && (name = e.target.getAttribute('data-mce-object'))) {
  1239. e.name = name;
  1240. }
  1241. });
  1242. };
  1243. var ResolveName = { setup: setup$1 };
  1244. var setup$2 = function (editor) {
  1245. editor.on('click keyup', function () {
  1246. var selectedNode = editor.selection.getNode();
  1247. if (selectedNode && editor.dom.hasClass(selectedNode, 'mce-preview-object')) {
  1248. if (editor.dom.getAttrib(selectedNode, 'data-mce-selected')) {
  1249. selectedNode.setAttribute('data-mce-selected', '2');
  1250. }
  1251. }
  1252. });
  1253. editor.on('ObjectSelected', function (e) {
  1254. var objectType = e.target.getAttribute('data-mce-object');
  1255. if (objectType === 'audio' || objectType === 'script') {
  1256. e.preventDefault();
  1257. }
  1258. });
  1259. editor.on('objectResized', function (e) {
  1260. var target = e.target;
  1261. var html;
  1262. if (target.getAttribute('data-mce-object')) {
  1263. html = target.getAttribute('data-mce-html');
  1264. if (html) {
  1265. html = unescape(html);
  1266. target.setAttribute('data-mce-html', escape(UpdateHtml.updateHtml(html, {
  1267. width: e.width,
  1268. height: e.height
  1269. })));
  1270. }
  1271. }
  1272. });
  1273. };
  1274. var Selection = { setup: setup$2 };
  1275. var stateSelectorAdapter = function (editor, selector) {
  1276. return function (buttonApi) {
  1277. return editor.selection.selectorChangedWithUnbind(selector.join(','), buttonApi.setActive).unbind;
  1278. };
  1279. };
  1280. var register$1 = function (editor) {
  1281. editor.ui.registry.addToggleButton('media', {
  1282. tooltip: 'Insert/edit media',
  1283. icon: 'embed',
  1284. onAction: function () {
  1285. editor.execCommand('mceMedia');
  1286. },
  1287. onSetup: stateSelectorAdapter(editor, [
  1288. 'img[data-mce-object]',
  1289. 'span[data-mce-object]',
  1290. 'div[data-ephox-embed-iri]'
  1291. ])
  1292. });
  1293. editor.ui.registry.addMenuItem('media', {
  1294. icon: 'embed',
  1295. text: 'Media...',
  1296. onAction: function () {
  1297. editor.execCommand('mceMedia');
  1298. }
  1299. });
  1300. };
  1301. var Buttons = { register: register$1 };
  1302. global.add('media', function (editor) {
  1303. Commands.register(editor);
  1304. Buttons.register(editor);
  1305. ResolveName.setup(editor);
  1306. FilterContent.setup(editor);
  1307. Selection.setup(editor);
  1308. return Api.get(editor);
  1309. });
  1310. function Plugin () {
  1311. }
  1312. return Plugin;
  1313. }());
  1314. })();