r74330 MediaWiki - Code Review archive

Repository:MediaWiki
Revision:r74329‎ | r74330 | r74331 >
Date:23:01, 5 October 2010
Author:dale
Status:deferred
Tags:
Comment:
* sync extension with mwEmbedStandAlone embedPlayer updates
Modified paths:
  • /trunk/extensions/TimedMediaHandler/EmbedPlayer/EmbedPlayer.i18n.php (modified) (history)
  • /trunk/extensions/TimedMediaHandler/EmbedPlayer/binPlayers/cortado/cortado-january.jar (deleted) (history)
  • /trunk/extensions/TimedMediaHandler/EmbedPlayer/binPlayers/cortado/cortado-ovt-stripped-0.5.0.jar (deleted) (history)
  • /trunk/extensions/TimedMediaHandler/EmbedPlayer/binPlayers/cortado/cortado-ovtk-stripped-0.6.0.jar (added) (history)
  • /trunk/extensions/TimedMediaHandler/EmbedPlayer/binPlayers/kaltura-player/LightDoodleskin.swf (added) (history)
  • /trunk/extensions/TimedMediaHandler/EmbedPlayer/binPlayers/kaltura-player/config.xml (modified) (history)
  • /trunk/extensions/TimedMediaHandler/EmbedPlayer/mw.EmbedPlayer.js (modified) (history)
  • /trunk/extensions/TimedMediaHandler/EmbedPlayer/mw.EmbedPlayerHtml.js (modified) (history)
  • /trunk/extensions/TimedMediaHandler/EmbedPlayer/mw.EmbedPlayerJava.js (modified) (history)
  • /trunk/extensions/TimedMediaHandler/EmbedPlayer/mw.EmbedPlayerKplayer.js (modified) (history)
  • /trunk/extensions/TimedMediaHandler/EmbedPlayer/mw.EmbedPlayerNative.js (modified) (history)
  • /trunk/extensions/TimedMediaHandler/EmbedPlayer/mw.EmbedPlayerVlc.js (modified) (history)
  • /trunk/extensions/TimedMediaHandler/EmbedPlayer/skins/kskin/mw.PlayerSkinKskin.js (modified) (history)
  • /trunk/extensions/TimedMediaHandler/EmbedPlayer/skins/kskin/mw.style.PlayerSkinKskin.css (modified) (history)
  • /trunk/extensions/TimedMediaHandler/EmbedPlayer/skins/mvpcf/mw.style.PlayerSkinMvpcf.css (modified) (history)
  • /trunk/extensions/TimedMediaHandler/EmbedPlayer/skins/mw.PlayerControlBuilder.js (modified) (history)
  • /trunk/extensions/TimedMediaHandler/TimedText/loader.js (modified) (history)
  • /trunk/extensions/TimedMediaHandler/TimedText/mw.TimedText.js (modified) (history)
  • /trunk/extensions/TimedMediaHandler/TimedText/mw.TimedTextEdit.js (modified) (history)

Diff [purge]

Index: trunk/extensions/TimedMediaHandler/TimedText/mw.TimedTextEdit.js
@@ -185,7 +185,7 @@
186186 $j('#timed-text-file-preview')
187187 .css({
188188 'width':'100%',
189 - 'height': ( $target.find( '.rightcolumn' ).height() - $j('#timed-text-rightcolum-desc').height() ) + 'px'
 189+ 'height': '300px'
190190 });
191191
192192 // Add Select file:
@@ -207,33 +207,33 @@
208208 $target.append(
209209 //Get a little helper input filed to update the language
210210 $j('<input />')
211 - .attr( {
212 - 'id' : "timed-text-langKey-input",
213 - 'type' : "text",
214 - 'maxlength' : "10",
215 - 'size' :"3"
216 - } )
217 - .change(function() {
218 - var langKey = $j(this).val();
219 - if( mw.languages[ langKey ] ) {
220 - $buttonTarget.find('.btnText').text(
221 - unescape( mw.languages[ langKey ] )
222 - );
223 - }
224 - }),
 211+ .attr( {
 212+ 'id' : "timed-text-langKey-input",
 213+ 'type' : "text",
 214+ 'maxlength' : "10",
 215+ 'size' :"3"
 216+ } )
 217+ .change(function() {
 218+ var langKey = $j(this).val();
 219+ if( mw.Language.names[ langKey ] ) {
 220+ $buttonTarget.find('.btnText').text(
 221+ unescape( mw.Language.names[ langKey ] )
 222+ );
 223+ }
 224+ }),
225225 // Get a jQuery button object with language menu:
226226 $j.button( {
227227 'style': { 'float' : 'left' },
228228 'class': 'language-select-btn',
229229 'text': gM('mwe-timedtext-select-language'),
230 - 'icon_id': 'triangle-1-e'
231 - } ).attr('id', 'language-select')
232 - .unbind()
233 - .buttonHover()
 230+ 'icon': 'triangle-1-e'
 231+ } )
 232+ .attr('id', 'language-select')
234233 )
235234
236235
237236 var $buttonTarget = $target.find('.language-select-btn');
 237+
