Commit RELEASE-NOTES line for the wgCategories js variable I added some time ago.
[lhc/web/wiklou.git] / js2 / mwEmbed / libClipEdit / mvClipEdit.js
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 } );
36
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
43
44 'p_rsdObj': null, // parent remote search object
45 'p_seqObj': null, // parent sequence Object
46
47 'controlActionsCb' : null, // the object that configures control Action callbacks
48
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"
53 }
54 var mvClipEdit = function( iObj ) {
55 return this.init( iObj );
56 };
57 mvClipEdit.prototype = {
58
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 }
71
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 },
98
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 );
134
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>';
264
265 $j( target ).html ( o );
266
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++ ) {
275
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() );
285
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 } )
297
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 );
348
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 );
382
383 var start_sec = npt2seconds( $tp.find( '.startInOut' ).val() );
384 var end_sec = npt2seconds( $tp.find( '.endInOut' ).val() );
385
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 }
393
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 } );
440
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 );
619
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();
622
623 // update video related keys
624 this.rObj['start_time'] = $tp.find( '.startInOut' ).val();
625 this.rObj['end_time'] = $tp.find( '.endInOut' ).val() ;
626
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 }
686 }
687
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;
691
692 function add_adjust_hooks( mvd_id, adj_callback ) {
693
694 var start_sec = npt2seconds( $j( '#mv_start_hr_' + mvd_id ).val() );
695 var end_sec = npt2seconds( $j( '#mv_end_hr_' + mvd_id ).val() );
696
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 } );
732 }
733
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 }
748 }
749
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 );