plugin.js 13 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449
  1. /*
  2. * Youtube Embed Plugin
  3. *
  4. * @author Jonnas Fonini <jonnasfonini@gmail.com>
  5. * @version 2.1.14
  6. */
  7. (function () {
  8. CKEDITOR.plugins.add('youtube', {
  9. lang: [ 'en', 'bg', 'pt', 'pt-br', 'ja', 'hu', 'it', 'fr', 'tr', 'ru', 'de', 'ar', 'nl', 'pl', 'vi', 'zh', 'el', 'he', 'es', 'nb', 'nn', 'fi', 'et', 'sk', 'cs', 'ko', 'eu', 'uk'],
  10. init: function (editor) {
  11. editor.addCommand('youtube', new CKEDITOR.dialogCommand('youtube', {
  12. allowedContent: 'div{*}(*); iframe{*}[!width,!height,!src,!frameborder,!allowfullscreen,!allow]; object param[*]; a[*]; img[*]'
  13. }));
  14. editor.ui.addButton('Youtube', {
  15. label : editor.lang.youtube.button,
  16. toolbar : 'insert',
  17. command : 'youtube',
  18. icon : this.path + 'images/icon.png'
  19. });
  20. CKEDITOR.dialog.add('youtube', function (instance) {
  21. var video,
  22. disabled = editor.config.youtube_disabled_fields || [];
  23. return {
  24. title : editor.lang.youtube.title,
  25. minWidth : 510,
  26. minHeight : 200,
  27. onShow: function () {
  28. for (var i = 0; i < disabled.length; i++) {
  29. this.getContentElement('youtubePlugin', disabled[i]).disable();
  30. }
  31. },
  32. contents :
  33. [{
  34. id : 'youtubePlugin',
  35. expand : true,
  36. elements :
  37. [{
  38. id : 'txtEmbed',
  39. type : 'textarea',
  40. label : editor.lang.youtube.txtEmbed,
  41. onChange : function (api) {
  42. handleEmbedChange(this, api);
  43. },
  44. onKeyUp : function (api) {
  45. handleEmbedChange(this, api);
  46. },
  47. validate : function () {
  48. if (this.isEnabled()) {
  49. if (!this.getValue()) {
  50. alert(editor.lang.youtube.noCode);
  51. return false;
  52. }
  53. else
  54. if (this.getValue().length === 0 || this.getValue().indexOf('//') === -1) {
  55. alert(editor.lang.youtube.invalidEmbed);
  56. return false;
  57. }
  58. }
  59. }
  60. },
  61. {
  62. type : 'html',
  63. html : editor.lang.youtube.or + '<hr>'
  64. },
  65. {
  66. type : 'hbox',
  67. widths : [ '70%', '15%', '15%' ],
  68. children :
  69. [
  70. {
  71. id : 'txtUrl',
  72. type : 'text',
  73. label : editor.lang.youtube.txtUrl,
  74. onChange : function (api) {
  75. handleLinkChange(this, api);
  76. },
  77. onKeyUp : function (api) {
  78. handleLinkChange(this, api);
  79. },
  80. validate : function () {
  81. if (this.isEnabled()) {
  82. if (!this.getValue()) {
  83. alert(editor.lang.youtube.noCode);
  84. return false;
  85. }
  86. else{
  87. video = ytVidId(this.getValue());
  88. if (this.getValue().length === 0 || video === false)
  89. {
  90. alert(editor.lang.youtube.invalidUrl);
  91. return false;
  92. }
  93. }
  94. }
  95. }
  96. },
  97. {
  98. type : 'text',
  99. id : 'txtWidth',
  100. width : '60px',
  101. label : editor.lang.youtube.txtWidth,
  102. 'default' : editor.config.youtube_width != null ? editor.config.youtube_width : '640',
  103. validate : function () {
  104. if (this.getValue()) {
  105. var width = parseInt (this.getValue()) || 0;
  106. if (width === 0) {
  107. alert(editor.lang.youtube.invalidWidth);
  108. return false;
  109. }
  110. }
  111. else {
  112. alert(editor.lang.youtube.noWidth);
  113. return false;
  114. }
  115. }
  116. },
  117. {
  118. type : 'text',
  119. id : 'txtHeight',
  120. width : '60px',
  121. label : editor.lang.youtube.txtHeight,
  122. 'default' : editor.config.youtube_height != null ? editor.config.youtube_height : '360',
  123. validate : function () {
  124. if (this.getValue()) {
  125. var height = parseInt(this.getValue()) || 0;
  126. if (height === 0) {
  127. alert(editor.lang.youtube.invalidHeight);
  128. return false;
  129. }
  130. }
  131. else {
  132. alert(editor.lang.youtube.noHeight);
  133. return false;
  134. }
  135. }
  136. }
  137. ]
  138. },
  139. {
  140. type : 'hbox',
  141. widths : [ '55%', '45%' ],
  142. children :
  143. [
  144. {
  145. id : 'chkResponsive',
  146. type : 'checkbox',
  147. label : editor.lang.youtube.txtResponsive,
  148. 'default' : editor.config.youtube_responsive != null ? editor.config.youtube_responsive : false
  149. },
  150. {
  151. id : 'chkNoEmbed',
  152. type : 'checkbox',
  153. label : editor.lang.youtube.txtNoEmbed,
  154. 'default' : editor.config.youtube_noembed != null ? editor.config.youtube_noembed : false
  155. }
  156. ]
  157. },
  158. {
  159. type : 'hbox',
  160. widths : [ '55%', '45%' ],
  161. children :
  162. [
  163. {
  164. id : 'chkRelated',
  165. type : 'checkbox',
  166. 'default' : editor.config.youtube_related != null ? editor.config.youtube_related : true,
  167. label : editor.lang.youtube.chkRelated
  168. },
  169. {
  170. id : 'chkOlderCode',
  171. type : 'checkbox',
  172. 'default' : editor.config.youtube_older != null ? editor.config.youtube_older : false,
  173. label : editor.lang.youtube.chkOlderCode
  174. }
  175. ]
  176. },
  177. {
  178. type : 'hbox',
  179. widths : [ '55%', '45%' ],
  180. children :
  181. [
  182. {
  183. id : 'chkPrivacy',
  184. type : 'checkbox',
  185. label : editor.lang.youtube.chkPrivacy,
  186. 'default' : editor.config.youtube_privacy != null ? editor.config.youtube_privacy : false
  187. },
  188. {
  189. id : 'chkAutoplay',
  190. type : 'checkbox',
  191. 'default' : editor.config.youtube_autoplay != null ? editor.config.youtube_autoplay : false,
  192. label : editor.lang.youtube.chkAutoplay
  193. }
  194. ]
  195. },
  196. {
  197. type : 'hbox',
  198. widths : [ '55%', '45%'],
  199. children :
  200. [
  201. {
  202. id : 'txtStartAt',
  203. type : 'text',
  204. label : editor.lang.youtube.txtStartAt,
  205. validate : function () {
  206. if (this.getValue()) {
  207. var str = this.getValue();
  208. if (!/^(?:(?:([01]?\d|2[0-3]):)?([0-5]?\d):)?([0-5]?\d)$/i.test(str)) {
  209. alert(editor.lang.youtube.invalidTime);
  210. return false;
  211. }
  212. }
  213. }
  214. },
  215. {
  216. id : 'chkControls',
  217. type : 'checkbox',
  218. 'default' : editor.config.youtube_controls != null ? editor.config.youtube_controls : true,
  219. label : editor.lang.youtube.chkControls
  220. }
  221. ]
  222. }
  223. ]
  224. }
  225. ],
  226. onOk: function()
  227. {
  228. var content = '';
  229. var responsiveStyle = '';
  230. if (this.getContentElement('youtubePlugin', 'txtEmbed').isEnabled()) {
  231. content = this.getValueOf('youtubePlugin', 'txtEmbed');
  232. }
  233. else {
  234. var url = 'https://', params = [], startSecs, paramAutoplay='';
  235. var width = this.getValueOf('youtubePlugin', 'txtWidth');
  236. var height = this.getValueOf('youtubePlugin', 'txtHeight');
  237. if (this.getContentElement('youtubePlugin', 'chkPrivacy').getValue() === true) {
  238. url += 'www.youtube-nocookie.com/';
  239. }
  240. else {
  241. url += 'www.youtube.com/';
  242. }
  243. url += 'embed/' + video;
  244. if (this.getContentElement('youtubePlugin', 'chkRelated').getValue() === false) {
  245. params.push('rel=0');
  246. }
  247. if (this.getContentElement('youtubePlugin', 'chkAutoplay').getValue() === true) {
  248. params.push('autoplay=1');
  249. paramAutoplay='autoplay';
  250. }
  251. if (this.getContentElement('youtubePlugin', 'chkControls').getValue() === false) {
  252. params.push('controls=0');
  253. }
  254. startSecs = this.getValueOf('youtubePlugin', 'txtStartAt');
  255. if (startSecs) {
  256. var seconds = hmsToSeconds(startSecs);
  257. params.push('start=' + seconds);
  258. }
  259. if (params.length > 0) {
  260. url = url + '?' + params.join('&');
  261. }
  262. if (this.getContentElement('youtubePlugin', 'chkResponsive').getValue() === true) {
  263. content += '<div class="youtube-embed-wrapper" style="position:relative;padding-bottom:56.25%;padding-top:30px;height:0;overflow:hidden">';
  264. responsiveStyle = 'style="position:absolute;top:0;left:0;width:100%;height:100%"';
  265. }
  266. if (this.getContentElement('youtubePlugin', 'chkOlderCode').getValue() === true) {
  267. url = url.replace('embed/', 'v/');
  268. url = url.replace(/&/g, '&amp;');
  269. if (url.indexOf('?') === -1) {
  270. url += '?';
  271. }
  272. else {
  273. url += '&amp;';
  274. }
  275. url += 'hl=' + (this.getParentEditor().config.language ? this.getParentEditor().config.language : 'en') + '&amp;version=3';
  276. content += '<object width="' + width + '" height="' + height + '" ' + responsiveStyle + '>';
  277. content += '<param name="movie" value="' + url + '"></param>';
  278. content += '<param name="allowFullScreen" value="true"></param>';
  279. content += '<param name="allowscriptaccess" value="always"></param>';
  280. content += '<embed src="' + url + '" type="application/x-shockwave-flash" ';
  281. content += 'width="' + width + '" height="' + height + '" '+ responsiveStyle + ' allowscriptaccess="always" ';
  282. content += 'allowfullscreen="true"></embed>';
  283. content += '</object>';
  284. }
  285. else
  286. if (this.getContentElement('youtubePlugin', 'chkNoEmbed').getValue() === true) {
  287. var imgSrc = 'https://img.youtube.com/vi/' + video + '/sddefault.jpg';
  288. content += '<a href="' + url + '" ><img width="' + width + '" height="' + height + '" src="' + imgSrc + '" ' + responsiveStyle + '/></a>';
  289. }
  290. else {
  291. content += '<iframe ' + (paramAutoplay ? 'allow="' + paramAutoplay + ';" ' : '') + 'width="' + width + '" height="' + height + '" src="' + url + '" ' + responsiveStyle;
  292. content += 'frameborder="0" allowfullscreen></iframe>';
  293. }
  294. if (this.getContentElement('youtubePlugin', 'chkResponsive').getValue() === true) {
  295. content += '</div>';
  296. }
  297. }
  298. var element = CKEDITOR.dom.element.createFromHtml(content);
  299. var instance = this.getParentEditor();
  300. instance.insertElement(element);
  301. }
  302. };
  303. });
  304. }
  305. });
  306. })();
  307. function handleLinkChange(el, api) {
  308. var video = ytVidId(el.getValue());
  309. var time = ytVidTime(el.getValue());
  310. if (el.getValue().length > 0) {
  311. el.getDialog().getContentElement('youtubePlugin', 'txtEmbed').disable();
  312. }
  313. else if (!disabled.length || !disabled.includes('txtEmbed')) {
  314. el.getDialog().getContentElement('youtubePlugin', 'txtEmbed').enable();
  315. }
  316. if (video && time) {
  317. var seconds = timeParamToSeconds(time);
  318. var hms = secondsToHms(seconds);
  319. el.getDialog().getContentElement('youtubePlugin', 'txtStartAt').setValue(hms);
  320. }
  321. }
  322. function handleEmbedChange(el, api) {
  323. if (el.getValue().length > 0) {
  324. el.getDialog().getContentElement('youtubePlugin', 'txtUrl').disable();
  325. }
  326. else {
  327. el.getDialog().getContentElement('youtubePlugin', 'txtUrl').enable();
  328. }
  329. }
  330. /**
  331. * JavaScript function to match (and return) the video Id
  332. * of any valid Youtube Url, given as input string.
  333. * @author: Stephan Schmitz <eyecatchup@gmail.com>
  334. * @url: http://stackoverflow.com/a/10315969/624466
  335. */
  336. function ytVidId(url) {
  337. var p = /^(?:https?:\/\/)?(?:www\.)?(?:youtu\.be\/|youtube\.com\/(?:embed\/|v\/|watch\?v=|watch\?.+&v=))((\w|-){11})(?:\S+)?$/;
  338. return (url.match(p)) ? RegExp.$1 : false;
  339. }
  340. /**
  341. * Matches and returns time param in YouTube Urls.
  342. */
  343. function ytVidTime(url) {
  344. var p = /t=([0-9hms]+)/;
  345. return (url.match(p)) ? RegExp.$1 : false;
  346. }
  347. /**
  348. * Converts time in hms format to seconds only
  349. */
  350. function hmsToSeconds(time) {
  351. var arr = time.split(':'), s = 0, m = 1;
  352. while (arr.length > 0) {
  353. s += m * parseInt(arr.pop(), 10);
  354. m *= 60;
  355. }
  356. return s;
  357. }
  358. /**
  359. * Converts seconds to hms format
  360. */
  361. function secondsToHms(seconds) {
  362. var h = Math.floor(seconds / 3600);
  363. var m = Math.floor((seconds / 60) % 60);
  364. var s = seconds % 60;
  365. var pad = function (n) {
  366. n = String(n);
  367. return n.length >= 2 ? n : "0" + n;
  368. };
  369. if (h > 0) {
  370. return pad(h) + ':' + pad(m) + ':' + pad(s);
  371. }
  372. else {
  373. return pad(m) + ':' + pad(s);
  374. }
  375. }
  376. /**
  377. * Converts time in youtube t-param format to seconds
  378. */
  379. function timeParamToSeconds(param) {
  380. var componentValue = function (si) {
  381. var regex = new RegExp('(\\d+)' + si);
  382. return param.match(regex) ? parseInt(RegExp.$1, 10) : 0;
  383. };
  384. return componentValue('h') * 3600
  385. + componentValue('m') * 60
  386. + componentValue('s');
  387. }
  388. /**
  389. * Converts seconds into youtube t-param value, e.g. 1h4m30s
  390. */
  391. function secondsToTimeParam(seconds) {
  392. var h = Math.floor(seconds / 3600);
  393. var m = Math.floor((seconds / 60) % 60);
  394. var s = seconds % 60;
  395. var param = '';
  396. if (h > 0) {
  397. param += h + 'h';
  398. }
  399. if (m > 0) {
  400. param += m + 'm';
  401. }
  402. if (s > 0) {
  403. param += s + 's';
  404. }
  405. return param;
  406. }