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