video.js 19 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453
  1. CKEDITOR.dialog.add( 'video', function ( editor )
  2. {
  3. var lang = editor.lang.video;
  4. function commitValue( videoNode, extraStyles )
  5. {
  6. var value=this.getValue();
  7. if ( !value && this.id=='id' )
  8. value = generateId();
  9. if (value == '') {
  10. // return;
  11. }
  12. switch (this.id) {
  13. case '360video':
  14. if (value) {
  15. videoNode.setAttribute( 'data-360video', 'true' );
  16. } else {
  17. videoNode.removeAttribute( 'data-360video' );
  18. }
  19. break;
  20. case '360videostereo':
  21. if (videoNode.getAttribute( 'data-360video' ) === 'true') {
  22. if (!value) {
  23. videoNode.setAttribute( 'data-360video-stereo', 'false' );
  24. } else {
  25. videoNode.removeAttribute( 'data-360video-stereo' );
  26. }
  27. }
  28. break;
  29. default:
  30. videoNode.setAttribute( this.id, value);
  31. }
  32. if ( !value )
  33. return;
  34. switch( this.id )
  35. {
  36. case 'responsive':
  37. videoNode.addClass('embed-responsive-item');
  38. break;
  39. case 'poster':
  40. extraStyles.backgroundImage = 'url(' + value + ')';
  41. break;
  42. case 'width':
  43. extraStyles.width = value.indexOf('%') > 0 ? value : (parseInt(value) + 'px');
  44. break;
  45. case 'height':
  46. extraStyles.height = value.indexOf('%') > 0 ? value : (parseInt(value) + 'px');
  47. break;
  48. }
  49. }
  50. function commitSrc( videoNode, extraStyles, videos )
  51. {
  52. var match = this.id.match(/(\w+)(\d)/),
  53. id = match[1],
  54. number = parseInt(match[2], 10);
  55. var video = videos[number] || (videos[number]={});
  56. video[id] = this.getValue();
  57. }
  58. function loadValue( videoNode )
  59. {
  60. if ( videoNode ) {
  61. switch (this.id) {
  62. case '360video':
  63. this.setValue(videoNode.getAttribute( 'data-360video' ) === 'true');
  64. break;
  65. case '360videostereo':
  66. this.setValue(videoNode.getAttribute( 'data-360video-stereo' ) !== 'false');
  67. break;
  68. default:
  69. this.setValue( videoNode.getAttribute( this.id ) );
  70. }
  71. }
  72. else
  73. {
  74. if ( this.id == 'id')
  75. this.setValue( generateId() );
  76. }
  77. }
  78. function loadSrc( videoNode, videos )
  79. {
  80. var match = this.id.match(/(\w+)(\d)/),
  81. id = match[1],
  82. number = parseInt(match[2], 10);
  83. var video = videos[number];
  84. if (!video)
  85. return;
  86. this.setValue( video[ id ] );
  87. }
  88. function generateId()
  89. {
  90. var now = new Date();
  91. return 'video' + now.getFullYear() + now.getMonth() + now.getDate() + now.getHours() + now.getMinutes() + now.getSeconds();
  92. }
  93. // To automatically get the dimensions of the poster image
  94. var onImgLoadEvent = function()
  95. {
  96. // Image is ready.
  97. var preview = this.previewImage;
  98. preview.removeListener( 'load', onImgLoadEvent );
  99. preview.removeListener( 'error', onImgLoadErrorEvent );
  100. preview.removeListener( 'abort', onImgLoadErrorEvent );
  101. this.setValueOf( 'info', 'width', preview.$.width );
  102. this.setValueOf( 'info', 'height', preview.$.height );
  103. };
  104. var onImgLoadErrorEvent = function()
  105. {
  106. // Error. Image is not loaded.
  107. var preview = this.previewImage;
  108. preview.removeListener( 'load', onImgLoadEvent );
  109. preview.removeListener( 'error', onImgLoadErrorEvent );
  110. preview.removeListener( 'abort', onImgLoadErrorEvent );
  111. };
  112. return {
  113. title : lang.dialogTitle,
  114. minWidth : 400,
  115. minHeight : 200,
  116. onShow : function()
  117. {
  118. // Clear previously saved elements.
  119. this.fakeImage = this.videoNode = null;
  120. // To get dimensions of poster image
  121. this.previewImage = editor.document.createElement( 'img' );
  122. var fakeImage = this.getSelectedElement();
  123. if ( fakeImage && fakeImage.data( 'cke-real-element-type' ) && fakeImage.data( 'cke-real-element-type' ) == 'video' )
  124. {
  125. this.fakeImage = fakeImage;
  126. var videoNode = editor.restoreRealElement( fakeImage ),
  127. videos = [],
  128. sourceList = videoNode.getElementsByTag( 'source', '' );
  129. if (sourceList.count()==0)
  130. sourceList = videoNode.getElementsByTag( 'source', 'cke' );
  131. for ( var i = 0, length = sourceList.count() ; i < length ; i++ )
  132. {
  133. var item = sourceList.getItem( i );
  134. videos.push( {src : item.getAttribute( 'src' ), type: item.getAttribute( 'type' )} );
  135. }
  136. this.videoNode = videoNode;
  137. this.setupContent( videoNode, videos );
  138. }
  139. else
  140. this.setupContent( null, [] );
  141. },
  142. onOk : function()
  143. {
  144. // If there's no selected element create one. Otherwise, reuse it
  145. var videoNode = null;
  146. if ( !this.fakeImage )
  147. {
  148. videoNode = CKEDITOR.dom.element.createFromHtml( '<cke:video></cke:video>', editor.document );
  149. videoNode.setAttributes(
  150. {
  151. controls : 'controls'
  152. } );
  153. }
  154. else
  155. {
  156. videoNode = this.videoNode;
  157. }
  158. var extraStyles = {}, videos = [];
  159. var responsive = this.getValueOf('info', 'responsive');
  160. videoNode.removeClass('embed-responsive-item');
  161. if (responsive) {
  162. this.setValueOf('info', 'width', '100%');
  163. this.setValueOf('info', 'height', '100%');
  164. }
  165. this.commitContent( videoNode, extraStyles, videos );
  166. var innerHtml = '', links = '',
  167. link = lang.linkTemplate || '',
  168. fallbackTemplate = lang.fallbackTemplate || '';
  169. for(var i=0; i<videos.length; i++)
  170. {
  171. var video = videos[i];
  172. if ( !video || !video.src )
  173. continue;
  174. innerHtml += '<cke:source src="' + video.src + '" type="' + video.type + '" />';
  175. links += link.replace('%src%', video.src).replace('%type%', video.type);
  176. }
  177. videoNode.setHtml( innerHtml + fallbackTemplate.replace( '%links%', links ) );
  178. var responsiveParent = null;
  179. // Refresh the fake image.
  180. var newFakeImage = editor.createFakeElement( videoNode, 'cke_video', 'video', false );
  181. newFakeImage.setStyles( extraStyles );
  182. if ( this.fakeImage )
  183. {
  184. newFakeImage.replace( this.fakeImage );
  185. editor.getSelection().selectElement( newFakeImage );
  186. if (responsive) {
  187. responsiveParent = newFakeImage.getParent();
  188. responsiveParent.removeClass('embed-responsive');
  189. responsiveParent.removeClass('embed-responsive-16by9');
  190. responsiveParent.removeClass('embed-responsive-4by3');
  191. }
  192. }
  193. else
  194. {
  195. // Insert it in a div
  196. var div = new CKEDITOR.dom.element( 'DIV', editor.document );
  197. editor.insertElement( div );
  198. div.append( newFakeImage );
  199. responsiveParent = div;
  200. }
  201. if (responsive) {
  202. newFakeImage.addClass('embed-responsive-item');
  203. responsiveParent.addClass('embed-responsive');
  204. switch (responsive) {
  205. case '16by9':
  206. responsiveParent.addClass('embed-responsive-16by9');
  207. break;
  208. case '4by3':
  209. responsiveParent.addClass('embed-responsive-4by3');
  210. break;
  211. }
  212. }
  213. },
  214. onHide : function()
  215. {
  216. if ( this.previewImage )
  217. {
  218. this.previewImage.removeListener( 'load', onImgLoadEvent );
  219. this.previewImage.removeListener( 'error', onImgLoadErrorEvent );
  220. this.previewImage.removeListener( 'abort', onImgLoadErrorEvent );
  221. this.previewImage.remove();
  222. this.previewImage = null; // Dialog is closed.
  223. }
  224. },
  225. contents :
  226. [
  227. {
  228. id : 'info',
  229. label: lang.infoLabel,
  230. elements :
  231. [
  232. {
  233. type : 'hbox',
  234. widths: [ '', '100px', '75px'],
  235. children : [
  236. {
  237. type : 'text',
  238. id : 'src0',
  239. label : lang.sourceVideo,
  240. commit : commitSrc,
  241. setup : loadSrc
  242. },
  243. {
  244. type : 'button',
  245. id : 'browse',
  246. hidden : 'true',
  247. style : 'display:inline-block;margin-top:10px;',
  248. filebrowser :
  249. {
  250. action : 'Browse',
  251. target: 'info:src0',
  252. url: editor.config.filebrowserVideoBrowseUrl || editor.config.filebrowserBrowseUrl
  253. },
  254. label : editor.lang.common.browseServer
  255. },
  256. {
  257. id : 'type0',
  258. label : lang.sourceType,
  259. type : 'select',
  260. 'default' : 'video/mp4',
  261. items :
  262. [
  263. [ 'MP4', 'video/mp4' ],
  264. [ 'WebM', 'video/webm' ]
  265. ],
  266. commit : commitSrc,
  267. setup : loadSrc
  268. }]
  269. },
  270. {
  271. type : 'hbox',
  272. widths: [ '', '100px', '75px'],
  273. children : [
  274. {
  275. type : 'text',
  276. id : 'src1',
  277. label : lang.sourceVideo,
  278. commit : commitSrc,
  279. setup : loadSrc
  280. },
  281. {
  282. type : 'button',
  283. id : 'browse',
  284. hidden : 'true',
  285. style : 'display:inline-block;margin-top:10px;',
  286. filebrowser :
  287. {
  288. action : 'Browse',
  289. target: 'info:src1',
  290. url: editor.config.filebrowserVideoBrowseUrl || editor.config.filebrowserBrowseUrl
  291. },
  292. label : editor.lang.common.browseServer
  293. },
  294. {
  295. id : 'type1',
  296. label : lang.sourceType,
  297. type : 'select',
  298. 'default':'video/webm',
  299. items :
  300. [
  301. [ 'MP4', 'video/mp4' ],
  302. [ 'WebM', 'video/webm' ]
  303. ],
  304. commit : commitSrc,
  305. setup : loadSrc
  306. }]
  307. },
  308. {
  309. type : 'hbox',
  310. widths: [ '', '100px'],
  311. children : [
  312. {
  313. type : 'text',
  314. id : 'poster',
  315. label : lang.poster,
  316. commit : commitValue,
  317. setup : loadValue,
  318. onChange : function()
  319. {
  320. var dialog = this.getDialog(),
  321. newUrl = this.getValue();
  322. //Update preview image
  323. if ( newUrl.length > 0 ) //Prevent from load before onShow
  324. {
  325. dialog = this.getDialog();
  326. var preview = dialog.previewImage;
  327. preview.on( 'load', onImgLoadEvent, dialog );
  328. preview.on( 'error', onImgLoadErrorEvent, dialog );
  329. preview.on( 'abort', onImgLoadErrorEvent, dialog );
  330. preview.setAttribute( 'src', newUrl );
  331. }
  332. }
  333. },
  334. {
  335. type : 'button',
  336. id : 'browse',
  337. hidden : 'true',
  338. style : 'display:inline-block;margin-top:10px;',
  339. filebrowser :
  340. {
  341. action : 'Browse',
  342. target: 'info:poster',
  343. url: editor.config.filebrowserImageBrowseUrl || editor.config.filebrowserBrowseUrl
  344. },
  345. label : editor.lang.common.browseServer
  346. }]
  347. },
  348. {
  349. type : 'hbox',
  350. widths: [ '33%', '33%', '33%'],
  351. children : [
  352. {
  353. type : 'text',
  354. id : 'width',
  355. label : editor.lang.common.width,
  356. 'default' : 400,
  357. validate : CKEDITOR.dialog.validate.notEmpty( lang.widthRequired ),
  358. commit : commitValue,
  359. setup : loadValue
  360. },
  361. {
  362. type : 'text',
  363. id : 'height',
  364. label : editor.lang.common.height,
  365. 'default' : 300,
  366. //validate : CKEDITOR.dialog.validate.notEmpty(lang.heightRequired ),
  367. commit : commitValue,
  368. setup : loadValue
  369. },
  370. {
  371. type : 'text',
  372. id : 'id',
  373. label : 'Id',
  374. commit : commitValue,
  375. setup : loadValue
  376. }
  377. ]
  378. },
  379. {
  380. type: 'radio',
  381. id: 'responsive',
  382. label: lang.responsive,
  383. items: [ [ lang.ratio16by9, '16by9' ], [ lang.ratio4by3, '4by3' ] ],
  384. commit : commitValue,
  385. setup : loadValue
  386. }
  387. ]
  388. },
  389. {
  390. id: '360',
  391. label: '360°',
  392. elements: [
  393. {
  394. type : 'html',
  395. html : lang.html360
  396. },
  397. {
  398. type : 'checkbox',
  399. id : '360video',
  400. label: lang.video360,
  401. commit : commitValue,
  402. setup : loadValue
  403. },
  404. {
  405. type : 'checkbox',
  406. id : '360videostereo',
  407. label : lang.video360stereo,
  408. 'default': 'checked',
  409. commit : commitValue,
  410. setup : loadValue
  411. }
  412. ]
  413. }
  414. ]
  415. };
  416. } );