video.js 9.6 KB

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