video.js 17 KB

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