* made wgMaxUploadSize check work with js2/firefogg uploading interface.
[lhc/web/wiklou.git] / js2 / mwEmbed / libClipEdit / mvClipEdit.js
1 /*
2 hanndles clip edit controls
3 'inoutpoints':0, //should let you set the in and out points of clip
4 'panzoom':0, //should allow setting keyframes and tweenning modes
5 'overlays':0, //should allow setting "locked to clip" overlay tracks
6 'audio':0 //should allow controlling the audio volume (with keyframes)
7 */
8 //set gMsg object:
9 loadGM( {
10 "mv_crop":"Crop Image",
11 "mv_apply_crop":"Apply Crop to Image",
12 "mv_reset_crop":"Rest Crop",
13 "mv_insert_image_page":"Insert Into page",
14 "mv_insert_into_sequence": "Insert Into Sequence",
15 "mv_preview_insert":"Preview Insert",
16 "mv_cancel_image_insert": "Cancel Insert",
17
18 "sc_fileopts":"Clip Detail Edit",
19 "sc_inoutpoints":"Set In-Out points",
20 "sc_overlays":"Overlays",
21 "sc_audio":"Audio Control",
22 "sc_duration":"Duration",
23
24 "mv_template_properties":"Template Properties",
25 "mv_custom_title":"Custom Title",
26 "mv_edit_properties":"Edit Properties",
27 "mv_other_properties":"Other Properties",
28 "mv_resource_page" : "Resource Page:",
29
30 "mv_set_in_out_points": "Set in-out points",
31 "mv_start_time": "Start Time",
32 "mv_end_time": "End Time",
33 "mv_preview_inout": "Preview/Play In-out points"
34 });
35
36 var default_clipedit_values = {
37 'rObj': null, // the resource object
38 'clip_disp_ct':null,//target clip disp
39 'control_ct':null, //control container
40 'media_type': null, //media type
41 'parent_ct': null, //parent container
42
43 'p_rsdObj': null, //parent remote search object
44 'p_seqObj': null, //parent sequence Object
45
46 'controlActionsCb' : null, //the object that configures control Action callbacks
47
48 'edit_action': null, //the requested edit action
49 'profile': 'inpage' //the given profile either "inpage" or "sequence"
50 }
51 var mvClipEdit = function(iObj) {
52 return this.init(iObj);
53 };
54 mvClipEdit.prototype = {
55
56 selTool:null, //selected tool
57 crop: null, //the crop values
58 base_img_src:null,
59
60 init:function( iObj){
61 //init object:
62 for(var i in default_clipedit_values){
63 if( iObj[i] ){
64 this[i] = iObj[i];
65 }
66 }
67
68 //if media type was not supplied detect for resource if possible:
69 //@@todo more advanced detection.
70 if(!this.media_type && this.rObj && this.rObj.type ){
71 if( this.rObj.type.indexOf("image/") === 0){
72 this.media_type = 'image';
73 }else if( this.rObj.type.indexOf("video/") === 0){
74 this.media_type = 'video';
75 }else if( this.rObj.type.indexOf("text/") === 0){
76 this.media_type = 'template';
77 }
78 }
79
80 //display control:
81 if(this.profile == 'sequence'){
82 this.doEditTypesMenu();
83 this.doDisplayEdit();
84 }else{
85 //check the media_type:
86 js_log('mvClipEdit:: media type:' + this.media_type + ' base width: ' + this.rObj.width + ' bh: ' + this.rObj.height);
87 //could seperate out into media Types objects for now just call method
88 if(this.media_type == 'image'){
89 this.setUpImageCtrl();
90 }else if(this.media_type=='video'){
91 this.setUpVideoCtrl();
92 }
93 }
94 },
95
96 //master edit types object:
97 //maybe we should refactor these into their own classes
98 //more refactor each media type should be its own class inheriting the shared baseEditType object
99 edit_types:{
100 'duration':{
101 'media':['image','template'],
102 'doEdit':function( _this, target ){
103 //(_this is a smilClip instance)
104 //do clock mouse scroll duration editor
105 $j(target).html(
106 '<label for="ce_dur">Duration: </label>' +
107 '<input name="ce_dur" tabindex="1" maxlength="11" value="'+
108 seconds2npt( _this.rObj.getDuration() )+
109 '" size="10"/>'+
110 '</div>'
111 ).children("input[name='ce_dur']").change(function(){
112 js_log("update duration:" + $j(this).val() );
113 //update the parent sequence object:
114 _this.rObj.dur = smilParseTime( $j(this).val() );
115 //update the playlist:
116 _this.p_seqObj.do_refresh_timeline( true );
117 });
118
119 }
120 },
121 'inoutpoints':{
122 'media':['video'],
123 'doEdit':function( _this, target ){
124 //do clock mouse scroll duration editor
125 var end_ntp = ( _this.rObj.embed.end_ntp) ? _this.rObj.embed.end_ntp : _this.rObj.embed.getDuration();
126 if(!end_ntp)
127 end_ntp = seconds2npt( _this.rObj.dur );
128
129 var start_ntp = (_this.rObj.embed.start_ntp) ? _this.rObj.embed.start_ntp : seconds2npt( 0 );
130 if(!start_ntp)
131 seconds2npt( 0 );
132
133 $j(target).html(
134 _this.getSetInOutHtml({
135 'start_ntp' : start_ntp,
136 'end_ntp' : end_ntp
137 })
138 );
139 _this.setInOutBindings();
140 }
141 },
142 'fileopts':{
143 'media':['image','video','template'],
144 'doEdit':function(_this, target ){
145 //if media type is template we have to query to get its URI to get its paramaters
146 if(_this.media_type == 'template' && !_this.rObj.tVars){
147 mv_set_loading('#sub_cliplib_ic');
148 var reqObj ={ 'action':'query',
149 'prop':'revisions',
150 'titles': _this.rObj.uri,
151 'rvprop':'content'
152 };
153 //get the interface uri from the plObject
154 var api_url = _this.p_seqObj.plObj.interface_url;
155 //first check
156 do_api_req( {
157 'data':reqObj,
158 'url':api_url
159 }, function(data){
160 if(typeof data.query.pages == 'undefined')
161 return _this.doEditOpts(target);
162 for(var i in data.query.pages){
163 var page = data.query.pages[i];
164 if(!page['revisions'] || !page['revisions'][0]['*']){
165 return _this.doEditOpts(target);
166 }else{
167 var template_rev = page['revisions'][0]['*'];
168 }
169 }
170
171 //do a regular ex to get the ~likely~ template values
172 //(of course this sucks)
173 //but maybe this will make its way into the api sometime soon to support wysiwyg type editors
174 //idealy it would expose a good deal of info about the template params
175 js_log('matching against: ' + template_rev);
176 var tempVars = template_rev.match(/\{\{\{([^\}]*)\}\}\}/gi);
177 //clean up results:
178 _this.rObj.tVars = new Array();
179 for(var i=0; i < tempVars.length; i++){
180 var tvar = tempVars[i].replace('{{{','').replace('}}}','');
181 //strip anything after a |
182 if(tvar.indexOf('|') != -1){
183 tvar = tvar.substr(0, tvar.indexOf('|'));
184 }
185 //check for duplicates:
186 var do_add=true;
187 for(var j=0; j < _this.rObj.tVars.length; j++){
188 js_log('checking: ' + _this.rObj.tVars[j] + ' against:' + tvar);
189 if( _this.rObj.tVars[j] == tvar)
190 do_add=false;
191 }
192 //add the template vars to the output obj
193 if(do_add)
194 _this.rObj.tVars.push( tvar );
195 }
196 _this.doEditOpts(target);
197 }
198 );
199 }else{
200 _this.doEditOpts(target);
201 }
202 }
203 },
204 'overlays':{
205 'media':['image','video'],
206 'doEdit':function(_this, target){
207 //do clock mouse scroll duration editor
208 $j(target).html('<h3>Current Overlays:</h3>Add,Remove,Modify');
209 }
210 },
211 'audio':{
212 'media':['image','video', 'template'],
213 'doEdit':function(_this, target){
214 //do clock mouse scroll duration editor
215 $j(target).html('<h3>Audio Volume:</h3>');
216 }
217 }
218 },
219 doEditOpts:function(target){
220 var _this = this;
221 //add html for rObj resource:
222 var o= '<table>' +
223 '<tr>' +
224 '<td colspan="2"><b>'+gM('mv_edit_properties')+'</b></td>'+
225 '</tr>'+
226 '<tr>'+
227 '<td>' +
228 gM('mv_custom_title') +
229 '</td>'+
230 '<td><input type="text" size="15" maxwidth="255" value="';
231 if(_this.rObj.title != null)
232 o+=_this.rObj.title;
233 o+='">'+
234 '</td>'+
235 '</tr>';
236 if( _this.rObj.tVars){
237 var existing_p = _this.rObj.params;
238 var testing_a = _this.rObj.tVars;
239 //debugger;
240 o+= '<tr>'+
241 '<td colspan="2"><b>' + gM('mv_template_properties') + '</b></td>'+
242 '</tr>';
243 for(var i =0; i < _this.rObj.tVars.length ; i++){
244 o+='<tr>'+
245 '<td>' +
246 _this.rObj.tVars[i] +
247 '</td>' +
248 '<td><input name="'+_this.rObj.tVars[i]+'" class="ic_tparam" type="text" size="15" maxwidth="255" value="';
249 if(_this.rObj.params[ _this.rObj.tVars[i] ]){
250 o+= _this.rObj.params[ _this.rObj.tVars[i] ];
251 }
252 o+='">'+
253 '</td>'+
254 '</tr>';
255 }
256 }
257 if(typeof wgArticlePath != 'undefined' ){
258 var res_src = wgArticlePath.replace(/\$1/, _this.rObj.uri );
259 var res_title = _this.rObj.uri;
260 }else{
261 //var res_page =
262 var res_src = _this.rObj.src;
263 var res_title = parseUri(_this.rObj.src).file;
264 }
265 o+= '<tr>'+
266 '<td colspan="2"><b>'+gM('mv_other_properties')+'</b></td>'+
267 '</tr>'+
268 '<tr>'+
269 '<td>' +
270 gM('mv_resource_page') +
271 '</td>' +
272 '<td><a href="' + res_src +'" '+
273 ' target="new">'+
274 res_title + '</a>'+
275 '</td>'+
276 '</tr>';
277 o+='</table>';
278
279 $j(target).html ( o );
280
281 //add update bindings
282 $j(target + ' .ic_tparam').change(function(){
283 js_log("updated tparam::" + $j(this).attr("name"));
284 //update param value:
285 _this.rObj.params[ $j(this).attr("name") ] = $j(this).val();
286 //re-parse & update template
287 var template_wiki_text = '{{' + _this.rObj.uri;
288 for(var i =0;i < _this.rObj.tVars.length ; i++){
289
290 template_wiki_text += "\n|"+_this.rObj.tVars[i] + ' = ' + _this.rObj.params[ _this.rObj.tVars[i] ] ;
291 }
292 template_wiki_text += "\n}}";
293 var reqObj ={
294 'action':'parse',
295 'title' : _this.p_seqObj.plObj.mTitle,
296 'text' : template_wiki_text
297 };
298 $j( _this.rObj.embed ).html( mv_get_loading_img() );
299
300 var api_url = _this.p_seqObj.plObj.interface_url;
301 do_api_req({
302 'data':reqObj,
303 'url':api_url
304 },function(data){
305 if(data.parse.text['*']){
306 //update the target
307 $j( _this.rObj.embed ).html( data.parse.text['*'] );
308 }
309 })
310 })
311
312 //update doFocusBindings
313 if( _this.p_seqObj )
314 _this.p_seqObj.doFocusBindings();
315 },
316 doEditTypesMenu:function(){
317 var _this = this;
318 //add in subMenus if set
319 //check for submenu and add to item container
320 var o='';
321 var tabc ='';
322 o+= '<div id="mv_submenu_clipedit">';
323 o+='<ul>';
324 var first_tab = false;
325 $j.each(this.edit_types, function(sInx, editType){
326 //check if the given editType is valid for our given media type
327 var include = false;
328 for(var i =0; i < editType.media.length;i++){
329 if( editType.media[i] == _this.media_type){
330 include = true;
331 if(!first_tab)
332 first_tab = sInx;
333 }
334 }
335 if(include){
336 o+= '<li>'+
337 '<a id="mv_smi_'+sInx+'" href="#sc_' + sInx + '">' + gM('sc_' + sInx ) + '</a>'+
338 '</li>';
339 tabc += '<div id="sc_' + sInx + '" style="overflow:auto;" ></div>';
340 }
341 });
342 o+= '</ul>' + tabc;
343 o+= '</div>';
344 //add sub menu container with menu html:
345 $j('#'+this.control_ct).html( o ) ;
346 //set up bindings:
347 $j('#mv_submenu_clipedit').tabs({
348 selected: 0,
349 select: function(event, ui) {
350 _this.doDisplayEdit( $j(ui.tab).attr('id').replace('mv_smi_', '') );
351 }
352 }).addClass('ui-tabs-vertical ui-helper-clearfix');
353 //close left:
354 $j("#mv_submenu_clipedit li").removeClass('ui-corner-top').addClass('ui-corner-left');
355 //update the default edit display:
356 _this.doDisplayEdit( first_tab );
357 },
358 doDisplayEdit:function( edit_type ){
359 if(!edit_type)
360 return false;
361 js_log('doDisplayEdit: ' + edit_type );
362
363 //do edit interface for that edit type:
364 if( this.edit_types[ edit_type ].doEdit )
365 this.edit_types[ edit_type ].doEdit(this, '#sc_'+edit_type );
366 },
367 setUpVideoCtrl:function(){
368 js_log('setUpVideoCtrl:f');
369 var _this = this;
370 var eb = $j('#embed_vid').get(0);
371 //turn on preview to avoid onDone actions
372 eb.preview_mode = true;
373 $j('#'+this.control_ct).html('<h3>Edit Video Tools:</h3>');
374 if( eb.supportsURLTimeEncoding() ){
375 $j('#'+this.control_ct).append(
376 _this.getSetInOutHtml({
377 'start_ntp' : eb.start_ntp,
378 'end_ntp' : eb.end_ntp
379 })
380 );
381 _this.setInOutBindings();
382 }
383 //if in a sequence we have no need for insertDesc
384 if( !_this.p_seqObj){
385 $j('#'+this.control_ct).append( _this.getInsertDescHtml() );
386 }
387 //update control actions
388 this.updateInsertControlActions();
389 },
390 setInOutBindings:function(){
391 var _this = this;
392
393 var start_sec = npt2seconds($j('#'+this.control_ct + ' .startInOut').val() );
394 var end_sec = npt2seconds($j('#'+this.control_ct + ' .endInOut').val() );
395
396 //if we don't have 0 as start then assume we are in a range request and give some buffer area:
397 var min_slider = (start_sec - 60 < 0 ) ? 0 : start_sec - 60;
398 if(min_slider!=0){
399 var max_slider = end_sec+60;
400 }else{
401 max_slider = end_sec;
402 }
403
404 $j('#'+this.control_ct + ' .inOutSlider').slider({
405 range: true,
406 min: min_slider,
407 max: max_slider,
408 values: [start_sec, end_sec],
409 slide: function(event, ui) {
410 js_log(" vals:"+ seconds2npt( ui.values[0] ) + ' : ' + seconds2npt( ui.values[1]) );
411 $j('#'+_this.control_ct + ' .startInOut').val( seconds2npt( ui.values[0] ) );
412 $j('#'+_this.control_ct + ' .endInOut').val( seconds2npt( ui.values[1] ) );
413 },
414 change:function(event, ui){
415 do_video_time_update( seconds2npt( ui.values[0]), seconds2npt( ui.values[1] ) );
416 }
417 });
418
419 //preview button:
420 $j('#'+this.control_ct + ' .inOutPreviewClip').hover(
421 function(){
422 $j(this).addClass('ui-state-hover');
423 },
424 function(){
425 $j(this).removeClass('ui-state-hover');
426 }
427 ).click(function(){
428 $j('#embed_vid').get(0).stop();
429 $j('#embed_vid').get(0).play();
430 });
431 //simple hover:
432
433 },
434 getSetInOutHtml:function( setInt ){
435 return '<strong>' + gM('mv_set_in_out_points') + '</strong>'+
436 '<table border="0" style="background: transparent; width:94%;height:50px;">'+
437 '<tr>' +
438 '<td style="width:55px">'+
439 gM('mv_start_time') +
440 '<input class="ui-widget-content ui-corner-all startInOut" size="9" value="' + setInt.start_ntp +'">'+
441 '</td>' +
442 '<td>' +
443 '<div class="inOutSlider"></div>'+
444 '</td>' +
445 '<td style="width:55px">'+
446 gM('mv_end_time') +
447 '<input class="ui-widget-content ui-corner-all endInOut" size="9" value="'+ setInt.end_ntp +'">'+
448 '</td>' +
449 '</tr>' +
450 '</table>'+
451 '<a href="#" class="ui-state-default ui-corner-all ui-icon_link inOutPreviewClip"><span class="ui-icon ui-icon-video"></span>'+ gM('mv_preview_inout') +'</a>';
452 },
453 getInsertDescHtml:function(){
454 var o= '<h3>Inline Description</h3>'+
455 '<textarea style="width:95%" id="mv_inline_img_desc" rows="5" cols="30">';
456 if( this.p_rsdObj ){
457 //if we have a parent remote search driver let it parse the inline description
458 o+= this.rObj.pSobj.getInlineDescWiki( this.rObj );
459 }
460 o+='</textarea><br>';
461 //js_log('getInsertDescHtml: ' + o );
462 return o;
463 },
464 updateInsertControlActions:function(){
465 var _this = this;
466 var b_target = _this.p_rsdObj.target_container + '~ .ui-dialog-buttonpane';
467 //empty the ui-dialog-buttonpane bar:
468 $j(b_target).empty();
469 for(var cbType in _this.controlActionsCb){
470 switch(cbType){
471 case 'insert_seq':
472 $j(b_target).append( $j.btnHtml(gM('mv_insert_into_sequence'), 'mv_insert_sequence', 'check' ) + ' ' )
473 .children('.mv_insert_sequence')
474 .btnBind()
475 .click(function(){
476 _this.applyEdit();
477 _this.controlActionsCb['insert_seq']( _this.rObj );
478 });
479 break;
480 case 'insert':
481 $j(b_target).append( $j.btnHtml(gM('mv_insert_image_page'), 'mv_insert_image_page', 'check' ) + ' ' )
482 .children('.mv_insert_image_page')
483 .btnBind()
484 .click(function(){
485 _this.applyEdit();
486 _this.controlActionsCb['insert']( _this.rObj );
487 }).show('slow');
488 break;
489 case 'preview':
490 $j(b_target).append( $j.btnHtml( gM('mv_preview_insert'), 'mv_preview_insert', 'refresh') + ' ' )
491 .children('.mv_preview_insert')
492 .btnBind()
493 .click(function(){
494 _this.applyEdit();
495 _this.controlActionsCb['preview']( _this.rObj );
496 }).show('slow');
497 break;
498 case 'cancel':
499 $j(b_target).append( $j.btnHtml( gM('mv_cancel_image_insert'), 'mv_cancel_img_edit', 'close') + ' ')
500 .children('.mv_cancel_img_edit')
501 .btnBind()
502 .click(function(){
503 //no cancel action;
504 _this.controlActionsCb['cancel']( _this.rObj );
505 }).show('slow');
506 break;
507 }
508 }
509 },
510 applyEdit:function(){
511 var _this = this;
512 js_log('applyEdit::' + this.media_type);
513 if(this.media_type == 'image'){
514 this.applyCrop();
515 }else if(this.media_type == 'video'){
516 this.applyVideoAdj();
517 }
518 //copy over the desc text to the resource object
519 _this.rObj['inlineDesc']= $j('#mv_inline_img_desc').val();
520 },
521 setUpImageCtrl:function(){
522 var _this = this;
523 //by default apply Crop tool
524 $j('#'+this.control_ct).html(
525 '<h3>Edit tools</h3>' +
526 '<div class="mv_edit_button mv_crop_button_base" id="mv_crop_button" alt="crop" title="'+gM('mv_crop')+'"/>'+
527 '<a href="#" class="mv_crop_msg">' + gM('mv_crop') + '</a> '+
528 '<span style="display:none" class="mv_crop_msg_load">' + gM('loading_txt') + '</span> '+
529 '<a href="#" style="display:none" class="mv_apply_crop">' + gM('mv_apply_crop') + '</a> '+
530 '<a href="#" style="display:none" class="mv_rest_crop">' + gM('mv_reset_crop') + '</a> '+
531 '<hr style="clear:both"/><br>'+
532 '<span style="float:left;">Layout:</span>' +
533 '<input type="radio" name="mv_layout" id="mv_layout_left" style="float:left"><div id="mv_layout_left_img" title="'+gM('mv_layout_left')+'"/>'+
534 '<input type="radio" name="mv_layout" id="mv_layout_right" style="float:left"><div id="mv_layout_right_img" title="'+gM('mv_layout_left')+'"/>'+
535 '<hr style="clear:both" /><br>' +
536 _this.getInsertDescHtml()
537 );
538 //add the actions to the 'button bar'
539 _this.updateInsertControlActions()
540
541 /*scale:
542 '<div class="mv_edit_button mv_scale_button_base" id="mv_scale_button" alt="crop" title="'+gM('mv_scale')+'"></div>'+
543 '<a href="#" class="mv_scale_msg">' + gM('mv_scale') + '</a><br>'+
544 '<a href="#" style="display:none" class="mv_apply_scale">' + gM('mv_apply_scale') + '</a> '+
545 '<a href="#" style="display:none" class="mv_rest_scale">' + gM('mv_reset_scale') + '</a><br> '+
546
547 */
548 //add bindings:
549
550 //make sure the default is reflected:
551 if( ! _this.rObj.layout )
552 _this.rObj.layout = 'right';
553 $j('#mv_layout_' + _this.rObj.layout)[0].checked = true;
554
555 //left radio click
556 $j('#mv_layout_left,#mv_layout_left_img').click(function(){
557 $j('#mv_layout_right')[0].checked = false;
558 $j('#mv_layout_left')[0].checked = true;
559 _this.rObj.layout = 'left';
560 });
561 //right radio click
562 $j('#mv_layout_right,#mv_layout_right_img').click(function(){
563 $j('#mv_layout_left')[0].checked = false;
564 $j('#mv_layout_right')[0].checked = true;
565 _this.rObj.layout = 'right';
566 });
567 $j('#mv_crop_button,.mv_crop_msg,.mv_apply_crop').click(function(){
568 js_log('click:mv_crop_button: base width: ' + _this.rObj.width + ' bh: ' + _this.rObj.height);
569 if($j('#mv_crop_button').hasClass('mv_crop_button_selected')){
570 _this.applyCrop();
571 }else{
572 js_log('click:turn on');
573 _this.enableCrop();
574 }
575 });
576 $j('.mv_rest_crop').click(function(){
577 $j('.mv_apply_crop,.mv_rest_crop').hide();
578 $j('.mv_crop_msg').show();
579 $j('#mv_crop_button').removeClass('mv_crop_button_selected').addClass('mv_crop_button_base').attr('title',gM('mv_crop'));
580 _this.rObj.crop=null;
581 $j('#' + _this.clip_disp_ct ).empty().html(
582 '<img src="' + _this.rObj.edit_url + '" id="rsd_edit_img">'
583 );
584 });
585 },
586 applyVideoAdj:function(){
587 js_log('applyVideoAdj::');
588
589 //be sure to "stop the video (some plugins can't have DOM elements on top of them)
590 $j('#embed_vid').get(0).stop();
591
592 //update video related keys:
593 ;
594 this.rObj['start_time'] = $j('#'+this.control_ct + ' .startInOut').val();
595 this.rObj['end_time'] = $j('#'+this.control_ct + ' .endInOut').val() ;
596
597 //do the local video adjust
598 if(typeof this.rObj.pSobj['applyVideoAdj'] != 'undefined'){
599 this.rObj.pSobj.applyVideoAdj( this.rObj );
600 }
601 },
602 applyCrop:function(){
603 var _this = this;
604 $j('.mv_apply_crop').hide();
605 $j('.mv_crop_msg').show();
606 $j('#mv_crop_button').removeClass('mv_crop_button_selected').addClass('mv_crop_button_base').attr('title',gM('mv_crop'));
607 js_log( 'click:turn off' );
608 var cat = _this.rObj;
609 if(_this.rObj.crop){
610 //empty out and display croped:
611 $j('#'+_this.clip_disp_ct ).empty().html(
612 '<div id="mv_cropcotainer" style="overflow:hidden;position:absolute;'+
613 'width:' + _this.rObj.crop.w + 'px;'+
614 'height:' + _this.rObj.crop.h + 'px;">'+
615 '<div id="mv_crop_img" style="position:absolute;'+
616 'top:-' + _this.rObj.crop.y +'px;'+
617 'left:-' + _this.rObj.crop.x + 'px;">'+
618 '<img src="' + _this.rObj.edit_url + '">'+
619 '</div>'+
620 '</div>'
621 );
622 }
623 return true;
624 },
625 //right now enableCrop loads "just in time"
626 //@@todo we really need an "auto loader" type system.
627 enableCrop:function(){
628 var _this = this;
629 $j('.mv_crop_msg').hide();
630 $j('.mv_crop_msg_load').show();
631 var doEnableCrop = function(){
632 $j('.mv_crop_msg_load').hide();
633 $j('.mv_rest_crop,.mv_apply_crop').show();
634 $j('#mv_crop_button').removeClass('mv_crop_button_base').addClass('mv_crop_button_selected').attr('title',gM('mv_crop_done'));
635 $j('#' + _this.clip_disp_ct + ' img').Jcrop({
636 onSelect: function(c){
637 js_log('on select:' + c.x +','+ c.y+','+ c.x2+','+ c.y2+','+ c.w+','+ c.h);
638 _this.rObj.crop = c;
639 },
640 onChange: function(c){
641 }
642 });
643 //temporary hack (@@todo need to debug why rsd_res_item gets moved )
644 $j('#clip_edit_disp .rsd_res_item').css({
645 'top':'0px',
646 'left':'0px'
647 });
648 }
649 //load the jcrop library if needed:
650 mvJsLoader.doLoad([
651 '$j.Jcrop'
652 ],function(){
653 doEnableCrop();
654 });
655 }
656 }
657
658 // mv_lock_vid_updates defined in mv_stream.js (we need to do some more refactoring )
659 if(typeof mv_lock_vid_updates == 'undefined')
660 mv_lock_vid_updates= false;
661
662 function add_adjust_hooks(mvd_id, adj_callback){
663 /*myClipEdit = new mvClipEdit({
664 'control_ct': '#mvd_form_'+mvd_id
665 });
666 $j('#mvd_form_'+mvd_id).html(
667 mvClipEdit.getSetInOutHtml({
668 'start_ntp' : $j('#mv_start_hr_' + mvd_id).val(),
669 'end_ntp' : $j('#mv_end_hr_' + mvd_id).val()
670 })
671 );
672 mvClipEdit.setInOutBindings();*/
673
674 var start_sec = npt2seconds($j('#mv_start_hr_' + mvd_id).val() );
675 var end_sec = npt2seconds($j('#mv_end_hr_' + mvd_id).val() );
676
677 //if we don't have 0 as start then assume we are in a range request and give some buffer area:
678 var min_slider = (start_sec - 60 < 0 ) ? 0 : start_sec - 60;
679 if(min_slider!=0){
680 var max_slider = end_sec+60;
681 }else{
682 max_slider = end_sec;
683 }
684 //pre-destroy just in case:
685 $j('#mvd_form_' + mvd_id + ' .inOutSlider').slider( 'destroy' ).slider({
686 range: true,
687 min: min_slider,
688 max: max_slider,
689 values: [start_sec, end_sec],
690 slide: function(event, ui) {
691 js_log(" vals:"+ seconds2npt( ui.values[0] ) + ' : ' + seconds2npt( ui.values[1]) );
692 $j('#mv_start_hr_' + mvd_id).val( seconds2npt( ui.values[0] ) );
693 $j('#mv_end_hr_' + mvd_id).val( seconds2npt( ui.values[1] ) );
694 },
695 change:function(event, ui){
696 do_video_time_update( seconds2npt( ui.values[0]), seconds2npt( ui.values[1] ) );
697 }
698 });
699 $j('.mv_adj_hr').change(function(){
700 //preserve track duration for nav and seq:
701 //ie seems to crash so no interface updates for IE for the time being
702 if(!$j.browser.msie){
703 if(mvd_id=='nav'||mvd_id=='seq'){
704 add_adjust_hooks(mvd_id); // (no adj_callback)
705 }else{
706 add_adjust_hooks(mvd_id)
707 }
708 }
709 //update the video time for onChange
710 do_video_time_update( $j('#mv_start_hr_'+mvd_id).val(), $j('#mv_end_hr_'+mvd_id).val() );
711 });
712 }
713
714 function do_video_time_update(start_time, end_time, mvd_id) {
715 js_log('do_video_time_update: ' +start_time +' '+ end_time);
716
717 if(mv_lock_vid_updates==false){
718 //update the vid title:
719 $j('#mv_videoPlayerTime').html( start_time + ' to ' + end_time );
720 var ebvid = $j('#embed_vid').get(0);
721 if( ebvid ){
722 if(ebvid.isPaused())
723 ebvid.stop();
724 ebvid.updateVideoTime(start_time, end_time);
725 js_log('update thumb: '+ start_time);
726 ebvid.updateThumbTimeNTP( start_time );
727 }
728 }
729 }