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