1 // set the dismissNativeWarn flag:
2 _global['dismissNativeWarn'] = false;
5 * Msg text is inherited from embedVideo (we should move it here (although can't load ctrlBuilder without parent EmbedVideo obj)
9 * base ctrlBuilder object
10 * @param the embedVideo element we are targeting
12 var ctrlBuilder = function( embedObj ) {
13 return this.init( embedObj );
17 * controlsBuilder prototype:
19 ctrlBuilder.prototype = {
20 init:function( embedObj, opt ) {
22 this.embedObj = embedObj;
24 // check for skin overrides for ctrlBuilder
25 if ( _global[ embedObj.skin_name + 'Config'] ) {
26 // clone as to not override prototype:
27 var _this = $j.extend( true, { }, this, _global[ embedObj.skin_name + 'Config'] );
35 // default volume layout is "vertical"
36 volume_layout : 'vertical',
42 getControls:function() {
43 // set up local pointer to the embedObj
44 var embedObj = this.embedObj;
45 // set up loadl ctrlBuilder ref
48 js_log( 'f:controlsBuilder:: opt:' + this.options );
49 this.id = ( embedObj.pc ) ? embedObj.pc.pp.id:embedObj.id;
50 this.available_width = embedObj.playerPixelWidth();
52 // Make pointer to the embedObj
53 this.embedObj = embedObj;
55 for ( var i in embedObj.supports ) {
56 _this.supports[i] = embedObj.supports[i];
60 if ( ( embedObj.roe ||
61 embedObj.wikiTitleKey ||
62 ( embedObj.media_element.timedTextSources &&
63 embedObj.media_element.timedTextSources() )
64 ) && embedObj.show_meta_link )
65 this.supports['closed_captions'] = true;
68 // Append options to body (if not already there)
69 if ( _this.body_options && $j( '#mv_vid_options_' + this.id ).length == 0 )
70 $j( 'body' ).append( this.components['mv_embedded_options'].o( this ) );
73 for ( var i in this.components ) {
74 if ( this.supports[i] ) {
75 if ( this.available_width > this.components[i].w ) {
76 // Special case with playhead don't add unless we have 60px
77 if ( i == 'play_head' && this.available_width < 60 )
79 o += this.components[i].o( this );
80 this.available_width -= this.components[i].w;
82 js_log( 'not enough space for control component:' + i );
90 * to be run once controls are attached to the dom
92 addControlHooks:function( $tp ) {
93 // set up local pointer to the embedObj
94 var embedObj = this.embedObj;
96 // var embed_id = (embedObj.pc!=null)?embedObj.pc.pp.id:embedObj.id;
99 $tp = $j( '#' + embedObj.id );
103 $tp.find( '.play-btn,.play-btn-large' ).unbind().btnBind().click( function() {
107 // add recommend firefox if we have non-native playback:
108 if ( embedObj.doNativeWarningCheck() ) {
109 $j( '#dc_' + embedObj.id ).hover(
111 if ( $j( '#gnp_' + embedObj.id ).length == 0 ) {
112 var toppos = ( embedObj.instanceOf == 'mvPlayList' ) ? 25:10;
113 $j( this ).append( '<div id="gnp_' + embedObj.id + '" class="ui-state-highlight ui-corner-all" ' +
114 'style="position:absolute;display:none;background:#FFF;top:' + toppos + 'px;left:10px;right:10px;">' +
115 gM( 'mwe-for_best_experience' ) +
116 '<br><input id="ffwarn_' + embedObj.id + '" type=\"checkbox\">' +
117 gM( 'mwe-do_not_warn_again' ) +
119 $j( '#ffwarn_' + embedObj.id ).click( function() {
120 if ( $j( this ).is( ':checked' ) ) {
121 // set up a cookie for 7 days:
122 $j.cookie( 'dismissNativeWarn', true, { expires: 7 } );
123 // set the current instance
124 _global['dismissNativeWarn'] = true;
125 $j( '#gnp_' + embedObj.id ).fadeOut( 'slow' );
127 _global['adismissNativeWarn'] = false;
128 $j.cookie( 'dismissNativeWarn', false );
133 if ( ( $j.cookie( 'dismissNativeWarn' ) !== true ) &&
134 _global['dismissNativeWarn'] === false ) {
135 $j( '#gnp_' + embedObj.id ).fadeIn( 'slow' );
139 $j( '#gnp_' + embedObj.id ).fadeOut( 'slow' );
144 if ( $j.browser.msie && $j.browser.version <= 6 ) {
145 $j( embedObj.id + ' .play-btn-large' ).pngFix();
150 $tp.find( '.timed-text' ).unbind().btnBind().click( function() {
151 embedObj.showTextInterface();
155 $tp.find( '.options-btn' ).unbind().btnBind().click( function() {
156 embedObj.doOptionsHTML();
159 // fullscreen binding:
160 $tp.find( '.fullscreen-btn' ).unbind().btnBind().click( function() {
161 embedObj.fullscreen();
164 js_log( " should add slider binding: " + $tp.find( '.play_head' ).length );
165 $tp.find( '.play_head' ).slider( {
170 start: function( event, ui ) {
171 var id = ( embedObj.pc != null ) ? embedObj.pc.pp.id:embedObj.id;
172 embedObj.userSlide = true;
173 $j( id + ' .play-btn-large' ).fadeOut( 'fast' );
174 // If playlist always start at 0
175 embedObj.start_time_sec = ( embedObj.instanceOf == 'mvPlayList' ) ? 0:
176 npt2seconds( embedObj.getTimeReq().split( '/' )[0] );
178 slide: function( event, ui ) {
179 var perc = ui.value / 1000;
180 embedObj.jump_time = seconds2npt( parseFloat( parseFloat( embedObj.getDuration() ) * perc ) + embedObj.start_time_sec );
181 // js_log('perc:' + perc + ' * ' + embedObj.getDuration() + ' jt:'+ this.jump_time);
182 if ( _this.long_time_disp ) {
183 embedObj.setStatus( gM( 'mwe-seek_to', embedObj.jump_time ) );
185 embedObj.setStatus( embedObj.jump_time );
187 // Update the thumbnail / frame
188 if ( embedObj.isPlaying == false ) {
189 embedObj.updateThumbPerc( perc );
192 change:function( event, ui ) {
193 // only run the onChange event if done by a user slide
194 // (otherwise it runs times it should not)
195 if ( embedObj.userSlide ) {
196 embedObj.userSlide = false;
197 embedObj.seeking = true;
198 // stop the monitor timer (if we can)
199 if ( embedObj.stopMonitor )
200 embedObj.stopMonitor();
202 var perc = ui.value / 1000;
203 // set seek time (in case we have to do a url seek)
204 embedObj.seek_time_sec = npt2seconds( embedObj.jump_time, true );
205 js_log( 'do jump to: ' + embedObj.jump_time + ' perc:' + perc + ' sts:' + embedObj.seek_time_sec );
206 embedObj.setStatus( gM( 'mwe-seeking' ) );
207 embedObj.doSeek( perc );
211 // up the z-index of the default status indicator:
212 $tp.find( '.play_head .ui-slider-handle' ).css( 'z-index', 4 );
213 $tp.find( '.play_head .ui-slider-range' ).addClass( 'ui-corner-all' ).css( 'z-index', 2 );
214 // extended class list for jQuery ui themeing (we can probably refactor this with custom buffering highlighter)
215 $tp.find( '.play_head' ).append( this.getMvBufferHtml() );
217 $opt = $j( '#mv_vid_options_' + embedObj.id );
218 // videoOptions ... @@todo should be merged with something more like kskin.js:
219 $opt.find( '.vo_selection' ).click( function() {
220 embedObj.displayHTML();
221 embedObj.showPlayerselect( $tp.find( '.videoOptionsComplete' ) );
225 $opt.find( '.vo_download' ).click( function() {
226 embedObj.displayHTML();
227 embedObj.showDownload( $tp.find( '.videoOptionsComplete' ) );
231 $opt.find( '.vo_showcode' ).click( function() {
232 embedObj.displayHTML();
233 embedObj.showShare( $tp.find( '.videoOptionsComplete' ) );
237 this.doVolumeBinding();
239 // check if we have any custom skin hooks to run (only one per skin)
240 if ( this.addSkinControlHooks && typeof( this.addSkinControlHooks ) == 'function' )
241 this.addSkinControlHooks();
243 doVolumeBinding:function() {
244 var embedObj = this.embedObj;
246 var $tp = $j( '#' + embedObj.id );
247 $tp.find( '.volume_control' ).unbind().btnBind().click( function() {
248 js_log( 'clicked volume control' );
249 $j( '#' + embedObj.id ).get( 0 ).toggleMute();
251 // add vertical volume display hover
252 if ( this.volume_layout == 'vertical' ) {
253 // default volume binding:
254 var hoverOverDelay = false;
255 var $tpvol = $tp.find( '.vol_container' );
256 $tp.find( '.volume_control' ).hover(
258 $tpvol.addClass( 'vol_container_top' );
259 // set to "below" if playing and embedType != native
260 if ( embedObj && embedObj.isPlaying && embedObj.isPlaying() && !embedObj.supports['overlays'] ) {
261 $tpvol.removeClass( 'vol_container_top' ).addClass( 'vol_container_below' );
263 $tpvol.fadeIn( 'fast' );
264 hoverOverDelay = true;
267 hoverOverDelay = false;
268 setTimeout( function doHideVolume() {
269 if ( !hoverOverDelay ) {
270 $tpvol.fadeOut( 'fast' );
283 slide: function( event, ui ) {
284 var perc = ui.value / 100;
285 // js_log('update volume:' + perc);
286 embedObj.updateVolumen( perc );
288 change:function( event, ui ) {
289 var perc = ui.value / 100;
291 $tp.find( '.volume_control span' ).removeClass( 'ui-icon-volume-on' ).addClass( 'ui-icon-volume-off' );
293 $tp.find( '.volume_control span' ).removeClass( 'ui-icon-volume-off' ).addClass( 'ui-icon-volume-on' );
295 var perc = ui.value / 100;
296 embedObj.updateVolumen( perc );
300 if ( this.volume_layout == 'vertical' )
301 sliderConf['orientation'] = "vertical";
303 $tp.find( '.volume-slider' ).slider( sliderConf );
305 getMvBufferHtml:function() {
306 return '<div class="ui-slider-range ui-slider-range-min ui-widget-header ' +
307 'ui-state-highlight ui-corner-all ' +
308 'mv_buffer" style="width:0px;height:100%;z-index:1;top:0px" />';
310 getComponent:function( component ) {
311 if ( this.components[ component ] ) {
312 return this.components[ component ].o( this );
318 * components take in the embedObj and return some html for the given component.
319 * components can be overwritten by skin javascript
324 'o':function( ctrlObj ) {
331 'o':function( ctrlObj ) {
332 // get dynamic position for big play button (@@todo maybe use margin:auto ? )
333 return $j( '<div/>' ).attr( {
334 'title' : gM( 'mwe-play_clip' ),
335 'class' : "ui-state-default play-btn-large"
338 'left' : ( ( ctrlObj.embedObj.playerPixelWidth() - this.w ) / 2 ),
339 'top' : ( ( ctrlObj.embedObj.playerPixelHeight() - this.h ) / 2 )
341 .wrap( '<div/>' ).parent().html();
344 'mv_embedded_options': {
346 'o':function( ctrlObj ) {
347 var o = '<div id="mv_vid_options_' + ctrlObj.id + '" class="videoOptions">' +
348 '<div class="videoOptionsTop"></div>' +
349 '<div class="videoOptionsBox">' +
350 '<div class="block">' +
351 '<h6>Video Options</h6>' +
353 '<div class="block">' +
354 '<p class="short_match vo_selection"><a href="#"><span>' + gM( 'mwe-chose_player' ) + '</span></a></p>' +
355 '<p class="short_match vo_download"><a href="#"><span>' + gM( 'mwe-download' ) + '</span></a></p>' +
356 '<p class="short_match vo_showcode"><a href="#"><span>' + gM( 'mwe-share' ) + '</span></a></p>';
358 // link to the stream page if we are not already there:
359 if ( ( ctrlObj.embedObj.roe || ctrlObj.embedObj.linkback ) && typeof mv_stream_interface == 'undefined' )
360 o += '<p class="short_match"><a href="javascript:$j(\'#' + ctrlObj.id + '\').get(0).doLinkBack()"><span><strong>Source Page</strong></span></a></p>';
363 '</div><!--videoOptionsInner-->' +
364 '<div class="videoOptionsBot"></div>' +
365 '</div><!--videoOptions-->';
371 'o':function( ctrlObj ) {
372 return '<div title="' + gM( 'mwe-player_fullscreen' ) + '" class="ui-state-default ui-corner-all ui-icon_link rButton fullscreen-btn">' +
373 '<span class="ui-icon ui-icon-arrow-4-diag"></span>' +
379 'o':function( ctrlObj ) {
380 return '<div title="' + gM( 'mwe-player_options' ) + '" class="ui-state-default ui-corner-all ui-icon_link rButton options-btn">' +
381 '<span class="ui-icon ui-icon-wrench"></span>' +
387 'o':function( ctrlObj ) {
388 return '<div title="' + gM( 'mwe-play_clip' ) + '" class="ui-state-default ui-corner-all ui-icon_link lButton play-btn">' +
389 '<span class="ui-icon ui-icon-play"/>' +
395 'o':function( ctrlObj ) {
396 return '<div title="' + gM( 'mwe-closed_captions' ) + '" class="ui-state-default ui-corner-all ui-icon_link rButton timed-text">' +
397 '<span class="ui-icon ui-icon-comment"></span>' +
403 'o':function( ctrlObj ) {
405 if ( ctrlObj.volume_layout == 'horizontal' )
406 o += '<div class="ui-slider ui-slider-horizontal rButton volume-slider"></div>';
408 o += '<div title="' + gM( 'mwe-volume_control' ) + '" class="ui-state-default ui-corner-all ui-icon_link rButton volume_control">' +
409 '<span class="ui-icon ui-icon-volume-on"></span>';
411 if ( ctrlObj.volume_layout == 'vertical' ) {
412 o += '<div style="position:absolute;display:none;left:0px;" class="vol_container ui-corner-all">' +
413 '<div class="volume-slider" ></div>' +
422 'o':function( ctrlObj ) {
423 return '<div class="ui-widget time-disp">' + ctrlObj.embedObj.getTimeReq() + '</div>';
427 'w':0, // special case (takes up remaining space)
428 'o':function( ctrlObj ) {
429 return '<div class="play_head" style="width: ' + ( ctrlObj.available_width - 34 ) + 'px;"></div>';