Нема описа

plugin.js 40KB

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