* added k-attribution link in credits
[lhc/web/wiklou.git] / js2 / mwEmbed / skins / ctrlBuilder.js
1 // set the dismissNativeWarn flag:
2 _global['dismissNativeWarn'] = false;
3
4 /**
5 * Msg text is inherited from embedVideo (we should move it here (although can't load ctrlBuilder without parent EmbedVideo obj)
6 /
7
8 /**
9 * base ctrlBuilder object
10 * @param the embedVideo element we are targeting
11 */
12 var ctrlBuilder = function( embedObj ) {
13 return this.init( embedObj );
14 };
15
16 /*
17 * controlsBuilder prototype:
18 */
19 ctrlBuilder.prototype = {
20 init:function( embedObj, opt ) {
21 var _this = this;
22 this.embedObj = embedObj;
23
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'] );
28 return _this;
29 }
30 return this;
31 },
32 pClass : 'mv-player',
33 long_time_disp: true,
34 body_options : true,
35 // default volume layout is "vertical"
36 volume_layout : 'vertical',
37 height:29,
38 supports: {
39 'options':true,
40 'borders':true
41 },
42 getControls:function() {
43 // set up local pointer to the embedObj
44 var embedObj = this.embedObj;
45 // set up loadl ctrlBuilder ref
46 var _this = this;
47
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();
51
52 // Make pointer to the embedObj
53 this.embedObj = embedObj;
54 var _this = this;
55 for ( var i in embedObj.supports ) {
56 _this.supports[i] = embedObj.supports[i];
57 };
58
59 // Special case vars:
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;
66
67
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 ) );
71
72 var o = '';
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 )
78 continue;
79 o += this.components[i].o( this );
80 this.available_width -= this.components[i].w;
81 } else {
82 js_log( 'not enough space for control component:' + i );
83 }
84 }
85 }
86 return o;
87 },
88 /*
89 * addControlHooks
90 * to be run once controls are attached to the dom
91 */
92 addControlHooks:function( $tp ) {
93 // Set up local pointer to the embedObj
94 var embedObj = this.embedObj;
95 var _this = this;
96
97 if ( !$tp )
98 $tp = $j( '#' + embedObj.id );
99
100
101 // Add play hook:
102 $tp.find( '.play-btn,.play-btn-large' ).unbind().btnBind().click( function() {
103 embedObj.play();
104 } );
105
106 // Add recommend firefox if we have non-native playback:
107 if ( embedObj.doNativeWarningCheck() ) {
108 $j( '#dc_' + embedObj.id ).hover(
109 function() {
110 if ( $j( '#gnp_' + embedObj.id ).length == 0 ) {
111 var toppos = ( embedObj.instanceOf == 'mvPlayList' ) ? 25:10;
112 $j( this ).append( '<div id="gnp_' + embedObj.id + '" class="ui-state-highlight ui-corner-all" ' +
113 'style="position:absolute;display:none;background:#FFF;top:' + toppos + 'px;left:10px;right:10px;">' +
114 gM( 'mwe-for_best_experience' ) +
115 '<br><input id="ffwarn_' + embedObj.id + '" type=\"checkbox\">' +
116 gM( 'mwe-do_not_warn_again' ) +
117 '</div>' );
118 $j( '#ffwarn_' + embedObj.id ).click( function() {
119 if ( $j( this ).is( ':checked' ) ) {
120 // set up a cookie for 7 days:
121 $j.cookie( 'dismissNativeWarn', true, { expires: 7 } );
122 // set the current instance
123 _global['dismissNativeWarn'] = true;
124 $j( '#gnp_' + embedObj.id ).fadeOut( 'slow' );
125 } else {
126 _global['adismissNativeWarn'] = false;
127 $j.cookie( 'dismissNativeWarn', false );
128 }
129
130 } );
131 }
132 if ( ( $j.cookie( 'dismissNativeWarn' ) !== true ) &&
133 _global['dismissNativeWarn'] === false ) {
134 $j( '#gnp_' + embedObj.id ).fadeIn( 'slow' );
135 }
136 },
137 function() {
138 $j( '#gnp_' + embedObj.id ).fadeOut( 'slow' );
139 }
140 );
141 }
142
143 if ( $j.browser.msie && $j.browser.version <= 6 ) {
144 $j( embedObj.id + ' .play-btn-large' ).pngFix();
145 }
146
147
148 // Captions binding:
149 $tp.find( '.timed-text' ).unbind().btnBind().click( function() {
150 embedObj.showTextInterface();
151 } );
152
153 // Options binding:
154 $tp.find( '.options-btn' ).unbind().btnBind().click( function() {
155 embedObj.doOptionsHTML();
156 } );
157
158 // Fullscreen binding:
159 $tp.find( '.fullscreen-btn' ).unbind().btnBind().click( function() {
160 embedObj.fullscreen();
161 } );
162
163 js_log( " should add slider binding: " + $tp.find( '.play_head' ).length );
164 $tp.find( '.play_head' ).slider( {
165 range: "min",
166 value: 0,
167 min: 0,
168 max: 1000,
169 start: function( event, ui ) {
170 var id = ( embedObj.pc != null ) ? embedObj.pc.pp.id:embedObj.id;
171 embedObj.userSlide = true;
172 $j( id + ' .play-btn-large' ).fadeOut( 'fast' );
173 // If playlist always start at 0
174 embedObj.start_time_sec = ( embedObj.instanceOf == 'mvPlayList' ) ? 0:
175 npt2seconds( embedObj.getTimeReq().split( '/' )[0] );
176 },
177 slide: function( event, ui ) {
178 var perc = ui.value / 1000;
179 embedObj.jump_time = seconds2npt( parseFloat( parseFloat( embedObj.getDuration() ) * perc ) + embedObj.start_time_sec );
180 // js_log('perc:' + perc + ' * ' + embedObj.getDuration() + ' jt:'+ this.jump_time);
181 if ( _this.long_time_disp ) {
182 embedObj.setStatus( gM( 'mwe-seek_to', embedObj.jump_time ) );
183 } else {
184 embedObj.setStatus( embedObj.jump_time );
185 }
186 // Update the thumbnail / frame
187 if ( embedObj.isPlaying == false ) {
188 embedObj.updateThumbPerc( perc );
189 }
190 },
191 change:function( event, ui ) {
192 // only run the onChange event if done by a user slide
193 // (otherwise it runs times it should not)
194 if ( embedObj.userSlide ) {
195 embedObj.userSlide = false;
196 embedObj.seeking = true;
197 // stop the monitor timer (if we can)
198 if ( embedObj.stopMonitor )
199 embedObj.stopMonitor();
200
201 var perc = ui.value / 1000;
202 // set seek time (in case we have to do a url seek)
203 embedObj.seek_time_sec = npt2seconds( embedObj.jump_time, true );
204 js_log( 'do jump to: ' + embedObj.jump_time + ' perc:' + perc + ' sts:' + embedObj.seek_time_sec );
205 embedObj.setStatus( gM( 'mwe-seeking' ) );
206 embedObj.doSeek( perc );
207 }
208 }
209 } );
210 // Up the z-index of the default status indicator:
211 $tp.find( '.play_head .ui-slider-handle' ).css( 'z-index', 4 );
212 $tp.find( '.play_head .ui-slider-range' ).addClass( 'ui-corner-all' ).css( 'z-index', 2 );
213
214 // Extended class list for jQuery ui themeing
215 //(we can probably refactor this with custom buffering highlighter)
216 $tp.find( '.play_head' ).append( this.getBufferHtml() );
217
218 $opt = $j( '#mv_vid_options_' + embedObj.id );
219 // videoOptions ... @@todo should be merged with something more like kskin.js:
220 $opt.find( '.vo_selection' ).click( function() {
221 embedObj.displayHTML();
222 embedObj.showPlayerselect( $tp.find( '.videoOptionsComplete' ) );
223 $opt.hide();
224 return false;
225 } );
226 $opt.find( '.vo_download' ).click( function() {
227 embedObj.displayHTML();
228 embedObj.showDownload( $tp.find( '.videoOptionsComplete' ) );
229 $opt.hide();
230 return false;
231 } )
232 $opt.find( '.vo_showcode' ).click( function() {
233 embedObj.displayHTML();
234 embedObj.showShare( $tp.find( '.videoOptionsComplete' ) );
235 $opt.hide();
236 return false;
237 } );
238 this.doVolumeBinding();
239
240 // Check if we have any custom skin Bindings to run
241 if ( this.addSkinControlBindings && typeof( this.addSkinControlBindings ) == 'function' )
242 this.addSkinControlBindings();
243 },
244 doVolumeBinding:function() {
245 var embedObj = this.embedObj;
246 var _this = this;
247 var $tp = $j( '#' + embedObj.id );
248 $tp.find( '.volume_control' ).unbind().btnBind().click( function() {
249 js_log( 'clicked volume control' );
250 $j( '#' + embedObj.id ).get( 0 ).toggleMute();
251 } );
252
253 // Add vertical volume display hover
254 if ( this.volume_layout == 'vertical' ) {
255 // default volume binding:
256 var hoverOverDelay = false;
257 var $tpvol = $tp.find( '.vol_container' );
258 $tp.find( '.volume_control' ).hover(
259 function() {
260 $tpvol.addClass( 'vol_container_top' );
261 // set to "below" if playing and embedType != native
262 if ( embedObj && embedObj.isPlaying && embedObj.isPlaying() && !embedObj.supports['overlays'] ) {
263 $tpvol.removeClass( 'vol_container_top' ).addClass( 'vol_container_below' );
264 }
265 $tpvol.fadeIn( 'fast' );
266 hoverOverDelay = true;
267 },
268 function() {
269 hoverOverDelay = false;
270 setTimeout( function doHideVolume() {
271 if ( !hoverOverDelay ) {
272 $tpvol.fadeOut( 'fast' );
273 }
274 }, 500 );
275 }
276 );
277 }
278
279 // Setup play-head slider:
280 var sliderConf = {
281 range: "min",
282 value: 80,
283 min: 0,
284 max: 100,
285 slide: function( event, ui ) {
286 var perc = ui.value / 100;
287 // js_log('update volume:' + perc);
288 embedObj.updateVolumen( perc );
289 },
290 change:function( event, ui ) {
291 var perc = ui.value / 100;
292 if ( perc == 0 ) {
293 $tp.find( '.volume_control span' ).removeClass( 'ui-icon-volume-on' ).addClass( 'ui-icon-volume-off' );
294 } else {
295 $tp.find( '.volume_control span' ).removeClass( 'ui-icon-volume-off' ).addClass( 'ui-icon-volume-on' );
296 }
297 var perc = ui.value / 100;
298 embedObj.updateVolumen( perc );
299 }
300 }
301
302 if ( this.volume_layout == 'vertical' )
303 sliderConf['orientation'] = "vertical";
304
305 $tp.find( '.volume-slider' ).slider( sliderConf );
306 },
307 /*
308 * Gets the Buffer Html that overlays the playhead
309 */
310 getBufferHtml:function() {
311 return '<div class="ui-slider-range ui-slider-range-min ui-widget-header ' +
312 'ui-state-highlight ui-corner-all ' +
313 'mv_buffer" style="width:0px;height:100%;z-index:1;top:0px" />';
314 },
315 getComponent:function( component ) {
316 if ( this.components[ component ] ) {
317 return this.components[ component ].o( this );
318 } else {
319 return false;
320 }
321 },
322 /*
323 * components take in the embedObj and return some html for the given component.
324 * components can be overwritten by skin javascript
325 */
326 components: {
327 'borders': {
328 'w':8,
329 'o':function( ctrlObj ) {
330 return '';
331 }
332 },
333 'play-btn-large': {
334 'w' : 130,
335 'h' : 96,
336 'o':function( ctrlObj ) {
337 // get dynamic position for big play button (@@todo maybe use margin:auto ? )
338 return $j( '<div/>' ).attr( {
339 'title' : gM( 'mwe-play_clip' ),
340 'class' : "ui-state-default play-btn-large"
341 } )
342 .css( {
343 'left' : ( ( ctrlObj.embedObj.playerPixelWidth() - this.w ) / 2 ),
344 'top' : ( ( ctrlObj.embedObj.playerPixelHeight() - this.h ) / 2 )
345 } )
346 .wrap( '<div/>' ).parent().html();
347 }
348 },
349 'mv_embedded_options': {
350 'w':0,
351 'o':function( ctrlObj ) {
352 var o = '<div id="mv_vid_options_' + ctrlObj.id + '" class="videoOptions">' +
353 '<div class="videoOptionsTop"></div>' +
354 '<div class="videoOptionsBox">' +
355 '<div class="block">' +
356 '<h6>Video Options</h6>' +
357 '</div>' +
358 '<div class="block">' +
359 '<p class="short_match vo_selection"><a href="#"><span>' + gM( 'mwe-chose_player' ) + '</span></a></p>' +
360 '<p class="short_match vo_download"><a href="#"><span>' + gM( 'mwe-download' ) + '</span></a></p>' +
361 '<p class="short_match vo_showcode"><a href="#"><span>' + gM( 'mwe-share' ) + '</span></a></p>';
362
363 // link to the stream page if we are not already there:
364 if ( ( ctrlObj.embedObj.roe || ctrlObj.embedObj.linkback ) && typeof mv_stream_interface == 'undefined' )
365 o += '<p class="short_match"><a href="javascript:$j(\'#' + ctrlObj.id + '\').get(0).doLinkBack()"><span><strong>Source Page</strong></span></a></p>';
366
367 o += '</div>' +
368 '</div><!--videoOptionsInner-->' +
369 '<div class="videoOptionsBot"></div>' +
370 '</div><!--videoOptions-->';
371 return o;
372 }
373 },
374 'fullscreen': {
375 'w':20,
376 'o':function( ctrlObj ) {
377 return '<div title="' + gM( 'mwe-player_fullscreen' ) + '" class="ui-state-default ui-corner-all ui-icon_link rButton fullscreen-btn">' +
378 '<span class="ui-icon ui-icon-arrow-4-diag"></span>' +
379 '</div>'
380 }
381 },
382 'options': {
383 'w':26,
384 'o':function( ctrlObj ) {
385 return '<div title="' + gM( 'mwe-player_options' ) + '" class="ui-state-default ui-corner-all ui-icon_link rButton options-btn">' +
386 '<span class="ui-icon ui-icon-wrench"></span>' +
387 '</div>';
388 }
389 },
390 'pause': {
391 'w':24,
392 'o':function( ctrlObj ) {
393 return '<div title="' + gM( 'mwe-play_clip' ) + '" class="ui-state-default ui-corner-all ui-icon_link lButton play-btn">' +
394 '<span class="ui-icon ui-icon-play"/>' +
395 '</div>';
396 }
397 },
398 'closed_captions': {
399 'w':23,
400 'o':function( ctrlObj ) {
401 return '<div title="' + gM( 'mwe-closed_captions' ) + '" class="ui-state-default ui-corner-all ui-icon_link rButton timed-text">' +
402 '<span class="ui-icon ui-icon-comment"></span>' +
403 '</div>'
404 }
405 },
406 'volume_control': {
407 'w':23,
408 'o':function( ctrlObj ) {
409 var o = '';
410 if ( ctrlObj.volume_layout == 'horizontal' )
411 o += '<div class="ui-slider ui-slider-horizontal rButton volume-slider"></div>';
412
413 o += '<div title="' + gM( 'mwe-volume_control' ) + '" class="ui-state-default ui-corner-all ui-icon_link rButton volume_control">' +
414 '<span class="ui-icon ui-icon-volume-on"></span>';
415
416 if ( ctrlObj.volume_layout == 'vertical' ) {
417 o += '<div style="position:absolute;display:none;left:0px;" class="vol_container ui-corner-all">' +
418 '<div class="volume-slider" ></div>' +
419 '</div>';
420 }
421 o += '</div>';
422 return o;
423 }
424 },
425 'time_display': {
426 'w':90,
427 'o':function( ctrlObj ) {
428 return '<div class="ui-widget time-disp">' + ctrlObj.embedObj.getTimeReq() + '</div>';
429 }
430 },
431 'play_head': {
432 'w':0, // special case (takes up remaining space)
433 'o':function( ctrlObj ) {
434 return '<div class="play_head" style="width: ' + ( ctrlObj.available_width - 34 ) + 'px;"></div>';
435 }
436 }
437 }
438 };