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