238238 // Add menu container:
239239 var loc = $buttonTarget.position();
240240 $target.append(
@@ -242,10 +242,8 @@
243243 .attr( 'id', 'upload-language-select' )
244244 .loadingSpinner()
245245 .css( {
246 - 'position' : 'absolute',
247 - 'z-index' : 10,
248 - 'top' : ( loc.top + 40 ) + 'px',
249 - 'left' : parseInt( loc.left ) + 'px',
 246+ 'position' : 'relative',
 247+ 'z-index' : 10,
250248 'height' : '180px',
251249 'width' : '180px',
252250 'overflow' : 'auto',
@@ -255,11 +253,16 @@
256254 .hide()
257255 );
258256 // Add menu binding to button target
259 - $buttonTarget.menu( {
260 - 'content' : _this.getLanguageList(),
261 - 'backLinkText' : gM( 'mwe-timedtext-back-btn' ),
262 - 'targetMenuContainer': '#upload-language-select'
263 - } );
 257+ setTimeout(function(){
 258+ $buttonTarget.menu( {
 259+ 'content' : _this.getLanguageList(),
 260+ 'backLinkText' : gM( 'mwe-timedtext-back-btn' ),
 261+ 'targetMenuContainer': '#upload-language-select',
 262+ 'keepPosition' : true
 263+ } );
 264+ // force the layout ( menu binding does strange things )
 265+ $j('#upload-language-select').css( {'left': '315px', 'top' : '87px', 'position' : 'absolute'});
 266+ },10);
264267
265268
266269 //Add upload input bindings:
@@ -280,9 +283,9 @@
281284 var langKey = $j(this).val().split( '.' );
282285 var extension = langKey.pop();
283286 langKey = langKey.pop();
284 - if( mw.languages[ langKey ] ) {
 287+ if( mw.Language.names[ langKey ] ) {
285288 $buttonTarget.find('.btnText').text(
286 - unescape( mw.languages[ langKey ] )
 289+ unescape( mw.Language.names[ langKey ] )
287290 );
288291 // Update the key code
289292 $j('#timed-text-langKey-input').val( langKey );
@@ -299,10 +302,8 @@
300303 $j.button( {
301304 'style': { 'float' : 'left' },
302305 'text': gM('mwe-timedtext-upload-text'),
303 - 'icon_id': 'disk'
 306+ 'icon': 'disk'
304307 } )
305 - .unbind()
306 - .buttonHover()
307308 .click( function() {
308309 _this.uploadTextFile();
309310 })
@@ -341,22 +342,29 @@
342343 buttons[ gM("mwe-timedtext-upload-text-another")] = function() {
343344 // just close the current dialog:
344345 $j( this ).dialog('close');
345 - }
 346+ };
346347 buttons[ gM( "mwe-timedtext-upload-text-done-uploading" ) ] = function() {
347348 window.location.reload();
348 - }
 349+ };
349350 //Edit success
350 - mw.addDialog(
351 - gM( "mwe-timedtext-upload-text-done"),
352 - gM("mwe-timedtext-upload-text-success"),
353 - buttons
354 - )
 351+ setTimeout(function(){
 352+ mw.addDialog( {
 353+ 'width' : '400px',
 354+ 'title' : gM( "mwe-timedtext-upload-text-done"),
 355+ 'content' : gM("mwe-timedtext-upload-text-success"),
 356+ 'buttons' : buttons
 357+ });
 358+ },10 );
355359 }else{
356 - mw.addDialog(
357 - gM( "mwe-timedtext-upload-text-fail-title"),
358 - gM( "mwe-timedtext-upload-text-fail-desc"),
359 - 'ok'
360 - )
 360+ //Edit fail
 361+ setTimeout(function(){
 362+ mw.addDialog({
 363+ 'width' : '400px',
 364+ 'title' : gM( "mwe-timedtext-upload-text-fail-title"),
 365+ 'content' :gM( "mwe-timedtext-upload-text-fail-desc"),
 366+ 'buttons' : gM( 'mwe-ok' )
 367+ });
 368+ },10 );
361369 }
362370 });
363371 })
@@ -377,8 +385,8 @@
378386 var _this = this;
379387 var $langMenu = $j( '<ul>' );
380388 // Loop through all supported languages:
381 - for ( var langKey in mw.languages ) {
382 - var language = mw.languages [ langKey ];
 389+ for ( var langKey in mw.Language.names ) {
 390+ var language = mw.Language.names [ langKey ];
383391 var source_icon = 'radio-on';
384392 //check if the key is in the _this.parentTimedText source array
385393 for( var i in _this.parentTimedText.textSources ) {
@@ -396,15 +404,16 @@
397405 },
398406 getLangMenuItem: function( langKey , source_icon) {
399407 return $j.getLineItem(
400 - langKey + ' - ' + unescape( mw.languages[ langKey ] ),
 408+ langKey + ' - ' + unescape( mw.Language.names[ langKey ] ),
401409 source_icon,
402 - function() {
 410+ function() {
403411 mw.log( "Selected: " + langKey );
404412 // Update the input box text
405413 $j('#timed-text-langKey-input').val( langKey );
406 - // Update the menu item:
407 - $j( '#language-select' ).val( unescape( mw.languages[ langKey ] ) )
408 - } );
 414+ // Update the menu item:
 415+ $j('#language-select').find('.btnText').text( unescape( mw.Language.names[ langKey ] ) )
 416+ }
 417+ );
409418 },
410419 /**
411420 * Creates the interface dialog container
@@ -433,18 +442,23 @@
434443 $j( _this.target_container ).dialog( {
435444 bgiframe: true,
436445 autoOpen: true,
 446+ width: $j(window).width()-50,
 447+ height: $j(window).height()-50,
 448+ position : 'center',
437449 modal: true,
438450 draggable: false,
439451 resizable: false,
440452 buttons: cancelButton,
441453 close: function() {
442 - // if we are 'editing' we should confirm they want to exist:
 454+ // @@TODO if we are 'editing' we should confirm they want to exist:
443455 $j( this ).parents( '.ui-dialog' ).fadeOut( 'slow' );
444456 }
445457 } );
 458+ // set a non-blocking fit window request
 459+ setTimeout(function(){
 460+ $j( _this.target_container ).dialogFitWindow();
 461+ },10);
446462
447 - $j( _this.target_container ).dialogFitWindow();
448 -
449463 // Add the window resize hook to keep dialog layout
450464 $j( window ).resize( function() {
451465 $j( _this.target_container ).dialogFitWindow();
Index: trunk/extensions/TimedMediaHandler/TimedText/loader.js
@@ -15,6 +15,12 @@
1616 } );
1717
1818 mw.setDefaultConfig( {
 19+ // If the Timed Text interface should be displayed:
 20+ // 'always' Displays link and call to contribute always
 21+ // 'auto' Looks for child timed text elements or "apiTitleKey" & load interface
 22+ // 'off' Does not display the timed text interface
 23+ "TimedText.showInterface" : "auto",
 24+
1925 /**
2026 * If the "add timed text" link / interface should be exposed
2127 */
@@ -44,8 +50,8 @@
4551 $j( mw ).bind( 'LoaderEmbedPlayerUpdateRequest', function( event, playerElement, classRequest ) {
4652
4753 var mwLoadTimedTextFlag = false;
48 - // Check for the textInterface config flag
49 - if( mw.getConfig( 'textInterface' ) == 'always' ) {
 54+ // Check for the TimedText.showInterface config flag
 55+ if( mw.getConfig( 'TimedText.showInterface' ) == 'always' ) {
5056 mwLoadTimedTextFlag = true;
5157 }
5258
@@ -65,10 +71,9 @@
6672
6773 // Add timed text items if flag set.
6874 // its oky if we merge in multiple times the loader can handle it
69 - if( mwLoadTimedTextFlag ) {
 75+ if( mwLoadTimedTextFlag ) {
7076 $j.merge( classRequest, mwTimedTextRequestSet );
7177 }
72 -
7378 } );
7479
7580
@@ -76,6 +81,9 @@
7782 mw.addModuleLoader( 'TimedText.Edit', [
7883 [
7984 '$j.ui',
 85+ '$j.widget',
 86+ '$j.ui.mouse',
 87+ '$j.ui.position',
8088 '$j.fn.menu',
8189 "mw.style.jquerymenu",
8290
Index: trunk/extensions/TimedMediaHandler/TimedText/mw.TimedText.js
@@ -11,36 +11,7 @@
1212 *
1313 */
1414
15 -mw.addMessages( {
16 - "mwe-timedtext-back-btn" : "Back",
17 - "mwe-timedtext-choose-text" : "Chose text",
18 - "mwe-timedtext-add-timed-text" : "Add timed text",
19 - "mwe-timedtext-loading-text-edit" : "Loading timed text editor",
20 -
21 - "mwe-timedtext-search" : "Search clip",
22 -
23 - "mwe-timedtext-layout" : "Layout",
24 - "mwe-timedtext-layout-ontop" : "Ontop of video",
25 - "mwe-timedtext-layout-below": "Below video",
26 - "mwe-timedtext-layout-off" : "Hide subtitles",
27 -
28 - "mwe-timedtext-loading-text" : "Loading text ...",
29 -
30 - "mwe-timedtext-key-language": "$1, $2",
31 -
32 - "mwe-timedtext-textcat-cc" : "Captions",
33 - "mwe-timedtext-textcat-sub" : "Subtitles",
34 - "mwe-timedtext-textcat-tad" : "Audio description",
35 - "mwe-timedtext-textcat-ktv" : "Karaoke",
36 - "mwe-timedtext-textcat-tik" : "Ticker text",
37 - "mwe-timedtext-textcat-ar" : "Active regions",
38 - "mwe-timedtext-textcat-nb" : "Annotation",
39 - "mwe-timedtext-textcat-meta" : "Timed metadata",
40 - "mwe-timedtext-textcat-trx" : "Transcript",
41 - "mwe-timedtext-textcat-lrc" : "Lyrics",
42 - "mwe-timedtext-textcat-lin" : "Linguistic markup",
43 - "mwe-timedtext-textcat-cue" : "Cue points"
44 -} );
 15+mw.includeAllModuleMessages();
4516
4617 // Bind to mw ( for uncluttered global namespace )
4718 ( function( $ ) {
@@ -51,7 +22,7 @@
5223 */
5324 mw.TimedText = function( embedPlayer, options ) {
5425 return this.init( embedPlayer, options);
55 - }
 26+ };
5627 mw.TimedText.prototype = {
5728
5829 /**
@@ -131,7 +102,7 @@
132103 */
133104 init: function( embedPlayer, options ) {
134105 var _this = this;
135 - mw.log("TimedText: init() ")
 106+ mw.log("TimedText: init() ");
136107 this.embedPlayer = embedPlayer;
137108 this.options = options;
138109
@@ -225,7 +196,7 @@
226197 // NOTE: Button target should be an option or config
227198 $menuButton.unbind().menu( {
228199 'content' : _this.getMainMenu(),
229 - 'zindex' : mw.getConfig( 'fullScreenIndex' )+2,
 200+ 'zindex' : mw.getConfig( 'EmbedPlayer.fullScreenZIndex' ) + 2,
230201 'crumbDefaultText' : ' ',
231202 'autoShow': autoShow,
232203 'targetMenuContainer' : _this.menuTarget,
@@ -492,7 +463,7 @@
493464 // Close the loader:
494465 mw.closeLoaderDialog();
495466 _this.editText.showUI();
496 - })
 467+ });
497468 },
498469
499470 /**
@@ -509,7 +480,7 @@
510481 var _this = this;
511482 return $j.getLineItem( gM( 'mwe-timedtext-add-timed-text'), 'script', function() {
512483 _this.showTimedTextEditUI( 'add' );
513 - } )
 484+ } );
514485 },
515486
516487 /**
@@ -550,7 +521,7 @@
551522 if( mw.Language.names[ lang_key ]) {
552523 return mw.Language.names[ lang_key ];
553524 }
554 - return false
 525+ return false;
555526 },
556527
557528 /**
@@ -580,7 +551,7 @@
581552 function() {
582553 _this.selectLayout( layoutMode );
583554 } )
584 - )
 555+ );
585556 });
586557 return $ul;
587558 },
@@ -643,7 +614,7 @@
644615 source.load( function() {
645616 // Refresh the interface:
646617 _this.refreshDisplay();
647 - })
 618+ });
648619 },
649620
650621 /**
@@ -655,7 +626,7 @@
656627 // Refresh the Menu (if it has a target to refresh)
657628 if( this.menuTarget ) {
658629 mw.log('bind menu refresh display');
659 - this.bindMenu( this.menuTarget, false )
 630+ this.bindMenu( this.menuTarget, false );
660631 }
661632 // Issues a "monitor" command to update the timed text for the new layout
662633 this.monitor();
@@ -798,12 +769,11 @@
799770 $j('<span \>')
800771 )
801772
802 - // If in fullscreen mode update the text size:
803 - if( this.embedPlayer.controlBuilder.fullscreenMode ){
804 - $track.css(
805 - this.embedPlayer.controlBuilder.getFullscreenTextCss()
806 - );
807 - }
 773+ // Scale the text Relative to player size:
 774+ $track.css(
 775+ this.embedPlayer.controlBuilder.getInterfaceSizeTextCss()
 776+ );
 777+
808778 $playerTarget.append( $track );
809779 // Resize the interface for layoutMode == 'ontop' ( if not in fullscreen )
810780 // NOTE this shoudl be a call to controlBuilder not handled here inline
@@ -979,6 +949,7 @@
980950 if( time >= caption.start &&
981951 time <= caption.end ) {
982952 this.prevIndex = i;
 953+ //mw.log("Start cap time: " + caption.start + ' End time: ' + caption.end );
983954 return caption.content;
984955 }
985956 }
@@ -1194,7 +1165,9 @@
11951166 loadTitleKey: function( titleKey, callback ) {
11961167 var request = {
11971168 'action': 'parse',
1198 - 'page': titleKey
 1169+ 'page': titleKey,
 1170+ 'smaxage' : 300,
 1171+ 'maxage' : 300
11991172 };
12001173 mw.getJSON( this.apiUrl, request, function( data ) {
12011174 if ( data && data.parse && data.parse.text['*'] ) {
@@ -1238,7 +1211,9 @@
12391212 'apprefix' : titleKey,
12401213 'apnamespace' : this.getTimedTextNS(),
12411214 'aplimit' : 200,
1242 - 'prop':'revisions'
 1215+ 'prop':'revisions',
 1216+ 'smaxage' : 300,
 1217+ 'maxage' : 300
12431218 };
12441219 mw.getJSON( this.apiUrl, request, function( sourcePages ) {
12451220 // If "timedText" is not a valid namespace try "just" with prefix:
Index: trunk/extensions/TimedMediaHandler/EmbedPlayer/mw.EmbedPlayer.js
@@ -7,70 +7,15 @@
88 * mw.PlayerControlBuilder Handles skinning of the player controls
99 */
1010
11 -mw.addMessages( {
12 - "mwe-embedplayer-loading_plugin" : "Loading plugin ...",
13 - "mwe-embedplayer-select_playback" : "Set playback preference",
14 - "mwe-embedplayer-link_back" : "Link back",
15 - "mwe-embedplayer-error_swap_vid" : "Error: mwEmbed was unable to swap the video tag for the mwEmbed interface",
16 - "mwe-embedplayer-add_to_end_of_sequence" : "Add to end of sequence",
17 - "mwe-embedplayer-missing_video_stream" : "The video file for this stream is missing",
18 - "mwe-embedplayer-play_clip" : "Play clip",
19 - "mwe-embedplayer-pause_clip" : "Pause clip",
20 - "mwe-embedplayer-volume_control" : "Volume control",
21 - "mwe-embedplayer-player_options" : "Player options",
22 - "mwe-embedplayer-timed_text" : "Timed text",
23 - "mwe-embedplayer-player_fullscreen" : "Fullscreen",
24 - "mwe-embedplayer-next_clip_msg" : "Play next clip",
25 - "mwe-embedplayer-prev_clip_msg" : "Play previous clip",
26 - "mwe-embedplayer-current_clip_msg" : "Continue playing this clip",
27 - "mwe-embedplayer-seek_to" : "Seek $1",
28 - "mwe-embedplayer-paused" : "paused",
29 - "mwe-embedplayer-download_segment" : "Download selection:",
30 - "mwe-embedplayer-download_full" : "Download full video file:",
31 - "mwe-embedplayer-download_right_click" : "To download, right click and select <i>Save link as...<\/i>",
32 - "mwe-embedplayer-download_clip" : "Download video",
33 - "mwe-embedplayer-download_text" : "Download text",
34 - "mwe-embedplayer-download" : "Download",
35 - "mwe-embedplayer-share" : "Share",
36 - "mwe-embedplayer-credits" : "Credits",
37 - "mwe-embedplayer-clip_linkback" : "Clip source page",
38 - "mwe-embedplayer-choose_player" : "Choose video player",
39 - "mwe-embedplayer-no-player" : "No player available for $1",
40 - "mwe-embedplayer-share_this_video" : "Share this video",
41 - "mwe-embedplayer-video_credits" : "Video credits",
42 - "mwe-embedplayer-kaltura-platform-title" : "Kaltura open source video platform",
43 - "mwe-embedplayer-menu_btn" : "Menu",
44 - "mwe-embedplayer-close_btn" : "Close",
45 - "mwe-embedplayer-ogg-player-vlc-player" : "VLC player",
46 - "mwe-embedplayer-ogg-player-oggNative" : "HTML5 Ogg player",
47 - "mwe-embedplayer-ogg-player-h264Native" : "HTML5 H.264 player",
48 - "mwe-embedplayer-ogg-player-oggPlugin" : "Generic Ogg plugin",
49 - "mwe-embedplayer-ogg-player-quicktime-mozilla" : "QuickTime plugin",
50 - "mwe-embedplayer-ogg-player-quicktime-activex" : "QuickTime ActiveX",
51 - "mwe-embedplayer-ogg-player-cortado" : "Java Cortado",
52 - "mwe-embedplayer-ogg-player-flowplayer" : "Flowplayer",
53 - "mwe-embedplayer-ogg-player-kplayer" : "Kaltura player",
54 - "mwe-embedplayer-ogg-player-selected" : "(selected)",
55 - "mwe-embedplayer-generic_missing_plugin" : "You browser does not appear to support the following playback type: <b>$1<\/b><br \/>Visit the <a href=\"http:\/\/commons.wikimedia.org\/wiki\/Commons:Media_help\">Playback methods<\/a> page to download a player.<br \/>",
56 - "mwe-embedplayer-missing-source" : "No source video was found. Check that your embed code includes a valid source or API key",
57 - "mwe-embedplayer-for_best_experience" : "For a better video playback experience we recommend the <b><a href=\"http:\/\/www.mozilla.com\/en-US\/firefox\/upgrade.html?from=mwEmbed\">latest Firefox<\/a>.<\/b>",
58 - "mwe-embedplayer-do_not_warn_again" : "Dismiss for now.",
59 - "mwe-embedplayer-playerSelect" : "Players",
60 - "mwe-embedplayer-read_before_embed" : "<a href=\"http:\/\/mediawiki.org\/wiki\/Security_Notes_on_Remote_Embedding\" target=\"_new\">Read this<\/a> before embedding.",
61 - "mwe-embedplayer-embed_site_or_blog" : "Embed on a page",
62 - "mwe-embedplayer-related_videos" : "Related videos",
63 - "mwe-embedplayer-seeking" : "seeking",
64 - "mwe-embedplayer-copy-code" : "Copy code",
65 - "mwe-embedplayer-video-h264" : "H.264 video",
66 - "mwe-embedplayer-video-flv" : "Flash video",
67 - "mwe-embedplayer-video-ogg" : "Ogg video",
68 - "mwe-embedplayer-video-audio" : "Ogg audio"
69 -} );
70 -
 11+/**
 12+ * Add the messages text:
 13+ */
 14+
 15+mw.includeAllModuleMessages();
7116 /*
7217 * The default video attributes supported by embedPlayer
7318 */
74 -mw.setConfig( 'embedPlayerAttributes', {
 19+mw.setDefaultConfig( 'EmbedPlayer.Attributes', {
7520 /*
7621 * Base html element attributes:
7722 */
@@ -89,7 +34,7 @@
9035 * also see: http://www.whatwg.org/specs/web-apps/current-work/multipage/video.html
9136 */
9237
93 - // Media src URI, can be relative or absolute URI
 38+ // Media src URI, can be relative or absolute URI
9439 "src" : null,
9540
9641 // Poster attribute for displaying a place holder image before loading or playing the video
@@ -158,10 +103,16 @@
159104 // The apiProvider where to lookup the title key
160105 "apiProvider" : null,
161106
162 - // If the player controls should be overlayed
163 - //( Global default via config overlayControls in module loader.js)
164 - "overlayControls" : true,
 107+ // If the player controls should be overlaid
 108+ //( Global default via config EmbedPlayer.OverlayControls in module loader.js)
 109+ "overlaycontrols" : true,
165110
 111+ // Attribute to use 'native' controls
 112+ "usenativecontrols" : false,
 113+
 114+ // If the player should include an attribution button:
 115+ 'attributionbutton' : true,
 116+
166117 // ROE url ( for xml based metadata )
167118 // also see: http://wiki.xiph.org/ROE
168119 "roe" : null,
@@ -180,14 +131,15 @@
181132 "download_link" : true,
182133
183134 // Content type of the media
184 - "type" : null
 135+ "type" : null
185136 });
186137
 138+
187139 /**
188140 * The base source attribute checks
189141 * also see: http://dev.w3.org/html5/spec/Overview.html#the-source-element
190142 */
191 -mw.setConfig( 'embedPlayerSourceAttributes', [
 143+mw.setDefaultConfig( 'embedPlayerSourceAttributes', [
192144 // source id
193145 'id',
194146
@@ -246,7 +198,7 @@
247199 * @param {Function} callback Function to call once embedding is done
248200 */
249201 $.embedPlayers = function( attributes, callback) {
250 - $j( mw.getConfig( 'rewritePlayerTags' ) ).embedPlayer( attributes, callback );
 202+ $j( mw.getConfig( 'EmbedPlayer.RewriteTags' ) ).embedPlayer( attributes, callback );
251203 };
252204
253205 /**
@@ -254,22 +206,65 @@
255207 *
256208 * Rewrites all tags via a given selector
257209 *
258 - * @param {Object} attributes [ Optional ] The embedPlayer options for the given video interface.
259 - * Attributes Object can inclued any key value pair that would otherwise be
 210+ * @param {object=} attributes Optional embedPlayer attributes for the given video interface.
 211+ * Attributes Object can include any key value pair that would otherwise be
260212 * an attribute in the html element.
261213 *
262 - * also see: mw.getConfig( 'embedPlayerAttributes' )
 214+ * also see: mw.getConfig( 'EmbedPlayer.Attributes' )
263215 *
264 - * @param {Function} callback [ Optional ] Function to be called once video interfaces are ready
 216+ * @param {Function=} callback Optional Function to be called once video interfaces are ready
265217 *
266218 */
267219 $.fn.embedPlayer = function( attributes, callback ) {
268 - var playerSelect = this.selector;
 220+ mw.log( 'EmbedPlayer:: fn.embedPlayer' );
 221+ var playerSelect = this.selector;
 222+
 223+ // Define attributes if unset
 224+ if( !attributes ) {
 225+ attributes = {};
 226+ }
 227+
269228 // Handle optional include of attributes argument:
270229 if( typeof attributes == 'function' ){
271 - callback = attributes;
 230+ callback = attributes;
 231+ attributes = {};
272232 }
273233
 234+ $j( playerSelect ).each( function( index, playerElement) {
 235+ // make sure the playerElement has an id:
 236+ if( $j( playerElement ).attr('id') =='' ){
 237+ $j( playerElement ).attr( "id", 'mwe_v' + ( index ) );
 238+ }
 239+
 240+ // If we are dynamically embedding on a "div" check if we can
 241+ // add a poster image behind the loader:
 242+ if( playerElement.nodeName.toLowerCase() == 'div'
 243+ && ( attributes.poster || $j(playerElement).attr( 'poster' ) ) ){
 244+ var posterSrc = ( attributes.poster ) ? attributes.poster : $j(playerElement).attr( 'poster' );
 245+
 246+ // Set image size:
 247+ var width = $j( playerElement ).width();
 248+ var height = $j( playerElement ).height();
 249+ if( !width ){
 250+ var width = ( attributes.width )? attributes.width : '100%';
 251+ }
 252+ if( !height ){
 253+ var height = ( attributes.height )? attributes.height : '100%';
 254+ }
 255+
 256+ mw.log('EmbedPlayer:: set loading background: ' + posterSrc);
 257+ $j( playerElement ).append(
 258+ $j( '<img />' )
 259+ .attr( 'src', posterSrc)
 260+ .css({
 261+ 'position' : 'absolute',
 262+ 'width' : width,
 263+ 'height' : height
 264+ })
 265+ )
 266+ }
 267+ });
 268+
274269 // If we have not detected browser plugin embed types do that now
275270 if( ! mw.EmbedTypes.players ){
276271 mw.EmbedTypes.init();
@@ -277,28 +272,36 @@
278273
279274 // Create the Global Embed Player Manager ( if not already created )
280275 if( ! mw.playerManager ) {
281 - mw.log( "Create the player manager:" );
 276+ mw.log( "EmbedPlayer::Create the player manager:" );
282277 mw.playerManager = new EmbedPlayerManager();
283278 // Run the global hooks that mw.playerManager is ready
284 - mw.log( 'trigger: EmbedPlayerManagerReady');
 279+ mw.log( 'EmbedPlayer::trigger: EmbedPlayerManagerReady');
285280 $j( mw ).trigger( 'EmbedPlayerManagerReady' );
286 - }
287 -
288 - // Add the embedPlayer ready callback
289 - if( typeof callback == 'function' ){
290 - mw.playerManager.addCallback( callback );
291 - }
 281+ }
 282+ var addedToPlayerManager = false;
292283 // Make sure we have user preference setup ( for setting preferences on video selection )
293 - mw.setupUserConfig( function() {
 284+ mw.setupUserConfig( function() {
 285+ mw.log("EmbedPlayer:: found: " + $j( playerSelect ).length + ' players ');
294286 // Add each selected element to the player manager:
295 - $j( playerSelect ).each( function( index, playerElement) {
296 - // make sure the video tag was not generated by our own native player:
 287+ $j( playerSelect ).each( function( index, playerElement) {
 288+ // Make sure the video tag was not generated by our library:
297289 if( $j( playerElement ).hasClass( 'nativeEmbedPlayerPid' ) ){
298 - mw.log( '$j.embedPlayer skip native player: ' + playerElement );
 290+ $j('#loadingSpinner_' + $j( playerElement ).attr('id') ).hide();
 291+ mw.log( 'EmbedPlayer::$j.embedPlayer skip embedPlayer gennerated video: ' + playerElement );
299292 } else {
 293+ addedToPlayerManager = true;
 294+ // Add the embedPlayer ready callback
 295+ mw.playerManager.addCallback( callback );
 296+ // Add the player
300297 mw.playerManager.addElement( playerElement, attributes);
301 - }
302 - } );
 298+ }
 299+
 300+ } );
 301+ // run the callback directly if no players were added to the playerManager
 302+ if( !addedToPlayerManager && callback ){
 303+ callback();
 304+ }
 305+
303306 })
304307 };
305308
@@ -318,6 +321,8 @@
319322 // Functions to run after the video interface is ready
320323 callbackFunctions : null,
321324
 325+ playerElementQueue: [],
 326+
322327 /**
323328 * Constructor initializes callbackFunctions and playerList
324329 */
@@ -333,7 +338,9 @@
334339 * @param {Function} callback Function to be called once players are ready
335340 */
336341 addCallback: function( callback ) {
337 - this.callbackFunctions.push( callback );
 342+ if( typeof callback == 'function' ){
 343+ this.callbackFunctions.push( callback );
 344+ }
338345 },
339346
340347 /**
@@ -369,82 +376,98 @@
370377 playerElement.id = 'vid' + ( this.playerList.length + 1 );
371378 }
372379 mw.log('EmbedPlayerManager: addElement:: ' + playerElement.id );
373 -
 380+
374381 // Add the element id to playerList
375382 this.playerList.push( playerElement.id );
376383
377384 // Check for player attributes such as skins or plugins attributes
378385 // that add to the request set
379 - var playerDependencyRequest = [ ];
 386+ var playerDependencyRequest = [];
380387
 388+ // merge in any custom attributes
 389+ $j.extend( playerElement, attributes );
 390+
381391 // Update the list of dependent libraries for the player
382392 // ( allows extensions to add to the dependency list )
383393 mw.embedPlayerUpdateLibraryRequest( playerElement, playerDependencyRequest );
384 -
 394+
385395 // Load any skins we need then swap in the interface
386 - mw.load( playerDependencyRequest, function() {
387 - // We should move all playlist handling to add-in
388 - switch( playerElement.tagName.toLowerCase() ) {
389 - case 'video':
390 - case 'audio':
391 - // By default treat the rewrite request as "video"
392 - default:
393 - var waitForMeta = true;
394 -
395 - // Let extensions determine if its worthwhile to wait for metadata:
396 - // We pass an object to the trigger to preserve reference values
397 - var eventObject = {
398 - 'playerElement':playerElement,
399 - 'waitForMeta' : waitForMeta
400 - }
401 -
402 - $j( mw ).trigger( 'addElementWaitForMetaEvent', eventObject );
403 - // update the waitForMeta
404 - waitForMeta = eventObject['waitForMeta'];
405 -
406 -
407 - // Set the wait for meta flag if unset by extension
408 - if( waitForMeta ){
409 - waitForMeta = _this.waitForMetaCheck( playerElement );
410 - }
 396+ mw.load( playerDependencyRequest, function() {
 397+ var waitForMeta = true;
411398
412 - var ranPlayerSwapFlag = false;
413 -
414 - // Local callback to runPlayer swap once playerElement has metadata
415 - function runPlayerSwap() {
416 - if( ranPlayerSwapFlag ){
417 - return ;
 399+ // Be sure to "stop" the target ( sometimes firefox keeps playing the video even
 400+ // though its been removed from the DOM )
 401+ if( playerElement.pause ){
 402+ playerElement.pause();
 403+ }
 404+
 405+
 406+ // Let extensions determine if its worthwhile to wait for metadata:
 407+ // We pass an object to the trigger to preserve reference values
 408+ var eventObject = {
 409+ 'playerElement' : playerElement,
 410+ 'waitForMeta' : waitForMeta
 411+ };
 412+ $j( mw ).trigger( 'addElementWaitForMetaEvent', eventObject );
 413+
 414+ // update the waitForMeta
 415+ waitForMeta = eventObject[ 'waitForMeta' ];
 416+
 417+
 418+ // Set the wait for meta flag if unset by extension
 419+ if( waitForMeta ){
 420+ waitForMeta = _this.waitForMetaCheck( playerElement );
 421+ }
 422+
 423+ var ranPlayerSwapFlag = false;
 424+
 425+ // Local callback to runPlayer swap once playerElement has metadata
 426+ function runPlayerSwap() {
 427+ if( ranPlayerSwapFlag ){
 428+ return ;
 429+ }
 430+ ranPlayerSwapFlag = true;
 431+ mw.log("EmbedPlayer::runPlayerSwap::" + $j( playerElement ).attr('id') );
 432+
 433+ var playerInterface = new mw.EmbedPlayer( playerElement , attributes);
 434+ var swapPlayer = _this.swapEmbedPlayerElement( playerElement, playerInterface );
 435+
 436+ // Copy over any data attributes from the playerElement
 437+ if( mw.getConfig( 'EmbedPlayer.DataAttributes' ) ) {
 438+ var dataAttr = mw.getConfig( 'EmbedPlayer.DataAttributes' )
 439+ for( var i in dataAttr ){
 440+ if( $j( playerElement ).data( i ) ){
 441+ $j( '#' + playerInterface.id ).data( i, $j( playerElement ).data( i ) );
418442 }
419 - mw.log("runPlayerSwap::" + $j( playerElement ).attr('id') );
420 - ranPlayerSwapFlag = true;
421 - var playerInterface = new mw.EmbedPlayer( playerElement , attributes);
422 -
423 - _this.swapEmbedPlayerElement( playerElement, playerInterface );
424 -
425 -
426 - // Pass the id to any hook that needs to interface prior to checkPlayerSources
427 - mw.log("addElement :: trigger :: newEmbedPlayerEvent");
428 - $j( mw ).trigger ( 'newEmbedPlayerEvent', playerInterface.id );
429 -
430 - // Issue the checkPlayerSources call to the new player interface:
431 - // make sure to use the element that is in the DOM:
432 - $j( '#' + playerInterface.id ).get(0).checkPlayerSources();
433443 }
434 -
435 - if( waitForMeta ) {
436 - mw.log('DO WaitForMeta ( video missing height (' + $j( playerElement ).attr('height') + '), width (' + $j( playerElement ).attr('width') + ') or duration' );
437 - playerElement.removeEventListener( "loadedmetadata", runPlayerSwap, true );
438 - playerElement.addEventListener( "loadedmetadata", runPlayerSwap, true );
439 -
440 - // Time-out of 5 seconds ( maybe still playable but no timely metadata )
441 - setTimeout( runPlayerSwap, 5000 );
442 - return ;
443 - } else {
444 - runPlayerSwap();
445 - return ;
446 - }
447 - break;
448 - }
 444+ }
 445+
 446+ // Pass the id to any hook that needs to interface prior to checkPlayerSources
 447+ mw.log("EmbedPlayer::addElement :trigger " + playerInterface.id );
 448+ $j( mw ).trigger ( 'newEmbedPlayerEvent', playerInterface.id );
 449+
 450+ // Issue the checkPlayerSources call to the new player interface:
 451+ // make sure to use the element that is in the DOM:
 452+ $j( '#' + playerInterface.id ).get(0).checkPlayerSources();
 453+ }
 454+
 455+ if( waitForMeta ) {
 456+ mw.log('EmbedPlayer::WaitForMeta ( video missing height (' +
 457+ $j( playerElement ).attr('height') + '), width (' +
 458+ $j( playerElement ).attr('width') + ') or duration: ' +
 459+ $j( playerElement ).attr('duration')
 460+ );
 461+
 462+ playerElement.removeEventListener( "loadedmetadata", runPlayerSwap, true );
 463+ playerElement.addEventListener( "loadedmetadata", runPlayerSwap, true );
 464+
 465+ // Time-out of 5 seconds ( maybe still playable but no timely metadata )
 466+ setTimeout( runPlayerSwap, 5000 );
 467+ return ;
 468+ } else {
 469+ runPlayerSwap();
 470+ return ;
 471+ }
449472 });
450473 },
451474
@@ -457,7 +480,8 @@
458481 */
459482 waitForMetaCheck: function( playerElement ){
460483 var waitForMeta = false;
461 -
 484+ if( !playerElement )
 485+ return ;
462486 // If we don't have a native player don't wait for metadata
463487 if( !mw.EmbedTypes.players.isSupportedPlayer( 'oggNative') &&
464488 !mw.EmbedTypes.players.isSupportedPlayer( 'h264Native' ) )
@@ -529,23 +553,25 @@
530554 * @param {Object} playerInterface Interface to swap into the target element
531555 */
532556 swapEmbedPlayerElement: function( targetElement, playerInterface ) {
533 - mw.log( 'swapEmbedPlayerElement: ' + targetElement.id );
 557+ mw.log( 'EmbedPlayer::swapEmbedPlayerElement: ' + targetElement.id );
534558 // Create a new element to swap the player interface into
535559 var swapPlayerElement = document.createElement('div');
536560
537 - // get properties / methods from playerInterface
 561+ // Get properties / methods from playerInterface
538562 for ( var method in playerInterface ) {
539563 if ( method != 'readyState' ) { // readyState crashes IE ( don't include )
540564 swapPlayerElement[ method ] = playerInterface[ method ];
541565 }
542566 }
 567+
543568 // Check if we are using native controls ( should keep the video embed around )
544 - // "wrap" the player interface
545 - if( playerInterface.useNativeControls() ) {
 569+ if( playerInterface.useNativePlayerControls() ) {
546570 $j( targetElement )
547 - .attr('id', playerInterface.pid )
 571+ .attr( 'id', playerInterface.pid )
 572+ .addClass( 'nativeEmbedPlayerPid' )
 573+ .show()
548574 .after(
549 - swapPlayerElement
 575+ $j( swapPlayerElement ).css( 'display', 'none' )
550576 )
551577 } else {
552578 $j( targetElement ).replaceWith( swapPlayerElement );
@@ -560,12 +586,18 @@
561587
562588 // If we don't already have a loadSpiner add one:
563589 if( $j('#loadingSpinner_' + playerInterface.id ).length == 0 ){
564 - $j( swapPlayerElement ).append(
565 - $j('<div />')
566 - .loadingSpinner()
567 - );
 590+ if( playerInterface.useNativePlayerControls() ) {
 591+ $j( targetElement )
 592+ .getAbsoluteOverlaySpinner()
 593+ .attr('id', 'loadingSpinner_' + playerInterface.id )
 594+ }else{
 595+ $j( swapPlayerElement ).append(
 596+ $j('<div />')
 597+ .loadingSpinner()
 598+ );
 599+ }
568600 }
569 - return true;
 601+ return swapPlayerElement;
570602 },
571603
572604
@@ -574,13 +606,13 @@
575607 * once players are "ready"
576608 *
577609 * This enables mw.ready event to expose video tag
578 - * elemetns as if the videotag was supported natively.
 610+ * elements as if the videotag was supported natively.
579611 *
580612 * @param {Object} player The EmbedPlayer object
581613 */
582614 playerReady: function( player ) {
583615 var _this = this;
584 - mw.log( 'ReadyToPlay callback player:' + player.id );
 616+ mw.log( 'EmbedPlayer::ReadyToPlay callback player:' + player.id );
585617 player.readyToPlay = true;
586618
587619 // Remove the player loader spinner:
@@ -601,10 +633,10 @@
602634 // Be sure to remove any player loader spinners
603635 $j('.playerLoadingSpinner').remove();
604636
605 - mw.log( "All on-page players ready run playerMannager callbacks" );
 637+ mw.log( "EmbedPlayer::All on-page players ready run playerMannager callbacks" );
606638 // Run queued functions
607639 if( _this.callbackFunctions ) {
608 - while ( _this.callbackFunctions.length ) {
 640+ while ( _this.callbackFunctions.length ) {
609641 _this.callbackFunctions.shift()();
610642 }
611643 }
@@ -665,7 +697,7 @@
666698 * MediaSource constructor:
667699 */
668700 init : function( element ) {
669 - // mw.log('adding mediaSource: ' + element);
 701+ // mw.log('EmbedPlayer::adding mediaSource: ' + element);
670702 this.src = $j( element ).attr( 'src' );
671703
672704 // Set default URLTimeEncoding if we have a time url:
@@ -784,11 +816,11 @@
785817 },
786818
787819 /** URI function.
788 - * @param {Number} seek_time_sec Int: Used to adjust the URI for url based seeks)
 820+ * @param {Number} serverSeekTime Int: Used to adjust the URI for url based seeks)
789821 * @return {String} the URI of the source.
790822 */
791 - getSrc : function( seek_time_sec ) {
792 - if ( !seek_time_sec || !this.URLTimeEncoding ) {
 823+ getSrc : function( serverSeekTime ) {
 824+ if ( !serverSeekTime || !this.URLTimeEncoding ) {
793825 return this.src;
794826 }
795827 var endvar = '';
@@ -797,7 +829,7 @@
798830 }
799831 return mw.replaceUrlParams( this.src,
800832 {
801 - 't': mw.seconds2npt( seek_time_sec ) + endvar
 833+ 't': mw.seconds2npt( serverSeekTime ) + endvar
802834 }
803835 );
804836 },
@@ -825,6 +857,12 @@
826858 case 'audio/ogg' :
827859 return gM( 'mwe-embedplayer-video-audio' );
828860 break;
 861+ case 'video/mpeg' :
 862+ return 'MPEG video'; // FIXME: i18n
 863+ break;
 864+ case 'video/x-msvideo' :
 865+ return 'AVI video'; // FIXME: i18n
 866+ break;
829867 }
830868
831869 // Return tilte based on file name:
@@ -837,13 +875,6 @@
838876 return this.mimeType;
839877 },
840878
841 - /** Index accessor function.
842 - * @return {Integer} the source's index within the enclosing mediaElement container.
843 - */
844 - getIndex : function() {
845 - return this.index;
846 - },
847 -
848879 /**
849880 *
850881 * Get Duration of the media in milliseconds from the source url.
@@ -893,6 +924,9 @@
894925 case '.mp4':
895926 return 'video/h264';
896927 break;
 928+ case 'webm':
 929+ return 'video/webm';
 930+ break;
897931 case '.srt':
898932 return 'text/x-srt';
899933 break;
@@ -912,6 +946,15 @@
913947 case '.xml':
914948 return 'text/xml';
915949 break;
 950+ case '.avi':
 951+ return 'video/x-msvideo';
 952+ break;
 953+ case '.mpg':
 954+ return 'video/mpeg';
 955+ break;
 956+ case '.mpeg':
 957+ return 'video/mpeg';
 958+ break;
916959 }
917960 }
918961 };
@@ -955,18 +998,19 @@
956999 * @param {Element} videoElement Element that has src attribute or has children source elements
9571000 */
9581001 init: function( videoElement ) {
959 - var _this = this;
960 - mw.log( videoElement.id + ' Initializing mediaElement...' );
 1002+ var _this = this;
 1003+ mw.log( "EmbedPlayer::mediaElement:init:" + videoElement.id );
9611004 this.sources = new Array();
9621005
9631006 // Process the videoElement as a source element:
9641007 if ( $j( videoElement ).attr( "src" ) ) {
9651008 _this.tryAddSource( videoElement );
9661009 }
967 -
 1010+
 1011+ // Process elements source children
9681012 $j( videoElement ).find( 'source,track' ).each( function( ) {
9691013 _this.tryAddSource( this );
970 - } );
 1014+ } );
9711015 },
9721016
9731017 /**
@@ -989,7 +1033,7 @@
9901034 */
9911035 textSourceExists: function() {
9921036 for ( var i = 0; i < this.sources.length; i++ ) {
993 - mw.log( this.sources[i].mimeType );
 1037+ mw.log('EmbedPlayer::textSourceExists:'+ this.sources[i].mimeType );
9941038 if ( this.sources[i].mimeType == 'text/cmml' ||
9951039 this.sources[i].mimeType == 'text/x-srt' )
9961040 {
@@ -1041,7 +1085,7 @@
10421086 * @param {Number} index Index of source element to set as selectedSource
10431087 */
10441088 selectSource:function( index ) {
1045 - mw.log( 'f:selectSource:' + index );
 1089+ mw.log( 'EmbedPlayer::mediaElement:selectSource:' + index );
10461090 var playableSources = this.getPlayableSources();
10471091 for ( var i = 0; i < playableSources.length; i++ ) {
10481092 if ( i == index ) {
@@ -1056,8 +1100,8 @@
10571101 /**
10581102 * Selects the default source via cookie preference, default marked, or by id order
10591103 */
1060 - autoSelectSource: function() {
1061 - mw.log( 'f:autoSelectSource:' );
 1104+ autoSelectSource: function() {
 1105+ mw.log( 'EmbedPlayer::mediaElement::autoSelectSource:' + this.id);
10621106 // Select the default source
10631107 var playableSources = this.getPlayableSources();
10641108 var flash_flag = ogg_flag = false;
@@ -1066,7 +1110,7 @@
10671111 for ( var source = 0; source < playableSources.length; source++ ) {
10681112 var mimeType = playableSources[source].mimeType;
10691113 if ( mw.EmbedTypes.players.preference[ 'format_preference' ] == mimeType ) {
1070 - mw.log( 'set via preference: ' + playableSources[source].mimeType );
 1114+ mw.log( 'Set via preference: ' + playableSources[source].mimeType );
10711115 this.selectedSource = playableSources[source];
10721116 return true;
10731117 }
@@ -1075,18 +1119,18 @@
10761120 // Set via marked default:
10771121 for ( var source = 0; source < playableSources.length; source++ ) {
10781122 if ( playableSources[ source ].markedDefault ) {
1079 - mw.log( 'set via marked default: ' + playableSources[source].markedDefault );
 1123+ mw.log( 'Set via marked default: ' + playableSources[source].markedDefault );
10801124 this.selectedSource = playableSources[source];
10811125 return true;
10821126 }
10831127 }
10841128
1085 - // Set native client for flash
 1129+ // Prefer native playback
10861130 for ( var source = 0; source < playableSources.length; source++ ) {
10871131 var mimeType = playableSources[source].mimeType;
10881132 var player = mw.EmbedTypes.players.defaultPlayer( mimeType );
1089 - mw.log( 'f:autoSelectSource:' + mimeType );
1090 - if ( this.isOgg( mimeType ) && player && player.library == 'Native' ) {
 1133+ if ( player && player.library == 'Native' ) {
 1134+ mw.log('Set native playback');
10911135 this.selectedSource = playableSources[ source ];
10921136 return true;
10931137 }
@@ -1103,7 +1147,8 @@
11041148 ||
11051149 player.library == 'Kplayer'
11061150 )
1107 - ) {
 1151+ ) {
 1152+ mw.log('Set h264 via native or flash fallback');
11081153 this.selectedSource = playableSources[ source ];
11091154 return true;
11101155 }
@@ -1197,7 +1242,7 @@
11981243 /**
11991244 * Get playable sources
12001245 *
1201 - * @returns {Array} of playbale sources
 1246+ * @returns {Array} of playable sources
12021247 */
12031248 getPlayableSources: function() {
12041249 var playableSources = [];
@@ -1216,7 +1261,7 @@
12171262 * @param roe_data ROE data.
12181263 */
12191264 addROE: function( roe_data ) {
1220 - mw.log( 'f:addROE' );
 1265+ mw.log( 'EmbedPlayer::mediaElement:addROE' );
12211266 this.addedROEData = true;
12221267 var _this = this;
12231268 if ( roe_data ) {
@@ -1291,7 +1336,7 @@
12921337 'cmmlData': null,
12931338
12941339 // Stores the seek time request, Updated by the doSeek function
1295 - 'seek_time_sec' : 0,
 1340+ 'serverSeekTime' : 0,
12961341
12971342 // If the embedPlayer is current 'seeking'
12981343 'seeking' : false,
@@ -1316,34 +1361,38 @@
13171362 * @param {Object} customAttributes Attributes supplied via argument (rather than applied to the element)
13181363 */
13191364 init: function( element, customAttributes ) {
1320 - var _this = this;
 1365+ var _this = this;
13211366 // Set customAttributes if unset:
13221367 if ( !customAttributes ) {
13231368 customAttributes = { };
13241369 }
13251370
1326 - var playerAttributes = mw.getConfig( 'embedPlayerAttributes' );
1327 -
1328 - // Setup the player Interface from supported attributes:
 1371+ var playerAttributes = mw.getConfig( 'EmbedPlayer.Attributes' );
 1372+ // Setup the player Interface from supported attributes:
13291373 for ( var attr in playerAttributes ) {
13301374 if ( customAttributes[ attr ] || customAttributes[ attr ] === false ) {
13311375 this[ attr ] = customAttributes[ attr ];
1332 - } else if ( element.getAttribute( attr ) ) {
1333 - this[ attr ] = element.getAttribute( attr );
 1376+ } else if ( element.getAttribute( attr ) != null ) {
 1377+ // boolean attributes
 1378+ if( element.getAttribute( attr ) == '' ){
 1379+ this[ attr ] = true;
 1380+ } else {
 1381+ this[ attr ] = element.getAttribute( attr );
 1382+ }
13341383 } else {
13351384 this[attr] = playerAttributes[attr];
13361385 }
13371386 // string -> boolean
13381387 if( this[ attr ] == "false" ) this[attr] = false;
13391388 if( this[ attr ] == "true" ) this[attr] = true;
1340 - }
 1389+ }
13411390
13421391 if( this.apiTitleKey ){
13431392 this.apiTitleKey = unescape( this.apiTitleKey );
13441393 }
13451394
13461395 // Hide "controls" if using native player controls:
1347 - if( this.useNativeControls() ){
 1396+ if( this.useNativePlayerControls() ){
13481397 _this.controls = false;
13491398 }
13501399
@@ -1368,10 +1417,13 @@
13691418
13701419 // Set the default skin if unset:
13711420 if ( !this.skinName ) {
1372 - this.skinName = mw.getConfig( 'playerSkinName' );
 1421+ this.skinName = mw.getConfig( 'EmbedPlayer.SkinName' );
13731422 }
1374 -
13751423
 1424+ if( !this.monitorRate ){
 1425+ this.monitorRate = mw.getConfig( 'EmbedPlayer.MonitorRate' );
 1426+ }
 1427+
13761428 // Make sure startOffset is cast as an float:
13771429 if ( this.startOffset && this.startOffset.split( ':' ).length >= 2 ) {
13781430 this.startOffset = parseFloat( mw.npt2seconds( this.startOffset ) );
@@ -1393,11 +1445,11 @@
13941446
13951447 // Make sure duration is a float:
13961448 this.duration = parseFloat( this.duration );
1397 - mw.log( this.id + " duration is: " + this.duration );
 1449+ mw.log( 'EmbedPlayer::mediaElement:' + this.id + " duration is: " + this.duration );
13981450
13991451 // Set the player size attributes based loaded video element:
14001452 this.setPlayerSize( element );
1401 -
 1453+
14021454 // Set the plugin id
14031455 this.pid = 'pid_' + this.id;
14041456
@@ -1410,7 +1462,25 @@
14111463
14121464 // Add the mediaElement object with the elements sources:
14131465 this.mediaElement = new mediaElement( element );
1414 -
 1466+
 1467+ // Process attribute "sources" for dynamic embedding
 1468+ if( customAttributes.sources && customAttributes.sources.length ){
 1469+ for( var i =0; i < customAttributes.sources.length ; i ++ ){
 1470+ var customSource = customAttributes.sources[i];
 1471+ if( customSource.src ){
 1472+ var $source = $j('<source />')
 1473+ .attr( 'src', customSource.src );
 1474+ // xxx todo pull list of valid source attributes from mediaSource prototype
 1475+ if( customSource.type ){
 1476+ $source.attr('type', customSource.type )
 1477+ }
 1478+ if( customSource.title ){
 1479+ $source.attr('title', customSource.title );
 1480+ }
 1481+ this.mediaElement.tryAddSource( $source.get(0) );
 1482+ }
 1483+ }
 1484+ }
14151485 },
14161486
14171487 /**
@@ -1430,55 +1500,75 @@
14311501 */
14321502 setPlayerSize: function( element ) {
14331503
1434 - this['height'] = parseInt( $j(element).css( 'height' ) );
1435 - this['width'] = parseInt( $j(element).css( 'width' ) );
 1504+ this.height = parseInt( $j(element).css( 'height' ) );
 1505+ this.width = parseInt( $j(element).css( 'width' ) );
14361506
1437 - if( !this['height'] && !this['width'] ) {
1438 - this['height'] = parseInt( $j(element).attr( 'height' ) );
1439 - this['width'] = parseInt( $j(element).attr( 'width' ) );
 1507+ if( !this.height && !this.width ) {
 1508+ this.height = parseInt( $j(element).attr( 'height' ) );
 1509+ this.width = parseInt( $j(element).attr( 'width' ) );
14401510 }
14411511
14421512 // Special case for audio
14431513 // Firefox sets audio height to "0px" while webkit uses 32px .. force zero:
1444 - if( element.tagName.toLowerCase() == 'audio' && this['height'] == '32') {
1445 - this['height'] = 0;
 1514+ if( element.tagName.toLowerCase() == 'audio' && this.height == '32' ) {
 1515+ this.height = 0;
14461516 }
14471517
14481518 // Use default aspect ration to get height or width ( if rewriting a non-audio player )
1449 - if( element.tagName.toLowerCase() != 'audio' ) {
1450 - if( this['height'] && !this['width'] && this.videoAspect ) {
1451 - var aspect = this.videoAspect.split( ':' );
1452 - this['width'] = parseInt( this.height * ( aspect[0] / aspect[1] ) );
 1519+ if( element.tagName.toLowerCase() != 'audio' && this.videoAspect ) {
 1520+ var aspect = this.videoAspect.split( ':' );
 1521+ if( this.height && !this.width ) {
 1522+ this.width = parseInt( this.height * ( aspect[0] / aspect[1] ) );
 1523+ }
 1524+ if( this.width && !this.height ) {
 1525+ var apectRatio = ( aspect[1] / aspect[0] );
 1526+ this.height = parseInt( this.width * ( aspect[1] / aspect[0] ) );
14531527 }
1454 -
1455 - if( this['width'] && !this['height'] && this.videoAspect ) {
1456 - var aspect = this.videoAspect.split( ':' );
1457 - this['height'] = parseInt( this.width * ( aspect[1] / aspect[0] ) );
1458 - }
14591528 }
14601529
14611530 // On load sometimes attr is temporally -1 as we don't have video metadata yet.
14621531 // or in IE we get NaN for width height
14631532 //
14641533 // NOTE: browsers that do support height width should set "waitForMeta" flag in addElement
1465 - if( ( isNaN( this['height'] ) && isNaN( this['width'] ) ) ||
1466 - ( this['height'] == -1 || this['width'] == -1 ) ||
 1534+ if( ( isNaN( this.height ) && isNaN( this.width ) ) ||
 1535+ ( this.height == -1 || this.width == -1 ) ||
14671536 // Check for firefox defaults
14681537 // Note: ideally firefox would not do random guesses at css values
14691538 ( (this.height == 150 || this.height == 64 ) && this.width == 300 )
14701539 ) {
1471 - var defaultSize = mw.getConfig( 'videoSize' ).split( 'x' );
1472 - this['width'] = defaultSize[0];
 1540+ var defaultSize = mw.getConfig( 'EmbedPlayer.DefaultSize' ).split( 'x' );
 1541+ this.width = defaultSize[0];
14731542
14741543 // Special height default for audio tag ( if not set )
14751544 if( element.tagName.toLowerCase() == 'audio' ) {
1476 - this['height'] = 0;
 1545+ this.height = 0;
14771546 }else{
1478 - this['height'] = defaultSize[1];
 1547+ this.height = defaultSize[1];
14791548 }
14801549 }
14811550
14821551 },
 1552+ /**
 1553+ * Resize the player to a new size
 1554+ */
 1555+ resizePlayer: function( size , animate){
 1556+ mw.log("EmbedPlayer::resizePlayer:" + size.width + ' x ' + size.height );
 1557+ this.width = size.width;
 1558+ this.height = size.height;
 1559+ var playerSize = {'width' : this.width, 'height' : this.height };
 1560+ // check if height needs to include interface contorls
 1561+ if( ! this.controlBuilder.checkOverlayControls() ){
 1562+ size.height = size.height + this.controlBuilder.height;
 1563+ }
 1564+
 1565+ if( animate ){
 1566+ $j(this).animate(playerSize);
 1567+ this.$interface.animate( size );
 1568+ }else{
 1569+ $j(this).css(playerSize);
 1570+ this.$interface.css( size );
 1571+ }
 1572+ },
14831573
14841574 /**
14851575 * Get the player pixel width not including controls
@@ -1504,21 +1594,22 @@
15051595 * that request is issued here
15061596 */
15071597 checkPlayerSources: function() {
1508 - mw.log( 'f:checkPlayerSources: ' + this.id );
 1598+ mw.log( 'EmbedPlayer::checkPlayerSources: ' + this.id );
15091599 var _this = this;
15101600
15111601 // Scope the end of check for player sources so it can be called in a callback
15121602 var finishCheckPlayerSources = function(){
15131603 // Run embedPlayer sources hook
1514 - mw.runTriggersCallback( _this, 'checkPlayerSourcesEvent', function(){
 1604+ mw.runTriggersCallback( _this, 'checkPlayerSourcesEvent', function(){
15151605 _this.checkForTimedText();
1516 - })
1517 - }
 1606+ });
 1607+ };
15181608
1519 - // NOTE: Should could be moved to mediaWiki Api support module
1520 - if ( _this.apiTitleKey ) {
 1609+ // NOTE: Should could be moved to mediaWiki Api support module
 1610+ // only load from api if sources are empty:
 1611+ if ( _this.apiTitleKey && this.mediaElement.sources.length == 0) {
15211612 // Load media from external data
1522 - mw.log( 'checkPlayerSources: loading apiTitleKey data' );
 1613+ mw.log( 'EmbedPlayer::checkPlayerSources: loading apiTitleKey:' + _this.apiTitleKey );
15231614 _this.loadSourceFromApi( function(){
15241615 finishCheckPlayerSources();
15251616 } );
@@ -1527,9 +1618,19 @@
15281619 finishCheckPlayerSources();
15291620 }
15301621 },
 1622+ /**
 1623+ * Insert and play a video source ( useful for ads or bumper videos )
 1624+ *
 1625+ * Only works while video is in active play back.
 1626+ * Only tested with native playback atm.
 1627+ */
 1628+ insertAndPlaySource: function( source ){
 1629+ mw.log("Error: only native playback supports insertAndPlaySource right now");
 1630+ },
15311631
15321632 /**
15331633 * Load Source video info from mediaWiki Api title key ( this.apiTitleKey )
 1634+ * @@todo move this to mediaWiki 'api' module
15341635 * @param {Function} callback Function called once loading is complete
15351636 */
15361637 loadSourceFromApi: function( callback ){
@@ -1541,7 +1642,7 @@
15421643
15431644 // Set local apiProvider via config if not defined
15441645 if( !_this.apiProvider ) {
1545 - _this.apiProvider = mw.getConfig( 'apiProvider' );
 1646+ _this.apiProvider = mw.getConfig( 'EmbedPlayer.ApiProvider' );
15461647 }
15471648
15481649 // Setup the request
@@ -1552,10 +1653,10 @@
15531654 'iiprop': 'url|size|dimensions|metadata',
15541655 'iiurlwidth': _this.width,
15551656 'redirects' : true // automatically resolve redirects
1556 - }
1557 -
 1657+ };
 1658+
15581659 // Run the request:
1559 - mw.getJSON( mw.getApiProviderURL( this.apiProvider ), request, function( data ){
 1660+ mw.getJSON( mw.getApiProviderURL( _this.apiProvider ), request, function( data ){
15601661 if ( data.query.pages ) {
15611662 for ( var i in data.query.pages ) {
15621663 if( i == '-1' ) {
@@ -1625,7 +1726,7 @@
16261727 */
16271728 checkForTimedText: function( ) {
16281729 var _this = this;
1629 - mw.log( 'checkForTimedText: ' + _this.id + " height: " + this.height );
 1730+ mw.log( 'EmbedPlayer::checkForTimedText: ' + _this.id + " height: " + this.height );
16301731 // Check for timedText support
16311732 if( this.isTimedTextSupported() ) {
16321733 mw.load( 'TimedText', function() {
@@ -1645,7 +1746,7 @@
16461747 * Sets load error if no source is playable
16471748 */
16481749 setupSourcePlayer: function() {
1649 - mw.log("setupSourcePlayer: " + this.id );
 1750+ mw.log("EmbedPlayer::setupSourcePlayer: " + this.id );
16501751 // Autoseletct the media source
16511752 this.mediaElement.autoSelectSource();
16521753
@@ -1684,6 +1785,9 @@
16851786
16861787 mw.log( 'No player found for given source type ' + missingType );
16871788 this.showPluginMissingHTML( missingType );
 1789+
 1790+ // Call the global player manager to inform this video interface is "ready" for page callback to be proccessed.
 1791+ mw.playerManager.playerReady( this );
16881792 }
16891793 },
16901794
@@ -1693,7 +1797,7 @@
16941798 * @param {Function} callback Function to be called once playback-system has been inherited
16951799 */
16961800 inheritEmbedPlayer: function( callback ) {
1697 - mw.log( "inheritEmbedPlayer:duration is: " + this.getDuration() + ' p: ' + this.id );
 1801+ mw.log( "EmbedPlayer::inheritEmbedPlayer:duration is: " + this.getDuration() + ' p: ' + this.id );
16981802
16991803 // Clear out any non-base embedObj methods:
17001804 if ( this.instanceOf ) {
@@ -1708,12 +1812,12 @@
17091813 }
17101814
17111815 // Set up the new embedObj
1712 - mw.log( 'f: inheritEmbedPlayer: embedding with ' + this.selectedPlayer.library );
 1816+ mw.log( 'EmbedPlayer::inheritEmbedPlayer: embedding with ' + this.selectedPlayer.library );
17131817 var _this = this;
17141818
17151819 // Load the selected player
17161820 this.selectedPlayer.load( function() {
1717 - mw.log( 'EmbedPlayer:: ' + _this.selectedPlayer.library + " player loaded for " + _this.id );
 1821+ mw.log( 'EmbedPlayer::inheritEmbedPlayer ' + _this.selectedPlayer.library + " player loaded for " + _this.id );
17181822
17191823 // Get embed library player Interface
17201824 var playerInterface = mw[ 'EmbedPlayer' + _this.selectedPlayer.library ];
@@ -1750,8 +1854,10 @@
17511855 selectPlayer: function( player ) {
17521856 var _this = this;
17531857 if ( this.selectedPlayer.id != player.id ) {
1754 - this.selectedPlayer = player;
 1858+ this.selectedPlayer = player;
17551859 this.inheritEmbedPlayer( function(){
 1860+ // Hide / remove track container
 1861+ _this.$interface.find( '.track' ).remove();
17561862 // We have to re-bind hoverIntent ( has to happen in this scope )
17571863 if( _this.controls && _this.controlBuilder.checkOverlayControls() ){
17581864 _this.controlBuilder.showControlBar();
@@ -1775,7 +1881,7 @@
17761882 *
17771883 * @return start_npt and end_npt time if present
17781884 */
1779 - getTimeRange: function() {
 1885+ getTimeRange: function() {
17801886 var end_time = (this.controlBuilder.longTimeDisp)? '/' + mw.seconds2npt( this.getDuration() ) : '';
17811887 var default_time_range = '0:00:00' + end_time;
17821888 if ( !this.mediaElement )
@@ -1823,7 +1929,8 @@
18241930 },
18251931
18261932 /**
1827 - * Seek function (should be implemented by embed player interface )
 1933+ * Seek function ( should be implemented by embedPlayer interface playerNative, playerKplayer etc. )
 1934+ * embedPlayer doSeek only handles URL time seeks
18281935 */
18291936 doSeek: function( percent ) {
18301937 var _this = this;
@@ -1832,19 +1939,22 @@
18331940 // Run the seeking hook
18341941 $j( this.embedPlayer ).trigger( 'onSeek' );
18351942
1836 - // See if we should do a server side seek ( player idepenent )
1837 - if ( this.supportsURLTimeEncoding() ) {
1838 - // Make sure this.seek_time_sec is up-to-date:
1839 - this.seek_time_sec = mw.npt2seconds( this.start_npt ) + parseFloat( percent * this.getDuration() );
1840 - mw.log( 'updated seek_time_sec: ' + mw.seconds2npt ( this.seek_time_sec ) );
 1943+ // See if we should do a server side seek ( player independent )
 1944+ if ( this.supportsURLTimeEncoding() ) {
 1945+ mw.log( 'EmbedPlayer::doSeek:: updated serverSeekTime: ' + mw.seconds2npt ( this.serverSeekTime ) );
18411946 this.stop();
18421947 this.didSeekJump = true;
 1948+ // Make sure this.serverSeekTime is up-to-date:
 1949+ this.serverSeekTime = mw.npt2seconds( this.start_npt ) + parseFloat( percent * this.getDuration() );
18431950 // Update the slider
1844 - this.updatePlayHead( percent );
1845 - }
 1951+ this.updatePlayHead( percent );
 1952+ }
 1953+
18461954 // Do play request in 100ms ( give the dom time to swap out the embed player )
1847 - setTimeout( function() {
 1955+ setTimeout( function() {
 1956+ _this.seeking = false;
18481957 _this.play()
 1958+ _this.monitor();
18491959 }, 100 );
18501960
18511961 // Run the onSeeking interface update
@@ -1859,91 +1969,47 @@
18601970 */
18611971 setCurrentTime: function( time, callback ) {
18621972 mw.log( 'Error: base embed setCurrentTime can not frame serve (override via plugin)' );
1863 - },
 1973+ },
18641974
18651975 /**
1866 - * Setup the embed player
1867 - * issues a loading request
1868 - */
1869 - doEmbedPlayer: function() {
1870 - mw.log( 'EmbedPlayer :: doEmbedPlayer::' + this.selectedPlayer.id );
1871 - //mw.log( 'thum disp:' + this.thumbnail_disp );
1872 - var _this = this;
1873 -
1874 - var doEmbedPlayerLocal = function(){
1875 - // Set "loading" here ( if displaying controls )
1876 - if( ! _this.useNativeControls() ){
1877 - $j( _this ).html(
1878 - $j( '<div />' )
1879 - .css({
1880 - 'color' : 'black',
1881 - 'width' : _this.width + 'px',
1882 - 'height' : _this.height + 'px'
1883 - })
1884 - );
1885 - }
1886 -
1887 - // Reset some play state flags:
1888 - _this.bufferStartFlag = false;
1889 - _this.bufferEndFlag = false;
1890 -
1891 - // Make sure the player is
1892 - mw.log( 'performing embed for ' + _this.id );
1893 - };
1894 -
1895 - // If no binded events, run the local doEmbedPlayer function directly:
1896 - if( $j( this ).data('events').length == 0 ){
1897 - doEmbedPlayerLocal();
1898 - } else {
1899 - // Trigger the doEmbedPlayer event / hook with callback
1900 - $j( this ).trigger( 'doEmbedPlayerEvent', function(){
1901 - //done
1902 - doEmbedPlayerLocal();
1903 - });
1904 - }
1905 -
1906 - // mw.log('should embed:' + embed_code);
1907 - _this.doEmbedHTML()
1908 - },
1909 -
1910 -
1911 -
1912 - /**
19131976 * On clip done action. Called once a clip is done playing
19141977 */
19151978 onClipDone: function() {
1916 - mw.log( 'base:onClipDone ::' + this.id + ' doneCount:' + this.donePlayingCount );
 1979+ mw.log( 'EmbedPlayer::onClipDone:' + this.id + ' doneCount:' + this.donePlayingCount + ' stop state:' +this.isStopped() );
19171980 var _this = this;
1918 -
1919 -
1920 - // Only run stoped once:
1921 - if( !this.isStoped() ){
 1981+
 1982+ // Only run stopped once:
 1983+ if( !this.isStopped() ){
19221984 // Stop the monitor:
19231985 this.stopMonitor();
19241986
 1987+ // Show the control bar:
 1988+ this.controlBuilder.showControlBar();
 1989+
19251990 // Update the clip done playing count:
19261991 this.donePlayingCount ++;
19271992
19281993 // Fire the html5 ended binding
1929 - mw.log( "ended" );
19301994 var onDoneActionObject = {
19311995 'runBaseControlDone' : true
19321996 }
19331997
1934 - // run the ended trigger ( allow the ended object to prevent default actions )
 1998+ // Run the ended trigger ( allow the ended object to prevent default actions )
 1999+ mw.log("EmbedPlayer::onClipDone:Trigger ended");
19352000 $j( this ).trigger( 'ended', onDoneActionObject );
19362001
19372002 if( onDoneActionObject.runBaseControlDone ){
19382003
19392004 // Check if we have the "loop" property set
19402005 if( this.loop ) {
 2006+ this.stop();
19412007 this.play();
19422008 return;
19432009 }
19442010
19452011 // Stop the clip (load the thumbnail etc)
19462012 this.stop();
1947 - this.seek_time_sec = 0;
 2013+ this.serverSeekTime = 0;
19482014 this.updatePlayHead( 0 );
19492015
19502016 // Make sure we are not in preview mode( no end clip actions in preview mode)
@@ -1964,7 +2030,7 @@
19652031 */
19662032 showThumbnail: function() {
19672033 var _this = this;
1968 - mw.log( 'f:showThumbnail' + this.thumbnail_disp );
 2034+ mw.log( 'EmbedPlayer::showThumbnail' + this.thumbnail_disp );
19692035
19702036 // Close Menu Overlay:
19712037 this.controlBuilder.closeMenuOverlay();
@@ -1978,7 +2044,7 @@
19792045 this.controlBuilder.addControlBindings();
19802046
19812047 // Once the thumbnail is shown run the mediaReady trigger (if not using native controls)
1982 - if( !this.useNativeControls() ){
 2048+ if( !this.useNativePlayerControls() ){
19832049 mw.log("mediaLoaded");
19842050 $j( this ).trigger( 'mediaLoaded' );
19852051 }
@@ -1993,13 +2059,13 @@
19942060 // Set-up the local controlBuilder instance:
19952061 this.controlBuilder = new mw.PlayerControlBuilder( this );
19962062 var _this = this;
1997 - // Make sure we have interface_wrap
1998 - if( $j( this ).parent( '.interface_wrap' ).length == 0 ) {
 2063+ // Make sure we have mwplayer_interface
 2064+ if( $j( this ).parent( '.mwplayer_interface' ).length == 0 ) {
19992065 // Select "player"
20002066 $j( this )
20012067 .wrap(
20022068 $j('<div>')
2003 - .addClass( 'interface_wrap ' + this.controlBuilder.playerClass )
 2069+ .addClass( 'mwplayer_interface ' + this.controlBuilder.playerClass )
20042070 .css({
20052071 'width' : parseInt( this.width ) + 'px',
20062072 'height' : parseInt( this.height ) + 'px',
@@ -2008,8 +2074,8 @@
20092075 )
20102076 }
20112077
2012 - //Set up local jQuery object reference to "interface_wrap"
2013 - this.$interface = $j( this ).parent( '.interface_wrap' );
 2078+ //Set up local jQuery object reference to "mwplayer_interface"
 2079+ this.$interface = $j( this ).parent( '.mwplayer_interface' );
20142080
20152081 // Update Thumbnail for the "player"
20162082 this.updatePosterHTML();
@@ -2024,7 +2090,7 @@
20252091 }
20262092
20272093 if ( this.autoplay ) {
2028 - mw.log( 'showPlayer::activating autoplay' );
 2094+ mw.log( 'EmbedPlayer::showPlayer::activating autoplay' );
20292095 // Issue a non-blocking play request
20302096 setTimeout(function(){
20312097 _this.play();
@@ -2047,7 +2113,9 @@
20482114 $j( '#' + this.pid ).hide()
20492115 }
20502116 if( this.mediaElement.sources.length == 0 ){
2051 - $j( this ).html(
 2117+ // hide the pid if present:
 2118+ $j( '#pid_' + this.id ).hide();
 2119+ $j( this ).show().html(
20522120 $j('<span />').text(
20532121 gM('mwe-embedplayer-missing-source')
20542122 )
@@ -2083,7 +2151,7 @@
20842152 * @param {String} time_req
20852153 */
20862154 updateVideoTimeReq: function( time_req ) {
2087 - mw.log( 'f:updateVideoTimeReq' );
 2155+ mw.log( 'EmbedPlayer::updateVideoTimeReq:' + time_req );
20882156 var time_parts = time_req.split( '/' );
20892157 this.updateVideoTime( time_parts[0], time_parts[1] );
20902158 },
@@ -2106,9 +2174,9 @@
21072175
21082176 // reset seek_offset:
21092177 if ( this.mediaElement.selectedSource.URLTimeEncoding ) {
2110 - this.seek_time_sec = 0;
 2178+ this.serverSeekTime = 0;
21112179 } else {
2112 - this.seek_time_sec = mw.npt2seconds( start_npt );
 2180+ this.serverSeekTime = mw.npt2seconds( start_npt );
21132181 }
21142182 },
21152183
@@ -2116,7 +2184,7 @@
21172185 * Render a thumbnail at a given time
21182186 * NOTE: Should overwrite by embed library if we can render frames natively
21192187 *
2120 - * @param {Object} options Options for rendred timeline thumb
 2188+ * @param {Object} options Options for rendered timeline thumb
21212189 */
21222190 renderTimelineThumbnail: function( options ) {
21232191 var my_thumb_src = this.mediaElement.getPosterSrc();
@@ -2248,13 +2316,13 @@
22492317 * download, and embed code.
22502318 */
22512319 updatePosterHTML: function () {
2252 - mw.log( 'embedPlayer:updatePosterHTML::' + this.id );
 2320+ mw.log( 'EmbedPlayer:updatePosterHTML::' + this.id );
22532321 var thumb_html = '';
22542322 var class_atr = '';
22552323 var style_atr = '';
22562324
22572325
2258 - if( this.useNativeControls() ){
 2326+ if( this.useNativePlayerControls() ){
22592327 this.showNativePlayer();
22602328 return ;
22612329 }
@@ -2295,12 +2363,16 @@
22962364 * @returns boolean true if the mwEmbed player interface should be used
22972365 * false if the mwEmbed player interface should not be used
22982366 */
2299 - useNativeControls: function() {
2300 - if( mw.getConfig('nativePlayerControls') == true ) {
 2367+ useNativePlayerControls: function() {
 2368+ if( this.usenativecontrols === true ){
23012369 return true;
23022370 }
2303 - if( mw.getConfig('nativePlayerControlsMobileSafari' ) &&
2304 - mw.isMobileSafari()
 2371+
 2372+ if( mw.getConfig('EmbedPlayer.NativeControls') === true ) {
 2373+ return true;
 2374+ }
 2375+ if( mw.getConfig('EmbedPlayer.NativeControlsMobileSafari' ) &&
 2376+ mw.isMobileHTML5()
23052377 ){
23062378 return true;
23072379 }
@@ -2323,57 +2395,80 @@
23242396 // Remove the player loader spinner if it exists
23252397 $j('#loadingSpinner_' + this.id ).remove();
23262398
 2399+
23272400 // Check if we need to refresh mobile safari
2328 - /*var mobileSafairNeedsRefresh = false;
2329 - if( $j( '#' + this.pid ).attr('controls') === false ){
2330 - mobileSafairNeedsRefresh = true;
2331 - }*/
 2401+ var mobileSafariNeedsRefresh = false;
 2402+
 2403+ // Unhide the original video element if not part of a playerThemer embed
 2404+ if( !$j( '#' + this.pid ).hasClass('PlayerThemer') ){
 2405+ $j( '#' + this.pid )
 2406+ .css( {
 2407+ 'position' : 'absolute'
 2408+ } )
 2409+ .show()
 2410+ .attr('controls', 'true');
 2411+
 2412+ mobileSafariNeedsRefresh = true;
 2413+ }
23322414
2333 - // For now always refersh ( buggy display control behavior in iPad )
2334 - mobileSafairNeedsRefresh = true;
2335 -
2336 - // Unhide the original video element
2337 - $j( '#' + this.pid )
2338 - .css( {
2339 - 'position' : 'absolute'
2340 - } )
2341 - .show()
2342 - .attr('controls', 'true');
2343 -
23442415 // iPad does not handle video tag update for attributes like "controls"
23452416 // so we have to do a full replace ( if controls are not included initially )
2346 - if( mw.isMobileSafari() && mobileSafairNeedsRefresh ) {
 2417+ if( mw.isMobileHTML5() && mobileSafariNeedsRefresh ) {
23472418 var source = this.mediaElement.getSources( 'video/h264' )[0];
2348 - if( ! source.src ){
 2419+ if( source && ! source.src ){
23492420 mw.log( 'Error: should have caught no playable sources for mobile safari earlier' );
2350 - }
2351 -
 2421+ }
 2422+
23522423 var videoAttribues = {
23532424 'id' : _this.pid,
23542425 'poster': _this.poster,
23552426 'src' : source.src,
23562427 'controls' : 'true'
23572428 }
 2429+
23582430 if( this.loop ){
23592431 videoAttribues[ 'loop' ] = 'true';
23602432 }
23612433 var cssStyle = {
23622434 'width' : _this.width,
23632435 'height' : _this.height
2364 - };
 2436+ };
23652437 $j( '#' + this.pid ).replaceWith(
23662438 _this.getNativePlayerHtml( videoAttribues, cssStyle )
23672439 )
23682440 // Bind native events:
23692441 this.applyMediaElementBindings();
23702442 }
 2443+ // Android only can play with a special play button ( no native controls in the dom , and no auto-play )
 2444+ // and only with 'native display'
 2445+ if( mw.isAndroid2() ){
 2446+ $j( '#' + _this.pid ).siblings('.play-btn-large').remove();
 2447+ $j( '#' + _this.pid ).after(
 2448+ $j('<div />')
 2449+ .css({
 2450+ 'position' : 'relative',
 2451+ 'top' : -1 * ( .5 * _this.getPlayerHeight() ) - 52,
 2452+ 'left' : ( .5 * _this.getPlayerWidth() ) - 75
 2453+ })
 2454+ .attr( {
 2455+ 'title' : gM( 'mwe-embedplayer-play_clip' ),
 2456+ 'class' : "ui-state-default play-btn-large"
 2457+ } )
 2458+ .click( function() {
 2459+ _this.play();
 2460+ // no need to hide the play button since android plays fullscreen
 2461+ } )
 2462+ )
 2463+ }
23712464 return ;
23722465 },
23732466 /**
23742467 * Should be set via native embed support
23752468 */
23762469 getNativePlayerHtml: function(){
2377 - return $j('<div />' ).html( 'Error: Trying to get native html5 player without native support for codec' );
 2470+ return $j('<div />' )
 2471+ .css( 'width', this.getWidth() )
 2472+ .html( 'Error: Trying to get native html5 player without native support for codec' );
23782473 },
23792474 /**
23802475 * Should be set via native embed support
@@ -2386,7 +2481,7 @@
23872482 * Gets code to embed the player remotely for "share" this player links
23882483 */
23892484 getEmbeddingHTML: function() {
2390 - switch( mw.getConfig( 'shareEmbedMode' ) ){
 2485+ switch( mw.getConfig( 'EmbedPlayer.ShareEmbedMode' ) ){
23912486 case 'object':
23922487 return this.getShareEmbedObject()
23932488 break;
@@ -2409,6 +2504,10 @@
24102505 } else if( this.apiTitleKey ) {
24112506 iframeUrl += 'apiTitleKey=' + escape( this.apiTitleKey ) + '&';
24122507 if ( this.apiProvider ) {
 2508+ // Commons always uses the commons api provider ( special hack should refactor )
 2509+ if( mw.parseUri( document.URL ).host == 'commons.wikimedia.org'){
 2510+ this.apiProvider = 'commons';
 2511+ }
24132512 iframeUrl += 'apiProvider=' + escape( this.apiProvider ) + '&';
24142513 }
24152514 } else {
@@ -2538,7 +2637,7 @@
25392638 doLinkBack: function() {
25402639 if ( ! this.linkback && this.roe && this.mediaElement.addedROEData == false ) {
25412640 var _this = this;
2542 - this.displayOverlay( gM( 'mwe-embedplayer-loading_txt' ) );
 2641+ this.displayMenuOverlay( gM( 'mwe-embedplayer-loading_txt' ) );
25432642 this.getMvJsonUrl( this.roe, function( data ) {
25442643 _this.mediaElement.addROE( data );
25452644 _this.doLinkBack();
@@ -2549,7 +2648,7 @@
25502649 } else if ( this.mediaElement.linkback ) {
25512650 window.location = this.mediaElement.linkback;
25522651 } else {
2553 - this.displayOverlay( gM( 'mwe-embedplayer-could_not_find_linkback' ) );
 2652+ this.displayMenuOverlay( gM( 'mwe-embedplayer-could_not_find_linkback' ) );
25542653 }
25552654 }
25562655 },
@@ -2561,15 +2660,15 @@
25622661 /**
25632662 * The Play Action
25642663 *
2565 - * Handles play requests, updates relevet states:
 2664+ * Handles play requests, updates relevant states:
25662665 * seeking =false
25672666 * paused = false
25682667 * Updates pause button
25692668 * Starts the "monitor"
25702669 */
25712670 play: function() {
2572 - var _this = this;
2573 - mw.log( "EmbedPlayer:: play" );
 2671+ var _this = this;
 2672+ mw.log( "EmbedPlayer:: play" );
25742673 // Hide any overlay:
25752674 this.controlBuilder.closeMenuOverlay();
25762675
@@ -2578,17 +2677,24 @@
25792678 if ( !this.selectedPlayer ) {
25802679 mw.log( 'no selectedPlayer' );
25812680 this.showPluginMissingHTML();
 2681+ return;
25822682 } else {
25832683 this.thumbnail_disp = false;
2584 - this.paused = false;
2585 - this.doEmbedPlayer();
 2684+ this.doEmbedHTML();
25862685 }
25872686 } else {
25882687 // the plugin is already being displayed
2589 - this.paused = false; // make sure we are not "paused"
25902688 this.seeking = false;
25912689 }
25922690
 2691+ // Run play hook (if we were previously in paused state )
 2692+ if( this.paused ){
 2693+ this.paused = false;
 2694+ mw.log("trigger play event::");
 2695+ $j( this ).trigger( 'play' );
 2696+ }
 2697+
 2698+
25932699 this.$interface.find('.play-btn span')
25942700 .removeClass( 'ui-icon-play' )
25952701 .addClass( 'ui-icon-pause' );
@@ -2600,19 +2706,18 @@
26012707 _this.pause();
26022708 } )
26032709 .attr( 'title', gM( 'mwe-embedplayer-pause_clip' ) );
2604 -
2605 -
2606 - //Run play hook:
2607 - mw.log("playEvent");
2608 - $j( this ).trigger( 'playEvent' );
2609 -
2610 - // If we previously finished playing this clip run the "replay hook"
2611 - if( this.donePlayingCount > 0 ) {
 2710+
 2711+ // Start the monitor if not already started
 2712+ this.monitor();
 2713+
 2714+ // If we previously finished playing this clip run the "replay hook"
 2715+ if( this.donePlayingCount > 0 ) {
26122716 mw.log("replayEvent");
26132717 $j( this ).trigger( 'replayEvent' );
2614 - }
 2718+ }
26152719 },
26162720
 2721+
26172722 /**
26182723 * Maps the html5 load request. There is no general way to "load" clips so
26192724 * underling plugin-player libs should override.
@@ -2629,11 +2734,15 @@
26302735 * There is no general way to pause the video
26312736 * must be overwritten by embed object to support this functionality.
26322737 */
2633 - pause: function() {
2634 - var _this = this;
2635 - // mw.log('mwEmbed:do pause');
2636 - // (playing) do pause
2637 - this.paused = true;
 2738+ pause: function( event ) {
 2739+ var _this = this;
 2740+
 2741+ // only trigger the pause event if not already in paused state:
 2742+ if( this.paused === false ){
 2743+ this.paused = true;
 2744+ mw.log('EmbedPlayer:trigger pause');
 2745+ //$j( this ).trigger('pause' );
 2746+ }
26382747
26392748 // update the ctrl "paused state"
26402749 this.$interface.find('.play-btn span' )
@@ -2646,7 +2755,7 @@
26472756 .click( function() {
26482757 _this.play();
26492758 } )
2650 - .attr( 'title', gM( 'mwe-embedplayer-play_clip' ) );
 2759+ .attr( 'title', gM( 'mwe-embedplayer-play_clip' ) );
26512760 },
26522761
26532762 /**
@@ -2660,37 +2769,34 @@
26612770 */
26622771 stop: function() {
26632772 var _this = this;
2664 - mw.log( 'mvEmbed:stop:' + this.id );
 2773+ mw.log( 'EmbedPlayer::stop:' + this.id );
 2774+
26652775 // no longer seeking:
26662776 this.didSeekJump = false;
26672777
2668 - // reset current time and prev time
2669 - this.currentTime = this.previousTime = 0;
 2778+ // Reset current time and prev time and seek offset
 2779+ this.currentTime = this.previousTime = this.serverSeekTime = 0;
26702780
2671 - // Previous player set time
 2781+ // Issue pause to update interface (only call this parent)
 2782+ if( !this.paused ){
 2783+ this.paused = true;
 2784+ // update the interface
 2785+ if ( this['parent_pause'] ) {
 2786+ this.parent_pause();
 2787+ } else {
 2788+ this.pause();
 2789+ }
 2790+ }
26722791
2673 - // First issue pause to update interface (only call this parent)
2674 - if ( this['parent_pause'] ) {
2675 - this.parent_pause();
2676 - } else {
2677 - this.pause();
2678 - }
 2792+ // Rewrite the html to thumbnail disp
 2793+ this.showThumbnail();
 2794+ this.bufferedPercent = 0; // reset buffer state
 2795+ this.controlBuilder.setStatus( this.getTimeRange() );
26792796
2680 - // Reset the currentTime:
2681 - this.currentTime = 0;
 2797+ // Reset the playhead
 2798+ mw.log("EmbedPlayer::Stop:: Reset play head")
 2799+ this.updatePlayHead( 0 );
26822800
2683 - // Check if thumbnail is being displayed in which case do nothing
2684 - if ( this.thumbnail_disp ) {
2685 - // already in stooped state
2686 - mw.log( 'already in stopped state' );
2687 - } else {
2688 - // rewrite the html to thumbnail disp
2689 - this.showThumbnail();
2690 - this.bufferedPercent = 0; // reset buffer state
2691 - this.updatePlayHead( 0 );
2692 - this.controlBuilder.setStatus( this.getTimeRange() );
2693 - }
2694 -
26952801 //Bind play-btn-large play
26962802 this.$interface.find( '.play-btn-large' )
26972803 .unbind( 'click' )
@@ -2715,7 +2821,7 @@
27162822 this.preMuteVolume = this.volume;
27172823 var percent = 0;
27182824 }
2719 - this.setVolume( percent );
 2825+ this.setVolume( percent );
27202826 // Update the interface
27212827 this.setInterfaceVolume( percent );
27222828 },
@@ -2732,7 +2838,7 @@
27332839 // Set the local volume attribute
27342840 this.previousVolume = this.volume = percent;
27352841
2736 - // Un-mute if setting possitive volume
 2842+ // Un-mute if setting positive volume
27372843 if( percent != 0 ){
27382844 this.muted = false;
27392845 }
@@ -2741,12 +2847,13 @@
27422848 this.setPlayerElementVolume( percent );
27432849
27442850 //mw.log(" setVolume:: " + percent + ' this.volume is: ' + this.volume);
 2851+ $j( this ).trigger('volumeChanged', percent );
27452852 },
27462853
27472854 /**
27482855 * Updates the interface volume
27492856 * TODO should move to controlBuilder
2750 - * @param {float} percent Pecentage volume to update interface
 2857+ * @param {float} percent Percentage volume to update interface
27512858 */
27522859 setInterfaceVolume: function( percent ) {
27532860 if( this.supports[ 'volumeControl' ] &&
@@ -2757,24 +2864,24 @@
27582865 },
27592866
27602867 /**
2761 - * Abstract Update volumen Method must be overided by plug-in / player interface
 2868+ * Abstract Update volume Method must be override by plug-in / player interface
27622869 */
27632870 setPlayerElementVolume: function( percent ) {
2764 - mw.log(' error player does not support volume adjustment' );
 2871+ mw.log('Error player does not support volume adjustment' );
27652872 },
27662873
27672874 /**
2768 - * Abstract get volumen Method must be overided by plug-in / player interface
2769 - * (if player does not ovrride we return the abstract player value )
 2875+ * Abstract get volume Method must be override by plug-in / player interface
 2876+ * (if player does not override we return the abstract player value )
27702877 */
27712878 getPlayerElementVolume: function(){
2772 - //mw.log(' error player does not support geting volume property' );
 2879+ //mw.log(' error player does not support getting volume property' );
27732880 return this.volume;
27742881 },
27752882
27762883 /**
2777 - * Abstract get volumen muted property must be overided by plug-in / player interface
2778 - * (if player does not ovride we return the abstract player value )
 2884+ * Abstract get volume muted property must be overwritten by plug-in / player interface
 2885+ * (if player does not override we return the abstract player value )
27792886 */
27802887 getPlayerElementMuted: function(){
27812888 //mw.log(' error player does not support getting mute property' );
@@ -2830,7 +2937,7 @@
28312938 * true if stopped
28322939 * false if playing
28332940 */
2834 - isStoped: function() {
 2941+ isStopped: function() {
28352942 return this.thumbnail_disp;
28362943 },
28372944
@@ -2845,7 +2952,7 @@
28462953 */
28472954 checkForCurrentTimeSeek: function(){
28482955 var _this = this;
2849 - // Check if a javascript currentTime change based seek has occured
 2956+ // Check if a javascript currentTime change based seek has occurred
28502957 if( _this.previousTime != _this.currentTime && !this.userSlide && !this.seeking){
28512958 // If the time has been updated and is in range issue a seek
28522959 if( _this.getDuration() && _this.currentTime <= _this.getDuration() ){
@@ -2868,30 +2975,40 @@
28692976 this.checkForCurrentTimeSeek();
28702977
28712978 // Update currentTime via embedPlayer
2872 - _this.currentTime = _this.getPlayerElementTime();
2873 -
 2979+ _this.currentTime = _this.getPlayerElementTime();
 2980+
 2981+ // Update any offsets from server seek
 2982+ if( _this.serverSeekTime && _this.supportsURLTimeEncoding ){
 2983+ _this.currentTime = _this.serverSeekTime + _this.getPlayerElementTime()
 2984+ }
 2985+
28742986 // Update the previousTime ( so we can know if the user-javascript changed currentTime )
28752987 _this.previousTime = _this.currentTime;
28762988
28772989
28782990 // Check if volume was set outside of embed player function
28792991 //mw.log( ' this.volume: ' + _this.volume + ' prev Volume:: ' + _this.previousVolume );
2880 - if( _this.volume != _this.previousVolume ) {
 2992+ if( Math.round( _this.volume * 100 ) != Math.round( _this.previousVolume * 100 ) ) {
28812993 _this.setInterfaceVolume( _this.volume );
 2994+ $j( this ).trigger('volumeChanged', _this.volume );
28822995 }
2883 - // Update the previus volume
2884 - _this.previousVolume = _this.volume;
 2996+
 2997+ // Update the previous volume
 2998+ _this.previousVolume = _this.volume;
 2999+
28853000 // Update the volume from the player element
28863001 _this.volume = this.getPlayerElementVolume();
28873002
28883003 // update the mute state from the player element
2889 - if( _this.muted != _this.getPlayerElementMuted() ){
2890 - mw.log("monitor:: muted does not mach embed player" );
2891 - this.toggleMute();
2892 - }
2893 -
2894 - //mw.log(' ct: ' + this.currentTime + ' dur: ' + ( parseInt( this.duration ) + 1 ) + ' is seek: ' + this.seeking );
2895 - if ( this.currentTime && this.currentTime > 0 && this.duration ) {
 3004+ if( _this.muted != _this.getPlayerElementMuted() && ! _this.isStopped() ){
 3005+ mw.log( "EmbedPlayer::monitor: muted does not mach embed player" );
 3006+ _this.toggleMute();
 3007+ // Make sure they match:
 3008+ _this.muted = _this.getPlayerElementMuted();
 3009+ }
 3010+
 3011+ //mw.log( 'Monitor:: ' + this.currentTime + ' duration: ' + ( parseInt( this.getDuration() ) + 1 ) + ' is seeking: ' + this.seeking );
 3012+ if ( this.currentTime >= 0 && this.duration ) {
28963013 if ( !this.userSlide && !this.seeking ) {
28973014 if ( parseInt( this.startOffset ) != 0 ) {
28983015 // If start offset include that calculation
@@ -2913,7 +3030,7 @@
29143031 }
29153032 } else {
29163033 // Media lacks duration just show end time
2917 - if ( this.isStoped() ) {
 3034+ if ( this.isStopped() ) {
29183035 this.controlBuilder.setStatus( this.getTimeRange() );
29193036 } else if ( this.isPaused() ) {
29203037 this.controlBuilder.setStatus( gM( 'mwe-embedplayer-paused' ) );
@@ -2936,19 +3053,26 @@
29373054 $j( this ).trigger( 'progress', this.progressEventData );
29383055 }
29393056
2940 - // Call monitor at 250ms interval.
2941 - if( ! this.isStoped() ) {
2942 - setTimeout( function(){
2943 - _this.monitor();
2944 - }, 250 )
2945 - }
 3057+ // Call monitor at 250ms interval. ( use setInterval to avoid stacking monitor requests )
 3058+ if( ! this.isStopped() ) {
 3059+ if( !this.monitorInterval ){
 3060+ this.monitorInterval = setInterval( function(){
 3061+ if( _this.monitor )
 3062+ _this.monitor();
 3063+ }, this.monitorRate )
 3064+ }
 3065+ } else {
 3066+ // If stopped "stop" monitor:
 3067+ clearInterval( this.monitorInterval );
 3068+ this.monitorInterval = 0;
 3069+ }
29463070
29473071 //mw.log('trigger:monitor:: ' + this.currentTime );
29483072 $j( this ).trigger( 'monitorEvent' );
29493073 },
29503074
29513075 /**
2952 - * Abstarct getPlayerElementTime function
 3076+ * Abstract getPlayerElementTime function
29533077 */
29543078 getPlayerElementTime: function(){
29553079 mw.log("Error: getPlayerElementTime should be implemented by embed library");
@@ -2957,18 +3081,21 @@
29583082 /**
29593083 * Update the Buffer status based on the local bufferedPercent var
29603084 */
2961 - updateBufferStatus: function() {
 3085+ updateBufferStatus: function() {
 3086+
29623087 // Get the buffer target based for playlist vs clip
29633088 $buffer = this.$interface.find( '.mw_buffer' );
29643089 // Update the buffer progress bar (if available )
29653090 if ( this.bufferedPercent != 0 ) {
2966 - // mw.log('bufferedPercent: ' + this.bufferedPercent);
2967 - if ( this.bufferedPercent > 1 )
 3091+ //mw.log('Update buffer css: ' + ( this.bufferedPercent * 100 ) + '% ' + $buffer.length );
 3092+ if ( this.bufferedPercent > 1 ){
29683093 this.bufferedPercent = 1;
 3094+ }
29693095
29703096 $buffer.css({
29713097 "width" : ( this.bufferedPercent * 100 ) + '%'
29723098 });
 3099+ $j( this ).trigger( 'updateBufferPercent', this.bufferedPercent );
29733100 } else {
29743101 $buffer.css( "width", '0px' );
29753102 }
@@ -2992,16 +3119,18 @@
29933120 *
29943121 * @param {Float} perc Value between 0 and 1 for position of playhead
29953122 */
2996 - updatePlayHead: function( perc ) {
2997 - $play_head = this.$interface.find( '.play_head' );
2998 - if ( this.controls && $play_head.length != 0 ) {
 3123+ updatePlayHead: function( perc ) {
 3124+ $playHead = this.$interface.find( '.play_head' );
 3125+ if ( this.controls && $playHead.length != 0 ) {
29993126 var val = parseInt( perc * 1000 );
3000 - $play_head.slider( 'value', val );
3001 - }
 3127+ $playHead.slider( 'value', val );
 3128+ }
 3129+ // @@todo should have 'progress' trigger the same as html5
 3130+ $j( this ).trigger('updatePlayHeadPercent', perc);
30023131 },
30033132
30043133 /**
3005 - * Highligh a section of video on the playhead
 3134+ * Highlight a section of video on the playhead
30063135 *
30073136 * @param {Object} options Provides "start" time & "end" time to highlight
30083137 */
@@ -3042,9 +3171,9 @@
30433172 } ).show();
30443173
30453174 this.jump_time = options['start'];
3046 - this.seek_time_sec = mw.npt2seconds( options['start'] );
 3175+ this.serverSeekTime = mw.npt2seconds( options['start'] );
30473176 // trim output to
3048 - this.controlBuilder.setStatus( gM( 'mwe-embedplayer-seek_to', mw.seconds2npt( this.seek_time_sec ) ) );
 3177+ this.controlBuilder.setStatus( gM( 'mwe-embedplayer-seek_to', mw.seconds2npt( this.serverSeekTime ) ) );
30493178 mw.log( 'DO update: ' + this.jump_time );
30503179 this.updateThumbTime( rel_start_sec );
30513180 },
@@ -3070,7 +3199,7 @@
30713200 */
30723201 getSrc: function() {
30733202 if( this.mediaElement.selectedSource ){
3074 - return this.mediaElement.selectedSource.getSrc( this.seek_time_sec );
 3203+ return this.mediaElement.selectedSource.getSrc( this.serverSeekTime );
30753204 }
30763205 return false;
30773206 },
@@ -3151,8 +3280,8 @@
31523281 load: function( callback ) {
31533282 //Load player library ( upper case the first letter of the library )
31543283 mw.load( [
3155 - 'mw.EmbedPlayer' + this.library[0].toUpperCase() + this.library.substr(1)
3156 - ], function() {
 3284+ 'mw.EmbedPlayer' + this.library.substr(0,1).toUpperCase() + this.library.substr(1)
 3285+ ], function() {
31573286 callback();
31583287 } );
31593288 }
@@ -3161,7 +3290,7 @@
31623291 /**
31633292 * players and supported mime types
31643293 * In an ideal world we would query the plugin to get what mime
3165 -* types it supports in practice not always reliable/avaliable
 3294+* types it supports in practice not always reliable/available
31663295 *
31673296 * We can't cleanly store these values per library since player library is loaded post player detection
31683297 *
@@ -3174,13 +3303,13 @@
31753304 // Java based player
31763305 var cortadoPlayer = new mediaPlayer( 'cortado', ['video/ogg', 'audio/ogg', 'application/ogg'], 'Java' );
31773306
3178 -// Native html5 player
 3307+// Native html5 players
31793308 var oggNativePlayer = new mediaPlayer( 'oggNative', ['video/ogg', 'audio/ogg', 'application/ogg' ], 'Native' );
3180 -
31813309 var h264NativePlayer = new mediaPlayer( 'h264Native', ['video/h264'], 'Native' );
 3310+var webmNativePlayer = new mediaPlayer( 'webmNative', ['video/webm'], 'Native' );
31823311
31833312 // VLC player
3184 -var vlcMineList = ['video/ogg', 'audio/ogg', 'application/ogg', 'video/x-flv', 'video/mp4', 'video/h264'];
 3313+var vlcMineList = ['video/ogg', 'audio/ogg', 'application/ogg', 'video/x-flv', 'video/mp4', 'video/h264', 'video/x-msvideo', 'video/mpeg'];
31853314 var vlcPlayer = new mediaPlayer( 'vlc-player', vlcMineList, 'Vlc' );
31863315
31873316 // Generic plugin
@@ -3226,6 +3355,8 @@
32273356 this.defaultPlayers['application/ogg'] = ['Native', 'Vlc', 'Java', 'Generic'];
32283357 this.defaultPlayers['audio/ogg'] = ['Native', 'Vlc', 'Java' ];
32293358 this.defaultPlayers['video/mp4'] = ['Vlc'];
 3359+ this.defaultPlayers['video/mpeg'] = ['Vlc'];
 3360+ this.defaultPlayers['video/x-msvideo'] = ['Vlc'];
32303361
32313362 this.defaultPlayers['text/html'] = ['Html'];
32323363 this.defaultPlayers['image/jpeg'] = ['Html'];
@@ -3330,11 +3461,11 @@
33313462 * @param {String} mimeType Mime type for the associated player stream
33323463 */
33333464 setPlayerPreference : function( playerId, mimeType ) {
3334 - var selectedPlayer = null;
 3465+ var selectedPlayer = null;
33353466 for ( var i = 0; i < this.players.length; i++ ) {
33363467 if ( this.players[i].id == playerId ) {
33373468 selectedPlayer = this.players[i];
3338 - mw.log( 'choosing ' + playerId + ' for ' + mimeType );
 3469+ mw.log( 'EmbedPlayer::setPlayerPreference: choosing ' + playerId + ' for ' + mimeType );
33393470 this.preference[ mimeType ] = playerId;
33403471 mw.setUserConfig( 'playerPref', this.preference );
33413472 break;
@@ -3348,7 +3479,7 @@
33493480 if ( embed.mediaElement.selectedSource && ( embed.mediaElement.selectedSource.mimeType == mimeType ) )
33503481 {
33513482 embed.selectPlayer( selectedPlayer );
3352 - mw.log( 'using ' + embed.selectedPlayer.getName() + ' for ' + embed.mediaElement.selectedSource.getTitle() );
 3483+ mw.log( 'EmbedPlayer::setPlayerPreference: using ' + embed.selectedPlayer.getName() + ' for ' + embed.mediaElement.selectedSource.getTitle() );
33533484 }
33543485 }
33553486 }
@@ -3414,12 +3545,17 @@
34153546 this.players.addPlayer( htmlPlayer );
34163547 // In Mozilla, navigator.javaEnabled() only tells us about preferences, we need to
34173548 // search navigator.mimeTypes to see if it's installed
3418 - var javaEnabled = navigator.javaEnabled();
 3549+ try{
 3550+ var javaEnabled = navigator.javaEnabled();
 3551+ } catch ( e ){
 3552+
 3553+ }
34193554 // Some browsers filter out duplicate mime types, hiding some plugins
34203555 var uniqueMimesOnly = $j.browser.opera || $j.browser.safari;
 3556+
34213557 // Opera will switch off javaEnabled in preferences if java can't be found.
34223558 // And it doesn't register an application/x-java-applet mime type like Mozilla does.
3423 - if ( javaEnabled ) {
 3559+ if ( javaEnabled && ( navigator.appName == 'Opera' ) ) {
34243560 this.players.addPlayer( cortadoPlayer );
34253561 }
34263562
@@ -3439,6 +3575,7 @@
34403576 if ( this.testActiveX( 'JavaWebStart.isInstalled' ) ) {
34413577 this.players.addPlayer( cortadoPlayer );
34423578 }
 3579+
34433580 // quicktime (currently off)
34443581 // if ( this.testActiveX( 'QuickTimeCheckObject.QuickTimeCheck.1' ) )
34453582 // this.players.addPlayer(quicktimeActiveXPlayer);
@@ -3451,14 +3588,22 @@
34523589 try {
34533590 var dummyvid = document.createElement( "video" );
34543591 if( dummyvid.canPlayType ) {
3455 - var canPlayH264 = dummyvid.canPlayType('video/mp4; codecs="avc1.42E01E, mp4a.40.2"' );
3456 - var canPlayOgg = dummyvid.canPlayType && dummyvid.canPlayType( "video/ogg;codecs=\"theora,vorbis\"" );
 3592+ // Add the webm player
 3593+ if( dummyvid.canPlayType('video/webm; codecs="vp8, vorbis"') ){
 3594+ this.players.addPlayer( webmNativePlayer );
 3595+ }
 3596+
34573597 // Test for h264:
3458 - if ( canPlayH264 == "probably" || canPlayH264 == "maybe" ) {
 3598+ if ( dummyvid.canPlayType('video/mp4; codecs="avc1.42E01E, mp4a.40.2"' ) ) {
34593599 this.players.addPlayer( h264NativePlayer );
34603600 }
3461 - // Test for ogg
3462 - if ( canPlayOgg == "probably" || canPlayOgg == "maybe" ) {
 3601+ // For now if Android assume we support h264Native (FIXME test on real devices )
 3602+ if ( mw.isAndroid2() ){
 3603+ this.players.addPlayer( h264NativePlayer );
 3604+ }
 3605+
 3606+ // Test for ogg
 3607+ if ( dummyvid.canPlayType( 'video/ogg; codecs="theora,vorbis"' ) ) {
34633608 this.players.addPlayer( oggNativePlayer );
34643609 // older versions of safari do not support canPlayType,
34653610 // but xiph qt registers mimetype via quicktime plugin
@@ -3469,7 +3614,7 @@
34703615 } catch ( e ) {
34713616 mw.log( 'could not run canPlayType ' + e );
34723617 }
3473 - }
 3618+ }
34743619
34753620 // "navigator" plugins
34763621 if ( navigator.mimeTypes && navigator.mimeTypes.length > 0 ) {
@@ -3495,6 +3640,11 @@
34963641 continue;
34973642 }
34983643
 3644+ if ( (type == 'video/mpeg' || type=='video/x-msvideo') &&
 3645+ pluginName.toLowerCase() == 'vlc multimedia plugin' ) {
 3646+ this.players.addPlayer( vlcMozillaPlayer );
 3647+ }
 3648+
34993649 if ( type == 'application/ogg' ) {
35003650 if ( pluginName.toLowerCase() == 'vlc multimedia plugin' ) {
35013651 this.players.addPlayer( vlcMozillaPlayer );
@@ -3544,7 +3694,7 @@
35453695 * @param {String} name Name of ActiveXObject to look for
35463696 */
35473697 testActiveX : function ( name ) {
3548 - mw.log(" test testActiveX: " + name);
 3698+ mw.log("EmbedPlayer::detect: test testActiveX: " + name);
35493699 var hasObj = true;
35503700 try {
35513701 // No IE, not a class called "name", it's a variable
@@ -3555,3 +3705,4 @@
35563706 return hasObj;
35573707 }
35583708 };
 3709+
Index: trunk/extensions/TimedMediaHandler/EmbedPlayer/skins/mvpcf/mw.style.PlayerSkinMvpcf.css
@@ -1,22 +1,9 @@
2 -/*
 2+/**
33 * reference player skin
44 */
55
6 -/*Video player*/
7 -
8 -/* large play button: */
9 -.mv-player .play-btn-large {
10 - width : 130px;
11 - height : 96px;
12 - background : url(images/player_big_play_button.png) !important;
13 - position : absolute;
14 - cursor : pointer;
15 - border : none !important;
16 - z-index : 1;
17 -}
18 -/*.ui-state-default */
196
20 -
 7+/*.ui-state-default */
218 .mv-player a:link {color: #2060c1; text-decoration: underline;}
229 .mv-player a:visited {color: #2060c1; text-decoration: underline;}
2310 /*a:visited {color: #75a5e4; text-decoration: underline;}*/ /*Not sure if you want this*/
@@ -31,7 +18,8 @@
3219 height: 305px;
3320 }
3421 .mv-player .control-bar {
35 - height: 29px;
 22+ height: 29px;
 23+ z-index: 2;
3624 }
3725 .mv-player .controlInnerSmall {
3826 /* width: 430px;*/
@@ -61,11 +49,6 @@
6250 position:relative;
6351 }
6452
65 -.controls a{
66 - display: block;
67 - height: 100%;
68 - width: 100%;
69 -}
7053 .mv-player .volume_icon {
7154 float: right;
7255 display: inline;
@@ -127,7 +110,7 @@
128111 width:10px;
129112 height:15px;
130113 margin-left:-5px;
131 - margin-top: -1px;
 114+ margin-top: -0px;
132115 z-index: 2;
133116 }
134117
Index: trunk/extensions/TimedMediaHandler/EmbedPlayer/skins/kskin/mw.style.PlayerSkinKskin.css
@@ -188,7 +188,7 @@
189189 opacity: 0.9;
190190 position: absolute;
191191 top: 0;
192 - z-index: 999;
 192+ z-index: 2;
193193 }
194194
195195 .k-player .k-menu-bar li a {
@@ -319,7 +319,7 @@
320320 height: 15px;
321321 overflow: hidden;
322322 padding-left: 2px;
323 - width: 100%;
 323+ width: 95%;
324324 }
325325
326326 .menu-screen.menu-share button {
@@ -334,8 +334,11 @@
335335 }
336336
337337 .k-player .menu-screen {
338 - height: 100%;
 338+ height: 100%;
 339+ overflow-y: auto;
 340+ overflow-x: hide;
339341 }
 342+
340343
341344 .k-player .menu-screen.menu-share div.ui-state-highlight {
342345 background: none repeat scroll 0 0 transparent;
Index: trunk/extensions/TimedMediaHandler/EmbedPlayer/skins/kskin/mw.PlayerSkinKskin.js
@@ -2,10 +2,6 @@
33 * Skin js allows you to override contrlBuilder html/class output
44 */
55
6 -mw.addMessages( {
7 - "mwe-embedplayer-credit-title" : "Title: $1"
8 -} );
9 -
106 mw.PlayerSkinKskin = {
117
128 // The parent class for all kskin css:
@@ -46,8 +42,8 @@
4743 'volumeControl': {
4844 'w':40
4945 },
50 - // No kalturaAttribution component for kSkin ( its integrated into the credits screen )
51 - 'kalturaAttribution' : false,
 46+ // No attributionButton component for kSkin ( its integrated into the credits screen )
 47+ 'attributionButton' : false,
5248
5349 // Time display:
5450 'timeDisplay': {
@@ -88,6 +84,9 @@
8985 $menuBar = $j( '<ul />' )
9086 .addClass( 'k-menu-bar' );
9187
 88+ // dont include about player menu item ( FIXME should be moved to a init function )
 89+ delete ctrlObj.supportedMenuItems['aboutPlayerLibrary'];
 90+
9291 // Output menu item containers:
9392 for ( var menuItem in ctrlObj.supportedMenuItems ) {
9493 $menuBar.append(
@@ -115,7 +114,8 @@
116115 'top' : '0px',
117116 'left' : '0px',
118117 'bottom' : '0px',
119 - 'right' : '45px'
 118+ 'right' : '45px',
 119+ 'overflow' : 'hidden'
120120 } )
121121 for ( var menuItem in ctrlObj.supportedMenuItems ) {
122122 $menuScreens.append(
@@ -203,6 +203,9 @@
204204 .text ( gM( 'mwe-embedplayer-menu_btn' ) );
205205 } );
206206 this.$playerTarget.find( '.play-btn-large' ).fadeIn( 'fast' );
 207+
 208+ // re display the control bar if hidden:
 209+ this.showControlBar();
207210
208211 // Set close overlay menu flag:
209212 this.displayOptionsMenuFlag = false;
@@ -221,6 +224,8 @@
222225 } );
223226 this.$playerTarget.find( '.play-btn-large' ).fadeOut( 'fast' );
224227
 228+ $j(this.embedPlayer).trigger( 'displayMenuOverlay' );
 229+
225230 // Set the Options Menu display flag to true:
226231 this.displayOptionsMenuFlag = true;
227232 },
@@ -315,7 +320,7 @@
316321 );
317322 break;
318323 case 'share':
319 - embedPlayer.$interface.find( '.menu-share').html(
 324+ embedPlayer.$interface.find( '.menu-share' ).html(
320325 this.getShare()
321326 );
322327 break;
@@ -323,7 +328,7 @@
324329 },
325330
326331 /**
327 - * Show the credit screen (presently specific to kaltura skin )
 332+ * Show the credit screen ( presently specific to kaltura skin )
328333 */
329334 showCredits: function() {
330335 // Set up the shortcuts:
@@ -339,7 +344,7 @@
340345 .loadingSpinner()
341346 );
342347
343 - if( mw.getConfig( 'kalturaAttribution' ) == true ){
 348+ if( mw.getConfig( 'EmbedPlayer.KalturaAttribution' ) == true ){
344349 $target.append(
345350 $j( '<div />' )
346351 .addClass( 'k-attribution' )
Index: trunk/extensions/TimedMediaHandler/EmbedPlayer/skins/mw.PlayerControlBuilder.js
@@ -2,6 +2,7 @@
33 * Msg text is inherited from embedPlayer
44 */
55
 6+( function( mw ) {
67 /**
78 * mw.PlayerControlBuilder object
89 * @param the embedPlayer element we are targeting
@@ -43,7 +44,10 @@
4445 'download' : true,
4546
4647 // Share the video menu
47 - 'share' : true
 48+ 'share' : true,
 49+
 50+ // Player library link
 51+ 'aboutPlayerLibrary': true
4852 },
4953
5054 // Flag to store the current fullscreen mode
@@ -65,7 +69,7 @@
6670 this.embedPlayer = embedPlayer;
6771
6872 // Check for skin overrides for controlBuilder
69 - var skinClass = embedPlayer.skinName[0].toUpperCase() + embedPlayer.skinName.substr( 1 );
 73+ var skinClass = embedPlayer.skinName.substr(0,1).toUpperCase() + embedPlayer.skinName.substr( 1 );
7074 if ( mw['PlayerSkin' + skinClass ]) {
7175
7276 // Clone as to not override prototype with the skin config
@@ -161,13 +165,13 @@
162166 if( embedPlayer.isTimedTextSupported() ){
163167 this.supportedComponets['timedText'] = true;
164168 }
165 - // Check for kalturaAttribution
166 - if( mw.getConfig( 'kalturaAttribution' ) ){
167 - this.supportedComponets[ 'kalturaAttribution' ] = true;
 169+ // Check for Attribution button
 170+ if( mw.getConfig( 'EmbedPlayer.AttributionButton' ) && embedPlayer.attributionbutton ){
 171+ this.supportedComponets[ 'attributionButton' ] = true;
168172 }
169173
170174 // Check global fullscreen enabled flag
171 - if( mw.getConfig( 'enableFullscreen' ) === false ){
 175+ if( mw.getConfig( 'EmbedPlayer.EnableFullscreen' ) === false ){
172176 this.supportedComponets[ 'fullscreen'] = false;
173177 }
174178
@@ -246,11 +250,11 @@
247251 /**
248252 * Get the fullscreen text css
249253 */
250 - getFullscreenTextCss: function() {
251 - // Some arbitrary scale relative to window size
252 - var textSize = ( $j( window ).width() / 8 ) + 20;
 254+ getInterfaceSizeTextCss: function() {
 255+ // Some arbitrary scale relative to window size ( 400px wide is text size 105% )
 256+ var textSize = this.embedPlayer.$interface.width() / 3.8;
253257 if( textSize < 95 ) textSize = 95;
254 - if( textSize > 250 ) textSize = 250;
 258+ if( textSize > 200 ) textSize = 200;
255259 //mw.log(' win size is: ' + $j( window ).width() + ' ts: ' + textSize );
256260 return {
257261 'font-size' : textSize + '%'
@@ -306,7 +310,7 @@
307311 $j( '<div />' )
308312 .addClass( 'mw-fullscreen-overlay' )
309313 // Set some arbitrary high z-index
310 - .css('z-index', mw.getConfig( 'fullScreenIndex' ) )
 314+ .css('z-index', mw.getConfig( 'EmbedPlayer.fullScreenZIndex' ) )
311315 .hide()
312316 .fadeIn("slow")
313317 );
@@ -323,7 +327,7 @@
324328 // Change the z-index of the interface
325329 $interface.css( {
326330 'position' : 'fixed',
327 - 'z-index' : mw.getConfig( 'fullScreenIndex' ) + 1,
 331+ 'z-index' : mw.getConfig( 'EmbedPlayer.fullScreenZIndex' ) + 1,
328332 'top' : this.windowOffset.top,
329333 'left' : this.windowOffset.left
330334 } );
@@ -361,7 +365,10 @@
362366 mw.log(' should update position: ' + $j( this ).css( 'position' ) );
363367 }
364368 } );
365 - } )
 369+
 370+ // Resize the timed text font size per new player width
 371+ $interface.find( '.track' ).css( _this.getInterfaceSizeTextCss() );
 372+ } );
366373
367374 // Set the player height width:
368375 $j( embedPlayer ).css( {
@@ -369,10 +376,8 @@
370377 } )
371378 // Animate a zoom ( while keeping aspect )
372379 .animate( _this.getFullscreenPlayerCss() );
 380+
373381
374 - // Resize the timed text font size per window width
375 - $interface.find( '.track' ).css( _this.getFullscreenTextCss() );
376 -
377382 // Reposition play-btn-large ( this is unfortunately not easy to position with 'margin': 'auto'
378383 $interface.find('.play-btn-large').animate( _this.getFullscreenPlayButtonCss() )
379384
@@ -417,7 +422,7 @@
418423 $interface.find('.play-btn-large').css( _this.getFullscreenPlayButtonCss() );
419424
420425 // Update the timed text size
421 - $interface.find( '.track' ).css( _this.getFullscreenTextCss() );
 426+ $interface.find( '.track' ).css( _this.getInterfaceSizeTextCss() );
422427 }
423428 });
424429
@@ -478,6 +483,9 @@
479484 // Restore the body scroll bar
480485 $j('body').css( 'overflow', 'auto' );
481486
 487+ // Resize the timed text font size per window width
 488+ $interface.find( '.track' ).css( _this.getInterfaceSizeTextCss() );
 489+
482490 } );
483491 mw.log( 'restore embedPlayer:: ' + embedPlayer.getWidth() + ' h: ' + embedPlayer.getHeight());
484492 // Restore the player:
@@ -492,11 +500,7 @@
493501 'left' : ( ( embedPlayer.getPlayerWidth() - this.getComponentWidth( 'playButtonLarge' ) ) / 2 ),
494502 'top' : ( ( embedPlayer.getPlayerHeight() -this.getComponentHeight( 'playButtonLarge' ) ) / 2 )
495503 } );
496 -
497 - // Restore text size:
498 - $interface.find( '.track' ).css({
499 - 'font-size' : '100%'
500 - })
 504+
501505 },
502506
503507 /**
@@ -553,7 +557,7 @@
554558 // Add recommend firefox if we have non-native playback:
555559 if ( _this.checkNativeWarning( ) ) {
556560 _this.doWarningBindinng(
557 - 'showNativePlayerWarning',
 561+ 'EmbedPlayer.ShowNativeWarning',
558562 gM( 'mwe-embedplayer-for_best_experience' )
559563 );
560564 }
@@ -601,7 +605,7 @@
602606 .animate( {
603607 'bottom' : 10
604608 }, 'slow' );
605 -
 609+
606610 },
607611
608612 /**
@@ -609,7 +613,11 @@
610614 */
611615 showControlBar: function(){
612616 var animateDuration = 'slow';
613 - $j( this.embedPlayer.getPlayerElement() ).css('z-index', '1')
 617+ if(! this.embedPlayer )
 618+ return ;
 619+ if( this.embedPlayer.getPlayerElement ){
 620+ $j( this.embedPlayer.getPlayerElement() ).css( 'z-index', '1' );
 621+ }
614622 mw.log( 'showControlBar' );
615623 // Move up text track if present
616624 this.embedPlayer.$interface.find( '.track' )
@@ -621,7 +629,7 @@
622630 );
623631
624632 // Show interface controls
625 - this.embedPlayer.$interface.find( '.control-bar')
 633+ this.embedPlayer.$interface.find( '.control-bar' )
626634 .fadeIn( animateDuration );
627635 },
628636
@@ -634,20 +642,25 @@
635643 if( ! this.embedPlayer.supports['overlays'] ){
636644 return false;
637645 }
638 - // If the config is false
639 - if( mw.getConfig( 'overlayControls' ) === false){
 646+
 647+ // If disabled via the player
 648+ if( this.embedPlayer.overlaycontrols === false ){
640649 return false;
641650 }
642651
643 - // If disabled via the player
644 - if( this.embedPlayer.overlayControls === false ){
 652+ // If the config is false
 653+ if( mw.getConfig( 'EmbedPlayer.OverlayControls' ) == false){
645654 return false;
646655 }
 656+
647657 // don't hide controls when content "height" is 0 ( audio tags )
648658 if( this.embedPlayer.getPlayerHeight() == 0 ){
649659 return false;
650660 }
651 - // Past alll tests OverlayControls is true:
 661+ if( this.embedPlayer.controls === false ){
 662+ return false;
 663+ }
 664+ // Past all tests OverlayControls is true:
652665 return true;
653666 },
654667
@@ -657,21 +670,29 @@
658671 * dependent on mediaElement being setup
659672 */
660673 checkNativeWarning: function( ) {
661 -
 674+ if( mw.getConfig( 'EmbedPlayer.ShowNativeWarning' ) === false ){
 675+ return false;
 676+ }
 677+
662678 // If the resolution is too small don't display the warning
663679 if( this.embedPlayer.getPlayerHeight() < 199 ){
664680 return false;
665 - }
666 -
 681+ }
667682 // See if we have we have ogg support
668683 var supportingPlayers = mw.EmbedTypes.players.getMIMETypePlayers( 'video/ogg' );
669684 for ( var i = 0; i < supportingPlayers.length; i++ ) {
670 - if ( supportingPlayers[i].id == 'oggNative' ) {
 685+
 686+ if ( supportingPlayers[i].id == 'oggNative'
 687+ &&
 688+ // xxx google chrome has broken oggNative playback:
 689+ // http://code.google.com/p/chromium/issues/detail?id=56180
 690+ ! /chrome/.test(navigator.userAgent.toLowerCase() )
 691+ ){
671692 return false;
672693 }
673694 }
674695
675 - // Check for h264 and or flash/flv source and playback support and dont' show wanring
 696+ // Check for h264 and or flash/flv source and playback support and don't show warning
676697 if(
677698 ( mw.EmbedTypes.players.getMIMETypePlayers( 'video/h264' ).length
678699 && this.embedPlayer.mediaElement.getSources( 'video/h264' ).length )
@@ -701,9 +722,12 @@
702723
703724 $j( embedPlayer ).hoverIntent({
704725 'timeout': 2000,
705 - 'over': function() {
706 - if ( $j( '#warningOverlay_' + embedPlayer.id ).length == 0 ) {
707 - var toppos = ( embedPlayer.instanceOf == 'mvPlayList' ) ? 25 : 10;
 726+ 'over': function() {
 727+ // don't do the overlay if already playing
 728+ if( embedPlayer.isPlaying() ){
 729+ return ;
 730+ }
 731+ if ( $j( '#warningOverlay_' + embedPlayer.id ).length == 0 ) {
708732
709733 $j( this ).append(
710734 $j('<div />')
@@ -716,7 +740,7 @@
717741 'display' : 'none',
718742 'background' : '#FFF',
719743 'color' : '#111',
720 - 'top' : toppos + 'px',
 744+ 'top' : '10px',
721745 'left' : '10px',
722746 'right' : '10px',
723747 'padding' : '4px'
@@ -805,7 +829,7 @@
806830 );
807831 }
808832
809 - // Setup play-head slider:
 833+ // Setup volume slider:
810834 var sliderConf = {
811835 range: "min",
812836 value: 80,
@@ -865,7 +889,7 @@
866890 * The ctrl builder updates the interface on seeking
867891 */
868892 onSeek: function(){
869 - mw.log( "controlBuilder:: onSeek" );
 893+ //mw.log( "controlBuilder:: onSeek" );
870894 // Update the interface:
871895 this.setStatus( gM( 'mwe-embedplayer-seeking' ) );
872896 },
@@ -892,7 +916,7 @@
893917 gM( 'mwe-embedplayer-choose_player' ),
894918 'gear',
895919 function( ) {
896 - ctrlObj.displayOverlay(
 920+ ctrlObj.displayMenuOverlay(
897921 ctrlObj.getPlayerSelect()
898922 );
899923 }
@@ -905,7 +929,7 @@
906930 gM( 'mwe-embedplayer-download' ),
907931 'disk',
908932 function( ) {
909 - ctrlObj.displayOverlay( gM('mwe-embedplayer-loading_txt' ) );
 933+ ctrlObj.displayMenuOverlay( gM('mwe-embedplayer-loading_txt' ) );
910934 // Call show download with the target to be populated
911935 ctrlObj.showDownload(
912936 ctrlObj.embedPlayer.$interface.find( '.overlay-content' )
@@ -921,12 +945,25 @@
922946 gM( 'mwe-embedplayer-share' ),
923947 'mail-closed',
924948 function( ) {
925 - ctrlObj.displayOverlay(
 949+ ctrlObj.displayMenuOverlay(
926950 ctrlObj.getShare()
927951 );
928952 $j( ctrlObj.embedPlayer ).trigger( 'showShareEvent' );
929953 }
930954 )
 955+ },
 956+
 957+ 'aboutPlayerLibrary' : function( ctrlObj ){
 958+ return $j.getLineItem(
 959+ gM( 'mwe-embedplayer-about-library' ),
 960+ 'info',
 961+ function( ) {
 962+ ctrlObj.displayMenuOverlay(
 963+ ctrlObj.aboutPlayerLibrary()
 964+ );
 965+ $j( ctrlObj.embedPlayer ).trigger( 'aboutPlayerLibrary' );
 966+ }
 967+ )
931968 }
932969 },
933970
@@ -936,8 +973,8 @@
937974 closeMenuOverlay: function(){
938975 var _this = this;
939976 var embedPlayer = this.embedPlayer;
940 - var $overlay = embedPlayer.$interface.find( '.overlay-win,.ui-widget-overlay,.ui-widget-shadow' );
941 -
 977+ var $overlay = embedPlayer.$interface.find( '.overlay-win,.ui-widget-overlay,.ui-widget-shadow' );
 978+
942979 this.displayOptionsMenuFlag = false;
943980 mw.log(' closeMenuOverlay: ' + this.displayOptionsMenuFlag);
944981
@@ -946,6 +983,10 @@
947984 } );
948985 // Show the big play button:
949986 embedPlayer.$interface.find( '.play-btn-large' ).fadeIn( 'slow' );
 987+
 988+
 989+ $j(embedPlayer).trigger( 'closeMenuOverlay' );
 990+
950991 return false; // onclick action return false
951992 },
952993
@@ -955,10 +996,10 @@
956997 *
957998 * @param {String} overlayContent content to be displayed
958999 */
959 - displayOverlay: function( overlayContent ) {
 1000+ displayMenuOverlay: function( overlayContent ) {
9601001 var _this = this;
9611002 var embedPlayer = this.embedPlayer;
962 - mw.log( 'displayOverlay::' );
 1003+ mw.log( 'displayMenuOverlay::' );
9631004 // set the overlay display flag to true:
9641005 this.displayOptionsMenuFlag = true;
9651006 mw.log(" set displayOptionsMenuFlag:: " + this.displayOptionsMenuFlag);
@@ -966,6 +1007,8 @@
9671008 if ( !this.supportedComponets[ 'overlays' ] ) {
9681009 embedPlayer.stop();
9691010 }
 1011+
 1012+
9701013 // Hide the big play button:
9711014 embedPlayer.$interface.find( '.play-btn-large' ).hide();
9721015
@@ -1038,11 +1081,32 @@
10391082 $overlayShadow
10401083 )
10411084 .find( '.overlay-win' )
1042 - .fadeIn( "slow" );
 1085+ .fadeIn( "slow" );
10431086
 1087+ // trigger menu overlay display
 1088+ $j(embedPlayer).trigger( 'displayMenuOverlay' );
 1089+
10441090 return false; // onclick action return false
10451091 },
1046 -
 1092+ aboutPlayerLibrary: function(){
 1093+ return $j( '<div />' )
 1094+ .append(
 1095+ $j( '<h3 />' )
 1096+ .text(
 1097+ gM('mwe-embedplayer-about-library')
 1098+ )
 1099+ ,
 1100+ $j( '<span />')
 1101+ .append(
 1102+ gM('mwe-embedplayer-about-library-desc',
 1103+ $j('<a />').attr({
 1104+ 'href' : MW_EMBED_LIBRARY_PAGE,
 1105+ 'target' : '_new'
 1106+ })
 1107+ )
 1108+ )
 1109+ )
 1110+ },
10471111 /**
10481112 * Get the "share" interface
10491113 *
@@ -1118,7 +1182,9 @@
11191183 * @param {Object} $target jQuery target for output
11201184 */
11211185 getPlayerSelect: function( ) {
1122 - mw.log('getPlayerSelect::');
 1186+ mw.log('ControlBuilder::getPlayerSelect: source:' +
 1187+ this.embedPlayer.mediaElement.selectedSource.getSrc() +
 1188+ ' player: ' + this.embedPlayer.selectedPlayer.id );
11231189
11241190 var embedPlayer = this.embedPlayer;
11251191
@@ -1132,22 +1198,22 @@
11331199
11341200 $j.each( embedPlayer.mediaElement.getPlayableSources(), function( sourceId, source ) {
11351201
1136 - var playable = mw.EmbedTypes.players.defaultPlayer( source.getMIMEType() );
1137 - var is_selected = ( source == embedPlayer.mediaElement.selectedSource );
 1202+ var isPlayable = (typeof mw.EmbedTypes.players.defaultPlayer( source.getMIMEType() ) == 'object' );
 1203+ var is_selected = ( source.getSrc() == embedPlayer.mediaElement.selectedSource.getSrc() );
11381204
11391205 $playerSelect.append(
11401206 $j( '<h2 />' )
11411207 .text( source.getTitle() )
11421208 );
11431209
1144 - if ( playable ) {
 1210+ if ( isPlayable ) {
11451211 $playerList = $j('<ul />');
11461212 // output the player select code:
11471213
11481214 var supportingPlayers = mw.EmbedTypes.players.getMIMETypePlayers( source.getMIMEType() );
11491215
1150 - for ( var i = 0; i < supportingPlayers.length ; i++ ) {
1151 -
 1216+ for ( var i = 0; i < supportingPlayers.length ; i++ ) {
 1217+
11521218 // Add link to select the player if not already selected )
11531219 if( embedPlayer.selectedPlayer.id == supportingPlayers[i].id && is_selected ) {
11541220 // Active player ( no link )
@@ -1169,8 +1235,8 @@
11701236 .click( function() {
11711237 var iparts = $j( this ).attr( 'id' ).replace(/sc_/ , '' ).split( '_' );
11721238 var sourceId = iparts[0];
1173 - var default_player_id = iparts[1];
1174 - mw.log( 'source id: ' + sourceId + ' player id: ' + default_player_id );
 1239+ var player_id = iparts[1];
 1240+ mw.log( 'source id: ' + sourceId + ' player id: ' + player_id );
11751241
11761242 embedPlayer.controlBuilder.closeMenuOverlay();
11771243
@@ -1180,10 +1246,11 @@
11811247 }
11821248
11831249 embedPlayer.mediaElement.selectSource( sourceId );
1184 -
 1250+ var playableSources = embedPlayer.mediaElement.getPlayableSources();
 1251+
11851252 mw.EmbedTypes.players.setPlayerPreference(
1186 - default_player_id,
1187 - embedPlayer.mediaElement.sources[ sourceId ].getMIMEType()
 1253+ player_id,
 1254+ playableSources[ sourceId ].getMIMEType()
11881255 );
11891256
11901257 // Issue a stop
@@ -1301,7 +1368,7 @@
13021369 var $textList = $j( '<ul />' );
13031370 $j.each( embedPlayer.mediaElement.getSources(), function( index, source ) {
13041371 if( source.getSrc() ) {
1305 - mw.log("add src: " + source.getTitle() );
 1372+ mw.log("showDownloadWithSources:: Add src: " + source.getTitle() );
13061373 var $dl_line = $j( '<li />').append(
13071374 $j('<a />')
13081375 .attr( 'href', source.getSrc() )
@@ -1420,15 +1487,31 @@
14211488 },
14221489
14231490 /**
1424 - * The kaltura attribution button
 1491+ * The Attribution button ( by default this is kaltura-icon
14251492 */
1426 - 'kalturaAttribution' : {
 1493+ 'attributionButton' : {
14271494 'w' : 28,
1428 - 'o' : function( ctrlObj ){
 1495+ 'o' : function( ctrlObj ){
 1496+ var buttonConfig = mw.getConfig( 'EmbedPlayer.AttributionButton');
 1497+
 1498+ var $icon = $j('<span />')
 1499+ .addClass( 'ui-icon' );
 1500+ if( buttonConfig['class'] ){
 1501+ $icon.addClass( buttonConfig['class'] )
 1502+ }
 1503+ // Check for source ( by configuration convention this is a 16x16 image
 1504+ if( buttonConfig.iconurl ){
 1505+ $icon.append(
 1506+ $j('<img />')
 1507+ .css({'width': '16px', 'height': '16px'})
 1508+ .attr('src', buttonConfig.iconurl )
 1509+ )
 1510+ }
 1511+
14291512 return $j('<a />')
14301513 .attr({
1431 - 'href': 'http://kaltura.com',
1432 - 'title' : gM( 'mwe-embedplayer-kaltura-platform-title' ),
 1514+ 'href': buttonConfig.href,
 1515+ 'title' : buttonConfig.title,
14331516 'target' : '_new'
14341517 })
14351518 .append(
@@ -1439,10 +1522,9 @@
14401523 'left' : '2px'
14411524 })
14421525 .append(
1443 - $j('<span />')
1444 - .addClass( 'ui-icon kaltura-icon' )
 1526+ $icon
14451527 )
1446 - )
 1528+ )
14471529 }
14481530 },
14491531
@@ -1463,7 +1545,7 @@
14641546 // Options binding:
14651547 .menu( {
14661548 'content' : ctrlObj.getOptionsMenu(),
1467 - 'zindex' : mw.getConfig( 'fullScreenIndex' ) + 1,
 1549+ 'zindex' : mw.getConfig( 'EmbedPlayer.fullScreenZIndex' ) + 1,
14681550 'positionOpts': {
14691551 'directionV' : 'up',
14701552 'offsetY' : 30,
@@ -1596,11 +1678,10 @@
15971679 'w' : 100,
15981680 'o' : function( ctrlObj ) {
15991681 return $j( '<div />' )
1600 - .addClass( "ui-widget time-disp" )
1601 - .append(
1602 - ctrlObj.embedPlayer.getTimeRange()
1603 - )
1604 -
 1682+ .addClass( "ui-widget time-disp" )
 1683+ .append(
 1684+ ctrlObj.embedPlayer.getTimeRange()
 1685+ )
16051686 }
16061687 },
16071688
@@ -1680,3 +1761,6 @@
16811762 }
16821763 }
16831764 };
 1765+
 1766+
 1767+} )( window.mw );
Index: trunk/extensions/TimedMediaHandler/EmbedPlayer/binPlayers/cortado/cortado-january.jar
Cannot display: file marked as a binary type.
svn:mime-type = application/octet-stream
Index: trunk/extensions/TimedMediaHandler/EmbedPlayer/binPlayers/cortado/cortado-ovt-stripped-0.5.0.jar
Cannot display: file marked as a binary type.
svn:mime-type = application/octet-stream
Index: trunk/extensions/TimedMediaHandler/EmbedPlayer/binPlayers/cortado/cortado-ovtk-stripped-0.6.0.jar
Cannot display: file marked as a binary type.
svn:mime-type = application/octet-stream
Property changes on: trunk/extensions/TimedMediaHandler/EmbedPlayer/binPlayers/cortado/cortado-ovtk-stripped-0.6.0.jar
___________________________________________________________________
Added: svn:mime-type
16841768 + application/octet-stream
Index: trunk/extensions/TimedMediaHandler/EmbedPlayer/binPlayers/kaltura-player/LightDoodleskin.swf
Cannot display: file marked as a binary type.
svn:mime-type = application/octet-stream
Property changes on: trunk/extensions/TimedMediaHandler/EmbedPlayer/binPlayers/kaltura-player/LightDoodleskin.swf
___________________________________________________________________
Added: svn:mime-type
16851769 + application/octet-stream
Index: trunk/extensions/TimedMediaHandler/EmbedPlayer/binPlayers/kaltura-player/config.xml
@@ -1,4 +1,4 @@
2 -<layout id="full" name="player" skinPath="assets/skin.swf">
 2+<layout id="full" skinPath="assets/skin.swf">
33 <HBox id="topLevel" width="100%" height="100%">
44 <VBox id="player" width="100%" height="100%" styleName="black">
55 <Canvas height="100%" width="100%" id="PlayerHolder" styleName="black">
Index: trunk/extensions/TimedMediaHandler/EmbedPlayer/mw.EmbedPlayerJava.js
@@ -219,7 +219,11 @@
220220 this.getPlayerElement();
221221 this.parent_play();
222222 if ( this.playerElement ) {
223 - this.playerElement.play();
 223+ try{
 224+ this.playerElement.play();
 225+ }catch( e ){
 226+ mw.log("EmbedPlayerJava::Could not issue play request");
 227+ }
224228 }
225229 },
226230
Index: trunk/extensions/TimedMediaHandler/EmbedPlayer/mw.EmbedPlayerHtml.js
@@ -2,7 +2,7 @@
33 * Used to embed HTML as a movie clip
44 * for use with mv_playlist SMIL additions
55 *
6 - * NOTE: will likely be depricated
 6+ * NOTE: will be deprecated
77 */
88 var pcHtmlEmbedDefaults = {
99 // default duration of 4 seconds
@@ -22,7 +22,7 @@
2323 'timeDisplay':true,
2424 'volumeControl':true,
2525
26 - 'overlays':true,
 26+ 'overlays':true
2727 },
2828
2929 // If the player is "ready to play"
@@ -92,8 +92,8 @@
9393 * @param {Float} perc Percentage to seek into the virtual player
9494 * @param {Function} callback Function called once time has been updated
9595 */
96 - setCurrentTime:function( perc, callback ) {
97 - this.pauseTime = perc * this.getDuration();
 96+ setCurrentTime:function( time, callback ) {
 97+ this.pauseTime = time;
9898 if( callback )
9999 callback();
100100 },
Index: trunk/extensions/TimedMediaHandler/EmbedPlayer/mw.EmbedPlayerVlc.js
@@ -38,7 +38,7 @@
3939 $j( this ).html(
4040 '<object classid="clsid:9BE31822-FDAD-461B-AD51-BE1D1C159921" ' +
4141 'codebase="http://downloads.videolan.org/pub/videolan/vlc/latest/win32/axvlc.cab#Version=0,8,6,0" ' +
42 - 'id="' + this.pid + '" events="True" height="' + this.getHeight() + '" width="' + this.getWidth() + '"' +
 42+ 'id="' + this.pid + '" events="True" height="' + this.getPlayerHeight() + '" width="' + this.getPlayerWidth() + '"' +
4343 '>' +
4444 '<param name="MRL" value="">' +
4545 '<param name="ShowDisplay" value="True">' +
@@ -129,7 +129,7 @@
130130 if ( ( this.playerElement.input.state == 3 ) && ( this.playerElement.input.position != percent ) )
131131 {
132132 this.playerElement.input.position = percent;
133 - this.setStatus( 'seeking...' );
 133+ this.controlBuilder.setStatus( 'seeking...' );
134134 }
135135 } else {
136136 this.doPlayThenSeek( percent );
@@ -173,10 +173,10 @@
174174 this.getPlayerElement();
175175 if ( !this.playerElement )
176176 return ;
177 - if ( this.playerElement.log ) {
178 - // mw.log( 'state:' + this.playerElement.input.state);
179 - // mw.log('time: ' + this.playerElement.input.time);
180 - // mw.log('pos: ' + this.playerElement.input.position);
 177+ try{
 178+ //mw.log( 'state:' + this.playerElement.input.state);
 179+ //mw.log('time: ' + this.playerElement.input.time);
 180+ //mw.log('pos: ' + this.playerElement.input.position);
181181 if ( this.playerElement.log.messages.count > 0 ) {
182182 // there is one or more messages in the log
183183 var iter = this.playerElement.log.messages.iterator();
@@ -191,6 +191,7 @@
192192 // clear the log once finished to avoid clogging
193193 this.playerElement.log.messages.clear();
194194 }
 195+
195196 var newState = this.playerElement.input.state;
196197 if ( this.prevState != newState ) {
197198 if ( newState == 0 )
@@ -222,6 +223,8 @@
223224 // current media is playing
224225 this.onPlaying();
225226 }
 227+ } catch( e ){
 228+ mw.log("EmbedPlayerVlc::Monitor error");
226229 }
227230 // update the status and check timmer via universal parent monitor
228231 this.parent_monitor();
@@ -232,10 +235,10 @@
233236 * @@note: should be localized:
234237 */
235238 onOpen: function() {
236 - this.setStatus( "Opening..." );
 239+ this.controlBuilder.setStatus( "Opening..." );
237240 },
238241 onBuffer: function() {
239 - this.setStatus( "Buffering..." );
 242+ this.controlBuilder.setStatus( "Buffering..." );
240243 },
241244 onPlay: function() {
242245 this.onPlaying();
@@ -299,8 +302,12 @@
300303 */
301304 pause : function() {
302305 this.parent_pause(); // update the interface if paused via native control
303 - if ( this.getPlayerElement() ) {
304 - this.playerElement.playlist.togglePause();
 306+ if ( this.getPlayerElement() ) {
 307+ try{
 308+ this.playerElement.playlist.togglePause();
 309+ } catch( e ){
 310+ mw.log("EmbedPlayerVlc could not pause video " + e);
 311+ }
305312 }
306313 },
307314
@@ -338,16 +345,20 @@
339346 */
340347 fullscreen : function() {
341348 if ( this.playerElement ) {
342 - if ( this.playerElement.video )
343 - this.playerElement.video.toggleFullscreen();
344 - }
345 - this.parent_fullscreen();
 349+ if ( this.playerElement.video ){
 350+ try{
 351+ this.playerElement.video.toggleFullscreen();
 352+ } catch ( e ){
 353+ mw.log("VlcEmbed toggle fullscreen : possible error: " + e);
 354+ }
 355+ }
 356+ }
346357 },
347358
348359 /**
349360 * Get the embed vlc object
350361 */
351 - getPlayerElement : function() {
 362+ getPlayerElement : function() {
352363 this.playerElement = $j( '#' + this.pid ).get(0);
353364 return this.playerElement;
354365 }
Index: trunk/extensions/TimedMediaHandler/EmbedPlayer/EmbedPlayer.i18n.php
@@ -3,7 +3,7 @@
44 * Internationalisation for EmbedPlayer
55 *
66 * @file
7 - * @ingroup Extensions
 7+ * @ingroup Extensions
88 */
99
1010 $messages = array();
@@ -34,6 +34,8 @@
3535 'mwe-embedplayer-download' => 'Download',
3636 'mwe-embedplayer-share' => 'Share',
3737 'mwe-embedplayer-credits' => 'Credits',
 38+ 'mwe-embedplayer-about-library'=> 'About kaltura player',
 39+ 'mwe-embedplayer-about-library-desc' => 'Kaltura\'s HTML5 Media Library enables you to take advantage of the html5 &lt;video&gt; and &lt;audio&gt; tags today with a consistent player interface across all major browsers. <br> <br> [$1 More about the kaltura player library].',
3840 'mwe-embedplayer-clip_linkback' => 'Clip source page',
3941 'mwe-embedplayer-choose_player' => 'Choose video player',
4042 'mwe-embedplayer-no-player' => 'No player available for $1',
@@ -61,12 +63,13 @@
6264 'mwe-embedplayer-embed_site_or_blog' => 'Embed on a page',
6365 'mwe-embedplayer-related_videos' => 'Related videos',
6466 'mwe-embedplayer-seeking' => 'seeking',
 67+ 'mwe-embedplayer-buffering' => 'buffering',
6568 'mwe-embedplayer-copy-code' => 'Copy code',
6669 'mwe-embedplayer-video-h264' => 'H.264 video',
6770 'mwe-embedplayer-video-flv' => 'Flash video',
6871 'mwe-embedplayer-video-ogg' => 'Ogg video',
6972 'mwe-embedplayer-video-audio' => 'Ogg audio',
70 - 'mwe-embedplayer-missing-source' => 'No source video was found. Check that your embed code includes a source or API key',
 73+ 'mwe-embedplayer-missing-source' => 'No source video was found',
7174 );
7275
7376 /** Message documentation (Message documentation)
Index: trunk/extensions/TimedMediaHandler/EmbedPlayer/mw.EmbedPlayerNative.js
@@ -40,13 +40,16 @@
4141 'volumeControl' : true,
4242 'overlays' : true
4343 },
 44+
 45+ insertAndPlayingConfig : false,
 46+
4447 /**
4548 * updates the supported features given the "type of player"
4649 */
4750 updateFeatureSupport: function(){
4851 // iWhatever devices appear to have a broken
4952 // dom overlay implementation of video atm. (hopefully iphone OS 4 fixes this )
50 - if( mw.isMobileSafari() ) {
 53+ if( mw.isMobileHTML5() ) {
5154 this.supports.overlays = false;
5255 }
5356 },
@@ -57,10 +60,14 @@
5861 doEmbedHTML : function () {
5962 var _this = this;
6063
 64+ // Reset some play state flags:
 65+ _this.bufferStartFlag = false;
 66+ _this.bufferEndFlag = false;
 67+
6168 mw.log( "native play url:" + this.getSrc() + ' startOffset: ' + this.start_ntp + ' end: ' + this.end_ntp );
6269
63 - // Check if using native contorls and already the "pid" is already in the DOM
64 - if( this.useNativeControls && $j( '#' + this.pid ).length &&
 70+ // Check if using native controls and already the "pid" is already in the DOM
 71+ if( this.useNativePlayerControls() && $j( '#' + this.pid ).length &&
6572 typeof $j( '#' + this.pid ).get(0).play != 'undefined' ) {
6673 _this.postEmbedJS();
6774 return ;
@@ -78,7 +85,7 @@
7986 * Get the native player embed code.
8087 *
8188 * @param {object} playerAttribtues Attributes to be override in function call
82 - * @return {object} jQuery player code object
 89+ * @return {object} cssSet css to apply to the player
8390 */
8491 getNativePlayerHtml: function( playerAttribtues, cssSet ){
8592 if( !playerAttribtues) {
@@ -169,12 +176,12 @@
170177 // Bind events to local js methods:
171178 vid.addEventListener( 'canplaythrogh', function() { $j( _this ).trigger('canplaythrough'); }, true);
172179 vid.addEventListener( 'loadedmetadata', function() { _this.onloadedmetadata() }, true);
173 - vid.addEventListener( 'progress', function( e ) { _this.onprogress( e ); }, true);
 180+ vid.addEventListener( 'progress', function( e ) { if( _this.onprogress ) { _this.onprogress( e ); } }, true);
174181 vid.addEventListener( 'ended', function() { _this.onended() }, true);
175182 vid.addEventListener( 'seeking', function() { _this.onSeeking() }, true);
176183 vid.addEventListener( 'seeked', function() { _this.onSeeked() }, true);
177184
178 - vid.addEventListener( 'pause', function() { _this.onPaused() }, true );
 185+ vid.addEventListener( 'pause', function() { if( _this.onPaused ) { _this.onPaused() } }, true );
179186 vid.addEventListener( 'play', function(){ _this.onPlay() }, true );
180187 vid.addEventListener( 'volumechange', function(){ _this.onVolumeChange() } , true );
181188 },
@@ -201,9 +208,8 @@
202209 mw.log( 'Native::doSeek p: ' + percentage + ' : ' + this.supportsURLTimeEncoding() + ' dur: ' + this.getDuration() + ' sts:' + this.seek_time_sec );
203210 this.seeking = true;
204211 // Run the seeking hook
205 - $j( this.embedPlayer ).trigger( 'onSeek' );
 212+ $j( this.embedPlayer ).trigger( 'onSeek' );
206213
207 -
208214 // Run the onSeeking interface update
209215 this.controlBuilder.onSeek();
210216
@@ -235,12 +241,81 @@
236242 mw.log( 'native::doNativeSeek::' + percentage );
237243 this.seeking = true;
238244 this.seek_time_sec = 0;
239 - this.doSeekedCallback( ( percentage * this.duration ) , function(){
 245+ this.setCurrentTime( ( percentage * this.duration ) , function(){
240246 _this.seeking = false;
241247 _this.monitor();
242 - })
 248+ })
 249+ },
 250+
 251+ insertAndPlaySource: function( src , options ){
 252+ mw.log("NativeEmbed:: insertAndPlaySource: " + src + ' insertAndPlayingConfig:' + this.insertAndPlayingConfig);
 253+ if(!options)
 254+ options = {};
243255
 256+ if( options.lockUI ){
 257+ this.playerElement.controls = false;
 258+ }
 259+
 260+ // Make sure to capture the original source
 261+ if(! this.insertAndPlayingConfig ){
 262+ //alert( 'setup this.insertAndPlayingConfig ');
 263+ this.insertAndPlayingConfig = {
 264+ 'src' : this.getSrc(),
 265+ 'time' : this.currentTime,
 266+ 'callback' : options.callback,
 267+ 'restoreControls' : options.lockUI
 268+ }
 269+ }
 270+ // Try to directly playback the source
 271+ this.switchSrc( src );
 272+
244273 },
 274+ restoreSourcePlayback: function( ){
 275+ var _this = this;
 276+ mw.log( "RestoreSourcePlayback:: empty out insertAndPlayingConfig" );
 277+ if( !this.insertAndPlayingConfig) {
 278+ mw.log("Error: called restored playback with empty insertAndPlayingConfig")
 279+ return;
 280+ }
 281+ this.switchSrc( this.insertAndPlayingConfig.src );
 282+ //this.playerElement.play();
 283+ // Remove insert and playing config flag
 284+ this.insertAndPlayingConfig = false;
 285+
 286+ var time = this.insertAndPlayingConfig.time;
 287+ var callback = this.insertAndPlayingConfig.callback;
 288+
 289+ // run the seek:
 290+ this.setCurrentTime( time ,function(){
 291+ if( this.insertAndPlayingConfig.restoreControls ){
 292+ this.playerElement.controls = true;
 293+ }
 294+ });
 295+ // Give some time for ipad to figure out whats going on:
 296+ setTimeout(function(){
 297+ _this.playerElement.load();
 298+ _this.playerElement.play();
 299+ },100);
 300+
 301+ //alert("insertAndPlayingConfig:: " + this.insertAndPlayingConfig);
 302+ // Run the callback
 303+ if( callback ){
 304+ callback();
 305+ }
 306+ },
 307+ switchSrc: function( src ){
 308+ mw.log( 'switchSrc' )
 309+ if( this.getPlayerElement() ){
 310+ try{
 311+ //this.playerElement.pause();
 312+ this.playerElement.src = src;
 313+ this.playerElement.load();
 314+ this.playerElement.play();
 315+ } catch( e ){
 316+ mw.log("Error: possible error in swiching source playback");
 317+ }
 318+ }
 319+ },
245320
246321 /**
247322 * Seek in a existing stream
@@ -277,47 +352,46 @@
278353 * @param {Float} position Seconds to set the time to
279354 * @param {Function} callback Function called once time has been set.
280355 */
281 - setCurrentTime: function( position , callback ) {
282 - var _this = this;
283 - //mw.log( 'native:setCurrentTime::: ' + position + ' : dur: ' + _this.getDuration() );
284 - this.getPlayerElement();
285 - if ( !this.playerElement ) {
286 - this.load( function() {
287 - _this.doSeekedCallback( position, callback );
288 - } );
289 - } else {
290 - _this.doSeekedCallback( position, callback );
291 - }
292 - },
293 -
294 - /**
295 - * Do the seek request with a callback
296 - *
297 - * @param {Float} position Position in seconds
298 - * @param {Function} callback Function to call once seeking completes
299 - */
300 - doSeekedCallback : function( position, callback ) {
 356+ setCurrentTime: function( time , callback, callbackCount ) {
301357 var _this = this;
 358+ if( !callbackCount )
 359+ callbackCount = 0;
302360 this.getPlayerElement();
303 - var once = function( event ) {
304 - callback();
305 - _this.playerElement.removeEventListener( 'seeked', once, false );
306 - };
307 - // Assume we will get to add the Listener before the seek is done
308 - _this.playerElement.currentTime = position;
309 - _this.playerElement.addEventListener( 'seeked', once, false );
 361+ if( _this.playerElement.readyState >= 1 ){
 362+ if( _this.playerElement.currentTime == time ){
 363+ callback();
 364+ return;
 365+ }
 366+ var once = function( event ) {
 367+ if( callback ){
 368+ callback();
 369+ }
 370+ _this.playerElement.removeEventListener( 'seeked', once, false );
 371+ };
 372+ // Assume we will get to add the Listener before the seek is done
 373+ _this.playerElement.addEventListener( 'seeked', once, false );
 374+ _this.playerElement.currentTime = time;
 375+ } else {
 376+ if( callbackCount >= 300 ){
 377+ mw.log("Error with seek request, media never in ready state");
 378+ return ;
 379+ }
 380+ setTimeout( function(){
 381+ _this.setCurrentTime( time, callback , callbackCount++);
 382+ }, 10 );
 383+ }
310384 },
311 -
 385+
312386 /**
313387 * Get the embed player time
314388 */
315389 getPlayerElementTime: function() {
316 - var _this = this;
 390+ var _this = this;
317391 // Make sure we have .vid obj
318392 this.getPlayerElement();
319393
320394 if ( !this.playerElement ) {
321 - mw.log( 'could not find video embed: ' + this.id + ' stop monitor' );
 395+ mw.log( 'Error: mwEmbedPlayer::getPlayerElementTime: missing ' + this.id + ' stop monitor' );
322396 return false;
323397 }
324398 // Return the playerElement currentTime
@@ -339,11 +413,13 @@
340414 * Pause the video playback
341415 * calls parent_pause to update the interface
342416 */
343 - pause: function() {
344 - this.getPlayerElement();
 417+ pause: function( ) {
 418+ this.getPlayerElement();
345419 this.parent_pause(); // update interface
346 - if ( this.playerElement ) {
347 - this.playerElement.pause();
 420+ if ( this.playerElement ) { // update player
 421+ if( !this.playerElement.paused ){
 422+ this.playerElement.pause();
 423+ }
348424 }
349425 },
350426
@@ -351,15 +427,28 @@
352428 * Play back the video stream
353429 * calls parent_play to update the interface
354430 */
355 - play: function() {
356 - this.getPlayerElement();
 431+ play: function( ) {
 432+
 433+ this.getPlayerElement();
357434 this.parent_play(); // update interface
358435 if ( this.playerElement && this.playerElement.play ) {
359 - this.playerElement.play();
 436+ // issue a play request if the media is paused:
 437+ if( this.playerElement.paused ){
 438+ this.playerElement.play();
 439+ }
360440 // re-start the monitor:
361441 this.monitor();
362442 }
363443 },
 444+ /**
 445+ * Stop the player ( end all listeners )
 446+ */
 447+ stop:function(){
 448+ if( this.playerElement ){
 449+ $j( this.playerElement ).unbind();
 450+ }
 451+ this.parent_stop();
 452+ },
364453
365454 /**
366455 * Toggle the Mute
@@ -435,7 +524,7 @@
436525 // No vid loaded
437526 mw.log( 'native::load() ... doEmbed' );
438527 this.onlyLoadFlag = true;
439 - this.doEmbedPlayer();
 528+ this.doEmbedHTML();
440529 this.onLoadedCallback = callback;
441530 } else {
442531 // Should not happen offten
@@ -448,7 +537,7 @@
449538 /**
450539 * Get /update the playerElement value
451540 */
452 - getPlayerElement: function () {
 541+ getPlayerElement: function () {
453542 this.playerElement = $j( '#' + this.pid ).get( 0 );
454543 return this.playerElement;
455544 },
@@ -495,19 +584,17 @@
496585 * Handle the native paused event
497586 */
498587 onPaused: function(){
499 - mw.log("native:paused:trigger");
500 - this.pause();
501 - $j( this ).trigger( 'pause' );
 588+ mw.log( "EmbedPlayer:native: OnPaused" );
 589+ this.parent_pause();
502590 },
503591
504592 /**
505593 * Handle the native play event
506594 */
507595 onPlay: function(){
508 - mw.log("native::play::trigger");
509 - if( !this.isPlaying () ){
510 - this.play();
511 - }
 596+ mw.log("EmbedPlayer:native:: OnPlay");
 597+ // Update the interface
 598+ this.parent_play();
512599 },
513600
514601 /**
@@ -519,8 +606,8 @@
520607 */
521608 onloadedmetadata: function() {
522609 this.getPlayerElement();
523 - mw.log( 'f:onloadedmetadata metadata ready Update duration:' + this.playerElement.duration + ' old dur: ' + this.getDuration() );
524 - if ( ! isNaN( this.playerElement.duration ) ) {
 610+ if ( this.playerElement && ! isNaN( this.playerElement.duration ) ) {
 611+ mw.log( 'f:onloadedmetadata metadata ready Update duration:' + this.playerElement.duration + ' old dur: ' + this.getDuration() );
525612 this.duration = this.playerElement.duration;
526613 }
527614
@@ -556,12 +643,15 @@
557644 * Used to update the bufferedPercent
558645 */
559646 onended: function() {
560 - var _this = this;
561 - //mw.log( 'native:onended:' + this.playerElement.currentTime + ' real dur:' + this.getDuration() );
562 - // run abstract player onEned if the abstract player still things we are playing
 647+ var _this = this;
 648+ mw.log( 'EmbedPlayer:native: onended:' + this.playerElement.currentTime + ' real dur:' + this.getDuration() +
 649+ ' insertAndPlayingConfig: ' + this.insertAndPlayingConfig);
563650
564 - if( this.isPlaying() ){
565 - this.onClipDone();
566 - }
 651+ if( this.insertAndPlayingConfig ){
 652+ this.restoreSourcePlayback();
 653+ this.insertAndPlayingConfig = false;
 654+ return ;
 655+ }
 656+ this.onClipDone();
567657 }
568658 };
Index: trunk/extensions/TimedMediaHandler/EmbedPlayer/mw.EmbedPlayerKplayer.js
@@ -31,13 +31,20 @@
3232 * Write the Embed html to the target
3333 */
3434 doEmbedHTML : function () {
35 - var _this = this;
36 - var playerPath = mw.getMwEmbedPath() + 'modules/EmbedPlayer/binPlayers/kaltura-player';
 35+ var _this = this;
3736
3837 mw.log("kPlayer:: embed src::" + _this.getSrc() );
3938 var flashvars = {};
4039 flashvars.autoPlay = "true";
 40+ var playerPath = mw.getMwEmbedPath() + 'modules/EmbedPlayer/binPlayers/kaltura-player';
4141 flashvars.entryId = mw.absoluteUrl( _this.getSrc() );
 42+
 43+ // Use a relative url if the protocal is file://
 44+ if( mw.parseUri( document.URL).protocol == 'file' ) {
 45+ playerPath = mw.getRelativeMwEmbedPath() + 'modules/EmbedPlayer/binPlayers/kaltura-player';
 46+ flashvars.entryId = _this.getSrc();
 47+ }
 48+
4249 flashvars.debugMode = "true";
4350 flashvars.fileSystemMode = "true";
4451 flashvars.widgetId = "_7463";
@@ -49,10 +56,10 @@
5057
5158 //flashvars.host = "www.kaltura.com";
5259 flashvars.externalInterfaceDisabled = 'false';
53 - //flashvars.skinPath = playerPath + '/skin.swf';
 60+ flashvars.skinPath = playerPath + '/skin.swf';
5461
5562 flashvars["full.skinPath"] = playerPath + '/LightDoodleskin.swf';
56 -
 63+
5764 var params = { };
5865 params.quality = "best";
5966 params.wmode = "opaque";
@@ -207,9 +214,18 @@
208215 */
209216 doSeek: function( percentage ) {
210217 var _this = this;
 218+ if ( this.supportsURLTimeEncoding() ){
 219+
 220+ // Make sure we could not do a local seek instead:
 221+ if ( !( percentage < this.bufferedPercent && this.playerElement.duration && !this.didSeekJump )) {
 222+ // We support URLTimeEncoding call parent seek:
 223+ this.parent_doSeek( percentage );
 224+ return;
 225+ }
 226+ }
 227+
211228 if( this.playerElement ) {
212 - var seekTime = percentage * this.getDuration();
213 -
 229+ var seekTime = percentage * this.getDuration();
214230 // Issue the seek to the flash player:
215231 this.playerElement.sendNotification('doSeek', seekTime);
216232

Follow-up revisions

RevisionCommit summaryAuthorDate
r74349Follow-up r74330: Message tweaks for consistenxy.raymond11:05, 6 October 2010

Status & tagging log