video.js 19 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452
  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. responsiveParent.addClass('embed-responsive');
  203. switch (responsive) {
  204. case '16by9':
  205. responsiveParent.addClass('embed-responsive-16by9');
  206. break;
  207. case '4by3':
  208. responsiveParent.addClass('embed-responsive-4by3');
  209. break;
  210. }
  211. }
  212. },
  213. onHide : function()
  214. {
  215. if ( this.previewImage )
  216. {
  217. this.previewImage.removeListener( 'load', onImgLoadEvent );
  218. this.previewImage.removeListener( 'error', onImgLoadErrorEvent );
  219. this.previewImage.removeListener( 'abort', onImgLoadErrorEvent );
  220. this.previewImage.remove();
  221. this.previewImage = null; // Dialog is closed.
  222. }
  223. },
  224. contents :
  225. [
  226. {
  227. id : 'info',
  228. label: lang.infoLabel,
  229. elements :
  230. [
  231. {
  232. type : 'hbox',
  233. widths: [ '', '100px', '75px'],
  234. children : [
  235. {
  236. type : 'text',
  237. id : 'src0',
  238. label : lang.sourceVideo,
  239. commit : commitSrc,
  240. setup : loadSrc
  241. },
  242. {
  243. type : 'button',
  244. id : 'browse',
  245. hidden : 'true',
  246. style : 'display:inline-block;margin-top:10px;',
  247. filebrowser :
  248. {
  249. action : 'Browse',
  250. target: 'info:src0',
  251. url: editor.config.filebrowserVideoBrowseUrl || editor.config.filebrowserBrowseUrl
  252. },
  253. label : editor.lang.common.browseServer
  254. },
  255. {
  256. id : 'type0',
  257. label : lang.sourceType,
  258. type : 'select',
  259. 'default' : 'video/mp4',
  260. items :
  261. [
  262. [ 'MP4', 'video/mp4' ],
  263. [ 'WebM', 'video/webm' ]
  264. ],
  265. commit : commitSrc,
  266. setup : loadSrc
  267. }]
  268. },
  269. {
  270. type : 'hbox',
  271. widths: [ '', '100px', '75px'],
  272. children : [
  273. {
  274. type : 'text',
  275. id : 'src1',
  276. label : lang.sourceVideo,
  277. commit : commitSrc,
  278. setup : loadSrc
  279. },
  280. {
  281. type : 'button',
  282. id : 'browse',
  283. hidden : 'true',
  284. style : 'display:inline-block;margin-top:10px;',
  285. filebrowser :
  286. {
  287. action : 'Browse',
  288. target: 'info:src1',
  289. url: editor.config.filebrowserVideoBrowseUrl || editor.config.filebrowserBrowseUrl
  290. },
  291. label : editor.lang.common.browseServer
  292. },
  293. {
  294. id : 'type1',
  295. label : lang.sourceType,
  296. type : 'select',
  297. 'default':'video/webm',
  298. items :
  299. [
  300. [ 'MP4', 'video/mp4' ],
  301. [ 'WebM', 'video/webm' ]
  302. ],
  303. commit : commitSrc,
  304. setup : loadSrc
  305. }]
  306. },
  307. {
  308. type : 'hbox',
  309. widths: [ '', '100px'],
  310. children : [
  311. {
  312. type : 'text',
  313. id : 'poster',
  314. label : lang.poster,
  315. commit : commitValue,
  316. setup : loadValue,
  317. onChange : function()
  318. {
  319. var dialog = this.getDialog(),
  320. newUrl = this.getValue();
  321. //Update preview image
  322. if ( newUrl.length > 0 ) //Prevent from load before onShow
  323. {
  324. dialog = this.getDialog();
  325. var preview = dialog.previewImage;
  326. preview.on( 'load', onImgLoadEvent, dialog );
  327. preview.on( 'error', onImgLoadErrorEvent, dialog );
  328. preview.on( 'abort', onImgLoadErrorEvent, dialog );
  329. preview.setAttribute( 'src', newUrl );
  330. }
  331. }
  332. },
  333. {
  334. type : 'button',
  335. id : 'browse',
  336. hidden : 'true',
  337. style : 'display:inline-block;margin-top:10px;',
  338. filebrowser :
  339. {
  340. action : 'Browse',
  341. target: 'info:poster',
  342. url: editor.config.filebrowserImageBrowseUrl || editor.config.filebrowserBrowseUrl
  343. },
  344. label : editor.lang.common.browseServer
  345. }]
  346. },
  347. {
  348. type : 'hbox',
  349. widths: [ '33%', '33%', '33%'],
  350. children : [
  351. {
  352. type : 'text',
  353. id : 'width',
  354. label : editor.lang.common.width,
  355. 'default' : 400,
  356. validate : CKEDITOR.dialog.validate.notEmpty( lang.widthRequired ),
  357. commit : commitValue,
  358. setup : loadValue
  359. },
  360. {
  361. type : 'text',
  362. id : 'height',
  363. label : editor.lang.common.height,
  364. 'default' : 300,
  365. //validate : CKEDITOR.dialog.validate.notEmpty(lang.heightRequired ),
  366. commit : commitValue,
  367. setup : loadValue
  368. },
  369. {
  370. type : 'text',
  371. id : 'id',
  372. label : 'Id',
  373. commit : commitValue,
  374. setup : loadValue
  375. }
  376. ]
  377. },
  378. {
  379. type: 'radio',
  380. id: 'responsive',
  381. label: lang.responsive,
  382. items: [ [ lang.ratio16by9, '16by9' ], [ lang.ratio4by3, '4by3' ] ],
  383. commit : commitValue,
  384. setup : loadValue
  385. }
  386. ]
  387. },
  388. {
  389. id: '360',
  390. label: '360°',
  391. elements: [
  392. {
  393. type : 'html',
  394. html : lang.html360
  395. },
  396. {
  397. type : 'checkbox',
  398. id : '360video',
  399. label: lang.video360,
  400. commit : commitValue,
  401. setup : loadValue
  402. },
  403. {
  404. type : 'checkbox',
  405. id : '360videostereo',
  406. label : lang.video360stereo,
  407. 'default': 'checked',
  408. commit : commitValue,
  409. setup : loadValue
  410. }
  411. ]
  412. }
  413. ]
  414. };
  415. } );