Index: branches/js2-work/phase3/js/mwEmbed/includes/jsAutoloadLocalClasses.php |
— | — | @@ -3,26 +3,74 @@ |
4 | 4 | if ( !defined( 'MEDIAWIKI' ) ) die( 1 ); |
5 | 5 | |
6 | 6 | global $wgJSAutoloadLocalClasses, $wgMwEmbedDirectory; |
| 7 | +global $wgJSModuleList; |
7 | 8 | |
| 9 | +// NOTE this is growing in complexity and globals sloppiness |
| 10 | +// we should refactor as a class with some static methods |
| 11 | + |
| 12 | +//Initialize $wgJSModuleList |
| 13 | +$wgJSModuleList = array(); |
| 14 | + |
| 15 | +//Initialize $wgLoaderJs |
| 16 | +$wgMwEmbedLoaderJs = ''; |
| 17 | + |
8 | 18 | /** |
9 | | - * loads javascript class name paths from mwEmbed.js |
| 19 | + * Loads javascript class name paths from mwEmbed.js |
10 | 20 | */ |
11 | 21 | function wfLoadMwEmbedClassPaths ( ) { |
12 | | - global $wgMwEmbedDirectory; |
| 22 | + global $wgMwEmbedDirectory, $wgJSModuleList, $wgMwEmbedLoaderJs; |
| 23 | + //Set up the replace key: |
| 24 | + $ClassReplaceKey = '/mw\.addClassFilePaths\s*\(\s*{(.*)}\s*\)\s*\;/siU'; |
13 | 25 | // Load classes from mwEmbed.js |
14 | 26 | if ( is_file( $wgMwEmbedDirectory . 'mwEmbed.js' ) ) { |
15 | | - |
16 | | - // NOTE: ideally we could cache this json var and or update it php side per svn release |
17 | 27 | // Read the file: |
18 | 28 | $file_content = file_get_contents( $wgMwEmbedDirectory . 'mwEmbed.js' ); |
19 | 29 | // Call jsClassPathLoader() for each lcPaths() call in the JS source |
20 | 30 | $replace_test = preg_replace_callback( |
21 | | - '/mw\.addClassFilePaths\s*\(\s*{(.*)}\s*\)\s*/siU', |
| 31 | + $ClassReplaceKey, |
22 | 32 | 'wfClassPathLoader', |
23 | 33 | $file_content |
24 | 34 | ); |
| 35 | + |
| 36 | + // Get the list of enabled modules into $wgJSModuleList |
| 37 | + $replace_test = preg_replace_callback( |
| 38 | + '/mwEnabledModuleList\s*\=\s*\[(.*)\]/siU', |
| 39 | + 'wfBuildModuleList', |
| 40 | + $file_content |
| 41 | + ); |
| 42 | + |
| 43 | + // Get all the classes from the loader files: |
| 44 | + foreach( $wgJSModuleList as $na => $moduleName){ |
| 45 | + $file_content = file_get_contents( |
| 46 | + $wgMwEmbedDirectory . 'modules/' . $moduleName . '/loader.js' |
| 47 | + ); |
| 48 | + // Add the mwEmbed loader js to its global collector: |
| 49 | + $wgMwEmbedLoaderJs .= $file_content; |
| 50 | + |
| 51 | + $replace_test.= preg_replace_callback( |
| 52 | + $ClassReplaceKey, |
| 53 | + 'wfClassPathLoader', |
| 54 | + $file_content |
| 55 | + ); |
| 56 | + } |
25 | 57 | } |
26 | 58 | } |
| 59 | +function wfBuildModuleList( $jsvar ){ |
| 60 | + global $wgMwEmbedDirectory, $wgJSModuleList; |
| 61 | + if(! isset( $jsvar[1] )){ |
| 62 | + return false; |
| 63 | + } |
| 64 | + $moduleSet = explode(',', $jsvar[1] ); |
| 65 | + |
| 66 | + foreach( $moduleSet as $na => $module ){ |
| 67 | + $moduleName = str_replace( array( '../', '\'', '"'), '', trim( $module )); |
| 68 | + // Check if there is there are module loader files |
| 69 | + if( is_file( $wgMwEmbedDirectory . 'modules/' . $moduleName . '/loader.js' )){ |
| 70 | + array_push( $wgJSModuleList, $moduleName ); |
| 71 | + } |
| 72 | + } |
| 73 | + return ''; |
| 74 | +} |
27 | 75 | function wfClassPathLoader( $jvar ) { |
28 | 76 | global $wgJSAutoloadLocalClasses, $wgMwEmbedDirectory; |
29 | 77 | if ( !isset( $jvar[1] ) ) |
Index: branches/js2-work/phase3/js/mwEmbed/modules/TimedText/mvTimeTextEdit.js |
— | — | @@ -1,158 +0,0 @@ |
2 | | -/* |
3 | | - * JS2-style mvTimedTextEdit.js |
4 | | - */ |
5 | | - |
6 | | -// Setup configuration vars (if not set already) |
7 | | -if ( !mwAddMediaConfig ) |
8 | | - var mwAddMediaConfig = { }; |
9 | | - |
10 | | -var mvTimeTextEdit = { }; |
11 | | - |
12 | | -mw.addMessages( { |
13 | | - "mwe-upload-subs-file" : "Upload subtitle", |
14 | | - "mwe-add-subs-file-title" : "Select subtitle to upload", |
15 | | - "mwe-error-only-srt" : "You can only upload srt files.", |
16 | | - "mwe-watch-video" : "Watch video", |
17 | | - "mwe-select-other-language" : "Select another language", |
18 | | - "mwe-saving" : "saving..." |
19 | | -} ) |
20 | | - |
21 | | - |
22 | | -mw.ready( function() { |
23 | | - function getSubtitle( f ) { |
24 | | - var name = f.files[0].name; |
25 | | - var srtData = f.files[0].getAsBinary(); |
26 | | - srtData = srtData.replace( '\r\n', '\n' ); |
27 | | - return srtData; |
28 | | - } |
29 | | - function getVideoTitle() { |
30 | | - var videoTitle = wgPageName.split( '.' ); |
31 | | - videoTitle.pop(); |
32 | | - videoTitle.pop(); |
33 | | - videoTitle = videoTitle.join( '.' ).replace( 'TimedText:', 'File:' ); |
34 | | - return videoTitle; |
35 | | - } |
36 | | - function uploadSubtitles() { |
37 | | - var request = { |
38 | | - 'meta' : 'siteinfo', |
39 | | - 'siprop' : 'languages' |
40 | | - }; |
41 | | - mw.getJSON( request, function( langDataRaw ) { |
42 | | - var apprefix = wgTitle.split( '.' ); |
43 | | - apprefix.pop(); |
44 | | - apprefix.pop(); |
45 | | - apprefix = apprefix.join( '.' ); |
46 | | - var request = { |
47 | | - 'list' : 'allpages', |
48 | | - 'apprefix' : apprefix |
49 | | - }; |
50 | | - mw.getJSON(request, function( subData ) { |
51 | | - var availableSubtitles = { }; |
52 | | - for ( var i in subData.query.allpages ) { |
53 | | - var subPage = subData.query.allpages[i]; |
54 | | - var langKey = subPage.title.split( '.' ); |
55 | | - var extension = langKey.pop(); |
56 | | - langKey = langKey.pop(); |
57 | | - availableSubtitles[langKey] = subPage.title; |
58 | | - } |
59 | | - var langData = { }; |
60 | | - var languageSelect = '<select id="timed_text_language">'; |
61 | | - |
62 | | - var lagRaw = langDataRaw.query.languages; |
63 | | - for ( var j in lagRaw ) { |
64 | | - var code = lagRaw[j].code; |
65 | | - var language = lagRaw[j]['*']; |
66 | | - langData[ code ] = language; |
67 | | - languageSelect += '<option value="' + code + '">'; |
68 | | - if ( availableSubtitles[code] ) { |
69 | | - languageSelect += language + '(' + code + ') +'; |
70 | | - } else { |
71 | | - languageSelect += language + '(' + code + ') -'; |
72 | | - } |
73 | | - languageSelect += '</option>'; |
74 | | - } |
75 | | - languageSelect += '/</select>'; |
76 | | - var cBtn = { }; |
77 | | - cBtn[ gM( 'mwe-cancel' ) ] = function() { |
78 | | - $j( this ).dialog( 'close' ); |
79 | | - } |
80 | | - cBtn[ gM( 'mwe-ok' ) ] = function() { |
81 | | - // get language from form |
82 | | - langKey = $j( '#timed_text_language' ).val(); |
83 | | - var title = wgPageName.split( '.' ); |
84 | | - title.pop(); |
85 | | - title.pop(); |
86 | | - title = title.join( '.' ) + '.' + langKey + '.srt'; |
87 | | - |
88 | | - var file = $j( '#timed_text_file_upload' ); |
89 | | - if ( !file[0].files[0] ) { |
90 | | - // no file to upload just jump to the lang key: |
91 | | - document.location.href = wgArticlePath.replace( '/$1', '?title=' + title + '&action=edit' ); |
92 | | - return ; |
93 | | - } |
94 | | - var langKey = file[0].files[0].name.split( '.' ); |
95 | | - var extension = langKey.pop(); |
96 | | - langKey = langKey.pop(); |
97 | | - var mimeTypes = { |
98 | | - 'srt': 'text/x-srt', |
99 | | - 'cmml': 'text/cmml' |
100 | | - } |
101 | | - if ( !mimeTypes[ extension ] ) { |
102 | | - mw.log( 'Error: unknown extension:' + extension ); |
103 | | - } |
104 | | - |
105 | | - |
106 | | - if ( extension == "srt" ) { |
107 | | - var srt = getSubtitle( file[0] ); |
108 | | - $j( this ).text( gM( 'mwe-saving' ) ); |
109 | | - $j( '.ui-dialog-buttonpane' ).remove(); |
110 | | - |
111 | | - var editToken = $j( 'input[name=wpEditToken]' ).val(); |
112 | | - var request = { |
113 | | - 'action' : 'edit', |
114 | | - 'title' : title, |
115 | | - 'text' : srt, |
116 | | - 'token': editToken |
117 | | - }; |
118 | | - mw.getJSON( request, function( dialog ) { |
119 | | - return function( result ) { |
120 | | - document.location.href = wgArticlePath.replace( '/$1', '?title=' + title + '&action=edit' ); |
121 | | - $j( dialog ).dialog( 'close' ); |
122 | | - } |
123 | | - }( this ) ); |
124 | | - } else { |
125 | | - $j( this ).html( gM( "mwe-error-only-srt" ) ); |
126 | | - } |
127 | | - } |
128 | | - $j.addDialog( gM( "mwe-add-subs-file-title" ), |
129 | | - '<input type="file" id="timed_text_file_upload"></input><br />' + languageSelect, |
130 | | - cBtn ); |
131 | | - $j( '#timed_text_file_upload' ).change( function( ev ) { |
132 | | - if ( this.files[0] ) { |
133 | | - var langKey = this.files[0].name.split( '.' ); |
134 | | - var extension = langKey.pop(); |
135 | | - langKey = langKey.pop(); |
136 | | - $j( '#timed_text_language' ).val( langKey ); |
137 | | - } |
138 | | - } ); |
139 | | - } ); |
140 | | - } ); |
141 | | - } |
142 | | - var tselect = ( $j( '#wikiEditor-ui-top' ).length != 0 ) ? '#wikiEditor-ui-top':'#toolbar'; |
143 | | - $j( tselect ).hide(); |
144 | | - var ttoolbar = $j( '<div>' ); |
145 | | - $j( tselect ).after( ttoolbar ); |
146 | | - |
147 | | - var button = $j( '<button>' ); |
148 | | - button.click( uploadSubtitles ) |
149 | | - button.text( gM( "mwe-upload-subs-file" ) ); |
150 | | - ttoolbar.append( button ); |
151 | | - ttoolbar.append( ' ' ); |
152 | | - |
153 | | - var button = $j( '<button>' ); |
154 | | - button.click( function() { document.location.href = wgArticlePath.replace( '$1', getVideoTitle() ); } ) |
155 | | - button.text( gM( "mwe-watch-video" ) ); |
156 | | - ttoolbar.append( button ); |
157 | | - |
158 | | -} ); |
159 | | - |
Index: branches/js2-work/phase3/js/mwEmbed/modules/TimedText/loader.js |
— | — | @@ -3,6 +3,7 @@ |
4 | 4 | */ |
5 | 5 | mw.addClassFilePaths( { |
6 | 6 | "mw.TimedText" : "modules/TimedText/mw.TimedText.js", |
| 7 | + "mw.TimedTextEdit" : "modules/TimedText/mw.TimedTextEdit.js", |
7 | 8 | "$j.fn.menu" : "modules/TimedText/jquery.menu.js" |
8 | 9 | }); |
9 | 10 | |
Index: branches/js2-work/phase3/js/mwEmbed/modules/TimedText/mw.TimedText.js |
— | — | @@ -19,6 +19,8 @@ |
20 | 20 | mw.addMessages( { |
21 | 21 | "mwe-back-btn" : "Back", |
22 | 22 | "mwe-chose-text" : "Chose text", |
| 23 | + "mwe-add-timed-text" : "Add timed text", |
| 24 | + "mwe-loading-text-edit" : "Loading timed text editor", |
23 | 25 | |
24 | 26 | "mwe-search" : "Search clip", |
25 | 27 | |
— | — | @@ -74,7 +76,7 @@ |
75 | 77 | }, |
76 | 78 | |
77 | 79 | /** |
78 | | - * The list of enabled sources |
| 80 | + * The list of enabled sources |
79 | 81 | */ |
80 | 82 | enabledSources: [ ], |
81 | 83 | |
— | — | @@ -107,8 +109,16 @@ |
108 | 110 | "LIN", |
109 | 111 | "CUE" |
110 | 112 | ], |
111 | | - |
| 113 | + |
112 | 114 | /** |
| 115 | + * Timed text extension to mime map |
| 116 | + */ |
| 117 | + timedTextExtMime: { |
| 118 | + 'srt': 'text/x-srt', |
| 119 | + 'cmml': 'text/cmml' |
| 120 | + }, |
| 121 | + |
| 122 | + /** |
113 | 123 | * Set of timedText providers |
114 | 124 | */ |
115 | 125 | timedTextProviders:{ |
— | — | @@ -154,6 +164,7 @@ |
155 | 165 | /** |
156 | 166 | * Show the timed text menu |
157 | 167 | * @param {Object} target to display the menu |
| 168 | + * @param {Bollean} autoShow If the menu should be displayed |
158 | 169 | */ |
159 | 170 | bindMenu: function( target , autoShow ){ |
160 | 171 | var _this = this; |
— | — | @@ -193,8 +204,7 @@ |
194 | 205 | |
195 | 206 | for( var i in this.enabledSources ) { |
196 | 207 | var source = this.enabledSources[ i ]; |
197 | | - this.updateSourceDisplay( source, currentTime ); |
198 | | - |
| 208 | + this.updateSourceDisplay( source, currentTime ); |
199 | 209 | } |
200 | 210 | }, |
201 | 211 | |
— | — | @@ -204,12 +214,14 @@ |
205 | 215 | * @param {Function} callback Function to call once text sources are loaded |
206 | 216 | */ |
207 | 217 | loadTextSources: function( callback ){ |
| 218 | + var _this = this; |
| 219 | + this.textSources = [ ]; |
208 | 220 | // Get local reference to all timed text sources: ( text/xml, text/x-srt etc ) |
209 | 221 | var inlineSources = this.embedPlayer.mediaElement.getSources( 'text' ); |
210 | 222 | //add all the sources to textSources |
211 | 223 | for( var i in inlineSources ){ |
212 | 224 | // make a new textSource: |
213 | | - var source = new textSource( inlineSources[i] ); |
| 225 | + var source = new TextSource( inlineSources[i] ); |
214 | 226 | this.textSources.push( source ); |
215 | 227 | } |
216 | 228 | |
— | — | @@ -221,22 +233,39 @@ |
222 | 234 | callback(); |
223 | 235 | return ; |
224 | 236 | } |
225 | | - // Else try to get sources from text provider: |
| 237 | + // Try to get sources from text provider: |
226 | 238 | var provider = this.timedTextProviders[ textProviderId ]; |
227 | 239 | var assetKey = this.embedPlayer.wikiTitleKey; |
228 | 240 | switch( provider.lib ){ |
229 | 241 | case 'mediaWiki': |
230 | 242 | this.textProvider = new mw.MediaWikiTextProvider( { |
231 | | - api_url: provider.api_url |
| 243 | + 'provider_id' : textProviderId, |
| 244 | + 'api_url': provider.api_url, |
| 245 | + 'embedPlayer': this.embedPlayer |
232 | 246 | }); |
233 | 247 | break; |
234 | | - } |
| 248 | + } |
235 | 249 | // Load the textProvider sources |
236 | 250 | this.textProvider.loadSources( assetKey, function( textSources ){ |
237 | | - for( var i in textSources ){ |
238 | | - var source = textSources[ i ]; |
239 | | - this.textSources.push( source ); |
240 | | - } |
| 251 | + for( var i in textSources ){ |
| 252 | + var textSource = textSources[ i ]; |
| 253 | + // Try to insert the itext source: |
| 254 | + var textElm = document.createElement( 'itext' ); |
| 255 | + $j( textElm ).attr( { |
| 256 | + 'category' : 'SUB', |
| 257 | + 'lang' : textSource.lang, |
| 258 | + 'type' : _this.timedTextExtMime[ textSource.extension ], |
| 259 | + 'titleKey' : textSource.titleKey |
| 260 | + } ); |
| 261 | + //debugger; |
| 262 | + // Add the sources to the parent embedPlayer |
| 263 | + // ( in case other interfaces want to access them ) |
| 264 | + var embedSource = _this.embedPlayer.mediaElement.tryAddSource( textElm ); |
| 265 | + // Get a "textSource" object: |
| 266 | + var source = new TextSource( embedSource, _this.textProvider); |
| 267 | + _this.textSources.push( source ); |
| 268 | + } |
| 269 | + // All sources loaded run callback: |
241 | 270 | callback(); |
242 | 271 | } ); |
243 | 272 | }, |
— | — | @@ -329,12 +358,24 @@ |
330 | 359 | var _this = this; |
331 | 360 | // Build the source list menu item: |
332 | 361 | |
333 | | - return $j( '<ul>' ).append( |
334 | | - // Chose language option: |
335 | | - _this.getLi( gM( 'mwe-chose-text') ).append( |
336 | | - _this.getLanguageMenu() |
337 | | - ), |
| 362 | + $menu = $j( '<ul>' ); |
| 363 | + // Chouse text menu item ( if there are sources) |
| 364 | + if( _this.textSources.length != 0 ){ |
| 365 | + $menu.append( |
| 366 | + _this.getLi( gM( 'mwe-chose-text') ).append( |
| 367 | + _this.getLanguageMenu() |
| 368 | + ) |
| 369 | + ) |
| 370 | + }else{ |
| 371 | + // Put in the "Make Transcript" link |
| 372 | + $menu.append( |
| 373 | + _this.getLi( gM( 'mwe-add-timed-text'), 'script', function(){ |
| 374 | + _this.showTimedTextEditUI( 'add' ); |
| 375 | + } ) |
| 376 | + ); |
338 | 377 | |
| 378 | + } |
| 379 | + $menu.append( |
339 | 380 | // Layout Menu option |
340 | 381 | _this.getLi( gM( 'mwe-layout' ) ).append( |
341 | 382 | _this.getLayoutMenu() |
— | — | @@ -343,9 +384,27 @@ |
344 | 385 | // Search Menu option |
345 | 386 | _this.getLi( gM('mwe-search'), 'search') |
346 | 387 | ); |
| 388 | + return $menu; |
347 | 389 | }, |
348 | 390 | |
349 | 391 | /** |
| 392 | + * Shows the timed text edit ui |
| 393 | + */ |
| 394 | + |
| 395 | + showTimedTextEditUI: function( mode ){ |
| 396 | + var _this = this; |
| 397 | + // Show a loader: |
| 398 | + $j.addLoaderDialog( gM( 'mwe-loading-text-edit' )); |
| 399 | + // Load the timedText edit interface |
| 400 | + mw.load( 'mw.TimedTextEdit', function(){ |
| 401 | + $j.closeLoaderDialog(); |
| 402 | + if( ! _this.editText ){ |
| 403 | + _this.editText = new mw.TimedTextEdit(); |
| 404 | + } |
| 405 | + _this.editText.showUI(); |
| 406 | + }) |
| 407 | + }, |
| 408 | + /** |
350 | 409 | * Utility function to assist in menu build out: |
351 | 410 | * Get menu line item (li) html: <li><a> msgKey </a></li> |
352 | 411 | * |
— | — | @@ -370,7 +429,7 @@ |
371 | 430 | |
372 | 431 | if( source.lang ){ |
373 | 432 | var langKey = source.lang.toLowerCase(); |
374 | | - mw.languages[ langKey ]; |
| 433 | + _this.getLanguageName ( langKey ); |
375 | 434 | return this.getLi( |
376 | 435 | gM('mwe-key-language', [langKey, unescape( mw.languages[ source.lang ] ) ] ), |
377 | 436 | sourceIcon, |
— | — | @@ -398,6 +457,15 @@ |
399 | 458 | $li.find( 'a' ).append( $j('<span>').text( string ) ); |
400 | 459 | return $li; |
401 | 460 | }, |
| 461 | + /** |
| 462 | + * Get lagnuage name from language key |
| 463 | + */ |
| 464 | + getLanguageName: function( lang_key ){ |
| 465 | + if( mw.languages[ lang_key ]){ |
| 466 | + return mw.languages[ lang_key ]; |
| 467 | + } |
| 468 | + return false |
| 469 | + }, |
402 | 470 | |
403 | 471 | /** |
404 | 472 | * Builds and returns the "layout" menu |
— | — | @@ -463,7 +531,7 @@ |
464 | 532 | */ |
465 | 533 | selectTextSource: function( source ){ |
466 | 534 | var _this = this; |
467 | | - mw.log(" select source: " + source.lang ); |
| 535 | + mw.log(" select source: " + source.lang ); |
468 | 536 | |
469 | 537 | // Update the config language if the source includes language |
470 | 538 | if( source.lang ) |
— | — | @@ -531,20 +599,33 @@ |
532 | 600 | sourcesWithoutCategory.push( _this.getLiSource( source ) ); |
533 | 601 | } |
534 | 602 | } |
535 | | - var $langMenu = $j('<ul>'); |
536 | | - for(var catKey in catSourceList){ |
537 | | - $catChildren = $j('<ul>'); |
538 | | - for(var i in catSourceList[ catKey ]){ |
539 | | - $catChildren.append( |
540 | | - catSourceList[ catKey ][i] |
541 | | - ) |
| 603 | + var $langMenu = $j('<ul>'); |
| 604 | + // Check if we have multiple categories ( if not just list them under the parent menu item) |
| 605 | + if( catSourceList.length > 1 ){ |
| 606 | + for(var catKey in catSourceList){ |
| 607 | + $catChildren = $j('<ul>'); |
| 608 | + for(var i in catSourceList[ catKey ]){ |
| 609 | + $catChildren.append( |
| 610 | + catSourceList[ catKey ][i] |
| 611 | + ) |
| 612 | + } |
| 613 | + // Append a cat menu item for each category list |
| 614 | + $langMenu.append( |
| 615 | + _this.getLi( gM( 'mwe-textcat-' + catKey.toLowerCase() ) ).append( |
| 616 | + $catChildren |
| 617 | + ) |
| 618 | + ); |
542 | 619 | } |
543 | | - $langMenu.append( |
544 | | - _this.getLi( gM( 'mwe-textcat-' + catKey.toLowerCase() ) ).append( |
545 | | - $catChildren |
546 | | - ) |
547 | | - ); |
| 620 | + } else { |
| 621 | + for(var catKey in catSourceList){ |
| 622 | + for(var i in catSourceList[ catKey ]){ |
| 623 | + $langMenu.append( |
| 624 | + catSourceList[ catKey ][i] |
| 625 | + ) |
| 626 | + } |
| 627 | + } |
548 | 628 | } |
| 629 | + |
549 | 630 | for(var i in sourcesWithoutCategory){ |
550 | 631 | $langMenu.append( sourcesWithoutCategory[i] ) |
551 | 632 | } |
— | — | @@ -566,8 +647,7 @@ |
567 | 648 | mw.log( 'updateTextDisplay: ' + text ); |
568 | 649 | |
569 | 650 | var $player = $j( '#' + this.embedPlayer.id); |
570 | | - var $textTarget = $player.find( '.itext_' + source.category + ' span' ); |
571 | | - |
| 651 | + var $textTarget = $player.find( '.itext_' + source.category + ' span' ); |
572 | 652 | // If we are missing the target add it: |
573 | 653 | if( $textTarget.length == 0){ |
574 | 654 | this.addItextDiv( source.category ) |
— | — | @@ -650,10 +730,10 @@ |
651 | 731 | * TextSource object extends a base mediaSource object |
652 | 732 | * with some timedText features |
653 | 733 | */ |
654 | | - var textSource = function( source ){ |
655 | | - return this.init( source ); |
| 734 | + TextSource = function( source , textProvider){ |
| 735 | + return this.init( source, textProvider ); |
656 | 736 | } |
657 | | - textSource.prototype = { |
| 737 | + TextSource.prototype = { |
658 | 738 | |
659 | 739 | //The load state: |
660 | 740 | loaded: false, |
— | — | @@ -670,7 +750,7 @@ |
671 | 751 | * @constructor Inherits mediaSource from embedPlayer |
672 | 752 | * @param {source} Base source element |
673 | 753 | */ |
674 | | - init: function( source ){ |
| 754 | + init: function( source , textProvider){ |
675 | 755 | for( var i in source){ |
676 | 756 | this[i] = source[i]; |
677 | 757 | } |
— | — | @@ -678,6 +758,10 @@ |
679 | 759 | if( ! this.category ){ |
680 | 760 | this.category = 'SUB'; |
681 | 761 | } |
| 762 | + //Set the textProvider if provided |
| 763 | + if( textProvider ){ |
| 764 | + this.textProvider = textProvider; |
| 765 | + } |
682 | 766 | }, |
683 | 767 | |
684 | 768 | /** |
— | — | @@ -686,6 +770,7 @@ |
687 | 771 | */ |
688 | 772 | load: function( callback ){ |
689 | 773 | var _this = this; |
| 774 | + |
690 | 775 | //check if its already loaded: |
691 | 776 | if( _this.loaded ){ |
692 | 777 | if( callback ){ |
— | — | @@ -700,6 +785,9 @@ |
701 | 786 | case 'text/cmml': |
702 | 787 | var handler = parseCMML; |
703 | 788 | break; |
| 789 | + case 'text/html': |
| 790 | + var handler = parseSrtHTML; |
| 791 | + break; |
704 | 792 | default: |
705 | 793 | var hanlder = null; |
706 | 794 | break; |
— | — | @@ -707,22 +795,38 @@ |
708 | 796 | if( !handler ){ |
709 | 797 | mw.log("Error: no handler for type: " + this.getMIMEType() ); |
710 | 798 | return ; |
| 799 | + } |
| 800 | + // Try to load src via src attr: |
| 801 | + if( this.getSrc() ){ |
| 802 | + // Issue the load request ( if we can ) |
| 803 | + if ( mw.parseUri( document.URL ).host != mw.parseUri( this.getSrc() ).host ){ |
| 804 | + mw.log("Error can't load non-json src via jsonp:" + this.getSrc() ) |
| 805 | + return ; |
| 806 | + } |
| 807 | + $j.get( this.getSrc(), function( data ){ |
| 808 | + // Parse and load captions: |
| 809 | + _this.captions = handler( data ); |
| 810 | + // Update the loaded state: |
| 811 | + _this.loaded = true; |
| 812 | + if( callback ){ |
| 813 | + callback(); |
| 814 | + } |
| 815 | + }, 'text' ); |
| 816 | + return ; |
| 817 | + } |
| 818 | + |
| 819 | + // Try to load src via provider: |
| 820 | + if( this.textProvider && this.titleKey ){ |
| 821 | + this.textProvider.loadTitleKey( this.titleKey, function( data ){ |
| 822 | + if( data ){ |
| 823 | + _this.captions = handler( data ); |
| 824 | + } |
| 825 | + if( callback ){ |
| 826 | + callback(); |
| 827 | + } |
| 828 | + return ; |
| 829 | + }); |
711 | 830 | } |
712 | | - // Issue the load request ( if we can ) |
713 | | - //if ( mw.parseUri( document.URL ).host != mw.parseUri( this.getSrc() ).host ){ |
714 | | - // mw.log("Error can't load non-json src via jsonp:" + this.getSrc() ) |
715 | | - // return ; |
716 | | - //} |
717 | | - |
718 | | - $j.get( this.getSrc(), function( data ){ |
719 | | - // Parse and load captions: |
720 | | - _this.captions = handler( data ); |
721 | | - // Update the loaded state: |
722 | | - _this.loaded = true; |
723 | | - if( callback ){ |
724 | | - callback(); |
725 | | - } |
726 | | - }, 'text' ); |
727 | 831 | }, |
728 | 832 | |
729 | 833 | /** |
— | — | @@ -858,27 +962,66 @@ |
859 | 963 | } |
860 | 964 | |
861 | 965 | */ |
862 | | - |
| 966 | + var default_textProvider_attr = [ |
| 967 | + 'api_url', |
| 968 | + 'provider_id', |
| 969 | + 'timed_text_NS', |
| 970 | + 'embedPlayer' |
| 971 | + ]; |
| 972 | + |
863 | 973 | mw.MediaWikiTextProvider = function( options ){ |
864 | 974 | this.init( options ) |
865 | 975 | } |
866 | 976 | mw.MediaWikiTextProvider.prototype = { |
| 977 | + |
| 978 | + // The api url: |
867 | 979 | api_url: null, |
868 | | - timedTextNS: null, |
| 980 | + |
| 981 | + // The timed text namespace |
| 982 | + timed_text_NS: null, |
| 983 | + |
869 | 984 | /** |
870 | 985 | * @constructor |
871 | 986 | * @param {Object} options Set of options for the provider |
872 | 987 | */ |
873 | 988 | init: function( options ){ |
874 | | - //Set the api url: |
875 | | - if( options.api_url ){ |
876 | | - this.api_url = options.api_url |
877 | | - } |
878 | | - if( options.timedTextNS ){ |
879 | | - this.timedTextNS = options.timedTextNS |
| 989 | + for(var i in default_textProvider_attr){ |
| 990 | + var attr = default_textProvider_attr[ i ]; |
| 991 | + if( options[ attr ] ) |
| 992 | + this[ attr ] = options[ attr ]; |
| 993 | + |
880 | 994 | } |
881 | 995 | }, |
882 | 996 | |
| 997 | + /** |
| 998 | + * Loads a single text source by titleKey |
| 999 | + * @param {titleKey} |
| 1000 | + */ |
| 1001 | + loadTitleKey: function( titleKey, callback ){ |
| 1002 | + var request = { |
| 1003 | + 'titles': titleKey, |
| 1004 | + 'prop':'revisions', |
| 1005 | + 'rvprop':'content' |
| 1006 | + }; |
| 1007 | + mw.getJSON( this.api_url, request, function( data ){ |
| 1008 | + if ( data && data.query && data.query.pages ) { |
| 1009 | + for ( var i in data.query.pages ) { |
| 1010 | + var page = data.query.pages[i]; |
| 1011 | + if ( page.revisions ) { |
| 1012 | + for ( var j in page.revisions ) { |
| 1013 | + if ( page.revisions[j]['*'] ) { |
| 1014 | + callback( page.revisions[j]['*'] ); |
| 1015 | + return ; |
| 1016 | + } |
| 1017 | + } |
| 1018 | + } |
| 1019 | + } |
| 1020 | + } |
| 1021 | + mw.log("Error: could not load:" + titleKey); |
| 1022 | + callback( false ); |
| 1023 | + } ); |
| 1024 | + }, |
| 1025 | + |
883 | 1026 | /** |
884 | 1027 | * Loads all available source for a given assetKey |
885 | 1028 | * |
— | — | @@ -886,23 +1029,26 @@ |
887 | 1030 | */ |
888 | 1031 | loadSources: function( assetKey, callback ){ |
889 | 1032 | var request = {}; |
890 | | - this.getSubPages( assetKey, function( subPages ){ |
891 | | - mw.log(' got sub pages... '); |
892 | | - if( !subData.query.allpages ){ |
| 1033 | + var _this = this; |
| 1034 | + this.getSourcePages( assetKey, function( sourcePages ){ |
| 1035 | + mw.log(' got sub pages... '); |
| 1036 | + if( ! sourcePages.query.allpages ){ |
| 1037 | + //Check if a shared asset |
893 | 1038 | mw.log( 'no subtitle pages found'); |
894 | 1039 | callback(); |
895 | 1040 | return ; |
896 | 1041 | } |
897 | | - _this.getSources( subPages ) |
898 | | - } ); |
| 1042 | + // We have sources put them into the player |
| 1043 | + callback( _this.getSources( sourcePages ) ); |
| 1044 | + } ); |
899 | 1045 | }, |
900 | 1046 | |
901 | | - /* |
| 1047 | + /** |
902 | 1048 | * Get the subtitle pages |
903 | 1049 | * @param {String} titleKey Title to get subtitles for |
904 | 1050 | * @param {Function} callback Function to call once NS subs are grabbed |
905 | 1051 | */ |
906 | | - getSubPages: function( titleKey, callback ){ |
| 1052 | + getSourcePages: function( titleKey, callback ){ |
907 | 1053 | var _this = this; |
908 | 1054 | var request = { |
909 | 1055 | 'list' : 'allpages', |
— | — | @@ -910,88 +1056,82 @@ |
911 | 1057 | 'apnamespace' : this.getTimedTextNS(), |
912 | 1058 | 'prop':'revisions' |
913 | 1059 | }; |
914 | | - mw.getJSON( this.api_url, request, function( subPages ) { |
915 | | - if ( subPages.error && subPages.error.code == 'apunknown_apnamespace' ) { |
| 1060 | + mw.getJSON( this.api_url, request, function( sourcePages ) { |
| 1061 | + if ( sourcePages.error && sourcePages.error.code == 'apunknown_apnamespace' ) { |
916 | 1062 | var request = { |
917 | 1063 | 'list' : 'allpages', |
918 | 1064 | 'apprefix' : _this.getCanonicalTimedTextNS() + ':' + _this.pe.wikiTitleKey |
919 | 1065 | }; |
920 | | - mw.getJSON( apiUrl, request, function( subData ) { |
921 | | - callback( subPages ) |
| 1066 | + mw.getJSON( apiUrl, request, function( sourcePages ) { |
| 1067 | + callback( sourcePages ) |
922 | 1068 | } ); |
923 | 1069 | } else { |
924 | | - callback( subPages ); |
| 1070 | + callback( sourcePages ); |
925 | 1071 | } |
926 | 1072 | } ); |
927 | 1073 | }, |
| 1074 | + |
928 | 1075 | /** |
929 | | - * Return the namespace (if not encoded on the page return default |
| 1076 | + * get the sources from sourcePages data object |
| 1077 | + * Put valid sources into the embedPlayer |
930 | 1078 | */ |
931 | | - getTimedTextNS: function(){ |
932 | | - if( this.timedTextNS ) |
933 | | - return this.timedTextNS; |
934 | | - if ( typeof wgNamespaceIds != 'undefined' && wgNamespaceIds['timedtext'] ) { |
935 | | - this.timedTextNS = wgNamespaceIds['timedtext']; |
936 | | - }else{ |
937 | | - //default value is 102 ( probably should store this elsewhere ) |
938 | | - this.timedTextNS = 102; |
939 | | - } |
940 | | - return this.timedTextNS; |
941 | | - }, |
942 | | - /* |
943 | | - * Return the namespace text |
944 | | - */ |
945 | | - getCanonicalTimedTextNS: function(){ |
946 | | - return 'TimedText'; |
947 | | - }, |
948 | | - /** |
949 | | - * Populate the sources |
950 | | - */ |
951 | | - getSources: function( subData ) { |
| 1079 | + getSources: function( sourcePages ) { |
952 | 1080 | var _this = this; |
953 | 1081 | // look for text tracks: |
954 | 1082 | var foundTextTracks = false; |
955 | | - |
956 | | - for ( var i in subData.query.allpages ) { |
| 1083 | + var sources = []; |
| 1084 | + for ( var i in sourcePages.query.allpages ) { |
957 | 1085 | |
958 | | - var subPage = subData.query.allpages[i]; |
| 1086 | + var subPage = sourcePages.query.allpages[i]; |
959 | 1087 | var langKey = subPage.title.split( '.' ); |
960 | 1088 | var extension = langKey.pop(); |
961 | 1089 | langKey = langKey.pop(); |
962 | | - |
963 | | - if ( ! _this.suportedMime[ extension ] ) { |
964 | | - mw.log( 'Error: unknown extension:' + extension ); |
965 | | - continue; |
966 | | - } |
967 | 1090 | |
968 | | - if ( !langData[ langKey] ) { |
969 | | - mw.log( 'Error: langkey:' + langKey + ' not found' ); |
| 1091 | + if ( ! _this.isSuportedLang( langKey ) ) { |
| 1092 | + mw.log( 'Error: langkey:' + langKey + ' not supported' ); |
970 | 1093 | } else { |
971 | | - var textElm = document.createElement( 'text' ); |
972 | | - $j( textElm ).attr( { |
973 | | - 'category' : 'SUB', |
974 | | - 'lang' : langKey, |
975 | | - 'type' : _this.suportedMime[ extension ], |
976 | | - 'title' : langData[ langKey] |
977 | | - } ); |
978 | | - // We use the api since ?action raw on the real title has cache issues |
979 | | - $j( textElm ).attr( { |
980 | | - 'apisrc' : hostPath + '/api.php', |
981 | | - 'titleKey' : subPage.title |
982 | | - } ); |
983 | | - _this.pe.media_element.tryAddSource( textElm ); |
984 | | - foundTextTracks = true; |
| 1094 | + sources.push( { |
| 1095 | + 'extension': extension, |
| 1096 | + 'lang': langKey, |
| 1097 | + 'titleKey': subPage.title |
| 1098 | + } ); |
985 | 1099 | } |
986 | 1100 | } |
987 | | - // after all text loaded (or we have allready checked commons |
988 | | - if ( foundTextTracks || hostPath.indexOf( 'commons.wikimedia' ) !== -1 ) { |
989 | | - // alert('calling getParseTimedText_rowReady '); |
990 | | - _this.getParseTimedText_rowReady(); |
991 | | - } else { |
992 | | - _this.checkSharedRepo(); |
| 1101 | + return sources; |
| 1102 | + }, |
| 1103 | + |
| 1104 | + /** |
| 1105 | + * Return the namespace (if not encoded on the page return default 102 ) |
| 1106 | + */ |
| 1107 | + getTimedTextNS: function(){ |
| 1108 | + if( this.timed_text_NS ) |
| 1109 | + return this.timed_text_NS; |
| 1110 | + if ( typeof wgNamespaceIds != 'undefined' && wgNamespaceIds['timedtext'] ) { |
| 1111 | + this.timed_text_NS = wgNamespaceIds['timedtext']; |
| 1112 | + }else{ |
| 1113 | + //default value is 102 ( probably should store this elsewhere ) |
| 1114 | + this.timed_text_NS = 102; |
993 | 1115 | } |
994 | | - } |
| 1116 | + return this.timed_text_NS; |
| 1117 | + }, |
995 | 1118 | |
| 1119 | + /** |
| 1120 | + * Get the Canonical timed text namespace text |
| 1121 | + */ |
| 1122 | + getCanonicalTimedTextNS: function(){ |
| 1123 | + return 'TimedText'; |
| 1124 | + }, |
| 1125 | + |
| 1126 | + /** |
| 1127 | + * Check if the language is supported |
| 1128 | + */ |
| 1129 | + isSuportedLang: function( lang_key ){ |
| 1130 | + if( mw.languages[ lang_key ]){ |
| 1131 | + return true; |
| 1132 | + } |
| 1133 | + return false; |
| 1134 | + } |
| 1135 | + |
996 | 1136 | } |
997 | 1137 | |
998 | 1138 | |
Index: branches/js2-work/phase3/js/mwEmbed/modules/TimedText/old_mvTimeTextEdit.js |
— | — | @@ -0,0 +1,158 @@ |
| 2 | +/* |
| 3 | + * JS2-style mvTimedTextEdit.js |
| 4 | + */ |
| 5 | + |
| 6 | +// Setup configuration vars (if not set already) |
| 7 | +if ( !mwAddMediaConfig ) |
| 8 | + var mwAddMediaConfig = { }; |
| 9 | + |
| 10 | +var mvTimeTextEdit = { }; |
| 11 | + |
| 12 | +mw.addMessages( { |
| 13 | + "mwe-upload-subs-file" : "Upload subtitle", |
| 14 | + "mwe-add-subs-file-title" : "Select subtitle to upload", |
| 15 | + "mwe-error-only-srt" : "You can only upload srt files.", |
| 16 | + "mwe-watch-video" : "Watch video", |
| 17 | + "mwe-select-other-language" : "Select another language", |
| 18 | + "mwe-saving" : "saving..." |
| 19 | +} ) |
| 20 | + |
| 21 | + |
| 22 | +mw.ready( function() { |
| 23 | + function getSubtitle( f ) { |
| 24 | + var name = f.files[0].name; |
| 25 | + var srtData = f.files[0].getAsBinary(); |
| 26 | + srtData = srtData.replace( '\r\n', '\n' ); |
| 27 | + return srtData; |
| 28 | + } |
| 29 | + function getVideoTitle() { |
| 30 | + var videoTitle = wgPageName.split( '.' ); |
| 31 | + videoTitle.pop(); |
| 32 | + videoTitle.pop(); |
| 33 | + videoTitle = videoTitle.join( '.' ).replace( 'TimedText:', 'File:' ); |
| 34 | + return videoTitle; |
| 35 | + } |
| 36 | + function uploadSubtitles() { |
| 37 | + var request = { |
| 38 | + 'meta' : 'siteinfo', |
| 39 | + 'siprop' : 'languages' |
| 40 | + }; |
| 41 | + mw.getJSON( request, function( langDataRaw ) { |
| 42 | + var apprefix = wgTitle.split( '.' ); |
| 43 | + apprefix.pop(); |
| 44 | + apprefix.pop(); |
| 45 | + apprefix = apprefix.join( '.' ); |
| 46 | + var request = { |
| 47 | + 'list' : 'allpages', |
| 48 | + 'apprefix' : apprefix |
| 49 | + }; |
| 50 | + mw.getJSON(request, function( subData ) { |
| 51 | + var availableSubtitles = { }; |
| 52 | + for ( var i in subData.query.allpages ) { |
| 53 | + var subPage = subData.query.allpages[i]; |
| 54 | + var langKey = subPage.title.split( '.' ); |
| 55 | + var extension = langKey.pop(); |
| 56 | + langKey = langKey.pop(); |
| 57 | + availableSubtitles[langKey] = subPage.title; |
| 58 | + } |
| 59 | + var langData = { }; |
| 60 | + var languageSelect = '<select id="timed_text_language">'; |
| 61 | + |
| 62 | + var lagRaw = langDataRaw.query.languages; |
| 63 | + for ( var j in lagRaw ) { |
| 64 | + var code = lagRaw[j].code; |
| 65 | + var language = lagRaw[j]['*']; |
| 66 | + langData[ code ] = language; |
| 67 | + languageSelect += '<option value="' + code + '">'; |
| 68 | + if ( availableSubtitles[code] ) { |
| 69 | + languageSelect += language + '(' + code + ') +'; |
| 70 | + } else { |
| 71 | + languageSelect += language + '(' + code + ') -'; |
| 72 | + } |
| 73 | + languageSelect += '</option>'; |
| 74 | + } |
| 75 | + languageSelect += '/</select>'; |
| 76 | + var cBtn = { }; |
| 77 | + cBtn[ gM( 'mwe-cancel' ) ] = function() { |
| 78 | + $j( this ).dialog( 'close' ); |
| 79 | + } |
| 80 | + cBtn[ gM( 'mwe-ok' ) ] = function() { |
| 81 | + // get language from form |
| 82 | + langKey = $j( '#timed_text_language' ).val(); |
| 83 | + var title = wgPageName.split( '.' ); |
| 84 | + title.pop(); |
| 85 | + title.pop(); |
| 86 | + title = title.join( '.' ) + '.' + langKey + '.srt'; |
| 87 | + |
| 88 | + var file = $j( '#timed_text_file_upload' ); |
| 89 | + if ( !file[0].files[0] ) { |
| 90 | + // no file to upload just jump to the lang key: |
| 91 | + document.location.href = wgArticlePath.replace( '/$1', '?title=' + title + '&action=edit' ); |
| 92 | + return ; |
| 93 | + } |
| 94 | + var langKey = file[0].files[0].name.split( '.' ); |
| 95 | + var extension = langKey.pop(); |
| 96 | + langKey = langKey.pop(); |
| 97 | + var mimeTypes = { |
| 98 | + 'srt': 'text/x-srt', |
| 99 | + 'cmml': 'text/cmml' |
| 100 | + } |
| 101 | + if ( !mimeTypes[ extension ] ) { |
| 102 | + mw.log( 'Error: unknown extension:' + extension ); |
| 103 | + } |
| 104 | + |
| 105 | + |
| 106 | + if ( extension == "srt" ) { |
| 107 | + var srt = getSubtitle( file[0] ); |
| 108 | + $j( this ).text( gM( 'mwe-saving' ) ); |
| 109 | + $j( '.ui-dialog-buttonpane' ).remove(); |
| 110 | + |
| 111 | + var editToken = $j( 'input[name=wpEditToken]' ).val(); |
| 112 | + var request = { |
| 113 | + 'action' : 'edit', |
| 114 | + 'title' : title, |
| 115 | + 'text' : srt, |
| 116 | + 'token': editToken |
| 117 | + }; |
| 118 | + mw.getJSON( request, function( dialog ) { |
| 119 | + return function( result ) { |
| 120 | + document.location.href = wgArticlePath.replace( '/$1', '?title=' + title + '&action=edit' ); |
| 121 | + $j( dialog ).dialog( 'close' ); |
| 122 | + } |
| 123 | + }( this ) ); |
| 124 | + } else { |
| 125 | + $j( this ).html( gM( "mwe-error-only-srt" ) ); |
| 126 | + } |
| 127 | + } |
| 128 | + $j.addDialog( gM( "mwe-add-subs-file-title" ), |
| 129 | + '<input type="file" id="timed_text_file_upload"></input><br />' + languageSelect, |
| 130 | + cBtn ); |
| 131 | + $j( '#timed_text_file_upload' ).change( function( ev ) { |
| 132 | + if ( this.files[0] ) { |
| 133 | + var langKey = this.files[0].name.split( '.' ); |
| 134 | + var extension = langKey.pop(); |
| 135 | + langKey = langKey.pop(); |
| 136 | + $j( '#timed_text_language' ).val( langKey ); |
| 137 | + } |
| 138 | + } ); |
| 139 | + } ); |
| 140 | + } ); |
| 141 | + } |
| 142 | + var tselect = ( $j( '#wikiEditor-ui-top' ).length != 0 ) ? '#wikiEditor-ui-top':'#toolbar'; |
| 143 | + $j( tselect ).hide(); |
| 144 | + var ttoolbar = $j( '<div>' ); |
| 145 | + $j( tselect ).after( ttoolbar ); |
| 146 | + |
| 147 | + var button = $j( '<button>' ); |
| 148 | + button.click( uploadSubtitles ) |
| 149 | + button.text( gM( "mwe-upload-subs-file" ) ); |
| 150 | + ttoolbar.append( button ); |
| 151 | + ttoolbar.append( ' ' ); |
| 152 | + |
| 153 | + var button = $j( '<button>' ); |
| 154 | + button.click( function() { document.location.href = wgArticlePath.replace( '$1', getVideoTitle() ); } ) |
| 155 | + button.text( gM( "mwe-watch-video" ) ); |
| 156 | + ttoolbar.append( button ); |
| 157 | + |
| 158 | +} ); |
| 159 | + |
Property changes on: branches/js2-work/phase3/js/mwEmbed/modules/TimedText/old_mvTimeTextEdit.js |
___________________________________________________________________ |
Name: svn:eol-style |
1 | 160 | + native |
Index: branches/js2-work/phase3/js/mwEmbed/modules/TimedText/mw.TimedTextEdit.js |
— | — | @@ -0,0 +1,21 @@ |
| 2 | +/** |
| 3 | +* Timed text edit interface based off of participatory culture foundation timed text mockups. |
| 4 | +*/ |
| 5 | + |
| 6 | +mw.TimedTextEdit = function(){ |
| 7 | + return this.init(); |
| 8 | +} |
| 9 | +mw.TimedTextEdit.prototype = { |
| 10 | + /** |
| 11 | + * @constructor |
| 12 | + */ |
| 13 | + init: function(){ |
| 14 | + |
| 15 | + }, |
| 16 | + /** |
| 17 | + * Show the editor UI |
| 18 | + */ |
| 19 | + showUI: function(){ |
| 20 | + |
| 21 | + } |
| 22 | +} |
\ No newline at end of file |
Index: branches/js2-work/phase3/js/mwEmbed/modules/AddMedia/searchLibs/archiveOrgSearch.js |
— | — | @@ -74,7 +74,7 @@ |
75 | 75 | var resource = data.response.docs[resource_id]; |
76 | 76 | var resource = { |
77 | 77 | // @@todo we should add .ogv or oga if video or audio: |
78 | | - 'titleKey' : resource.identifier + '.ogg', |
| 78 | + 'titleKey' : resource.identifier + '.ogv', |
79 | 79 | 'resourceKey': resource.identifier, |
80 | 80 | 'link' : _this.detailsUrl + resource.identifier, |
81 | 81 | 'title' : resource.title, |
Index: branches/js2-work/phase3/js/mwEmbed/modules/AddMedia/loader.js |
— | — | @@ -4,6 +4,7 @@ |
5 | 5 | mw.addMessages( { |
6 | 6 | "mwe-loading-add-media-wiz" : "Loading add media wizard" |
7 | 7 | }); |
| 8 | + |
8 | 9 | // Add class file paths ( From ROOT ) |
9 | 10 | mw.addClassFilePaths( { |
10 | 11 | "$j.fn.dragDropFile" : "modules/AddMedia/jquery.dragDropFile.js", |
Index: branches/js2-work/phase3/js/mwEmbed/modules/AddMedia/mw.RemoteSearchDriver.js |
— | — | @@ -147,8 +147,8 @@ |
148 | 148 | } |
149 | 149 | } |
150 | 150 | |
151 | | - $.addMediaWiz = function( options ){ |
152 | | - $.fn.addMediaWiz ( options, function( amwObj ) { |
| 151 | + $.addMediaWizard = function( options ){ |
| 152 | + $.fn.addMediaWizard ( options, function( amwObj ) { |
153 | 153 | // do the add-media-wizard display |
154 | 154 | amwObj.createUI(); |
155 | 155 | } ) |
Index: branches/js2-work/phase3/js/mwEmbed/modules/EmbedPlayer/mw.EmbedPlayer.js |
— | — | @@ -189,12 +189,6 @@ |
190 | 190 | // media codecs attribute ( if provided ) |
191 | 191 | 'codecs', |
192 | 192 | |
193 | | - // api url ( used for timed text sources ) |
194 | | - 'apisrc', |
195 | | - |
196 | | - // titleKey ( used for api lookups ) |
197 | | - 'titleKey', |
198 | | - |
199 | 193 | // Title string for the source asset |
200 | 194 | 'title', |
201 | 195 | |
— | — | @@ -219,7 +213,16 @@ |
220 | 214 | 'default', |
221 | 215 | |
222 | 216 | // Language key used for subtitle tracks |
223 | | - 'lang' |
| 217 | + 'lang', |
| 218 | + |
| 219 | + // titleKey ( used for api lookups ) |
| 220 | + 'titleKey', |
| 221 | + |
| 222 | + // The provider type ( for what type of api querie to make ) |
| 223 | + 'provider_type', |
| 224 | + |
| 225 | + // The api url for the provider |
| 226 | + 'provider_url' |
224 | 227 | ); |
225 | 228 | |
226 | 229 | // Set the browser player warning flag to true by default ( applies to all players so its not part of attribute defaults above ) |
— | — | @@ -375,9 +378,13 @@ |
376 | 379 | case 'audio': |
377 | 380 | var element_id = element_id; |
378 | 381 | var playerInx = _this.playerList.length; |
379 | | - |
| 382 | + var ranPlayerSwapFlag = false; |
380 | 383 | // Local callback to runPlayer swap once element has metadat |
381 | | - function runPlayerSwap(){ |
| 384 | + function runPlayerSwap(){ |
| 385 | + mw.log("runPlayerSwap" ); |
| 386 | + if( ranPlayerSwapFlag ) |
| 387 | + return ; |
| 388 | + ranPlayerSwapFlag = true; |
382 | 389 | var playerInterface = new mw.EmbedPlayer( element , attributes); |
383 | 390 | _this.swapEmbedPlayerElement( element, playerInterface ); |
384 | 391 | |
— | — | @@ -389,6 +396,8 @@ |
390 | 397 | mw.log(" WaitForMeta ( video missing height width info and has src )"); |
391 | 398 | element.removeEventListener( "loadedmetadata", runPlayerSwap, true ); |
392 | 399 | element.addEventListener( "loadedmetadata", runPlayerSwap, true ); |
| 400 | + // Time-out of 3 seconds ( maybe still playable but no timely metadata ) |
| 401 | + setTimeout( runPlayerSwap, 3000 ); |
393 | 402 | }else{ |
394 | 403 | runPlayerSwap( element_id ) |
395 | 404 | } |
— | — | @@ -558,6 +567,11 @@ |
559 | 568 | // End time in npt format |
560 | 569 | end_npt: null, |
561 | 570 | |
| 571 | + // A provider "id" to idenfiy api request type |
| 572 | + provider_type : null, |
| 573 | + |
| 574 | + // The api url for the provider |
| 575 | + provider_url : null, |
562 | 576 | |
563 | 577 | /** |
564 | 578 | * MediaSource constructor: |
— | — | @@ -623,11 +637,13 @@ |
624 | 638 | // if we have time we can use: |
625 | 639 | if ( this.URLTimeEncoding ) { |
626 | 640 | // make sure its a valid start time / end time (else set default) |
627 | | - if ( !mw.npt2seconds( start_npt ) ) |
| 641 | + if ( !mw.npt2seconds( start_npt ) ){ |
628 | 642 | start_npt = this.start_npt; |
629 | | - |
630 | | - if ( !mw.npt2seconds( end_npt ) ) |
| 643 | + } |
| 644 | + |
| 645 | + if ( !mw.npt2seconds( end_npt ) ){ |
631 | 646 | end_npt = this.end_npt; |
| 647 | + } |
632 | 648 | |
633 | 649 | this.src = mw.replaceUrlParams( this.src, { |
634 | 650 | 't': start_npt + '/' + end_npt |
— | — | @@ -839,7 +855,7 @@ |
840 | 856 | this.durationHint = $j( video_element ).attr( 'durationHint' ); |
841 | 857 | // Convert duration hint if needed: |
842 | 858 | this.duration = mw.npt2seconds( this.durationHint ); |
843 | | - } |
| 859 | + } |
844 | 860 | |
845 | 861 | // Process the video_element as a source element: |
846 | 862 | if ( $j( video_element ).attr( "src" ) ) |
— | — | @@ -1049,7 +1065,7 @@ |
1050 | 1066 | if ( this.sources[i].src == new_src ) { |
1051 | 1067 | // Source already exists update any new attr: |
1052 | 1068 | this.sources[i].updateSource( element ); |
1053 | | - return ; |
| 1069 | + return this.sources[i]; |
1054 | 1070 | } |
1055 | 1071 | } |
1056 | 1072 | } |
— | — | @@ -1062,7 +1078,8 @@ |
1063 | 1079 | source.startOffset = praserFloat( this.startOffset ); |
1064 | 1080 | |
1065 | 1081 | mw.log( 'pushed source to stack' + source + 'sl:' + this.sources.length ); |
1066 | | - this.sources.push( source ); |
| 1082 | + this.sources.push( source ); |
| 1083 | + return source; |
1067 | 1084 | }, |
1068 | 1085 | |
1069 | 1086 | /** |
— | — | @@ -1266,11 +1283,11 @@ |
1267 | 1284 | * |
1268 | 1285 | * @param {Element} element Source element to grab size from |
1269 | 1286 | */ |
1270 | | - setPlayerSize:function( element ){ |
| 1287 | + setPlayerSize:function( element ){ |
1271 | 1288 | this['height'] = parseInt( $j(element).css( 'height' ).replace( 'px' , '' ) ); |
1272 | 1289 | this['width'] = parseInt( $j(element).css( 'width' ).replace( 'px' , '' ) ); |
1273 | 1290 | |
1274 | | - if( ! this['height'] && ! this['width'] ){ |
| 1291 | + if( !this['height'] && !this['width'] ){ |
1275 | 1292 | this['height'] = parseInt( $j(element).attr( 'height' ) ); |
1276 | 1293 | this['width'] = parseInt( $j(element).attr( 'width' ) ); |
1277 | 1294 | } |
— | — | @@ -1290,8 +1307,7 @@ |
1291 | 1308 | |
1292 | 1309 | // On load sometimes attr is temporally -1 as we don't have video metadata yet. |
1293 | 1310 | // NOTE: this edge case should be handled by waiting for metadata see: "waitForMeta" in addElement |
1294 | | - if( ( !this['height'] || !this['width'] ) || |
1295 | | - ( this['height'] == -1 || this['width'] == -1 ) || |
| 1311 | + if( ( this['height'] == -1 || this['width'] == -1 ) || |
1296 | 1312 | // Check for firefox defaults |
1297 | 1313 | // Note: ideally firefox would not do random guesses at css values |
1298 | 1314 | ( (this.height == 150 || this.height == 64 ) && this.width == 300 ) |
— | — | @@ -2530,14 +2546,16 @@ |
2531 | 2547 | var dl_list = ''; |
2532 | 2548 | var dl_txt_list = ''; |
2533 | 2549 | $j.each( _this.mediaElement.getSources(), function( index, source ) { |
2534 | | - var dl_line = '<li>' + '<a style="color:white" href="' + source.getSrc() + '"> ' |
2535 | | - + source.getTitle() + '</a> ' + '</li>' + "\n"; |
2536 | | - if ( source.getSrc().indexOf( '?t=' ) !== -1 ) { |
2537 | | - out += dl_line; |
2538 | | - } else if ( this.getMIMEType() == "text/cmml" || this.getMIMEType() == "text/x-srt" ) { |
2539 | | - dl_txt_list += dl_line; |
2540 | | - } else { |
2541 | | - dl_list += dl_line; |
| 2550 | + if( source.getSrc() ){ |
| 2551 | + var dl_line = '<li>' + '<a style="color:white" href="' + source.getSrc() + '"> ' |
| 2552 | + + source.getTitle() + '</a> ' + '</li>' + "\n"; |
| 2553 | + if ( source.getSrc().indexOf( '?t=' ) !== -1 ) { |
| 2554 | + out += dl_line; |
| 2555 | + } else if ( this.getMIMEType() == "text/cmml" || this.getMIMEType() == "text/x-srt" ) { |
| 2556 | + dl_txt_list += dl_line; |
| 2557 | + } else { |
| 2558 | + dl_list += dl_line; |
| 2559 | + } |
2542 | 2560 | } |
2543 | 2561 | } ); |
2544 | 2562 | |
Index: branches/js2-work/phase3/js/mwEmbed/mwEmbed.js |
— | — | @@ -26,38 +26,41 @@ |
27 | 27 | } |
28 | 28 | |
29 | 29 | /** |
| 30 | +* The set of modules that you want enable. |
| 31 | +* |
| 32 | +* Each enabledModules array value should be a name |
| 33 | +* of a folder in mwEmbed/modules |
| 34 | +* |
| 35 | +* Modules must define a loader.js file in the root |
| 36 | +* of the module folder. |
| 37 | +* |
| 38 | +* The loader file should be short and only include: |
| 39 | +* Class paths of the module classes |
| 40 | +* Sytle sheets of the module |
| 41 | +* Loader function(s) that load module classes |
| 42 | +* |
| 43 | +* When using the scriptLoader the enabledModules loader code |
| 44 | +* is transcluded into base mwEmbed class include. |
| 45 | +*/ |
| 46 | +var mwEnabledModuleList = [ |
| 47 | + 'AddMedia', |
| 48 | + 'ClipEdit', |
| 49 | + 'EmbedPlayer', |
| 50 | + 'ApiProxy', |
| 51 | + 'Sequencer', |
| 52 | + 'TimedText' |
| 53 | +]; |
| 54 | + |
| 55 | +/** |
30 | 56 | * Default global config values. Configuration values are set via mw.setConfig |
31 | 57 | * Configuration values should generally be set prior to dom-ready |
32 | 58 | */ |
33 | 59 | var mwDefaultConf = { |
34 | 60 | |
35 | | - /** |
36 | | - * The set of modules that you want enable. |
37 | | - * |
38 | | - * Each enabledModules array value should be a name |
39 | | - * of a folder in mwEmbed/modules |
40 | | - * |
41 | | - * Modules must define a loader.js file in the root |
42 | | - * of the module folder. |
43 | | - * |
44 | | - * The loader file should be short and only include: |
45 | | - * Class paths of the module classes |
46 | | - * Sytle sheets of the module |
47 | | - * Loader function(s) that load module classes |
48 | | - * |
49 | | - * When using the scriptLoader the enabledModules loader code |
50 | | - * is transcluded into base mwEmbed class include. |
51 | | - */ |
52 | | - 'enabledModules' : [ |
53 | | - 'AddMedia', |
54 | | - 'ClipEdit', |
55 | | - 'EmbedPlayer', |
56 | | - 'ApiProxy', |
57 | | - 'Sequencer', |
58 | | - 'TimedText' |
59 | | - ], |
60 | 61 | |
| 62 | + 'enabledModules' : mwEnabledModuleList, |
61 | 63 | |
| 64 | + |
62 | 65 | // Default skin name |
63 | 66 | 'skinName' : 'mvpcf', |
64 | 67 | |
Index: branches/js2-work/phase3/js/mwEmbed/jsScriptLoader.php |
— | — | @@ -91,7 +91,14 @@ |
92 | 92 | if( $jstxt ){ |
93 | 93 | $this->jsout .= $this->doProcessJs( $jstxt ); |
94 | 94 | } |
| 95 | + |
| 96 | + // If the special mwEmbed class entry point (include loader js |
| 97 | + if( $classKey == 'mwEmbed' ){ |
| 98 | + global $wgMwEmbedLoaderJs; |
| 99 | + $this->jsout .= $wgMwEmbedLoaderJs; |
| 100 | + } |
95 | 101 | } |
| 102 | + |
96 | 103 | // Check if we should minify the whole thing: |
97 | 104 | if ( !$this->debug ) { |
98 | 105 | $this->jsout = self::getMinifiedJs( $this->jsout , $this->requestKey ); |
— | — | @@ -106,7 +113,7 @@ |
107 | 114 | if ( $this->error_msg != '' ) { |
108 | 115 | //just set the content type (don't send cache header) |
109 | 116 | header( 'Content-Type: text/javascript' ); |
110 | | - echo 'alert(\'Error With ScriptLoader.php ::' . str_replace( "\n", '\'+"\n"+' . "\n'", $this->error_msg ) . '\');'; |
| 117 | + echo 'alert(\'Error With ScriptLoader ::' . str_replace( "\n", '\'+"\n"+' . "\n'", $this->error_msg ) . '\');'; |
111 | 118 | echo trim( $this->jsout ); |
112 | 119 | } else { |
113 | 120 | // All good, let's output "cache" headers |
Index: branches/js2-work/phase3/js/mwEmbed/remotes/mediaWiki.js |
— | — | @@ -20,17 +20,23 @@ |
21 | 21 | // Use wikibits onLoad hook: ( since we don't have js2 / mw object loaded ) |
22 | 22 | addOnloadHook( function() { |
23 | 23 | // Only do rewrites if mwEmbed / js2 is "off" |
24 | | - if ( typeof mwEmbed_VERSION == 'undefined' ) { |
25 | | - setTimeout(function(){ |
26 | | - doPageSpecificRewrite(); |
27 | | - }, 200 ); |
| 24 | + if ( typeof mwEmbed_VERSION == 'undefined' ) { |
| 25 | + doPageSpecificRewrite(); |
28 | 26 | } |
29 | 27 | } ); |
30 | 28 | |
31 | 29 | /** |
32 | 30 | * Page specific rewrites for mediaWiki |
33 | 31 | */ |
34 | | -function doPageSpecificRewrite() { |
| 32 | + |
| 33 | +// Deal with multiple doPageSpecificRewrite |
| 34 | +if( !ranRewrites){ |
| 35 | + var ranRewrites = 'none'; |
| 36 | +} |
| 37 | +function doPageSpecificRewrite() { |
| 38 | + if( ranRewrites != 'none') |
| 39 | + return ; |
| 40 | + ranRewrites = 'done'; |
35 | 41 | // Add media wizard |
36 | 42 | if ( wgAction == 'edit' || wgAction == 'submit' ) { |
37 | 43 | loadMwEmbed( [ |
— | — | @@ -80,11 +86,10 @@ |
81 | 87 | var vidIdList = []; |
82 | 88 | var divs = document.getElementsByTagName( 'div' ); |
83 | 89 | for ( var i = 0; i < divs.length; i++ ) { |
84 | | - if ( divs[i].id && divs[i].id.substring( 0, 11 ) == 'ogg_player_' ) { |
85 | | - if( divs[i].getAttribute( "id" ) != 'ogg_player_2' ) |
86 | | - vidIdList.push( divs[i].getAttribute( "id" ) ); |
| 90 | + if ( divs[i].id && divs[i].id.substring( 0, 11 ) == 'ogg_player_' ) { |
| 91 | + vidIdList.push( divs[i].getAttribute( "id" ) ); |
87 | 92 | } |
88 | | - } |
| 93 | + } |
89 | 94 | if ( vidIdList.length > 0 ) { |
90 | 95 | var jsSetVideo = [ 'embedPlayer', '$j.ui', 'ctrlBuilder', '$j.cookie', '$j.ui.slider', 'kskinConfig' ]; |
91 | 96 | // Quick sniff use java if IE and native if firefox |
— | — | @@ -117,14 +122,14 @@ |
118 | 123 | if ( !vidId ) |
119 | 124 | return ; |
120 | 125 | |
121 | | - mw.log( 'vidIdList on: ' + vidId + ' length: ' + vidIdList.length + ' left in the set: ' + vidIdList ); |
| 126 | + mw.log( 'vidIdList on: ' + vidId + ' id:' + $j('#' + vidId ).length + ' length: ' + vidIdList.length + ' left in the set: ' + vidIdList ); |
122 | 127 | |
123 | 128 | tag_type = 'video'; |
124 | 129 | |
125 | 130 | // Check type: |
126 | 131 | var pwidth = $j( '#' + vidId ).width(); |
127 | 132 | var $pimg = $j( '#' + vidId + ' img:first' ); |
128 | | - if( $pimg.attr('src').split('/').pop() == 'play.png'){ |
| 133 | + if( $pimg.attr('src') && $pimg.attr('src').split('/').pop() == 'play.png'){ |
129 | 134 | tag_type = 'audio'; |
130 | 135 | poster_attr = ''; |
131 | 136 | pheight = 0; |
— | — | @@ -132,27 +137,32 @@ |
133 | 138 | var poster_attr = 'poster = "' + $pimg.attr( 'src' ) + '" '; |
134 | 139 | var pheight = $pimg.attr( 'height' ); |
135 | 140 | } |
136 | | - |
137 | | - |
| 141 | + |
138 | 142 | // Parsed values: |
139 | 143 | var src = ''; |
140 | 144 | var duration_attr = ''; |
141 | | - |
| 145 | + var rewriteHTML = $j( '#' + vidId ).html(); |
142 | 146 | |
| 147 | + if( rewriteHTML == ''){ |
| 148 | + mw.log( "Error: empty rewrite html" ); |
| 149 | + return ; |
| 150 | + }else{ |
| 151 | + mw.log(" rewrite: " + rewriteHTML + "\n of type: " + typeof rewriteHTML); |
| 152 | + } |
143 | 153 | var re = new RegExp( /videoUrl(":?\s*)*([^&]*)/ ); |
144 | | - src = re.exec( $j( '#' + vidId ).html() )[2]; |
| 154 | + src = re.exec( rewriteHTML )[2]; |
145 | 155 | |
146 | 156 | var wikiTitleKey = src.split( '/' ); |
147 | 157 | wikiTitleKey = unescape( wikiTitleKey[ wikiTitleKey.length - 1 ] ); |
148 | 158 | |
149 | 159 | var re = new RegExp( /length(":?\s*)*([^,]*)/ ); |
150 | | - var dv = re.exec( $j( '#' + vidId ).html() )[2]; |
| 160 | + var dv = re.exec( rewriteHTML )[2]; |
151 | 161 | if ( dv ) { |
152 | 162 | duration_attr = 'durationHint="' + dv + '" '; |
153 | 163 | } |
154 | 164 | |
155 | 165 | var re = new RegExp( /offset(":?\s*)*([^,&]*)/ ); |
156 | | - offset = re.exec( $j( '#' + vidId ).html() )[2]; |
| 166 | + offset = re.exec( rewriteHTML )[2]; |
157 | 167 | var offset_attr = offset ? 'startOffset="' + offset + '"' : ''; |
158 | 168 | |
159 | 169 | if ( src ) { |
— | — | @@ -166,7 +176,11 @@ |
167 | 177 | 'class="kskin" '; |
168 | 178 | |
169 | 179 | if ( tag_type == 'audio' ) { |
170 | | - html_out = '<audio' + common_attr + ' style="width:' + pwidth + 'px;"></audio>'; |
| 180 | + if( pwidth < 250 ){ |
| 181 | + pwidth = 250; |
| 182 | + } |
| 183 | + html_out = '<audio' + common_attr + ' ' + |
| 184 | + 'style="width:' + pwidth + 'px;height:0px;"></audio>'; |
171 | 185 | } else { |
172 | 186 | html_out = '<video' + common_attr + |
173 | 187 | poster_attr + ' ' + |
— | — | @@ -179,10 +193,10 @@ |
180 | 194 | |
181 | 195 | // Do the actual rewrite |
182 | 196 | $j( '#mwe_' + vidId ).embedPlayer( function() { |
183 | | - if ( vidIdList.length != 0 ) { |
| 197 | + if ( vidIdList.length != 0 ) { |
184 | 198 | setTimeout( function() { |
185 | 199 | procVidId( vidIdList.pop() ) |
186 | | - }, 10 ); |
| 200 | + }, 10 ); |
187 | 201 | } |
188 | 202 | } ); |
189 | 203 | |
Index: branches/js2-work/phase3/js/editPage.js |
— | — | @@ -44,7 +44,7 @@ |
45 | 45 | $.addLoaderDialog( gM( 'mwe-loading-add-media-wiz' ) ); |
46 | 46 | mw.load( 'AddMedia.addMediaWizard', function(){ |
47 | 47 | $.closeLoaderDialog(); |
48 | | - $j.addMediaWiz( amwConf ); |
| 48 | + $j.addMediaWizard( amwConf ); |
49 | 49 | }); |
50 | 50 | } |
51 | 51 | }; |
— | — | @@ -62,7 +62,7 @@ |
63 | 63 | |
64 | 64 | $j( '#btn-add-media-wiz' ).attr( 'title', gM( 'mwe-loading-add-media-wiz' ) ); |
65 | 65 | mw.load( 'AddMedia.addMediaWizard', function(){ |
66 | | - $j( '#btn-add-media-wiz' ).addMediaWiz( |
| 66 | + $j( '#btn-add-media-wiz' ).addMediaWizard( |
67 | 67 | amwConf |
68 | 68 | ); |
69 | 69 | }); |
— | — | @@ -73,7 +73,9 @@ |
74 | 74 | mw.log( 'Failed to bind via build section bind via target:' ); |
75 | 75 | $j( ".tool[rel='file']" ).attr( 'title', gM( 'mwe-loading-add-media-wiz' ) ); |
76 | 76 | mw.load( 'AddMedia.addMediaWizard', function(){ |
77 | | - $j( ".tool[rel='file']" ).unbind().addMediaWiz( amwConf ); |
| 77 | + if( $j( ".tool[rel='file']" ).length != 0 ){ |
| 78 | + $j( ".tool[rel='file']" ).unbind().addMediaWizard( amwConf ); |
| 79 | + } |
78 | 80 | }); |
79 | 81 | } |
80 | 82 | } |