r44460 MediaWiki - Code Review archive

Repository:MediaWiki
Revision:r44459‎ | r44460 | r44461 >
Date:19:03, 11 December 2008
Author:dale
Status:deferred
Tags:
Comment:
* library paths re-organization for sequencer and remote search
* mv_remote search updates
* some multi-language planning / stubs
* external_media_wizard.js mediaWiki user script external repository searching
Modified paths:
  • /trunk/extensions/MetavidWiki/skins/mv_embed/README (modified) (history)
  • /trunk/extensions/MetavidWiki/skins/mv_embed/embedLibs (deleted) (history)
  • /trunk/extensions/MetavidWiki/skins/mv_embed/i18n (added) (history)
  • /trunk/extensions/MetavidWiki/skins/mv_embed/i18n/README (added) (history)
  • /trunk/extensions/MetavidWiki/skins/mv_embed/libEmbedObj (added) (history)
  • /trunk/extensions/MetavidWiki/skins/mv_embed/libEmbedObj/mv_nativeEmbed.js (replaced) (history)
  • /trunk/extensions/MetavidWiki/skins/mv_embed/libEmbedObj/mv_vlcEmbed.js (replaced) (history)
  • /trunk/extensions/MetavidWiki/skins/mv_embed/libRemoteMediaSearch (added) (history)
  • /trunk/extensions/MetavidWiki/skins/mv_embed/libRemoteMediaSearch/mv_remote_media_search.js (added) (history)
  • /trunk/extensions/MetavidWiki/skins/mv_embed/libSequencer (added) (history)
  • /trunk/extensions/MetavidWiki/skins/mv_embed/libSequencer/mv_clip_edit.js (added) (history)
  • /trunk/extensions/MetavidWiki/skins/mv_embed/libSequencer/mv_playlist.js (added) (history)
  • /trunk/extensions/MetavidWiki/skins/mv_embed/libSequencer/mv_sequencer.js (added) (history)
  • /trunk/extensions/MetavidWiki/skins/mv_embed/libTimedText (added) (history)
  • /trunk/extensions/MetavidWiki/skins/mv_embed/libTimedText/mv_timed_text.js (replaced) (history)
  • /trunk/extensions/MetavidWiki/skins/mv_embed/mv_clip_edit.js (deleted) (history)
  • /trunk/extensions/MetavidWiki/skins/mv_embed/mv_embed.js (modified) (history)
  • /trunk/extensions/MetavidWiki/skins/mv_embed/mv_embed_iframe.php (modified) (history)
  • /trunk/extensions/MetavidWiki/skins/mv_embed/mv_playlist.js (deleted) (history)
  • /trunk/extensions/MetavidWiki/skins/mv_embed/mv_remote_media_search.js (deleted) (history)
  • /trunk/extensions/MetavidWiki/skins/mv_embed/mv_sequencer.js (deleted) (history)
  • /trunk/extensions/MetavidWiki/skins/mv_embed/timedTextLibs (deleted) (history)

Diff [purge]

Index: trunk/extensions/MetavidWiki/skins/mv_embed/mv_playlist.js
@@ -1,1961 +0,0 @@
2 -/*
3 - * the playlist object code
4 - * only included if playlist object found
5 - *
6 - * part of mv_embed:
7 - * http://metavid.org/wiki/index.php/Mv_embed
8 - */
9 -var mv_default_playlist_attributes = {
10 - //playlist attributes :
11 - "id":null,
12 - "title":null,
13 - "width":400,
14 - "height":300,
15 - "desc":'',
16 - "controls":true,
17 - //playlist user controlled features
18 - "linkback":null,
19 - "src":null,
20 - "embed_link":true,
21 -
22 - //enable sequencer? (only display top frame no navigation or accompanying text
23 - "sequencer":false
24 -}
25 -//the call back rate for animations and internal timers in ms: 33 is about 30 frames a second:
26 -var MV_ANIMATION_CB_RATE = 33;
27 -
28 -//globals:
29 -var mv_lock_vid_updates=false;
30 -//10 possible colors for clips: (can be in hexadecimal)
31 -var mv_clip_colors = new Array('aqua', 'blue', 'fuchsia', 'green', 'lime', 'maroon', 'navy', 'olive', 'purple', 'red');
32 -//the base url for requesting stream metadata
33 -if(typeof wgServer=='undefined'){
34 - var defaultMetaDataProvider = 'http://metavid.org/overlay/archive_browser/export_cmml?stream_name=';
35 -}else{
36 - var defaultMetaDataProvider = wgServer+wgScript+'?title=Special:MvExportStream&feed_format=roe&stream_name=';
37 -}
38 -
39 -var mvPlayList = function(element) {
40 - return this.init(element);
41 -};
42 -//set up the mvPlaylist object
43 -mvPlayList.prototype = {
44 - instanceOf:'mvPlayList',
45 - pl_duration:null,
46 - update_tl_hook:null,
47 - clip_ready_count:0,
48 - cur_clip:null,
49 - start_clip:null,
50 - start_clip_src:null,
51 - disp_play_head:null,
52 - userSlide:false,
53 - loading:true,
54 - loading_external_data:true, //if we are loading external data (set to loading by default)
55 -
56 - interface_url:null, //the interface url
57 - tracks:{},
58 - default_track:null, // the default track to add clips to.
59 - //the layout for the playlist object
60 - pl_layout : {
61 - seq_title:.1,
62 - clip_desc:.63, //displays the clip description
63 - clip_aspect:1.33, // 4/3 video aspect ratio
64 - seq:.25, //display clip thumbnails
65 - seq_thumb:.25, //size for thumbnails (same as seq by default)
66 - seq_nav:0, //for a nav bar at the base (currently disabled)
67 - //some pl_layout info:
68 - title_bar_height:17,
69 - control_height:29
70 - },
71 - init : function(element){
72 - js_log('mvPlayList:init:');
73 - this.tracks={};
74 - this.default_track=null;
75 -
76 - //add default track & default track pointer:
77 - this.tracks[0]= new trackObj();
78 - this.default_track = this.tracks[0];
79 -
80 - //get all the attributes:
81 - for(var attr in mv_default_playlist_attributes){
82 - if( element.getAttribute(attr) ){
83 - this[attr]=element.getAttribute(attr);
84 - //js_log('attr:' + attr + ' val: ' + video_attributes[attr] +" "+'elm_val:' + element.getAttribute(attr) + "\n (set by elm)");
85 - }else{
86 - this[attr]=mv_default_playlist_attributes[attr];
87 - //js_log('attr:' + attr + ' val: ' + video_attributes[attr] +" "+ 'elm_val:' + element.getAttribute(attr) + "\n (set by attr)");
88 - }
89 - }
90 - //make sure height and width are int:
91 - this.width =parseInt(this.width);
92 - this.height=parseInt(this.height);
93 -
94 - //if style is set override width and height
95 - if(element.style.width)this.width = parseInt(element.style.width.replace('px',''));
96 - if(element.style.height)this.height = parseInt(element.style.height.replace('px',''));
97 - },
98 - //the element has now been swapped into the dom:
99 - on_dom_swap:function(){
100 - js_log('pl: dom swap');
101 - //get and load the html:
102 - this.getHTML();
103 - },
104 - //run inheritEmbedObj on every clip (we have changed the playback method)
105 - inheritEmbedObj:function(){
106 - $j.each(this.tracks, function(i,track){
107 - track.inheritEmbedObj();
108 - });
109 - },
110 - doOptionsHTML:function(){
111 - //grab "options" use current clip:
112 - this.cur_clip.embed.doOptionsHTML();
113 - },
114 - //pulls up the video editor inline
115 - doEditor:function(){
116 - //black out the page:
117 - $j('body').append('<div id="mv_overlay"/> '+
118 - '<div id="modalbox" class="modal_editor">');
119 -
120 - $j('#modalbox').html('loading editor<blink>...</blink>');
121 - var _this=this;
122 - js_log("calling sequence with url:" + _this.src);
123 -
124 - //clone the playlist (to make for easy cancel)
125 - /*var this_plObj_Clone = $j('#'+this.id).get(0).cloneNode(true);
126 - this_plObj_Clone.sequencer=true;
127 - this_plObj_Clone.id= 'seq_plobj';
128 - debugger;
129 - */
130 - //load sequencer:
131 - mv_do_sequence({
132 - "sequence_container_id":'modalbox',
133 - "mv_pl_src":this.src
134 - });
135 -
136 - },
137 - selectPlaybackMethod:function(){
138 - this.cur_clip.embed.selectPlaybackMethod();
139 - },
140 - closeDisplayedHTML:function(){
141 - this.cur_clip.embed.closeDisplayedHTML();
142 - },
143 - showVideoDownload:function(){
144 - this.cur_clip.embed.showVideoDownload();
145 - },
146 - showEmbedCode:function(){
147 - var embed_code = '&lt;script type=&quot;text/javascript&quot; '+
148 - 'src=&quot;'+mv_embed_path+'mv_embed.js&quot;&gt;&lt;/script&gt '+"\n" +
149 - '&lt;playlist id=&quot;'+this.id+'&quot; ';
150 - if(this.src){
151 - embed_code+='src=&quot;'+this.src+'&quot; /&gt;';
152 - }else{
153 - embed_code+='&gt;'+"\n";
154 - embed_code+= this.data.htmlEntities();
155 - embed_code+='&lt;playlist/&gt;';
156 - }
157 - this.cur_clip.embed.showEmbedCode(embed_code);
158 - },
159 - getPlaylist:function(){
160 - js_log("f:getPlaylist: " + this.srcType );
161 - //@@todo lazy load plLib
162 - eval('var plObj = '+this.srcType+'Playlist;');
163 - //import methods from the plObj to this
164 - for(var method in plObj){
165 - //js parent preservation for local overwritten methods
166 - if(this[method])this['parent_' + method] = this[method];
167 - this[method]=plObj[method];
168 - js_log('inherit:'+ method);
169 - }
170 -
171 - if(typeof this.doParse != 'function'){
172 - return js_log('error: method doParse not found in plObj'+ this.srcType);
173 - }
174 -
175 - if(typeof this.doParse == 'function'){
176 - if( this.doParse() ){
177 - this.doWhenParseDone();
178 - }else{
179 - return js_log("error: failed to parse playlist");
180 - //error or parse needs to do ajax requests
181 - }
182 - }
183 - },
184 - doWhenParseDone:function(){
185 - js_log('f:doWhenParseDone');
186 - //do additional init for clips:
187 - var _this = this;
188 - var error=false;
189 - _this.clip_ready_count=0;
190 - for( var i in this.default_track.clips ){
191 - var clip = this.default_track.clips[i];
192 - if(clip.embed.load_error){
193 - var error = clip.embed.load_error;
194 - //break on any clip we can't playback:
195 - break;
196 - }
197 - if( clip.embed.ready_to_play ){
198 - _this.clip_ready_count++;
199 - continue;
200 - }
201 - //js_log('clip sources count: '+ clip.embed.media_element.sources.length);
202 - clip.embed.on_dom_swap();
203 - if( clip.embed.loading_external_data==false &&
204 - clip.embed.init_with_sources_loadedDone==false){
205 - clip.embed.init_with_sources_loaded();
206 - }
207 - }
208 -
209 - //@@todo for some plugins we have to conform types of clips
210 - // ie vlc can play flash _followed_by_ ogg _followed_by_ whatever
211 - // but
212 - // native ff 3.1a2 can only play ogg
213 - if( error){
214 - this.load_error=error;
215 - this.is_ready=false;
216 - }else if( _this.clip_ready_count == this.getClipCount() ){
217 - js_log("done init all clips");
218 - this.doWhenClipLoadDone();
219 - }else{
220 - js_log("only "+ _this.clip_ready_count +" clips done, scheduling callback:");
221 - if( !mvJsLoader.load_error ) //re-issue request if no load error:
222 - setTimeout('document.getElementById(\''+this.id+'\').doWhenParseDone()', 250);
223 - }
224 - },
225 - doWhenClipLoadDone:function(){
226 - this.loading = false;
227 - this.ready_to_play = true;
228 - this.getHTML();
229 - },
230 - getDuration:function( regen ){
231 - //js_log("GET PL DURRATION for : "+ this.tracks[this.default_track_id].clips.length + 'clips');
232 - if(!regen && this.pl_duration)
233 - return this.pl_duration;
234 -
235 - var durSum=0;
236 - $j.each( this.default_track.clips, function( i, clip ){
237 - if( clip.embed ){
238 - js_log('plDUR:add : '+ clip.getDuration() + ' src:' + clip.embed.src);
239 - clip.dur_offset = durSum;
240 - durSum += clip.getDuration();
241 - }else{
242 - js_log("ERROR: clip " +clip.id + " not ready");
243 - }
244 - });
245 - this.pl_duration=durSum;
246 - //js_log("return dur: " + this.pl_duration);
247 - return this.pl_duration;
248 - },
249 - getDataSource:function(){
250 - js_log("f:getDataSource "+ this.src);
251 - //determine the type / first is it m3u or xml?
252 - var pl_parent = this;
253 - this.makeURLAbsolute();
254 - if(this.src!=null){
255 - do_request(this.src, function(data){
256 - pl_parent.data=data;
257 - pl_parent.getSourceType();
258 - });
259 - }
260 - },
261 - getSourceType:function(){
262 - js_log('data type of: '+ this.src + ' = ' + typeof (this.data) + "\n"+ this.data);
263 - this.srcType =null;
264 - //if not external use different detection matrix
265 - if(this.loading_external_data){
266 - if( typeof this.data == 'object' ){
267 - js_log('object');
268 - //object assume xml (either xspf or rss)
269 - plElm = this.data.getElementsByTagName('playlist')[0];
270 - if( plElm ){
271 - if(plElm.getAttribute('xmlns')=='http://xspf.org/ns/0/'){
272 - this.srcType ='xspf';
273 - }
274 - }
275 - //check itunes style rss "items"
276 - rssElm = this.data.getElementsByTagName('rss')[0];
277 - if(rssElm){
278 - if(rssElm.getAttribute('xmlns:itunes')=='http://www.itunes.com/dtds/podcast-1.0.dtd'){
279 - this.srcType='itunes';
280 - }
281 - }
282 - //check for smil tag:
283 - smilElm = this.data.getElementsByTagName('smil')[0];
284 - if(smilElm){
285 - //don't check dtd yet.. (have not defined the smil subset)
286 - this.srcType='smil';
287 - }
288 - }else if(typeof this.data == 'string'){
289 - js_log('String');
290 - //look at the first line:
291 - var first_line = this.data.substring(0, this.data.indexOf("\n"));
292 - js_log('first line: '+ first_line);
293 - //string
294 - if(first_line.indexOf('#EXTM3U')!=-1){
295 - this.srcType = 'm3u';
296 - }else if(first_line.indexOf('<smil')!=-1){
297 - //@@todo parse string
298 - this.srcType = 'smil';
299 - }
300 - }
301 - }
302 -
303 - if(this.srcType){
304 - js_log('is of type:'+ this.srcType);
305 - this.getPlaylist();
306 - }else{
307 - //unknown playlist type
308 - js_log('unknown playlist type?');
309 - if(this.src){
310 - this.innerHTML= 'error: unknown playlist type at url:<br> ' + this.src;
311 - }else{
312 - this.innerHTML='error: unset src or unknown inline playlist data<br>';
313 - }
314 - }
315 - },
316 - //simple function to make a path into an absolute url if its not already
317 - makeURLAbsolute:function(){
318 - if(this.src){
319 - if(this.src.indexOf('://')==-1){
320 - var purl = parseUri(document.URL);
321 - if(this.src.charAt(0)=='/'){
322 - this.src = purl.protocol +'://'+ purl.host + this.src;
323 - }else{
324 - this.src= purl.protocol +'://'+ purl.host + purl.directory + this.src;
325 - }
326 - }
327 - }
328 - },
329 - //set up minimal media_element emulation:
330 - media_element:{
331 - selected_source:{
332 - supports_url_time_encoding:true
333 - }
334 - },
335 - //@@todo needs to update for multi-track clip counts
336 - getClipCount:function(){
337 - return this.default_track.clips.length;
338 - },
339 - //},
340 - //takes in the playlist
341 - // inherits all the properties
342 - // swaps in the playlist object html/interface div
343 - getHTML:function(){
344 - if(this.loading){
345 - js_log('called getHTML (loading)');
346 - $j('#'+this.id).html('loading playlist<blink>...</blink>');
347 - if(this.loading_external_data){
348 - //load the data source chain of functions (to update the innerHTML)
349 - this.getDataSource();
350 - }else{
351 - //detect datatype and parse directly:
352 - this.getSourceType();
353 - }
354 - }else{
355 - //check for empty playlist otherwise renderDisplay:
356 - if(this.default_track.getClipCount()==0){
357 - $j(this).html('empty playlist');
358 - return ;
359 - }else{
360 - this.renderDisplay();
361 - }
362 - }
363 - },
364 - renderDisplay:function(){
365 - js_log('track length: ' +this.default_track.getClipCount() );''
366 -
367 - var plObj=this;
368 - //setup layout for title and dc_ clip container
369 - $j(this).html('<div id="dc_'+this.id+'" style="width:'+this.width+'px;' +
370 - 'height:'+(this.height+this.pl_layout.title_bar_height + this.pl_layout.control_height)+'px;position:relative;">' +
371 - ' <div style="font-size:13px;border:solid thin;width:'+this.width+'px;" id="ptitle_'+this.id+'"></div>' +
372 - '</div>');
373 -
374 - //add the playlist controls:
375 - $j('#dc_'+plObj.id).append(
376 - '<div class="videoPlayer" style="position:absolute;top:'+(plObj.height+plObj.pl_layout.title_bar_height)+'px">' +
377 - '<div id="mv_embedded_controls_'+plObj.id+'" ' +
378 - 'style="postion:relative;top:'+(plObj.height+plObj.pl_layout.title_bar_height)+'px;' +
379 - 'width:'+plObj.width+'px" ' +
380 - 'class="controls">' +
381 - plObj.getControlsHTML() +
382 - '</div>'+
383 - '</div>'
384 - );
385 - //once the controls are in the DOM add hooks:
386 - ctrlBuilder.addControlHooks(this);
387 - //add the play button:
388 - $j('#dc_'+plObj.id).append(
389 - this.cur_clip.embed.getPlayButton()
390 - );
391 -
392 - this.setupClipDisplay();
393 -
394 - //update the title and status bar
395 - this.updateBaseStatus();
396 - },
397 - setupClipDisplay:function(){
398 - var plObj = this;
399 - $j.each(this.default_track.clips, function(i, clip){
400 - $j('#dc_'+plObj.id).append('<div class="clip_container" id="clipDesc_'+clip.id+'" '+
401 - 'style="display:none;position:absolute;text-align: center;border:solid thin;width:'+plObj.width + 'px;'+
402 - 'height:'+(plObj.height )+'px;'+
403 - 'top:' + this.title_bar_height + 'px;left:0px"></div>');
404 - //update the embed html:
405 - clip.embed.height=plObj.height;
406 - clip.embed.width=plObj.width;
407 - clip.embed.play_button=false;
408 -
409 - clip.embed.getHTML();//get the thubnails for everything
410 - $j(clip.embed).css({ 'position':"absolute",'top':"0px", 'left':"0px"});
411 - if($j('#clipDesc_'+clip.id).get(0)){
412 - $j('#clipDesc_'+clip.id).get(0).appendChild(clip.embed);
413 - }else{
414 - js_log('cound not find: clipDesc_'+clip.id);
415 - }
416 - });
417 - if(this.cur_clip)
418 - $j('#clipDesc_'+this.cur_clip.id).css( { display:'inline' } );
419 - },
420 - updateThumbPerc:function( perc ){
421 - //get float seconds:
422 - var float_sec = ( this.getDuration() * perc );
423 - this.updateThumbTime( float_sec );
424 - },
425 - updateThumbTime:function( float_sec ){
426 - //update display & cur_clip:
427 - var pl_sum_time =0;
428 - var clip_float_sec=0;
429 - //js_log('seeking clip: ');
430 - for(var i in this.default_track.clips){
431 - var clip = this.default_track.clips[i];
432 - if( (clip.getDuration() + pl_sum_time) >= float_sec ){
433 - if(this.cur_clip.id != clip.id){
434 - $j('#clipDesc_'+this.cur_clip.id).hide();
435 - this.cur_clip = clip;
436 - $j('#clipDesc_'+this.cur_clip.id).show();
437 - }
438 - break;
439 - }
440 - pl_sum_time+=clip.getDuration();
441 - }
442 -
443 - //update start_offset
444 - if(typeof this.cur_clip.embed.start_offset=='undefined'){
445 - if(!typeof this.cur_clip.embed.media_element.selected_source!='undefined')
446 - this.cur_clip.embed.start_offset=this.cur_clip.embed.media_element.selected_source.start_offset;
447 - }
448 -
449 - //issue thumbnail update request: (if plugin supports it will render out frame
450 - // if not then we do a call to the server to get a new jpeg thumbnail
451 - this.cur_clip.embed.updateThumbTime( float_sec - pl_sum_time );
452 -
453 - this.cur_clip.embed.currentTime = (float_sec -pl_sum_time)+this.cur_clip.embed.start_offset ;
454 - this.cur_clip.embed.seek_time_sec = (float_sec -pl_sum_time );
455 -
456 - //render effects ontop: (handled by doSmilActions)
457 - this.doSmilActions( single_line = true );
458 - },
459 - updateBaseStatus:function(){
460 - js_log('f:updateBaseStatus');
461 - $j('#ptitle_'+this.id).html(''+
462 - '<b>' + this.title + '</b> '+
463 - this.getClipCount()+' clips, <i>'+
464 - seconds2ntp( this.getDuration() ) + '</i>' +
465 - '<a href="#" onclick="$j(\'#'+this.id+'\').get(0).doEditor();" style="position:absolute;top:0px;right:0px">edit</a>');
466 - //render out the dividers on the timeline:
467 - this.colorPlayHead();
468 - //update status:
469 - this.setStatus('0:0:00/'+seconds2ntp( this.getDuration() ));
470 - },
471 - /*setStatus override (could call the jquery directly) */
472 - setStatus:function(value){
473 - $j('#mv_time_'+this.id).html( value );
474 - },
475 - setSliderValue:function(value){
476 - //js_log('calling original embed slider with val: '+value);
477 - this.cur_clip.embed.pe_setSliderValue( value );
478 - //call seq playline update here
479 - },
480 - getSeqThumb: function(){
481 - //for each clip
482 - if(this.getClipCount()>3){
483 - this.pl_layout.seq_thumb=.17;
484 - }else{
485 - this.pl_layout.seq_thumb=.25;
486 - }
487 - $j.each(this.default_track.clips, function(i,n){
488 - //js_log('add thumb for:' + n.src);
489 - n.getThumb();
490 - });
491 - },
492 - getPlayHeadPos: function(prec_done){
493 - var plObj = this;
494 - if($j('#mv_seeker_'+this.id).length==0){
495 - //js_log('no playhead so we can\'t get playhead pos' );
496 - return 0;
497 - }
498 - var track_len = $j('#mv_seeker_'+this.id).css('width').replace(/px/, '');
499 - //assume the duration is static and present at .duration during playback
500 - var clip_perc = this.cur_clip.embed.duration / this.getDuration();
501 - var perc_offset =time_offset = 0;
502 - for(var i in this.default_track.clips){
503 - var clip = this.default_track.clips[i];
504 - if(this.cur_clip.id ==clip.id)break;
505 - perc_offset+=(clip.embed.duration / plObj.getDuration());
506 - time_offset+=clip.embed.duration;
507 - }
508 - //run any update time line hooks:
509 - if(this.update_tl_hook){
510 - var cur_time_ms = time_offset + Math.round(this.cur_clip.embed.duration*prec_done);
511 - if(typeof update_tl_hook =='function'){
512 - this.update_tl_hook(cur_time_ms);
513 - }else{
514 - //string type passed use eval:
515 - eval(this.update_tl_hook+'('+cur_time_ms+');');
516 - }
517 - }
518 -
519 - //handle offset hack @@todo fix so this is not needed:
520 - if(perc_offset > .66)
521 - perc_offset+=(8/track_len);
522 - //js_log('perc:'+ perc_offset +' c:'+ clip_perc + '*' + prec_done + ' v:'+(clip_perc*prec_done));
523 - return perc_offset + (clip_perc*prec_done);
524 - },
525 - //attempts to load the embed object with the playlist
526 - loadEmbedPlaylist: function(){
527 - //js_log('load playlist');
528 - },
529 - //called when the plugin advances to the next clip in the playlist
530 - playlistNext:function(){
531 - js_log('pl advance');
532 - this.cur_clip=this.getClip(1);
533 - },
534 - next: function(){
535 - //advance the playhead to the next clip
536 - var next_clip = this.getClip(1);
537 - //@@todo where the plugin supports pre_loading future clips and manage that in javascript
538 - //stop current clip
539 - this.cur_clip.embed.stop();
540 - this.updateCurrentClip(next_clip);
541 - this.cur_clip.embed.play();
542 - },
543 - updateCurrentClip:function(new_clip){
544 - js_log('f:updateCurrentClip:'+new_clip.id);
545 - //do swap:
546 - $j('#clipDesc_'+this.cur_clip.id).hide();
547 - this.cur_clip=new_clip;
548 - $j('#clipDesc_'+this.cur_clip.id).show();
549 - //update the playhead:
550 - this.setSliderValue( this.cur_clip.dur_offset / this.getDuration() );
551 - },
552 - prev: function(){
553 - //advance the playhead to the previous clip
554 - var prev_clip = this.getClip(-1);
555 - //@@todo we could do something fancy like use playlist for sets of clips where supported.
556 - // or in cases where the player nativly supports the playlist format we can just pass it in (ie m3u or xspf)
557 - if(this.cur_clip.embed.supports['playlist_swap_loader']){
558 - //where the plugin supports pre_loading future clips and manage that in javascript
559 - //pause current clip
560 - this.cur_clip.embed.pause;
561 - //do swap:
562 - this.updateCurrentClip(prev_clip);
563 - this.cur_clip.embed.play();
564 - }else{
565 - js_log('do prev hard embed swap');
566 - this.switchPlayingClip(prev_clip);
567 - }
568 - },
569 - switchPlayingClip:function(new_clip){
570 - //swap out the existing embed code for next clip embed code
571 - $j('#mv_ebct_'+this.id).empty();
572 - new_clip.embed.width=this.width;
573 - new_clip.embed.height=this.height;
574 - //js_log('set embed to: '+ new_clip.embed.getEmbedObj());
575 - $j('#mv_ebct_'+this.id).html( new_clip.embed.getEmbedObj() );
576 - this.cur_clip=new_clip;
577 - //run js code:
578 - this.cur_clip.embed.pe_postEmbedJS();
579 - },
580 - //playlist play
581 - play: function(){
582 - var plObj=this;
583 - js_log('pl play');
584 - //hide the playlist play button:
585 - $j('#big_play_link_'+this.id).hide();
586 -
587 - //un-pause if paused:
588 - if(this.paused)
589 - this.paused=false;
590 -
591 - this.start_clip = this.cur_clip;
592 - this.start_clip_src= this.cur_clip.src;
593 -
594 - if(this.cur_clip.embed.supports['playlist_swap_loader'] ){
595 - //navtive support:
596 - // * pre-loads clips
597 - // * mv_playlist smil extension, manages transitions animations overlays etc.
598 - js_log('clip obj supports playlist swap_loader (ie playlist controlled playback)');
599 - //update cur clip based if sequence playhead set:
600 - var d = new Date();
601 - this.clockStartTime = d.getTime();
602 -
603 - this.monitor();
604 -
605 - //@@todo pre-load each clip:
606 - this.cur_clip.embed.play();
607 - }else if(this.cur_clip.embed.supports['playlist_driver']){
608 - js_log('playlist_driver');
609 - //embedObject is feed the playlist info directly and manages next/prev
610 - this.cur_clip.embed.playMovieAt(this.cur_clip.order);
611 - }else{
612 - //not much playlist support just play the first clip:
613 - js_log('basic play');
614 - //play cur_clip
615 - this.cur_clip.embed.play();
616 - }
617 - },
618 - toggleMute:function(){
619 - this.cur_clip.embed.toggleMute();
620 - },
621 - pause:function(){
622 - js_log('f:pause: playlist');
623 - var ct = new Date();
624 - this.pauseTime = this.currentTime;
625 - js_log('pause time: '+ this.pauseTime);
626 -
627 - window.clearInterval( this.smil_monitorTimerId );
628 - },
629 - fullscreen:function(){
630 - this.cur_clip.embed.fullscreen();
631 - },
632 - //playlist stops playback for the current clip (and resets state for start clips)
633 - stop:function(){
634 - /*js_log("pl stop:"+ this.start_clip.id + ' c:'+this.cur_clip.id);
635 - //if start clip
636 - if(this.start_clip.id!=this.cur_clip.id){
637 - //restore clipDesc visibility & hide desc for start clip:
638 - $j('#clipDesc_'+this.start_clip.id).html('');
639 - this.start_clip.getDetail();
640 - $j('#clipDesc_'+this.start_clip.id).css({display:'none'});
641 - this.start_clip.setBaseEmbedDim(this.start_clip.embed);
642 - //equivalent of base stop
643 - $j('#'+this.start_clip.embed.id).html(this.start_clip.embed.getThumbnailHTML());
644 - this.start_clip.embed.thumbnail_disp=true;
645 - }
646 - //empty the play-back container
647 - $j('#mv_ebct_'+this.id).empty();*/
648 -
649 - //make sure the current clip is vissable:
650 - $j('#clipDesc_'+this.cur_clip.id).css({display:'inline'});
651 -
652 - //do stop current clip
653 - this.cur_clip.embed.stop();
654 - //stop the monitor:
655 - window.clearInterval( this.smil_monitorTimerId );
656 - },
657 - doSeek:function(v){
658 - js_log('pl:doSeek:'+v);
659 - var plObj = this;
660 - var prevClip=null;
661 - //jump to the clip in the current percent.
662 - var perc_offset=0;
663 - var next_perc_offset=0;
664 - for(var i in plObj.default_track.clips){
665 - var clip = plObj.default_track.clips[i];
666 - next_perc_offset+=( clip.getDuration() / plObj.getDuration()) ;
667 - //js_log('on ' + clip.getDuration() +' next_perc_offset:'+ next_perc_offset);
668 - if(next_perc_offset > v ){
669 - //pass along the relative percentage to embed object:
670 - //js_log('seek:'+ v +' - '+perc_offset + ') / (' + next_perc_offset +' - '+ perc_offset);
671 - var relative_perc = (v -perc_offset) / (next_perc_offset - perc_offset);
672 - plObj.cur_clip = clip;
673 - plObj.cur_clip.embed.doSeek( relative_perc );
674 - this.play();
675 - return '';
676 - }
677 - perc_offset = next_perc_offset;
678 - }
679 - },
680 - //gets playlist controls large control height for sporting
681 - //next prev button and more status display
682 - getControlsHTML:function(){
683 - //get controls from current clip (add some playlist specific controls:
684 - this.cur_clip.embed.supports['prev_next']=true;
685 - return ctrlBuilder.getControls(this.cur_clip.embed);
686 - },
687 - //ads colors/dividers between tracks
688 - colorPlayHead: function(){
689 - if( !this.mv_seeker_width)
690 - this.mv_seeker_width = $j('#mv_seeker_slider_'+this.id).width();
691 -
692 - if( !this.track_len )
693 - this.track_len = $j('#seeker_bar_'+this.id).css('width').replace(/px/, '');
694 -
695 - //total duration:
696 - var pl_duration = this.getDuration();
697 -
698 - var cur_pixle=0;
699 - //set up plObj
700 - var _this = this;
701 - //js_log("do play head total dur: "+pl_duration );
702 - $j.each(this.default_track.clips, function(i, clip){
703 - var perc = ( clip.getDuration() / pl_duration );
704 - var pwidth = Math.round( perc * _this.track_len);
705 - //var pwidth = Math.round( perc * _this.track_len - (_this.mv_seeker_width*perc) );
706 -
707 - var barHtml = '<div id="cl_status_'+clip.id+'" class="cl_status" style="' +
708 - 'left:'+cur_pixle +'px;'+
709 - 'width:'+pwidth + 'px;';
710 - //set left or right border based on track pos
711 - barHtml+=( i == _this.default_track.getClipCount()-1 )?
712 - 'border-left:solid thin black;':
713 - 'border-right:solid thin black;';
714 - barHtml+= 'filter:alpha(opacity=40);'+
715 - '-moz-opacity:.40;">'
716 - '</div>';
717 - //background:#DDDclip.getColor()
718 - $j('#seeker_bar_'+_this.id).append(barHtml);
719 -
720 - //js_log('offset:' + cur_pixle +' width:'+pwidth+' add clip'+ clip.id + ' is '+clip.embed.getDuration() +' = ' + perc +' of ' + _this.track_len);
721 - cur_pixle+=pwidth;
722 - });
723 - },
724 - setUpHover:function(){
725 - js_log('Setup Hover');
726 - //set up hover for prev,next
727 - var th = 50;
728 - var tw = th*this.pl_layout.clip_aspect;
729 - var plObj = this;
730 - $j('#mv_prev_link_'+plObj.id+',#mv_next_link_'+plObj.id).hover(function() {
731 - var clip = (this.id=='mv_prev_link_'+plObj.id)?
732 - plObj.getClip(-1):plObj.getClip(1);
733 - //get the position of #mv_perv|next_link:
734 - var loc = getAbsolutePos(this.id);
735 - //js_log('Hover: x:'+loc.x + ' y:' + loc.y + ' :'+clip.img);
736 - $j("body").append('<div id="mv_Athub" style="position:absolute;' +
737 - 'top:'+loc.y+'px;left:'+loc.x+'px;width:'+tw+'px;height:'+th+'px;">'+
738 - '<img style="border:solid 2px '+clip.getColor()+';position:absolute;top:0px;left:0px;" width="'+tw+'" height="'+th+'" src="'+clip.img+'"/>'+
739 - '</div>');
740 - }, function() {
741 - $j('#mv_Athub').remove();
742 - });
743 - },
744 - //returns a clip. If offset is out of bound returns first or last clip
745 - getClip: function(clip_offset){
746 - if(!clip_offset)clip_offset=0;
747 -
748 - var cov = parseInt( this.cur_clip.order ) + parseInt( clip_offset );
749 - var cmax = this.getClipCount()-1;
750 - js_log( 'f:getClip: '+clip_offset + ' cov:'+cov +' cmax:'+ cmax);
751 -
752 - //force first or last clip if offset is outOfBounds
753 - if( cov >= 0 && cov <= cmax ){
754 - return this.default_track.clips[ cov ];
755 - }else{
756 - if(cov < 0) return this.default_track.clips[0];
757 - if(cov > cmax) return this.default_track.clips[cmax];
758 - }
759 - },
760 - /*
761 - * generic add Clip to ~default~ track
762 - */
763 - addCliptoTrack: function(clipObj, pos){
764 - if( typeof clipObj['track_id'] =='undefined'){
765 - var track = this.default_track;
766 - }else{
767 - var track = this.tracks[ clipObj.track_id ]
768 - }
769 - js_log('add clip' + clipObj.id +' to track: at:' + pos);
770 - //set the first clip to current (maybe deprecated )
771 - if(clipObj.order==0){
772 - if(!this.cur_clip)this.cur_clip=clipObj;
773 - }
774 - track.addClip(clipObj, pos);
775 - },
776 - swapClipDesc: function(req_clipID, callback){
777 - //hide all but the requested
778 - var plObj=this;
779 - js_log('r:'+req_clipID+' cur:'+plObj.id);
780 - if(req_clipID==plObj.cur_clip.id){
781 - js_log('no swap to same clip');
782 - }else{
783 - //fade out clips
784 - req_clip=null;
785 - $j.each(this.default_track.clips, function(i, clip){
786 - if(clip.id!=req_clipID){
787 - //fade out if display!=none already
788 - if($j('#clipDesc_'+clip.id).css('display')!='none'){
789 - $j('#clipDesc_'+clip.id).fadeOut("slow");
790 - }
791 - }else{
792 - req_clip =clip;
793 - }
794 - });
795 - //fade in requested clip *and set req_clip to current
796 - $j('#clipDesc_'+req_clipID).fadeIn("slow", function(){
797 - plObj.cur_clip = req_clip;
798 - if(callback)
799 - callback();
800 - });
801 - }
802 - },
803 - getPLControls: function(){
804 - js_log('getPL cont');
805 - return '<a id="mv_prev_link_'+this.id+'" title="Previus Clip" onclick="document.getElementById(\''+this.id+'\').prev();return false;" href="#">'+
806 - getTransparentPng({id:'mv_prev_btn_'+this.id,style:'float:left',width:'27', height:'27', border:"0",
807 - src:mv_embed_path+'images/vid_prev_sm.png' }) +
808 - '</a>'+
809 - '<a id="mv_next_link_'+this.id+'" title="Next Clip" onclick="document.getElementById(\''+this.id+'\').next();return false;" href="#">'+
810 - getTransparentPng({id:'mv_next_btn_'+this.id,style:'float:left',width:'27', height:'27', border:"0",
811 - src:mv_embed_path+'images/vid_next_sm.png' }) +
812 - '</a>';
813 - },
814 - run_transition: function( clip_inx, trans_type){
815 - if(typeof this.default_track.clips[ clip_inx ][ trans_type ] == 'undefined')
816 - clearInterval( this.default_track.clips[ clip_inx ].timerId );
817 - else
818 - this.default_track.clips[ clip_inx ][ trans_type ].run_transition();
819 - }
820 -}
821 -var gclipFocus=null;
822 -//delay the swap by .2 seconds
823 -function mvSeqOver(clipID,playlistID){
824 - setTimeout('doMvSeqOver(\''+clipID+'\',\''+playlistID+'\')', 200);
825 - gclipFocus=clipID;
826 -}
827 -function mvSeqOut(){
828 - gclipFocus=null;
829 -}
830 -function doMvSeqOver(clipID, playlistID){
831 - if(!mv_lock_vid_updates){
832 - if(gclipFocus==clipID){
833 - plElm = document.getElementById(playlistID);
834 - //js_log("got playlist by id: "+ plElm.id);
835 - if(plElm)plElm.swapClipDesc(clipID);
836 - }
837 - }
838 -}
839 -
840 -/* Object Stubs:
841 - *
842 - * @videoTrack ... stores clips and layer info
843 - *
844 - * @clip... each clip segment is a clip object.
845 - * */
846 -var mvClip = function(o) {
847 - if(o)
848 - this.init(o);
849 - return this;
850 -};
851 -//set up the mvPlaylist object
852 -mvClip.prototype = {
853 - id:null, //clip id
854 - pp:null, // parent playlist
855 - order:null, //the order/array key for the current clip
856 - src:null,
857 - info:null,
858 - title:null,
859 - mvclip:null,
860 - type:null,
861 - img:null,
862 - duration:null,
863 - loading:false,
864 - isAnimating:false,
865 - init:function(o){
866 - //init object including pointer to parent
867 - for(var i in o){
868 - this[i]=o[i];
869 - };
870 - js_log('id is: '+ this.id);
871 - },
872 - //setup the embed object:
873 - setUpEmbedObj:function(){
874 - js_log('pl:setUpEmbedObj');
875 - //init:
876 - //debugger;
877 -
878 - this.embed=null;
879 - //js_log('setup embed for clip '+ this.id + ':id is a function?');
880 - //set up the pl_mv_embed object:
881 - var init_pl_embed={id:'e_'+this.id,
882 - pc:this, //parent clip
883 - src:this.src
884 - };
885 -
886 - this.setBaseEmbedDim(init_pl_embed);
887 - //always display controls for playlists:
888 -
889 - //if in sequence mode hide controls / embed links
890 - // init_pl_embed.play_button=false;
891 - init_pl_embed.controls=false;
892 - //if(this.pp.sequencer=='true'){
893 - init_pl_embed.embed_link=null;
894 - init_pl_embed.linkback=null;
895 -
896 - if(this.poster)init_pl_embed['thumbnail']=this.poster;
897 -
898 - if(this.type)init_pl_embed['type'] = this.type;
899 -
900 - this.embed = new PlMvEmbed(init_pl_embed);
901 -
902 - js_log('ve src len:' + this.embed.media_element.sources.length);
903 - //js_log('media element:'+ this.embed.media_element.length);
904 - //js_log('type of embed:' + typeof(this.embed) + ' seq:' + this.pp.sequencer+' pb:'+ this.embed.play_button);
905 - },
906 - doAdjust:function(side, delta){
907 - js_log("f:doAdjust: " + side + ' , ' + delta);
908 - if(this.embed){
909 - if(side=='start'){
910 - var start_offset =parseInt(this.embed.start_offset)+parseInt(delta*-1);
911 - this.embed.updateVideoTime( seconds2ntp(start_offset), seconds2ntp ( this.embed.start_offset + this.embed.getDuration() ) );
912 - }else if(side=='end'){
913 - var end_offset = parseInt(this.embed.start_offset) + parseInt( this.embed.getDuration() ) + parseInt(delta);
914 - this.embed.updateVideoTime( seconds2ntp(this.embed.start_offset), seconds2ntp(end_offset) );
915 - }
916 - //update everything:
917 - this.pp.refresh();
918 - /*var base_src = this.src.substr(0,this.src.indexOf('?'));
919 - js_log("delta:"+ delta);
920 - if(side=='start'){
921 - //since we adjust start invert the delta:
922 - var start_offset =parseInt(this.embed.start_offset/1000)+parseInt(delta*-1);
923 - this.src = base_src +'?t='+ seconds2ntp(start_offset) +'/'+ this.embed.end_ntp;
924 - }else if(side=='end'){
925 - //put back into seconds for adjustment:
926 - var end_offset = parseInt(this.embed.start_offset/1000) + parseInt(this.embed.duration/1000) + parseInt(delta);
927 - this.src = base_src +'?t='+ this.embed.start_ntp +'/'+ seconds2ntp(end_offset);
928 - }
929 - this.embed.updateVideoTime( this.src );
930 - //update values
931 - this.duration = this.embed.getDuration();
932 - this.pp.pl_duration=null;
933 - //update playlist stuff:
934 - this.pp.updateTitle();*/
935 - }
936 - },
937 - getDuration:function(){
938 - if(!this.embed)this.setUpEmbedObj();
939 - return this.embed.getDuration();
940 - },
941 - setBaseEmbedDim:function(o){
942 - if(!o)o=this;
943 - //o.height=Math.round(pl_layout.clip_desc*this.pp.height)-2;//give it some padding:
944 - //o.width=Math.round(o.height*pl_layout.clip_aspect)-2;
945 - o.height= this.pp.height;
946 - o.width = this.pp.width;
947 - },
948 - //output the detail view:
949 - //@@todo
950 - /*getDetail:function(){
951 - //js_log('get detail:' + this.pp.title);
952 - var th=Math.round( this.pl_layout.clip_desc * this.pp.height );
953 - var tw=Math.round( th * this.pl_layout.clip_aspect );
954 -
955 - var twDesc = (this.pp.width-tw)-2;
956 -
957 - if(this.title==null)
958 - this.title='clip ' + this.order + ' ' +this.pp.title;
959 - if(this.desc==null)
960 - this.desc=this.pp.desc;
961 - //update the embed html:
962 - this.embed.getHTML();
963 -
964 - $j(this.embed).css({ 'position':"absolute",'top':"0px", 'left':"0px"});
965 -
966 - //js_log('append child to:#clipDesc_'+this.id);
967 - if($j('#clipDesc_'+this.id).get(0)){
968 - $j('#clipDesc_'+this.id).get(0).appendChild(this.embed);
969 -
970 - $j('#clipDesc_'+this.id).append(''+
971 - '<div id="pl_desc_txt_'+this.id+'" class="pl_desc" style="position:absolute;left:'+(tw+2)+'px;width:'+twDesc+'px;height:'+th+'px;overflow:auto;">'+
972 - '<b>'+this.title+'</b><br>'+
973 - this.desc + '<br>' +
974 - '<b>clip length:</b> '+ this.embed.getDurationNTP()+
975 - '</div>');
976 - }
977 - },*/
978 - getTitle:function(){
979 - if(typeof this.title == 'string')
980 - return this.title
981 -
982 - return 'untitled clip ' + this.order;
983 - },
984 - getThumb:function(){
985 - var out='';
986 - //if we have the parent playlist grab it to get the image scale
987 - if(this.pp){
988 - //js_log('pl height:' + this.pp.height + ' * ' + pl_layout.seq);
989 - var th = Math.round( this.pp.height * this.pl_layout.seq_thumb );
990 - //assume standard 4 by 3 video thumb res:
991 - var tw = Math.round( th * this.pl_layout.clip_aspect );
992 - //js_log('set by relative position:'+ th + ' '+tw);
993 - }
994 - var img = this.getClipImg();
995 -
996 - out+='<span ';
997 - if(this.title)out+='title="'+this.title+'" ';
998 - out+='style="position:relative;display:inline;padding:2px;" ';
999 - out+='onclick="document.getElementById(\''+this.pp.id+'\').play()" ';
1000 - out+='onmouseover="mvSeqOver(\''+this.id+'\',\''+this.pp.id+'\')" ';
1001 - out+='onmouseout="mvSeqOut()" ';
1002 - out+='>';
1003 - out+='<img style="border:solid 2px '+this.getColor()+'" height="'+th+'" width="'+tw+'" src="'+img+'"></span>';
1004 -
1005 - $j('#seqThumb_'+this.pp.id).append(out);
1006 - },
1007 - getClipImg:function(start_offset, size){
1008 - js_log('f:getClipImg ' + start_offset + ' s:'+size);
1009 - if( !this.img){
1010 - return mv_default_thumb_url;
1011 - }else{
1012 - if(!size && !start_offset){
1013 - return this.img;
1014 - }else{
1015 - //if a metavid image (has request parameters) use size and time args
1016 - if(this.img.indexOf('?')!=-1){
1017 - js_log('get with offset: '+ start_offset);
1018 - var time = seconds2ntp( start_offset+ (this.embed.start_offset/1000) );
1019 - js_log("time is: " + time);
1020 - this.img = this.img.replace(/t\=[^&]*/gi, "t="+time);
1021 - if(this.img.indexOf('&size=')!=-1){
1022 - this.img = this.img.replace(/size=[^&]*/gi, "size="+size);
1023 - }else{
1024 - this.img+='&size='+size;
1025 - }
1026 - }
1027 - return this.img;
1028 - }
1029 - }
1030 - },
1031 - getColor: function(){
1032 - //js_log('get color:'+ num +' : '+ num.toString().substr(num.length-1, 1) + ' : '+colors[ num.toString().substr(num.length-1, 1)] );
1033 - var num = this.id.substr( this.id.length-1, 1);
1034 - if(!isNaN(num)){
1035 - num=num.charCodeAt(0);
1036 - }
1037 - if(num >= 10)num=num % 10;
1038 - return mv_clip_colors[num];
1039 - }
1040 -}
1041 -/* mv_embed extensions for playlists */
1042 -var PlMvEmbed=function(vid_init){
1043 - //js_log('PlMvEmbed: '+ vid_init.id);
1044 - //create the div container
1045 - var ve = document.createElement('div');
1046 - //extend ve with all this
1047 - this.init(vid_init);
1048 - for(method in this){
1049 - if(method!='readyState'){
1050 - ve[method]= this[method];
1051 - }
1052 - }
1053 - js_log('ve src len:'+ ve.media_element.sources.length);
1054 - return ve;
1055 -}
1056 -//all the overwritten and new methods for playlist extension of mv_embed
1057 -PlMvEmbed.prototype = {
1058 - init:function(vid_init){
1059 - //send embed_video a created video element:
1060 - ve = document.createElement('div');
1061 - for(var i in vid_init){
1062 - //set the parent clip pointer:
1063 - if(i=='pc'){
1064 - this['pc']=vid_init['pc'];
1065 - }else{
1066 - ve.setAttribute(i,vid_init[i]);
1067 - }
1068 - }
1069 - var videoInterface = new embedVideo(ve);
1070 - //inherit the videoInterface
1071 - for(method in videoInterface){
1072 - if(method!='style'){
1073 - if(this[method]){
1074 - //parent embed method preservation:
1075 - this['pe_'+method]=videoInterface[method];
1076 - }else{
1077 - this[method]=videoInterface[method];
1078 - }
1079 - }
1080 - //string -> boolean:
1081 - if(this[method]=="false")this[method]=false;
1082 - if(this[method]=="true")this[method]=true;
1083 - }
1084 - },
1085 - stop:function(){
1086 - //set up convenience pointer to parent playlist
1087 - var plObj = this.pc.pp;
1088 - var plEmbed = this;
1089 -
1090 - js_log('do stop');
1091 - var th=Math.round( plObj.pl_layout.clip_desc * plObj.height );
1092 - var tw=Math.round( th * plObj.pl_layout.clip_aspect );
1093 - //run the parent stop:
1094 - this.pe_stop();
1095 - var pl_height = (plObj.sequencer=='true')?plObj.height+27:plObj.height;
1096 - //restore control offsets:
1097 - /*(if(this.pc.pp.controls){
1098 - $j('#dc_'+plObj.id).animate({
1099 - height:pl_height
1100 - },"slow");
1101 - }*/
1102 - //if(plObj.sequencer=='true'){
1103 - plEmbed.getHTML();
1104 - /*}else{
1105 - //fade in elements
1106 - $j('#big_play_link_'+this.id+',#lb_'+this.id+',#le_'+this.id+',#seqThumb_'+plObj.id+',#pl_desc_txt_'+this.pc.id).fadeIn("slow");
1107 - //animate restore of resize
1108 - var res ={};
1109 - this.pc.setBaseEmbedDim(res);
1110 - //debugger;
1111 - $j('#img_thumb_'+this.id).animate(res,"slow",null,function(){
1112 - plEmbed.pc.setBaseEmbedDim(plEmbed);
1113 - plEmbed.getHTML();
1114 - //restore the detail
1115 - $j('#clipDesc_'+plEmbed.pc.id).empty();
1116 - plEmbed.pc.getDetail();
1117 - //$j('#seqThumb_'+plObj.id).css({position:'absolute',bottom:Math.round(this.height* pl_layout.seq_nav)});
1118 - //$j('#'+plEmbed.id+',#dc_'+plEmbed.id).css({position:'absolute', zindex:0,width:tw,height:th});
1119 - });
1120 - }*/
1121 - },
1122 - play:function(){
1123 - js_log('pl eb play');
1124 - var plEmbed = this;
1125 - var plObj = this.pc.pp;
1126 - //check if we are already playing
1127 - if( !this.thumbnail_disp ){
1128 - plEmbed.pe_play();
1129 - return '';
1130 - }
1131 - mv_lock_vid_updates=true;
1132 -
1133 - js_log('controls: '+plObj.controls);
1134 - //fade out interface elements
1135 - /*$j('#big_play_link_'+this.id+',#seqThumb_'+plObj.id+',#pl_desc_txt_'+this.pc.id).fadeOut("slow");*/
1136 - plEmbed.pe_play();
1137 - },
1138 - //do post interface operations
1139 - postEmbedJS:function(){
1140 - //add playlist clips (if plugin supports it)
1141 - if(this.pc.pp.cur_clip.embed.playlistSupport())
1142 - this.pc.pp.loadEmbedPlaylist();
1143 - //color playlist points (if play_head present)
1144 - if(this.pc.pp.disp_play_head)
1145 - this.pc.pp.colorPlayHead();
1146 - //setup hover images (for playhead and next/prev buttons)
1147 - this.pc.pp.setUpHover();
1148 - //call the parent postEmbedJS
1149 - this.pe_postEmbedJS();
1150 - mv_lock_vid_updates=false;
1151 - },
1152 - getPlayButton:function(){
1153 - return this.pe_getPlayButton(this.pc.pp.id);
1154 - },
1155 - setStatus:function(value){
1156 - //status updates handled by playlist obj
1157 - },
1158 - setSliderValue:function(value){
1159 - //setSlider value handled by playlist obj
1160 - }
1161 -}
1162 -
1163 -/*
1164 - * m3u parse
1165 - */
1166 -var m3uPlaylist = {
1167 - doParse:function(){
1168 - //for each line not # add as clip
1169 - var inx =0;
1170 - var this_pl = this;
1171 - //js_log('data:'+ this.data.toString());
1172 - $j.each(this.data.split("\n"), function(i,n){
1173 - //js_log('on line '+i+' val:'+n+' len:'+n.length);
1174 - if(n.charAt(0)!='#'){
1175 - if(n.length>3){
1176 - //@@todo make sure its a valid url
1177 - //js_log('add url: '+i + ' '+ n);
1178 - var cur_clip = new mvClip({type:'srcClip',id:'p_'+this_pl.id+'_c_'+inx,pp:this_pl,src:n,order:inx});
1179 - //setup the embed object
1180 - cur_clip.setUpEmbedObj();
1181 - js_log('m3uPlaylist len:'+ thisClip.embed.media_element.sources.length);
1182 - this_pl.addCliptoTrack(cur_clip);
1183 - inx++;
1184 - }
1185 - }
1186 - });
1187 - return true;
1188 - }
1189 -}
1190 -
1191 -var itunesPlaylist = {
1192 - doParse:function(){
1193 - var properties = { title:'title', linkback:'link',
1194 - author:'itunes:author',desc:'description',
1195 - date:'pubDate' };
1196 - var tmpElm = null;
1197 - for(i in properties){
1198 - tmpElm = this.data.getElementsByTagName(properties[i])[0];
1199 - if(tmpElm){
1200 - this[i] = tmpElm.childNodes[0].nodeValue;
1201 - //js_log('set '+i+' to '+this[i]);
1202 - }
1203 - }
1204 - //image src is nested in itunes rss:
1205 - tmpElm = this.data.getElementsByTagName('image')[0];
1206 - if(tmpElm){
1207 - imgElm = tmpElm.getElementsByTagName('url')[0];
1208 - if(imgElm){
1209 - this.img = imgElm.childNodes[0].nodeValue;
1210 - }
1211 - }
1212 - //get the clips:
1213 - var clips = this.data.getElementsByTagName("item");
1214 - properties.src = 'guid';
1215 - for (var i=0;i<clips.length;i++){
1216 - var cur_clip = new mvClip({type:'srcClip',id:'p_'+this.id+'_c_'+i,pp:this,order:i});
1217 - for(var j in properties){
1218 - tmpElm = clips[i].getElementsByTagName( properties[j] )[0];
1219 - if(tmpElm!=null){
1220 - cur_clip[j] = tmpElm.childNodes[0].nodeValue;
1221 - //js_log('set clip property: ' + j+' to '+cur_clip[j]);
1222 - }
1223 - }
1224 - //image is nested
1225 - tmpElm = clips[i].getElementsByTagName('image')[0];
1226 - if(tmpElm){
1227 - imgElm = tmpElm.getElementsByTagName('url')[0];
1228 - if(imgElm){
1229 - cur_clip.img = imgElm.childNodes[0].nodeValue;
1230 - }
1231 - }
1232 - //set up the embed object now that all the values have been set
1233 - cur_clip.setUpEmbedObj();
1234 -
1235 - //add the current clip to the clip list
1236 - this.addCliptoTrack(cur_clip);
1237 - }
1238 - return true;
1239 - }
1240 -}
1241 -
1242 -/*
1243 - * parse xsfp:
1244 - * http://www.xspf.org/xspf-v1.html
1245 - */
1246 -var xspfPlaylist ={
1247 - doParse:function(){
1248 - //js_log('do xsfp parse: '+ this.data.innerHTML);
1249 - var properties = { title:'title', linkback:'info',
1250 - author:'creator',desc:'annotation',
1251 - img:'image', date:'date' };
1252 - var tmpElm = null;
1253 - //get the first instance of any of the meta tags (ok that may be the meta on the first clip)
1254 - //js_log('do loop on properties:' + properties);
1255 - for(i in properties){
1256 - js_log('on property: '+i);
1257 - tmpElm = this.data.getElementsByTagName(properties[i])[0];
1258 - if(tmpElm){
1259 - if(tmpElm.childNodes[0]){
1260 - this[i] = tmpElm.childNodes[0].nodeValue;
1261 - js_log('set pl property: ' + i+' to '+this[i]);
1262 - }
1263 - }
1264 - }
1265 - var clips = this.data.getElementsByTagName("track");
1266 - js_log('found clips:'+clips.length);
1267 - //add any clip specific properties
1268 - properties.src = 'location';
1269 - for (var i=0;i<clips.length;i++){
1270 - var cur_clip = new mvClip({type:'srcClip',id:'p_'+this.id+'_c_'+i,pp:this,order:i});
1271 - //js_log('cur clip:'+ cur_clip.id);
1272 - for(var j in properties){
1273 - tmpElm = clips[i].getElementsByTagName( properties[j] )[0];
1274 - if(tmpElm!=null){
1275 - if( tmpElm.childNodes.length!=0){
1276 - cur_clip[j] = tmpElm.childNodes[0].nodeValue;
1277 - js_log('set clip property: ' + j+' to '+cur_clip[j]);
1278 - }
1279 - }
1280 - }
1281 - //add mvClip ref from info link:
1282 - if(cur_clip.linkback){
1283 - //if mv linkback
1284 - mvInx = 'Stream:';
1285 - mvclippos = cur_clip.linkback.indexOf(mvInx);
1286 - if(mvclippos!==false){
1287 - cur_clip.mvclip=cur_clip.linkback.substr( mvclippos+mvInx.length );
1288 - }
1289 - }
1290 - //set up the embed object now that all the values have been set
1291 - cur_clip.setUpEmbedObj();
1292 - //add the current clip to the clip list
1293 - this.addCliptoTrack(cur_clip);
1294 - }
1295 - //js_log('done with parse');
1296 - return true;
1297 - }
1298 -}
1299 -/*****************************
1300 - * SMIL CODE (could be put into another js file / lazy_loaded for improved basic playlist performance / modularity)
1301 - *****************************/
1302 -/*playlist driver extensions to the playlist object*/
1303 -mvPlayList.prototype.monitor = function(){
1304 - //js_log('pl:monitor');
1305 - //js_log('mvPlayList:monitor trueTime: '+ ( (ct.getTime() - this.clockStartTime )/1000));
1306 - //if paused stop updates
1307 - if( this.paused ){
1308 - //clearInterval( this.smil_monitorTimerId );
1309 - return ;
1310 - }
1311 - //js_log("pl check: " + this.currentTime + ' < '+this.getDuration());
1312 - //check if we should be done:
1313 - if( this.currentTime > this.getDuration() )
1314 - this.stop();
1315 -
1316 - //update the playlist current time:
1317 - this.currentTime = this.cur_clip.dur_offset + this.cur_clip.embed.currentTime;
1318 - //update slider:
1319 - if(!this.userSlide){
1320 - this.setStatus(seconds2ntp(this.currentTime) + '/' + seconds2ntp(this.getDuration()) );
1321 - this.setSliderValue(this.currentTime / this.getDuration());
1322 - }
1323 -
1324 - //status updates are handled by children clips ... playlist just manages smil actions
1325 - this.doSmilActions();
1326 -
1327 - if( ! this.smil_monitorTimerId ){
1328 - if(document.getElementById(this.id)){
1329 - this.smil_monitorTimerId = setInterval('$j(\'#'+this.id+'\').get(0).monitor()', 250);
1330 - }
1331 - }
1332 -}
1333 -//handles the rendering of overlays load of future clips (if necessary)
1334 -//@@todo could be lazy loaded if necessary
1335 -mvPlayList.prototype.doSmilActions = function( single_frame ){
1336 - //js_log('f:doSmilActions: ' + this.cur_clip.id + ' tid: ' + this.cur_clip.transOut );
1337 - var offSetTime = 0; //offset time should let us start a transition later on if we have to.
1338 - var _clip = this.cur_clip; //setup a local pointer to cur_clip
1339 -
1340 -
1341 - //do any smil time actions that may change the current clip
1342 - if( this.userSlide ){
1343 - //current clip set is set via updateThumbTime function
1344 - }else{
1345 - //assume playing and go to next:
1346 - if( _clip.dur <= _clip.embed.currentTime
1347 - && _clip.order != _clip.pp.getClipCount()-1 ){
1348 - //force next clip
1349 - js_log('order:' + _clip.order + ' != count:' + ( _clip.pp.getClipCount()-1 ) +
1350 - ' smil dur: ' + _clip.dur + ' <= curTime: ' + _clip.embed.currentTime + ' go to next clip..');
1351 - //do a _play next:
1352 - _clip.pp.next();
1353 - }
1354 - }
1355 - //@@todo could maybe generalize transIn with trasOut into one "flow" with a few scattered if statements
1356 - //update/setup all transitions (will render current transition state)
1357 - var in_range=false;
1358 - //pretty similar actions per transition types so group into a loop:
1359 - var tran_types = {'transIn':true,'transOut':true};
1360 - for(var tid in tran_types ){
1361 - eval('var tObj = _clip.'+tid);
1362 - if(!tObj)
1363 - continue;
1364 - //js_log('f:doSmilActions: ' + _clip.id + ' tid:'+tObj.id + ' tclip_id:'+ tObj.pClip.id);
1365 - //make sue we are in range:
1366 - if( tid=='transIn' )
1367 - in_range = (_clip.embed.currentTime <= tObj.dur)?true:false;
1368 -
1369 - if( tid=='transOut' )
1370 - in_range = (_clip.embed.currentTime >= (_clip.dur - tObj.dur))?true:false;
1371 -
1372 - if( in_range ){
1373 - if( this.userSlide || single_frame ){
1374 - if( tid=='transIn' )
1375 - mvTransLib.doUpdate(tObj, (_clip.embed.currentTime / tObj.dur) );
1376 -
1377 - if( tid=='transOut' )
1378 - mvTransLib.doUpdate(tObj, (_clip.embed.currentTime-(_clip.dur - tObj.dur)) /tObj.dur);
1379 -
1380 - }else{
1381 - if( tObj.animation_state==0 ){
1382 - js_log('init/run_transition ');
1383 - tObj.run_transition();
1384 - }
1385 - }
1386 - }else{
1387 - //close up transition if done & still onDispaly
1388 - if( tObj.overlay_selector_id ){
1389 - js_log('close up transition :'+tObj.overlay_selector_id);
1390 - mvTransLib.doCloseTransition( tObj );
1391 - }
1392 - }
1393 - }
1394 -}
1395 -
1396 -/*
1397 - * mvTransLib library of transitions
1398 - * a single object called to initiate transition effects can easily be extended in separate js file
1399 - * /mvTransLib is a all static object no instances of mvTransLib/
1400 - * (that way a limited feature set "sequence" need not include a _lot_ of js unless necessary )
1401 - *
1402 - * Smil Transition Effects see:
1403 - * http://www.w3.org/TR/SMIL3/smil-transitions.html#TransitionEffects-TransitionAttribute
1404 - */
1405 -var mvTransLib = {
1406 - /*
1407 - * function doTransition lookups up the transition in the mvTransLib obj
1408 - * and init the transition if its available
1409 - * @param tObj transition attribute object
1410 - * @param offSetTime default value 0 if we need to start rendering from a given time
1411 - */
1412 - doInitTransition:function(tObj){
1413 - js_log('mvTransLib:f:doInitTransition');
1414 - if(!tObj.type)
1415 - return js_log('transition is missing type attribute');
1416 -
1417 - if(!tObj.subtype)
1418 - return js_log('transition is missing subtype attribute');
1419 -
1420 - if(!this['type'][tObj.type])
1421 - return js_log('mvTransLib does not support type: '+tObj.type);
1422 -
1423 - if(!this['type'][tObj.type][tObj.subtype])
1424 - return js_log('mvTransLib does not support subType: '+tObj.subtype);
1425 -
1426 - //setup overlay_selector_id
1427 - if(tObj.subtype=='crossfade'){
1428 - if(tObj.transAttrType=='transIn')
1429 - var other_pClip = tObj.pClip.pp.getClip(-1);
1430 - if(tObj.transAttrType=='transOut')
1431 - var other_pClip = tObj.pClip.pp.getClip(1);
1432 -
1433 - if(typeof(other_pClip)=='undefined' || other_pClip.id == tObj.pClip.pp.cur_clip.id)
1434 - js_log('Error: crossfade without media asset');
1435 - //if not sliding start playback:
1436 - if(!tObj.pClip.pp.userSlide)
1437 - other_pClip.embed.play();
1438 - tObj.overlay_selector_id = 'clipDesc_'+other_pClip.id;
1439 - }else{
1440 - tObj.overlay_selector_id =this.getOverlaySelector(tObj);
1441 - }
1442 -
1443 - //all good call function with tObj param
1444 - js_log('should call: '+tObj.type + ' ' + tObj.subtype );
1445 - this['type'][tObj.type][tObj.subtype].init(tObj);
1446 - },
1447 - doCloseTransition:function(tObj){
1448 - if(tObj.subtype=='crossfade'){
1449 - //close up crossfade
1450 - js_log("close up crossfade");
1451 - }else{
1452 - $j('#'+tObj.overlay_selector_id).remove();
1453 - }
1454 - //null selector:
1455 - tObj.overlay_selector_id=null;
1456 - },
1457 - getOverlaySelector:function(tObj){
1458 - var overlay_selector_id= tObj.transAttrType + tObj.pClip.id;
1459 - js_log('f:getOverlaySelector: '+overlay_selector_id + ' append to: ' +'#videoPlayer_'+tObj.pClip.embed.id );
1460 - //make sure overlay_selector_id not already here:
1461 - if( $j('#'+overlay_selector_id).length == 0 ){
1462 - $j('#videoPlayer_'+tObj.pClip.embed.id).prepend(''+
1463 - '<div id="'+overlay_selector_id+'" ' +
1464 - 'style="position:absolute;top:0px;left:0px;' +
1465 - 'height:'+parseInt(tObj.pClip.pp.height)+'px;'+
1466 - 'width:'+parseInt(tObj.pClip.pp.width)+'px;' +
1467 - 'z-index:2">' +
1468 - '</div>');
1469 - }
1470 - return overlay_selector_id;
1471 - },
1472 - doUpdate:function(tObj, percent){
1473 - //init the transition if nessesary:
1474 - if(!tObj.overlay_selector_id)
1475 - this.doInitTransition(tObj);
1476 -
1477 - //@@todo we should ensure visability outside of doUpate loop
1478 - if(!$j('#'+tObj.overlay_selector_id).is(':visible'))
1479 - $j('#'+tObj.overlay_selector_id).show();
1480 -
1481 - //do update:
1482 - /*js_log('doing update for: '+ tObj.pClip.id +
1483 - ' type:' + tObj.transAttrType +
1484 - ' t_type:'+ tObj.type +
1485 - ' subypte:'+ tObj.subtype +
1486 - ' percent:' + percent);*/
1487 -
1488 - this['type'][tObj.type][tObj.subtype].u(tObj,percent);
1489 - },
1490 - /*
1491 - * mvTransLib: functional library mapping:
1492 - */
1493 - type:{
1494 - //types:
1495 - fade:{
1496 - fadeFromColor:{
1497 - 'init':function(tObj){
1498 - //js_log('f:fadeFromColor: '+tObj.overlay_selector_id +' to color: '+ tObj.fadeColor);
1499 - if(!tObj.fadeColor)
1500 - return js_log('missing fadeColor');
1501 - if($j('#'+tObj.overlay_selector_id).length==0){
1502 - js_log("ERROR can't find: "+ tObj.overlay_selector_id);
1503 - }
1504 - //set the initial state
1505 - $j('#'+tObj.overlay_selector_id).css({
1506 - 'background-color':tObj.fadeColor,
1507 - 'opacity':"1"
1508 - });
1509 - },
1510 - 'u':function(tObj, percent){
1511 - //js_log(':fadeFromColor:update: '+ percent);
1512 - //fade from color (invert the percent)
1513 - var percent = 1- percent;
1514 - $j('#'+tObj.overlay_selector_id).css({
1515 - "opacity" : percent
1516 - });
1517 - }
1518 - },
1519 - //corssFade
1520 - crossfade:{
1521 - "init":function(tObj){
1522 - js_log('f:crossfade: '+tObj.overlay_selector_id);
1523 - if($j('#'+tObj.overlay_selector_id).length==0)
1524 - js_log("ERROR overlay selector not found: "+tObj.overlay_selector_id);
1525 -
1526 - //set the initial state show the zero opacity animation
1527 - $j('#'+tObj.overlay_selector_id).css({'opacity':0}).show();
1528 - },
1529 - 'u':function(tObj, percent){
1530 - $j('#'+tObj.overlay_selector_id).css({
1531 - "opacity" : percent
1532 - });
1533 - }
1534 - }
1535 - }
1536 - }
1537 -}
1538 -//very limited smile feature set more details soon:
1539 -//region="video_region" transIn="fromGreen" begin="2s"
1540 -//http://www.w3.org/TR/2007/WD-SMIL3-20070713/smil-extended-media-object.html#edef-ref
1541 -var smilPlaylist ={
1542 - transitions:{},
1543 - doParse:function(){
1544 - var _this = this;
1545 - js_log('f:doParse smilPlaylist');
1546 - //@@todo get/parse meta that we are intersted in:
1547 - var meta_tags = this.data.getElementsByTagName('meta');
1548 - var metaNames = new Array('title','interface_url', 'linkback', 'mTitle', 'mTalk');
1549 - $j.each(meta_tags, function(i,meta_elm){
1550 - js_log( "on META tag: "+ $j(meta_elm).attr('name') );
1551 - for(var i in metaNames){
1552 - var _name = metaNames[i];
1553 - if( $j(meta_elm).attr('name') && $j(meta_elm).attr('content') ){
1554 - if( $j(meta_elm).attr('name')== _name ){
1555 - _this[ _name ] = $j(meta_elm).attr('content');
1556 - js_log('set :' + _name + ' to ' + _this[ _name ]);
1557 - }
1558 - }
1559 - }
1560 - });
1561 - //add transition objects:
1562 - var transition_tags = this.data.getElementsByTagName('transition');
1563 - $j.each(transition_tags, function( i, trans_elm ){
1564 - if( $j(trans_elm).attr("id") ){
1565 - _this.transitions[ $j(trans_elm).attr("id")]= new transitionObj(trans_elm);
1566 - }else{
1567 - js_log('skipping transition: (missing id) ' + trans_elm );
1568 - }
1569 - });
1570 - js_log('loaded transitions:' + _this.transitions.length);
1571 - //add seq (latter we will have support more than one seq tag) / more than one "track"
1572 - var seq_tags = this.data.getElementsByTagName('seq');
1573 - $j.each(seq_tags, function(i,seq_elm){
1574 - var inx = 0;
1575 - //get all the clips for the given seq:
1576 - $j.each(seq_elm.childNodes, function(i, mediaElement){
1577 - //~complex~ @@todo to handlde a lot like "switch" "region" etc
1578 - //js_log('process: ' + mediaElemnt.tagName);
1579 - if(typeof mediaElement.tagName!='undefined'){
1580 - if( _this.tryAddMedia( mediaElement, inx ) ){
1581 - inx++;
1582 - }
1583 - }
1584 - });
1585 - });
1586 - js_log("done proc seq tags");
1587 - return true;
1588 - },
1589 - tryAddMedia:function(mediaElement, order, track_id){
1590 - js_log('SMIL:tryAddMedia:' + mediaElement);
1591 - //set up basic mvSMILClip send it the mediaElemnt & mvClip init:
1592 - var clipObj = new mvSMILClip(mediaElement,
1593 - {
1594 - "id":'p_' + this.id + '_c_' + order,
1595 - "pp":this, //set the parent playlist object pointer
1596 - "order": order
1597 - }
1598 - );
1599 - //set optional params track
1600 - if( typeof track_id != 'undefined')
1601 - clipObj["track_id"] = track_id;
1602 -
1603 - //debugger;
1604 - if (clipObj ){
1605 - //set up embed:
1606 - clipObj.setUpEmbedObj();
1607 - //add clip to track:
1608 - this.addCliptoTrack( clipObj , order);
1609 - return true;
1610 - }
1611 - //@@todo we could throw error details here once we integrate try catches everywhere :P
1612 - return false;
1613 - }
1614 -}
1615 -/* extension to mvClip to support smil properties */
1616 -var mvSMILClip=function(smil_clip_element, mvClipInit){
1617 - return this.init(smil_clip_element, mvClipInit);
1618 -}
1619 -//all the overwritten and new methods for SMIL extension of mv_embed
1620 -mvSMILClip.prototype = {
1621 - //http://www.w3.org/TR/2007/WD-SMIL3-20070713/smil-extended-media-object.html#smilMediaNS-BasicMedia
1622 - //and added resource description elements
1623 - supported_attributes : new Array(
1624 - 'id',
1625 - 'src',
1626 - 'type',
1627 - 'region',
1628 - 'transIn',
1629 - 'transOut',
1630 - 'fill',
1631 - 'dur',
1632 -
1633 - 'uri',
1634 - 'poster'
1635 - ),
1636 - init:function(smil_clip_element, mvClipInit){
1637 - _this = this;
1638 -
1639 - //make new mvCLip with ClipInit vals
1640 - var myMvClip = new mvClip( mvClipInit );
1641 -
1642 - //inherit mvClip
1643 - for(var method in myMvClip){
1644 - if(typeof this[method] != 'undefined' ){
1645 - this['parent_'+method]=myMvClip[method];
1646 - }else{
1647 - this[method] = myMvClip[method];
1648 - }
1649 - }
1650 -
1651 - //get supported media attr init non-set
1652 - $j.each(this.supported_attributes, function(i, attr){
1653 - if( $j(smil_clip_element).attr(attr)){
1654 - _this[attr]=$j(smil_clip_element).attr(attr);
1655 - }
1656 - })
1657 - this['tagName'] = smil_clip_element.tagName;
1658 -
1659 - if( smil_clip_element.firstChild ){
1660 - this['wholeText'] = smil_clip_element.firstChild.nodeValue;
1661 - js_log("SET wholeText for: "+this['tagName'] + ' '+ this['wholeText']);
1662 - }
1663 - //debugger;
1664 - //mv_embed specific property:
1665 - if( $j(smil_clip_element).attr('poster') )
1666 - this['img'] = $j(smil_clip_element).attr('poster');
1667 -
1668 - //lookup and assign copies of transitions
1669 - // (since transition needs to hold some per-instance state info)
1670 - if(this.transIn && this.pp.transitions[ this.transIn ]){
1671 - this.transIn = this.pp.transitions[ this.transIn ].clone();
1672 - this.transIn.pClip = _this;
1673 - this.transIn.transAttrType='transIn';
1674 - }
1675 -
1676 - if(this.transOut && this.pp.transitions[ this.transOut ]){
1677 - this.transOut = this.pp.transitions[ this.transOut ].clone();
1678 - this.transOut.pClip = _this;
1679 - this.transOut.transAttrType = 'transOut';
1680 - }
1681 - //parse duration / begin times:
1682 - if(this.dur)
1683 - this.dur = smilParseTime(this.dur);
1684 -
1685 - //conform type to video/ogg:
1686 - if(this['type']=='application/ogg'){
1687 - this['type']='video/ogg'; //conform to 'video/ogg' type
1688 - }
1689 -
1690 - return this;
1691 - },
1692 - //returns the values of supported_attributes:
1693 - getAttributeObj:function(){
1694 - var elmObj = {};
1695 - for(var i in this.supported_attributes){
1696 - var attr = this.supported_attributes[i];
1697 - if(this[attr])
1698 - elmObj[ attr ] = this[attr];
1699 - }
1700 - return elmObj;
1701 - },
1702 - /*
1703 - * getDuration
1704 - * @returns duration in int
1705 - */
1706 - getDuration:function(){
1707 - //check for smil dur:
1708 - if( this.dur )
1709 - return this.dur;
1710 - return this.embed.getDuration();
1711 - }
1712 -}
1713 -/* object to manage embedding html with smil timings
1714 - * grabs settings from parent clip
1715 - */
1716 -var transitionObj = function(element) {
1717 - this.init(element);
1718 -};
1719 -transitionObj.prototype = {
1720 - supported_attributes : new Array(
1721 - 'id',
1722 - 'type',
1723 - 'subtype',
1724 - 'fadeColor',
1725 - 'dur'
1726 - ),
1727 - transAttrType:null, //transIn or transOut
1728 - overlay_selector_id:null,
1729 - pClip:null,
1730 - timerId:null,
1731 - animation_state:0, //can be 0=unset, 1=running, 2=done
1732 - interValCount:0, //inter-intervalCount for animating between time updates
1733 - dur:2, //default duration of 2
1734 - init:function(element){
1735 - //load supported attributes:
1736 - var _this = this;
1737 - $j.each(this.supported_attributes, function(i, attr){
1738 - if(element.getAttribute(attr))
1739 - _this[attr]= element.getAttribute(attr);
1740 - });
1741 - //@@todo process duration (for now just strip s) per:
1742 - //http://www.w3.org/TR/SMIL3/smil-timing.html#Timing-ClockValueSyntax
1743 - if(_this.dur)
1744 - _this.dur = smilParseTime(_this.dur);
1745 - },
1746 - //returns the values of supported_attributes:
1747 - getAttributeObj:function(){
1748 - var elmObj = {};
1749 - for(var i in this.supported_attributes){
1750 - var attr = this.supported_attributes[i];
1751 - if(this[attr])
1752 - elmObj[ attr ] = this[attr];
1753 - }
1754 - return elmObj;
1755 - },
1756 - /*
1757 - * the main animation loop called every MV_ANIMATION_CB_RATE or 34ms ~around 30frames per second~
1758 - */
1759 - run_transition:function(){
1760 - //js_log('f:run_transition:' + this.interValCount);
1761 -
1762 - //update the time from the video if native:
1763 - if(typeof this.pClip.embed.vid !='undefined'){
1764 - this.interValCount=0;
1765 - this.pClip.embed.currentTime = this.pClip.embed.vid.currentTime;
1766 - }
1767 -
1768 - //}else{
1769 - //relay on currentTime update grabs (every 250ms or so) (ie for images)
1770 - // if(this.prev_curtime!=this.pClip.embed.currentTime){
1771 - // this.prev_curtime = this.pClip.embed.currentTime;
1772 - // this.interValCount=0;
1773 - // }
1774 - //}
1775 - //start_time =asigned by doSmilActions
1776 - //base_cur_time = pClip.embed.currentTime;
1777 - //dur = asigned by attribute
1778 - if(this.animation_state==0){
1779 - mvTransLib.doInitTransition(this);
1780 - this.animation_state=1;
1781 - }
1782 - //set percentage include difrence of currentTime to prev_curTime
1783 - // ie updated in-between currentTime updates)
1784 -
1785 - if(this.transAttrType=='transIn')
1786 - var percentage = ( this.pClip.embed.currentTime +
1787 - ( (this.interValCount*MV_ANIMATION_CB_RATE)/1000 )
1788 - ) / this.dur ;
1789 -
1790 - if(this.transAttrType=='transOut')
1791 - var percentage = (this.pClip.embed.currentTime +
1792 - ( (this.interValCount*MV_ANIMATION_CB_RATE)/1000 )
1793 - - (this.pClip.dur - this.dur)
1794 - ) /this.dur ;
1795 -
1796 - /*js_log('percentage = ct:'+this.pClip.embed.currentTime + ' + ic:'+this.interValCount +' * cb:'+MV_ANIMATION_CB_RATE +
1797 - ' / ' + this.dur + ' = ' + percentage );
1798 - */
1799 -
1800 - //js_log('cur percentage of transition: '+percentage);
1801 - //update state based on current time + cur_time_offset (for now just use pClip.embed.currentTime)
1802 - mvTransLib.doUpdate(this, percentage);
1803 -
1804 - if( percentage >= 1 ){
1805 - js_log("transition done update with percentage "+percentage);
1806 - this.animation_state=2;
1807 - clearInterval(this.timerId);
1808 - mvTransLib.doCloseTransition(this)
1809 - return true;
1810 - }
1811 -
1812 - this.interValCount++;
1813 - //setInterval in we are still in running state and user is not using the playhead
1814 - if( this.animation_state==1 ){
1815 - if(!this.timerId){
1816 - this.timerId = setInterval('document.getElementById(\'' + this.pClip.pp.id + '\').'+
1817 - 'run_transition(\'' + this.pClip.pp.cur_clip.order + '\','+
1818 - '\''+ this.transAttrType + '\')',
1819 - MV_ANIMATION_CB_RATE);
1820 - }
1821 - }else{
1822 - clearInterval(this.timerId);
1823 - }
1824 - return true;
1825 - },
1826 - clone:function(){
1827 - var cObj = new this.constructor();
1828 - for(var i in this)
1829 - cObj[i]=this[i];
1830 - return cObj;
1831 - }
1832 -}
1833 -/*
1834 - * takes an input
1835 - * @time_str input time string
1836 - * returns time in seconds
1837 - *
1838 - * @@todo process duration (for now just srip s) per:
1839 - * http://www.w3.org/TR/SMIL3/smil-timing.html#Timing-ClockValueSyntax
1840 - * (probably have to use a Time object to fully support the smil spec
1841 - */
1842 -function smilParseTime(time_str){
1843 - return parseInt(time_str.replace('s', ''));
1844 -}
1845 -/***************************
1846 - * end SMIL specific code
1847 - ***************************/
1848 - var trackObj = function( initObj ){
1849 - return this.init( initObj );
1850 - }
1851 - var supported_track_attr =
1852 -trackObj.prototype = {
1853 - //eventualy should be something like "seq" per SMIL spec
1854 - //http://www.w3.org/TR/SMIL3/smil-timing.html#edef-seq
1855 - // but we don't really support anywhere near the full concept of seq containers yet either
1856 - supported_attributes: new Array(
1857 - 'title',
1858 - 'desc:'
1859 - ),
1860 - disp_mode:'timeline_thumb',
1861 - init : function(initObj){
1862 - if(!initObj)
1863 - initObj={};
1864 - //make sure clips is new:
1865 - this.clips = new Array();
1866 -
1867 - var _this = this;
1868 - $j.each(this.supported_attributes, function(i, attr){
1869 - if(initObj[attr])
1870 - _this[attr] = initObj[attr];
1871 - });
1872 - },
1873 - //returns the values of supported_attributes:
1874 - getAttributeObj:function(){
1875 - var elmObj = {};
1876 - for(var i in this.supported_attributes){
1877 - var attr = this.supported_attributes[i];
1878 - if(this[attr])
1879 - elmObj[ attr ] = this[attr];
1880 - }
1881 - return elmObj;
1882 - },
1883 - addClip:function(clipObj, pos){
1884 - js_log('pl_Track: AddClip at:' + pos);
1885 - if( typeof pos == 'undefined' )
1886 - pos = this.clips.length;
1887 - //get everything after pos
1888 - this.clips.splice(pos, 0, clipObj);
1889 - //keep the clip order values accurate:
1890 - this.reOrderClips();
1891 - },
1892 - reOrderClips:function(){
1893 - for(var k in this.clips){
1894 - this.clips[k].order=k;
1895 - }
1896 - },
1897 - getClipCount:function(){
1898 - return this.clips.length;
1899 - },
1900 - inheritEmbedObj: function(){
1901 - $j.each(this.clips, function(i, clip){
1902 - clip.embed.inheritEmbedObj();
1903 - });
1904 - }
1905 -};
1906 -
1907 -/* utility functions
1908 - * (could be combined with other stuff)
1909 - */
1910 -
1911 -function getAbsolutePos(objectId) {
1912 - // Get an object left position from the upper left viewport corner
1913 - o = document.getElementById(objectId);
1914 - oLeft = o.offsetLeft; // Get left position from the parent object
1915 - while(o.offsetParent!=null) { // Parse the parent hierarchy up to the document element
1916 - oParent = o.offsetParent // Get parent object reference
1917 - oLeft += oParent.offsetLeft // Add parent left position
1918 - o = oParent
1919 - }
1920 - o = document.getElementById(objectId);
1921 - oTop = o.offsetTop;
1922 - while(o.offsetParent!=null) { // Parse the parent hierarchy up to the document element
1923 - oParent = o.offsetParent // Get parent object reference
1924 - oTop += oParent.offsetTop // Add parent top position
1925 - o = oParent
1926 - }
1927 - return {x:oLeft,y:oTop};
1928 -}
1929 -String.prototype.htmlEntities = function(){
1930 - var chars = new Array ('&','à','á','â','ã','ä','å','æ','ç','è','é',
1931 - 'ê','ë','ì','í','î','ï','ð','ñ','ò','ó','ô',
1932 - 'õ','ö','ø','ù','ú','û','ü','ý','þ','ÿ','À',
1933 - 'Á','Â','Ã','Ä','Å','Æ','Ç','È','É','Ê','Ë',
1934 - 'Ì','Í','Î','Ï','Ð','Ñ','Ò','Ó','Ô','Õ','Ö',
1935 - 'Ø','Ù','Ú','Û','Ü','Ý','Þ','€','\"','ß','<',
1936 - '>','¢','£','¤','¥','¦','§','¨','©','ª','«',
1937 - '¬','­','®','¯','°','±','²','³','´','µ','¶',
1938 - '·','¸','¹','º','»','¼','½','¾');
1939 -
1940 - var entities = new Array ('amp','agrave','aacute','acirc','atilde','auml','aring',
1941 - 'aelig','ccedil','egrave','eacute','ecirc','euml','igrave',
1942 - 'iacute','icirc','iuml','eth','ntilde','ograve','oacute',
1943 - 'ocirc','otilde','ouml','oslash','ugrave','uacute','ucirc',
1944 - 'uuml','yacute','thorn','yuml','Agrave','Aacute','Acirc',
1945 - 'Atilde','Auml','Aring','AElig','Ccedil','Egrave','Eacute',
1946 - 'Ecirc','Euml','Igrave','Iacute','Icirc','Iuml','ETH','Ntilde',
1947 - 'Ograve','Oacute','Ocirc','Otilde','Ouml','Oslash','Ugrave',
1948 - 'Uacute','Ucirc','Uuml','Yacute','THORN','euro','quot','szlig',
1949 - 'lt','gt','cent','pound','curren','yen','brvbar','sect','uml',
1950 - 'copy','ordf','laquo','not','shy','reg','macr','deg','plusmn',
1951 - 'sup2','sup3','acute','micro','para','middot','cedil','sup1',
1952 - 'ordm','raquo','frac14','frac12','frac34');
1953 -
1954 - newString = this;
1955 - for (var i = 0; i < chars.length; i++)
1956 - {
1957 - myRegExp = new RegExp();
1958 - myRegExp.compile(chars[i],'g')
1959 - newString = newString.replace (myRegExp, '&' + entities[i] + ';');
1960 - }
1961 - return newString;
1962 -}
\ No newline at end of file
Index: trunk/extensions/MetavidWiki/skins/mv_embed/mv_remote_media_search.js
@@ -1,211 +0,0 @@
2 -/*
3 -* a library for doing remote semantic wiki searches with a focus on media results.
4 -*/
5 -var mvBaseRemoteSearch = function(initObj) {
6 - return this.init(initObj);
7 -};
8 -mvBaseRemoteSearch.prototype = {
9 - //default values:
10 - thumb_width:80,
11 -
12 - completed_req:0,
13 - num_req:0,
14 -
15 - result_display_mode:'box', //box or list
16 - resultsObj:{},
17 - //init the object:
18 - init:function( initObj ){
19 - js_log('mvBaseRemoteSearch:init');
20 - for(var i in initObj){
21 - this[i] = initObj[i];
22 - }
23 -
24 - var _this = this;
25 - if(this['target_submit']){
26 - $j('#'+this['target_submit']).click(function(){
27 - js_log('doSearch REQ');
28 - _this.getSearchResults();
29 - });
30 - }
31 - //set up bindings for interface components
32 - //if(this['target_input'])
33 - //@@todo autocomplete for titles
34 -
35 - //if(this['target_results')
36 - //@@todo error checking
37 -
38 - //check if we are in metavid Temporal semantic media search mode
39 - //add an "advanced search" button
40 -
41 - //add in controls: (find a better place for these / use css)
42 - //this seems highly verbose do do a simple control
43 - var box_dark_url = mv_embed_path + 'skins/' + mv_skin_name + '/images/box_layout_icon_dark.png';
44 - var box_light_url = mv_embed_path + 'skins/' + mv_skin_name + '/images/box_layout_icon.png';
45 - var list_dark_url = mv_embed_path + 'skins/' + mv_skin_name + '/images/list_layout_icon_dark.png';
46 - var list_light_url = mv_embed_path + 'skins/' + mv_skin_name + '/images/list_layout_icon.png';
47 -
48 - $j('#'+this.target_submit).after('<img id="msc_box_layout" ' +
49 - 'src = "' + ( (_this.result_display_mode=='box')?box_dark_url:box_light_url ) + '" ' +
50 - 'style="width:20px;height:20px;cursor:pointer;"> ' +
51 - '<img id="msc_list_layout" '+
52 - 'src = "' + ( (_this.result_display_mode=='list')?list_dark_url:list_light_url ) + '" '+
53 - 'style="width:20px;height:20px;cursor:pointer;">'
54 - );
55 -
56 - $j('#msc_box_layout').hover(function(){
57 - $j(this).attr("src", box_dark_url );
58 - }, function(){
59 - $j(this).attr("src", ( (_this.result_display_mode=='box')?box_dark_url:box_light_url ) );
60 - }).click(function(){
61 - $j(this).attr("src", box_dark_url);
62 - $j('#msc_list_layout').attr("src", list_light_url);
63 - _this.setDispMode('box');
64 - });
65 -
66 - $j('#msc_list_layout').hover(function(){
67 - $j(this).attr("src", list_dark_url);
68 - }, function(){
69 - $j(this).attr("src", ( (_this.result_display_mode=='list')?list_dark_url:list_light_url ) );
70 - }).click(function(){
71 - $j(this).attr("src", list_dark_url);
72 - $j('#msc_box_layout').attr("src", box_light_url);
73 - _this.setDispMode('list');
74 - });
75 -
76 - //or if we are in plain mediaWiki mode:
77 - return this;
78 - },
79 - setDispMode:function(mode){
80 - js_log('setDispMode:' + mode);
81 - this.result_display_mode=mode;
82 - //reformat the results:
83 - this.formatOutputResults();
84 - },
85 - //check request done used for when we have multiple requests to check before formating results.
86 - checkRequestDone:function(){
87 - //display output if done:
88 - this.completed_req++;
89 - if(this.completed_req == this.num_req){
90 - this.formatOutputResults();
91 - }
92 - },
93 - formatOutputResults:function(){
94 - js_log('f:formatOutputResults');
95 - //debugger;
96 - var o='';
97 - //output results based on display mode:
98 - for( var rInx in this.resultsObj ){
99 - var resultItem = this.resultsObj[rInx];
100 - if( this.result_display_mode == 'box' ){
101 - o+='<div id="mv_result_' + rInx + '" class="mv_clip_box_result" style="width:' + this.thumb_width + 'px;">';
102 - o+='<img style="width:' + this.thumb_width + 'px;" src="' + resultItem.poster + '">';
103 - o+='</div>';
104 - }else if(this.result_display_mode == 'list'){
105 - o+='<div id="mv_result_' + rInx + '" class="mv_clip_list_result" style="width:90%">';
106 - o+='<img style="float:left;width:' + this.thumb_width + 'px;" src="' + resultItem.poster + '">';
107 - o+= pageObj.revisions[0]['*'];
108 - o+='</div>';
109 - o+='<div style="clear:both" />';
110 - }
111 - }
112 - js_log('set : ' +this.target_results + ' to ' + o);
113 - //debugger;
114 - $j('#'+this.target_results).html(o);
115 - }
116 -}
117 -
118 -/*
119 -* api modes (implementations should call these objects which inherit the mvBaseRemoteSearch
120 -*/
121 -var metavidRemoteSearch = function(initObj) {
122 - return this.init(initObj);
123 -};
124 -metavidRemoteSearch.prototype = {
125 - init:function(initObj){
126 - var baseSearch = new mvBaseRemoteSearch(initObj);
127 - //inherit:
128 - for(var i in baseSearch){
129 - if(typeof this[i] =='undefined'){
130 - this[i] = baseSearch[i];
131 - }else{
132 - this['parent_'+i] = baseSearch[i];
133 - }
134 - }
135 - }
136 -}
137 -
138 -var mediaWikiRemoteSearch = function(initObj) {
139 - return this.init(initObj);
140 -};
141 -mediaWikiRemoteSearch.prototype = {
142 - init:function(initObj){
143 - var baseSearch = new mvBaseRemoteSearch(initObj);
144 - //inherit:
145 - for(var i in baseSearch){
146 - if(typeof this[i] =='undefined'){
147 - this[i] = baseSearch[i];
148 - }else{
149 - this['parent_'+i] = baseSearch[i];
150 - }
151 - }
152 - },
153 - getSearchResults:function(){
154 - js_log('f:getSearchResults for:' + $j('#'+this.target_input).val() );
155 - //set results div to "loading"
156 - $j('#'+this.target_results).html( getMsg('loading_txt') );
157 - //empty out the current results:
158 - this.resultsObj={};
159 - //do two queries against the Image / File / MVD namespace:
160 - //construct search request:
161 - var req_url =this.p_seq.plObj.interface_url.replace(/index\.php/, 'api.php');
162 - //build the image request object:
163 - var rObj = {
164 - 'action':'query',
165 - 'generator':'search',
166 - 'gsrsearch': encodeURIComponent( $j('#'+this.target_input).val() ),
167 - 'gsrnamespace':6, //(only search images)
168 - 'gsrwhat':'title',
169 - 'prop':'imageinfo|revisions|categories',
170 - 'iiprop':'url',
171 - 'iiurlwidth':'80',
172 - 'rvprop':'content'
173 - };
174 - var _this = this;
175 - //set up the number of request:
176 - this.completed_req=0;
177 - this.num_req=2;
178 - //setup the number of requests result flag:
179 - do_api_req( rObj, req_url, function(data){
180 - //parse the return data
181 - _this.addMediaWikiAPIResults( data);
182 - _this.checkRequestDone();
183 - });
184 - //also do a request for page titles (would be nice if api could query both at the same time)
185 - rObj['gsrwhat']='text';
186 - do_api_req( rObj, req_url, function(data){
187 - //parse the return data
188 - _this.addResults( data);
189 - _this.checkRequestDone();
190 - });
191 - },
192 - addResults:function( data ){
193 - //make sure we have pages to idoerate:
194 - if(data.query && data.query.pages){
195 - for(var page_id in data.query.pages){
196 - var page = data.query.pages[ page_id ];
197 -
198 - this.resultsObj['ref'][page_id]={
199 - 'uri':page.title,
200 - 'poster':page.imageinfo.thumburl,
201 - 'src':page.imageinfo.url,
202 - 'desc':page.revisions['*'],
203 - 'meta':{
204 - 'categories':page.categories
205 - }
206 - }
207 - }
208 - }else{
209 - js_log('no results:' + data);
210 - }
211 - }
212 -}
\ No newline at end of file
Index: trunk/extensions/MetavidWiki/skins/mv_embed/mv_sequencer.js
@@ -1,1358 +0,0 @@
2 -/*
3 - * mv_sequencer.js Created on Oct 17, 2007
4 - *
5 - * All Metavid Wiki code is Released under the GPL2
6 - * for more info visit http://metavid.org/wiki/Code
7 - *
8 - * @author Michael Dale
9 - * @email dale@ucsc.edu
10 - * @url http://metavid.org
11 - *
12 - *
13 - * mv_sequencer.js
14 - * is a basic embeddable sequencer.
15 - * extends the playlist with drag/drop/sortable/add/remove functionality
16 - * editing of annotative content (mostly for wiki)
17 - * enables more dynamic layouts
18 - * exports back out to json or inline format
19 - */
20 -
21 -gMsg['menu_clipedit'] = 'Edit Selected Resource';
22 - gMsg['sc_fileopts'] ='Clip Detail';
23 - gMsg['sc_inoutpoints'] ='Set In-Out points';
24 - gMsg['sc_panzoom'] ='Pan zoom Controls';
25 - gMsg['sc_overlays'] ='Overlays';
26 - gMsg['sc_audio'] ='Audio Control';
27 -
28 -gMsg['menu_cliplib'] = 'Add Resource';
29 -gMsg['menu_transition'] = 'Transitions Effects';
30 -gMsg['menu_resource_overview'] = 'Resource Overview';
31 -gMsg['menu_options'] = 'Options';
32 -
33 -gMsg['loading_timeline'] = 'Loading TimeLine <blink>...</blink>';
34 -gMsg['loading_user_rights'] = 'Loading user rights <blink>...</blink>';
35 -
36 -gMsg['no_edit_permissions'] = 'You don\'t have permissions to save changes to this sequence';
37 -
38 -
39 -gMsg['edit_clip'] = 'Edit Clip';
40 -gMsg['edit_save'] = 'Save Changes';
41 -gMsg['edit_cancel'] = 'Cancel Edit';
42 -gMsg['edit_cancel_confirm'] = 'Are you sure you want to cancel your edit, changes will be lost';
43 -
44 -gMsg['zoom_in'] = 'Zoom In';
45 -gMsg['zoom_out'] = 'Zoom Out';
46 -gMsg['cut_clip'] = 'Cut Clips';
47 -gMsg['expand_track'] = 'Expand Track';
48 -gMsg['colapse_track'] = 'Collapse Track';
49 -gMsg['play_clip'] = 'Play From Playline Position';
50 -gMsg['pixle2sec'] = 'pixles to seconds';
51 -gMsg['rmclip'] = 'Remove Clip';
52 -gMsg['clip_in'] = 'clip in';
53 -gMsg['clip_out'] = 'clip out';
54 -
55 - //used to set default values and validate the passed init object
56 -var sequencerDefaultValues = {
57 -
58 - instance_name:'mvSeq', //for now only one instance by name mvSeq is allowed
59 - sequence_container_id:'null',//text value (so that its a valid property)
60 - video_container_id:'mv_video_container',
61 -
62 - video_width : 400,
63 - video_height: 300,
64 -
65 - sequence_tools_id:'mv_sequence_tools',
66 - timeline_id:'mv_timeline',
67 - plObj_id:'seq_plobj',
68 - plObj:'null',
69 -
70 - timeline_scale:.06, //in pixel to second ratio ie 100pixles for every ~30seconds
71 - timeline_duration:500, //default timeline length in seconds
72 - playline_time:0,
73 - track_thumb_height:60,
74 - track_text_height:20,
75 -
76 - //default timeline mode: "clip" (i-movie like) or "time" (finalCut like)
77 - timeline_mode:'clip',
78 -
79 - track_clipThumb_height:80, // how large are the i-movie type clips
80 -
81 - base_adj_duration:.5, //default time to subtract or add when adjusting clips.
82 -
83 - //default clipboard is empty:
84 - clipboard:new Array(),
85 - //stores the clipboard edit token (if user has rights to edit their User page)
86 - clipboardEditToken:null,
87 - //stores the sequence edit token (if user has rights to edit the current sequence)
88 - sequenceEditToken:null,
89 -
90 - //Msg are all the language specific values ...
91 - // (@@todo overwrite by msg values preloaded in the page)
92 - //tack/clips can be pushed via json or inline playlist format
93 - inline_playlist:'null', //text value so its a valid property
94 - inline_playlist_id:'null',
95 - mv_pl_src:'null',
96 - //the edit stack:
97 - edit_stack:new Array(),
98 -
99 - //trackObj used to payload playlist Track Object (when inline not present)
100 - tracks:{}
101 -}
102 -var mvSequencer = function(initObj) {
103 - return this.init(initObj);
104 -};
105 -//set up the mvSequencer object
106 -mvSequencer.prototype = {
107 - menu_items : {
108 - 'clipedit':{
109 - 'd':1,
110 - 'submenu':{
111 - 'fileopts':1,
112 - 'inoutpoints':0,
113 - 'panzoom':0,
114 - 'overlays':0,
115 - 'audio':0
116 - }
117 - },
118 - 'cliplib':{
119 - 'd':0
120 - },
121 - 'transition':{
122 - 'd':0
123 - },
124 - 'options':{
125 - 'd':0
126 - }
127 - },
128 -
129 - //set up initial key states:
130 - key_shift_down:false,
131 - key_ctrl_down:false,
132 -
133 - init:function( initObj ){
134 - //set up pointer to this_seq for current scope:
135 - var this_seq = this;
136 - //set the default values:
137 - for(var i in sequencerDefaultValues){
138 - this[ i ] = sequencerDefaultValues[i];
139 - }
140 - for(var i in initObj){
141 - //js_log('on '+ i + ' :' + initObj[i]);
142 - if(sequencerDefaultValues[i]){ //make sure its a valid property
143 - this[i] = initObj[i];
144 - }
145 - }
146 - if(this.sequence_container_id==null)
147 - return js_log('Error: no sequence_container_id');
148 -
149 - //check for sequence_container
150 - if(this.sequence_container_id=='null')
151 - return js_log("Error: missing sequence_container_id");
152 -
153 - //$j('#'+this.sequence_container_id).css('position', 'relative');
154 - this['base_width'] = $j('#'+this.sequence_container_id).width();
155 - this['base_height'] = $j('#'+this.sequence_container_id).height();
156 -
157 -
158 - //add the container divs (with basic layout ~universal~
159 - $j('#'+this.sequence_container_id).html(''+
160 - '<div id="'+this.video_container_id+'" style="position:absolute;right:0px;top:0px;' +
161 - 'width:'+this.video_width+'px;height:'+this.video_height+'px;border:solid thin blue;background:#FFF;font-color:black;"/>'+
162 - '<div id="'+this.sequence_tools_id+'" style="position:absolute;' +
163 - 'left:0px;right:'+(this.video_width+10)+'px;top:0px;height:'+this.video_height+'px;border:solid thin black;"/>'+
164 - '<div id="'+this.timeline_id+'" style="position:absolute;' +
165 - 'left:0px;right:0px;top:'+(this.video_height+10)+'px;bottom:25px;overflow:auto;">'+
166 - getMsg('loading_timeline')+ '</div>'+
167 - '<div id="' + this.sequence_container_id + '_status" style="position:absolute;left:0px;width:300px;"></div>'+
168 - '<div id="' + this.sequence_container_id + '_save_cancel" style="position:absolute;'+
169 - 'right:0px;bottom:0px;height:25px;overflow:hidden;">'+
170 - getMsg('loading_user_rights') +
171 - '</div>'
172 - );
173 -
174 - js_log('set: '+this.sequence_container_id + ' html to:'+ "\n"+
175 - $j('#'+this.sequence_container_id).html()
176 - );
177 - //first check if we got a cloned PL object:
178 - //(when the editor is invoked with the plalylist already on the page)
179 - //@@NOT WORKING... (need a better "clone" function)
180 - /*if( this.plObj != 'null' ){
181 - js_log('found plObj clone');
182 - //extend with mvSeqPlayList object:
183 - this.plObj = new mvSeqPlayList(this.plObj);
184 - js_log('mvSeqPlayList added: ' + this.plObj.org_control_height );
185 - $j('#'+this.video_container_id).get(0).attachNode( this.plObj );
186 - this.plObj.getHTML();
187 - this.checkReadyPlObj();
188 - return ;
189 - }*/
190 -
191 - //else check for source based sequence editor (a clean page load of the editor)
192 - if( this.mv_pl_src != 'null' ) {
193 - js_log( ' pl src:: ' + this.mv_pl_src );
194 - var src_attr=' src="' + this.mv_pl_src+'" ';
195 - }else{
196 - js_log( ' null playlist src .. (start empty) ');
197 - var src_attr='';
198 - }
199 - $j('#'+this.video_container_id).html('<playlist ' + src_attr +
200 - ' style="width:' + this.video_width + 'px;height:' + this.video_height + 'px;" '+
201 - ' sequencer="true" id="' + this.plObj_id + '" />');
202 -
203 - rewrite_by_id( this.plObj_id );
204 - setTimeout(this.instance_name +'.checkReadyPlObj()', 25);
205 - },
206 - updateSeqSaveButtons:function(){
207 - var cancel_button = '<a style="border:' +
208 - 'solid gray;font-size:1.2em;" onClick="window.confirm(\''+getMsg('edit_cancel_confirm')+'\')" '+
209 - 'href="javascript:'+this.instance_name+'.closeModEditor()">'+
210 - getMsg('edit_cancel') + '</a> ';
211 - if( this.sequenceEditToken ){
212 - $j('#'+this.sequence_container_id+'_save_cancel').html( cancel_button +
213 - '<a style="border:solid gray;font-size:1.2em;" href="#" onClick="'+this.instance_name+'.getSeqOutputJSON()">'+
214 - 'Preview Json Output'+
215 - '</a>' +
216 - '<a style="border:solid gray;font-size:1.2em;" href="#" onClick="'+this.instance_name+'.getSeqOutputHLRDXML()">'+
217 - 'Preview XML Output (will be save shortly) ' +
218 - '</a>');
219 - }else{
220 - $j('#'+this.sequence_container_id+'_save_cancel').html( cancel_button + getMsg('no_edit_permissions') );
221 - }
222 - },
223 - //display a menu item (hide the rest)
224 - disp:function( item ){
225 - js_log('disp: ' + item);
226 - for(var i in this.menu_items){
227 - if(i==item){
228 - $j('#'+i+'_ic').fadeIn("fast");
229 - }else{
230 - $j('#'+i+'_ic').filter(':visible').fadeOut("fast");
231 - }
232 - }
233 - },
234 - //load the menu items:
235 - loadInitMenuItems:function(){
236 - js_log('loadInitMenuItems');
237 - if( !this.plObj.interface_url )
238 - return js_log( 'Error:missing interface_url, can not load item' );
239 -
240 - var req_url =this.plObj.interface_url+ '?action=ajax&rs=mv_seqtool_disp&rsargs[]=';
241 - //ouput the requested items list:
242 - for(var i in this.menu_items){
243 - req_url+='|'+i;
244 - //if single items set to loading:
245 - if(typeof this.menu_items[i].submenu == 'undefined')
246 - $j('#'+i+'_ic').html( getMsg('loading_txt') );//set targets to loading
247 - //else set the default sub menu to loading:
248 - for(var j in this.menu_items[i].submenu){
249 - if(this.menu_items[i].submenu[j])
250 - $j('#sc_'+j).html( getMsg('loading_txt') );
251 - }
252 - }
253 - var this_seq = this;
254 - do_request(req_url, function(data){
255 - if( typeof data=='string' ){
256 - js_log(' eval data: ' + data);
257 - eval(data);
258 - var data = mv_result['pay_load'];
259 - }
260 - for( var i in data ){
261 - var menu_item = this_seq.menu_items[i];
262 - js_log('set '+ i + ' to: '+ data[i] );
263 - if( menu_item.submenu ){
264 - if(typeof data[i]=='string'){
265 - //just set the default item
266 - for(var j in menu_item.submenu){
267 - if( menu_item.submenu[j] )
268 - $j('#sc_'+j).html( data[i] );
269 - }
270 - }else if(typeof data[i] == 'object'){
271 - //see if we have sub data for each sub-menu item
272 - for(var j in data[i]){
273 - $j('#sc_'+j).html( data[i][j] );
274 - }
275 - }
276 - }else{
277 - //just set the parent container
278 - $j('#'+i+'_ic').html( data[i] );
279 - this_seq.doMenuItemDispJs(i)
280 - }
281 - }
282 - });
283 - },
284 - doMenuItemDispJs:function(item){
285 - var this_seq = this;
286 - var target_id = item + '_ic';
287 - var menu_item = this.menu_items[item];
288 - //do any menu item post embed js hook processing:
289 - switch(item){
290 - case 'clipedit':
291 - //load mv_clip_edit.js
292 - break;
293 - case 'transition':
294 - //render out the transitions library
295 - this.renderTransitionsSet(target_id);
296 - break;
297 - case 'cliplib':
298 - //load the search interface with sequence tool targets
299 - //@@todo it maybe cleaner to just pass along msg text in JSON
300 - //and have the search interface build the html
301 - if( !this.plObj.interface_url )
302 - return js_log( 'Error:missing interface_url, can not load search interface' );
303 -
304 - //check default search
305 - mvJsLoader.doLoad({'mediaWikiRemoteSearch':'mv_remote_media_search.js'}, function(){
306 - this_seq.mySearch = new mediaWikiRemoteSearch( {
307 - 'p_seq':this_seq,
308 - 'instance_name': this_seq.instance_name + '.mySearch',
309 - 'target_input':'mv_ams_search',
310 - 'target_submit':'mv_ams_submit',
311 - 'target_results':'mv_ams_results'
312 - });
313 - });
314 - break;
315 - case 'options':
316 - $j('#'+target_id+" input[value='simple_editor']").attr({
317 - 'checked':(this_seq.timeline_mode=='clip')?true:false
318 - }).click(function(){
319 - this_seq.doSimpleTl();
320 - });
321 - $j('#'+target_id+" input[value='advanced_editor']").attr({
322 - 'checked':( this_seq.timeline_mode=='time' )?true:false
323 - }).click(function(){
324 - this_seq.doAdvancedTl();
325 - });
326 - //set up the options for context menus
327 - break;
328 - }
329 - },
330 - //renders out the transitions effects set
331 - renderTransitionsSet:function(target_id){
332 - js_log('f:renderTransitionsSet:' + target_id);
333 - var o = '';
334 - if(typeof mvTransLib == 'undefined')
335 - return js_log('Error: missing mvTransLib');
336 -
337 - for(var i in mvTransLib['type']){
338 - js_log('on tran type: ' + i);
339 - var base_trans_name = i;
340 - var tLibSet = mvTransLib['type'][ i ];
341 - for(var j in tLibSet){
342 - trans_name=base_trans_name+'_'+j;
343 - js_log('tname: ' + trans_name);
344 - o+='<img style="float:left;padding:10px;" '+
345 - 'src="'+mv_embed_path +'/skins/'+mv_skin_name+'/transition_images/'+ trans_name + '.png">';
346 - }
347 - }
348 - js_log('should set: ' + target_id + ' to: ' + o);
349 - $j('#'+target_id).append(o);
350 - },
351 - renderTimeLine:function(){
352 - //empty out the top level html:
353 - $j('#'+this.timeline_id).html('');
354 - //add html general for timeline
355 - if( this.timeline_mode=='time'){
356 - $j('#'+this.timeline_id).html(''+
357 - '<div id="'+this.timeline_id+'_left_cnt" class="mv_tl_left_cnt">'+
358 - '<div id="'+this.timeline_id+'_head_control" style="position:absolute;top:0px;left:0px;right:0px;height:30px;">' +
359 - '<a title="'+getMsg('play_clip')+'" href="javascript:'+this.instance_name+'.play_jt()">'+
360 - '<img style="width:16px;height:16px;border:0" src="' + mv_embed_path + 'images/control_play_blue.png">'+
361 - '</a>'+
362 - '<a title="'+getMsg('zoom_in')+'" href="javascript:'+this.instance_name+'.zoom_in()">'+
363 - '<img style="width:16px;height:16px;border:0" src="' + mv_embed_path + 'images/zoom_in.png">'+
364 - '</a>'+
365 - '<a title="'+getMsg('zoom_out')+'" href="javascript:'+this.instance_name+'.zoom_out()">'+
366 - '<img style="width:16px;height:16px;border:0" src="' + mv_embed_path + 'images/zoom_out.png">'+
367 - '</a>'+
368 - '<a title="'+getMsg('cut_clip')+'" href="javascript:'+this.instance_name+'.cut_mode()">'+
369 - '<img style="width:16px;height:16px;border:0" src="' + mv_embed_path + 'images/cut.png">'+
370 - '</a>'+
371 - '</div>' +
372 - '</div>' +
373 - '<div id="'+this.timeline_id+'_tracks" class="mv_seq_tracks">' +
374 - '<div id="'+this.timeline_id+'_head_jump" class="mv_head_jump" style="position:absolute;top:0px;left:0px;height:20px;"></div>'+
375 - '<div id="'+this.timeline_id+'_playline" class="mv_playline"></div>'+
376 - '</div>'
377 - );
378 - //add playlist hook to update timeline
379 - this.plObj.update_tl_hook = this.instance_name+'.update_tl_hook';
380 - var this_sq = this;
381 - var top_pos=25;
382 - //add tracks:
383 - for(var i in this.plObj.tracks){
384 - var track = this.plObj.tracks[i];
385 - //js_log("on track: "+ i + ' t:'+ $j('#'+this.timeline_id+'_left_cnt').html() );
386 - //set up track based on disp type
387 - switch(track.disp_mode){
388 - case 'timeline_thumb':
389 - var track_height=60;
390 - var exc_img = 'opened';
391 - var exc_action='close';
392 - var exc_msg = getMsg('colapse_track');
393 - break;
394 - case 'text':
395 - var track_height=20;
396 - var exc_img = 'closed';
397 - var exc_action='open';
398 - var exc_msg = getMsg('expand_track');
399 - break;
400 - }
401 - //add track name:
402 - $j('#'+this.timeline_id+'_left_cnt').append(
403 - '<div id="track_cnt_'+i+'" style="top:'+top_pos+'px;height:'+track_height+'px;" class="track_name">'+
404 - '<a id="mv_exc_'+i+'" title="'+exc_msg+'" href="javascript:'+this_sq.instance_name+'.exc_track('+i+',\''+exc_action+'\')">'+
405 - '<img id="'+this_sq.timeline_id+'_close_expand" style="width:16px;height:16px;border:0" '+
406 - ' src="'+mv_embed_path + 'images/'+exc_img+'.png">'+
407 - '</a>'+
408 - track.title+'</div>'
409 - );
410 - //also render the clips in the trackset container: (thumb or text view)
411 - $j('#'+this.timeline_id+'_tracks').append(
412 - '<div id="container_track_'+i+'" style="top:'+top_pos+'px;height:'+(track_height+2)+'px;left:0px;right:0px;" class="container_track" />'
413 - );
414 - top_pos+=track_height+20;
415 - }
416 - }
417 - if( this.timeline_mode=='clip'){
418 - var top_pos=this.plObj.org_control_height;
419 - //debugger;
420 - for(var i in this.plObj.tracks){
421 - var track_height=this.track_clipThumb_height;
422 - var timeline_id = this.timeline_id
423 - //add in play box and container tracks
424 - $j('#'+timeline_id).append(''+
425 - '<div id="interface_container_track_' + i + '" ' +
426 - ' style="position:absolute;top:25px;height:'+(track_height+30)+'px;left:10px;right:0px;"' +
427 - '>'+
428 - '<div id="container_track_'+i+'" style="position:relative;top:0px;' +
429 - 'height:'+(track_height+30)+'px;left:0px;right:0px;" class="container_track">' +
430 - '</div>'+
431 - '<div id="' + timeline_id + '_playline" class="mv_story_playline">' +
432 - '<div class="mv_playline_top"/>'+
433 - '</div>'+
434 - '</div>'
435 - );
436 - top_pos+=track_height+20;
437 - }
438 - }
439 - },
440 - //once playlist is ready continue
441 - checkReadyPlObj:function(){
442 - this.plObj = $j('#'+ this.plObj_id ).get(0);
443 - if( this.plObj )
444 - if( ! this.plObj.loading )
445 - this.plReadyInit();
446 -
447 - //else keep checking for the playlist to be ready
448 - if( this.plObj.loading ){
449 - if(this.plReadyTimeout==200){
450 - js_error('error playlist never ready');
451 - }else{
452 - this.plReadyTimeout++;
453 - setTimeout(this.instance_name +'.checkReadyPlObj()', 25);
454 - }
455 - }
456 - },
457 - plReadyInit:function(){
458 - var this_seq = this;
459 - js_log('plReadyInit');
460 - js_log( this.plObj );
461 - //give the playlist a pointer to its parent seq:
462 - this.plObj['seqObj'] = this;
463 -
464 - //update playlist (since if its empty right now)
465 - if(this.plObj.getClipCount()==0){
466 - $j('#'+this.plObj_id).html('empty playlist');
467 - }
468 -
469 - //propogate the edit tokens
470 - //if on an edit page just grab from the form:
471 - this.sequenceEditToken = $j('input[@wpEditToken]').val();
472 - if(typeof this.sequenceEditToken == 'undefined'){
473 - //(calling the sequencer inline) try and get edit token via api call:
474 - //(somewhat fragile way to get at the api... should move to config
475 - var token_url =this.plObj.interface_url.replace(/index\.php/, 'api.php');
476 - token_url += '?action=query&format=xml&prop=info&intoken=edit&titles=';
477 - $j.ajax({
478 - type: "GET",
479 - url: token_url + this_seq.plObj.mTitle,
480 - success:function(data){
481 - var pageElm = data.getElementsByTagName('page')[0];
482 - if( $j(pageElm).attr('edittoken') ){
483 - this_seq.sequenceEditToken = $j(pageElm).attr('edittoken');
484 - }
485 - this_seq.updateSeqSaveButtons();
486 - }
487 - });
488 - //also grab permmisions for sending clipboard commands to the server
489 - $j.ajax({
490 - type:"GET",
491 - url: token_url + this_seq.plObj.mTalk,
492 - success:function(data){
493 - var pageElm = data.getElementsByTagName('page')[0];
494 - if( $j(pageElm).attr('edittoken') ){
495 - this_seq.clipboardEditToken = $j(pageElm).attr('edittoken');
496 - }
497 - }
498 - });
499 - }
500 -
501 -
502 - //render the menu:
503 - var menu_html = '<ul id="seq_menu">';
504 - var item_containers ='';
505 -
506 - //@@todo ~maybe~ load menu via ajax request
507 - //(avoid so much hmtl in js? or keep in js to keep high protabillity of sequencer? )
508 -
509 - $j.each(this.menu_items, function(inx, menu_item){
510 - var disp_style = (menu_item.d)?'inline':'none';
511 - var sel_class = (menu_item.d)?'class="mv_selected_item"':'';
512 - menu_html+='<li '+sel_class+' id="mv_menu_item_'+inx+'">' + getMsg('menu_' + inx ) +'</li>';
513 - item_containers += '<div class="seq_control_container" id="' + inx +
514 - '_ic" style="display:' + disp_style +';">'
515 - //add in subMenus if set
516 - //check for submenu and add to item container
517 - var sub_menu_html='';
518 - if( typeof menu_item.submenu != 'undefined'){
519 - sub_menu_html+= '<ul id="mv_submenu_' + inx +'" class="mv_submenu">';
520 - $j.each(menu_item.submenu, function(subInx, sub_menu_item){
521 - var disp_style = (menu_item.d)?'block':'none';
522 - var sub_sel_class = (sub_menu_item==1)?'class="mv_sub_selected"':'';
523 - sub_menu_html+= '<li ' + sub_sel_class + ' id="mv_sub_menu_item_' + subInx + '">' +
524 - getMsg('sc_' + subInx ) + '</li>';
525 - item_containers+= '<div class="submenu_container" id="sc_' + subInx+'" '+
526 - ' style="display:' + disp_style +';"></div>';
527 - });
528 - sub_menu_html+= '</ul>';
529 - }
530 - item_containers+= sub_menu_html + '</div>';
531 - });
532 - menu_html+='</ul>';
533 -
534 - $j('#'+this.sequence_tools_id).html( menu_html + item_containers );
535 - //add binding for menu
536 - $j('#seq_menu li').click(function(){
537 - $j('#seq_menu li').removeClass('mv_selected_item');
538 - $j(this).addClass('mv_selected_item');
539 - this_seq.disp( $j(this).attr('id').replace('mv_menu_item_','') );
540 - });
541 -
542 - //load init content into containers
543 - this.loadInitMenuItems();
544 -
545 - //render the timeline
546 - this.renderTimeLine();
547 - this.do_refresh_timeline();
548 -
549 - var this_seq = this;
550 - //set up key bidnings
551 - $j().keydown(function(e){
552 - js_log('pushed down on:' + e.which);
553 - if( e.which == 16 )
554 - this_seq.key_shift_down = true;
555 -
556 - if( e.which == 17)
557 - this_seq.key_ctrl_down = true;
558 -
559 - if( e.which == 67 && this_seq.key_ctrl_down)
560 - this_seq.copySelectedClips();
561 -
562 - if( e.which == 88 && this_seq.key_ctrl_down)
563 - this_seq.cutSelectedClips();
564 -
565 - if( e.which == 86 && this_seq.key_ctrl_down)
566 - this_seq.pasteClipBoardClips();
567 -
568 - });
569 - $j().keyup(function(e){
570 - js_log('key up on ' + e.which);
571 - //user let go of "shift" turn off multi-select
572 - if( e.which == 16 )
573 - this_seq.key_shift_down = false;
574 -
575 - if( e.which == 17)
576 - this_seq.key_ctrl_down = false;
577 -
578 - //backspace or delete key:
579 - if( e.which == 8 || e.which == 46 ){
580 - this_seq.removeSelectedClips();
581 - }
582 - });
583 - },
584 - update_tl_hook:function(jh_time_ms){
585 - //put into seconds scale:
586 - var jh_time_sec_float = jh_time_ms/1000;
587 - //render playline at given time
588 - //js_log('tl scale: '+this.timeline_scale);
589 - $j('#'+this.timeline_id+'_playline').css('left', Math.round(jh_time_sec_float/this.timeline_scale)+'px' );
590 - //js_log('at time:'+ jh_time_sec + ' px:'+ Math.round(jh_time_sec_float/this.timeline_scale));
591 - },
592 - /*returns a xml or json representation of the current sequence */
593 - getSeqOutputJSON:function(){
594 - js_log('json output');
595 - },
596 - getSeqOutputHLRDXML:function(){
597 - var o='<sequence_hlrd>' +"\n";
598 - o+="\t<head>";
599 - //get transitions
600 - for(var i in this.plObj.transitions){
601 - var tObj = this.plObj.transitions[i].getAttributeObj();
602 - o+="\t<transition ";
603 - for(var j in tObj){
604 - o+=' '+j+'="' + tObj[j] + '"\n\t\t';
605 - }
606 - o+='/>'+"\n"; //transitions don't have children
607 - }
608 - o+="\t</head>\n";
609 -
610 - //get clips
611 - o+="\t<body>\n";
612 - //output each track:
613 - for(var i in this.plObj.tracks){
614 - var curTrack = this.plObj.tracks[i];
615 - o+="\t<seq";
616 - var tAttr = curTrack.getAttributeObj();
617 - for(var j in tAttr){
618 - o+=' '+j+'="' + tAttr[j] + '"\n\t\t\t';
619 - }
620 - o+=">\n";
621 - for( var k in curTrack.clips ){
622 - var curClip = curTrack.clips[k];
623 - o+="\t\t<ref ";
624 - var cAttr = curClip.getAttributeObj();
625 - for(var j in cAttr){
626 - var val = (j=='transIn' || j=='transOut') ? cAttr[j].id : cAttr[j];
627 - o+=' '+j+'="' + val + '"\n\t\t\t';
628 - }
629 - o+="/>\n" //close the clip
630 - }
631 - o+="\n</seq>n";
632 - }
633 - o+="\t</body>\n";
634 - //close the tag
635 - o+='</sequence_hlrd>';
636 -
637 - alert('f:getSeqOutputHLRDXML'+ o);
638 -
639 - return false;
640 - },
641 - //@@todo integrate into clip view ...
642 - editClip:function(track_inx, clip_inx){
643 - $j('#modalbox').hide();
644 - if($j('#modal_window').length==0){
645 - $j('body').append('<div id="modal_window" class="modal_editor" />');
646 - }
647 - //empty out the modal_window and show it
648 - $j('#modal_window').empty().show();
649 - //set to the current clip in "clip mode"
650 - var clip = this.plObj.tracks[track_inx].clips[ clip_inx ];
651 - //@@todo do per clip type edit modes:
652 - $j('#modal_window').append('<div style="position:absolute;top:10px;left:25%;width:'+this.plObj.width+'px;">'+
653 - '<h3>' + clip.getTitle() + '</h3>'+
654 - '<video id="chop_clip_' + track_inx + '_' + clip_inx + '" ' +
655 - 'style="width:'+this.plObj.width+'px;height:'+this.plObj.height+'px;" '+
656 - 'poster="'+clip.embed.media_element.getThumbnailURL()+'" ' +
657 - 'src="' + clip.src + '"></video>'+
658 - '<div style="padding-top:10px;">'+
659 - '<span style="position:absolute;left:0px;">'+
660 - 'start time:<input id="chop_start" type="text" size="10" value="0:0:0">'+
661 - '</span>'+
662 - '<span style="position:absolute;right:0px;">'+
663 - 'end time:<input id="chop_end" type="text" size="10" '+
664 - 'value="' + seconds2ntp(clip.getDuration()) + '" >' +
665 - '</span>'+
666 - '</div>'+
667 - '</div>'
668 - //start time end time field display
669 - );
670 - $j('#modal_window').append('<div style="position:absolute;bottom:10px;left:50%;">'+
671 - '<a style="border:solid gray;font-size:1.2em;" onClick="window.confirm(\''+getMsg('edit_cancel_confirm')+'\')" '+
672 - 'href="javascript:'+this.instance_name+'.closeModWindow()">'+
673 - getMsg('edit_cancel') + '</a> '+
674 - '<a style="border:solid gray;font-size:1.2em;" href="javascript:'+this.instance_name+'.saveClipEdit()">'+
675 - getMsg('edit_save')+
676 - '</a>'+
677 - '</div>'
678 - );
679 - rewrite_by_id('chop_clip_' + track_inx + '_' + clip_inx );
680 - //@@todo add in-out setters
681 -
682 - //@@todo add start / end hooks
683 -
684 - },
685 - //save new clip segment
686 - saveClipEdit:function(){
687 - //saves the clip updates
688 - },
689 - closeModEditor:function(){
690 - $j('#modalbox,#mv_overlay').remove();
691 - },
692 - closeModWindow:function(){
693 - $j('#modal_window').hide();
694 - $j('#modalbox').show();
695 - },
696 - pasteClipBoardClips:function(){
697 - js_log('f:pasteClipBoardClips');
698 - //@@todo query the server for updated clipboard
699 - //paste before the "current clip"
700 - this.addClips(this.clipboard, this.plObj.cur_clip.order );
701 - },
702 - copySelectedClips:function(){
703 - var this_seq = this;
704 - //set all the selected clips
705 - this.clipboard = new Array();
706 - $j('.mv_selected_clip').each(function(){
707 - //add each clip to the clip board:
708 - var cur_clip = this_seq.getClipFromSeqID( $j(this).parent().attr('id') );
709 - this_seq.clipboard.push( cur_clip.getAttributeObj() );
710 - });
711 - //upload clipboard to the server (if possible)
712 - if( parseUri( document.URL ).host != parseUri( this_seq.plObj.interface_url ).host ){
713 - js_log('error: presently we can\'t copy clips across domains');
714 - }else{
715 - var req_url = this_seq.plObj.interface_url + '?action=ajax&rs=mv_seqtool_clipboard&rsargs[]=copy';
716 - $j.ajax({
717 - type: "POST",
718 - url:req_url,
719 - data: $j.param( {
720 - "clipboard_data": $j.toJSON( this_seq.clipboard ),
721 - "clipboardEditToken": this_seq.clipboardEditToken
722 - }),
723 - success:function(data){
724 - //callback( data );
725 - js_log('did clipboard push ' + $j.toJSON( this_seq.clipboard ) );
726 - }
727 - });
728 - }
729 - },
730 - cutSelectedClips:function(){
731 - this.copySelectedClips();
732 - this.removeSelectedClips();
733 - },
734 - removeSelectedClips:function(){
735 - var remove_clip_ary=new Array();
736 - //remove selected clips from display
737 - $j('.container_track .mv_selected_clip').each(function(){
738 - //grab the track index from the id (assumes track_#_clip_#
739 - remove_clip_ary.push ( $j(this).parent().attr('id').replace('track_','').replace('clip_','').split('_') );
740 - });
741 - this.removeClips(remove_clip_ary);
742 - },
743 - //add a single or set of clips
744 - //to a given position and track_inx
745 - addClips:function( clipSet, before_clip_pos, track_inx){
746 - this_seq = this;
747 - js_log("seq: add clip: at: "+ before_clip_pos + ' in track: ' + track_inx);
748 - var cur_pos = before_clip_pos;
749 - js_log('paste clip before_clip_pos: ' + before_clip_pos);
750 - var smilXML =
751 - $j.each(clipSet, function(inx, clipInitDom){
752 - var mediaElement = document.createElement('ref');
753 - for(var i in clipInitDom){
754 - if(i!='id')
755 - $j(mediaElement).attr(i, clipInitDom[i]);
756 - }
757 - if( this_seq.plObj.tryAddMedia( mediaElement, cur_pos, track_inx ) )
758 - cur_pos++;
759 - });
760 - //debugger;
761 - this.do_refresh_timeline();
762 - },
763 - removeClips:function( remove_clip_ary ){
764 - var this_seq = this;
765 - var jselect = coma ='';
766 - js_log('clip count before removal : ' + this_seq.plObj.default_track.clips.length + ' should remove ' + remove_clip_ary.length );
767 - var afected_tracks = new Array();
768 - //add order to track_clip before we start removing:
769 - $j.each( remove_clip_ary, function(inx, track_clip){
770 - remove_clip_ary[inx]['order'] = this_seq.plObj.tracks[ track_clip[0] ].clips[ track_clip[1] ].order;
771 - });
772 - $j.each( remove_clip_ary, function(inx, track_clip){
773 - var track_inx = track_clip[0];
774 - var clip_inx = track_clip[1];
775 - var clip_rm_order = track_clip['order'];
776 - js_log('remove t:' + track_inx + ' c:'+ clip_inx + ' id:' +' #track_'+track_inx+'_clip_'+clip_inx + ' order:' + clip_rm_order);
777 - //remove the clips from the base tracks
778 - for(var i in this_seq.plObj.tracks[ track_inx ].clips){
779 - cur_clip = this_seq.plObj.tracks[ track_inx ].clips[i]
780 - if(cur_clip.order == clip_rm_order){
781 - this_seq.plObj.tracks[ track_clip[0] ].clips.splice( i, 1);
782 - }
783 - }
784 - //add track to affected track list:
785 - afected_tracks[ track_inx ]=true;
786 - jselect += coma + '#track_' +track_inx + '_clip_' + clip_inx;
787 - coma=',';
788 - });
789 - //update/ reorder:
790 - $j.each(afected_tracks, function(track_inx, affected){
791 - this_seq.plObj.tracks[track_inx].reOrderClips();
792 - });
793 -
794 - js_log('clip count after removal : ' + this_seq.plObj.default_track.clips.length);
795 - //animate the removal (@@todo should be able to call the resulting fadeOut only once without a flag)
796 - var done_with_refresh=false;
797 - $j(jselect).fadeOut("slow", function(){
798 - if( !done_with_refresh )
799 - this_seq.do_refresh_timeline();
800 - done_with_refresh=true;
801 - }).empty(); //empty to remove any persistent bindings
802 - },
803 - doEdit:function( editObj ){
804 - //add the current editObj to the edit stack (should allow for "undo")
805 - this.edit_stack.push( editObj );
806 - //make the adjustments
807 - this.makeAdjustment( editObj );
808 - },
809 - /*
810 - * takes adjust ment object with options:
811 - * track_inx, clip_inx, start, end delta
812 - */
813 - makeAdjustment:function(e){
814 - switch(e.type){
815 - case 'resize_start':
816 - this.plObj.tracks[e.track_inx].clips[e.clip_inx].doAdjust('start', e.delta);
817 - break;
818 - case 'resize_end':
819 - this.plObj.tracks[e.track_inx].clips[e.clip_inx].doAdjust('end', e.delta);
820 - break;
821 - }
822 - js_log('re render: '+e.track_inx);
823 - //refresh the playlist after adjustment
824 - this.do_refresh_timeline();
825 - },
826 - //@@todo set up key bindings for undo
827 - undoEdit:function(){
828 - var editObj = this.edit_stack.pop();
829 - //invert the delta
830 -
831 - },
832 - exc_track:function(inx,req){
833 - this_seq = this;
834 - if(req=='close'){
835 - $j('#mv_exc_'+inx).attr('href', 'javascript:'+this.instance_name+'.exc_track('+inx+',\'open\')');
836 - $j('#mv_exc_'+inx + ' > img').attr('src',mv_embed_path + 'images/closed.png');
837 - $j('#track_cnt_'+inx+',#container_track_'+inx).animate({height:this.track_text_height}, "slow",'',
838 - function(){
839 - this_seq.plObj.tracks[inx].disp_mode='text';
840 - this_seq.render_tracks( inx );
841 - });
842 - }else if(req=='open'){
843 - $j('#mv_exc_'+inx).attr('href', 'javascript:'+this.instance_name+'.exc_track('+inx+',\'close\')');
844 - $j('#mv_exc_'+inx + ' > img').attr('src',mv_embed_path + 'images/opened.png');
845 - $j('#track_cnt_'+inx+',#container_track_'+inx).animate({height:this.track_thumb_height}, "slow",'',
846 - function(){
847 - this_seq.plObj.tracks[inx].disp_mode='timeline_thumb';
848 - this_seq.render_tracks(inx);
849 - });
850 -
851 - }
852 - },
853 - //adds tracks
854 - add_track:function(inx, track){
855 -
856 - },
857 - //toggle cut mode (change icon to cut)
858 - cut_mode:function(){
859 - js_log('do cut mode');
860 - //add cut layer ontop of clips
861 - },
862 - doAdvancedTl:function(){
863 - this.timeline_mode='time';
864 - this.renderTimeLine();
865 - this.do_refresh_timeline();
866 - return false;
867 - },
868 - doSimpleTl:function(){
869 - this.timeline_mode='clip';
870 - this.renderTimeLine();
871 - this.do_refresh_timeline();
872 - return false;
873 - },
874 - //renders updates the timeline based on the current scale
875 - render_tracks:function( track_inx ){
876 - js_log("f::render track: "+track_inx);
877 - var this_seq = this;
878 - //inject the tracks into the timeline (if not already there)
879 - for(var track_id in this.plObj.tracks){
880 - if( track_inx==track_id || typeof track_inx=='undefined' ){
881 - //empty out the track container:
882 - //$j('#container_track_'+track_id).empty();
883 - var track_html=droppable_html='';
884 - //set up per track vars:
885 - var track = this.plObj.tracks[track_id];
886 - var cur_clip_time=0;
887 -
888 - //set up some constants for timeline_mode == clip:
889 - if(this.timeline_mode == 'clip'){
890 - var frame_width = Math.round(this.track_clipThumb_height*1.3333333);
891 - var container_width = frame_width+60;
892 - }
893 -
894 - //for each clip:
895 - for(var j in track.clips){
896 - clip = track.clips[j];
897 - //var img = clip.getClipImg('icon');
898 - if(this.timeline_mode == 'clip'){
899 - clip.left_px = j*container_width;
900 - clip.width_px = container_width;
901 - var base_id = 'track_'+track_id+'_clip_'+j;
902 - track_html+='<span id="'+base_id+'" '+
903 - 'class="mv_storyboard_container mv_clip_drag" '+
904 - 'style="'+
905 - 'left:'+clip.left_px+'px;'+
906 - 'height:' + (this.track_clipThumb_height+30) + 'px;' +
907 - 'width:'+(container_width)+'px;" >';
908 - track_html+=clip.embed.renderTimelineThumbnail({
909 - 'width':frame_width,
910 - 'thumb_class':'mv_clip_thumb',
911 - 'height':this.track_clipThumb_height,
912 - 'time':0
913 - });
914 - //render out edit button
915 - track_html+='<div onClick="'+this.instance_name+'.editClip('+track_id+','+j+')" class="clip_edit_button clip_edit_base"/>';
916 -
917 - //render out transition edit box
918 - track_html+='<div style="" id="tb_' + base_id + '" class="clip_trans_box"/>';
919 -
920 - //render out adjustment text
921 - track_html+='<div id="' + base_id + '_adj' + '" class="mv_adj_text" style="top:'+ (this.track_clipThumb_height+10 )+'px;">'+
922 - '<span class="mv_adjust_click" onClick="'+this.instance_name+'.adjClipDur(' + track_id + ',' + j + ',\'-\')" /> - </span>'+
923 - ( (clip.getDuration() > 60 )? seconds2ntp(clip.getDuration()): clip.getDuration() ) +
924 - '<span class="mv_adjust_click" onClick="'+this.instance_name+'.adjClipDur(' + track_id + ',' + j + ',\'+\')" /> + </span>'+
925 - '</div>';
926 - track_html+='</span>';
927 -
928 - }
929 - //do per display type rendering:
930 - if(this.timeline_mode == 'time'){
931 - clip.left_px = Math.round( cur_clip_time/this.timeline_scale);
932 - clip.width_px = Math.round( Math.round( clip.getDuration() )/this.timeline_scale);
933 - js_log('at time:' + cur_clip_time + ' left: ' +clip.left_px + ' clip dur: ' + Math.round( clip.getDuration() ) + ' clip width:' + clip.width_px);
934 -
935 - //for every clip_width pixle output image
936 - if(track.disp_mode=='timeline_thumb'){
937 - track_html+='<span id="track_'+track_id+'_clip_'+j+'" '+
938 - 'class="mv_tl_clip mv_clip_drag" '+
939 - 'style="'+
940 - 'left:' + clip.left_px + 'px;'+
941 - 'width:'+ clip.width_px + 'px;'+
942 - 'height:'+ clip.height_px + 'px" >';
943 - track_html+= this.render_clip_frames( clip );
944 - }else if(track.disp_mode=='text'){
945 - //'+left_px+
946 - track_html+='<span id="track_'+track_id+'_clip_'+j+'" style="left:'+clip.left_px+'px;'+
947 - 'width:'+clip.width_px+'px;background:'+clip.getColor()+
948 - '" class="mv_time_clip_text mv_clip_drag">'+clip.title;
949 - }
950 - //add in per clip controls
951 - track_html+='<div title="'+getMsg('clip_in')+' '+clip.embed.start_ntp+'" class="ui-resizable-w ui-resizable-handle" style="width: 16px; height: 16px; left: 0px; top: 2px;background:url(\''+mv_embed_path+'images/application_side_contract.png\');" ></div>'+"\n";
952 - track_html+='<div title="'+getMsg('clip_out')+' '+clip.embed.end_ntp+'" class="ui-resizable-e ui-resizable-handle" style="width: 16px; height: 16px; right: 0px; top: 2px;background:url(\''+mv_embed_path+'images/application_side_expand.png\');" ></div>'+"\n";
953 - track_html+='<div title="'+getMsg('rmclip')+'" onClick="'+this.instance_name + '.removeClips(new Array([' + track_id + ',' + j + ']))" style="position:absolute;cursor:pointer;width: 16px; height: 16px; left: 0px; bottom:2px;background:url(\''+mv_embed_path+'images/delete.png\');"></div>'+"\n";
954 - track_html+='<span style="display:none;" class="mv_clip_stats"></span>';
955 -
956 - track_html+='</span>';
957 - //droppable_html+='<div id="dropBefore_'+i+'_c_'+j+'" class="mv_droppable" style="height:'+this.track_thumb_height+'px;left:'+clip.left_px+'px;width:'+Math.round(clip.width_px/2)+'px"></div>';
958 - //droppable_html+='<div id="dropAfter_'+i+'_c_'+j+'" class="mv_droppable" style="height:'+this.track_thumb_height+'px;left:'+(clip.left_px+Math.round(clip.width_px/2))+'px;width:'+(clip.width_px/2)+'px"></div>';
959 - cur_clip_time+=Math.round( clip.getDuration() ); //increment cur_clip_time
960 - }
961 -
962 - }
963 -
964 - //js_log("new htmL for track i: "+track_id + ' html:'+track_html);
965 - $j('#container_track_'+track_id).html( track_html );
966 -
967 -
968 - //apply edit button mouse over effect:
969 - $j('.clip_edit_button').hover(function(){
970 - $j(this).removeClass("clip_edit_base").addClass("clip_edit_over");
971 - },function(){
972 - $j(this).removeClass("clip_edit_over").addClass("clip_edit_base");
973 - });
974 -
975 -
976 -
977 - //apply onClick edit controls:
978 - $j('.mv_clip_thumb').click(function(){
979 - var cur_clip_click = this;
980 - //if not in multi select mode remove all existing selections
981 - //(except for the current click which is handled down below)
982 - js_log(' ks: ' + this_seq.key_shift_down + ' ctrl_down:' +this_seq.key_ctrl_down);
983 - if( ! this_seq.key_shift_down && ! this_seq.key_ctrl_down){
984 - $j('.mv_selected_clip').each(function(inx, selected_clip){
985 - if( $j(this).parent().attr('id') != $j(cur_clip_click).parent().attr('id')
986 - || ( $j('.mv_selected_clip').length > 1 ) ){
987 - $j(this).removeClass("mv_selected_clip");
988 - $j('#' + $j(this).parent().attr("id") + '_adj').fadeOut("fast");
989 - }
990 - });
991 - }
992 -
993 - //jump to clip time
994 - var sClipObj = this_seq.getClipFromSeqID( $j(this).parent().attr('id') );
995 - this_seq.plObj.updateCurrentClip( sClipObj );
996 - if( $j(this).hasClass("mv_selected_clip") ){
997 - $j(this).removeClass("mv_selected_clip");
998 - $j('#' + $j(this).parent().attr("id") + '_adj').fadeOut("fast");
999 - }else{
1000 - $j(this).addClass('mv_selected_clip');
1001 - $j('#' + $j(this).parent().attr("id") + '_adj').fadeIn("fast");
1002 - }
1003 - //if shift select is down select the in-between clips
1004 - if( this_seq.key_shift_down ){
1005 - //get the min max of current selection (within the current track)
1006 - var max_order = 0;
1007 - var min_order = 999999999999999;
1008 - $j('.mv_selected_clip').each(function(){
1009 - var cur_clip = this_seq.getClipFromSeqID( $j(this).parent().attr('id') );
1010 - //get min max
1011 - if(cur_clip.order < min_order)
1012 - min_order = cur_clip.order;
1013 - if(cur_clip.order > max_order)
1014 - max_order = cur_clip.order;
1015 - });
1016 - //select all non-selected between max or min
1017 - js_log('sOrder: ' + sClipObj.order + ' min:' + min_order + ' max:'+ max_order);
1018 - if( sClipObj.order <= min_order ){
1019 - for( var i = sClipObj.order; i <= max_order; i++ ){
1020 - $j('#track_' + track_id + '_clip_' + i + ' > .mv_clip_thumb' ).addClass('mv_selected_clip');
1021 - }
1022 - }
1023 - if( sClipObj.order >= max_order ){
1024 - for( var i =min_order; i <= max_order; i++ ){
1025 - $j('#track_' + track_id + '_clip_' + i + ' > .mv_clip_thumb' ).addClass('mv_selected_clip');
1026 - }
1027 - }
1028 - }
1029 -
1030 - });
1031 - //add in control for time based display
1032 - //debugger;
1033 - if(this.timeline_mode == 'time'){
1034 - $j('.ui-resizable-handle').mousedown( function(){
1035 - js_log('hid: ' + $j(this).attr('class'));
1036 - this_seq.resize_mode = ($j(this).attr('class').indexOf('ui-resizable-e')!=-1)?
1037 - 'resize_end':'resize_start';
1038 - });
1039 - }
1040 - var insert_key='na';
1041 - // drag hooks:
1042 - //@@todo support multiple clips
1043 - for(var j in track.clips){
1044 - $j('#track_'+track_id+'_clip_'+j).draggable({
1045 - axis:'x',
1046 - containment:'#container_track_'+track_id,
1047 - opacity:50,
1048 - handle: ":not(.clip_control)",
1049 - scroll:true,
1050 - drag:function(e, ui){
1051 - //animate re-arrange by left position:
1052 - //js_log('left: '+ui.position.left);
1053 - //locate clip (based on clip duration not animate)
1054 - var id_parts = this.id.split('_');
1055 - var track_inx = id_parts[1];
1056 - var clip_inx = id_parts[3];
1057 - var clips = this_seq.plObj.tracks[track_inx].clips;
1058 - var cur_drag_clip = clips[clip_inx];
1059 - var return_org = true;
1060 - $j(this).css('zindex',10);
1061 - //find out where we are inserting and set left border to solid red thick
1062 - for(var k in clips){
1063 - if( ui.position.left > clips[k].left_px &&
1064 - ui.position.left < (clips[k].left_px + clips[k].width_px)){
1065 - if(clip_inx!=k){
1066 - //also make sure we are not where we started
1067 - if(k-1!=clip_inx){
1068 - $j('#track_'+track_inx+'_clip_'+k).css('border-left', 'solid thick red');
1069 - insert_key=k;
1070 - }else{
1071 - insert_key='na';
1072 - }
1073 - }else{
1074 - insert_key='na';
1075 - }
1076 - }else{
1077 - $j('#track_'+track_inx+'_clip_'+k).css('border-left', 'solid thin white');
1078 - }
1079 - }
1080 - //if greater than the last k insert after
1081 - if(ui.position.left > (clips[k].left_px + clips[k].width_px) &&
1082 - k!=clip_inx ){
1083 - $j('#track_'+track_inx+'_clip_'+k).css('border-right', 'solid thick red');
1084 - insert_key='end';
1085 - }else{
1086 - $j('#track_'+track_inx+'_clip_'+k).css('border-right', 'solid thin white');
1087 - }
1088 - },
1089 - start:function(e,ui){
1090 - js_log('start drag:' + this.id);
1091 - //make sure we are ontop
1092 - $j(this).css({top:'0px',zindex:10});
1093 - },
1094 - stop:function(e, ui){
1095 - $j(this).css({top:'0px',zindex:0});
1096 -
1097 - var id_parts = this.id.split('_');
1098 - var track_inx = id_parts[1];
1099 - var clip_inx = id_parts[3];
1100 - var clips = this_seq.plObj.tracks[track_inx].clips;
1101 - var cur_drag_clip = clips[clip_inx];
1102 -
1103 - if(insert_key!='na' && insert_key!='end' ){
1104 - cur_drag_clip.order=insert_key-.5;
1105 - }else if (insert_key=='end'){
1106 - cur_drag_clip.order=clips.length;
1107 - }
1108 - //reorder array based on new order
1109 - clips.sort(sort_func);
1110 - function sort_func(a, b){
1111 - return a.order - b.order;
1112 - }
1113 - //assign keys back to order:
1114 - this_seq.plObj.tracks[track_inx].reOrderClips();
1115 - //redraw:
1116 - this_seq.do_refresh_timeline();
1117 - }
1118 - });
1119 - //add in resize hook if in time mode:
1120 - if(this.timeline_mode == 'time'){
1121 - $j('#track_'+track_id+'_clip_'+j).resizable({
1122 - minWidth:10,
1123 - maxWidth:6000,
1124 - start: function(e,ui) {
1125 - //set border to red
1126 - $j(this).css({'border':'solid thin red'});
1127 - //fade In Time stats (end or start based on handle)
1128 - //dragging east (adjusting end time)
1129 - js_log( 'append to: '+ this.id);
1130 - $j('#' + this.id + ' > .mv_clip_stats').fadeIn("fast");
1131 - },
1132 - stop: function(e,ui) {
1133 - js_log('stop resize');
1134 - //restore border
1135 - $j(this).css('border', 'solid thin white');
1136 - //remove stats
1137 - var clip_drag = this;
1138 - $j('#'+this.id+' > .mv_clip_stats').fadeOut("fast",function(){
1139 - var id_parts = clip_drag.id.split('_');
1140 - var track_inx = id_parts[1];
1141 - var clip_inx = id_parts[3];
1142 - //update clip
1143 - this_seq.doEdit({
1144 - type:this_seq.resize_mode,
1145 - delta:this_seq.edit_delta,
1146 - track_inx:track_inx,
1147 - clip_inx:clip_inx})
1148 - });
1149 - },
1150 - resize: function(e,ui) {
1151 - //update time stats & render images:
1152 - this_seq.update_clip_resize(this);
1153 - }
1154 - });
1155 - }
1156 - }
1157 - $j('#container_track_'+track_id).width(Math.round( this.timeline_duration / this.timeline_scale));
1158 - }
1159 - //debugger;
1160 - }
1161 - },
1162 - getClipFromSeqID:function( clip_seq_id ){
1163 - js_log('get id from: ' + clip_seq_id);
1164 - var ct = clip_seq_id.replace('track_','').replace('clip_','').split('_');
1165 - return this.plObj.tracks[ ct[0] ].clips[ ct[1] ];
1166 - },
1167 - //renders clip frames
1168 - render_clip_frames:function(clip, frame_offset_count){
1169 - js_log('f:render_clip_frames: ' + clip.id + ' foc:' + frame_offset_count);
1170 - var clip_frames_html='';
1171 - var frame_width = Math.round(this.track_thumb_height*1.3333333);
1172 -
1173 - var pint = (frame_offset_count==null)?0:frame_offset_count*frame_width;
1174 -
1175 - //js_log("pinit: "+ pint+ ' < '+clip.width_px+' ++'+frame_width);
1176 - for(var p=pint;p<clip.width_px;p+=frame_width){
1177 - var clip_time = (p==0)?0:Math.round(p*this.timeline_scale);
1178 - js_log('rendering clip frames: p:' +p+' '+ (p*this.timeline_scale)+' ' + clip_time);
1179 - clip_frames_html+=clip.embed.renderTimelineThumbnail({
1180 - 'width': frame_width,
1181 - 'thumb_class':'mv_tl_thumb',
1182 - 'height': this.track_thumb_height,
1183 - 'size' : "icon", //set size to "icon" preset
1184 - 'time': clip_time
1185 - });
1186 - }
1187 - js_log('render_clip_frames:'+clip_frames_html);
1188 - return clip_frames_html;
1189 - },
1190 - update_clip_resize:function(clip_element){
1191 - //js_log('update_clip_resize');
1192 - var this_seq = this;
1193 - var id_parts = clip_element.id.split('_');
1194 - track_inx = id_parts[1];
1195 - clip_inx = id_parts[3];
1196 - //set clip:
1197 - var clip = this.plObj.tracks[ track_inx ].clips[ clip_inx ];
1198 - var clip_desc ='';
1199 - //would be nice if getting the width did not flicker the border
1200 - //@@todo do a work around e in resize function has some screen based offset values
1201 - clip.width_px = $j(clip_element).width();
1202 - var width_dif = clip.width_px - Math.round( Math.round( clip.getDuration() )/this.timeline_scale);
1203 - //var left_px = $j(clip_element).css('left');
1204 -
1205 - var new_clip_dur = Math.round( clip.width_px*this.timeline_scale );
1206 - var clip_dif = (new_clip_dur - clip.getDuration() );
1207 - var clip_dif_str = (clip_dif >0)?'+'+clip_dif:clip_dif;
1208 - //set the edit global delta
1209 - this.edit_delta = clip_dif;
1210 -
1211 - //get new length:
1212 - clip_desc+='length: ' + seconds2ntp(new_clip_dur) +'('+clip_dif_str+')';
1213 - if(this_seq.resize_mode=='resize_end'){
1214 - //expanding right
1215 - var new_end = seconds2ntp(ntp2seconds(clip.embed.end_ntp)+clip_dif);
1216 - clip_desc+='<br>end time: ' + new_end;
1217 - //also shift all the other clips (after the current)
1218 - //js_log("track_inx: " + track_inx + ' clip inx:'+clip_inx);
1219 - //$j('#container_track_'+track_inx+' > .mv_clip_drag :gt('+clip_inx+')').each(function(){
1220 - $j('#container_track_'+track_inx+' > :gt('+clip_inx+')').each(function(){
1221 - var move_id_parts = this.id.split('_');
1222 - var move_clip = this_seq.plObj.tracks[move_id_parts[1]].clips[move_id_parts[3]];
1223 - //js_log('should move:'+ this.id);
1224 - $j(this).css('left', move_clip.left_px + width_dif);
1225 - });
1226 - }else{
1227 - //expanding left (resize_start)
1228 - var new_start = seconds2ntp(ntp2seconds(clip.embed.start_ntp)+clip_dif);
1229 - clip_desc+='<br>start time: ' + new_start;
1230 - }
1231 -
1232 - //update clip stats:
1233 - $j('#'+clip_element.id+' > .mv_clip_stats').html(clip_desc);
1234 - var frame_width = Math.round(this.track_thumb_height*1.3333333);
1235 - //check if we need to append some images:
1236 - var frame_count = $j('#'+clip_element.id+' > img').length;
1237 - if(clip.width_px > (frame_count * frame_width) ){
1238 - //if dragging left append
1239 - js_log('width_px:'+clip.width_px+' framecount:'+frame_count+' Xcw='+(frame_count * frame_width));
1240 - $j('#'+clip_element.id).append(this.render_clip_frames(clip, frame_count));
1241 - }
1242 - },
1243 - //renders cnt_time
1244 - render_playheadhead_seeker:function(){
1245 - //render out time stamps and time "jump" links
1246 - //first get total width
1247 - if(this.timeline_mode=='time'){
1248 - //hide the old control if present
1249 - $j('#'+this.timeline_id + '_pl_control').remove();
1250 - //set width based on pixle to time and current length:
1251 - pixle_length = Math.round( this.timeline_duration / this.timeline_scale);
1252 - $j('#'+this.timeline_id+'_head_jump').width(pixle_length);
1253 - //output times every 50pixles
1254 - var out='';
1255 - //output time-desc every 50pixles and jump links every 10 pixles
1256 - var n=0;
1257 - for(i=0;i<pixle_length;i+=10){
1258 - out+='<div onclick="'+this.instance_name+'.jt('+i*this.timeline_scale+');"' +
1259 - ' style="z-index:2;position:absolute;left:'+i+'px;width:10px;height:20px;top:0px;"></div>';
1260 - if(n==0)
1261 - out+='<span style="position:absolute;left:'+i+'px;">|'+seconds2ntp(Math.round(i*this.timeline_scale))+'</span>';
1262 - n++;
1263 - if(n==10)n=0;
1264 - }
1265 - $j('#'+this.timeline_id+'_head_jump').html(out);
1266 - }
1267 - if(this.timeline_mode=='clip'){
1268 - //remove the old one if its still there
1269 - $j('#'+this.timeline_id +'_pl_control').remove();
1270 - //render out a playlist clip wide and all the way to the right (only playhead and play button) (outside of timeline)
1271 - $j('#'+this.sequence_container_id).append('<div id="'+ this.timeline_id +'_pl_control"'+
1272 - ' style="position:absolute;top:' + (this.plObj.height) +'px;'+
1273 - 'right:1px;width:'+this.plObj.width+'px;height:'+this.plObj.org_control_height+'" '+
1274 - 'class="videoPlayer"><div class="controls">'+
1275 - this.plObj.getControlsHTML() +
1276 - '</div>'+
1277 - '</div>');
1278 - //update time and render out clip dividers .. should be used to show load progress
1279 - this.plObj.updateBaseStatus();
1280 -
1281 - //once the controls are in the DOM add hooks:
1282 - ctrlBuilder.addControlHooks(this.plObj);
1283 - }
1284 - },
1285 - jt:function( jh_time ){
1286 - js_log('jt:' + jh_time);
1287 - var this_seq = this;
1288 - this.playline_time = jh_time;
1289 - js_log('time: ' + seconds2ntp(jh_time) + ' ' + Math.round(jh_time/this.timeline_scale));
1290 - //render playline at given time
1291 - $j('#'+this.timeline_id+'_playline').css('left', Math.round(jh_time/this.timeline_scale)+'px' );
1292 - cur_pl_time=0;
1293 - //update the thumb with the requested time:
1294 - this.plObj.updateThumbTime( jh_time );
1295 - },
1296 - //adjusts the current scale
1297 - zoom_in:function(){
1298 - this.timeline_scale = this.timeline_scale*.75;
1299 - this.do_refresh_timeline();
1300 - js_log('zoomed in:'+this.timeline_scale);
1301 - },
1302 - zoom_out:function(){
1303 - this.timeline_scale = this.timeline_scale*(1+(1/3));
1304 - this.do_refresh_timeline();
1305 - js_log('zoom out: '+this.timeline_scale);
1306 - },
1307 - do_refresh_timeline:function(){
1308 - //regen duration
1309 - this.plObj.getDuration( true );
1310 - //refresh player:
1311 - this.plObj.getHTML();
1312 -
1313 - this.render_playheadhead_seeker();
1314 - this.render_tracks();
1315 - this.jt(this.playline_time);
1316 - }
1317 -
1318 -}
1319 -/* extension to mvPlayList to support sequencer features properties */
1320 -var mvSeqPlayList = function( element ){
1321 - return this.init( element );
1322 -}
1323 -mvSeqPlayList.prototype = {
1324 - init:function(element){
1325 - var myPlObj = new mvPlayList(element);
1326 - //inherit mvClip
1327 - for(var method in myPlObj){
1328 - if(typeof this[method] != 'undefined' ){
1329 - this['parent_'+method]=myPlObj[method];
1330 - }else{
1331 - this[method] = myPlObj[method];
1332 - }
1333 - }
1334 - this.org_control_height = this.pl_layout.control_height;
1335 - //do specific mods:(controls and title are managed by the sequencer)
1336 - this.pl_layout.title_bar_height=0;
1337 - this.pl_layout.control_height=0;
1338 - },
1339 - //update the timeline playhead and passalong to parent
1340 - setSliderValue:function( perc ){
1341 - js_log("set " + perc + ' of cur_clip: ' + this.cur_clip.order );
1342 - //$j('#'+ this.seqObj.timeline_id + '_playline').css('left')
1343 - this.parent_setSliderValue( perc );
1344 - },
1345 - getControlsHTML:function(){
1346 - //get controls from current clip add some playlist specific controls:
1347 - this.cur_clip.embed.supports['prev_next'] = true;
1348 - this.cur_clip.embed.supports['options'] = false;
1349 - return ctrlBuilder.getControls( this.cur_clip.embed );
1350 - },
1351 - //override renderDisplay
1352 - renderDisplay:function(){
1353 - //setup layout for title and dc_ clip container
1354 - $j(this).html('<div id="dc_'+this.id+'" style="width:'+this.width+'px;' +
1355 - 'height:'+(this.height)+'px;position:relative;" />');
1356 -
1357 - this.setupClipDisplay();
1358 - }
1359 -}
Index: trunk/extensions/MetavidWiki/skins/mv_embed/mv_clip_edit.js
@@ -1,16 +0,0 @@
2 -/*
3 -hanndles clip edit controls
4 - 'inoutpoints':0, //should let you set the in and out points of clip
5 - 'panzoom':0, //should allow setting keyframes and tweening modes
6 - 'overlays':0, //should allow setting "locked to clip" overlay tracks
7 - 'audio':0 //should allow controling the audio volume (with keyframes)
8 -*/
9 -
10 -var mvClipEdit = function(initObj) {
11 - return this.init(initObj);
12 -};
13 -mvClipEdit.prototype = {
14 - init:function( initObj){
15 - //setup the clip editor
16 - }
17 -}
Index: trunk/extensions/MetavidWiki/skins/mv_embed/mv_embed_iframe.php
@@ -52,40 +52,6 @@
5353 'height' => $height,
5454 ));
5555 }
56 -
57 -/**
58 - * JS escape function copied from MediaWiki's Xml::escapeJsString()
59 - */
60 -function wfEscapeJsString( $string ) {
61 - // See ECMA 262 section 7.8.4 for string literal format
62 - $pairs = array(
63 - "\\" => "\\\\",
64 - "\"" => "\\\"",
65 - '\'' => '\\\'',
66 - "\n" => "\\n",
67 - "\r" => "\\r",
68 -
69 - # To avoid closing the element or CDATA section
70 - "<" => "\\x3c",
71 - ">" => "\\x3e",
72 -
73 - # To avoid any complaints about bad entity refs
74 - "&" => "\\x26",
75 -
76 - # Work around https://bugzilla.mozilla.org/show_bug.cgi?id=274152
77 - # Encode certain Unicode formatting chars so affected
78 - # versions of Gecko don't misinterpret our strings;
79 - # this is a common problem with Farsi text.
80 - "\xe2\x80\x8c" => "\\u200c", // ZERO WIDTH NON-JOINER
81 - "\xe2\x80\x8d" => "\\u200d", // ZERO WIDTH JOINER
82 - );
83 - return strtr( $string, $pairs );
84 -}
85 -
86 -function error_out($error=''){
87 - output_page(array('error' => $error));
88 - exit();
89 -}
9056 function output_page($params){
9157 extract( $params );
9258 ?>
Index: trunk/extensions/MetavidWiki/skins/mv_embed/mv_embed.js
@@ -21,7 +21,8 @@
2222 MV_DO_INIT=false;
2323 }
2424
25 -var MV_EMBED_VERSION = '1.0rc1';
 25+//used to grab unnique copies of scripts.
 26+var MV_EMBED_VERSION = '1.0rc2';
2627
2728 //the name of the player skin (default is mvpcf)
2829 var mv_skin_name = 'mvpcf';
@@ -58,11 +59,13 @@
5960 var parseUri=function(d){var o=parseUri.options,value=o.parser[o.strictMode?"strict":"loose"].exec(d);for(var i=0,uri={};i<14;i++){uri[o.key[i]]=value[i]||""}uri[o.q.name]={};uri[o.key[12]].replace(o.q.parser,function(a,b,c){if(b)uri[o.q.name][b]=c});return uri};parseUri.options={strictMode:false,key:["source","protocol","authority","userInfo","user","password","host","port","relative","path","directory","file","query","anchor"],q:{name:"queryKey",parser:/(?:^|&)([^&=]*)=?([^&]*)/g},parser:{strict:/^(?:([^:\/?#]+):)?(?:\/\/((?:(([^:@]*):?([^:@]*))?@)?([^:\/?#]*)(?::(\d*))?))?((((?:[^?#\/]*\/)*)([^?#]*))(?:\?([^#]*))?(?:#(.*))?)/,loose:/^(?:(?![^:@]+:[^:@\/]*@)([^:\/?#.]+):)?(?:\/\/)?((?:(([^:@]*):?([^:@]*))?@)?([^:\/?#]*)(?::(\d*))?)(((\/(?:[^?#](?![^?#\/]*\.[^?#\/.]+(?:[?#]|$)))*\/?)?([^?#\/]*))(?:\?([^#]*))?(?:#(.*))?)/}};
6061
6162 //get mv_embed location if it has not been set
62 -if(!mv_embed_path){
 63+if( !mv_embed_path ){
6364 var mv_embed_path =getMvEmbedPath();
6465 }
65 -//here you can add in delay load reference to test things with delayed load time:
66 -//mv_embed_path = mv_embed_path + 'delay_load.php/';
 66+//set the unique request id (for ensuring fresh copies of scripts on udpates)
 67+if( !mv_embed_urid ){
 68+ var mv_embed_urid = getMvUniqueReqId();
 69+}
6770
6871 //the default thumbnail for missing images:
6972 var mv_default_thumb_url = mv_embed_path + 'images/vid_default_thumb.jpg';
@@ -222,7 +225,7 @@
223226 js_log('jquery loaded');
224227 mvJsLoader.doLoad(_this.lib_plugins, function(){
225228 //load control ui after ui.core loaded
226 - mvJsLoader.doLoad(_this.lib_controlui,function(){
 229+ mvJsLoader.doLoad(_this.lib_controlui, function(){
227230 js_log('plugins loaded');
228231 mvEmbed.libs_loaded=true;
229232 mvEmbed.init();
@@ -320,13 +323,10 @@
321324 else
322325 {
323326 var _this = this;
324 - var plugin_path = mv_embed_path + 'embedLibs/mv_'+this.library+'Embed.js';
 327+ var plugin_path = mv_embed_path + 'libEmbedObj/mv_'+this.library+'Embed.js';
325328 //add the callback:
326 - this.loading_callbacks.push(callback);
327 -
328 - js_log('plugin not loaded, queing callback');
329 - js_log('requesting plugin: ' + plugin_path + ' should define lib:' + this.library+'Embed');
330 -
 329+ this.loading_callbacks.push(callback);
 330+ //jQuery based get script does not work so well.
331331 /*$j.getScript(plugin_path, function(){
332332 js_log(_this.id + ' plugin loaded');
333333 _this.loaded = true;
@@ -335,7 +335,7 @@
336336 _this.loading_callbacks = null;
337337 });*/
338338
339 - eval('var lib = {"'+this.library+'Embed":\'embedLibs/mv_'+this.library+'Embed.js\'}');
 339+ eval('var lib = {"'+this.library+'Embed":\'libEmbedObj/mv_'+this.library+'Embed.js\'}');
340340 //js_log('DO LOAD: '+this.library);
341341 mvJsLoader.doLoad(lib,function(){
342342 //js_log( 'type of lib: ' + eval( 'typeof ' + this.library + 'Embed' ) );
@@ -1047,14 +1047,14 @@
10481048 });
10491049 if(loadPlaylistLib){
10501050 js_log('f:load Playlist Lib:');
1051 - mvJsLoader.doLoad({'mvPlayList':'mv_playlist.js'},function(){
 1051+ mvJsLoader.doLoad({'mvPlayList':'libSequencer/mv_playlist.js'},function(){
10521052 $j('playlist').each(function(){
10531053 //check if we are in sequence mode load sequence libs (if not already loaded)
10541054 if( $j(this).attr('sequencer')=="true" ){
10551055 var pl_element = this;
10561056 //load the mv_sequencer and the json util lib:
10571057 mvJsLoader.doLoad({
1058 - 'mvSeqPlayList':'mv_sequencer.js'
 1058+ 'mvSeqPlayList':'libSequencer/mv_sequencer.js'
10591059 },function(){
10601060 var seqObj = new mvSeqPlayList( pl_element );
10611061 swapEmbedVideoElement( pl_element, seqObj );
@@ -1072,7 +1072,20 @@
10731073 });
10741074 }
10751075 }
1076 -
 1076+/* init remote search */
 1077+function mv_do_remote_search(initObj){
 1078+ //insure we have the basic libs (jquery etc) :
 1079+ mvEmbed.load_libs(function(){
 1080+ //load search specifc extra stuff
 1081+ mvJsLoader.doLoad({
 1082+ 'mvBaseRemoteSearch':'libRemoteMediaSearch/mv_remote_media_search.js'
 1083+ }, function(){
 1084+ var mvrs = new remoteSearchDriver(initObj);
 1085+ });
 1086+ });
 1087+}
 1088+
 1089+/* init the sequencer */
10771090 function mv_do_sequence(initObj){
10781091 //issue a request to get the css file (if not already included):
10791092 if(!styleSheetPresent(mv_embed_path+'skins/'+mv_skin_name+'/mv_sequence.css'))
@@ -1081,7 +1094,7 @@
10821095 mvEmbed.load_libs(function(){
10831096 //load playlist object and drag,drop,resize,hoverintent,libs
10841097 mvJsLoader.doLoad({
1085 - 'mvPlayList':'mv_playlist.js',
 1098+ 'mvPlayList':'libSequencer/mv_playlist.js',
10861099 '$j.ui.sortable':'jquery/jquery.ui-1.5.2/ui/minified/ui.sortable.min.js',
10871100 '$j.ui.resizable':'jquery/jquery.ui-1.5.2/ui/minified/ui.resizable.min.js',
10881101 '$j.contextMenu':'jquery/plugins/jquery.contextMenu.js'
@@ -1093,7 +1106,7 @@
10941107 },function(){
10951108 //load the sequencer
10961109 mvJsLoader.doLoad({
1097 - 'mvSequencer':'mv_sequencer.js'
 1110+ 'mvSequencer':'libSequencer/mv_sequencer.js'
10981111 },function(){
10991112 //init the sequence object (it will take over from there)
11001113 _global['mvSeq'] = new mvSequencer(initObj);
@@ -2421,7 +2434,7 @@
24222435 if(typeof this.textInterface == 'undefined' ){
24232436 //load the default text interface:
24242437 mvJsLoader.doLoad({
2425 - 'textInterface':'timedTextLibs/mv_timed_text.js',
 2438+ 'textInterface':'libTimedText/mv_timed_text.js',
24262439 '$j.fn.hoverIntent':'jquery/plugins/jquery.hoverIntent.js'
24272440 }, function(){
24282441
@@ -2868,7 +2881,8 @@
28692882 }
28702883 times = ntp.split(':');
28712884 if(times.length!=3){
2872 - return js_log('ntp2seconds:not valid ntp:'+ntp);
 2885+ js_log('ntp2seconds:not valid ntp:'+ntp);
 2886+ return false;
28732887 }
28742888 //sometimes the comma is used inplace of pereid for ms
28752889 times[2] = times[2].replace(/,\s?/,'.');
@@ -2883,11 +2897,15 @@
28842898
28852899 //does a remote or local api request based on request url
28862900 function do_api_req(req_param, api_url, callback){
2887 - if(typeof req_param != 'object')
2888 - return js_log('Error: request paramaters must be an object');
 2901+ if(typeof req_param != 'object'){
 2902+ js_log('Error: request paramaters must be an object');
 2903+ return false;
 2904+ }
28892905 if( !api_url){
2890 - if(!wgServer || ! wgScriptPath)
2891 - return js_log('Error: no api url');
 2906+ if(!wgServer || ! wgScriptPath){
 2907+ js_log('Error: no api url');
 2908+ return false;
 2909+ }
28922910
28932911 api_url = wgServer +((wgServer == null) ? parseUri(document.URL).host + (wgScriptPath + "/api.php") : parseUri(document.URL).host + wgScript);
28942912 //update to api.php (if index.php was in the wgScript path):
@@ -2919,7 +2937,8 @@
29202938 }
29212939 }
29222940 //do a "normal" request (should be deprecated via extending the mediaWiki API)
2923 -function do_request(req_url, callback){
 2941+function do_request(req_url, callback){
 2942+ //pass along a unique inentifier if set
29242943 js_log('do request: ' + req_url);
29252944 //if we are doing a request to the same domain or relative link do a normal GET:
29262945 if( parseUri(document.URL).host == parseUri(req_url).host ||
@@ -2988,9 +3007,12 @@
29893008 //load external js via dom injection
29903009 //@@todo swich over to jQuery injection
29913010 function loadExternalJs(url, callback){
 3011+ //add a unquie request id to ensure fresh copies where appopriate
 3012+ if( url.indexOf('?')==-1 ){
 3013+ url+='?'+mv_embed_urid;
 3014+ }
29923015 js_log('load js: '+ url);
29933016 //if(window['$j'])
2994 - // $j.getScript(url, callback);
29953017 //have to use direct ajax call insted of $j.getScript()
29963018 //since you can't send "cache" option to $j.getScript()
29973019 /*$j.ajax({
@@ -3026,21 +3048,33 @@
30273049 e.rel = 'stylesheet';
30283050 document.getElementsByTagName("head")[0].appendChild(e);
30293051 }
 3052+
 3053+function getMvEmbedURL(){
 3054+ js_elements = document.getElementsByTagName("script");
 3055+ for(var i=0;i<js_elements.length; i++){
 3056+ if( js_elements[i].src.indexOf('mv_embed.js') !=-1){
 3057+ return js_elements[i].src;
 3058+ }
 3059+ }
 3060+ return false;
 3061+}
 3062+//gets a unique id from the mv_embed url else returns the version number
 3063+function getMvUniqueReqId(){
 3064+ var mv_embed_url = getMvEmbedURL();
 3065+ if( mv_embed_url.indexOf('?')!=-1 ){
 3066+ return mv_embed_url.substr( mv_embed_url.indexOf('?')+1 );
 3067+ }
 3068+ return MV_EMBED_VERSION;
 3069+}
30303070 /*
30313071 * sets the global mv_embed path based on the scripts location
30323072 */
30333073 function getMvEmbedPath(){
3034 - js_elements = document.getElementsByTagName("script");
3035 - for(var i=0;i<js_elements.length; i++){
3036 - var mstr = js_elements[i].src.indexOf('mv_embed.js');
3037 - if( mstr !=-1){
3038 - mv_embed_path = js_elements[i].src.substr(0,mstr);
3039 - }
3040 - }
 3074+ var mv_embed_url = getMvEmbedURL();
 3075+ mv_embed_path = mv_embed_url.substr(0, mv_embed_url.indexOf('mv_embed.js'));
30413076 //absolute the url (if relative) (if we don't have mv_embed path)
3042 - if(mv_embed_path.indexOf('://')==-1){
3043 - var doc_url = document.URL;
3044 - var pURL = parseUri(doc_url);
 3077+ if(mv_embed_path.indexOf('://')==-1){
 3078+ var pURL = parseUri( document.URL );
30453079 if(mv_embed_path.charAt(0)=='/'){
30463080 mv_embed_path = pURL.protocol + '://' + pURL.authority + mv_embed_path;
30473081 }else{
@@ -3049,9 +3083,7 @@
30503084 mv_embed_path = pURL.protocol + '://' + pURL.authority + pURL.directory + mv_embed_path;
30513085 }
30523086 }
3053 - }else{
3054 - js_log('already absolute');
3055 - }
 3087+ }
30563088 return mv_embed_path;
30573089 }
30583090 if (typeof DOMParser == "undefined") {
Index: trunk/extensions/MetavidWiki/skins/mv_embed/README
@@ -1,6 +1,6 @@
22 ***********************************************
33 *
4 -* mv_embed version 1.0rc1
 4+* mv_embed version 1.0rc2
55 * for details see: http://metavid.ucsc.edu/wiki/index.php/Mv_embed
66 * and this README
77 *
@@ -9,7 +9,7 @@
1010 *
1111 * @author Michael Dale
1212 * @email dale@ucsc.edu
13 -* @url http://metavid.ucsc.edu
 13+* @url http://metavid.org
1414 *
1515 *********************************************
1616
Index: trunk/extensions/MetavidWiki/skins/mv_embed/libEmbedObj/mv_genericEmbed.js
@@ -0,0 +1,9 @@
 2+/* the most simple implementation used for unknown application/ogg plugin */
 3+var genericEmbed={
 4+ instanceOf:'genericEmbed',
 5+ getEmbedHTML:function(){
 6+ return '<object type="application/ogg" '+
 7+ 'width="'+this.width+'" height="'+this.height+'" ' +
 8+ 'data="' + this.media_element.selected_source.getURI(this.seek_time_sec) + '"></object>';
 9+ }
 10+}
\ No newline at end of file
Property changes on: trunk/extensions/MetavidWiki/skins/mv_embed/libEmbedObj/mv_genericEmbed.js
___________________________________________________________________
Added: svn:mergeinfo
Added: svn:eol-style
111 + native
Index: trunk/extensions/MetavidWiki/skins/mv_embed/libEmbedObj/mv_flashEmbed.js
@@ -0,0 +1,1772 @@
 2+/**
 3+ * metavid: mv_flashEmbed builds off of flowplayer api (included first in this file)
 4+ */
 5+
 6+ /**
 7+ * flowplayer.js 3.0.0-rc5. The Flowplayer API.
 8+ *
 9+ * This file is part of Flowplayer, http://flowplayer.org
 10+ *
 11+ * Author: Tero Piirainen, <support@flowplayer.org>
 12+ * Copyright (c) 2008 Flowplayer Ltd
 13+ *
 14+ * Released under the MIT License:
 15+ * http://www.opensource.org/licenses/mit-license.php
 16+ *
 17+ * Version: 3.0.0-rc5 - Thu Nov 20 2008 22:09:49 GMT-0000 (GMT+00:00)
 18+ */
 19+(function() {
 20+
 21+/*
 22+ FEATURES
 23+ --------
 24+ - handling multiple instances
 25+ - Flowplayer programming API
 26+ - Flowplayer event model
 27+ - player loading / unloading
 28+ - $f() function
 29+ - jQuery support
 30+*/
 31+
 32+
 33+/*jslint glovar: true, browser: true */
 34+/*global flowplayer, $f */
 35+
 36+// {{{ private utility methods
 37+
 38+ function log(args) {
 39+
 40+ // write into opera console
 41+ if (typeof opera == 'object') {
 42+ opera.postError("$f.fireEvent: " + args.join(" | "));
 43+
 44+
 45+ } else if (typeof console == 'object') {
 46+ console.log("$f.fireEvent", [].slice.call(args));
 47+ }
 48+ }
 49+
 50+
 51+ // thanks: http://keithdevens.com/weblog/archive/2007/Jun/07/javascript.clone
 52+ function clone(obj) {
 53+ if (!obj || typeof obj != 'object') { return obj; }
 54+ var temp = new obj.constructor();
 55+ for (var key in obj) {
 56+ if (obj.hasOwnProperty(key)) {
 57+ temp[key] = clone(obj[key]);
 58+ }
 59+ }
 60+ return temp;
 61+ }
 62+
 63+ // stripped from jQuery, thanks John Resig
 64+ function each(obj, fn) {
 65+ if (!obj) { return; }
 66+
 67+ var name, i = 0, length = obj.length;
 68+
 69+ // object
 70+ if (length === undefined) {
 71+ for (name in obj) {
 72+ if (fn.call(obj[name], name, obj[name]) === false) { break; }
 73+ }
 74+
 75+ // array
 76+ } else {
 77+ for (var value = obj[0];
 78+ i < length && fn.call( value, i, value ) !== false; value = obj[++i]) {
 79+ }
 80+ }
 81+
 82+ return obj;
 83+ }
 84+
 85+
 86+ // convenience
 87+ function el(id) {
 88+ return document.getElementById(id);
 89+ }
 90+
 91+
 92+ // used extensively. a very simple implementation.
 93+ function extend(to, from, skipFuncs) {
 94+ if (to && from) {
 95+ each(from, function(name, value) {
 96+ if (!skipFuncs || typeof value != 'function') {
 97+ to[name] = value;
 98+ }
 99+ });
 100+ }
 101+ }
 102+
 103+ // var arr = select("elem.className");
 104+ function select(query) {
 105+ var index = query.indexOf(".");
 106+ if (index != -1) {
 107+ var tag = query.substring(0, index) || "*";
 108+ var klass = query.substring(index + 1, query.length);
 109+ var els = [];
 110+ each(document.getElementsByTagName(tag), function() {
 111+ if (this.className && this.className.indexOf(klass) != -1) {
 112+ els.push(this);
 113+ }
 114+ });
 115+ return els;
 116+ }
 117+ }
 118+
 119+ // fix event inconsistencies across browsers
 120+ function stopEvent(e) {
 121+ e = e || window.event;
 122+
 123+ if (e.preventDefault) {
 124+ e.stopPropagation();
 125+ e.preventDefault();
 126+
 127+ } else {
 128+ e.returnValue = false;
 129+ e.cancelBubble = true;
 130+ }
 131+ return false;
 132+ }
 133+
 134+ // push an event listener into existing array of listeners
 135+ function bind(to, evt, fn) {
 136+ to[evt] = to[evt] || [];
 137+ to[evt].push(fn);
 138+ }
 139+
 140+
 141+ // generates an unique id
 142+ function makeId() {
 143+ return "_" + ("" + Math.random()).substring(2, 10);
 144+ }
 145+
 146+//}}}
 147+
 148+
 149+// {{{ Clip
 150+
 151+ var Clip = function(json, index, player) {
 152+
 153+ // private variables
 154+ var self = this;
 155+ var cuepoints = {};
 156+ var listeners = {};
 157+ this.index = index;
 158+
 159+ // instance variables
 160+ if (typeof json == 'string') {
 161+ json = {url:json};
 162+ }
 163+
 164+ extend(this, json, true);
 165+
 166+ // event handling
 167+ each(("Begin*,Start,Pause*,Resume*,Seek*,Stop*,Finish*,LastSecond,Update,BufferFull,BufferEmpty,BufferStop").split(","),
 168+ function() {
 169+
 170+ var evt = "on" + this;
 171+
 172+ // before event
 173+ if (evt.indexOf("*") != -1) {
 174+ evt = evt.substring(0, evt.length -1);
 175+ var before = "onBefore" + evt.substring(2);
 176+
 177+ self[before] = function(fn) {
 178+ bind(listeners, before, fn);
 179+ return self;
 180+ };
 181+ }
 182+
 183+ self[evt] = function(fn) {
 184+ bind(listeners, evt, fn);
 185+ return self;
 186+ };
 187+
 188+
 189+ // set common clip event listeners to player level
 190+ if (index == -1) {
 191+ if (self[before]) {
 192+ player[before] = self[before];
 193+ }
 194+ if (self[evt]) {
 195+ player[evt] = self[evt];
 196+ }
 197+ }
 198+
 199+ });
 200+
 201+ extend(this, {
 202+
 203+
 204+ onCuepoint: function(points, fn) {
 205+
 206+ // embedded cuepoints
 207+ if (arguments.length == 1) {
 208+ cuepoints.embedded = [null, points];
 209+ return self;
 210+ }
 211+
 212+ if (typeof points == 'number') {
 213+ points = [points];
 214+ }
 215+
 216+ var fnId = makeId();
 217+ cuepoints[fnId] = [points, fn];
 218+
 219+ if (player.isLoaded()) {
 220+ player._api().fp_addCuepoints(points, index, fnId);
 221+ }
 222+
 223+ return self;
 224+ },
 225+
 226+ update: function(json) {
 227+ extend(self, json);
 228+
 229+ if (player.isLoaded()) {
 230+ player._api().fp_updateClip(json, index);
 231+ }
 232+ var conf = player.getConfig();
 233+ var clip = (index == -1) ? conf.clip : conf.playlist[index];
 234+ extend(clip, json, true);
 235+ },
 236+
 237+
 238+ // internal event for performing clip tasks. should be made private someday
 239+ _fireEvent: function(evt, arg1, arg2, target) {
 240+
 241+ if (evt == 'onLoad') {
 242+ each(cuepoints, function(key, val) {
 243+ player._api().fp_addCuepoints(val[0], index, key);
 244+ });
 245+ return false;
 246+ }
 247+
 248+ // target clip we are working against
 249+ if (index != -1) {
 250+ target = self;
 251+ }
 252+
 253+ if (evt == 'onCuepoint') {
 254+ var fn = cuepoints[arg1];
 255+ if (fn) {
 256+ return fn[1].call(player, target, arg2);
 257+ }
 258+ }
 259+
 260+ if (evt == 'onStart' || evt == 'onUpdate') {
 261+
 262+ extend(target, arg1);
 263+
 264+ if (!target.duration) {
 265+ target.duration = arg1.metaData.duration;
 266+ } else {
 267+ target.fullDuration = arg1.metaData.duration;
 268+ }
 269+ }
 270+
 271+ var ret = true;
 272+ each(listeners[evt], function() {
 273+ ret = this.call(player, target, arg1);
 274+ });
 275+ return ret;
 276+ }
 277+
 278+ });
 279+
 280+
 281+ // get cuepoints from config
 282+ if (json.onCuepoint) {
 283+ self.onCuepoint.apply(self, json.onCuepoint);
 284+ delete json.onCuepoint;
 285+ }
 286+
 287+ // get other events
 288+ each(json, function(key, val) {
 289+ if (typeof val == 'function') {
 290+ bind(listeners, key, val);
 291+ delete json[key];
 292+ }
 293+ });
 294+
 295+
 296+ // setup common clip event callbacks for Player object too (shortcuts)
 297+ if (index == -1) {
 298+ player.onCuepoint = this.onCuepoint;
 299+ }
 300+
 301+ };
 302+
 303+//}}}
 304+
 305+
 306+// {{{ Plugin
 307+
 308+ var Plugin = function(name, json, player, fn) {
 309+
 310+ var listeners = {};
 311+ var self = this;
 312+ var hasMethods = false;
 313+
 314+ if (fn) {
 315+ extend(listeners, fn);
 316+ }
 317+
 318+ // custom callback functions in configuration
 319+ each(json, function(key, val) {
 320+ if (typeof val == 'function') {
 321+ listeners[key] = val;
 322+ delete json[key];
 323+ }
 324+ });
 325+
 326+ // core plugin methods
 327+ extend(this, {
 328+
 329+ animate: function(props, speed, fn) {
 330+ if (!props) {
 331+ return self;
 332+ }
 333+
 334+ if (typeof speed == 'function') {
 335+ fn = speed;
 336+ speed = 500;
 337+ }
 338+
 339+ if (typeof props == 'string') {
 340+ var key = props;
 341+ props = {};
 342+ props[key] = speed;
 343+ speed = 500;
 344+ }
 345+
 346+ if (fn) {
 347+ var fnId = makeId();
 348+ listeners[fnId] = fn;
 349+ }
 350+
 351+ if (speed === undefined) { speed = 500; }
 352+ json = player._api().fp_animate(name, props, speed, fnId);
 353+ return self;
 354+ },
 355+
 356+ css: function(props, val) {
 357+ if (val !== undefined) {
 358+ var css = {};
 359+ css[props] = val;
 360+ props = css;
 361+ }
 362+ json = player._api().fp_css(name, props);
 363+ extend(self, json);
 364+ return self;
 365+ },
 366+
 367+ show: function() {
 368+ this.display = 'block';
 369+ player._api().fp_showPlugin(name);
 370+ return self;
 371+ },
 372+
 373+ hide: function() {
 374+ this.display = 'none';
 375+ player._api().fp_hidePlugin(name);
 376+ return self;
 377+ },
 378+
 379+ toggle: function() {
 380+ this.display = player._api().fp_togglePlugin(name);
 381+ return self;
 382+ },
 383+
 384+ fadeTo: function(o, speed, fn) {
 385+
 386+ if (typeof speed == 'function') {
 387+ fn = speed;
 388+ speed = 500;
 389+ }
 390+
 391+ if (fn) {
 392+ var fnId = makeId();
 393+ listeners[fnId] = fn;
 394+ }
 395+ this.display = player._api().fp_fadeTo(name, o, speed, fnId);
 396+ this.opacity = o;
 397+ return self;
 398+ },
 399+
 400+ fadeIn: function(speed, fn) {
 401+ return self.fadeTo(1, speed, fn);
 402+ },
 403+
 404+ fadeOut: function(speed, fn) {
 405+ return self.fadeTo(0, speed, fn);
 406+ },
 407+
 408+ getName: function() {
 409+ return name;
 410+ },
 411+
 412+
 413+ // internal method not meant to be used by clients
 414+ _fireEvent: function(evt, arg) {
 415+
 416+
 417+ // update plugins properties & methods
 418+ if (evt == 'onUpdate') {
 419+ var json = arg || player._api().fp_getPlugin(name);
 420+ if (!json) { return; }
 421+
 422+ extend(self, json);
 423+ delete self.methods;
 424+
 425+ if (!hasMethods) {
 426+ each(json.methods, function() {
 427+ var method = "" + this;
 428+
 429+ self[method] = function() {
 430+ var a = [].slice.call(arguments);
 431+ var ret = player._api().fp_invoke(name, method, a);
 432+ return ret == 'undefined' ? self : ret;
 433+ };
 434+ });
 435+ hasMethods = true;
 436+ }
 437+ }
 438+
 439+ // plugin callbacks
 440+ var fn = listeners[evt];
 441+
 442+ if (fn) {
 443+
 444+ fn.call(self, arg);
 445+
 446+ // "one-shot" callback
 447+ if (evt.substring(0, 1) == "_") {
 448+ delete listeners[evt];
 449+ }
 450+ }
 451+ }
 452+
 453+ });
 454+
 455+ };
 456+
 457+
 458+//}}}
 459+
 460+
 461+function Player(wrapper, params, conf) {
 462+
 463+ // private variables (+ arguments)
 464+ var
 465+ self = this,
 466+ api = null,
 467+ html,
 468+ commonClip,
 469+ playlist = [],
 470+ plugins = {},
 471+ listeners = {},
 472+ playerId,
 473+ apiId,
 474+ activeIndex,
 475+ swfHeight,
 476+ wrapperHeight;
 477+
 478+
 479+// {{{ public methods
 480+
 481+ extend(self, {
 482+
 483+ id: function() {
 484+ return playerId;
 485+ },
 486+
 487+ isLoaded: function() {
 488+ return (api !== null);
 489+ },
 490+
 491+ getParent: function() {
 492+ return wrapper;
 493+ },
 494+
 495+ hide: function(all) {
 496+ if (all) { wrapper.style.height = "0px"; }
 497+ if (api) { api.style.height = "0px"; }
 498+ return self;
 499+ },
 500+
 501+ show: function() {
 502+ wrapper.style.height = wrapperHeight + "px";
 503+ if (api) { api.style.height = swfHeight + "px"; }
 504+ return self;
 505+ },
 506+
 507+ isHidden: function() {
 508+ return api && parseInt(api.style.height, 10) === 0;
 509+ },
 510+
 511+
 512+ load: function(fn) {
 513+
 514+ if (!api && self._fireEvent("onBeforeLoad") !== false) {
 515+
 516+ // unload all instances
 517+ each(players, function() {
 518+ this.unload();
 519+ });
 520+
 521+ html = wrapper.innerHTML;
 522+ flashembed(wrapper, params, {config: conf});
 523+
 524+ // function argument
 525+ if (fn) {
 526+ fn.cached = true;
 527+ bind(listeners, "onLoad", fn);
 528+ }
 529+ }
 530+
 531+ return self;
 532+ },
 533+
 534+ unload: function() {
 535+
 536+ if (api && html.replace(/\s/g, '') !== '' && !api.fp_isFullscreen() &&
 537+ self._fireEvent("onBeforeUnload") !== false) {
 538+ api.fp_close();
 539+ wrapper.innerHTML = html;
 540+ self._fireEvent("onUnload");
 541+ api = null;
 542+ }
 543+
 544+ return self;
 545+ },
 546+
 547+ getClip: function(index) {
 548+ if (index === undefined) {
 549+ index = activeIndex;
 550+ }
 551+ return playlist[index];
 552+ },
 553+
 554+
 555+ getCommonClip: function() {
 556+ return commonClip;
 557+ },
 558+
 559+ getPlaylist: function() {
 560+ return playlist;
 561+ },
 562+
 563+ getPlugin: function(name) {
 564+ var plugin = plugins[name];
 565+
 566+ // create plugin if nessessary
 567+ if (!plugin && self.isLoaded()) {
 568+ var json = self._api().fp_getPlugin(name);
 569+ if (json) {
 570+ plugin = new Plugin(name, json, self);
 571+ plugins[name] = plugin;
 572+ }
 573+ }
 574+ return plugin;
 575+ },
 576+
 577+ getScreen: function() {
 578+ return self.getPlugin("screen");
 579+ },
 580+
 581+ getControls: function() {
 582+ return self.getPlugin("controls");
 583+ },
 584+
 585+ getConfig: function() {
 586+ return clone(conf);
 587+ },
 588+
 589+ getFlashParams: function() {
 590+ return params;
 591+ },
 592+
 593+ loadPlugin: function(name, url, props, fn) {
 594+
 595+ // properties not supplied
 596+ if (typeof props == 'function') {
 597+ fn = props;
 598+ props = {};
 599+ }
 600+
 601+ // if fn not given, make a fake id so that plugin's onUpdate get's fired
 602+ var fnId = fn ? makeId() : "_";
 603+ self._api().fp_loadPlugin(name, url, props, fnId);
 604+
 605+ // create new plugin
 606+ var arg = {};
 607+ arg[fnId] = fn;
 608+ var p = new Plugin(name, null, self, arg);
 609+ plugins[name] = p;
 610+ return p;
 611+ },
 612+
 613+
 614+ getState: function() {
 615+ return api ? api.fp_getState() : -1;
 616+ },
 617+
 618+ // "lazy" play
 619+ play: function(clip) {
 620+
 621+ function play() {
 622+ if (clip !== undefined) {
 623+ self._api().fp_play(clip);
 624+ } else {
 625+ self._api().fp_play();
 626+ }
 627+ }
 628+
 629+ if (api) {
 630+ play();
 631+
 632+ } else {
 633+ self.load(function() {
 634+ play();
 635+ });
 636+ }
 637+
 638+ return self;
 639+ },
 640+
 641+ getVersion: function() {
 642+ var js = "flowplayer.js 3.0.0-rc5";
 643+ if (api) {
 644+ var ver = api.fp_getVersion();
 645+ ver.push(js);
 646+ return ver;
 647+ }
 648+ return js;
 649+ },
 650+
 651+ _api: function() {
 652+ if (!api) {
 653+ throw "Flowplayer " +self.id()+ " not loaded. Try moving your call to player's onLoad event";
 654+ }
 655+ return api;
 656+ },
 657+
 658+ _dump: function() {
 659+ console.log(listeners);
 660+ }
 661+
 662+ });
 663+
 664+
 665+ // event handlers
 666+ each(("Click*,Load*,Unload*,Keypress*,Volume*,Mute*,Unmute*,PlaylistReplace,Fullscreen*,FullscreenExit,Error").split(","),
 667+ function() {
 668+ var name = "on" + this;
 669+
 670+ // before event
 671+ if (name.indexOf("*") != -1) {
 672+ name = name.substring(0, name.length -1);
 673+ var name2 = "onBefore" + name.substring(2);
 674+ self[name2] = function(fn) {
 675+ bind(listeners, name2, fn);
 676+ return self;
 677+ };
 678+ }
 679+
 680+ // normal event
 681+ self[name] = function(fn) {
 682+ bind(listeners, name, fn);
 683+ return self;
 684+ };
 685+ }
 686+ );
 687+
 688+
 689+ // core API methods
 690+ each(("pause,resume,mute,unmute,stop,toggle,seek,getStatus,getVolume,setVolume,getTime,isPaused,isPlaying,startBuffering,stopBuffering,isFullscreen,reset").split(","),
 691+ function() {
 692+ var name = this;
 693+
 694+ self[name] = function(arg) {
 695+ if (!api) { return self; }
 696+ var ret = (arg === undefined) ? api["fp_" + name]() : api["fp_" + name](arg);
 697+ return ret == 'undefined' ? self : ret;
 698+ };
 699+ }
 700+ );
 701+
 702+//}}}
 703+
 704+
 705+// {{{ public method: _fireEvent
 706+
 707+ self._fireEvent = function(evt, arg0, arg1, arg2) {
 708+
 709+ if (conf.debug) {
 710+ log(arguments);
 711+ }
 712+
 713+ // internal onLoad
 714+ if (evt == 'onLoad' && !api) {
 715+
 716+ api = api || el(apiId);
 717+ swfHeight = api.clientHeight;
 718+
 719+ each(playlist, function() {
 720+ this._fireEvent("onLoad");
 721+ });
 722+
 723+ each(plugins, function(name, p) {
 724+ p._fireEvent("onUpdate");
 725+ });
 726+
 727+
 728+ commonClip._fireEvent("onLoad");
 729+ }
 730+
 731+ if (evt == 'onContextMenu') {
 732+ each(conf.contextMenu[arg0], function(key, fn) {
 733+ fn.call(self);
 734+ });
 735+ return;
 736+ }
 737+
 738+ if (evt == 'onPluginEvent') {
 739+ var name = arg0.name || arg0;
 740+ var p = plugins[name];
 741+ if (p) {
 742+ if (arg0.name) {
 743+ p._fireEvent("onUpdate", arg0);
 744+ }
 745+ p._fireEvent(arg1);
 746+ }
 747+ return;
 748+ }
 749+
 750+ // onPlaylistReplace
 751+ if (evt == 'onPlaylistReplace') {
 752+ playlist = [];
 753+ var index = 0;
 754+ each(arg0, function() {
 755+ playlist.push(new Clip(this, index++));
 756+ });
 757+ }
 758+
 759+ var ret = true;
 760+
 761+ // clip event
 762+ if (arg0 === 0 || (arg0 && arg0 >= 0)) {
 763+
 764+ activeIndex = arg0;
 765+ var clip = playlist[arg0];
 766+
 767+ if (clip) {
 768+ ret = clip._fireEvent(evt, arg1, arg2);
 769+ }
 770+
 771+ if (!clip || ret !== false) {
 772+
 773+ // clip argument is given for common clip, because it behaves as the target
 774+ ret = commonClip._fireEvent(evt, arg1, arg2, clip);
 775+ }
 776+ }
 777+
 778+ // player event
 779+ var i = 0;
 780+ each(listeners[evt], function() {
 781+ ret = this.call(self, arg0);
 782+
 783+ // remove cached entry
 784+ if (this.cached) {
 785+ listeners[evt].splice(i, 1);
 786+ }
 787+
 788+ // break loop
 789+ if (ret === false) { return false; }
 790+ i++;
 791+
 792+ });
 793+
 794+ return ret;
 795+ };
 796+
 797+//}}}
 798+
 799+
 800+// {{{ init
 801+
 802+ function init() {
 803+
 804+ if ($f(wrapper)) {
 805+ return null;
 806+ }
 807+
 808+ wrapperHeight = parseInt(wrapper.style.height) || wrapper.clientHeight;
 809+
 810+ // register this player into global array of instances
 811+ players.push(self);
 812+
 813+
 814+ // flashembed parameters
 815+ if (typeof params == 'string') {
 816+ params = {src: params};
 817+ }
 818+
 819+ // playerId
 820+ playerId = wrapper.id || "fp" + makeId();
 821+ apiId = params.id || playerId + "_api";
 822+ params.id = apiId;
 823+ conf.playerId = playerId;
 824+
 825+
 826+ // plain url is given as config
 827+ if (typeof conf == 'string') {
 828+ conf = {clip:{url:conf}};
 829+ }
 830+
 831+ // common clip is always there
 832+ conf.clip = conf.clip || {};
 833+ commonClip = new Clip(conf.clip, -1, self);
 834+
 835+
 836+ // wrapper href as playlist
 837+ if (wrapper.getAttribute("href")) {
 838+ conf.playlist = [{url:wrapper.getAttribute("href", 2)}];
 839+ }
 840+
 841+ // playlist
 842+ conf.playlist = conf.playlist || [conf.clip];
 843+
 844+ var index = 0;
 845+ each(conf.playlist, function() {
 846+
 847+ var clip = this;
 848+
 849+ // clip is an array, we don't allow that
 850+ if (typeof clip == 'object' && clip.length) {
 851+ clip = "" + clip;
 852+ }
 853+
 854+ if (!clip.url && typeof clip == 'string') {
 855+ clip = {url: clip};
 856+ }
 857+
 858+ // populate common clip properties to each clip
 859+ extend(clip, conf.clip, true);
 860+
 861+ // modify configuration playlist
 862+ conf.playlist[index] = clip;
 863+
 864+ // populate playlist array
 865+ clip = new Clip(clip, index, self);
 866+ playlist.push(clip);
 867+ index++;
 868+ });
 869+
 870+
 871+ // event listeners
 872+ each(conf, function(key, val) {
 873+ if (typeof val == 'function') {
 874+ bind(listeners, key, val);
 875+ delete conf[key];
 876+ }
 877+ });
 878+
 879+
 880+ // plugins
 881+ each(conf.plugins, function(name, val) {
 882+ if (val) {
 883+ plugins[name] = new Plugin(name, val, self);
 884+ }
 885+ });
 886+
 887+
 888+ // setup controlbar plugin if not explicitly defined
 889+ if (!conf.plugins || conf.plugins.controls === undefined) {
 890+ plugins.controls = new Plugin("controls", null, self);
 891+ }
 892+
 893+ // Flowplayer uses black background by default
 894+ params.bgcolor = params.bgcolor || "#000000";
 895+
 896+
 897+ // setup default settings for express install
 898+ params.version = params.version || [9,0];
 899+ params.expressInstall = 'http://www.flowplayer.org/swf/expressinstall.swf';
 900+
 901+
 902+ // click function
 903+ function doClick(e) {
 904+ if (self._fireEvent("onBeforeClick") !== false) {
 905+ self.load();
 906+ }
 907+ return stopEvent(e);
 908+ }
 909+
 910+ // defer loading upon click
 911+ html = wrapper.innerHTML;
 912+ if (html.replace(/\s/g, '') !== '') {
 913+
 914+ if (wrapper.addEventListener) {
 915+ wrapper.addEventListener("click", doClick, false);
 916+
 917+ } else if (wrapper.attachEvent) {
 918+ wrapper.attachEvent("onclick", doClick);
 919+ }
 920+
 921+ // player is loaded upon page load
 922+ } else {
 923+
 924+ // prevent default action from wrapper (safari problem) loaded
 925+ if (wrapper.addEventListener) {
 926+ wrapper.addEventListener("click", stopEvent, false);
 927+ }
 928+
 929+ // load player
 930+ self.load();
 931+ }
 932+
 933+ }
 934+
 935+ // possibly defer initialization until DOM get's loaded
 936+ if (typeof wrapper == 'string') {
 937+ flashembed.domReady(function() {
 938+ var node = el(wrapper);
 939+
 940+ if (!node) {
 941+ throw "Flowplayer cannot access element: " + wrapper;
 942+ } else {
 943+ wrapper = node;
 944+ init();
 945+ }
 946+ });
 947+
 948+ // we have a DOM element so page is already loaded
 949+ } else {
 950+ init();
 951+ }
 952+
 953+
 954+//}}}
 955+
 956+
 957+}
 958+
 959+
 960+// {{{ flowplayer() & statics
 961+
 962+// container for player instances
 963+var players = [];
 964+
 965+
 966+// this object is returned when multiple player's are requested
 967+function Iterator(arr) {
 968+
 969+ this.length = arr.length;
 970+
 971+ this.each = function(fn) {
 972+ each(arr, fn);
 973+ };
 974+
 975+ this.size = function() {
 976+ return arr.length;
 977+ };
 978+}
 979+
 980+// these two variables are the only global variables
 981+window.flowplayer = window.$f = function() {
 982+
 983+ var instance = null;
 984+ var arg = arguments[0];
 985+
 986+
 987+ // $f()
 988+ if (!arguments.length) {
 989+ each(players, function() {
 990+ if (this.isLoaded()) {
 991+ instance = this;
 992+ return false;
 993+ }
 994+ });
 995+
 996+ return instance || players[0];
 997+ }
 998+
 999+ if (arguments.length == 1) {
 1000+
 1001+ // $f(index);
 1002+ if (typeof arg == 'number') {
 1003+ return players[arg];
 1004+
 1005+
 1006+ // $f(wrapper || 'containerId' || '*');
 1007+ } else {
 1008+
 1009+ // $f("*");
 1010+ if (arg == '*') {
 1011+ return new Iterator(players);
 1012+ }
 1013+
 1014+ // $f(wrapper || 'containerId');
 1015+ each(players, function() {
 1016+ if (this.id() == arg.id || this.id() == arg || this.getParent() == arg) {
 1017+ instance = this;
 1018+ return false;
 1019+ }
 1020+ });
 1021+
 1022+ return instance;
 1023+ }
 1024+ }
 1025+
 1026+ // instance builder
 1027+ if (arguments.length > 1) {
 1028+
 1029+ var swf = arguments[1];
 1030+ var conf = (arguments.length == 3) ? arguments[2] : {};
 1031+
 1032+ if (typeof arg == 'string') {
 1033+
 1034+ // select arg by classname
 1035+ if (arg.indexOf(".") != -1) {
 1036+ var instances = [];
 1037+
 1038+ each(select(arg), function() {
 1039+ instances.push(new Player(this, clone(swf), clone(conf)));
 1040+ });
 1041+
 1042+ return new Iterator(instances);
 1043+
 1044+ // select node by id
 1045+ } else {
 1046+ var node = el(arg);
 1047+ return new Player(node !== null ? node : arg, swf, conf);
 1048+ }
 1049+
 1050+
 1051+ // arg is a DOM element
 1052+ } else if (arg) {
 1053+ return new Player(arg, swf, conf);
 1054+ }
 1055+
 1056+ }
 1057+
 1058+ return null;
 1059+};
 1060+
 1061+extend(window.$f, {
 1062+
 1063+ // called by Flash External Interface
 1064+ fireEvent: function(id, evt, a0, a1, a2) {
 1065+ var p = $f(id);
 1066+ return p ? p._fireEvent(evt, a0, a1, a2) : null;
 1067+ },
 1068+
 1069+
 1070+ // create plugins by modifying Player's prototype
 1071+ addPlugin: function(name, fn) {
 1072+ Player.prototype[name] = fn;
 1073+ return $f;
 1074+ },
 1075+
 1076+ // utility methods for plugin developers
 1077+ each: each,
 1078+
 1079+ extend: extend
 1080+
 1081+});
 1082+
 1083+//}}}
 1084+
 1085+
 1086+//{{{ jQuery support
 1087+
 1088+if (typeof jQuery == 'function') {
 1089+
 1090+ jQuery.prototype.flowplayer = function(params, conf) {
 1091+
 1092+ // select instances
 1093+ if (!arguments.length || typeof arguments[0] == 'number') {
 1094+ var arr = [];
 1095+ this.each(function() {
 1096+ var p = $f(this);
 1097+ if (p) {
 1098+ arr.push(p);
 1099+ }
 1100+ });
 1101+ return arguments.length ? arr[arguments[0]] : new Iterator(arr);
 1102+ }
 1103+
 1104+ // create flowplayer instances
 1105+ return this.each(function() {
 1106+ $f(this, clone(params), conf ? clone(conf) : {});
 1107+ });
 1108+
 1109+ };
 1110+
 1111+}
 1112+
 1113+//}}}
 1114+
 1115+
 1116+})();
 1117+/**
 1118+ * flashembed 0.34. Adobe Flash embedding script
 1119+ *
 1120+ * http://flowplayer.org/tools/flash-embed.html
 1121+ *
 1122+ * Copyright (c) 2008 Tero Piirainen (support@flowplayer.org)
 1123+ *
 1124+ * Released under the MIT License:
 1125+ * http://www.opensource.org/licenses/mit-license.php
 1126+ *
 1127+ * >> Basically you can do anything you want but leave this header as is <<
 1128+ *
 1129+ * first version 0.01 - 03/11/2008
 1130+ * version 0.34 - Tue Nov 11 2008 09:09:52 GMT-0000 (GMT+00:00)
 1131+ */
 1132+(function() {
 1133+
 1134+//{{{ utility functions
 1135+
 1136+var jQ = typeof jQuery == 'function';
 1137+
 1138+
 1139+// from "Pro JavaScript techniques" by John Resig
 1140+function isDomReady() {
 1141+
 1142+ if (domReady.done) { return false; }
 1143+
 1144+ var d = document;
 1145+ if (d && d.getElementsByTagName && d.getElementById && d.body) {
 1146+ clearInterval(domReady.timer);
 1147+ domReady.timer = null;
 1148+
 1149+ for (var i = 0; i < domReady.ready.length; i++) {
 1150+ domReady.ready[i].call();
 1151+ }
 1152+
 1153+ domReady.ready = null;
 1154+ domReady.done = true;
 1155+ }
 1156+}
 1157+
 1158+// if jQuery is present, use it's more effective domReady method
 1159+var domReady = jQ ? jQuery : function(f) {
 1160+
 1161+ if (domReady.done) {
 1162+ return f();
 1163+ }
 1164+
 1165+ if (domReady.timer) {
 1166+ domReady.ready.push(f);
 1167+
 1168+ } else {
 1169+ domReady.ready = [f];
 1170+ domReady.timer = setInterval(isDomReady, 13);
 1171+ }
 1172+};
 1173+
 1174+
 1175+// override extend params function
 1176+function extend(to, from) {
 1177+ if (from) {
 1178+ for (key in from) {
 1179+ if (from.hasOwnProperty(key)) {
 1180+ to[key] = from[key];
 1181+ }
 1182+ }
 1183+ }
 1184+
 1185+ return to;
 1186+}
 1187+
 1188+
 1189+function concatVars(vars) {
 1190+ var out = "";
 1191+
 1192+ for (var key in vars) {
 1193+ if (vars[key]) {
 1194+ out += [key] + '=' + asString(vars[key]) + '&';
 1195+ }
 1196+ }
 1197+ return out.substring(0, out.length -1);
 1198+}
 1199+
 1200+
 1201+
 1202+// JSON.asString() function
 1203+function asString(obj) {
 1204+
 1205+ switch (typeOf(obj)){
 1206+ case 'string':
 1207+ obj = obj.replace(new RegExp('(["\\\\])', 'g'), '\\$1');
 1208+
 1209+ // flash does not handle %- characters well. transforms "50%" to "50pct" (a dirty hack, I admit)
 1210+ obj = obj.replace(/^\s?(\d+)%/, "$1pct");
 1211+ return '"' +obj+ '"';
 1212+
 1213+ case 'array':
 1214+ return '['+ map(obj, function(el) {
 1215+ return asString(el);
 1216+ }).join(',') +']';
 1217+
 1218+ case 'function':
 1219+ return '"function()"';
 1220+
 1221+ case 'object':
 1222+ var str = [];
 1223+ for (var prop in obj) {
 1224+ if (obj.hasOwnProperty(prop)) {
 1225+ str.push('"'+prop+'":'+ asString(obj[prop]));
 1226+ }
 1227+ }
 1228+ return '{'+str.join(',')+'}';
 1229+ }
 1230+
 1231+ // replace ' --> " and remove spaces
 1232+ return String(obj).replace(/\s/g, " ").replace(/\'/g, "\"");
 1233+}
 1234+
 1235+
 1236+// private functions
 1237+function typeOf(obj) {
 1238+ if (obj === null || obj === undefined) { return false; }
 1239+ var type = typeof obj;
 1240+ return (type == 'object' && obj.push) ? 'array' : type;
 1241+}
 1242+
 1243+
 1244+// version 9 bugfix: (http://blog.deconcept.com/2006/07/28/swfobject-143-released/)
 1245+if (window.attachEvent) {
 1246+ window.attachEvent("onbeforeunload", function() {
 1247+ __flash_unloadHandler = function() {};
 1248+ __flash_savedUnloadHandler = function() {};
 1249+ });
 1250+}
 1251+
 1252+function map(arr, func) {
 1253+ var newArr = [];
 1254+ for (var i in arr) {
 1255+ if (arr.hasOwnProperty(i)) {
 1256+ newArr[i] = func(arr[i]);
 1257+ }
 1258+ }
 1259+ return newArr;
 1260+}
 1261+
 1262+function getEmbedCode(p, c) {
 1263+ var html = '<embed type="application/x-shockwave-flash" ';
 1264+
 1265+ if (p.id) { extend(p, {name:p.id}); }
 1266+
 1267+ for (var key in p) {
 1268+ if (p[key] !== null) {
 1269+ html += key + '="' +p[key]+ '"\n\t';
 1270+ }
 1271+ }
 1272+
 1273+ if (c) {
 1274+ html += 'flashvars=\'' + concatVars(c) + '\'';
 1275+ }
 1276+
 1277+ // thanks Tom Price (07/17/2008)
 1278+ html += '/>';
 1279+
 1280+ return html;
 1281+}
 1282+
 1283+function getObjectCode(p, c, embeddable) {
 1284+
 1285+ var html = '<object classid="clsid:D27CDB6E-AE6D-11cf-96B8-444553540000" ';
 1286+ html += 'width="' + p.width + '" height="' + p.height + '"';
 1287+
 1288+ // force id for IE. otherwise embedded Flash object cannot be returned
 1289+ if (!p.id && document.all) {
 1290+ p.id = "_" + ("" + Math.random()).substring(5);
 1291+ }
 1292+
 1293+ if (p.id) {
 1294+ html += ' id="' + p.id + '"';
 1295+ }
 1296+
 1297+ html += '>';
 1298+
 1299+ // sometimes ie fails to load flash if it's on cache
 1300+ if (document.all) {
 1301+ p.src += ((p.src.indexOf("?") != -1 ? "&" : "?") + Math.random());
 1302+ }
 1303+
 1304+ html += '\n\t<param name="movie" value="'+ p.src +'" />';
 1305+
 1306+ var e = extend({}, p);
 1307+ e.id = e.width = e.height = e.src = null;
 1308+
 1309+ for (var k in e) {
 1310+ if (e[k] !== null) {
 1311+ html += '\n\t<param name="'+ k +'" value="'+ e[k] +'" />';
 1312+ }
 1313+ }
 1314+
 1315+ if (c) {
 1316+ html += '\n\t<param name="flashvars" value=\'' + concatVars(c) + '\' />';
 1317+ }
 1318+
 1319+ if (embeddable) {
 1320+ html += getEmbedCode(p, c);
 1321+ }
 1322+
 1323+ html += "</object>";
 1324+
 1325+ return html;
 1326+}
 1327+
 1328+function getFullHTML(p, c) {
 1329+ return getObjectCode(p, c, true);
 1330+}
 1331+
 1332+function getHTML(p, c) {
 1333+ var isNav = navigator.plugins && navigator.mimeTypes && navigator.mimeTypes.length;
 1334+ return (isNav) ? getEmbedCode(p, c) : getObjectCode(p, c);
 1335+}
 1336+
 1337+//}}}
 1338+
 1339+
 1340+window.flashembed = function(root, userParams, flashvars) {
 1341+
 1342+
 1343+//{{{ construction
 1344+
 1345+ // setup params
 1346+ var params = {
 1347+
 1348+ // very common params
 1349+ src: '#',
 1350+ width: '100%',
 1351+ height: '100%',
 1352+
 1353+ // flashembed specific options
 1354+ version:null,
 1355+ onFail:null,
 1356+ expressInstall:null,
 1357+ debug: false,
 1358+
 1359+ // flashembed defaults
 1360+ // bgcolor: 'transparent',
 1361+ allowfullscreen: true,
 1362+ allowscriptaccess: 'always',
 1363+ quality: 'high',
 1364+ type: 'application/x-shockwave-flash',
 1365+ pluginspage: 'http://www.adobe.com/go/getflashplayer'
 1366+ };
 1367+
 1368+
 1369+ if (typeof userParams == 'string') {
 1370+ userParams = {src: userParams};
 1371+ }
 1372+
 1373+ extend(params, userParams);
 1374+
 1375+ var version = flashembed.getVersion();
 1376+ var required = params.version;
 1377+ var express = params.expressInstall;
 1378+ var debug = params.debug;
 1379+
 1380+
 1381+ if (typeof root == 'string') {
 1382+ var el = document.getElementById(root);
 1383+ if (el) {
 1384+ root = el;
 1385+ } else {
 1386+ domReady(function() {
 1387+ flashembed(root, userParams, flashvars);
 1388+ });
 1389+ return;
 1390+ }
 1391+ }
 1392+
 1393+ if (!root) { return; }
 1394+
 1395+
 1396+ // is supported
 1397+ if (!required || flashembed.isSupported(required)) {
 1398+ params.onFail = params.version = params.expressInstall = params.debug = null;
 1399+
 1400+ // root.innerHTML may cause broplems: http://domscripting.com/blog/display/99
 1401+ // thanks to: Ryan Rud
 1402+ // var tmp = document.createElement("extradiv");
 1403+ // tmp.innerHTML = getHTML();
 1404+ // root.appendChild(tmp);
 1405+
 1406+ root.innerHTML = getHTML(params, flashvars);
 1407+
 1408+ // return our API
 1409+ return root.firstChild;
 1410+
 1411+ // custom fail event
 1412+ } else if (params.onFail) {
 1413+ var ret = params.onFail.call(params, flashembed.getVersion(), flashvars);
 1414+ if (ret === true) { root.innerHTML = ret; }
 1415+
 1416+
 1417+ // express install
 1418+ } else if (required && express && flashembed.isSupported([6,65])) {
 1419+
 1420+ extend(params, {src: express});
 1421+
 1422+ flashvars = {
 1423+ MMredirectURL: location.href,
 1424+ MMplayerType: 'PlugIn',
 1425+ MMdoctitle: document.title
 1426+ };
 1427+
 1428+ root.innerHTML = getHTML(params, flashvars);
 1429+
 1430+ // not supported
 1431+ } else {
 1432+
 1433+ // minor bug fixed here 08.04.2008 (thanks JRodman)
 1434+
 1435+ if (root.innerHTML.replace(/\s/g, '') !== '') {
 1436+ // custom content was supplied
 1437+
 1438+ } else {
 1439+ root.innerHTML =
 1440+ "<h2>Flash version " + required + " or greater is required</h2>" +
 1441+ "<h3>" +
 1442+ (version[0] > 0 ? "Your version is " + version : "You have no flash plugin installed") +
 1443+ "</h3>" +
 1444+ "<p>Download latest version from <a href='" + params.pluginspage + "'>here</a></p>";
 1445+ }
 1446+ }
 1447+
 1448+ return root;
 1449+
 1450+//}}}
 1451+
 1452+
 1453+};
 1454+
 1455+
 1456+//{{{ static methods
 1457+
 1458+extend(window.flashembed, {
 1459+
 1460+ // returns arr[major, fix]
 1461+ getVersion: function() {
 1462+
 1463+ var version = [0, 0];
 1464+
 1465+ if (navigator.plugins && typeof navigator.plugins["Shockwave Flash"] == "object") {
 1466+ var _d = navigator.plugins["Shockwave Flash"].description;
 1467+ if (typeof _d != "undefined") {
 1468+ _d = _d.replace(/^.*\s+(\S+\s+\S+$)/, "$1");
 1469+ var _m = parseInt(_d.replace(/^(.*)\..*$/, "$1"), 10);
 1470+ var _r = /r/.test(_d) ? parseInt(_d.replace(/^.*r(.*)$/, "$1"), 10) : 0;
 1471+ version = [_m, _r];
 1472+ }
 1473+
 1474+ } else if (window.ActiveXObject) {
 1475+
 1476+ try { // avoid fp 6 crashes
 1477+ var _a = new ActiveXObject("ShockwaveFlash.ShockwaveFlash.7");
 1478+
 1479+ } catch(e) {
 1480+ try {
 1481+ _a = new ActiveXObject("ShockwaveFlash.ShockwaveFlash.6");
 1482+ version = [6, 0];
 1483+ _a.AllowScriptAccess = "always"; // throws if fp < 6.47
 1484+
 1485+ } catch(ee) {
 1486+ if (version[0] == 6) { return; }
 1487+ }
 1488+ try {
 1489+ _a = new ActiveXObject("ShockwaveFlash.ShockwaveFlash");
 1490+ } catch(eee) {
 1491+
 1492+ }
 1493+
 1494+ }
 1495+
 1496+ if (typeof _a == "object") {
 1497+ _d = _a.GetVariable("$version"); // bugs in fp 6.21 / 6.23
 1498+ if (typeof _d != "undefined") {
 1499+ _d = _d.replace(/^\S+\s+(.*)$/, "$1").split(",");
 1500+ version = [parseInt(_d[0], 10), parseInt(_d[2], 10)];
 1501+ }
 1502+ }
 1503+ }
 1504+
 1505+ return version;
 1506+ },
 1507+
 1508+ isSupported: function(version) {
 1509+ var now = flashembed.getVersion();
 1510+ var ret = (now[0] > version[0]) || (now[0] == version[0] && now[1] >= version[1]);
 1511+ return ret;
 1512+ },
 1513+
 1514+ domReady: domReady,
 1515+
 1516+ // returns a String representation from JSON object
 1517+ asString: asString,
 1518+
 1519+ getHTML: getHTML,
 1520+
 1521+ getFullHTML: getFullHTML
 1522+
 1523+});
 1524+
 1525+//}}}
 1526+
 1527+
 1528+// setup jquery support
 1529+if (jQ) {
 1530+
 1531+ jQuery.prototype.flashembed = function(params, flashvars) {
 1532+ return this.each(function() {
 1533+ flashembed(this, params, flashvars);
 1534+ });
 1535+ };
 1536+
 1537+}
 1538+
 1539+})();
 1540+
 1541+/************************************************
 1542+********* mv_embed extension to flowplayer.js ***
 1543+************************************************/
 1544+var flashEmbed = {
 1545+ instanceOf:'flashEmbed',
 1546+ monitorTimerId : 0,
 1547+ old_pid:0,
 1548+ startedTimedPlayback:false,
 1549+ supports: {
 1550+ 'play_head':true,
 1551+ 'pause':true,
 1552+ 'stop':true,
 1553+ //'fullscreen':true,
 1554+ 'time_display':true,
 1555+ //'volume_control':true,
 1556+ 'overlay':false,
 1557+ 'fullscreen':false
 1558+ },
 1559+ getEmbedHTML: function (){
 1560+ setTimeout('document.getElementById(\''+this.id+'\').postEmbedJS()', 150);
 1561+ return this.wrapEmebedContainer( this.getEmbedObj() );
 1562+ },
 1563+ getEmbedObj:function(){
 1564+ /*return '<a href="' + this.media_element.selected_source.getURI(this.seek_time_sec) +'" '+
 1565+ 'style="display:block;width:' + this.width + 'px;height:' + this.height + 'px" '+
 1566+ 'id="' + this.pid + '"> rewrite me'+
 1567+ '</a>';*/
 1568+ //give the embed element a unique pid (work around for flowplayer persistence)
 1569+ if( this.old_pid!=0 ){
 1570+ this.pid = this.pid +'_'+ this.old_pid;
 1571+ }
 1572+ return '<a '+
 1573+ 'href="'+ this.media_element.selected_source.getURI( this.seek_time_sec ) + '" '+
 1574+ 'style="display:block;width:' + parseInt(this.width) + 'px;height:' + parseInt(this.height) + 'px" '+
 1575+ 'id="'+this.pid+'">'+
 1576+ '</a>';
 1577+ },
 1578+ postEmbedJS: function()
 1579+ {
 1580+ var _this = this;
 1581+ js_log('embedFlow: uri:'+ _this.media_element.selected_source.getURI(this.seek_time_sec)
 1582+ +' '+ mv_embed_path + 'flowplayer/flowplayer-3.0.1.swf' ) ;
 1583+ var flowConfig = {
 1584+ clip: {
 1585+ url: _this.media_element.selected_source.getURI(this.seek_time_sec),
 1586+ // when this is false playback does not start until play button is pressed
 1587+ autoPlay: true
 1588+ },
 1589+ plugins: {
 1590+ controls: {
 1591+ all: false,
 1592+ fullscreen: true,
 1593+ backgroundColor: 'transparent',
 1594+ backgroundGradient: 'none',
 1595+ autoHide:'always',
 1596+ top:'95%',
 1597+ right:'0px'
 1598+ }
 1599+ }
 1600+ };
 1601+
 1602+ $f(this.pid, mv_embed_path + 'flowplayer/flowplayer-3.0.1.swf', flowConfig);
 1603+ //get the this.fla value:
 1604+ this.getFLA();
 1605+ //set up bindings (for when interacting with the swf causes action:
 1606+ this.fla.onPause(function(){
 1607+ _this.parent_pause(); //update the interface
 1608+ })
 1609+ this.fla.onResume( function(){
 1610+ _this.parent_play(); //update the interface
 1611+ });
 1612+ //start monitor:
 1613+ this.monitor();
 1614+ this.old_pid++;
 1615+ },
 1616+ /* js hooks/controls */
 1617+ play: function(){
 1618+ this.getFLA();
 1619+ //update play/pause button etc
 1620+ this.parent_play();
 1621+ if( this.fla ){
 1622+ this.fla.play();
 1623+ setTimeout('$j(\'#'+this.id+'\').get(0).monitor()', 250);
 1624+ }
 1625+ },
 1626+ toggleMute: function(){
 1627+ parent_toggleMute();
 1628+ this.getFLA();
 1629+ if(this.fla){
 1630+ if(this.muted){
 1631+
 1632+ }else{
 1633+
 1634+ }
 1635+ }
 1636+ },
 1637+ fullscreen:function(){
 1638+ if(this.fla){
 1639+ this.fla.fullscreen();
 1640+ }else{
 1641+ js_log('must be playing before you can go fullscreen');
 1642+ }
 1643+ },
 1644+ pause : function()
 1645+ {
 1646+ this.getFLA();
 1647+ this.parent_pause();
 1648+ js_log("Flash:Pause: " + this.fla.isPaused() );
 1649+ if( this.fla['pause'] ){
 1650+ if( ! this.fla.isPaused() ){
 1651+ js_log('calling plugin pause');
 1652+ this.fla.pause();
 1653+ }
 1654+ }
 1655+ },
 1656+ monitor : function()
 1657+ {
 1658+ //do monitor update:
 1659+ if( ! this.monitorTimerId ){
 1660+ if(document.getElementById(this.id)){
 1661+ this.monitorTimerId = setInterval('$j(\'#'+this.id+'\').get(0).monitor()', 250);
 1662+ }
 1663+ }
 1664+
 1665+ var flash_state = this.fla.getStatus();
 1666+ if( typeof flash_state == 'undefined' ){
 1667+ var flash_state = {
 1668+ "time" : this.fla.getTime()
 1669+ };
 1670+ js_log('got time: ' + flash_state.time);
 1671+ }else{
 1672+ //simplification of buffer state ... should move to support returning time rages like:
 1673+ //http://www.whatwg.org/specs/web-apps/current-work/#normalized-timeranges-object
 1674+ this.bufferedPercent = flash_state.bufferEnd / this.getDuration();
 1675+ }
 1676+
 1677+ //set the current Time (based on timeFormat)
 1678+ if( this.media_element.selected_source.timeFormat =='anx' ){
 1679+ this.currentTime = flash_state.time;
 1680+ //js_log('set buffer: ' + flash_state.bufferEnd + ' at time: ' + flash_state.time +' of total dur: ' + this.getDuration());
 1681+ }else{
 1682+ this.currentTime = flash_state.time + this.media_element.selected_source.start_offset;
 1683+ //stop buffering if greater than the duration:
 1684+ if( flash_state.bufferEnd > this.getDuration() + 5 ){
 1685+ //js_log('should stop buffering (does not seem to work)' + flash_state.bufferEnd + ' > dur: ' + this.getDuration() );
 1686+ this.fla.stopBuffering();
 1687+ }
 1688+ }
 1689+
 1690+ var end_ntp = (this.media_element.selected_source.end_ntp)?
 1691+ this.media_element.selected_source.end_ntp : seconds2ntp(0);
 1692+ var start_ntp = this.media_element.selected_source.start_ntp;
 1693+
 1694+ if(this.currentTime > ntp2seconds(start_ntp) && !this.startedTimedPlayback){
 1695+ this.startedTimedPlayback=true;
 1696+ js_log("time is "+ this.currentTime + " started playback");
 1697+ }
 1698+ /* to support local seeks */
 1699+ if(this.currentTime > 1 && this.seek_time_sec != 0 && !this.media_element.selected_source.supports_url_time_encoding)
 1700+ {
 1701+ js_log('flashEmbed: _local_ Seeking to ' + this.seek_time_sec);
 1702+ this.fla.seek( this.seek_time_sec );
 1703+ this.seek_time_sec = 0;
 1704+ }
 1705+
 1706+ //flash is giving bogus duration get from "this" (if available)
 1707+ /*if(!this.media_element.selected_source.end_ntp && this.fla.getDuration()>0)
 1708+ this.media_element.selected_source.setDuration(this.fla.getDuration());
 1709+ */
 1710+
 1711+ if(!this.userSlide){
 1712+ if((this.currentTime - ntp2seconds(start_ntp))<0){
 1713+ this.setStatus('buffering...');
 1714+ }else{
 1715+ this.setStatus( seconds2ntp(this.currentTime) + '/' + end_ntp);
 1716+ this.setSliderValue((this.currentTime - ntp2seconds(start_ntp)) / (ntp2seconds(end_ntp)-ntp2seconds(start_ntp)) );
 1717+ }
 1718+ }
 1719+
 1720+ //checks to see if we reached the end of playback:
 1721+ if(this.startedTimedPlayback &&
 1722+ ( this.currentTime > (ntp2seconds(end_ntp)+1)
 1723+ ||
 1724+ ( this.currentTime > (ntp2seconds(end_ntp)-1)
 1725+ && this.prevTime == this.currentTime) )
 1726+ ){
 1727+ js_log('probbaly reached end of stream: '+this.currentTime);
 1728+ this.onClipDone();
 1729+ }
 1730+ this.prevTime = this.currentTime;
 1731+ //js_log('cur perc loaded: ' + this.fla.getPercentLoaded() +' cur time : ' + (this.currentTime - ntp2seconds(start_ntp)) +' / ' +(ntp2seconds(end_ntp)-ntp2seconds(start_ntp)));
 1732+ },
 1733+ // get the embed fla object
 1734+ getFLA : function (){
 1735+ this.fla = $f(this.pid);
 1736+ },
 1737+ stop : function(){
 1738+ js_log('f:flashEmbed:stop');
 1739+ this.startedTimedPlayback=false;
 1740+ if (this.monitorTimerId != 0 )
 1741+ {
 1742+ clearInterval(this.monitorTimerId);
 1743+ this.monitorTimerId = 0;
 1744+ }
 1745+ if(this.fla)
 1746+ this.fla.unload();
 1747+ this.parent_stop();
 1748+ },
 1749+ onStop: function(){
 1750+ js_log('f:onStop');
 1751+ //stop updates:
 1752+ if( this.monitorTimerId != 0 )
 1753+ {
 1754+ clearInterval(this.monitorTimerId);
 1755+ this.monitorTimerId = 0;
 1756+ }
 1757+ },
 1758+ onClipDone: function(){
 1759+ js_log('f:flash:onClipDone');
 1760+ if( ! this.startedTimedPlayback){
 1761+ js_log('clip done before timed playback started .. not good. (ignoring) ');
 1762+ //keep monitoring:
 1763+ this.monitor();
 1764+ }else{
 1765+ js_log('clip done and '+ this.startedTimedPlayback);
 1766+ //stop the clip if its not stopped already:
 1767+ this.stop();
 1768+ this.setStatus("Clip Done...");
 1769+ //run the onClip done action:
 1770+ this.parent_onClipDone();
 1771+ }
 1772+ }
 1773+}
Property changes on: trunk/extensions/MetavidWiki/skins/mv_embed/libEmbedObj/mv_flashEmbed.js
___________________________________________________________________
Added: svn:mergeinfo
Added: svn:eol-style
11774 + native
Index: trunk/extensions/MetavidWiki/skins/mv_embed/libEmbedObj/mv_javaEmbed.js
@@ -0,0 +1,84 @@
 2+var javaEmbed = {
 3+ instanceOf:'javaEmbed',
 4+ supports: {'play_head':true, 'pause':true, 'stop':true, 'fullscreen':true, 'time_display':true, 'volume_control':true},
 5+ getEmbedHTML : function (){
 6+ if(this.controls)
 7+ setTimeout('document.getElementById(\''+this.id+'\').postEmbedJS()', 150);
 8+ //set a default duration of 30 seconds: cortao should detect duration.
 9+ return this.wrapEmebedContainer( this.getEmbedObj() );
 10+ },
 11+ getEmbedObj:function(){
 12+ if(!this.duration)this.duration=30;
 13+ if(mv_java_iframe){
 14+ //make sure iframe and embed path match (java security model)
 15+ var iframe_src='';
 16+ var src = this.media_element.selected_source.getURI();
 17+ //make url absolute:
 18+ if(src[0]=='/'){
 19+ //js_log('java: media relative path from:'+ document.URL);
 20+ var pURL=parseUri(document.URL);
 21+ src= pURL.protocol + '://' + pURL.authority + src;
 22+ }else if(src.indexOf('://')===-1){
 23+ //js_log('java: media relative file');
 24+ var pURL=parseUri(document.URL);
 25+ src= pURL.protocol + '://' + pURL.authority + pURL.directory + src;
 26+ }
 27+ js_log('java media url: '+ src);
 28+ var parent_domain='';
 29+ if(parseUri(mv_embed_path).host != parseUri(src).host){
 30+ iframe_src = parseUri(src).protocol + '://'+
 31+ parseUri(src).authority +
 32+ mv_media_iframe_path + 'cortado_iframe.php';
 33+ parent_domain = '&parent_domain='+parseUri(mv_embed_path).host;
 34+ }else{
 35+ iframe_src = mv_embed_path + 'cortado_iframe.php';
 36+ }
 37+ //js_log('base iframe src:'+ iframe_src);
 38+ iframe_src+= "?media_url=" + src + '&id=' + this.pid;
 39+ iframe_src+= "&width=" + this.width + "&height=" + this.height;
 40+ iframe_src+= "&duration=" + this.duration;
 41+ iframe_src+=parent_domain;
 42+ return '<iframe id="iframe_'+this.pid+'" width="'+this.width+'" height="'+this.height+'" '+
 43+ 'frameborder=0 scrolling=no marginwidth=0 marginheight=0 ' +
 44+ 'src = "'+ iframe_src + '"></iframe>';
 45+ }else{
 46+ //load directly in the page..
 47+ // (media must be on the same server or applet must be signed)
 48+ return ''+
 49+ '<applet id="'+this.pid+'" code="com.fluendo.player.Cortado.class" archive="cortado-ovt-stripped_r34336.jar" width="'+this.width+'" height="'+this.height+'"> '+ "\n"+
 50+ '<param name="url" value="'+this.media_element.selected_source.src+'" /> ' + "\n"+
 51+ '<param name="local" value="false"/>'+ "\n"+
 52+ '<param name="keepaspect" value="true" />'+ "\n"+
 53+ '<param name="video" value="true" />'+"\n"+
 54+ '<param name="audio" value="true" />'+"\n"+
 55+ '<param name="seekable" value="true" />'+"\n"+
 56+ '<param name="duration" value="'+this.duration+'" />'+"\n"+
 57+ '<param name="bufferSize" value="200" />'+"\n"+
 58+ '</applet>';
 59+ }
 60+ },
 61+ postEmbedJS:function(){
 62+ this.getJCE();
 63+ },
 64+ //get java cortado embed object
 65+ getJCE:function(){
 66+ if(!mv_java_iframe){
 67+ this.jce = $j('#'+this.pid).get(0);
 68+ }else{
 69+ //set via iframe refrence:
 70+ //(does not work even if we set window.domain on the remote iframe)
 71+ //this.jce = $j('#iframe_'+this.pid).get(0).contentDocument.getElementById(this.pid);
 72+ }
 73+ },
 74+ pause:function(){
 75+ this.stop();
 76+ },
 77+ currentTime:function(){
 78+ if(typeof this.jce != 'undefined' ){
 79+ if(typeof this.jce.getPlayPosition != 'undefined' ){
 80+ return this.jce.getPlayPosition();
 81+ }
 82+ }
 83+ return '0';
 84+ }
 85+}
Property changes on: trunk/extensions/MetavidWiki/skins/mv_embed/libEmbedObj/mv_javaEmbed.js
___________________________________________________________________
Added: svn:mergeinfo
Added: svn:eol-style
186 + native
Index: trunk/extensions/MetavidWiki/skins/mv_embed/libEmbedObj/mv_oggplayEmbed.js
@@ -0,0 +1,252 @@
 2+/*
 3+ * oggPlay embed
 4+ * plugin: http://www.annodex.net/software/plugin/index.html
 5+ * javascript refrence: http://wiki.xiph.org/index.php/OggPlayJavascriptAPI
 6+ */
 7+var oggplayEmbed = {
 8+ instanceOf:'oggplayEmbed',
 9+ pl_aqueue:Array(),
 10+ pl_pqueue:Array(),
 11+ start_pos:0,
 12+ getEmbedHTML:function(){
 13+ var controls_html='';
 14+ //setup the interface controls if requested
 15+ if(this.controls){
 16+ /*for the ogg playhead we need scriptaculus/prototype */
 17+ //try and get the interface
 18+ if( this.get_interface_lib(true) ){
 19+ js_log('interface loaded');
 20+ controls_html =this.getControlsHtml('all');
 21+ controls_html+='<div style="clear:both;">';
 22+ }else{
 23+ //if not present, it's loading
 24+ return 'loading interface <blink>...</blink>';
 25+ }
 26+ }
 27+ setTimeout('document.getElementById(\''+this.id+'\').postEmbedJS()', 150);
 28+ return this.wrapEmebedContainer(this.getEmbedObj() ) + controls_html;
 29+ },
 30+ getEmbedObj:function(){
 31+ return '<embed type="application/liboggplay" ' +
 32+ 'id="'+this.pid + '" ' +
 33+ 'src="'+this.media_element.selected_source.getURI(this.seek_time_sec)+'" '+
 34+ 'width="'+this.width+'" height="'+this.height+'">' +
 35+ '</embed>';
 36+ },
 37+ postEmbedJS:function(){
 38+ this.getOggElement();
 39+ if(this.controls){
 40+ setTimeout('document.getElementById(\''+this.id+'\').monitor()',250);
 41+ }
 42+ //check if in playlist mode:
 43+ if(this.pc){
 44+ var plObj = this.pc.pp;
 45+ var _this = this;
 46+
 47+ //register a callback for next clip:
 48+ this.ogg.registerPlaylistCallback(
 49+ {
 50+ call:function(){document.getElementById(plObj.id).playlistNext();}
 51+ }
 52+ );
 53+
 54+ //js_log('current pl pos:'+this.ogg.getCurrentPlaylistPosition() );
 55+ //load up the playlist inserting on either side of the current clip
 56+ $j.each(plObj.tracks[0].clips, function(i, clip){
 57+ if(i < plObj.cur_clip.order){
 58+ //js_log('insert before:'+ clip.src);
 59+ _this.insertMovieBefore(clip.src);
 60+ }else if(i > plObj.cur_clip.order){
 61+ //js_log('insert after:'+ clip.src);
 62+ _this.appendMovie(clip.src);
 63+ }
 64+ });
 65+ //js_log('current pl pos:'+this.ogg.getCurrentPlaylistPosition() );
 66+ //js_log('current pl length:'+this.ogg.getPlaylistLength() );
 67+ //append/insert any clips that the user added (before the ogg object was ready)
 68+ while(this.pl_aqueue.length!=0){
 69+ this.appendMovie(this.pl_aqueue.pop() );
 70+ }
 71+ while(this.pl_pqueue.length!=0){
 72+ this.insertMovieBefore(this.pl_pqueue.pop() );
 73+ }
 74+ }
 75+ //update the duration
 76+ this.getDuration();
 77+ },
 78+ monitor:function(){
 79+ if(this.ogg){
 80+ //js_log('state:' + this.ogg.getCurrentState());
 81+ if(this.ogg){
 82+ switch(this.ogg.getCurrentState()){
 83+ //paused
 84+ case 0:
 85+ this.onPaused();
 86+ break;
 87+ //plaing
 88+ case 1:
 89+ this.onPlaying();
 90+ break;
 91+ //finished
 92+ case 2:
 93+ this.onStop();
 94+ //assume reached the end:
 95+ break;
 96+ }
 97+ }
 98+ }
 99+ if(!this.monitorTimerId ){
 100+ this.monitorTimerId = setInterval('document.getElementById(\''+this.id+'\').monitor()', 250);
 101+ }
 102+ },
 103+ onPlaying:function(){
 104+ var mediaLen = this.ogg.getMovieLength();
 105+ if( mediaLen > 0 )
 106+ {
 107+ // seekable media
 108+ //as long as the user is not interacting with the playhead update:
 109+ if(! this.userSlide){
 110+ var start_offset=this.start_offset;
 111+ //if in playlist mode make sure we have the right start_offset:
 112+ if(this.pc)
 113+ start_offset = this.pc.pp.cur_clip.embed.start_offset;
 114+
 115+ var oog_position = (this.ogg.getPlayPosition()-start_offset) / this.duration;
 116+ //js_log('current pos: ' + this.ogg.getPlayPosition() + '-' +start_offset+' /'+ this.ogg.getMovieLength() + ' =' + oog_position);
 117+ this.setSliderValue(oog_position);
 118+ this.setStatus(this.getTimeInfo());
 119+ }else{
 120+ //update info to seek to:
 121+ this.setStatus('seek to: ' + seconds2ntp( (this.start_offset /1000)+
 122+ Math.round((this.sliderVal*mediaLen)/1000) ));
 123+ }
 124+ }else{
 125+ //@@todo find out if movie is buffering or live stream
 126+ this.setStatus(innerHTML = 'buffering<blink>...</blink>');
 127+ }
 128+ },
 129+ getTimeInfo:function(){
 130+ return seconds2ntp(Math.round(this.ogg.getPlayPosition() / 1000) )+
 131+ "/" + seconds2ntp(Math.round(this.duration+this.start_offset) / 1000);
 132+ },
 133+ doSeek:function(v){
 134+ var mediaLen = this.ogg.getMovieLength();
 135+ js_log('seek to: '+v+' in ntp:' + seconds2ntp(Math.round( (v*mediaLen)/1000) ) );
 136+ var mediaLen = this.ogg.getMovieLength();
 137+ //usto need: this.start_offset
 138+ this.ogg.setPlayPosition( v*mediaLen );
 139+ //js_log('seeking to: '+( v*mediaLen)+ ' of ' +mediaLen );
 140+ this.setStatus('seeking<blink>...</blink>');
 141+ },
 142+ onPaused:function(){
 143+ //document.getElementById("PlayOrPause").value = " Play ";
 144+ },
 145+ onStop:function(){
 146+ if(this.controls){
 147+ this.setSliderValue(0);
 148+ this.setStatus("-:--:--/-:--:--");
 149+ }
 150+ //call the stop to (reload the thumbnail)
 151+ //document.getElementById("PlayOrPause").value = " Play ";
 152+ //document.getElementById("PlayOrPause").disabled = false;
 153+ },
 154+ getDuration:function(){
 155+ //trust the url more than (getMovieLength) for anx content
 156+ if(this.parent_getDuration()==null){
 157+ //make sure the ogg is ready:
 158+ if(!this.thumbnail_disp){
 159+ this.getOggElement();
 160+ if(this.ogg){
 161+ this.duration = this.ogg.getMovieLength();
 162+ }else{
 163+ this.duration=null;
 164+ }
 165+ }
 166+ }
 167+ return this.duration;
 168+ },
 169+ getOggElement:function(){
 170+ if(document.getElementById(this.pid)){
 171+ this.ogg = this.getPluginEmbed();
 172+ }else{
 173+ this.ogg=null;
 174+ }
 175+ js_log('this.ogg: '+ this.ogg);
 176+ },
 177+ playlistPrev:function(){
 178+ if(this.ogg){
 179+ this.ogg.playlistPrev();
 180+ }
 181+ },
 182+ playlistNext:function(){
 183+ if(this.ogg){
 184+ this.ogg.playlistNext();
 185+ //update the start_offset value:
 186+ this.getDuration();
 187+ }
 188+ },
 189+ insertMovieBefore:function(url, pos){
 190+ if(url){
 191+ if(this.ogg){
 192+ if(!pos)var pos = this.ogg.getCurrentPlaylistPosition();
 193+ this.ogg.insertMovieBefore(pos, url);
 194+ }else{
 195+ this.pl_pqueue.push(url);
 196+ }
 197+ }
 198+ },
 199+ //append the url if this.ogg is present else put it in the plqueue
 200+ appendMovie:function(url){
 201+ if(url){
 202+ if(this.ogg){
 203+ this.ogg.appendMovie(url);
 204+ }else{
 205+ this.pl_aqueue.push(url);
 206+ }
 207+ }
 208+ },
 209+ playMovieAt:function(pos){
 210+ this.getOggElement();
 211+ if(this.ogg){
 212+ js_log('ogg.playMovieAT');
 213+ this.ogg.playMovieAt(pos);
 214+ }else{
 215+ js_log('this.play');
 216+ this.start_pos = pos;
 217+ this.play();
 218+ }
 219+ },
 220+ play:function (){
 221+ this.getOggElement();
 222+ if(!this.ogg || this.thumbnail_disp){
 223+ this.parent_play();
 224+ }else{
 225+ //if finished restart
 226+ if(this.ogg.getCurrentState()==2){
 227+ this.ogg.restart();
 228+ //if paused:play
 229+ }else if(this.ogg.getCurrentState()==0){
 230+ this.ogg.play();
 231+ }
 232+ this.paused=false;
 233+ }
 234+ //update the duration
 235+ this.getDuration();
 236+ },
 237+ pause:function(){
 238+ this.ogg.pause();
 239+ },
 240+ stop: function(){
 241+ js_log('oggplay stop:' + this.thumbnail_disp);
 242+ if(!this.thumbnail_disp){
 243+ if( this.monitorTimerId != 0 )
 244+ {
 245+ clearInterval(this.monitorTimerId);
 246+ this.monitorTimerId = 0;
 247+ }
 248+ //do a full stop ( swap out the embed code)
 249+ this.onStop();
 250+ this.parent_stop();
 251+ }
 252+ }
 253+}
\ No newline at end of file
Property changes on: trunk/extensions/MetavidWiki/skins/mv_embed/libEmbedObj/mv_oggplayEmbed.js
___________________________________________________________________
Added: svn:mergeinfo
Added: svn:eol-style
1254 + native
Index: trunk/extensions/MetavidWiki/skins/mv_embed/libEmbedObj/mv_htmlEmbed.js
@@ -0,0 +1,171 @@
 2+/*
 3+ * used to embed HTML as a movie clip
 4+ * for use with mv_playlist SMIL additions
 5+ * (we make assumptions about this.pc (parent clip) being available)
 6+ */
 7+var pcHtmlEmbedDefaults={
 8+ 'dur':4 //default duration of 4seconds
 9+}
 10+var htmlEmbed ={
 11+ supports: {
 12+ 'play_head':true,
 13+ 'pause':true,
 14+ 'fullscreen':false,
 15+ 'time_display':true,
 16+ 'volume_control':true,
 17+
 18+ 'overlays':true,
 19+ 'playlist_swap_loader':true //if the object supports playlist functions
 20+ },
 21+ ready_to_play:true,
 22+ pauseTime:0,
 23+ currentTime:0,
 24+ start_offset:0,
 25+ monitorTimerId:false,
 26+ play:function(){
 27+ //call the parent
 28+ this.parent_play();
 29+
 30+ js_log('f:play: htmlEmbedWrapper');
 31+ var ct = new Date();
 32+ this.clockStartTime = ct.getTime();
 33+
 34+ //start up monitor:
 35+ this.monitor();
 36+ },
 37+ stop:function(){
 38+ this.pause();
 39+ //window.clearInterval( this.monitorTimerId );
 40+ },
 41+ pause:function(){
 42+ js_log('f:pause: htmlEmbedWrapper');
 43+ var ct = new Date();
 44+ this.pauseTime = this.currentTime;
 45+ js_log('pause time: '+ this.pauseTime);
 46+
 47+ window.clearInterval( this.monitorTimerId );
 48+ },
 49+ //monitor just needs to keep track of time (do it at frame rate time) .
 50+ monitor:function(){
 51+ //js_log('html:monitor: '+ this.currentTime);
 52+ var ct = new Date();
 53+ this.currentTime =( ( ct.getTime() - this.clockStartTime )/1000 ) +this.pauseTime;
 54+ var ct = new Date();
 55+ //js_log('mvPlayList:monitor trueTime: '+ this.currentTime);
 56+
 57+ if( ! this.monitorTimerId ){
 58+ if(document.getElementById(this.id)){
 59+ if( !MV_ANIMATION_CB_RATE )
 60+ var MV_ANIMATION_CB_RATE= 33;
 61+ this.monitorTimerId = window.setInterval('$j(\'#'+this.id+'\').get(0).monitor()', 250);
 62+ }
 63+ }
 64+ },
 65+ //set up minimal media_element emulation:
 66+ media_element:{
 67+ autoSelectSource:function(){
 68+ return true;
 69+ },
 70+ selectedPlayer:{
 71+ library:"html"
 72+ },
 73+ selected_source:{
 74+ supports_url_time_encoding:true
 75+ }
 76+ },
 77+ inheritEmbedObj:function(){
 78+ return true;
 79+ },
 80+ renderTimelineThumbnail:function( options ){
 81+ //generate a scaled down version _that_ we can clone if nessisary
 82+ //add a not vissiable container to the body:
 83+ var do_refresh = (typeof options['refresh'] != 'undefined')?true:false;
 84+
 85+ var thumb_render_id = this.id +'_thumb_render_'+ options.height;
 86+ if( $j('#' + thumb_render_id ).length == 0 || do_refresh ){
 87+ //set the font scale down percentage: (kind of arbitrary)
 88+ var scale_perc = options.width / this.pc.pp.width;
 89+ //js_log('scale_perc:'+options.width + ' / '+ $j(this).width()+ ' = '+scale_perc );
 90+ //min scale font percent of 70 (overflow is hidden)
 91+ var font_perc = ( Math.round( scale_perc*100 ) < 80 )?80:Math.round( scale_perc*100 );
 92+ var thumb_class = (typeof options['thumb_class'] !='undefined')? options['thumb_class'] : '';
 93+
 94+ $j('body').append( '<div id="' + thumb_render_id + '" style="display:none">'+
 95+ '<div class="' + thumb_class + '" '+
 96+ 'style="width:'+options.width+'px;height:'+options.height+'px;" >'+
 97+ this.getThumbnailHTML() +
 98+ '</div>'+
 99+ '</div>'
 100+ );
 101+ //scale down the fonts:
 102+ $j('#' + thumb_render_id + ' *').filter('span,div,p,h,h1,h2,h3,h4,h5,h6').css('font-size',font_perc+'%')
 103+
 104+ //replace out links:
 105+ $j('#' + thumb_render_id +' a').each(function(){
 106+ $j(this).replaceWith("<span>" + $j(this).html() + "</span>");
 107+ });
 108+
 109+ //scale images that have width or height:
 110+ $j('#' + thumb_render_id + ' img').filter('[width]').each(function(){
 111+ $j(this).attr({
 112+ 'width': Math.round( $j(this).attr('width') * scale_perc ),
 113+ 'height': Math.round( $j(this).attr('height') * scale_perc )
 114+ }
 115+ );
 116+ });
 117+ }
 118+ return $j('#' + thumb_render_id ).html();
 119+ },
 120+ //nothing to update in static html display: (return a static representation)
 121+ //@@todo render out a mini text "preview"
 122+ updateThumbTime:function( float_time ){
 123+ return ;
 124+ },
 125+ getEmbedHTML:function(){
 126+ js_log('f:html:getEmbedHTML: ' + this.id);
 127+ //set up the css for our parent div:
 128+ $j(this).css({'width':this.pc.pp.width, 'height':this.pc.pp.height, 'overflow':"hidden"});
 129+ //@@todo support more smil animation layout stuff:
 130+
 131+ //wrap output in videoPlayer_ div:
 132+ $j(this).html('<div id="videoPlayer_'+ this.id+'">'+this.getThumbnailHTML()+'</div>');
 133+ },
 134+ getThumbnailHTML:function(){
 135+ var out='';
 136+ if( this.pc.type =='image/jpeg'){
 137+ js_log('should put src: '+this.pc.src);
 138+ out = '<img width="'+this.pc.pp.width+'" height="'+this.pc.pp.height+'" src="'+this.pc.src+'">';
 139+ }else{
 140+ out = this.pc.wholeText;
 141+ }
 142+ //js_log('f:getThumbnailHTML: got thumb: '+out);
 143+ return out;
 144+ },
 145+ doThumbnailHTML:function(){
 146+ js_log('f:htmlEmbed:doThumbnailHTML');
 147+ this.getEmbedHTML();
 148+ },
 149+ /* since its just html display get the "embed" right away */
 150+ getHTML:function(){
 151+ js_log('getHTML: htmlEmbed');
 152+ this.getEmbedHTML();
 153+ },
 154+ getDuration:function(){
 155+ if(this.pc.dur)
 156+ return this.pc.dur;
 157+ //return default value:
 158+ return pcHtmlEmbedDefaults.dur;
 159+ },
 160+ updateVideoTime:function(start_ntp, end_ntp){
 161+ //since we don't really have timeline for html elements just take the delta and set it as the duration
 162+ this.pc.dur = ntp2seconds(end_ntp) - ntp2seconds(start_ntp);
 163+ },
 164+ //gives a chance to make any nesseary external requests
 165+ //@@todo we can "start loading images" if we want
 166+ on_dom_swap:function(){
 167+ this.loading_external_data=false
 168+ this.ready_to_play=true;
 169+ debugger;
 170+ return ;
 171+ }
 172+}
\ No newline at end of file
Property changes on: trunk/extensions/MetavidWiki/skins/mv_embed/libEmbedObj/mv_htmlEmbed.js
___________________________________________________________________
Added: svn:eol-style
1173 + native
Index: trunk/extensions/MetavidWiki/skins/mv_embed/libEmbedObj/mv_vlcEmbed.js
@@ -0,0 +1,331 @@
 2+/*
 3+* vlc embed based on: http://people.videolan.org/~damienf/plugin-0.8.6.html
 4+* javascript api: http://www.videolan.org/doc/play-howto/en/ch04.html
 5+* assume version > 0.8.5.1
 6+*/
 7+var vlcEmbed = {
 8+ instanceOf:'vlcEmbed',
 9+ supports: {'play_head':true,
 10+ 'pause':true,
 11+ 'stop':true,
 12+ 'fullscreen':true,
 13+ 'time_display':true,
 14+ 'volume_control':false,
 15+
 16+ 'playlist_driver':true, //if the object supports playlist functions
 17+ 'overlay':false
 18+ },
 19+ //init vars:
 20+ monitorTimerId : 0,
 21+ prevState : 0,
 22+ currentTime:0,
 23+ duration:0,
 24+ userSlide:false,
 25+ pejs_count:0, //post embed js count
 26+
 27+ getEmbedHTML: function(){
 28+ //give VLC 150ms to initialize before we start playback
 29+ //@@todo should be able to do this as an ready event
 30+ this.pejs_count=0;
 31+ setTimeout('document.getElementById(\''+this.id+'\').postEmbedJS()', 150);
 32+ return this.getEmbedObj();
 33+ },
 34+ getEmbedObj:function(){
 35+ return '<object classid="clsid:9BE31822-FDAD-461B-AD51-BE1D1C159921" '+
 36+ 'codebase="http://downloads.videolan.org/pub/videolan/vlc/latest/win32/axvlc.cab#Version=0,8,6,0" '+
 37+ 'id="'+this.pid+'" events="True" height="'+this.height+'" width="'+this.width+'">'+
 38+ '<param name="MRL" value="">'+
 39+ '<param name="ShowDisplay" value="True">'+
 40+ '<param name="AutoLoop" value="False">'+
 41+ '<param name="AutoPlay" value="False">'+
 42+ '<param name="Volume" value="50">'+
 43+ '<param name="StartTime" value="0">'+
 44+ '<embed pluginspage="http://www.videolan.org" type="application/x-vlc-plugin" '+
 45+ 'progid="VideoLAN.VLCPlugin.2" name="'+this.pid+'" height="'+this.height+'" width="'+this.width+'">'+
 46+ '</object>';
 47+ },
 48+
 49+ /*
 50+ * some java script to start vlc playback after the embed:
 51+ */
 52+ postEmbedJS: function(){
 53+ //load a pointer to the vlc into the object (this.vlc)
 54+ this.getVLC();
 55+ if( this.vlc.log ){
 56+ //manipulate the dom object to make sure vlc has the correct size:
 57+ this.vlc.style.width=this.width;
 58+ this.vlc.style.height=this.height;
 59+ this.vlc.playlist.items.clear();
 60+ //@@todo if client supports seeking no need to send seek_offset to URI
 61+ js_log('vlc play::' + this.media_element.selected_source.getURI( this.seek_time_sec ));
 62+ var itemId = this.vlc.playlist.add( this.media_element.selected_source.getURI(this.seek_time_sec) );
 63+ if( itemId != -1 ){
 64+ //play
 65+ this.vlc.playlist.playItem(itemId);
 66+ }else{
 67+ js_log("error:cannot play at the moment !");
 68+ }
 69+ //if controls enabled start up javascript interface and monitor:
 70+ if(this.controls){
 71+ //activate the slider: scriptaculus based)
 72+ //this.activateSlider();
 73+ //start doing status updates every 1/10th of a second
 74+ }
 75+ setTimeout('$j(\'#'+this.id+'\').get(0).monitor()',100);
 76+ }else{
 77+ js_log('postEmbedJS:vlc not ready');
 78+ this.pejs_count++;
 79+ if( this.pejs_count < 10 ){
 80+ setTimeout('document.getElementById(\''+this.id+'\').postEmbedJS()',100);
 81+ }else{
 82+ js_log('vlc never ready');
 83+ }
 84+ }
 85+ },
 86+ /* //disable local seeking (while we don't know what we have avaliable)
 87+ doSeek : function(value){
 88+ if( this.vlc ) {
 89+ if( (this.vlc.input.state == 3) && (this.vlc.input.position != value) )
 90+ {
 91+ this.vlc.input.position = value;
 92+ this.setStatus( 'seeking...' );
 93+ }
 94+ }
 95+ },*/
 96+ playMovieAt: function (order){
 97+ //@@todo add clips to playlist after (order) and then play
 98+ this.play();
 99+ },
 100+ /*
 101+ * updates the status time
 102+ */
 103+ monitor: function(){
 104+ this.getVLC();
 105+ if(this.vlc.log){
 106+ //js_log( 'state:' + this.vlc.input.state);
 107+ //js_log('time: ' + this.vlc.input.time);
 108+ //js_log('pos: ' + this.vlc.input.position);
 109+ if( this.vlc.log.messages.count > 0 ){
 110+ // there is one or more messages in the log
 111+ var iter = this.vlc.log.messages.iterator();
 112+ while( iter.hasNext ){
 113+ var msg = iter.next();
 114+ var msgtype = msg.type.toString();
 115+ if( (msg.severity == 1) && (msgtype == "input") )
 116+ {
 117+ js_log( msg.message );
 118+ }
 119+ }
 120+ // clear the log once finished to avoid clogging
 121+ this.vlc.log.messages.clear();
 122+ }
 123+ var newState = this.vlc.input.state;
 124+ if( this.prevState != newState ){
 125+ if( newState == 0 )
 126+ {
 127+ // current media has stopped
 128+ this.onStop();
 129+ //assume we reached the end: (since it was not a js call to stop)
 130+ this.onClipDone();
 131+ }
 132+ else if( newState == 1 )
 133+ {
 134+ // current media is opening/connecting
 135+ this.onOpen();
 136+ }
 137+ else if( newState == 2 )
 138+ {
 139+ // current media is buffering data
 140+ this.onBuffer();
 141+ }
 142+ else if( newState == 3 )
 143+ {
 144+ // current media is now playing
 145+ this.onPlay();
 146+ }
 147+ else if( this.vlc.input.state == 4 )
 148+ {
 149+ // current media is now paused
 150+ this.onPause();
 151+ }
 152+ this.prevState = newState;
 153+ }else if( newState == 3 ){
 154+ // current media is playing
 155+ this.onPlaying();
 156+ }
 157+ }
 158+ //do monitor update:
 159+ if( ! this.monitorTimerId ){
 160+ if(document.getElementById(this.id)){
 161+ this.monitorTimerId = setInterval('document.getElementById(\''+this.id+'\').monitor()', 250);
 162+ }
 163+ }
 164+ },
 165+/* events */
 166+ onOpen: function(){
 167+ this.setStatus("Opening...");
 168+ //document.getElementById("info_"+this.id).innerHTML = "Opening...";
 169+ //document.getElementById("PlayOrPause").disabled = true;
 170+ //document.getElementById("Stop").disabled = false;
 171+ },
 172+ onBuffer: function(){
 173+ this.setStatus("Buffering...");
 174+ //document.getElementById("info_"+this.id).innerHTML = "Buffering...";
 175+ //document.getElementById("PlayOrPause").disabled = true;
 176+ //document.getElementById("Stop").disabled = false;
 177+ },
 178+ onPlay: function(){
 179+ //document.getElementById("PlayOrPause").value = "Pause";
 180+ //document.getElementById("PlayOrPause").disabled = false;
 181+ //document.getElementById("Stop").disabled = false;
 182+ this.onPlaying();
 183+ },
 184+ liveFeedRoll: 0,
 185+ onPlaying: function(){
 186+ if(this.seek_time_sec != 0 && !this.media_element.selected_source.supports_url_time_encoding)
 187+ {
 188+ // VLC seems to have a problem seeking into the future this way
 189+ var ms_difference = this.seek_time_sec * 1000 - this.vlc.input.time;
 190+ if(ms_difference <= 0)
 191+ {
 192+ js_log('Seeking to ' + this.seek_time_sec);
 193+ this.vlc.input.time = this.seek_time_sec * 1000;
 194+ this.vlc.input.rate=1.0;
 195+ this.seek_time_sec = 0;
 196+ }
 197+ else if (this.vlc.input.rate == 1.0)
 198+ {
 199+ var rate = Math.max(2, ms_difference / 500)
 200+ js_log('setting rate to: ' + rate);
 201+ this.vlc.input.rate=rate;
 202+ }
 203+ }
 204+ //for now trust the duration from url over vlc input.length
 205+ if(!this.media_element.selected_source.end_ntp && this.vlc.input.length>0)
 206+ {
 207+ js_log('setting duration to ' + this.vlc.input.length /1000);
 208+ this.media_element.selected_source.setDuration(this.vlc.input.length /1000);
 209+ }
 210+
 211+ this.duration = (this.getDuration())?this.getDuration():this.vlc.input.length /1000;
 212+ /*if(this.duration!=this.vlc.input.length /1000){
 213+ this.duration = this.vlc.input.length /1000;
 214+ }*/
 215+ //update the currentTime attribute
 216+ if( this.media_element.selected_source.timeFormat =='anx' ){
 217+ this.currentTime = this.vlc.input.time/1000;
 218+ //js_log('set buffer: ' + flash_state.bufferEnd + ' at time: ' + flash_state.time +' of total dur: ' + this.getDuration());
 219+ }else{
 220+ this.currentTime = (this.vlc.input.time/1000) + this.media_element.selected_source.start_offset;
 221+ }
 222+ if( this.duration > 0 || this.vlc.input.time > 0){
 223+ this.start_offset=this.media_element.selected_source.start_offset;
 224+
 225+ //if we have media duration proceed
 226+ if(this.duration){
 227+ //as long as the user is not interacting with the playhead update:
 228+ if(! this.userSlide){
 229+ //slider pos is not accurate with flash:
 230+ if(this.vlc.input.position!=0 && this.media_element.selected_source.mime_type!='video/x-flv'){
 231+ /*js_log(' set slider via input.position: ' +
 232+ this.media_element.selected_source.mime_type + ' pos:'+ this.vlc.input.position);
 233+ */
 234+ this.setSliderValue(this.vlc.input.position);
 235+ }else{
 236+ //set via time:
 237+ /*js_log('t:' +(this.vlc.input.time/1000) +' - so:'+this.start_offset+
 238+ ' set slider:' + ((this.vlc.input.time/1000)-this.start_offset) + ' / ' + this.duration +
 239+ ' ='+ ((this.vlc.input.time/1000)-this.start_offset)/this.duration );
 240+ */
 241+ this.setSliderValue( ((this.vlc.input.time/1000) -this.start_offset) / this.duration);
 242+ }
 243+ //js_log('set status: '+ seconds2ntp(this.currentTime) + ' e:'+seconds2ntp(this.duration+this.start_offset));
 244+ this.setStatus(seconds2ntp(this.currentTime) + '/' + seconds2ntp(this.duration+this.start_offset) );
 245+ }
 246+ }
 247+ }else{
 248+ //@@todo hide playhead remove the slider (its a live stream)
 249+ this.setStatus('live');
 250+ }
 251+ },
 252+ onPause: function(){
 253+ this.parent_pause(); //update the inteface if paused via native control
 254+ },
 255+ onStop: function(){
 256+ //
 257+ // disable logging
 258+ this.vlc.log.verbosity = -1;
 259+ //document.getElementById("Stop").disabled = true;
 260+ if(this.controls){
 261+ this.setSliderValue(0);
 262+ this.setStatus("-:--:--/-:--:--");
 263+ }
 264+ //stop updates:
 265+ if( this.monitorTimerId != 0 )
 266+ {
 267+ clearInterval(this.monitorTimerId);
 268+ this.monitorTimerId = 0;
 269+ }
 270+ //document.getElementById("PlayOrPause").value = " Play ";
 271+ //document.getElementById("PlayOrPause").disabled = false;
 272+ },
 273+ /* js hooks/controls */
 274+ play : function(){
 275+ js_log('f:vlcPlay');
 276+ this.getVLC();
 277+ //call the parent
 278+ this.parent_play();
 279+ if( this.vlc ){
 280+ //plugin is already being present send play call:
 281+ // clear the message log and enable error logging
 282+ this.vlc.log.verbosity = 1;
 283+ this.vlc.log.messages.clear();
 284+ this.vlc.playlist.play();
 285+ this.monitor();
 286+ this.paused=false;
 287+ }
 288+ },
 289+ stop : function(){
 290+ js_log(this.vlc);
 291+ if(typeof this.vlc != 'undefined' ){
 292+ if(typeof this.vlc.playlist != 'undefined'){
 293+ this.vlc.playlist.stop();
 294+ if( this.monitorTimerId != 0 )
 295+ {
 296+ clearInterval(this.monitorTimerId);
 297+ this.monitorTimerId = 0;
 298+ }
 299+ }
 300+ }
 301+ //this.onStop();
 302+ //do parent stop
 303+ this.parent_stop();
 304+ },
 305+ pause : function(){
 306+ this.parent_pause(); //update the inteface if paused via native control
 307+ this.vlc.playlist.togglePause();
 308+ },
 309+ fullscreen : function(){
 310+ if(this.vlc){
 311+ if(this.vlc.video)
 312+ this.vlc.video.toggleFullscreen();
 313+ }
 314+ },
 315+ /* returns current time in float seconds
 316+ * as per html5 we should just have an attribute by name of CurrentTime
 317+ * http://www.whatwg.org/specs/web-apps/current-work/#currenttime
 318+ currentTime : function(){
 319+ if(typeof this.vlc != 'undefined' ){
 320+ if(typeof this.vlc.input != 'undefined' ){
 321+ return this.vlc.input.time/1000;
 322+ }
 323+ }
 324+ return '0';
 325+ },
 326+ */
 327+ // get the embed vlc object
 328+ getVLC : function(){
 329+ this.vlc = this.getPluginEmbed();
 330+ }
 331+}
 332+
Property changes on: trunk/extensions/MetavidWiki/skins/mv_embed/libEmbedObj/mv_vlcEmbed.js
___________________________________________________________________
Added: svn:mergeinfo
Added: svn:eol-style
1333 + native
Index: trunk/extensions/MetavidWiki/skins/mv_embed/libEmbedObj/mv_nativeEmbed.js
@@ -0,0 +1,172 @@
 2+//native embed library:
 3+var nativeEmbed = {
 4+ instanceOf:'nativeEmbed',
 5+ canPlayThrough:false,
 6+ grab_try_count:0,
 7+ supports: {
 8+ 'play_head':true,
 9+ 'pause':true,
 10+ 'fullscreen':false,
 11+ 'time_display':true,
 12+ 'volume_control':true,
 13+
 14+ 'overlays':true,
 15+ 'playlist_swap_loader':true //if the object supports playlist functions
 16+ },
 17+ getEmbedHTML : function (){
 18+ var embed_code = this.getEmbedObj();
 19+ js_log('embed code: ' + embed_code);
 20+ js_log("DURATION: "+ this.getDuration() );
 21+ return this.wrapEmebedContainer( embed_code);
 22+
 23+ setTimeout('$j(\'#'+this.id+'\').get(0).postEmbedJS()', 150);
 24+ },
 25+ getEmbedObj:function(){
 26+ //we want to let mv_embed handle the controls so notice the absence of control attribute
 27+ // controls=false results in controls being displayed:
 28+ //http://lists.whatwg.org/pipermail/whatwg-whatwg.org/2008-August/016159.html
 29+ js_log("play url:" + this.getURI( this.seek_time_sec ));
 30+ return '<video ' +
 31+ 'id="'+this.pid + '" ' +
 32+ 'style="width:'+this.width+'px;height:'+this.height+'px;" ' +
 33+ 'width="'+this.width+'" height="'+this.height+'" '+
 34+ 'src="' + this.media_element.selected_source.getURI( this.seek_time_sec ) + '" ' +
 35+ 'oncanplaythrough="$j(\'#'+this.id+'\').get(0).oncanplaythrough();return false;" ' +
 36+ 'onloadedmetadata="$j(\'#'+this.id+'\').get(0).onloadedmetadata();return false;" ' +
 37+ 'loadedmetadata="$j(\'#'+this.id+'\').get(0).onloadedmetadata();return false;" ' +
 38+ 'onended="$j(\'#'+this.id+'\').get(0).onended();return false;" >' +
 39+ '</video>';
 40+ },
 41+ //@@todo : loading progress
 42+ postEmbedJS:function(){
 43+ this.getVID();
 44+ if(typeof this.vid != 'undefined'){
 45+ js_log("GOT video object sending PLAY()");
 46+ this.vid.play();
 47+ //this.vid.load(); //does not seem to work so well
 48+ setTimeout('$j(\'#'+this.id+'\').get(0).monitor()',100);
 49+ }else{
 50+ js_log('could not grab vid obj trying again:' + typeof this.vid);
 51+ this.grab_try_count++;
 52+ if( this.grab_count == 10 ){
 53+ js_log(' could not get vid object after 10 tries re-run: getEmbedObj()' ) ;
 54+ //reload the dom:
 55+ this.grab_try_count=0;
 56+ this.getEmbedObj();
 57+ }else{
 58+ setTimeout('$j(\'#'+this.id+'\').get(0).postEmbedJS()',100);
 59+ }
 60+ }
 61+ },
 62+ monitor : function(){
 63+ //js_log('native:monitor');
 64+ this.getVID(); //make shure we have .vid obj
 65+ if(!this.vid){
 66+ js_log('could not find video embed: '+this.id + ' stop monitor');
 67+ this.stopMonitor();
 68+ return false;
 69+ }
 70+ //js_log('time loaded: ' + this.vid.TimeRanges );
 71+ //js_log('current time: '+ this.vid.currentTime + ' dur: ' + this.duration);
 72+
 73+ //update duration if not set (for now trust the getDuration more than this.vid.duration
 74+ this.duration =(this.getDuration())?this.getDuration():this.vid.duration;
 75+
 76+ //update currentTime
 77+ this.currentTime = this.vid.currentTime;
 78+
 79+ //update the start offset:
 80+ if(!this.start_offset)
 81+ this.start_offset=this.media_element.selected_source.start_offset;
 82+
 83+ //don't update status if we are not the current clip
 84+ if(this.pc){
 85+ if(this.pc.pp.cur_clip.id != this.pc.id)
 86+ return true;
 87+ }
 88+
 89+ //only update the interface if controls have been included:
 90+ if( this.currentTime > 0 ){
 91+ if(!this.userSlide){
 92+ if(this.currentTime > this.duration){//we are likely viewing a annodex stream add in offset
 93+ this.setSliderValue((this.currentTime-this.start_offset)/this.duration);
 94+ this.setStatus( seconds2ntp(this.currentTime) + '/'+ seconds2ntp(this.start_offset+this.duration ));
 95+ }else{
 96+ this.setSliderValue(this.currentTime/this.duration );
 97+ this.setStatus( seconds2ntp(this.currentTime) + '/'+ seconds2ntp(this.duration ));
 98+ }
 99+ }
 100+ }
 101+ //update load progress if nessisary f
 102+ if( ! this.monitorTimerId ){
 103+ if(document.getElementById(this.id)){
 104+ this.monitorTimerId = setInterval('$j(\'#'+this.id+'\').get(0).monitor()', 250);
 105+ }
 106+ }
 107+ },
 108+ /*
 109+ * native callbacks for the video tag:
 110+ */
 111+ oncanplaythrough : function(){
 112+ js_log("f:oncanplaythrough start playback");
 113+ //this.play();
 114+ },
 115+ onloadedmetadata: function(){
 116+ js_log('f:onloadedmetadata get duration: ' +this.vid.duration);
 117+ //this.
 118+ },
 119+ onloadedmetadata: function(){
 120+ js_log('f:onloadedmetadata metadata ready');
 121+ //set the clip duration
 122+ },
 123+ onended:function(){
 124+ //clip "ended"
 125+ js_log('f:onended ');
 126+ //stop monitor
 127+ this.stopMonitor();
 128+ this.stop();
 129+ },
 130+ stopMonitor:function(){
 131+ if( this.monitorTimerId != 0 )
 132+ {
 133+ clearInterval(this.monitorTimerId);
 134+ this.monitorTimerId = 0;
 135+ }
 136+ },
 137+ pause : function(){
 138+ this.getVID();
 139+ this.parent_pause(); //update interface
 140+ if(this.vid){
 141+ this.vid.pause();
 142+ }
 143+ //stop updates:
 144+ this.stopMonitor();
 145+ },
 146+ play:function(){
 147+ this.getVID();
 148+ this.parent_play(); //update interface
 149+ if( this.vid ){
 150+ this.vid.play();
 151+ //re-start the monitor:
 152+ this.monitor();
 153+ }
 154+ },
 155+ playMovieAt:function(order){
 156+ js_log('f:playMovieAt '+order);
 157+ this.play();
 158+ },
 159+ // get the embed vlc object
 160+ getVID : function (){
 161+ this.vid = $j('#'+this.pid).get(0);
 162+ },
 163+ /*
 164+ * playlist driver
 165+ * mannages native playlist calls
 166+ */
 167+ playlistNext:function(){
 168+ if(!this.pc){//make sure we are a clip
 169+ //
 170+
 171+ }
 172+ }
 173+}
\ No newline at end of file
Property changes on: trunk/extensions/MetavidWiki/skins/mv_embed/libEmbedObj/mv_nativeEmbed.js
___________________________________________________________________
Added: svn:mergeinfo
Added: svn:eol-style
1174 + native
Index: trunk/extensions/MetavidWiki/skins/mv_embed/libEmbedObj/mv_quicktimeEmbed.js
@@ -0,0 +1,82 @@
 2+//any plugin specific msg:
 3+gMsg['ogg-no-xiphqt']='You do not appear to have the XiphQT component for QuickTime. QuickTime cannot play ' +
 4+ 'Ogg files without this component. Please ' +
 5+ '<a href="http://www.mediawiki.org/wiki/Extension:OggHandler/Client_download">download XiphQT</a> or choose another player.';
 6+
 7+var quicktimeEmbed = {
 8+ instanceOf:'quicktimeEmbed',
 9+ qtTimers:{},
 10+ getEmbedHTML : function (){
 11+ var controls_html ='';
 12+ js_log('embedObj control is: '+this.controls);
 13+ if(this.controls){
 14+ controls_html+= this.getControlsHtml('stop');
 15+ //if in playlist mode get prev/next and run postEmbedJS():
 16+ if(this.pc){
 17+ controls_html+= this.pc.pp.getPLControls();
 18+ setTimeout('document.getElementById(\''+this.id+'\').postEmbedJS()', 150);
 19+ }
 20+ }
 21+ return this.wrapEmebedContainer( this.getEmbedObj() )+ controls_html;
 22+ },
 23+ getEmbedObj:function(){
 24+ var controllerHeight = 16; // by observation
 25+ var extraAttribs = '';
 26+ if ( embedTypes.playerType == 'quicktime-activex' ) {
 27+ extraAttribs = 'classid="clsid:02BF25D5..."';
 28+ }
 29+ // Poll for completion
 30+ var this_ = this;
 31+ this.qtTimers[this.pid] = window.setInterval( this.makeQuickTimePollFunction(), 500 );
 32+
 33+ return "<div><object id=" + this.pid +
 34+ " type='video/quicktime'" +
 35+ " width=" + this.width +
 36+ " height=" + this.height + controllerHeight +
 37+
 38+ // See http://svn.wikimedia.org/viewvc/mediawiki?view=rev&revision=25605
 39+ " data=" + this.hq( this.extPathUrl + '/null_file.mov' ) +
 40+ ' ' + extraAttribs +
 41+ ">" +
 42+ // Scale, don't clip
 43+ "<param name='SCALE' value='Aspect'/>" +
 44+ "<param name='AUTOPLAY' value='True'/>" +
 45+ "<param name='src' value=" + mv_embed_path + 'null_file.mov' + "/>" +
 46+ "<param name='QTSRC' value=" + this.media_element.selected_source.getURI(this.seek_time_sec) + "/>" +
 47+ "</object></div>";
 48+ },
 49+ makeQuickTimePollFunction : function ( ) {
 50+ var this_ = this;
 51+ return function () {
 52+ var videoElt = document.getElementById( this_.pid );
 53+ if ( videoElt ) {
 54+ // Detect XiphQT (may throw)
 55+ var xiphQtVersion = false, done = false;
 56+ js_log('try quicktime: getComponent:');
 57+ try {
 58+ xiphQtVersion = videoElt.GetComponentVersion('imdc','XiTh', 'Xiph');
 59+ done = true;
 60+ } catch ( e ) {}
 61+ js_log('done with try');
 62+ if ( done ) {
 63+ window.clearInterval( this_.qtTimers[this_.pid] );
 64+ if ( !xiphQtVersion || xiphQtVersion == '0.0' ) {
 65+ $j(this_).html(getMsg('ogg-no-xiphqt'));
 66+ /*var div = document.createElement( 'div' );
 67+ div.className = 'ogg-player-options';
 68+ div.style.cssText = 'width:' + ( params.width - 10 ) + 'px;'
 69+ div.innerHTML = this_.getMsg( 'ogg-no-xiphqt' );
 70+ var optionsDiv = document.getElementById( params.id + '_options_box' );
 71+ if ( optionsDiv ) {
 72+ elt.insertBefore( div, optionsDiv.parentNode );
 73+ } else {
 74+ elt.appendChild( div );
 75+ }*/
 76+ }
 77+ // Disable autoplay on back button
 78+ //this_.setParam( videoElt, 'AUTOPLAY', 'False' );
 79+ }
 80+ }
 81+ };
 82+ },
 83+}
Property changes on: trunk/extensions/MetavidWiki/skins/mv_embed/libEmbedObj/mv_quicktimeEmbed.js
___________________________________________________________________
Added: svn:mergeinfo
Added: svn:eol-style
184 + native
Property changes on: trunk/extensions/MetavidWiki/skins/mv_embed/libEmbedObj
___________________________________________________________________
Added: svn:mergeinfo
Index: trunk/extensions/MetavidWiki/skins/mv_embed/libTimedText/mv_timed_text.js
@@ -0,0 +1,441 @@
 2+// text interface object (for inline display captions)
 3+var textInterface = function( parentEmbed ){
 4+ return this.init( parentEmbed );
 5+}
 6+textInterface.prototype = {
 7+ text_lookahead_time:0,
 8+ body_ready:false,
 9+ default_time_range: "source", //by default just use the source don't get a time-range
 10+ transcript_set:null,
 11+ autoscroll:true,
 12+ scrollTimerId:0,
 13+ init:function( parentEmbed ){
 14+ //init a new availableTracks obj:
 15+ this.availableTracks={};
 16+ //set the parent embed object:
 17+ this.pe=parentEmbed;
 18+ //parse roe if not already done:
 19+ this.getTimedTextTracks();
 20+ },
 21+ //@@todo separate out data loader & data display
 22+ getTimedTextTracks:function(){
 23+ js_log("load timed text from roe: "+ this.pe.roe);
 24+ var _this = this;
 25+ //if roe not yet loaded do load it:
 26+ if(this.pe.roe){
 27+ if(!this.pe.media_element.addedROEData){
 28+ js_log("load roe data!");
 29+ $j('#mv_txt_load_'+_this.pe.id).show(); //show the loading icon
 30+ do_request( _this.pe.roe, function(data)
 31+ {
 32+ //continue
 33+ _this.pe.media_element.addROE(data);
 34+ _this.getParseTimedText_rowReady();
 35+ });
 36+ }else{
 37+ js_log('row data ready (no roe request)');
 38+ _this.getParseTimedText_rowReady();
 39+ }
 40+ }else{
 41+ if( this.pe.media_element.timedTextSources() ){
 42+ _this.getParseTimedText_rowReady();
 43+ }else{
 44+ js_log('no roe data or timed text sources');
 45+ }
 46+ }
 47+ },
 48+ getParseTimedText_rowReady: function (){
 49+ var _this = this;
 50+ //create timedTextObj
 51+ var default_found=false;
 52+ js_log("mv_txt_load_:SHOW mv_txt_load_");
 53+ $j('#mv_txt_load_'+_this.pe.id).show(); //show the loading icon
 54+
 55+ $j.each( this.pe.media_element.sources, function(inx, source){
 56+
 57+ if( typeof source.id == 'undefined' || source.id == null ){
 58+ source.id = 'tt_' + inx;
 59+ }
 60+ var tObj = new timedTextObj( source );
 61+ //make sure its a valid timed text format (we have not loaded or parsed yet) : (
 62+ if( tObj.lib != null ){
 63+ js_log('adding Track: ' + source.id + ' to ' + _this.pe.id);
 64+ _this.availableTracks[ source.id ] = tObj;
 65+ //js_log( 'is : ' + source.id + ' default: ' + source.default );
 66+ //display if requested:
 67+ if( source['default'] == "true" ){
 68+ //we did set at least one track by default tag
 69+ default_found=true;
 70+ js_log('do load timed text: ' + source.id );
 71+ _this.loadAndDisplay( source.id );
 72+ }else{
 73+ //don't load the track and don't display
 74+ }
 75+ }
 76+ });
 77+
 78+ //no default clip found take the first_id
 79+ if(!default_found){
 80+ $j.each( _this.availableTracks, function(inx, sourceTrack){
 81+ _this.loadAndDisplay( sourceTrack.id );
 82+ default_found=true;
 83+ //retun after loading first available
 84+ return false;
 85+ });
 86+ }
 87+
 88+ //if nothing found anywhere update the loading icon to say no tracks found
 89+ if(!default_found)
 90+ $j('#mv_txt_load_'+_this.pe.id).html( getMsg('no_text_tracks_found') );
 91+
 92+
 93+ },
 94+ loadAndDisplay: function ( track_id){
 95+ var _this = this;
 96+ $j('#mv_txt_load_'+_this.pe.id).show();//show the loading icon
 97+ _this.availableTracks[ track_id ].load(_this.default_time_range, function(){
 98+ $j('#mv_txt_load_'+_this.pe.id).hide();
 99+ _this.addTrack( track_id );
 100+ });
 101+ },
 102+ addTrack: function( track_id ){
 103+ js_log('f:displayTrack:'+ track_id);
 104+ var _this = this;
 105+ //set the display flag to true:
 106+ _this.availableTracks[ track_id ].display=true;
 107+ //setup the layout:
 108+ this.setup_layout();
 109+ js_log("SHOULD ADD: "+ track_id + ' count:' + _this.availableTracks[ track_id ].textNodes.length);
 110+ $j.each(_this.availableTracks[ track_id ].textNodes, function(inx, text_clip){
 111+ _this.add_merge_text_clip( text_clip );
 112+ });
 113+ },
 114+ add_merge_text_clip: function(text_clip){
 115+ var _this = this;
 116+ //make sure the clip does not already exist:
 117+ if($j('#tc_'+text_clip.id).length==0){
 118+ var inserted = false;
 119+ var text_clip_start_time = ntp2seconds( text_clip.start );
 120+
 121+ var insertHTML = '<div style="border:solid thin black;" id="tc_'+text_clip.id+'" ' +
 122+ 'start="'+text_clip.start+'" end="'+text_clip.end+'" class="mvtt tt_'+text_clip.type_id+'">' +
 123+ '<div class="mvttseek" style="top:0px;left:0px;right:0px;height:20px;font-size:small">'+
 124+ '<img style="display:inline;" src="'+mv_embed_path+'/images/control_play_blue.png">'+
 125+ text_clip.start + ' to ' +text_clip.end+
 126+ '</div>'+
 127+ text_clip.body +
 128+ '</div>';
 129+ //js_log("ADDING CLIP: " + text_clip_start_time + ' html: ' + insertHTML);
 130+ $j('#mmbody_'+this.pe.id +' .mvtt').each(function(){
 131+ if(!inserted){
 132+ //js_log( ntp2seconds($j(this).attr('start')) + ' > ' + text_clip_start_time);
 133+ if( ntp2seconds($j(this).attr('start')) > text_clip_start_time){
 134+ inserted=true;
 135+ $j(this).before(insertHTML);
 136+ }
 137+ }
 138+ });
 139+ //js_log('should just add to end: '+insertHTML);
 140+ if(!inserted){
 141+ $j('#mmbody_'+this.pe.id ).append(insertHTML);
 142+ }
 143+
 144+ //apply the mouse over transcript seek/click functions:
 145+ $j(".mvttseek").click( function() {
 146+ _this.pe.play();
 147+ });
 148+ $j(".mvttseek").hoverIntent({
 149+ interval:200, //polling interval
 150+ timeout:200, //delay before onMouseOut
 151+ over:function () {
 152+ js_log('mvttseek: over');
 153+ $j(this).parent().addClass('tt_highlight');
 154+ //do section highlight
 155+ _this.pe.highlightPlaySection( {
 156+ 'start' : $j(this).parent().attr("start"),
 157+ 'end' : $j(this).parent().attr("end")
 158+ });
 159+ },
 160+ out:function () {
 161+ js_log('mvttseek: out');
 162+ $j(this).parent().removeClass('tt_highlight');
 163+ //de highlight section
 164+ _this.pe.hideHighlight();
 165+ }
 166+ }
 167+ );
 168+ }
 169+ },
 170+ setup_layout:function(){
 171+ //check if we have already loaded the menu/body:
 172+ if($j('#tt_mmenu_'+this.pe.id).length==0){
 173+ $j('#metaBox_'+this.pe.id).html(
 174+ this.getMenu() +
 175+ this.getBody()
 176+ );
 177+ }
 178+ },
 179+ show:function(){
 180+ //setup layout if not already done:
 181+ this.setup_layout();
 182+ //display the interface if not already displayed:
 183+ $j('#metaBox_'+this.pe.id).fadeIn("fast");
 184+ //start the autoscroll timer:
 185+ if( this.autoscroll )
 186+ this.setAutoScroll();
 187+ },
 188+ close:function(){
 189+ //the meta box:
 190+ $j('#metaBox_'+this.pe.id).fadeOut('fast');
 191+ //the icon link:
 192+ $j('#metaButton_'+this.pe.id).fadeIn('fast');
 193+ },
 194+ getBody:function(){
 195+ return '<div id="mmbody_'+this.pe.id+'" ' +
 196+ 'style="position:absolute;top:20px;left:0px;' +
 197+ 'right:0px;bottom:0px;' +
 198+ 'height:'+(this.pe.height-20)+
 199+ 'px;overflow:auto;"><span style="display:none;" id="mv_txt_load_' + this.pe.id + '">'+
 200+ getMsg('loading_txt')+'</span>' +
 201+ '</div>';
 202+ },
 203+ getTsSelect:function(){
 204+ var _this = this;
 205+ js_log('getTsSelect');
 206+ var selHTML = '<div id="mvtsel_' + this.pe.id + '" style="position:absolute;background:#FFF;top:20px;left:0px;right:0px;bottom:0px;overflow:auto;">';
 207+ selHTML+='<b>' + getMsg('select_transcript_set') + '</b><ul>';
 208+ //debugger;
 209+ for(var i in _this.availableTracks){ //for in loop ok on object
 210+ var checked = ( _this.availableTracks[i].display ) ? 'checked' : '';
 211+ selHTML+='<li><input name="'+i+'" class="mvTsSelect" type="checkbox" ' + checked + '>'+
 212+ _this.availableTracks[i].getTitle() + '</li>';
 213+ }
 214+ selHTML+='</ul>' +
 215+ '<a href="#" onClick="document.getElementById(\'' + this.pe.id + '\').textInterface.applyTsSelect();return false;">'+getMsg('close')+'</a>'+
 216+ '</div>';
 217+ $j('#metaBox_'+_this.pe.id).append( selHTML );
 218+ },
 219+ applyTsSelect:function(){
 220+ var _this = this;
 221+ //update availableTracks
 222+ $j('#mvtsel_'+this.pe.id+' .mvTsSelect').each(function(){
 223+ if(this.checked){
 224+ var track_id = this.name;
 225+ //if not yet loaded now would be a good time
 226+ if(! _this.availableTracks[ track_id ].loaded ){
 227+ _this.loadAndDisplay( track_id);
 228+ }else{
 229+ _this.availableTracks[this.name].display=true;
 230+ //display the named class:
 231+ $j('#mmbody_'+_this.pe.id +' .tt_'+this.name ).fadeIn("fast");
 232+ }
 233+ }else{
 234+ if(_this.availableTracks[this.name].display){
 235+ _this.availableTracks[this.name].display=false;
 236+ //hide unchecked
 237+ $j('#mmbody_'+_this.pe.id +' .tt_'+this.name ).fadeOut("fast");
 238+ }
 239+ }
 240+ });
 241+ $j('#mvtsel_'+_this.pe.id).fadeOut("fast").remove();
 242+ },
 243+ monitor:function(){
 244+ //grab the time from the video object
 245+ var cur_time = parseInt( this.pe.currentTime );
 246+ if(cur_time!=0 && this.prevTimeScroll!=cur_time){
 247+ //search for current time: flash red border trascript
 248+ _this = this;
 249+ $j('#mmbody_'+this.pe.id +' .mvtt').each(function(){
 250+ if(ntp2seconds($j(this).attr('start')) == cur_time){
 251+ _this.prevTimeScroll=cur_time;
 252+ $j('#mmbody_'+_this.pe.id).animate({scrollTop: $j(this).get(0).offsetTop}, 'slow');
 253+ }
 254+ });
 255+ }
 256+ },
 257+ setAutoScroll:function( timer ){
 258+ var _this = this;
 259+ this.autoscroll = ( typeof timer=='undefined' )?this.autoscroll:timer;
 260+ if(this.autoscroll){
 261+ //start the timer if its not already running
 262+ if(!this.scrollTimerId){
 263+ this.scrollTimerId = setInterval('$j(\'#'+_this.pe.id+'\').get(0).textInterface.monitor()', 500);
 264+ }
 265+ //jump to the current position:
 266+ var cur_time = parseInt (this.pe.currentTime );
 267+ js_log('cur time: '+ cur_time);
 268+
 269+ _this = this;
 270+ var scroll_to_id='';
 271+ $j('#mmbody_'+this.pe.id +' .mvtt').each(function(){
 272+ if(cur_time > ntp2seconds($j(this).attr('start')) ){
 273+ _this.prevTimeScroll=cur_time;
 274+ if( $j(this).attr('id') )
 275+ scroll_to_id = $j(this).attr('id');
 276+ }
 277+ });
 278+ if(scroll_to_id != '')
 279+ $j( '#mmbody_' + _this.pe.id ).animate( { scrollTop: $j('#'+scroll_to_id).position().top } , 'slow' );
 280+ }else{
 281+ //stop the timer
 282+ clearInterval(this.scrollTimerId);
 283+ this.scrollTimerId=0;
 284+ }
 285+ },
 286+ getMenu:function(){
 287+ var out='';
 288+ //add in loading icon:
 289+ var as_checked = (this.autoscroll)?'checked':'';
 290+ out+= '<div id="tt_mmenu_'+this.pe.id+'" style="background:#AAF;font-size:small;position:absolute;top:0;height:20px;left:0px;right:0px;">' +
 291+ '<a style="font-color:#000;" title="'+getMsg('close')+'" href="#" onClick="document.getElementById(\''+this.pe.id+'\').closeTextInterface();return false;">'+
 292+ '<img border="0" width="16" height="16" src="'+mv_embed_path + 'images/cancel.png"></a> ' +
 293+ '<a style="font-color:#000;" title="'+getMsg('select_transcript_set')+'" href="#" onClick="document.getElementById(\''+this.pe.id+'\').textInterface.getTsSelect();return false;">'+
 294+ getMsg('select_transcript_set')+'</a> | ' +
 295+ '<input onClick="document.getElementById(\''+this.pe.id+'\').textInterface.setAutoScroll(this.checked);return false;" ' +
 296+ 'type="checkbox" '+as_checked +'>'+getMsg('auto_scroll');
 297+ if(this.pe.media_element.linkback){
 298+ out+=' | <a style="font-color:#000;" title="'+getMsg('improve_transcript')+'" href="'+this.pe.media_element.linkback+'" target="_new">'+
 299+ getMsg('improve_transcript')+'</a> ';
 300+ }
 301+ out+='</div>';
 302+ return out;
 303+ }
 304+}
 305+
 306+/* text format objects
 307+* @@todo allow loading from external lib set
 308+*/
 309+var timedTextObj = function( source ){
 310+ //@@todo in the future we could support timed text in oggs if they can be accessed via javascript
 311+ //we should be able to do a HEAD request to see if we can read transcripts from the file.
 312+ switch( source.mime_type ){
 313+ case 'text/cmml':
 314+ this.lib = 'CMML';
 315+ break;
 316+ case 'text/srt':
 317+ case 'text/x-srt':
 318+ this.lib = 'SRT';
 319+ break;
 320+ default:
 321+ js_log( source.mime_type + ' is not suported timed text fromat');
 322+ return ;
 323+ break;
 324+ }
 325+ //extend with the per-mime type lib:
 326+ eval('var tObj = timedText' + this.lib + ';');
 327+ for( var i in tObj ){
 328+ this[ i ] = tObj[i];
 329+ }
 330+ return this.init( source );
 331+}
 332+
 333+//base timedText object
 334+timedTextObj.prototype = {
 335+ loaded: false,
 336+ lib:null,
 337+ display: false,
 338+ textNodes:new Array(),
 339+ init: function( source ){
 340+ //copy source properties
 341+ this.source = source;
 342+ this.id = source.id;
 343+ },
 344+ getTitle:function(){
 345+ return this.source.title;
 346+ },
 347+ getSRC:function(){
 348+ return this.source.src;
 349+ }
 350+}
 351+
 352+// Specific Timed Text formats:
 353+
 354+timedTextCMML = {
 355+ load: function( range, callback ){
 356+ var _this = this;
 357+ js_log('textCMML: loading track: '+ this.src);
 358+
 359+ //:: Load transcript range ::
 360+
 361+ var pcurl = parseUri( _this.getSRC() );
 362+ var req_time = pcurl.queryKey['t'].split('/');
 363+ req_time[0]=ntp2seconds(req_time[0]);
 364+ req_time[1]=ntp2seconds(req_time[1]);
 365+ if(req_time[1]-req_time[0]> _this.request_length){
 366+ //longer than 5 min will only issue a (request 5 min)
 367+ req_time[1] = req_time[0]+_this.request_length;
 368+ }
 369+ //set up request url:
 370+ url = pcurl.protocol+'://'+pcurl.authority+pcurl.path+'?';
 371+ $j.each(pcurl.queryKey, function(key, val){
 372+ if( key != 't'){
 373+ url+=key+'='+val+'&';
 374+ }else{
 375+ url+= 't=' + seconds2ntp(req_time[0]) + '/' + seconds2ntp(req_time[1]) + '&';
 376+ }
 377+ });
 378+ do_request( url, function(data){
 379+ js_log("load track clip count:" + data.getElementsByTagName('clip').length );
 380+ _this.doParse( data );
 381+ _this.loaded=true;
 382+ callback();
 383+ });
 384+ },
 385+ doParse: function(data){
 386+ var _this = this;
 387+ $j.each(data.getElementsByTagName('clip'), function(inx, clip){
 388+ //js_log(' on clip ' + clip.id);
 389+ var text_clip = {
 390+ start: $j(clip).attr('start').replace('npt:', ''),
 391+ end: $j(clip).attr('end').replace('npt:', ''),
 392+ type_id: _this.id,
 393+ id: $j(clip).attr('id')
 394+ }
 395+ $j.each( clip.getElementsByTagName('body'), function(binx, bn ){
 396+ if(bn.textContent){
 397+ text_clip.body = bn.textContent;
 398+ }else if(bn.text){
 399+ text_clip.body = bn.text;
 400+ }
 401+ });
 402+ _this.textNodes.push( text_clip );
 403+ });
 404+ }
 405+}
 406+timedTextSRT = {
 407+ load: function( range, callback ){
 408+ var _this = this;
 409+ js_log('textSRT: loading : '+ _this.getSRC() );
 410+ do_request( _this.getSRC() , function(data){
 411+ js_log("data: " + data);
 412+ _this.doParse( data );
 413+ _this.loaded=true;
 414+ callback();
 415+ });
 416+ },
 417+ doParse:function( data ){
 418+ //split up the transcript chunks:
 419+ var tc = data.split('\n\n');
 420+ for(var s=0; s < tc.length ; s++) {
 421+ var st = tc[s].split('\n');
 422+ if(st.length >=2) {
 423+ var n = st[0];
 424+ var i = st[1].split(' --> ')[0].replace(/^\s+|\s+$/g,"");
 425+ var o = st[1].split(' --> ')[1].replace(/^\s+|\s+$/g,"");
 426+ var t = st[2];
 427+ if(st.length > 2) {
 428+ for(j=3; j<st.length;j++)
 429+ t += '\n'+st[j];
 430+ }
 431+ var text_clip = {
 432+ "start": i,
 433+ "end": o,
 434+ "type_id": this.id,
 435+ "id": this.id + '_' + n,
 436+ "body": t
 437+ }
 438+ this.textNodes.push( text_clip );
 439+ }
 440+ }
 441+ }
 442+}
\ No newline at end of file
Property changes on: trunk/extensions/MetavidWiki/skins/mv_embed/libTimedText/mv_timed_text.js
___________________________________________________________________
Added: svn:eol-style
1443 + native
Property changes on: trunk/extensions/MetavidWiki/skins/mv_embed/libTimedText
___________________________________________________________________
Added: svn:mergeinfo
Index: trunk/extensions/MetavidWiki/skins/mv_embed/libRemoteMediaSearch/mv_remote_media_search.js
@@ -0,0 +1,229 @@
 2+/*
 3+* a library for doing remote media searches
 4+*/
 5+
 6+var remoteSearchDriver = function(initObj){
 7+ return this.init( initObj );
 8+}
 9+remoteSearchDriver.prototype = {
 10+ init:function( initObj ){
 11+ //do profile check:
 12+ if( initObj.profile == 'mediawiki_edit'){
 13+
 14+ }
 15+ if( initObj.profile == 'sequence'){
 16+
 17+ }
 18+ }
 19+}
 20+
 21+
 22+var mvBaseRemoteSearch = function(initObj) {
 23+ return this.init(initObj);
 24+};
 25+mvBaseRemoteSearch.prototype = {
 26+ //default values:
 27+ thumb_width:80,
 28+
 29+ completed_req:0,
 30+ num_req:0,
 31+
 32+ result_display_mode:'box', //box or list or preview
 33+ resultsObj:{},
 34+ //init the object:
 35+ init:function( initObj ){
 36+ js_log('mvBaseRemoteSearch:init');
 37+ for(var i in initObj){
 38+ this[i] = initObj[i];
 39+ }
 40+
 41+ var _this = this;
 42+ if(this['target_submit']){
 43+ $j('#'+this['target_submit']).click(function(){
 44+ js_log('doSearch REQ');
 45+ _this.getSearchResults();
 46+ });
 47+ }
 48+
 49+ //set up bindings for interface components
 50+ //if(this['target_input'])
 51+ //@@todo autocomplete for titles
 52+
 53+ //if(this['target_results')
 54+ //@@todo error checking
 55+
 56+ //check if we are in metavid Temporal semantic media search mode
 57+ //add an "advanced search" button
 58+
 59+ //add in controls: (find a better place for these / use css)
 60+ //this seems highly verbose do do a simple control
 61+ var box_dark_url = mv_embed_path + 'skins/' + mv_skin_name + '/images/box_layout_icon_dark.png';
 62+ var box_light_url = mv_embed_path + 'skins/' + mv_skin_name + '/images/box_layout_icon.png';
 63+ var list_dark_url = mv_embed_path + 'skins/' + mv_skin_name + '/images/list_layout_icon_dark.png';
 64+ var list_light_url = mv_embed_path + 'skins/' + mv_skin_name + '/images/list_layout_icon.png';
 65+
 66+ $j('#'+this.target_submit).after('<img id="msc_box_layout" ' +
 67+ 'src = "' + ( (_this.result_display_mode=='box')?box_dark_url:box_light_url ) + '" ' +
 68+ 'style="width:20px;height:20px;cursor:pointer;"> ' +
 69+ '<img id="msc_list_layout" '+
 70+ 'src = "' + ( (_this.result_display_mode=='list')?list_dark_url:list_light_url ) + '" '+
 71+ 'style="width:20px;height:20px;cursor:pointer;">'
 72+ );
 73+
 74+ $j('#msc_box_layout').hover(function(){
 75+ $j(this).attr("src", box_dark_url );
 76+ }, function(){
 77+ $j(this).attr("src", ( (_this.result_display_mode=='box')?box_dark_url:box_light_url ) );
 78+ }).click(function(){
 79+ $j(this).attr("src", box_dark_url);
 80+ $j('#msc_list_layout').attr("src", list_light_url);
 81+ _this.setDispMode('box');
 82+ });
 83+
 84+ $j('#msc_list_layout').hover(function(){
 85+ $j(this).attr("src", list_dark_url);
 86+ }, function(){
 87+ $j(this).attr("src", ( (_this.result_display_mode=='list')?list_dark_url:list_light_url ) );
 88+ }).click(function(){
 89+ $j(this).attr("src", list_dark_url);
 90+ $j('#msc_box_layout').attr("src", box_light_url);
 91+ _this.setDispMode('list');
 92+ });
 93+
 94+ //or if we are in plain mediaWiki mode:
 95+ return this;
 96+ },
 97+ setDispMode:function(mode){
 98+ js_log('setDispMode:' + mode);
 99+ this.result_display_mode=mode;
 100+ //reformat the results:
 101+ this.formatOutputResults();
 102+ },
 103+ //check request done used for when we have multiple requests to check before formating results.
 104+ checkRequestDone:function(){
 105+ //display output if done:
 106+ this.completed_req++;
 107+ if(this.completed_req == this.num_req){
 108+ this.formatOutputResults();
 109+ }
 110+ },
 111+ formatOutputResults:function(){
 112+ js_log('f:formatOutputResults');
 113+ //debugger;
 114+ var o='';
 115+ //output results based on display mode:
 116+ for( var rInx in this.resultsObj ){
 117+ var resultItem = this.resultsObj[rInx];
 118+ if( this.result_display_mode == 'box' ){
 119+ o+='<div id="mv_result_' + rInx + '" class="mv_clip_box_result" style="width:' + this.thumb_width + 'px;">';
 120+ o+='<img style="width:' + this.thumb_width + 'px;" src="' + resultItem.poster + '">';
 121+ o+='</div>';
 122+ }else if(this.result_display_mode == 'list'){
 123+ o+='<div id="mv_result_' + rInx + '" class="mv_clip_list_result" style="width:90%">';
 124+ o+='<img style="float:left;width:' + this.thumb_width + 'px;" src="' + resultItem.poster + '">';
 125+ o+= pageObj.revisions[0]['*'];
 126+ o+='</div>';
 127+ o+='<div style="clear:both" />';
 128+ }
 129+ }
 130+ js_log('set : ' +this.target_results + ' to ' + o);
 131+ //debugger;
 132+ $j('#'+this.target_results).html(o);
 133+ }
 134+}
 135+
 136+/*
 137+* api modes (implementations should call these objects which inherit the mvBaseRemoteSearch
 138+*/
 139+var metavidRemoteSearch = function(initObj) {
 140+ return this.init(initObj);
 141+};
 142+metavidRemoteSearch.prototype = {
 143+ init:function(initObj){
 144+ var baseSearch = new mvBaseRemoteSearch(initObj);
 145+ //inherit:
 146+ for(var i in baseSearch){
 147+ if(typeof this[i] =='undefined'){
 148+ this[i] = baseSearch[i];
 149+ }else{
 150+ this['parent_'+i] = baseSearch[i];
 151+ }
 152+ }
 153+ }
 154+}
 155+
 156+var mediaWikiRemoteSearch = function(initObj) {
 157+ return this.init(initObj);
 158+};
 159+mediaWikiRemoteSearch.prototype = {
 160+ init:function(initObj){
 161+ var baseSearch = new mvBaseRemoteSearch(initObj);
 162+ //inherit:
 163+ for(var i in baseSearch){
 164+ if(typeof this[i] =='undefined'){
 165+ this[i] = baseSearch[i];
 166+ }else{
 167+ this['parent_'+i] = baseSearch[i];
 168+ }
 169+ }
 170+ },
 171+ getSearchResults:function(){
 172+ js_log('f:getSearchResults for:' + $j('#'+this.target_input).val() );
 173+ //set results div to "loading"
 174+ $j('#'+this.target_results).html( getMsg('loading_txt') );
 175+ //empty out the current results:
 176+ this.resultsObj={};
 177+ //do two queries against the Image / File / MVD namespace:
 178+ //construct search request:
 179+ var req_url =this.p_seq.plObj.interface_url.replace(/index\.php/, 'api.php');
 180+ //build the image request object:
 181+ var rObj = {
 182+ 'action':'query',
 183+ 'generator':'search',
 184+ 'gsrsearch': encodeURIComponent( $j('#'+this.target_input).val() ),
 185+ 'gsrnamespace':6, //(only search images)
 186+ 'gsrwhat':'title',
 187+ 'prop':'imageinfo|revisions|categories',
 188+ 'iiprop':'url',
 189+ 'iiurlwidth':'80',
 190+ 'rvprop':'content'
 191+ };
 192+ var _this = this;
 193+ //set up the number of request:
 194+ this.completed_req=0;
 195+ this.num_req=2;
 196+ //setup the number of requests result flag:
 197+ do_api_req( rObj, req_url, function(data){
 198+ //parse the return data
 199+ _this.addMediaWikiAPIResults( data);
 200+ _this.checkRequestDone();
 201+ });
 202+ //also do a request for page titles (would be nice if api could query both at the same time)
 203+ rObj['gsrwhat']='text';
 204+ do_api_req( rObj, req_url, function(data){
 205+ //parse the return data
 206+ _this.addResults( data);
 207+ _this.checkRequestDone();
 208+ });
 209+ },
 210+ addResults:function( data ){
 211+ //make sure we have pages to idoerate:
 212+ if(data.query && data.query.pages){
 213+ for(var page_id in data.query.pages){
 214+ var page = data.query.pages[ page_id ];
 215+
 216+ this.resultsObj['ref'][page_id]={
 217+ 'uri':page.title,
 218+ 'poster':page.imageinfo.thumburl,
 219+ 'src':page.imageinfo.url,
 220+ 'desc':page.revisions['*'],
 221+ 'meta':{
 222+ 'categories':page.categories
 223+ }
 224+ }
 225+ }
 226+ }else{
 227+ js_log('no results:' + data);
 228+ }
 229+ }
 230+}
\ No newline at end of file
Property changes on: trunk/extensions/MetavidWiki/skins/mv_embed/libRemoteMediaSearch/mv_remote_media_search.js
___________________________________________________________________
Added: svn:mergeinfo
Added: svn:eol-style
1231 + native
Index: trunk/extensions/MetavidWiki/skins/mv_embed/i18n/README
@@ -0,0 +1,51 @@
 2+This _short_ document outlines the plan for internationalization support for stand alone
 3+javascript libraries being integrated into mediaWiki.
 4+
 5+A key piece is of this system is the script_loader.
 6+
 7+For static usage every script file should have an associative text js language file:
 8+mv_embed.en.js
 9+mv_embed.es.js
 10+mv_embed.fn.js
 11+
 12+libSequencer_mv_sequencer.en.js
 13+libSequencer_mv_sequencer.es.js
 14+
 15+These static files will be updated via mediaWikis translation system.
 16+
 17+
 18+These static files will be combined with the server side load script so that the language segment
 19+is requested at the same time the script is included. It won't result in a separate request because
 20+script_loader.php will combine the files.
 21+
 22+script_loader.php arguments:
 23+@uid _string the unique id to ensure fresh copy of the scripts
 24+@sl _string the list of scripts with relative paths
 25+@debug _boolean if debug is "ON" don't send out minimised code
 26+the javascript should read this param on Document.URL and not group requests for ease of debuging.
 27+
 28+
 29+script_loader.php will take a set of scripts as arguments ie:
 30+http://server.com/script_loader.php?uid=SVN_Version_Number&sl=/mv_embed/mv_embed.js,mv_embed.en.js,/jQuery/jquery.js
 31+
 32+It will minimise the scripts (strip comments and a custom stip of debug statements ie js_log('msg')
 33+can use: http://code.google.com/p/jsmin-php/ for minimisation.
 34+
 35+Features:
 36+script_loader will concatenate all the minimised code from the requested set of scripts.
 37+
 38+script_loader will send appropriate http cache headers.
 39+ Can expire _never_ since we send unique SVN version id to force updates.
 40+ This will integrate with the squid proxy setup so the minimisation just
 41+ happens on fresh requests
 42+
 43+script_loader will read the client accept header and send out gziped or not.
 44+
 45+MediaWiki specific Features:
 46+
 47+We will want pass the il8n off to mediaWikis existing internationalization infastructure.
 48+MediaWiki should parse the il8n js file and check mediaWikis message space for any language variables.
 49+Yes this does result in all js_variables being stored twice.
 50+
 51+But will have the advantage of being a stand alone solution for media remixing and should enable
 52+wider participation in development.
Index: trunk/extensions/MetavidWiki/skins/mv_embed/libSequencer/mv_sequencer.js
@@ -0,0 +1,1366 @@
 2+/*
 3+ * mv_sequencer.js Created on Oct 17, 2007
 4+ *
 5+ * All Metavid Wiki code is Released under the GPL2
 6+ * for more info visit http://metavid.org/wiki/Code
 7+ *
 8+ * @author Michael Dale
 9+ * @email dale@ucsc.edu
 10+ * @url http://metavid.org
 11+ *
 12+ *
 13+ * mv_sequencer.js
 14+ * is a basic embeddable sequencer.
 15+ * extends the playlist with drag/drop/sortable/add/remove functionality
 16+ * editing of annotative content (mostly for wiki)
 17+ * enables more dynamic layouts
 18+ * exports back out to json or inline format
 19+ */
 20+
 21+gMsg['menu_clipedit'] = 'Edit Selected Resource';
 22+ gMsg['sc_fileopts'] ='Clip Detail';
 23+ gMsg['sc_inoutpoints'] ='Set In-Out points';
 24+ gMsg['sc_panzoom'] ='Pan zoom Controls';
 25+ gMsg['sc_overlays'] ='Overlays';
 26+ gMsg['sc_audio'] ='Audio Control';
 27+
 28+gMsg['menu_cliplib'] = 'Add Resource';
 29+gMsg['menu_transition'] = 'Transitions Effects';
 30+gMsg['menu_resource_overview'] = 'Resource Overview';
 31+gMsg['menu_options'] = 'Options';
 32+
 33+gMsg['loading_timeline'] = 'Loading TimeLine <blink>...</blink>';
 34+gMsg['loading_user_rights'] = 'Loading user rights <blink>...</blink>';
 35+
 36+gMsg['no_edit_permissions'] = 'You don\'t have permissions to save changes to this sequence';
 37+
 38+
 39+gMsg['edit_clip'] = 'Edit Clip';
 40+gMsg['edit_save'] = 'Save Changes';
 41+gMsg['edit_cancel'] = 'Cancel Edit';
 42+gMsg['edit_cancel_confirm'] = 'Are you sure you want to cancel your edit, changes will be lost';
 43+
 44+gMsg['zoom_in'] = 'Zoom In';
 45+gMsg['zoom_out'] = 'Zoom Out';
 46+gMsg['cut_clip'] = 'Cut Clips';
 47+gMsg['expand_track'] = 'Expand Track';
 48+gMsg['colapse_track'] = 'Collapse Track';
 49+gMsg['play_clip'] = 'Play From Playline Position';
 50+gMsg['pixle2sec'] = 'pixles to seconds';
 51+gMsg['rmclip'] = 'Remove Clip';
 52+gMsg['clip_in'] = 'clip in';
 53+gMsg['clip_out'] = 'clip out';
 54+
 55+ //used to set default values and validate the passed init object
 56+var sequencerDefaultValues = {
 57+
 58+ instance_name:'mvSeq', //for now only one instance by name mvSeq is allowed
 59+ sequence_container_id:'null',//text value (so that its a valid property)
 60+ video_container_id:'mv_video_container',
 61+
 62+ video_width : 400,
 63+ video_height: 300,
 64+
 65+ sequence_tools_id:'mv_sequence_tools',
 66+ timeline_id:'mv_timeline',
 67+ plObj_id:'seq_plobj',
 68+ plObj:'null',
 69+
 70+ timeline_scale:.06, //in pixel to second ratio ie 100pixles for every ~30seconds
 71+ timeline_duration:500, //default timeline length in seconds
 72+ playline_time:0,
 73+ track_thumb_height:60,
 74+ track_text_height:20,
 75+
 76+ //default timeline mode: "clip" (i-movie like) or "time" (finalCut like)
 77+ timeline_mode:'clip',
 78+
 79+ track_clipThumb_height:80, // how large are the i-movie type clips
 80+
 81+ base_adj_duration:.5, //default time to subtract or add when adjusting clips.
 82+
 83+ //default clipboard is empty:
 84+ clipboard:new Array(),
 85+ //stores the clipboard edit token (if user has rights to edit their User page)
 86+ clipboardEditToken:null,
 87+ //stores the sequence edit token (if user has rights to edit the current sequence)
 88+ sequenceEditToken:null,
 89+
 90+ //Msg are all the language specific values ...
 91+ // (@@todo overwrite by msg values preloaded in the page)
 92+ //tack/clips can be pushed via json or inline playlist format
 93+ inline_playlist:'null', //text value so its a valid property
 94+ inline_playlist_id:'null',
 95+ mv_pl_src:'null',
 96+ //the edit stack:
 97+ edit_stack:new Array(),
 98+
 99+ //trackObj used to payload playlist Track Object (when inline not present)
 100+ tracks:{}
 101+}
 102+var mvSequencer = function(initObj) {
 103+ return this.init(initObj);
 104+};
 105+//set up the mvSequencer object
 106+mvSequencer.prototype = {
 107+ menu_items : {
 108+ 'clipedit':{
 109+ 'd':1,
 110+ 'submenu':{
 111+ 'fileopts':1,
 112+ 'inoutpoints':0,
 113+ 'panzoom':0,
 114+ 'overlays':0,
 115+ 'audio':0
 116+ }
 117+ },
 118+ 'cliplib':{
 119+ 'd':0
 120+ },
 121+ 'transition':{
 122+ 'd':0
 123+ },
 124+ 'options':{
 125+ 'd':0
 126+ }
 127+ },
 128+
 129+ //set up initial key states:
 130+ key_shift_down:false,
 131+ key_ctrl_down:false,
 132+
 133+ init:function( initObj ){
 134+ //set up pointer to this_seq for current scope:
 135+ var this_seq = this;
 136+ //set the default values:
 137+ for(var i in sequencerDefaultValues){
 138+ this[ i ] = sequencerDefaultValues[i];
 139+ }
 140+ for(var i in initObj){
 141+ //js_log('on '+ i + ' :' + initObj[i]);
 142+ if(sequencerDefaultValues[i]){ //make sure its a valid property
 143+ this[i] = initObj[i];
 144+ }
 145+ }
 146+ if(this.sequence_container_id==null){
 147+ js_log('Error: no sequence_container_id');
 148+ return false;
 149+ }
 150+
 151+ //check for sequence_container
 152+ if(this.sequence_container_id=='null'){
 153+ js_log("Error: missing sequence_container_id");
 154+ return false;
 155+ }
 156+
 157+ //$j('#'+this.sequence_container_id).css('position', 'relative');
 158+ this['base_width'] = $j('#'+this.sequence_container_id).width();
 159+ this['base_height'] = $j('#'+this.sequence_container_id).height();
 160+
 161+
 162+ //add the container divs (with basic layout ~universal~
 163+ $j('#'+this.sequence_container_id).html(''+
 164+ '<div id="'+this.video_container_id+'" style="position:absolute;right:0px;top:0px;' +
 165+ 'width:'+this.video_width+'px;height:'+this.video_height+'px;border:solid thin blue;background:#FFF;font-color:black;"/>'+
 166+ '<div id="'+this.sequence_tools_id+'" style="position:absolute;' +
 167+ 'left:0px;right:'+(this.video_width+10)+'px;top:0px;height:'+this.video_height+'px;border:solid thin black;"/>'+
 168+ '<div id="'+this.timeline_id+'" style="position:absolute;' +
 169+ 'left:0px;right:0px;top:'+(this.video_height+10)+'px;bottom:25px;overflow:auto;">'+
 170+ getMsg('loading_timeline')+ '</div>'+
 171+ '<div id="' + this.sequence_container_id + '_status" style="position:absolute;left:0px;width:300px;"></div>'+
 172+ '<div id="' + this.sequence_container_id + '_save_cancel" style="position:absolute;'+
 173+ 'right:0px;bottom:0px;height:25px;overflow:hidden;">'+
 174+ getMsg('loading_user_rights') +
 175+ '</div>'
 176+ );
 177+
 178+ js_log('set: '+this.sequence_container_id + ' html to:'+ "\n"+
 179+ $j('#'+this.sequence_container_id).html()
 180+ );
 181+ //first check if we got a cloned PL object:
 182+ //(when the editor is invoked with the plalylist already on the page)
 183+ //@@NOT WORKING... (need a better "clone" function)
 184+ /*if( this.plObj != 'null' ){
 185+ js_log('found plObj clone');
 186+ //extend with mvSeqPlayList object:
 187+ this.plObj = new mvSeqPlayList(this.plObj);
 188+ js_log('mvSeqPlayList added: ' + this.plObj.org_control_height );
 189+ $j('#'+this.video_container_id).get(0).attachNode( this.plObj );
 190+ this.plObj.getHTML();
 191+ this.checkReadyPlObj();
 192+ return ;
 193+ }*/
 194+
 195+ //else check for source based sequence editor (a clean page load of the editor)
 196+ if( this.mv_pl_src != 'null' ) {
 197+ js_log( ' pl src:: ' + this.mv_pl_src );
 198+ var src_attr=' src="' + this.mv_pl_src+'" ';
 199+ }else{
 200+ js_log( ' null playlist src .. (start empty) ');
 201+ var src_attr='';
 202+ }
 203+ $j('#'+this.video_container_id).html('<playlist ' + src_attr +
 204+ ' style="width:' + this.video_width + 'px;height:' + this.video_height + 'px;" '+
 205+ ' sequencer="true" id="' + this.plObj_id + '" />');
 206+
 207+ rewrite_by_id( this.plObj_id );
 208+ setTimeout(this.instance_name +'.checkReadyPlObj()', 25);
 209+ },
 210+ updateSeqSaveButtons:function(){
 211+ var cancel_button = '<a style="border:' +
 212+ 'solid gray;font-size:1.2em;" onClick="window.confirm(\''+getMsg('edit_cancel_confirm')+'\')" '+
 213+ 'href="javascript:'+this.instance_name+'.closeModEditor()">'+
 214+ getMsg('edit_cancel') + '</a> ';
 215+ if( this.sequenceEditToken ){
 216+ $j('#'+this.sequence_container_id+'_save_cancel').html( cancel_button +
 217+ '<a style="border:solid gray;font-size:1.2em;" href="#" onClick="'+this.instance_name+'.getSeqOutputJSON()">'+
 218+ 'Preview Json Output'+
 219+ '</a>' +
 220+ '<a style="border:solid gray;font-size:1.2em;" href="#" onClick="'+this.instance_name+'.getSeqOutputHLRDXML()">'+
 221+ 'Preview XML Output (will be save shortly) ' +
 222+ '</a>');
 223+ }else{
 224+ $j('#'+this.sequence_container_id+'_save_cancel').html( cancel_button + getMsg('no_edit_permissions') );
 225+ }
 226+ },
 227+ //display a menu item (hide the rest)
 228+ disp:function( item ){
 229+ js_log('disp: ' + item);
 230+ for(var i in this.menu_items){
 231+ if(i==item){
 232+ $j('#'+i+'_ic').fadeIn("fast");
 233+ }else{
 234+ $j('#'+i+'_ic').filter(':visible').fadeOut("fast");
 235+ }
 236+ }
 237+ },
 238+ //load the menu items:
 239+ loadInitMenuItems:function(){
 240+ js_log('loadInitMenuItems');
 241+ if( !this.plObj.interface_url ){
 242+ js_log( 'Error:missing interface_url, can not load item' );
 243+ return false;
 244+ }
 245+
 246+ var req_url =this.plObj.interface_url+ '?action=ajax&rs=mv_seqtool_disp&rsargs[]=';
 247+ //ouput the requested items list:
 248+ for(var i in this.menu_items){
 249+ req_url+='|'+i;
 250+ //if single items set to loading:
 251+ if(typeof this.menu_items[i].submenu == 'undefined')
 252+ $j('#'+i+'_ic').html( getMsg('loading_txt') );//set targets to loading
 253+ //else set the default sub menu to loading:
 254+ for(var j in this.menu_items[i].submenu){
 255+ if(this.menu_items[i].submenu[j])
 256+ $j('#sc_'+j).html( getMsg('loading_txt') );
 257+ }
 258+ }
 259+ var this_seq = this;
 260+ do_request(req_url, function(data){
 261+ if( typeof data=='string' ){
 262+ js_log(' eval data: ' + data);
 263+ eval(data);
 264+ var data = mv_result['pay_load'];
 265+ }
 266+ for( var i in data ){
 267+ var menu_item = this_seq.menu_items[i];
 268+ js_log('set '+ i + ' to: '+ data[i] );
 269+ if( menu_item.submenu ){
 270+ if(typeof data[i]=='string'){
 271+ //just set the default item
 272+ for(var j in menu_item.submenu){
 273+ if( menu_item.submenu[j] )
 274+ $j('#sc_'+j).html( data[i] );
 275+ }
 276+ }else if(typeof data[i] == 'object'){
 277+ //see if we have sub data for each sub-menu item
 278+ for(var j in data[i]){
 279+ $j('#sc_'+j).html( data[i][j] );
 280+ }
 281+ }
 282+ }else{
 283+ //just set the parent container
 284+ $j('#'+i+'_ic').html( data[i] );
 285+ this_seq.doMenuItemDispJs(i)
 286+ }
 287+ }
 288+ });
 289+ },
 290+ doMenuItemDispJs:function(item){
 291+ var this_seq = this;
 292+ var target_id = item + '_ic';
 293+ var menu_item = this.menu_items[item];
 294+ //do any menu item post embed js hook processing:
 295+ switch(item){
 296+ case 'clipedit':
 297+ //load mv_clip_edit.js
 298+ break;
 299+ case 'transition':
 300+ //render out the transitions library
 301+ this.renderTransitionsSet(target_id);
 302+ break;
 303+ case 'cliplib':
 304+ //load the search interface with sequence tool targets
 305+ //@@todo it maybe cleaner to just pass along msg text in JSON
 306+ //and have the search interface build the html
 307+ if( ! this.plObj.interface_url ){
 308+ js_log( 'Error:missing interface_url, can not load search interface' );
 309+ return false;
 310+ }
 311+
 312+ //check default search
 313+ mvJsLoader.doLoad({'mediaWikiRemoteSearch':'libRemoteMediaSearch/mv_remote_media_search.js'}, function(){
 314+ this_seq.mySearch = new remoteSearchDriver({
 315+ 'profile':'sequence',
 316+ 'p_seq':this_seq,
 317+ 'instance_name': this_seq.instance_name + '.mySearch'
 318+ });
 319+ });
 320+ break;
 321+ case 'options':
 322+ $j('#'+target_id+" input[value='simple_editor']").attr({
 323+ 'checked':(this_seq.timeline_mode=='clip')?true:false
 324+ }).click(function(){
 325+ this_seq.doSimpleTl();
 326+ });
 327+ $j('#'+target_id+" input[value='advanced_editor']").attr({
 328+ 'checked':( this_seq.timeline_mode=='time' )?true:false
 329+ }).click(function(){
 330+ this_seq.doAdvancedTl();
 331+ });
 332+ //set up the options for context menus
 333+ break;
 334+ }
 335+ },
 336+ //renders out the transitions effects set
 337+ renderTransitionsSet:function(target_id){
 338+ js_log('f:renderTransitionsSet:' + target_id);
 339+ var o = '';
 340+ if(typeof mvTransLib == 'undefined'){
 341+ js_log('Error: missing mvTransLib');
 342+ return false;
 343+ }
 344+
 345+ for(var i in mvTransLib['type']){
 346+ js_log('on tran type: ' + i);
 347+ var base_trans_name = i;
 348+ var tLibSet = mvTransLib['type'][ i ];
 349+ for(var j in tLibSet){
 350+ trans_name=base_trans_name+'_'+j;
 351+ js_log('tname: ' + trans_name);
 352+ o+='<img style="float:left;padding:10px;" '+
 353+ 'src="'+mv_embed_path +'/skins/'+mv_skin_name+'/transition_images/'+ trans_name + '.png">';
 354+ }
 355+ }
 356+ js_log('should set: ' + target_id + ' to: ' + o);
 357+ $j('#'+target_id).append(o);
 358+ },
 359+ renderTimeLine:function(){
 360+ //empty out the top level html:
 361+ $j('#'+this.timeline_id).html('');
 362+ //add html general for timeline
 363+ if( this.timeline_mode=='time'){
 364+ $j('#'+this.timeline_id).html(''+
 365+ '<div id="'+this.timeline_id+'_left_cnt" class="mv_tl_left_cnt">'+
 366+ '<div id="'+this.timeline_id+'_head_control" style="position:absolute;top:0px;left:0px;right:0px;height:30px;">' +
 367+ '<a title="'+getMsg('play_clip')+'" href="javascript:'+this.instance_name+'.play_jt()">'+
 368+ '<img style="width:16px;height:16px;border:0" src="' + mv_embed_path + 'images/control_play_blue.png">'+
 369+ '</a>'+
 370+ '<a title="'+getMsg('zoom_in')+'" href="javascript:'+this.instance_name+'.zoom_in()">'+
 371+ '<img style="width:16px;height:16px;border:0" src="' + mv_embed_path + 'images/zoom_in.png">'+
 372+ '</a>'+
 373+ '<a title="'+getMsg('zoom_out')+'" href="javascript:'+this.instance_name+'.zoom_out()">'+
 374+ '<img style="width:16px;height:16px;border:0" src="' + mv_embed_path + 'images/zoom_out.png">'+
 375+ '</a>'+
 376+ '<a title="'+getMsg('cut_clip')+'" href="javascript:'+this.instance_name+'.cut_mode()">'+
 377+ '<img style="width:16px;height:16px;border:0" src="' + mv_embed_path + 'images/cut.png">'+
 378+ '</a>'+
 379+ '</div>' +
 380+ '</div>' +
 381+ '<div id="'+this.timeline_id+'_tracks" class="mv_seq_tracks">' +
 382+ '<div id="'+this.timeline_id+'_head_jump" class="mv_head_jump" style="position:absolute;top:0px;left:0px;height:20px;"></div>'+
 383+ '<div id="'+this.timeline_id+'_playline" class="mv_playline"></div>'+
 384+ '</div>'
 385+ );
 386+ //add playlist hook to update timeline
 387+ this.plObj.update_tl_hook = this.instance_name+'.update_tl_hook';
 388+ var this_sq = this;
 389+ var top_pos=25;
 390+ //add tracks:
 391+ for(var i in this.plObj.tracks){
 392+ var track = this.plObj.tracks[i];
 393+ //js_log("on track: "+ i + ' t:'+ $j('#'+this.timeline_id+'_left_cnt').html() );
 394+ //set up track based on disp type
 395+ switch(track.disp_mode){
 396+ case 'timeline_thumb':
 397+ var track_height=60;
 398+ var exc_img = 'opened';
 399+ var exc_action='close';
 400+ var exc_msg = getMsg('colapse_track');
 401+ break;
 402+ case 'text':
 403+ var track_height=20;
 404+ var exc_img = 'closed';
 405+ var exc_action='open';
 406+ var exc_msg = getMsg('expand_track');
 407+ break;
 408+ }
 409+ //add track name:
 410+ $j('#'+this.timeline_id+'_left_cnt').append(
 411+ '<div id="track_cnt_'+i+'" style="top:'+top_pos+'px;height:'+track_height+'px;" class="track_name">'+
 412+ '<a id="mv_exc_'+i+'" title="'+exc_msg+'" href="javascript:'+this_sq.instance_name+'.exc_track('+i+',\''+exc_action+'\')">'+
 413+ '<img id="'+this_sq.timeline_id+'_close_expand" style="width:16px;height:16px;border:0" '+
 414+ ' src="'+mv_embed_path + 'images/'+exc_img+'.png">'+
 415+ '</a>'+
 416+ track.title+'</div>'
 417+ );
 418+ //also render the clips in the trackset container: (thumb or text view)
 419+ $j('#'+this.timeline_id+'_tracks').append(
 420+ '<div id="container_track_'+i+'" style="top:'+top_pos+'px;height:'+(track_height+2)+'px;left:0px;right:0px;" class="container_track" />'
 421+ );
 422+ top_pos+=track_height+20;
 423+ }
 424+ }
 425+ if( this.timeline_mode=='clip'){
 426+ var top_pos=this.plObj.org_control_height;
 427+ //debugger;
 428+ for(var i in this.plObj.tracks){
 429+ var track_height=this.track_clipThumb_height;
 430+ var timeline_id = this.timeline_id
 431+ //add in play box and container tracks
 432+ $j('#'+timeline_id).append(''+
 433+ '<div id="interface_container_track_' + i + '" ' +
 434+ ' style="position:absolute;top:25px;height:'+(track_height+30)+'px;left:10px;right:0px;"' +
 435+ '>'+
 436+ '<div id="container_track_'+i+'" style="position:relative;top:0px;' +
 437+ 'height:'+(track_height+30)+'px;left:0px;right:0px;" class="container_track">' +
 438+ '</div>'+
 439+ '<div id="' + timeline_id + '_playline" class="mv_story_playline">' +
 440+ '<div class="mv_playline_top"/>'+
 441+ '</div>'+
 442+ '</div>'
 443+ );
 444+ top_pos+=track_height+20;
 445+ }
 446+ }
 447+ },
 448+ //once playlist is ready continue
 449+ checkReadyPlObj:function(){
 450+ this.plObj = $j('#'+ this.plObj_id ).get(0);
 451+ if( this.plObj )
 452+ if( ! this.plObj.loading )
 453+ this.plReadyInit();
 454+
 455+ //else keep checking for the playlist to be ready
 456+ if( this.plObj.loading ){
 457+ if(this.plReadyTimeout==200){
 458+ js_error('error playlist never ready');
 459+ }else{
 460+ this.plReadyTimeout++;
 461+ setTimeout(this.instance_name +'.checkReadyPlObj()', 25);
 462+ }
 463+ }
 464+ },
 465+ plReadyInit:function(){
 466+ var this_seq = this;
 467+ js_log('plReadyInit');
 468+ js_log( this.plObj );
 469+ //give the playlist a pointer to its parent seq:
 470+ this.plObj['seqObj'] = this;
 471+
 472+ //update playlist (since if its empty right now)
 473+ if(this.plObj.getClipCount()==0){
 474+ $j('#'+this.plObj_id).html('empty playlist');
 475+ }
 476+
 477+ //propogate the edit tokens
 478+ //if on an edit page just grab from the form:
 479+ this.sequenceEditToken = $j('input[@wpEditToken]').val();
 480+ if(typeof this.sequenceEditToken == 'undefined'){
 481+ //(calling the sequencer inline) try and get edit token via api call:
 482+ //(somewhat fragile way to get at the api... should move to config
 483+ var token_url =this.plObj.interface_url.replace(/index\.php/, 'api.php');
 484+ token_url += '?action=query&format=xml&prop=info&intoken=edit&titles=';
 485+ $j.ajax({
 486+ type: "GET",
 487+ url: token_url + this_seq.plObj.mTitle,
 488+ success:function(data){
 489+ var pageElm = data.getElementsByTagName('page')[0];
 490+ if( $j(pageElm).attr('edittoken') ){
 491+ this_seq.sequenceEditToken = $j(pageElm).attr('edittoken');
 492+ }
 493+ this_seq.updateSeqSaveButtons();
 494+ }
 495+ });
 496+ //also grab permmisions for sending clipboard commands to the server
 497+ $j.ajax({
 498+ type:"GET",
 499+ url: token_url + this_seq.plObj.mTalk,
 500+ success:function(data){
 501+ var pageElm = data.getElementsByTagName('page')[0];
 502+ if( $j(pageElm).attr('edittoken') ){
 503+ this_seq.clipboardEditToken = $j(pageElm).attr('edittoken');
 504+ }
 505+ }
 506+ });
 507+ }
 508+
 509+
 510+ //render the menu:
 511+ var menu_html = '<ul id="seq_menu">';
 512+ var item_containers ='';
 513+
 514+ //@@todo ~maybe~ load menu via ajax request
 515+ //(avoid so much hmtl in js? or keep in js to keep high protabillity of sequencer? )
 516+
 517+ $j.each(this.menu_items, function(inx, menu_item){
 518+ var disp_style = (menu_item.d)?'inline':'none';
 519+ var sel_class = (menu_item.d)?'class="mv_selected_item"':'';
 520+ menu_html+='<li '+sel_class+' id="mv_menu_item_'+inx+'">' + getMsg('menu_' + inx ) +'</li>';
 521+ item_containers += '<div class="seq_control_container" id="' + inx +
 522+ '_ic" style="display:' + disp_style +';">'
 523+ //add in subMenus if set
 524+ //check for submenu and add to item container
 525+ var sub_menu_html='';
 526+ if( typeof menu_item.submenu != 'undefined'){
 527+ sub_menu_html+= '<ul id="mv_submenu_' + inx +'" class="mv_submenu">';
 528+ $j.each(menu_item.submenu, function(subInx, sub_menu_item){
 529+ var disp_style = (menu_item.d)?'block':'none';
 530+ var sub_sel_class = (sub_menu_item==1)?'class="mv_sub_selected"':'';
 531+ sub_menu_html+= '<li ' + sub_sel_class + ' id="mv_sub_menu_item_' + subInx + '">' +
 532+ getMsg('sc_' + subInx ) + '</li>';
 533+ item_containers+= '<div class="submenu_container" id="sc_' + subInx+'" '+
 534+ ' style="display:' + disp_style +';"></div>';
 535+ });
 536+ sub_menu_html+= '</ul>';
 537+ }
 538+ item_containers+= sub_menu_html + '</div>';
 539+ });
 540+ menu_html+='</ul>';
 541+
 542+ $j('#'+this.sequence_tools_id).html( menu_html + item_containers );
 543+ //add binding for menu
 544+ $j('#seq_menu li').click(function(){
 545+ $j('#seq_menu li').removeClass('mv_selected_item');
 546+ $j(this).addClass('mv_selected_item');
 547+ this_seq.disp( $j(this).attr('id').replace('mv_menu_item_','') );
 548+ });
 549+
 550+ //load init content into containers
 551+ this.loadInitMenuItems();
 552+
 553+ //render the timeline
 554+ this.renderTimeLine();
 555+ this.do_refresh_timeline();
 556+
 557+ var this_seq = this;
 558+ //set up key bidnings
 559+ $j().keydown(function(e){
 560+ js_log('pushed down on:' + e.which);
 561+ if( e.which == 16 )
 562+ this_seq.key_shift_down = true;
 563+
 564+ if( e.which == 17)
 565+ this_seq.key_ctrl_down = true;
 566+
 567+ if( e.which == 67 && this_seq.key_ctrl_down)
 568+ this_seq.copySelectedClips();
 569+
 570+ if( e.which == 88 && this_seq.key_ctrl_down)
 571+ this_seq.cutSelectedClips();
 572+
 573+ if( e.which == 86 && this_seq.key_ctrl_down)
 574+ this_seq.pasteClipBoardClips();
 575+
 576+ });
 577+ $j().keyup(function(e){
 578+ js_log('key up on ' + e.which);
 579+ //user let go of "shift" turn off multi-select
 580+ if( e.which == 16 )
 581+ this_seq.key_shift_down = false;
 582+
 583+ if( e.which == 17)
 584+ this_seq.key_ctrl_down = false;
 585+
 586+ //backspace or delete key:
 587+ if( e.which == 8 || e.which == 46 ){
 588+ this_seq.removeSelectedClips();
 589+ }
 590+ });
 591+ },
 592+ update_tl_hook:function(jh_time_ms){
 593+ //put into seconds scale:
 594+ var jh_time_sec_float = jh_time_ms/1000;
 595+ //render playline at given time
 596+ //js_log('tl scale: '+this.timeline_scale);
 597+ $j('#'+this.timeline_id+'_playline').css('left', Math.round(jh_time_sec_float/this.timeline_scale)+'px' );
 598+ //js_log('at time:'+ jh_time_sec + ' px:'+ Math.round(jh_time_sec_float/this.timeline_scale));
 599+ },
 600+ /*returns a xml or json representation of the current sequence */
 601+ getSeqOutputJSON:function(){
 602+ js_log('json output');
 603+ },
 604+ getSeqOutputHLRDXML:function(){
 605+ var o='<sequence_hlrd>' +"\n";
 606+ o+="\t<head>";
 607+ //get transitions
 608+ for(var i in this.plObj.transitions){
 609+ var tObj = this.plObj.transitions[i].getAttributeObj();
 610+ o+="\t<transition ";
 611+ for(var j in tObj){
 612+ o+=' '+j+'="' + tObj[j] + '"\n\t\t';
 613+ }
 614+ o+='/>'+"\n"; //transitions don't have children
 615+ }
 616+ o+="\t</head>\n";
 617+
 618+ //get clips
 619+ o+="\t<body>\n";
 620+ //output each track:
 621+ for(var i in this.plObj.tracks){
 622+ var curTrack = this.plObj.tracks[i];
 623+ o+="\t<seq";
 624+ var tAttr = curTrack.getAttributeObj();
 625+ for(var j in tAttr){
 626+ o+=' '+j+'="' + tAttr[j] + '"\n\t\t\t';
 627+ }
 628+ o+=">\n";
 629+ for( var k in curTrack.clips ){
 630+ var curClip = curTrack.clips[k];
 631+ o+="\t\t<ref ";
 632+ var cAttr = curClip.getAttributeObj();
 633+ for(var j in cAttr){
 634+ var val = (j=='transIn' || j=='transOut') ? cAttr[j].id : cAttr[j];
 635+ o+=' '+j+'="' + val + '"\n\t\t\t';
 636+ }
 637+ o+="/>\n" //close the clip
 638+ }
 639+ o+="\n</seq>n";
 640+ }
 641+ o+="\t</body>\n";
 642+ //close the tag
 643+ o+='</sequence_hlrd>';
 644+
 645+ alert('f:getSeqOutputHLRDXML'+ o);
 646+
 647+ return false;
 648+ },
 649+ //@@todo integrate into clip view ...
 650+ editClip:function(track_inx, clip_inx){
 651+ $j('#modalbox').hide();
 652+ if($j('#modal_window').length==0){
 653+ $j('body').append('<div id="modal_window" class="modal_editor" />');
 654+ }
 655+ //empty out the modal_window and show it
 656+ $j('#modal_window').empty().show();
 657+ //set to the current clip in "clip mode"
 658+ var clip = this.plObj.tracks[track_inx].clips[ clip_inx ];
 659+ //@@todo do per clip type edit modes:
 660+ $j('#modal_window').append('<div style="position:absolute;top:10px;left:25%;width:'+this.plObj.width+'px;">'+
 661+ '<h3>' + clip.getTitle() + '</h3>'+
 662+ '<video id="chop_clip_' + track_inx + '_' + clip_inx + '" ' +
 663+ 'style="width:'+this.plObj.width+'px;height:'+this.plObj.height+'px;" '+
 664+ 'poster="'+clip.embed.media_element.getThumbnailURL()+'" ' +
 665+ 'src="' + clip.src + '"></video>'+
 666+ '<div style="padding-top:10px;">'+
 667+ '<span style="position:absolute;left:0px;">'+
 668+ 'start time:<input id="chop_start" type="text" size="10" value="0:0:0">'+
 669+ '</span>'+
 670+ '<span style="position:absolute;right:0px;">'+
 671+ 'end time:<input id="chop_end" type="text" size="10" '+
 672+ 'value="' + seconds2ntp(clip.getDuration()) + '" >' +
 673+ '</span>'+
 674+ '</div>'+
 675+ '</div>'
 676+ //start time end time field display
 677+ );
 678+ $j('#modal_window').append('<div style="position:absolute;bottom:10px;left:50%;">'+
 679+ '<a style="border:solid gray;font-size:1.2em;" onClick="window.confirm(\''+getMsg('edit_cancel_confirm')+'\')" '+
 680+ 'href="javascript:'+this.instance_name+'.closeModWindow()">'+
 681+ getMsg('edit_cancel') + '</a> '+
 682+ '<a style="border:solid gray;font-size:1.2em;" href="javascript:'+this.instance_name+'.saveClipEdit()">'+
 683+ getMsg('edit_save')+
 684+ '</a>'+
 685+ '</div>'
 686+ );
 687+ rewrite_by_id('chop_clip_' + track_inx + '_' + clip_inx );
 688+ //@@todo add in-out setters
 689+
 690+ //@@todo add start / end hooks
 691+
 692+ },
 693+ //save new clip segment
 694+ saveClipEdit:function(){
 695+ //saves the clip updates
 696+ },
 697+ closeModEditor:function(){
 698+ $j('#modalbox,#mv_overlay').remove();
 699+ },
 700+ closeModWindow:function(){
 701+ $j('#modal_window').hide();
 702+ $j('#modalbox').show();
 703+ },
 704+ pasteClipBoardClips:function(){
 705+ js_log('f:pasteClipBoardClips');
 706+ //@@todo query the server for updated clipboard
 707+ //paste before the "current clip"
 708+ this.addClips(this.clipboard, this.plObj.cur_clip.order );
 709+ },
 710+ copySelectedClips:function(){
 711+ var this_seq = this;
 712+ //set all the selected clips
 713+ this.clipboard = new Array();
 714+ $j('.mv_selected_clip').each(function(){
 715+ //add each clip to the clip board:
 716+ var cur_clip = this_seq.getClipFromSeqID( $j(this).parent().attr('id') );
 717+ this_seq.clipboard.push( cur_clip.getAttributeObj() );
 718+ });
 719+ //upload clipboard to the server (if possible)
 720+ if( parseUri( document.URL ).host != parseUri( this_seq.plObj.interface_url ).host ){
 721+ js_log('error: presently we can\'t copy clips across domains');
 722+ }else{
 723+ var req_url = this_seq.plObj.interface_url + '?action=ajax&rs=mv_seqtool_clipboard&rsargs[]=copy';
 724+ $j.ajax({
 725+ type: "POST",
 726+ url:req_url,
 727+ data: $j.param( {
 728+ "clipboard_data": $j.toJSON( this_seq.clipboard ),
 729+ "clipboardEditToken": this_seq.clipboardEditToken
 730+ }),
 731+ success:function(data){
 732+ //callback( data );
 733+ js_log('did clipboard push ' + $j.toJSON( this_seq.clipboard ) );
 734+ }
 735+ });
 736+ }
 737+ },
 738+ cutSelectedClips:function(){
 739+ this.copySelectedClips();
 740+ this.removeSelectedClips();
 741+ },
 742+ removeSelectedClips:function(){
 743+ var remove_clip_ary=new Array();
 744+ //remove selected clips from display
 745+ $j('.container_track .mv_selected_clip').each(function(){
 746+ //grab the track index from the id (assumes track_#_clip_#
 747+ remove_clip_ary.push ( $j(this).parent().attr('id').replace('track_','').replace('clip_','').split('_') );
 748+ });
 749+ this.removeClips(remove_clip_ary);
 750+ },
 751+ //add a single or set of clips
 752+ //to a given position and track_inx
 753+ addClips:function( clipSet, before_clip_pos, track_inx){
 754+ this_seq = this;
 755+ js_log("seq: add clip: at: "+ before_clip_pos + ' in track: ' + track_inx);
 756+ var cur_pos = before_clip_pos;
 757+ js_log('paste clip before_clip_pos: ' + before_clip_pos);
 758+ var smilXML =
 759+ $j.each(clipSet, function(inx, clipInitDom){
 760+ var mediaElement = document.createElement('ref');
 761+ for(var i in clipInitDom){
 762+ if(i!='id')
 763+ $j(mediaElement).attr(i, clipInitDom[i]);
 764+ }
 765+ if( this_seq.plObj.tryAddMedia( mediaElement, cur_pos, track_inx ) )
 766+ cur_pos++;
 767+ });
 768+ //debugger;
 769+ this.do_refresh_timeline();
 770+ },
 771+ removeClips:function( remove_clip_ary ){
 772+ var this_seq = this;
 773+ var jselect = coma ='';
 774+ js_log('clip count before removal : ' + this_seq.plObj.default_track.clips.length + ' should remove ' + remove_clip_ary.length );
 775+ var afected_tracks = new Array();
 776+ //add order to track_clip before we start removing:
 777+ $j.each( remove_clip_ary, function(inx, track_clip){
 778+ remove_clip_ary[inx]['order'] = this_seq.plObj.tracks[ track_clip[0] ].clips[ track_clip[1] ].order;
 779+ });
 780+ $j.each( remove_clip_ary, function(inx, track_clip){
 781+ var track_inx = track_clip[0];
 782+ var clip_inx = track_clip[1];
 783+ var clip_rm_order = track_clip['order'];
 784+ js_log('remove t:' + track_inx + ' c:'+ clip_inx + ' id:' +' #track_'+track_inx+'_clip_'+clip_inx + ' order:' + clip_rm_order);
 785+ //remove the clips from the base tracks
 786+ for(var i in this_seq.plObj.tracks[ track_inx ].clips){
 787+ cur_clip = this_seq.plObj.tracks[ track_inx ].clips[i]
 788+ if(cur_clip.order == clip_rm_order){
 789+ this_seq.plObj.tracks[ track_clip[0] ].clips.splice( i, 1);
 790+ }
 791+ }
 792+ //add track to affected track list:
 793+ afected_tracks[ track_inx ]=true;
 794+ jselect += coma + '#track_' +track_inx + '_clip_' + clip_inx;
 795+ coma=',';
 796+ });
 797+ //update/ reorder:
 798+ $j.each(afected_tracks, function(track_inx, affected){
 799+ this_seq.plObj.tracks[track_inx].reOrderClips();
 800+ });
 801+
 802+ js_log('clip count after removal : ' + this_seq.plObj.default_track.clips.length);
 803+ //animate the removal (@@todo should be able to call the resulting fadeOut only once without a flag)
 804+ var done_with_refresh=false;
 805+ $j(jselect).fadeOut("slow", function(){
 806+ if( !done_with_refresh )
 807+ this_seq.do_refresh_timeline();
 808+ done_with_refresh=true;
 809+ }).empty(); //empty to remove any persistent bindings
 810+ },
 811+ doEdit:function( editObj ){
 812+ //add the current editObj to the edit stack (should allow for "undo")
 813+ this.edit_stack.push( editObj );
 814+ //make the adjustments
 815+ this.makeAdjustment( editObj );
 816+ },
 817+ /*
 818+ * takes adjust ment object with options:
 819+ * track_inx, clip_inx, start, end delta
 820+ */
 821+ makeAdjustment:function(e){
 822+ switch(e.type){
 823+ case 'resize_start':
 824+ this.plObj.tracks[e.track_inx].clips[e.clip_inx].doAdjust('start', e.delta);
 825+ break;
 826+ case 'resize_end':
 827+ this.plObj.tracks[e.track_inx].clips[e.clip_inx].doAdjust('end', e.delta);
 828+ break;
 829+ }
 830+ js_log('re render: '+e.track_inx);
 831+ //refresh the playlist after adjustment
 832+ this.do_refresh_timeline();
 833+ },
 834+ //@@todo set up key bindings for undo
 835+ undoEdit:function(){
 836+ var editObj = this.edit_stack.pop();
 837+ //invert the delta
 838+
 839+ },
 840+ exc_track:function(inx,req){
 841+ this_seq = this;
 842+ if(req=='close'){
 843+ $j('#mv_exc_'+inx).attr('href', 'javascript:'+this.instance_name+'.exc_track('+inx+',\'open\')');
 844+ $j('#mv_exc_'+inx + ' > img').attr('src',mv_embed_path + 'images/closed.png');
 845+ $j('#track_cnt_'+inx+',#container_track_'+inx).animate({height:this.track_text_height}, "slow",'',
 846+ function(){
 847+ this_seq.plObj.tracks[inx].disp_mode='text';
 848+ this_seq.render_tracks( inx );
 849+ });
 850+ }else if(req=='open'){
 851+ $j('#mv_exc_'+inx).attr('href', 'javascript:'+this.instance_name+'.exc_track('+inx+',\'close\')');
 852+ $j('#mv_exc_'+inx + ' > img').attr('src',mv_embed_path + 'images/opened.png');
 853+ $j('#track_cnt_'+inx+',#container_track_'+inx).animate({height:this.track_thumb_height}, "slow",'',
 854+ function(){
 855+ this_seq.plObj.tracks[inx].disp_mode='timeline_thumb';
 856+ this_seq.render_tracks(inx);
 857+ });
 858+
 859+ }
 860+ },
 861+ //adds tracks
 862+ add_track:function(inx, track){
 863+
 864+ },
 865+ //toggle cut mode (change icon to cut)
 866+ cut_mode:function(){
 867+ js_log('do cut mode');
 868+ //add cut layer ontop of clips
 869+ },
 870+ doAdvancedTl:function(){
 871+ this.timeline_mode='time';
 872+ this.renderTimeLine();
 873+ this.do_refresh_timeline();
 874+ return false;
 875+ },
 876+ doSimpleTl:function(){
 877+ this.timeline_mode='clip';
 878+ this.renderTimeLine();
 879+ this.do_refresh_timeline();
 880+ return false;
 881+ },
 882+ //renders updates the timeline based on the current scale
 883+ render_tracks:function( track_inx ){
 884+ js_log("f::render track: "+track_inx);
 885+ var this_seq = this;
 886+ //inject the tracks into the timeline (if not already there)
 887+ for(var track_id in this.plObj.tracks){
 888+ if( track_inx==track_id || typeof track_inx=='undefined' ){
 889+ //empty out the track container:
 890+ //$j('#container_track_'+track_id).empty();
 891+ var track_html=droppable_html='';
 892+ //set up per track vars:
 893+ var track = this.plObj.tracks[track_id];
 894+ var cur_clip_time=0;
 895+
 896+ //set up some constants for timeline_mode == clip:
 897+ if(this.timeline_mode == 'clip'){
 898+ var frame_width = Math.round(this.track_clipThumb_height*1.3333333);
 899+ var container_width = frame_width+60;
 900+ }
 901+
 902+ //for each clip:
 903+ for(var j in track.clips){
 904+ clip = track.clips[j];
 905+ //var img = clip.getClipImg('icon');
 906+ if(this.timeline_mode == 'clip'){
 907+ clip.left_px = j*container_width;
 908+ clip.width_px = container_width;
 909+ var base_id = 'track_'+track_id+'_clip_'+j;
 910+ track_html+='<span id="'+base_id+'" '+
 911+ 'class="mv_storyboard_container mv_clip_drag" '+
 912+ 'style="'+
 913+ 'left:'+clip.left_px+'px;'+
 914+ 'height:' + (this.track_clipThumb_height+30) + 'px;' +
 915+ 'width:'+(container_width)+'px;" >';
 916+ track_html+=clip.embed.renderTimelineThumbnail({
 917+ 'width':frame_width,
 918+ 'thumb_class':'mv_clip_thumb',
 919+ 'height':this.track_clipThumb_height,
 920+ 'time':0
 921+ });
 922+ //render out edit button
 923+ track_html+='<div onClick="'+this.instance_name+'.editClip('+track_id+','+j+')" class="clip_edit_button clip_edit_base"/>';
 924+
 925+ //render out transition edit box
 926+ track_html+='<div style="" id="tb_' + base_id + '" class="clip_trans_box"/>';
 927+
 928+ //render out adjustment text
 929+ track_html+='<div id="' + base_id + '_adj' + '" class="mv_adj_text" style="top:'+ (this.track_clipThumb_height+10 )+'px;">'+
 930+ '<span class="mv_adjust_click" onClick="'+this.instance_name+'.adjClipDur(' + track_id + ',' + j + ',\'-\')" /> - </span>'+
 931+ ( (clip.getDuration() > 60 )? seconds2ntp(clip.getDuration()): clip.getDuration() ) +
 932+ '<span class="mv_adjust_click" onClick="'+this.instance_name+'.adjClipDur(' + track_id + ',' + j + ',\'+\')" /> + </span>'+
 933+ '</div>';
 934+ track_html+='</span>';
 935+
 936+ }
 937+ //do per display type rendering:
 938+ if(this.timeline_mode == 'time'){
 939+ clip.left_px = Math.round( cur_clip_time/this.timeline_scale);
 940+ clip.width_px = Math.round( Math.round( clip.getDuration() )/this.timeline_scale);
 941+ js_log('at time:' + cur_clip_time + ' left: ' +clip.left_px + ' clip dur: ' + Math.round( clip.getDuration() ) + ' clip width:' + clip.width_px);
 942+
 943+ //for every clip_width pixle output image
 944+ if(track.disp_mode=='timeline_thumb'){
 945+ track_html+='<span id="track_'+track_id+'_clip_'+j+'" '+
 946+ 'class="mv_tl_clip mv_clip_drag" '+
 947+ 'style="'+
 948+ 'left:' + clip.left_px + 'px;'+
 949+ 'width:'+ clip.width_px + 'px;'+
 950+ 'height:'+ clip.height_px + 'px" >';
 951+ track_html+= this.render_clip_frames( clip );
 952+ }else if(track.disp_mode=='text'){
 953+ //'+left_px+
 954+ track_html+='<span id="track_'+track_id+'_clip_'+j+'" style="left:'+clip.left_px+'px;'+
 955+ 'width:'+clip.width_px+'px;background:'+clip.getColor()+
 956+ '" class="mv_time_clip_text mv_clip_drag">'+clip.title;
 957+ }
 958+ //add in per clip controls
 959+ track_html+='<div title="'+getMsg('clip_in')+' '+clip.embed.start_ntp+'" class="ui-resizable-w ui-resizable-handle" style="width: 16px; height: 16px; left: 0px; top: 2px;background:url(\''+mv_embed_path+'images/application_side_contract.png\');" ></div>'+"\n";
 960+ track_html+='<div title="'+getMsg('clip_out')+' '+clip.embed.end_ntp+'" class="ui-resizable-e ui-resizable-handle" style="width: 16px; height: 16px; right: 0px; top: 2px;background:url(\''+mv_embed_path+'images/application_side_expand.png\');" ></div>'+"\n";
 961+ track_html+='<div title="'+getMsg('rmclip')+'" onClick="'+this.instance_name + '.removeClips(new Array([' + track_id + ',' + j + ']))" style="position:absolute;cursor:pointer;width: 16px; height: 16px; left: 0px; bottom:2px;background:url(\''+mv_embed_path+'images/delete.png\');"></div>'+"\n";
 962+ track_html+='<span style="display:none;" class="mv_clip_stats"></span>';
 963+
 964+ track_html+='</span>';
 965+ //droppable_html+='<div id="dropBefore_'+i+'_c_'+j+'" class="mv_droppable" style="height:'+this.track_thumb_height+'px;left:'+clip.left_px+'px;width:'+Math.round(clip.width_px/2)+'px"></div>';
 966+ //droppable_html+='<div id="dropAfter_'+i+'_c_'+j+'" class="mv_droppable" style="height:'+this.track_thumb_height+'px;left:'+(clip.left_px+Math.round(clip.width_px/2))+'px;width:'+(clip.width_px/2)+'px"></div>';
 967+ cur_clip_time+=Math.round( clip.getDuration() ); //increment cur_clip_time
 968+ }
 969+
 970+ }
 971+
 972+ //js_log("new htmL for track i: "+track_id + ' html:'+track_html);
 973+ $j('#container_track_'+track_id).html( track_html );
 974+
 975+
 976+ //apply edit button mouse over effect:
 977+ $j('.clip_edit_button').hover(function(){
 978+ $j(this).removeClass("clip_edit_base").addClass("clip_edit_over");
 979+ },function(){
 980+ $j(this).removeClass("clip_edit_over").addClass("clip_edit_base");
 981+ });
 982+
 983+
 984+
 985+ //apply onClick edit controls:
 986+ $j('.mv_clip_thumb').click(function(){
 987+ var cur_clip_click = this;
 988+ //if not in multi select mode remove all existing selections
 989+ //(except for the current click which is handled down below)
 990+ js_log(' ks: ' + this_seq.key_shift_down + ' ctrl_down:' +this_seq.key_ctrl_down);
 991+ if( ! this_seq.key_shift_down && ! this_seq.key_ctrl_down){
 992+ $j('.mv_selected_clip').each(function(inx, selected_clip){
 993+ if( $j(this).parent().attr('id') != $j(cur_clip_click).parent().attr('id')
 994+ || ( $j('.mv_selected_clip').length > 1 ) ){
 995+ $j(this).removeClass("mv_selected_clip");
 996+ $j('#' + $j(this).parent().attr("id") + '_adj').fadeOut("fast");
 997+ }
 998+ });
 999+ }
 1000+
 1001+ //jump to clip time
 1002+ var sClipObj = this_seq.getClipFromSeqID( $j(this).parent().attr('id') );
 1003+ this_seq.plObj.updateCurrentClip( sClipObj );
 1004+ if( $j(this).hasClass("mv_selected_clip") ){
 1005+ $j(this).removeClass("mv_selected_clip");
 1006+ $j('#' + $j(this).parent().attr("id") + '_adj').fadeOut("fast");
 1007+ }else{
 1008+ $j(this).addClass('mv_selected_clip');
 1009+ $j('#' + $j(this).parent().attr("id") + '_adj').fadeIn("fast");
 1010+ }
 1011+ //if shift select is down select the in-between clips
 1012+ if( this_seq.key_shift_down ){
 1013+ //get the min max of current selection (within the current track)
 1014+ var max_order = 0;
 1015+ var min_order = 999999999999999;
 1016+ $j('.mv_selected_clip').each(function(){
 1017+ var cur_clip = this_seq.getClipFromSeqID( $j(this).parent().attr('id') );
 1018+ //get min max
 1019+ if(cur_clip.order < min_order)
 1020+ min_order = cur_clip.order;
 1021+ if(cur_clip.order > max_order)
 1022+ max_order = cur_clip.order;
 1023+ });
 1024+ //select all non-selected between max or min
 1025+ js_log('sOrder: ' + sClipObj.order + ' min:' + min_order + ' max:'+ max_order);
 1026+ if( sClipObj.order <= min_order ){
 1027+ for( var i = sClipObj.order; i <= max_order; i++ ){
 1028+ $j('#track_' + track_id + '_clip_' + i + ' > .mv_clip_thumb' ).addClass('mv_selected_clip');
 1029+ }
 1030+ }
 1031+ if( sClipObj.order >= max_order ){
 1032+ for( var i =min_order; i <= max_order; i++ ){
 1033+ $j('#track_' + track_id + '_clip_' + i + ' > .mv_clip_thumb' ).addClass('mv_selected_clip');
 1034+ }
 1035+ }
 1036+ }
 1037+
 1038+ });
 1039+ //add in control for time based display
 1040+ //debugger;
 1041+ if(this.timeline_mode == 'time'){
 1042+ $j('.ui-resizable-handle').mousedown( function(){
 1043+ js_log('hid: ' + $j(this).attr('class'));
 1044+ this_seq.resize_mode = ($j(this).attr('class').indexOf('ui-resizable-e')!=-1)?
 1045+ 'resize_end':'resize_start';
 1046+ });
 1047+ }
 1048+ var insert_key='na';
 1049+ // drag hooks:
 1050+ //@@todo support multiple clips
 1051+ for(var j in track.clips){
 1052+ $j('#track_'+track_id+'_clip_'+j).draggable({
 1053+ axis:'x',
 1054+ containment:'#container_track_'+track_id,
 1055+ opacity:50,
 1056+ handle: ":not(.clip_control)",
 1057+ scroll:true,
 1058+ drag:function(e, ui){
 1059+ //animate re-arrange by left position:
 1060+ //js_log('left: '+ui.position.left);
 1061+ //locate clip (based on clip duration not animate)
 1062+ var id_parts = this.id.split('_');
 1063+ var track_inx = id_parts[1];
 1064+ var clip_inx = id_parts[3];
 1065+ var clips = this_seq.plObj.tracks[track_inx].clips;
 1066+ var cur_drag_clip = clips[clip_inx];
 1067+ var return_org = true;
 1068+ $j(this).css('zindex',10);
 1069+ //find out where we are inserting and set left border to solid red thick
 1070+ for(var k in clips){
 1071+ if( ui.position.left > clips[k].left_px &&
 1072+ ui.position.left < (clips[k].left_px + clips[k].width_px)){
 1073+ if(clip_inx!=k){
 1074+ //also make sure we are not where we started
 1075+ if(k-1!=clip_inx){
 1076+ $j('#track_'+track_inx+'_clip_'+k).css('border-left', 'solid thick red');
 1077+ insert_key=k;
 1078+ }else{
 1079+ insert_key='na';
 1080+ }
 1081+ }else{
 1082+ insert_key='na';
 1083+ }
 1084+ }else{
 1085+ $j('#track_'+track_inx+'_clip_'+k).css('border-left', 'solid thin white');
 1086+ }
 1087+ }
 1088+ //if greater than the last k insert after
 1089+ if(ui.position.left > (clips[k].left_px + clips[k].width_px) &&
 1090+ k!=clip_inx ){
 1091+ $j('#track_'+track_inx+'_clip_'+k).css('border-right', 'solid thick red');
 1092+ insert_key='end';
 1093+ }else{
 1094+ $j('#track_'+track_inx+'_clip_'+k).css('border-right', 'solid thin white');
 1095+ }
 1096+ },
 1097+ start:function(e,ui){
 1098+ js_log('start drag:' + this.id);
 1099+ //make sure we are ontop
 1100+ $j(this).css({top:'0px',zindex:10});
 1101+ },
 1102+ stop:function(e, ui){
 1103+ $j(this).css({top:'0px',zindex:0});
 1104+
 1105+ var id_parts = this.id.split('_');
 1106+ var track_inx = id_parts[1];
 1107+ var clip_inx = id_parts[3];
 1108+ var clips = this_seq.plObj.tracks[track_inx].clips;
 1109+ var cur_drag_clip = clips[clip_inx];
 1110+
 1111+ if(insert_key!='na' && insert_key!='end' ){
 1112+ cur_drag_clip.order=insert_key-.5;
 1113+ }else if (insert_key=='end'){
 1114+ cur_drag_clip.order=clips.length;
 1115+ }
 1116+ //reorder array based on new order
 1117+ clips.sort(sort_func);
 1118+ function sort_func(a, b){
 1119+ return a.order - b.order;
 1120+ }
 1121+ //assign keys back to order:
 1122+ this_seq.plObj.tracks[track_inx].reOrderClips();
 1123+ //redraw:
 1124+ this_seq.do_refresh_timeline();
 1125+ }
 1126+ });
 1127+ //add in resize hook if in time mode:
 1128+ if(this.timeline_mode == 'time'){
 1129+ $j('#track_'+track_id+'_clip_'+j).resizable({
 1130+ minWidth:10,
 1131+ maxWidth:6000,
 1132+ start: function(e,ui) {
 1133+ //set border to red
 1134+ $j(this).css({'border':'solid thin red'});
 1135+ //fade In Time stats (end or start based on handle)
 1136+ //dragging east (adjusting end time)
 1137+ js_log( 'append to: '+ this.id);
 1138+ $j('#' + this.id + ' > .mv_clip_stats').fadeIn("fast");
 1139+ },
 1140+ stop: function(e,ui) {
 1141+ js_log('stop resize');
 1142+ //restore border
 1143+ $j(this).css('border', 'solid thin white');
 1144+ //remove stats
 1145+ var clip_drag = this;
 1146+ $j('#'+this.id+' > .mv_clip_stats').fadeOut("fast",function(){
 1147+ var id_parts = clip_drag.id.split('_');
 1148+ var track_inx = id_parts[1];
 1149+ var clip_inx = id_parts[3];
 1150+ //update clip
 1151+ this_seq.doEdit({
 1152+ type:this_seq.resize_mode,
 1153+ delta:this_seq.edit_delta,
 1154+ track_inx:track_inx,
 1155+ clip_inx:clip_inx})
 1156+ });
 1157+ },
 1158+ resize: function(e,ui) {
 1159+ //update time stats & render images:
 1160+ this_seq.update_clip_resize(this);
 1161+ }
 1162+ });
 1163+ }
 1164+ }
 1165+ $j('#container_track_'+track_id).width(Math.round( this.timeline_duration / this.timeline_scale));
 1166+ }
 1167+ //debugger;
 1168+ }
 1169+ },
 1170+ getClipFromSeqID:function( clip_seq_id ){
 1171+ js_log('get id from: ' + clip_seq_id);
 1172+ var ct = clip_seq_id.replace('track_','').replace('clip_','').split('_');
 1173+ return this.plObj.tracks[ ct[0] ].clips[ ct[1] ];
 1174+ },
 1175+ //renders clip frames
 1176+ render_clip_frames:function(clip, frame_offset_count){
 1177+ js_log('f:render_clip_frames: ' + clip.id + ' foc:' + frame_offset_count);
 1178+ var clip_frames_html='';
 1179+ var frame_width = Math.round(this.track_thumb_height*1.3333333);
 1180+
 1181+ var pint = (frame_offset_count==null)?0:frame_offset_count*frame_width;
 1182+
 1183+ //js_log("pinit: "+ pint+ ' < '+clip.width_px+' ++'+frame_width);
 1184+ for(var p=pint;p<clip.width_px;p+=frame_width){
 1185+ var clip_time = (p==0)?0:Math.round(p*this.timeline_scale);
 1186+ js_log('rendering clip frames: p:' +p+' '+ (p*this.timeline_scale)+' ' + clip_time);
 1187+ clip_frames_html+=clip.embed.renderTimelineThumbnail({
 1188+ 'width': frame_width,
 1189+ 'thumb_class':'mv_tl_thumb',
 1190+ 'height': this.track_thumb_height,
 1191+ 'size' : "icon", //set size to "icon" preset
 1192+ 'time': clip_time
 1193+ });
 1194+ }
 1195+ js_log('render_clip_frames:'+clip_frames_html);
 1196+ return clip_frames_html;
 1197+ },
 1198+ update_clip_resize:function(clip_element){
 1199+ //js_log('update_clip_resize');
 1200+ var this_seq = this;
 1201+ var id_parts = clip_element.id.split('_');
 1202+ track_inx = id_parts[1];
 1203+ clip_inx = id_parts[3];
 1204+ //set clip:
 1205+ var clip = this.plObj.tracks[ track_inx ].clips[ clip_inx ];
 1206+ var clip_desc ='';
 1207+ //would be nice if getting the width did not flicker the border
 1208+ //@@todo do a work around e in resize function has some screen based offset values
 1209+ clip.width_px = $j(clip_element).width();
 1210+ var width_dif = clip.width_px - Math.round( Math.round( clip.getDuration() )/this.timeline_scale);
 1211+ //var left_px = $j(clip_element).css('left');
 1212+
 1213+ var new_clip_dur = Math.round( clip.width_px*this.timeline_scale );
 1214+ var clip_dif = (new_clip_dur - clip.getDuration() );
 1215+ var clip_dif_str = (clip_dif >0)?'+'+clip_dif:clip_dif;
 1216+ //set the edit global delta
 1217+ this.edit_delta = clip_dif;
 1218+
 1219+ //get new length:
 1220+ clip_desc+='length: ' + seconds2ntp(new_clip_dur) +'('+clip_dif_str+')';
 1221+ if(this_seq.resize_mode=='resize_end'){
 1222+ //expanding right
 1223+ var new_end = seconds2ntp(ntp2seconds(clip.embed.end_ntp)+clip_dif);
 1224+ clip_desc+='<br>end time: ' + new_end;
 1225+ //also shift all the other clips (after the current)
 1226+ //js_log("track_inx: " + track_inx + ' clip inx:'+clip_inx);
 1227+ //$j('#container_track_'+track_inx+' > .mv_clip_drag :gt('+clip_inx+')').each(function(){
 1228+ $j('#container_track_'+track_inx+' > :gt('+clip_inx+')').each(function(){
 1229+ var move_id_parts = this.id.split('_');
 1230+ var move_clip = this_seq.plObj.tracks[move_id_parts[1]].clips[move_id_parts[3]];
 1231+ //js_log('should move:'+ this.id);
 1232+ $j(this).css('left', move_clip.left_px + width_dif);
 1233+ });
 1234+ }else{
 1235+ //expanding left (resize_start)
 1236+ var new_start = seconds2ntp(ntp2seconds(clip.embed.start_ntp)+clip_dif);
 1237+ clip_desc+='<br>start time: ' + new_start;
 1238+ }
 1239+
 1240+ //update clip stats:
 1241+ $j('#'+clip_element.id+' > .mv_clip_stats').html(clip_desc);
 1242+ var frame_width = Math.round(this.track_thumb_height*1.3333333);
 1243+ //check if we need to append some images:
 1244+ var frame_count = $j('#'+clip_element.id+' > img').length;
 1245+ if(clip.width_px > (frame_count * frame_width) ){
 1246+ //if dragging left append
 1247+ js_log('width_px:'+clip.width_px+' framecount:'+frame_count+' Xcw='+(frame_count * frame_width));
 1248+ $j('#'+clip_element.id).append(this.render_clip_frames(clip, frame_count));
 1249+ }
 1250+ },
 1251+ //renders cnt_time
 1252+ render_playheadhead_seeker:function(){
 1253+ //render out time stamps and time "jump" links
 1254+ //first get total width
 1255+ if(this.timeline_mode=='time'){
 1256+ //hide the old control if present
 1257+ $j('#'+this.timeline_id + '_pl_control').remove();
 1258+ //set width based on pixle to time and current length:
 1259+ pixle_length = Math.round( this.timeline_duration / this.timeline_scale);
 1260+ $j('#'+this.timeline_id+'_head_jump').width(pixle_length);
 1261+ //output times every 50pixles
 1262+ var out='';
 1263+ //output time-desc every 50pixles and jump links every 10 pixles
 1264+ var n=0;
 1265+ for(i=0;i<pixle_length;i+=10){
 1266+ out+='<div onclick="'+this.instance_name+'.jt('+i*this.timeline_scale+');"' +
 1267+ ' style="z-index:2;position:absolute;left:'+i+'px;width:10px;height:20px;top:0px;"></div>';
 1268+ if(n==0)
 1269+ out+='<span style="position:absolute;left:'+i+'px;">|'+seconds2ntp(Math.round(i*this.timeline_scale))+'</span>';
 1270+ n++;
 1271+ if(n==10)n=0;
 1272+ }
 1273+ $j('#'+this.timeline_id+'_head_jump').html(out);
 1274+ }
 1275+ if(this.timeline_mode=='clip'){
 1276+ //remove the old one if its still there
 1277+ $j('#'+this.timeline_id +'_pl_control').remove();
 1278+ //render out a playlist clip wide and all the way to the right (only playhead and play button) (outside of timeline)
 1279+ $j('#'+this.sequence_container_id).append('<div id="'+ this.timeline_id +'_pl_control"'+
 1280+ ' style="position:absolute;top:' + (this.plObj.height) +'px;'+
 1281+ 'right:1px;width:'+this.plObj.width+'px;height:'+this.plObj.org_control_height+'" '+
 1282+ 'class="videoPlayer"><div class="controls">'+
 1283+ this.plObj.getControlsHTML() +
 1284+ '</div>'+
 1285+ '</div>');
 1286+ //update time and render out clip dividers .. should be used to show load progress
 1287+ this.plObj.updateBaseStatus();
 1288+
 1289+ //once the controls are in the DOM add hooks:
 1290+ ctrlBuilder.addControlHooks(this.plObj);
 1291+ }
 1292+ },
 1293+ jt:function( jh_time ){
 1294+ js_log('jt:' + jh_time);
 1295+ var this_seq = this;
 1296+ this.playline_time = jh_time;
 1297+ js_log('time: ' + seconds2ntp(jh_time) + ' ' + Math.round(jh_time/this.timeline_scale));
 1298+ //render playline at given time
 1299+ $j('#'+this.timeline_id+'_playline').css('left', Math.round(jh_time/this.timeline_scale)+'px' );
 1300+ cur_pl_time=0;
 1301+ //update the thumb with the requested time:
 1302+ this.plObj.updateThumbTime( jh_time );
 1303+ },
 1304+ //adjusts the current scale
 1305+ zoom_in:function(){
 1306+ this.timeline_scale = this.timeline_scale*.75;
 1307+ this.do_refresh_timeline();
 1308+ js_log('zoomed in:'+this.timeline_scale);
 1309+ },
 1310+ zoom_out:function(){
 1311+ this.timeline_scale = this.timeline_scale*(1+(1/3));
 1312+ this.do_refresh_timeline();
 1313+ js_log('zoom out: '+this.timeline_scale);
 1314+ },
 1315+ do_refresh_timeline:function(){
 1316+ //regen duration
 1317+ this.plObj.getDuration( true );
 1318+ //refresh player:
 1319+ this.plObj.getHTML();
 1320+
 1321+ this.render_playheadhead_seeker();
 1322+ this.render_tracks();
 1323+ this.jt(this.playline_time);
 1324+ }
 1325+
 1326+}
 1327+/* extension to mvPlayList to support sequencer features properties */
 1328+var mvSeqPlayList = function( element ){
 1329+ return this.init( element );
 1330+}
 1331+mvSeqPlayList.prototype = {
 1332+ init:function(element){
 1333+ var myPlObj = new mvPlayList(element);
 1334+ //inherit mvClip
 1335+ for(var method in myPlObj){
 1336+ if(typeof this[method] != 'undefined' ){
 1337+ this['parent_'+method]=myPlObj[method];
 1338+ }else{
 1339+ this[method] = myPlObj[method];
 1340+ }
 1341+ }
 1342+ this.org_control_height = this.pl_layout.control_height;
 1343+ //do specific mods:(controls and title are managed by the sequencer)
 1344+ this.pl_layout.title_bar_height=0;
 1345+ this.pl_layout.control_height=0;
 1346+ },
 1347+ //update the timeline playhead and passalong to parent
 1348+ setSliderValue:function( perc ){
 1349+ js_log("set " + perc + ' of cur_clip: ' + this.cur_clip.order );
 1350+ //$j('#'+ this.seqObj.timeline_id + '_playline').css('left')
 1351+ this.parent_setSliderValue( perc );
 1352+ },
 1353+ getControlsHTML:function(){
 1354+ //get controls from current clip add some playlist specific controls:
 1355+ this.cur_clip.embed.supports['prev_next'] = true;
 1356+ this.cur_clip.embed.supports['options'] = false;
 1357+ return ctrlBuilder.getControls( this.cur_clip.embed );
 1358+ },
 1359+ //override renderDisplay
 1360+ renderDisplay:function(){
 1361+ //setup layout for title and dc_ clip container
 1362+ $j(this).html('<div id="dc_'+this.id+'" style="width:'+this.width+'px;' +
 1363+ 'height:'+(this.height)+'px;position:relative;" />');
 1364+
 1365+ this.setupClipDisplay();
 1366+ }
 1367+}
Property changes on: trunk/extensions/MetavidWiki/skins/mv_embed/libSequencer/mv_sequencer.js
___________________________________________________________________
Added: svn:mergeinfo
Added: svn:eol-style
11368 + native
Index: trunk/extensions/MetavidWiki/skins/mv_embed/libSequencer/mv_clip_edit.js
@@ -0,0 +1,16 @@
 2+/*
 3+hanndles clip edit controls
 4+ 'inoutpoints':0, //should let you set the in and out points of clip
 5+ 'panzoom':0, //should allow setting keyframes and tweening modes
 6+ 'overlays':0, //should allow setting "locked to clip" overlay tracks
 7+ 'audio':0 //should allow controling the audio volume (with keyframes)
 8+*/
 9+
 10+var mvClipEdit = function(initObj) {
 11+ return this.init(initObj);
 12+};
 13+mvClipEdit.prototype = {
 14+ init:function( initObj){
 15+ //setup the clip editor
 16+ }
 17+}
Property changes on: trunk/extensions/MetavidWiki/skins/mv_embed/libSequencer/mv_clip_edit.js
___________________________________________________________________
Added: svn:mergeinfo
Added: svn:eol-style
118 + native
Index: trunk/extensions/MetavidWiki/skins/mv_embed/libSequencer/mv_playlist.js
@@ -0,0 +1,1971 @@
 2+/*
 3+ * the playlist object code
 4+ * only included if playlist object found
 5+ *
 6+ * part of mv_embed:
 7+ * http://metavid.org/wiki/index.php/Mv_embed
 8+ */
 9+var mv_default_playlist_attributes = {
 10+ //playlist attributes :
 11+ "id":null,
 12+ "title":null,
 13+ "width":400,
 14+ "height":300,
 15+ "desc":'',
 16+ "controls":true,
 17+ //playlist user controlled features
 18+ "linkback":null,
 19+ "src":null,
 20+ "embed_link":true,
 21+
 22+ //enable sequencer? (only display top frame no navigation or accompanying text
 23+ "sequencer":false
 24+}
 25+//the call back rate for animations and internal timers in ms: 33 is about 30 frames a second:
 26+var MV_ANIMATION_CB_RATE = 33;
 27+
 28+//globals:
 29+var mv_lock_vid_updates=false;
 30+//10 possible colors for clips: (can be in hexadecimal)
 31+var mv_clip_colors = new Array('aqua', 'blue', 'fuchsia', 'green', 'lime', 'maroon', 'navy', 'olive', 'purple', 'red');
 32+//the base url for requesting stream metadata
 33+if(typeof wgServer=='undefined'){
 34+ var defaultMetaDataProvider = 'http://metavid.org/overlay/archive_browser/export_cmml?stream_name=';
 35+}else{
 36+ var defaultMetaDataProvider = wgServer+wgScript+'?title=Special:MvExportStream&feed_format=roe&stream_name=';
 37+}
 38+
 39+var mvPlayList = function(element) {
 40+ return this.init(element);
 41+};
 42+//set up the mvPlaylist object
 43+mvPlayList.prototype = {
 44+ instanceOf:'mvPlayList',
 45+ pl_duration:null,
 46+ update_tl_hook:null,
 47+ clip_ready_count:0,
 48+ cur_clip:null,
 49+ start_clip:null,
 50+ start_clip_src:null,
 51+ disp_play_head:null,
 52+ userSlide:false,
 53+ loading:true,
 54+ loading_external_data:true, //if we are loading external data (set to loading by default)
 55+
 56+ interface_url:null, //the interface url
 57+ tracks:{},
 58+ default_track:null, // the default track to add clips to.
 59+ //the layout for the playlist object
 60+ pl_layout : {
 61+ seq_title:.1,
 62+ clip_desc:.63, //displays the clip description
 63+ clip_aspect:1.33, // 4/3 video aspect ratio
 64+ seq:.25, //display clip thumbnails
 65+ seq_thumb:.25, //size for thumbnails (same as seq by default)
 66+ seq_nav:0, //for a nav bar at the base (currently disabled)
 67+ //some pl_layout info:
 68+ title_bar_height:17,
 69+ control_height:29
 70+ },
 71+ init : function(element){
 72+ js_log('mvPlayList:init:');
 73+ this.tracks={};
 74+ this.default_track=null;
 75+
 76+ //add default track & default track pointer:
 77+ this.tracks[0]= new trackObj();
 78+ this.default_track = this.tracks[0];
 79+
 80+ //get all the attributes:
 81+ for(var attr in mv_default_playlist_attributes){
 82+ if( element.getAttribute(attr) ){
 83+ this[attr]=element.getAttribute(attr);
 84+ //js_log('attr:' + attr + ' val: ' + video_attributes[attr] +" "+'elm_val:' + element.getAttribute(attr) + "\n (set by elm)");
 85+ }else{
 86+ this[attr]=mv_default_playlist_attributes[attr];
 87+ //js_log('attr:' + attr + ' val: ' + video_attributes[attr] +" "+ 'elm_val:' + element.getAttribute(attr) + "\n (set by attr)");
 88+ }
 89+ }
 90+ //make sure height and width are int:
 91+ this.width =parseInt(this.width);
 92+ this.height=parseInt(this.height);
 93+
 94+ //if style is set override width and height
 95+ if(element.style.width)this.width = parseInt(element.style.width.replace('px',''));
 96+ if(element.style.height)this.height = parseInt(element.style.height.replace('px',''));
 97+ },
 98+ //the element has now been swapped into the dom:
 99+ on_dom_swap:function(){
 100+ js_log('pl: dom swap');
 101+ //get and load the html:
 102+ this.getHTML();
 103+ },
 104+ //run inheritEmbedObj on every clip (we have changed the playback method)
 105+ inheritEmbedObj:function(){
 106+ $j.each(this.tracks, function(i,track){
 107+ track.inheritEmbedObj();
 108+ });
 109+ },
 110+ doOptionsHTML:function(){
 111+ //grab "options" use current clip:
 112+ this.cur_clip.embed.doOptionsHTML();
 113+ },
 114+ //pulls up the video editor inline
 115+ doEditor:function(){
 116+ //black out the page:
 117+ $j('body').append('<div id="mv_overlay"/> '+
 118+ '<div id="modalbox" class="modal_editor">');
 119+
 120+ $j('#modalbox').html('loading editor<blink>...</blink>');
 121+ var _this=this;
 122+ js_log("calling sequence with url:" + _this.src);
 123+
 124+ //clone the playlist (to make for easy cancel)
 125+ /*var this_plObj_Clone = $j('#'+this.id).get(0).cloneNode(true);
 126+ this_plObj_Clone.sequencer=true;
 127+ this_plObj_Clone.id= 'seq_plobj';
 128+ debugger;
 129+ */
 130+ //load sequencer:
 131+ mv_do_sequence({
 132+ "sequence_container_id":'modalbox',
 133+ "mv_pl_src":this.src
 134+ });
 135+
 136+ },
 137+ selectPlaybackMethod:function(){
 138+ this.cur_clip.embed.selectPlaybackMethod();
 139+ },
 140+ closeDisplayedHTML:function(){
 141+ this.cur_clip.embed.closeDisplayedHTML();
 142+ },
 143+ showVideoDownload:function(){
 144+ this.cur_clip.embed.showVideoDownload();
 145+ },
 146+ showEmbedCode:function(){
 147+ var embed_code = '&lt;script type=&quot;text/javascript&quot; '+
 148+ 'src=&quot;'+mv_embed_path+'mv_embed.js&quot;&gt;&lt;/script&gt '+"\n" +
 149+ '&lt;playlist id=&quot;'+this.id+'&quot; ';
 150+ if(this.src){
 151+ embed_code+='src=&quot;'+this.src+'&quot; /&gt;';
 152+ }else{
 153+ embed_code+='&gt;'+"\n";
 154+ embed_code+= this.data.htmlEntities();
 155+ embed_code+='&lt;playlist/&gt;';
 156+ }
 157+ this.cur_clip.embed.showEmbedCode(embed_code);
 158+ },
 159+ getPlaylist:function(){
 160+ js_log("f:getPlaylist: " + this.srcType );
 161+ //@@todo lazy load plLib
 162+ eval('var plObj = '+this.srcType+'Playlist;');
 163+ //import methods from the plObj to this
 164+ for(var method in plObj){
 165+ //js parent preservation for local overwritten methods
 166+ if(this[method])this['parent_' + method] = this[method];
 167+ this[method]=plObj[method];
 168+ js_log('inherit:'+ method);
 169+ }
 170+
 171+ if(typeof this.doParse != 'function'){
 172+ js_log('error: method doParse not found in plObj'+ this.srcType);
 173+ return false;
 174+ }
 175+
 176+ if(typeof this.doParse == 'function'){
 177+ if( this.doParse() ){
 178+ this.doWhenParseDone();
 179+ }else{
 180+ js_log("error: failed to parse playlist");
 181+ return false;
 182+ //error or parse needs to do ajax requests
 183+ }
 184+ }
 185+ },
 186+ doWhenParseDone:function(){
 187+ js_log('f:doWhenParseDone');
 188+ //do additional init for clips:
 189+ var _this = this;
 190+ var error=false;
 191+ _this.clip_ready_count=0;
 192+ for( var i in this.default_track.clips ){
 193+ var clip = this.default_track.clips[i];
 194+ if(clip.embed.load_error){
 195+ var error = clip.embed.load_error;
 196+ //break on any clip we can't playback:
 197+ break;
 198+ }
 199+ if( clip.embed.ready_to_play ){
 200+ _this.clip_ready_count++;
 201+ continue;
 202+ }
 203+ //js_log('clip sources count: '+ clip.embed.media_element.sources.length);
 204+ clip.embed.on_dom_swap();
 205+ if( clip.embed.loading_external_data==false &&
 206+ clip.embed.init_with_sources_loadedDone==false){
 207+ clip.embed.init_with_sources_loaded();
 208+ }
 209+ }
 210+
 211+ //@@todo for some plugins we have to conform types of clips
 212+ // ie vlc can play flash _followed_by_ ogg _followed_by_ whatever
 213+ // but
 214+ // native ff 3.1a2 can only play ogg
 215+ if( error){
 216+ this.load_error=error;
 217+ this.is_ready=false;
 218+ }else if( _this.clip_ready_count == this.getClipCount() ){
 219+ js_log("done init all clips");
 220+ this.doWhenClipLoadDone();
 221+ }else{
 222+ js_log("only "+ _this.clip_ready_count +" clips done, scheduling callback:");
 223+ if( !mvJsLoader.load_error ) //re-issue request if no load error:
 224+ setTimeout('document.getElementById(\''+this.id+'\').doWhenParseDone()', 250);
 225+ }
 226+ },
 227+ doWhenClipLoadDone:function(){
 228+ this.loading = false;
 229+ this.ready_to_play = true;
 230+ this.getHTML();
 231+ },
 232+ getDuration:function( regen ){
 233+ //js_log("GET PL DURRATION for : "+ this.tracks[this.default_track_id].clips.length + 'clips');
 234+ if(!regen && this.pl_duration)
 235+ return this.pl_duration;
 236+
 237+ var durSum=0;
 238+ $j.each( this.default_track.clips, function( i, clip ){
 239+ if( clip.embed ){
 240+ js_log('plDUR:add : '+ clip.getDuration() + ' src:' + clip.embed.src);
 241+ clip.dur_offset = durSum;
 242+ durSum += clip.getDuration();
 243+ }else{
 244+ js_log("ERROR: clip " +clip.id + " not ready");
 245+ }
 246+ });
 247+ this.pl_duration=durSum;
 248+ //js_log("return dur: " + this.pl_duration);
 249+ return this.pl_duration;
 250+ },
 251+ getDataSource:function(){
 252+ js_log("f:getDataSource "+ this.src);
 253+ //determine the type / first is it m3u or xml?
 254+ var pl_parent = this;
 255+ this.makeURLAbsolute();
 256+ if(this.src!=null){
 257+ do_request(this.src, function(data){
 258+ pl_parent.data=data;
 259+ pl_parent.getSourceType();
 260+ });
 261+ }
 262+ },
 263+ getSourceType:function(){
 264+ js_log('data type of: '+ this.src + ' = ' + typeof (this.data) + "\n"+ this.data);
 265+ this.srcType =null;
 266+ //if not external use different detection matrix
 267+ if(this.loading_external_data){
 268+ if( typeof this.data == 'object' ){
 269+ js_log('object');
 270+ //object assume xml (either xspf or rss)
 271+ plElm = this.data.getElementsByTagName('playlist')[0];
 272+ if( plElm ){
 273+ if(plElm.getAttribute('xmlns')=='http://xspf.org/ns/0/'){
 274+ this.srcType ='xspf';
 275+ }
 276+ }
 277+ //check itunes style rss "items"
 278+ rssElm = this.data.getElementsByTagName('rss')[0];
 279+ if(rssElm){
 280+ if(rssElm.getAttribute('xmlns:itunes')=='http://www.itunes.com/dtds/podcast-1.0.dtd'){
 281+ this.srcType='itunes';
 282+ }
 283+ }
 284+ //check for smil tag:
 285+ smilElm = this.data.getElementsByTagName('smil')[0];
 286+ if(smilElm){
 287+ //don't check dtd yet.. (have not defined the smil subset)
 288+ this.srcType='smil';
 289+ }
 290+ }else if(typeof this.data == 'string'){
 291+ js_log('String');
 292+ //look at the first line:
 293+ var first_line = this.data.substring(0, this.data.indexOf("\n"));
 294+ js_log('first line: '+ first_line);
 295+ //string
 296+ if(first_line.indexOf('#EXTM3U')!=-1){
 297+ this.srcType = 'm3u';
 298+ }else if(first_line.indexOf('<smil')!=-1){
 299+ //@@todo parse string
 300+ this.srcType = 'smil';
 301+ }
 302+ }
 303+ }
 304+
 305+ if(this.srcType){
 306+ js_log('is of type:'+ this.srcType);
 307+ this.getPlaylist();
 308+ }else{
 309+ //unknown playlist type
 310+ js_log('unknown playlist type?');
 311+ if(this.src){
 312+ this.innerHTML= 'error: unknown playlist type at url:<br> ' + this.src;
 313+ }else{
 314+ this.innerHTML='error: unset src or unknown inline playlist data<br>';
 315+ }
 316+ }
 317+ },
 318+ //simple function to make a path into an absolute url if its not already
 319+ makeURLAbsolute:function(){
 320+ if(this.src){
 321+ if(this.src.indexOf('://')==-1){
 322+ var purl = parseUri(document.URL);
 323+ if(this.src.charAt(0)=='/'){
 324+ this.src = purl.protocol +'://'+ purl.host + this.src;
 325+ }else{
 326+ this.src= purl.protocol +'://'+ purl.host + purl.directory + this.src;
 327+ }
 328+ }
 329+ }
 330+ },
 331+ //set up minimal media_element emulation:
 332+ media_element:{
 333+ selected_source:{
 334+ supports_url_time_encoding:true
 335+ }
 336+ },
 337+ //@@todo needs to update for multi-track clip counts
 338+ getClipCount:function(){
 339+ return this.default_track.clips.length;
 340+ },
 341+ //},
 342+ //takes in the playlist
 343+ // inherits all the properties
 344+ // swaps in the playlist object html/interface div
 345+ getHTML:function(){
 346+ if(this.loading){
 347+ js_log('called getHTML (loading)');
 348+ $j('#'+this.id).html('loading playlist<blink>...</blink>');
 349+ if(this.loading_external_data){
 350+ //load the data source chain of functions (to update the innerHTML)
 351+ this.getDataSource();
 352+ }else{
 353+ //detect datatype and parse directly:
 354+ this.getSourceType();
 355+ }
 356+ }else{
 357+ //check for empty playlist otherwise renderDisplay:
 358+ if(this.default_track.getClipCount()==0){
 359+ $j(this).html('empty playlist');
 360+ return ;
 361+ }else{
 362+ this.renderDisplay();
 363+ }
 364+ }
 365+ },
 366+ renderDisplay:function(){
 367+ js_log('track length: ' +this.default_track.getClipCount() );''
 368+
 369+ var plObj=this;
 370+ //setup layout for title and dc_ clip container
 371+ $j(this).html('<div id="dc_'+this.id+'" style="width:'+this.width+'px;' +
 372+ 'height:'+(this.height+this.pl_layout.title_bar_height + this.pl_layout.control_height)+'px;position:relative;">' +
 373+ ' <div style="font-size:13px;border:solid thin;width:'+this.width+'px;" id="ptitle_'+this.id+'"></div>' +
 374+ '</div>');
 375+
 376+ //add the playlist controls:
 377+ $j('#dc_'+plObj.id).append(
 378+ '<div class="videoPlayer" style="position:absolute;top:'+(plObj.height+plObj.pl_layout.title_bar_height)+'px">' +
 379+ '<div id="mv_embedded_controls_'+plObj.id+'" ' +
 380+ 'style="postion:relative;top:'+(plObj.height+plObj.pl_layout.title_bar_height)+'px;' +
 381+ 'width:'+plObj.width+'px" ' +
 382+ 'class="controls">' +
 383+ plObj.getControlsHTML() +
 384+ '</div>'+
 385+ '</div>'
 386+ );
 387+ //once the controls are in the DOM add hooks:
 388+ ctrlBuilder.addControlHooks(this);
 389+ //add the play button:
 390+ $j('#dc_'+plObj.id).append(
 391+ this.cur_clip.embed.getPlayButton()
 392+ );
 393+
 394+ this.setupClipDisplay();
 395+
 396+ //update the title and status bar
 397+ this.updateBaseStatus();
 398+ },
 399+ setupClipDisplay:function(){
 400+ var plObj = this;
 401+ $j.each(this.default_track.clips, function(i, clip){
 402+ $j('#dc_'+plObj.id).append('<div class="clip_container" id="clipDesc_'+clip.id+'" '+
 403+ 'style="display:none;position:absolute;text-align: center;border:solid thin;width:'+plObj.width + 'px;'+
 404+ 'height:'+(plObj.height )+'px;'+
 405+ 'top:' + this.title_bar_height + 'px;left:0px"></div>');
 406+ //update the embed html:
 407+ clip.embed.height=plObj.height;
 408+ clip.embed.width=plObj.width;
 409+ clip.embed.play_button=false;
 410+
 411+ clip.embed.getHTML();//get the thubnails for everything
 412+ $j(clip.embed).css({ 'position':"absolute",'top':"0px", 'left':"0px"});
 413+ if($j('#clipDesc_'+clip.id).get(0)){
 414+ $j('#clipDesc_'+clip.id).get(0).appendChild(clip.embed);
 415+ }else{
 416+ js_log('cound not find: clipDesc_'+clip.id);
 417+ }
 418+ });
 419+ if(this.cur_clip)
 420+ $j('#clipDesc_'+this.cur_clip.id).css( { display:'inline' } );
 421+ },
 422+ updateThumbPerc:function( perc ){
 423+ //get float seconds:
 424+ var float_sec = ( this.getDuration() * perc );
 425+ this.updateThumbTime( float_sec );
 426+ },
 427+ updateThumbTime:function( float_sec ){
 428+ //update display & cur_clip:
 429+ var pl_sum_time =0;
 430+ var clip_float_sec=0;
 431+ //js_log('seeking clip: ');
 432+ for(var i in this.default_track.clips){
 433+ var clip = this.default_track.clips[i];
 434+ if( (clip.getDuration() + pl_sum_time) >= float_sec ){
 435+ if(this.cur_clip.id != clip.id){
 436+ $j('#clipDesc_'+this.cur_clip.id).hide();
 437+ this.cur_clip = clip;
 438+ $j('#clipDesc_'+this.cur_clip.id).show();
 439+ }
 440+ break;
 441+ }
 442+ pl_sum_time+=clip.getDuration();
 443+ }
 444+
 445+ //update start_offset
 446+ if(typeof this.cur_clip.embed.start_offset=='undefined'){
 447+ if(!typeof this.cur_clip.embed.media_element.selected_source!='undefined')
 448+ this.cur_clip.embed.start_offset=this.cur_clip.embed.media_element.selected_source.start_offset;
 449+ }
 450+
 451+ //issue thumbnail update request: (if plugin supports it will render out frame
 452+ // if not then we do a call to the server to get a new jpeg thumbnail
 453+ this.cur_clip.embed.updateThumbTime( float_sec - pl_sum_time );
 454+
 455+ this.cur_clip.embed.currentTime = (float_sec -pl_sum_time)+this.cur_clip.embed.start_offset ;
 456+ this.cur_clip.embed.seek_time_sec = (float_sec -pl_sum_time );
 457+
 458+ //render effects ontop: (handled by doSmilActions)
 459+ this.doSmilActions( single_line = true );
 460+ },
 461+ updateBaseStatus:function(){
 462+ js_log('f:updateBaseStatus');
 463+ $j('#ptitle_'+this.id).html(''+
 464+ '<b>' + this.title + '</b> '+
 465+ this.getClipCount()+' clips, <i>'+
 466+ seconds2ntp( this.getDuration() ) + '</i>' +
 467+ '<a href="#" onclick="$j(\'#'+this.id+'\').get(0).doEditor();" style="position:absolute;top:0px;right:0px">edit</a>');
 468+ //render out the dividers on the timeline:
 469+ this.colorPlayHead();
 470+ //update status:
 471+ this.setStatus('0:0:00/'+seconds2ntp( this.getDuration() ));
 472+ },
 473+ /*setStatus override (could call the jquery directly) */
 474+ setStatus:function(value){
 475+ $j('#mv_time_'+this.id).html( value );
 476+ },
 477+ setSliderValue:function(value){
 478+ //js_log('calling original embed slider with val: '+value);
 479+ this.cur_clip.embed.pe_setSliderValue( value );
 480+ //call seq playline update here
 481+ },
 482+ getSeqThumb: function(){
 483+ //for each clip
 484+ if(this.getClipCount()>3){
 485+ this.pl_layout.seq_thumb=.17;
 486+ }else{
 487+ this.pl_layout.seq_thumb=.25;
 488+ }
 489+ $j.each(this.default_track.clips, function(i,n){
 490+ //js_log('add thumb for:' + n.src);
 491+ n.getThumb();
 492+ });
 493+ },
 494+ getPlayHeadPos: function(prec_done){
 495+ var plObj = this;
 496+ if($j('#mv_seeker_'+this.id).length==0){
 497+ //js_log('no playhead so we can\'t get playhead pos' );
 498+ return 0;
 499+ }
 500+ var track_len = $j('#mv_seeker_'+this.id).css('width').replace(/px/, '');
 501+ //assume the duration is static and present at .duration during playback
 502+ var clip_perc = this.cur_clip.embed.duration / this.getDuration();
 503+ var perc_offset =time_offset = 0;
 504+ for(var i in this.default_track.clips){
 505+ var clip = this.default_track.clips[i];
 506+ if(this.cur_clip.id ==clip.id)break;
 507+ perc_offset+=(clip.embed.duration / plObj.getDuration());
 508+ time_offset+=clip.embed.duration;
 509+ }
 510+ //run any update time line hooks:
 511+ if(this.update_tl_hook){
 512+ var cur_time_ms = time_offset + Math.round(this.cur_clip.embed.duration*prec_done);
 513+ if(typeof update_tl_hook =='function'){
 514+ this.update_tl_hook(cur_time_ms);
 515+ }else{
 516+ //string type passed use eval:
 517+ eval(this.update_tl_hook+'('+cur_time_ms+');');
 518+ }
 519+ }
 520+
 521+ //handle offset hack @@todo fix so this is not needed:
 522+ if(perc_offset > .66)
 523+ perc_offset+=(8/track_len);
 524+ //js_log('perc:'+ perc_offset +' c:'+ clip_perc + '*' + prec_done + ' v:'+(clip_perc*prec_done));
 525+ return perc_offset + (clip_perc*prec_done);
 526+ },
 527+ //attempts to load the embed object with the playlist
 528+ loadEmbedPlaylist: function(){
 529+ //js_log('load playlist');
 530+ },
 531+ //called when the plugin advances to the next clip in the playlist
 532+ playlistNext:function(){
 533+ js_log('pl advance');
 534+ this.cur_clip=this.getClip(1);
 535+ },
 536+ next: function(){
 537+ //advance the playhead to the next clip
 538+ var next_clip = this.getClip(1);
 539+ //@@todo where the plugin supports pre_loading future clips and manage that in javascript
 540+ //stop current clip
 541+ this.cur_clip.embed.stop();
 542+ this.updateCurrentClip(next_clip);
 543+ this.cur_clip.embed.play();
 544+ },
 545+ updateCurrentClip:function(new_clip){
 546+ js_log('f:updateCurrentClip:'+new_clip.id);
 547+ //do swap:
 548+ $j('#clipDesc_'+this.cur_clip.id).hide();
 549+ this.cur_clip=new_clip;
 550+ $j('#clipDesc_'+this.cur_clip.id).show();
 551+ //update the playhead:
 552+ this.setSliderValue( this.cur_clip.dur_offset / this.getDuration() );
 553+ },
 554+ prev: function(){
 555+ //advance the playhead to the previous clip
 556+ var prev_clip = this.getClip(-1);
 557+ //@@todo we could do something fancy like use playlist for sets of clips where supported.
 558+ // or in cases where the player nativly supports the playlist format we can just pass it in (ie m3u or xspf)
 559+ if(this.cur_clip.embed.supports['playlist_swap_loader']){
 560+ //where the plugin supports pre_loading future clips and manage that in javascript
 561+ //pause current clip
 562+ this.cur_clip.embed.pause;
 563+ //do swap:
 564+ this.updateCurrentClip(prev_clip);
 565+ this.cur_clip.embed.play();
 566+ }else{
 567+ js_log('do prev hard embed swap');
 568+ this.switchPlayingClip(prev_clip);
 569+ }
 570+ },
 571+ switchPlayingClip:function(new_clip){
 572+ //swap out the existing embed code for next clip embed code
 573+ $j('#mv_ebct_'+this.id).empty();
 574+ new_clip.embed.width=this.width;
 575+ new_clip.embed.height=this.height;
 576+ //js_log('set embed to: '+ new_clip.embed.getEmbedObj());
 577+ $j('#mv_ebct_'+this.id).html( new_clip.embed.getEmbedObj() );
 578+ this.cur_clip=new_clip;
 579+ //run js code:
 580+ this.cur_clip.embed.pe_postEmbedJS();
 581+ },
 582+ //playlist play
 583+ play: function(){
 584+ var plObj=this;
 585+ js_log('pl play');
 586+ //hide the playlist play button:
 587+ $j('#big_play_link_'+this.id).hide();
 588+
 589+ //un-pause if paused:
 590+ if(this.paused)
 591+ this.paused=false;
 592+
 593+ this.start_clip = this.cur_clip;
 594+ this.start_clip_src= this.cur_clip.src;
 595+
 596+ if(this.cur_clip.embed.supports['playlist_swap_loader'] ){
 597+ //navtive support:
 598+ // * pre-loads clips
 599+ // * mv_playlist smil extension, manages transitions animations overlays etc.
 600+ js_log('clip obj supports playlist swap_loader (ie playlist controlled playback)');
 601+ //update cur clip based if sequence playhead set:
 602+ var d = new Date();
 603+ this.clockStartTime = d.getTime();
 604+
 605+ this.monitor();
 606+
 607+ //@@todo pre-load each clip:
 608+ this.cur_clip.embed.play();
 609+ }else if(this.cur_clip.embed.supports['playlist_driver']){
 610+ js_log('playlist_driver');
 611+ //embedObject is feed the playlist info directly and manages next/prev
 612+ this.cur_clip.embed.playMovieAt(this.cur_clip.order);
 613+ }else{
 614+ //not much playlist support just play the first clip:
 615+ js_log('basic play');
 616+ //play cur_clip
 617+ this.cur_clip.embed.play();
 618+ }
 619+ },
 620+ toggleMute:function(){
 621+ this.cur_clip.embed.toggleMute();
 622+ },
 623+ pause:function(){
 624+ js_log('f:pause: playlist');
 625+ var ct = new Date();
 626+ this.pauseTime = this.currentTime;
 627+ js_log('pause time: '+ this.pauseTime);
 628+
 629+ window.clearInterval( this.smil_monitorTimerId );
 630+ },
 631+ fullscreen:function(){
 632+ this.cur_clip.embed.fullscreen();
 633+ },
 634+ //playlist stops playback for the current clip (and resets state for start clips)
 635+ stop:function(){
 636+ /*js_log("pl stop:"+ this.start_clip.id + ' c:'+this.cur_clip.id);
 637+ //if start clip
 638+ if(this.start_clip.id!=this.cur_clip.id){
 639+ //restore clipDesc visibility & hide desc for start clip:
 640+ $j('#clipDesc_'+this.start_clip.id).html('');
 641+ this.start_clip.getDetail();
 642+ $j('#clipDesc_'+this.start_clip.id).css({display:'none'});
 643+ this.start_clip.setBaseEmbedDim(this.start_clip.embed);
 644+ //equivalent of base stop
 645+ $j('#'+this.start_clip.embed.id).html(this.start_clip.embed.getThumbnailHTML());
 646+ this.start_clip.embed.thumbnail_disp=true;
 647+ }
 648+ //empty the play-back container
 649+ $j('#mv_ebct_'+this.id).empty();*/
 650+
 651+ //make sure the current clip is vissable:
 652+ $j('#clipDesc_'+this.cur_clip.id).css({display:'inline'});
 653+
 654+ //do stop current clip
 655+ this.cur_clip.embed.stop();
 656+ //stop the monitor:
 657+ window.clearInterval( this.smil_monitorTimerId );
 658+ },
 659+ doSeek:function(v){
 660+ js_log('pl:doSeek:'+v);
 661+ var plObj = this;
 662+ var prevClip=null;
 663+ //jump to the clip in the current percent.
 664+ var perc_offset=0;
 665+ var next_perc_offset=0;
 666+ for(var i in plObj.default_track.clips){
 667+ var clip = plObj.default_track.clips[i];
 668+ next_perc_offset+=( clip.getDuration() / plObj.getDuration()) ;
 669+ //js_log('on ' + clip.getDuration() +' next_perc_offset:'+ next_perc_offset);
 670+ if(next_perc_offset > v ){
 671+ //pass along the relative percentage to embed object:
 672+ //js_log('seek:'+ v +' - '+perc_offset + ') / (' + next_perc_offset +' - '+ perc_offset);
 673+ var relative_perc = (v -perc_offset) / (next_perc_offset - perc_offset);
 674+ plObj.cur_clip = clip;
 675+ plObj.cur_clip.embed.doSeek( relative_perc );
 676+ this.play();
 677+ return '';
 678+ }
 679+ perc_offset = next_perc_offset;
 680+ }
 681+ },
 682+ //gets playlist controls large control height for sporting
 683+ //next prev button and more status display
 684+ getControlsHTML:function(){
 685+ //get controls from current clip (add some playlist specific controls:
 686+ this.cur_clip.embed.supports['prev_next']=true;
 687+ return ctrlBuilder.getControls(this.cur_clip.embed);
 688+ },
 689+ //ads colors/dividers between tracks
 690+ colorPlayHead: function(){
 691+ if( !this.mv_seeker_width)
 692+ this.mv_seeker_width = $j('#mv_seeker_slider_'+this.id).width();
 693+
 694+ if( !this.track_len )
 695+ this.track_len = $j('#seeker_bar_'+this.id).css('width').replace(/px/, '');
 696+
 697+ //total duration:
 698+ var pl_duration = this.getDuration();
 699+
 700+ var cur_pixle=0;
 701+ //set up plObj
 702+ var _this = this;
 703+ //js_log("do play head total dur: "+pl_duration );
 704+ $j.each(this.default_track.clips, function(i, clip){
 705+ var perc = ( clip.getDuration() / pl_duration );
 706+ var pwidth = Math.round( perc * _this.track_len);
 707+ //var pwidth = Math.round( perc * _this.track_len - (_this.mv_seeker_width*perc) );
 708+
 709+ var barHtml = '<div id="cl_status_'+clip.id+'" class="cl_status" style="' +
 710+ 'left:'+cur_pixle +'px;'+
 711+ 'width:'+pwidth + 'px;';
 712+ //set left or right border based on track pos
 713+ barHtml+=( i == _this.default_track.getClipCount()-1 )?
 714+ 'border-left:solid thin black;':
 715+ 'border-right:solid thin black;';
 716+ barHtml+= 'filter:alpha(opacity=40);'+
 717+ '-moz-opacity:.40;">'
 718+ '</div>';
 719+ //background:#DDDclip.getColor()
 720+ $j('#seeker_bar_'+_this.id).append(barHtml);
 721+
 722+ //js_log('offset:' + cur_pixle +' width:'+pwidth+' add clip'+ clip.id + ' is '+clip.embed.getDuration() +' = ' + perc +' of ' + _this.track_len);
 723+ cur_pixle+=pwidth;
 724+ });
 725+ },
 726+ setUpHover:function(){
 727+ js_log('Setup Hover');
 728+ //set up hover for prev,next
 729+ var th = 50;
 730+ var tw = th*this.pl_layout.clip_aspect;
 731+ var plObj = this;
 732+ $j('#mv_prev_link_'+plObj.id+',#mv_next_link_'+plObj.id).hover(function() {
 733+ var clip = (this.id=='mv_prev_link_'+plObj.id)?
 734+ plObj.getClip(-1):plObj.getClip(1);
 735+ //get the position of #mv_perv|next_link:
 736+ var loc = getAbsolutePos(this.id);
 737+ //js_log('Hover: x:'+loc.x + ' y:' + loc.y + ' :'+clip.img);
 738+ $j("body").append('<div id="mv_Athub" style="position:absolute;' +
 739+ 'top:'+loc.y+'px;left:'+loc.x+'px;width:'+tw+'px;height:'+th+'px;">'+
 740+ '<img style="border:solid 2px '+clip.getColor()+';position:absolute;top:0px;left:0px;" width="'+tw+'" height="'+th+'" src="'+clip.img+'"/>'+
 741+ '</div>');
 742+ }, function() {
 743+ $j('#mv_Athub').remove();
 744+ });
 745+ },
 746+ //returns a clip. If offset is out of bound returns first or last clip
 747+ getClip: function(clip_offset){
 748+ if(!clip_offset)clip_offset=0;
 749+
 750+ var cov = parseInt( this.cur_clip.order ) + parseInt( clip_offset );
 751+ var cmax = this.getClipCount()-1;
 752+ js_log( 'f:getClip: '+clip_offset + ' cov:'+cov +' cmax:'+ cmax);
 753+
 754+ //force first or last clip if offset is outOfBounds
 755+ if( cov >= 0 && cov <= cmax ){
 756+ return this.default_track.clips[ cov ];
 757+ }else{
 758+ if(cov < 0) return this.default_track.clips[0];
 759+ if(cov > cmax) return this.default_track.clips[cmax];
 760+ }
 761+ },
 762+ /*
 763+ * generic add Clip to ~default~ track
 764+ */
 765+ addCliptoTrack: function(clipObj, pos){
 766+ if( typeof clipObj['track_id'] =='undefined'){
 767+ var track = this.default_track;
 768+ }else{
 769+ var track = this.tracks[ clipObj.track_id ]
 770+ }
 771+ js_log('add clip' + clipObj.id +' to track: at:' + pos);
 772+ //set the first clip to current (maybe deprecated )
 773+ if(clipObj.order==0){
 774+ if(!this.cur_clip)this.cur_clip=clipObj;
 775+ }
 776+ track.addClip(clipObj, pos);
 777+ },
 778+ swapClipDesc: function(req_clipID, callback){
 779+ //hide all but the requested
 780+ var plObj=this;
 781+ js_log('r:'+req_clipID+' cur:'+plObj.id);
 782+ if(req_clipID==plObj.cur_clip.id){
 783+ js_log('no swap to same clip');
 784+ }else{
 785+ //fade out clips
 786+ req_clip=null;
 787+ $j.each(this.default_track.clips, function(i, clip){
 788+ if(clip.id!=req_clipID){
 789+ //fade out if display!=none already
 790+ if($j('#clipDesc_'+clip.id).css('display')!='none'){
 791+ $j('#clipDesc_'+clip.id).fadeOut("slow");
 792+ }
 793+ }else{
 794+ req_clip =clip;
 795+ }
 796+ });
 797+ //fade in requested clip *and set req_clip to current
 798+ $j('#clipDesc_'+req_clipID).fadeIn("slow", function(){
 799+ plObj.cur_clip = req_clip;
 800+ if(callback)
 801+ callback();
 802+ });
 803+ }
 804+ },
 805+ getPLControls: function(){
 806+ js_log('getPL cont');
 807+ return '<a id="mv_prev_link_'+this.id+'" title="Previus Clip" onclick="document.getElementById(\''+this.id+'\').prev();return false;" href="#">'+
 808+ getTransparentPng({id:'mv_prev_btn_'+this.id,style:'float:left',width:'27', height:'27', border:"0",
 809+ src:mv_embed_path+'images/vid_prev_sm.png' }) +
 810+ '</a>'+
 811+ '<a id="mv_next_link_'+this.id+'" title="Next Clip" onclick="document.getElementById(\''+this.id+'\').next();return false;" href="#">'+
 812+ getTransparentPng({id:'mv_next_btn_'+this.id,style:'float:left',width:'27', height:'27', border:"0",
 813+ src:mv_embed_path+'images/vid_next_sm.png' }) +
 814+ '</a>';
 815+ },
 816+ run_transition: function( clip_inx, trans_type){
 817+ if(typeof this.default_track.clips[ clip_inx ][ trans_type ] == 'undefined')
 818+ clearInterval( this.default_track.clips[ clip_inx ].timerId );
 819+ else
 820+ this.default_track.clips[ clip_inx ][ trans_type ].run_transition();
 821+ }
 822+}
 823+var gclipFocus=null;
 824+//delay the swap by .2 seconds
 825+function mvSeqOver(clipID,playlistID){
 826+ setTimeout('doMvSeqOver(\''+clipID+'\',\''+playlistID+'\')', 200);
 827+ gclipFocus=clipID;
 828+}
 829+function mvSeqOut(){
 830+ gclipFocus=null;
 831+}
 832+function doMvSeqOver(clipID, playlistID){
 833+ if(!mv_lock_vid_updates){
 834+ if(gclipFocus==clipID){
 835+ plElm = document.getElementById(playlistID);
 836+ //js_log("got playlist by id: "+ plElm.id);
 837+ if(plElm)plElm.swapClipDesc(clipID);
 838+ }
 839+ }
 840+}
 841+
 842+/* Object Stubs:
 843+ *
 844+ * @videoTrack ... stores clips and layer info
 845+ *
 846+ * @clip... each clip segment is a clip object.
 847+ * */
 848+var mvClip = function(o) {
 849+ if(o)
 850+ this.init(o);
 851+ return this;
 852+};
 853+//set up the mvPlaylist object
 854+mvClip.prototype = {
 855+ id:null, //clip id
 856+ pp:null, // parent playlist
 857+ order:null, //the order/array key for the current clip
 858+ src:null,
 859+ info:null,
 860+ title:null,
 861+ mvclip:null,
 862+ type:null,
 863+ img:null,
 864+ duration:null,
 865+ loading:false,
 866+ isAnimating:false,
 867+ init:function(o){
 868+ //init object including pointer to parent
 869+ for(var i in o){
 870+ this[i]=o[i];
 871+ };
 872+ js_log('id is: '+ this.id);
 873+ },
 874+ //setup the embed object:
 875+ setUpEmbedObj:function(){
 876+ js_log('pl:setUpEmbedObj');
 877+ //init:
 878+ //debugger;
 879+
 880+ this.embed=null;
 881+ //js_log('setup embed for clip '+ this.id + ':id is a function?');
 882+ //set up the pl_mv_embed object:
 883+ var init_pl_embed={id:'e_'+this.id,
 884+ pc:this, //parent clip
 885+ src:this.src
 886+ };
 887+
 888+ this.setBaseEmbedDim(init_pl_embed);
 889+ //always display controls for playlists:
 890+
 891+ //if in sequence mode hide controls / embed links
 892+ // init_pl_embed.play_button=false;
 893+ init_pl_embed.controls=false;
 894+ //if(this.pp.sequencer=='true'){
 895+ init_pl_embed.embed_link=null;
 896+ init_pl_embed.linkback=null;
 897+
 898+ if(this.poster)init_pl_embed['thumbnail']=this.poster;
 899+
 900+ if(this.type)init_pl_embed['type'] = this.type;
 901+
 902+ this.embed = new PlMvEmbed(init_pl_embed);
 903+
 904+ js_log('ve src len:' + this.embed.media_element.sources.length);
 905+ //js_log('media element:'+ this.embed.media_element.length);
 906+ //js_log('type of embed:' + typeof(this.embed) + ' seq:' + this.pp.sequencer+' pb:'+ this.embed.play_button);
 907+ },
 908+ doAdjust:function(side, delta){
 909+ js_log("f:doAdjust: " + side + ' , ' + delta);
 910+ if(this.embed){
 911+ if(side=='start'){
 912+ var start_offset =parseInt(this.embed.start_offset)+parseInt(delta*-1);
 913+ this.embed.updateVideoTime( seconds2ntp(start_offset), seconds2ntp ( this.embed.start_offset + this.embed.getDuration() ) );
 914+ }else if(side=='end'){
 915+ var end_offset = parseInt(this.embed.start_offset) + parseInt( this.embed.getDuration() ) + parseInt(delta);
 916+ this.embed.updateVideoTime( seconds2ntp(this.embed.start_offset), seconds2ntp(end_offset) );
 917+ }
 918+ //update everything:
 919+ this.pp.refresh();
 920+ /*var base_src = this.src.substr(0,this.src.indexOf('?'));
 921+ js_log("delta:"+ delta);
 922+ if(side=='start'){
 923+ //since we adjust start invert the delta:
 924+ var start_offset =parseInt(this.embed.start_offset/1000)+parseInt(delta*-1);
 925+ this.src = base_src +'?t='+ seconds2ntp(start_offset) +'/'+ this.embed.end_ntp;
 926+ }else if(side=='end'){
 927+ //put back into seconds for adjustment:
 928+ var end_offset = parseInt(this.embed.start_offset/1000) + parseInt(this.embed.duration/1000) + parseInt(delta);
 929+ this.src = base_src +'?t='+ this.embed.start_ntp +'/'+ seconds2ntp(end_offset);
 930+ }
 931+ this.embed.updateVideoTime( this.src );
 932+ //update values
 933+ this.duration = this.embed.getDuration();
 934+ this.pp.pl_duration=null;
 935+ //update playlist stuff:
 936+ this.pp.updateTitle();*/
 937+ }
 938+ },
 939+ getDuration:function(){
 940+ if(!this.embed)this.setUpEmbedObj();
 941+ return this.embed.getDuration();
 942+ },
 943+ setBaseEmbedDim:function(o){
 944+ if(!o)o=this;
 945+ //o.height=Math.round(pl_layout.clip_desc*this.pp.height)-2;//give it some padding:
 946+ //o.width=Math.round(o.height*pl_layout.clip_aspect)-2;
 947+ o.height= this.pp.height;
 948+ o.width = this.pp.width;
 949+ },
 950+ //output the detail view:
 951+ //@@todo
 952+ /*getDetail:function(){
 953+ //js_log('get detail:' + this.pp.title);
 954+ var th=Math.round( this.pl_layout.clip_desc * this.pp.height );
 955+ var tw=Math.round( th * this.pl_layout.clip_aspect );
 956+
 957+ var twDesc = (this.pp.width-tw)-2;
 958+
 959+ if(this.title==null)
 960+ this.title='clip ' + this.order + ' ' +this.pp.title;
 961+ if(this.desc==null)
 962+ this.desc=this.pp.desc;
 963+ //update the embed html:
 964+ this.embed.getHTML();
 965+
 966+ $j(this.embed).css({ 'position':"absolute",'top':"0px", 'left':"0px"});
 967+
 968+ //js_log('append child to:#clipDesc_'+this.id);
 969+ if($j('#clipDesc_'+this.id).get(0)){
 970+ $j('#clipDesc_'+this.id).get(0).appendChild(this.embed);
 971+
 972+ $j('#clipDesc_'+this.id).append(''+
 973+ '<div id="pl_desc_txt_'+this.id+'" class="pl_desc" style="position:absolute;left:'+(tw+2)+'px;width:'+twDesc+'px;height:'+th+'px;overflow:auto;">'+
 974+ '<b>'+this.title+'</b><br>'+
 975+ this.desc + '<br>' +
 976+ '<b>clip length:</b> '+ this.embed.getDurationNTP()+
 977+ '</div>');
 978+ }
 979+ },*/
 980+ getTitle:function(){
 981+ if(typeof this.title == 'string')
 982+ return this.title
 983+
 984+ return 'untitled clip ' + this.order;
 985+ },
 986+ getThumb:function(){
 987+ var out='';
 988+ //if we have the parent playlist grab it to get the image scale
 989+ if(this.pp){
 990+ //js_log('pl height:' + this.pp.height + ' * ' + pl_layout.seq);
 991+ var th = Math.round( this.pp.height * this.pl_layout.seq_thumb );
 992+ //assume standard 4 by 3 video thumb res:
 993+ var tw = Math.round( th * this.pl_layout.clip_aspect );
 994+ //js_log('set by relative position:'+ th + ' '+tw);
 995+ }
 996+ var img = this.getClipImg();
 997+
 998+ out+='<span ';
 999+ if(this.title)out+='title="'+this.title+'" ';
 1000+ out+='style="position:relative;display:inline;padding:2px;" ';
 1001+ out+='onclick="document.getElementById(\''+this.pp.id+'\').play()" ';
 1002+ out+='onmouseover="mvSeqOver(\''+this.id+'\',\''+this.pp.id+'\')" ';
 1003+ out+='onmouseout="mvSeqOut()" ';
 1004+ out+='>';
 1005+ out+='<img style="border:solid 2px '+this.getColor()+'" height="'+th+'" width="'+tw+'" src="'+img+'"></span>';
 1006+
 1007+ $j('#seqThumb_'+this.pp.id).append(out);
 1008+ },
 1009+ getClipImg:function(start_offset, size){
 1010+ js_log('f:getClipImg ' + start_offset + ' s:'+size);
 1011+ if( !this.img){
 1012+ return mv_default_thumb_url;
 1013+ }else{
 1014+ if(!size && !start_offset){
 1015+ return this.img;
 1016+ }else{
 1017+ //if a metavid image (has request parameters) use size and time args
 1018+ if(this.img.indexOf('?')!=-1){
 1019+ js_log('get with offset: '+ start_offset);
 1020+ var time = seconds2ntp( start_offset+ (this.embed.start_offset/1000) );
 1021+ js_log("time is: " + time);
 1022+ this.img = this.img.replace(/t\=[^&]*/gi, "t="+time);
 1023+ if(this.img.indexOf('&size=')!=-1){
 1024+ this.img = this.img.replace(/size=[^&]*/gi, "size="+size);
 1025+ }else{
 1026+ this.img+='&size='+size;
 1027+ }
 1028+ }
 1029+ return this.img;
 1030+ }
 1031+ }
 1032+ },
 1033+ getColor: function(){
 1034+ //js_log('get color:'+ num +' : '+ num.toString().substr(num.length-1, 1) + ' : '+colors[ num.toString().substr(num.length-1, 1)] );
 1035+ var num = this.id.substr( this.id.length-1, 1);
 1036+ if(!isNaN(num)){
 1037+ num=num.charCodeAt(0);
 1038+ }
 1039+ if(num >= 10)num=num % 10;
 1040+ return mv_clip_colors[num];
 1041+ }
 1042+}
 1043+/* mv_embed extensions for playlists */
 1044+var PlMvEmbed=function(vid_init){
 1045+ //js_log('PlMvEmbed: '+ vid_init.id);
 1046+ //create the div container
 1047+ var ve = document.createElement('div');
 1048+ //extend ve with all this
 1049+ this.init(vid_init);
 1050+ for(method in this){
 1051+ if(method!='readyState'){
 1052+ ve[method]= this[method];
 1053+ }
 1054+ }
 1055+ js_log('ve src len:'+ ve.media_element.sources.length);
 1056+ return ve;
 1057+}
 1058+//all the overwritten and new methods for playlist extension of mv_embed
 1059+PlMvEmbed.prototype = {
 1060+ init:function(vid_init){
 1061+ //send embed_video a created video element:
 1062+ ve = document.createElement('div');
 1063+ for(var i in vid_init){
 1064+ //set the parent clip pointer:
 1065+ if(i=='pc'){
 1066+ this['pc']=vid_init['pc'];
 1067+ }else{
 1068+ ve.setAttribute(i,vid_init[i]);
 1069+ }
 1070+ }
 1071+ var videoInterface = new embedVideo(ve);
 1072+ //inherit the videoInterface
 1073+ for(method in videoInterface){
 1074+ if(method!='style'){
 1075+ if(this[method]){
 1076+ //parent embed method preservation:
 1077+ this['pe_'+method]=videoInterface[method];
 1078+ }else{
 1079+ this[method]=videoInterface[method];
 1080+ }
 1081+ }
 1082+ //string -> boolean:
 1083+ if(this[method]=="false")this[method]=false;
 1084+ if(this[method]=="true")this[method]=true;
 1085+ }
 1086+ },
 1087+ stop:function(){
 1088+ //set up convenience pointer to parent playlist
 1089+ var plObj = this.pc.pp;
 1090+ var plEmbed = this;
 1091+
 1092+ js_log('do stop');
 1093+ var th=Math.round( plObj.pl_layout.clip_desc * plObj.height );
 1094+ var tw=Math.round( th * plObj.pl_layout.clip_aspect );
 1095+ //run the parent stop:
 1096+ this.pe_stop();
 1097+ var pl_height = (plObj.sequencer=='true')?plObj.height+27:plObj.height;
 1098+ //restore control offsets:
 1099+ /*(if(this.pc.pp.controls){
 1100+ $j('#dc_'+plObj.id).animate({
 1101+ height:pl_height
 1102+ },"slow");
 1103+ }*/
 1104+ //if(plObj.sequencer=='true'){
 1105+ plEmbed.getHTML();
 1106+ /*}else{
 1107+ //fade in elements
 1108+ $j('#big_play_link_'+this.id+',#lb_'+this.id+',#le_'+this.id+',#seqThumb_'+plObj.id+',#pl_desc_txt_'+this.pc.id).fadeIn("slow");
 1109+ //animate restore of resize
 1110+ var res ={};
 1111+ this.pc.setBaseEmbedDim(res);
 1112+ //debugger;
 1113+ $j('#img_thumb_'+this.id).animate(res,"slow",null,function(){
 1114+ plEmbed.pc.setBaseEmbedDim(plEmbed);
 1115+ plEmbed.getHTML();
 1116+ //restore the detail
 1117+ $j('#clipDesc_'+plEmbed.pc.id).empty();
 1118+ plEmbed.pc.getDetail();
 1119+ //$j('#seqThumb_'+plObj.id).css({position:'absolute',bottom:Math.round(this.height* pl_layout.seq_nav)});
 1120+ //$j('#'+plEmbed.id+',#dc_'+plEmbed.id).css({position:'absolute', zindex:0,width:tw,height:th});
 1121+ });
 1122+ }*/
 1123+ },
 1124+ play:function(){
 1125+ js_log('pl eb play');
 1126+ var plEmbed = this;
 1127+ var plObj = this.pc.pp;
 1128+ //check if we are already playing
 1129+ if( !this.thumbnail_disp ){
 1130+ plEmbed.pe_play();
 1131+ return '';
 1132+ }
 1133+ mv_lock_vid_updates=true;
 1134+
 1135+ js_log('controls: '+plObj.controls);
 1136+ //fade out interface elements
 1137+ /*$j('#big_play_link_'+this.id+',#seqThumb_'+plObj.id+',#pl_desc_txt_'+this.pc.id).fadeOut("slow");*/
 1138+ plEmbed.pe_play();
 1139+ },
 1140+ //do post interface operations
 1141+ postEmbedJS:function(){
 1142+ //add playlist clips (if plugin supports it)
 1143+ if(this.pc.pp.cur_clip.embed.playlistSupport())
 1144+ this.pc.pp.loadEmbedPlaylist();
 1145+ //color playlist points (if play_head present)
 1146+ if(this.pc.pp.disp_play_head)
 1147+ this.pc.pp.colorPlayHead();
 1148+ //setup hover images (for playhead and next/prev buttons)
 1149+ this.pc.pp.setUpHover();
 1150+ //call the parent postEmbedJS
 1151+ this.pe_postEmbedJS();
 1152+ mv_lock_vid_updates=false;
 1153+ },
 1154+ getPlayButton:function(){
 1155+ return this.pe_getPlayButton(this.pc.pp.id);
 1156+ },
 1157+ setStatus:function(value){
 1158+ //status updates handled by playlist obj
 1159+ },
 1160+ setSliderValue:function(value){
 1161+ //setSlider value handled by playlist obj
 1162+ }
 1163+}
 1164+
 1165+/*
 1166+ * m3u parse
 1167+ */
 1168+var m3uPlaylist = {
 1169+ doParse:function(){
 1170+ //for each line not # add as clip
 1171+ var inx =0;
 1172+ var this_pl = this;
 1173+ //js_log('data:'+ this.data.toString());
 1174+ $j.each(this.data.split("\n"), function(i,n){
 1175+ //js_log('on line '+i+' val:'+n+' len:'+n.length);
 1176+ if(n.charAt(0)!='#'){
 1177+ if(n.length>3){
 1178+ //@@todo make sure its a valid url
 1179+ //js_log('add url: '+i + ' '+ n);
 1180+ var cur_clip = new mvClip({type:'srcClip',id:'p_'+this_pl.id+'_c_'+inx,pp:this_pl,src:n,order:inx});
 1181+ //setup the embed object
 1182+ cur_clip.setUpEmbedObj();
 1183+ js_log('m3uPlaylist len:'+ thisClip.embed.media_element.sources.length);
 1184+ this_pl.addCliptoTrack(cur_clip);
 1185+ inx++;
 1186+ }
 1187+ }
 1188+ });
 1189+ return true;
 1190+ }
 1191+}
 1192+
 1193+var itunesPlaylist = {
 1194+ doParse:function(){
 1195+ var properties = { title:'title', linkback:'link',
 1196+ author:'itunes:author',desc:'description',
 1197+ date:'pubDate' };
 1198+ var tmpElm = null;
 1199+ for(i in properties){
 1200+ tmpElm = this.data.getElementsByTagName(properties[i])[0];
 1201+ if(tmpElm){
 1202+ this[i] = tmpElm.childNodes[0].nodeValue;
 1203+ //js_log('set '+i+' to '+this[i]);
 1204+ }
 1205+ }
 1206+ //image src is nested in itunes rss:
 1207+ tmpElm = this.data.getElementsByTagName('image')[0];
 1208+ if(tmpElm){
 1209+ imgElm = tmpElm.getElementsByTagName('url')[0];
 1210+ if(imgElm){
 1211+ this.img = imgElm.childNodes[0].nodeValue;
 1212+ }
 1213+ }
 1214+ //get the clips:
 1215+ var clips = this.data.getElementsByTagName("item");
 1216+ properties.src = 'guid';
 1217+ for (var i=0;i<clips.length;i++){
 1218+ var cur_clip = new mvClip({type:'srcClip',id:'p_'+this.id+'_c_'+i,pp:this,order:i});
 1219+ for(var j in properties){
 1220+ tmpElm = clips[i].getElementsByTagName( properties[j] )[0];
 1221+ if(tmpElm!=null){
 1222+ cur_clip[j] = tmpElm.childNodes[0].nodeValue;
 1223+ //js_log('set clip property: ' + j+' to '+cur_clip[j]);
 1224+ }
 1225+ }
 1226+ //image is nested
 1227+ tmpElm = clips[i].getElementsByTagName('image')[0];
 1228+ if(tmpElm){
 1229+ imgElm = tmpElm.getElementsByTagName('url')[0];
 1230+ if(imgElm){
 1231+ cur_clip.img = imgElm.childNodes[0].nodeValue;
 1232+ }
 1233+ }
 1234+ //set up the embed object now that all the values have been set
 1235+ cur_clip.setUpEmbedObj();
 1236+
 1237+ //add the current clip to the clip list
 1238+ this.addCliptoTrack(cur_clip);
 1239+ }
 1240+ return true;
 1241+ }
 1242+}
 1243+
 1244+/*
 1245+ * parse xsfp:
 1246+ * http://www.xspf.org/xspf-v1.html
 1247+ */
 1248+var xspfPlaylist ={
 1249+ doParse:function(){
 1250+ //js_log('do xsfp parse: '+ this.data.innerHTML);
 1251+ var properties = { title:'title', linkback:'info',
 1252+ author:'creator',desc:'annotation',
 1253+ img:'image', date:'date' };
 1254+ var tmpElm = null;
 1255+ //get the first instance of any of the meta tags (ok that may be the meta on the first clip)
 1256+ //js_log('do loop on properties:' + properties);
 1257+ for(i in properties){
 1258+ js_log('on property: '+i);
 1259+ tmpElm = this.data.getElementsByTagName(properties[i])[0];
 1260+ if(tmpElm){
 1261+ if(tmpElm.childNodes[0]){
 1262+ this[i] = tmpElm.childNodes[0].nodeValue;
 1263+ js_log('set pl property: ' + i+' to '+this[i]);
 1264+ }
 1265+ }
 1266+ }
 1267+ var clips = this.data.getElementsByTagName("track");
 1268+ js_log('found clips:'+clips.length);
 1269+ //add any clip specific properties
 1270+ properties.src = 'location';
 1271+ for (var i=0;i<clips.length;i++){
 1272+ var cur_clip = new mvClip({type:'srcClip',id:'p_'+this.id+'_c_'+i,pp:this,order:i});
 1273+ //js_log('cur clip:'+ cur_clip.id);
 1274+ for(var j in properties){
 1275+ tmpElm = clips[i].getElementsByTagName( properties[j] )[0];
 1276+ if(tmpElm!=null){
 1277+ if( tmpElm.childNodes.length!=0){
 1278+ cur_clip[j] = tmpElm.childNodes[0].nodeValue;
 1279+ js_log('set clip property: ' + j+' to '+cur_clip[j]);
 1280+ }
 1281+ }
 1282+ }
 1283+ //add mvClip ref from info link:
 1284+ if(cur_clip.linkback){
 1285+ //if mv linkback
 1286+ mvInx = 'Stream:';
 1287+ mvclippos = cur_clip.linkback.indexOf(mvInx);
 1288+ if(mvclippos!==false){
 1289+ cur_clip.mvclip=cur_clip.linkback.substr( mvclippos+mvInx.length );
 1290+ }
 1291+ }
 1292+ //set up the embed object now that all the values have been set
 1293+ cur_clip.setUpEmbedObj();
 1294+ //add the current clip to the clip list
 1295+ this.addCliptoTrack(cur_clip);
 1296+ }
 1297+ //js_log('done with parse');
 1298+ return true;
 1299+ }
 1300+}
 1301+/*****************************
 1302+ * SMIL CODE (could be put into another js file / lazy_loaded for improved basic playlist performance / modularity)
 1303+ *****************************/
 1304+/*playlist driver extensions to the playlist object*/
 1305+mvPlayList.prototype.monitor = function(){
 1306+ //js_log('pl:monitor');
 1307+ //js_log('mvPlayList:monitor trueTime: '+ ( (ct.getTime() - this.clockStartTime )/1000));
 1308+ //if paused stop updates
 1309+ if( this.paused ){
 1310+ //clearInterval( this.smil_monitorTimerId );
 1311+ return ;
 1312+ }
 1313+ //js_log("pl check: " + this.currentTime + ' < '+this.getDuration());
 1314+ //check if we should be done:
 1315+ if( this.currentTime > this.getDuration() )
 1316+ this.stop();
 1317+
 1318+ //update the playlist current time:
 1319+ this.currentTime = this.cur_clip.dur_offset + this.cur_clip.embed.currentTime;
 1320+ //update slider:
 1321+ if(!this.userSlide){
 1322+ this.setStatus(seconds2ntp(this.currentTime) + '/' + seconds2ntp(this.getDuration()) );
 1323+ this.setSliderValue(this.currentTime / this.getDuration());
 1324+ }
 1325+
 1326+ //status updates are handled by children clips ... playlist just manages smil actions
 1327+ this.doSmilActions();
 1328+
 1329+ if( ! this.smil_monitorTimerId ){
 1330+ if(document.getElementById(this.id)){
 1331+ this.smil_monitorTimerId = setInterval('$j(\'#'+this.id+'\').get(0).monitor()', 250);
 1332+ }
 1333+ }
 1334+}
 1335+//handles the rendering of overlays load of future clips (if necessary)
 1336+//@@todo could be lazy loaded if necessary
 1337+mvPlayList.prototype.doSmilActions = function( single_frame ){
 1338+ //js_log('f:doSmilActions: ' + this.cur_clip.id + ' tid: ' + this.cur_clip.transOut );
 1339+ var offSetTime = 0; //offset time should let us start a transition later on if we have to.
 1340+ var _clip = this.cur_clip; //setup a local pointer to cur_clip
 1341+
 1342+
 1343+ //do any smil time actions that may change the current clip
 1344+ if( this.userSlide ){
 1345+ //current clip set is set via updateThumbTime function
 1346+ }else{
 1347+ //assume playing and go to next:
 1348+ if( _clip.dur <= _clip.embed.currentTime
 1349+ && _clip.order != _clip.pp.getClipCount()-1 ){
 1350+ //force next clip
 1351+ js_log('order:' + _clip.order + ' != count:' + ( _clip.pp.getClipCount()-1 ) +
 1352+ ' smil dur: ' + _clip.dur + ' <= curTime: ' + _clip.embed.currentTime + ' go to next clip..');
 1353+ //do a _play next:
 1354+ _clip.pp.next();
 1355+ }
 1356+ }
 1357+ //@@todo could maybe generalize transIn with trasOut into one "flow" with a few scattered if statements
 1358+ //update/setup all transitions (will render current transition state)
 1359+ var in_range=false;
 1360+ //pretty similar actions per transition types so group into a loop:
 1361+ var tran_types = {'transIn':true,'transOut':true};
 1362+ for(var tid in tran_types ){
 1363+ eval('var tObj = _clip.'+tid);
 1364+ if(!tObj)
 1365+ continue;
 1366+ //js_log('f:doSmilActions: ' + _clip.id + ' tid:'+tObj.id + ' tclip_id:'+ tObj.pClip.id);
 1367+ //make sue we are in range:
 1368+ if( tid=='transIn' )
 1369+ in_range = (_clip.embed.currentTime <= tObj.dur)?true:false;
 1370+
 1371+ if( tid=='transOut' )
 1372+ in_range = (_clip.embed.currentTime >= (_clip.dur - tObj.dur))?true:false;
 1373+
 1374+ if( in_range ){
 1375+ if( this.userSlide || single_frame ){
 1376+ if( tid=='transIn' )
 1377+ mvTransLib.doUpdate(tObj, (_clip.embed.currentTime / tObj.dur) );
 1378+
 1379+ if( tid=='transOut' )
 1380+ mvTransLib.doUpdate(tObj, (_clip.embed.currentTime-(_clip.dur - tObj.dur)) /tObj.dur);
 1381+
 1382+ }else{
 1383+ if( tObj.animation_state==0 ){
 1384+ js_log('init/run_transition ');
 1385+ tObj.run_transition();
 1386+ }
 1387+ }
 1388+ }else{
 1389+ //close up transition if done & still onDispaly
 1390+ if( tObj.overlay_selector_id ){
 1391+ js_log('close up transition :'+tObj.overlay_selector_id);
 1392+ mvTransLib.doCloseTransition( tObj );
 1393+ }
 1394+ }
 1395+ }
 1396+}
 1397+
 1398+/*
 1399+ * mvTransLib library of transitions
 1400+ * a single object called to initiate transition effects can easily be extended in separate js file
 1401+ * /mvTransLib is a all static object no instances of mvTransLib/
 1402+ * (that way a limited feature set "sequence" need not include a _lot_ of js unless necessary )
 1403+ *
 1404+ * Smil Transition Effects see:
 1405+ * http://www.w3.org/TR/SMIL3/smil-transitions.html#TransitionEffects-TransitionAttribute
 1406+ */
 1407+var mvTransLib = {
 1408+ /*
 1409+ * function doTransition lookups up the transition in the mvTransLib obj
 1410+ * and init the transition if its available
 1411+ * @param tObj transition attribute object
 1412+ * @param offSetTime default value 0 if we need to start rendering from a given time
 1413+ */
 1414+ doInitTransition:function(tObj){
 1415+ js_log('mvTransLib:f:doInitTransition');
 1416+ if(!tObj.type){
 1417+ js_log('transition is missing type attribute');
 1418+ return false;
 1419+ }
 1420+
 1421+ if(!tObj.subtype){
 1422+ js_log('transition is missing subtype attribute');
 1423+ return false;
 1424+ }
 1425+
 1426+ if(!this['type'][tObj.type]){
 1427+ js_log('mvTransLib does not support type: '+tObj.type);
 1428+ return false;
 1429+ }
 1430+
 1431+ if(!this['type'][tObj.type][tObj.subtype]){
 1432+ js_log('mvTransLib does not support subType: '+tObj.subtype);
 1433+ return false;
 1434+ }
 1435+
 1436+ //setup overlay_selector_id
 1437+ if(tObj.subtype=='crossfade'){
 1438+ if(tObj.transAttrType=='transIn')
 1439+ var other_pClip = tObj.pClip.pp.getClip(-1);
 1440+ if(tObj.transAttrType=='transOut')
 1441+ var other_pClip = tObj.pClip.pp.getClip(1);
 1442+
 1443+ if(typeof(other_pClip)=='undefined' || other_pClip.id == tObj.pClip.pp.cur_clip.id)
 1444+ js_log('Error: crossfade without media asset');
 1445+ //if not sliding start playback:
 1446+ if(!tObj.pClip.pp.userSlide)
 1447+ other_pClip.embed.play();
 1448+ tObj.overlay_selector_id = 'clipDesc_'+other_pClip.id;
 1449+ }else{
 1450+ tObj.overlay_selector_id =this.getOverlaySelector(tObj);
 1451+ }
 1452+
 1453+ //all good call function with tObj param
 1454+ js_log('should call: '+tObj.type + ' ' + tObj.subtype );
 1455+ this['type'][tObj.type][tObj.subtype].init(tObj);
 1456+ },
 1457+ doCloseTransition:function(tObj){
 1458+ if(tObj.subtype=='crossfade'){
 1459+ //close up crossfade
 1460+ js_log("close up crossfade");
 1461+ }else{
 1462+ $j('#'+tObj.overlay_selector_id).remove();
 1463+ }
 1464+ //null selector:
 1465+ tObj.overlay_selector_id=null;
 1466+ },
 1467+ getOverlaySelector:function(tObj){
 1468+ var overlay_selector_id= tObj.transAttrType + tObj.pClip.id;
 1469+ js_log('f:getOverlaySelector: '+overlay_selector_id + ' append to: ' +'#videoPlayer_'+tObj.pClip.embed.id );
 1470+ //make sure overlay_selector_id not already here:
 1471+ if( $j('#'+overlay_selector_id).length == 0 ){
 1472+ $j('#videoPlayer_'+tObj.pClip.embed.id).prepend(''+
 1473+ '<div id="'+overlay_selector_id+'" ' +
 1474+ 'style="position:absolute;top:0px;left:0px;' +
 1475+ 'height:'+parseInt(tObj.pClip.pp.height)+'px;'+
 1476+ 'width:'+parseInt(tObj.pClip.pp.width)+'px;' +
 1477+ 'z-index:2">' +
 1478+ '</div>');
 1479+ }
 1480+ return overlay_selector_id;
 1481+ },
 1482+ doUpdate:function(tObj, percent){
 1483+ //init the transition if nessesary:
 1484+ if(!tObj.overlay_selector_id)
 1485+ this.doInitTransition(tObj);
 1486+
 1487+ //@@todo we should ensure visability outside of doUpate loop
 1488+ if(!$j('#'+tObj.overlay_selector_id).is(':visible'))
 1489+ $j('#'+tObj.overlay_selector_id).show();
 1490+
 1491+ //do update:
 1492+ /*js_log('doing update for: '+ tObj.pClip.id +
 1493+ ' type:' + tObj.transAttrType +
 1494+ ' t_type:'+ tObj.type +
 1495+ ' subypte:'+ tObj.subtype +
 1496+ ' percent:' + percent);*/
 1497+
 1498+ this['type'][tObj.type][tObj.subtype].u(tObj,percent);
 1499+ },
 1500+ /*
 1501+ * mvTransLib: functional library mapping:
 1502+ */
 1503+ type:{
 1504+ //types:
 1505+ fade:{
 1506+ fadeFromColor:{
 1507+ 'init':function(tObj){
 1508+ //js_log('f:fadeFromColor: '+tObj.overlay_selector_id +' to color: '+ tObj.fadeColor);
 1509+ if(!tObj.fadeColor)
 1510+ js_log('missing fadeColor');
 1511+ if($j('#'+tObj.overlay_selector_id).length==0){
 1512+ js_log("ERROR can't find: "+ tObj.overlay_selector_id);
 1513+ }
 1514+ //set the initial state
 1515+ $j('#'+tObj.overlay_selector_id).css({
 1516+ 'background-color':tObj.fadeColor,
 1517+ 'opacity':"1"
 1518+ });
 1519+ },
 1520+ 'u':function(tObj, percent){
 1521+ //js_log(':fadeFromColor:update: '+ percent);
 1522+ //fade from color (invert the percent)
 1523+ var percent = 1- percent;
 1524+ $j('#'+tObj.overlay_selector_id).css({
 1525+ "opacity" : percent
 1526+ });
 1527+ }
 1528+ },
 1529+ //corssFade
 1530+ crossfade:{
 1531+ "init":function(tObj){
 1532+ js_log('f:crossfade: '+tObj.overlay_selector_id);
 1533+ if($j('#'+tObj.overlay_selector_id).length==0)
 1534+ js_log("ERROR overlay selector not found: "+tObj.overlay_selector_id);
 1535+
 1536+ //set the initial state show the zero opacity animation
 1537+ $j('#'+tObj.overlay_selector_id).css({'opacity':0}).show();
 1538+ },
 1539+ 'u':function(tObj, percent){
 1540+ $j('#'+tObj.overlay_selector_id).css({
 1541+ "opacity" : percent
 1542+ });
 1543+ }
 1544+ }
 1545+ }
 1546+ }
 1547+}
 1548+//very limited smile feature set more details soon:
 1549+//region="video_region" transIn="fromGreen" begin="2s"
 1550+//http://www.w3.org/TR/2007/WD-SMIL3-20070713/smil-extended-media-object.html#edef-ref
 1551+var smilPlaylist ={
 1552+ transitions:{},
 1553+ doParse:function(){
 1554+ var _this = this;
 1555+ js_log('f:doParse smilPlaylist');
 1556+ //@@todo get/parse meta that we are intersted in:
 1557+ var meta_tags = this.data.getElementsByTagName('meta');
 1558+ var metaNames = new Array('title','interface_url', 'linkback', 'mTitle', 'mTalk');
 1559+ $j.each(meta_tags, function(i,meta_elm){
 1560+ js_log( "on META tag: "+ $j(meta_elm).attr('name') );
 1561+ for(var i in metaNames){
 1562+ var _name = metaNames[i];
 1563+ if( $j(meta_elm).attr('name') && $j(meta_elm).attr('content') ){
 1564+ if( $j(meta_elm).attr('name')== _name ){
 1565+ _this[ _name ] = $j(meta_elm).attr('content');
 1566+ js_log('set :' + _name + ' to ' + _this[ _name ]);
 1567+ }
 1568+ }
 1569+ }
 1570+ });
 1571+ //add transition objects:
 1572+ var transition_tags = this.data.getElementsByTagName('transition');
 1573+ $j.each(transition_tags, function( i, trans_elm ){
 1574+ if( $j(trans_elm).attr("id") ){
 1575+ _this.transitions[ $j(trans_elm).attr("id")]= new transitionObj(trans_elm);
 1576+ }else{
 1577+ js_log('skipping transition: (missing id) ' + trans_elm );
 1578+ }
 1579+ });
 1580+ js_log('loaded transitions:' + _this.transitions.length);
 1581+ //add seq (latter we will have support more than one seq tag) / more than one "track"
 1582+ var seq_tags = this.data.getElementsByTagName('seq');
 1583+ $j.each(seq_tags, function(i,seq_elm){
 1584+ var inx = 0;
 1585+ //get all the clips for the given seq:
 1586+ $j.each(seq_elm.childNodes, function(i, mediaElement){
 1587+ //~complex~ @@todo to handlde a lot like "switch" "region" etc
 1588+ //js_log('process: ' + mediaElemnt.tagName);
 1589+ if(typeof mediaElement.tagName!='undefined'){
 1590+ if( _this.tryAddMedia( mediaElement, inx ) ){
 1591+ inx++;
 1592+ }
 1593+ }
 1594+ });
 1595+ });
 1596+ js_log("done proc seq tags");
 1597+ return true;
 1598+ },
 1599+ tryAddMedia:function(mediaElement, order, track_id){
 1600+ js_log('SMIL:tryAddMedia:' + mediaElement);
 1601+ //set up basic mvSMILClip send it the mediaElemnt & mvClip init:
 1602+ var clipObj = new mvSMILClip(mediaElement,
 1603+ {
 1604+ "id":'p_' + this.id + '_c_' + order,
 1605+ "pp":this, //set the parent playlist object pointer
 1606+ "order": order
 1607+ }
 1608+ );
 1609+ //set optional params track
 1610+ if( typeof track_id != 'undefined')
 1611+ clipObj["track_id"] = track_id;
 1612+
 1613+ //debugger;
 1614+ if (clipObj ){
 1615+ //set up embed:
 1616+ clipObj.setUpEmbedObj();
 1617+ //add clip to track:
 1618+ this.addCliptoTrack( clipObj , order);
 1619+ return true;
 1620+ }
 1621+ //@@todo we could throw error details here once we integrate try catches everywhere :P
 1622+ return false;
 1623+ }
 1624+}
 1625+/* extension to mvClip to support smil properties */
 1626+var mvSMILClip=function(smil_clip_element, mvClipInit){
 1627+ return this.init(smil_clip_element, mvClipInit);
 1628+}
 1629+//all the overwritten and new methods for SMIL extension of mv_embed
 1630+mvSMILClip.prototype = {
 1631+ //http://www.w3.org/TR/2007/WD-SMIL3-20070713/smil-extended-media-object.html#smilMediaNS-BasicMedia
 1632+ //and added resource description elements
 1633+ supported_attributes : new Array(
 1634+ 'id',
 1635+ 'src',
 1636+ 'type',
 1637+ 'region',
 1638+ 'transIn',
 1639+ 'transOut',
 1640+ 'fill',
 1641+ 'dur',
 1642+
 1643+ 'uri',
 1644+ 'poster'
 1645+ ),
 1646+ init:function(smil_clip_element, mvClipInit){
 1647+ _this = this;
 1648+
 1649+ //make new mvCLip with ClipInit vals
 1650+ var myMvClip = new mvClip( mvClipInit );
 1651+
 1652+ //inherit mvClip
 1653+ for(var method in myMvClip){
 1654+ if(typeof this[method] != 'undefined' ){
 1655+ this['parent_'+method]=myMvClip[method];
 1656+ }else{
 1657+ this[method] = myMvClip[method];
 1658+ }
 1659+ }
 1660+
 1661+ //get supported media attr init non-set
 1662+ $j.each(this.supported_attributes, function(i, attr){
 1663+ if( $j(smil_clip_element).attr(attr)){
 1664+ _this[attr]=$j(smil_clip_element).attr(attr);
 1665+ }
 1666+ })
 1667+ this['tagName'] = smil_clip_element.tagName;
 1668+
 1669+ if( smil_clip_element.firstChild ){
 1670+ this['wholeText'] = smil_clip_element.firstChild.nodeValue;
 1671+ js_log("SET wholeText for: "+this['tagName'] + ' '+ this['wholeText']);
 1672+ }
 1673+ //debugger;
 1674+ //mv_embed specific property:
 1675+ if( $j(smil_clip_element).attr('poster') )
 1676+ this['img'] = $j(smil_clip_element).attr('poster');
 1677+
 1678+ //lookup and assign copies of transitions
 1679+ // (since transition needs to hold some per-instance state info)
 1680+ if(this.transIn && this.pp.transitions[ this.transIn ]){
 1681+ this.transIn = this.pp.transitions[ this.transIn ].clone();
 1682+ this.transIn.pClip = _this;
 1683+ this.transIn.transAttrType='transIn';
 1684+ }
 1685+
 1686+ if(this.transOut && this.pp.transitions[ this.transOut ]){
 1687+ this.transOut = this.pp.transitions[ this.transOut ].clone();
 1688+ this.transOut.pClip = _this;
 1689+ this.transOut.transAttrType = 'transOut';
 1690+ }
 1691+ //parse duration / begin times:
 1692+ if(this.dur)
 1693+ this.dur = smilParseTime(this.dur);
 1694+
 1695+ //conform type to video/ogg:
 1696+ if(this['type']=='application/ogg'){
 1697+ this['type']='video/ogg'; //conform to 'video/ogg' type
 1698+ }
 1699+
 1700+ return this;
 1701+ },
 1702+ //returns the values of supported_attributes:
 1703+ getAttributeObj:function(){
 1704+ var elmObj = {};
 1705+ for(var i in this.supported_attributes){
 1706+ var attr = this.supported_attributes[i];
 1707+ if(this[attr])
 1708+ elmObj[ attr ] = this[attr];
 1709+ }
 1710+ return elmObj;
 1711+ },
 1712+ /*
 1713+ * getDuration
 1714+ * @returns duration in int
 1715+ */
 1716+ getDuration:function(){
 1717+ //check for smil dur:
 1718+ if( this.dur )
 1719+ return this.dur;
 1720+ return this.embed.getDuration();
 1721+ }
 1722+}
 1723+/* object to manage embedding html with smil timings
 1724+ * grabs settings from parent clip
 1725+ */
 1726+var transitionObj = function(element) {
 1727+ this.init(element);
 1728+};
 1729+transitionObj.prototype = {
 1730+ supported_attributes : new Array(
 1731+ 'id',
 1732+ 'type',
 1733+ 'subtype',
 1734+ 'fadeColor',
 1735+ 'dur'
 1736+ ),
 1737+ transAttrType:null, //transIn or transOut
 1738+ overlay_selector_id:null,
 1739+ pClip:null,
 1740+ timerId:null,
 1741+ animation_state:0, //can be 0=unset, 1=running, 2=done
 1742+ interValCount:0, //inter-intervalCount for animating between time updates
 1743+ dur:2, //default duration of 2
 1744+ init:function(element){
 1745+ //load supported attributes:
 1746+ var _this = this;
 1747+ $j.each(this.supported_attributes, function(i, attr){
 1748+ if(element.getAttribute(attr))
 1749+ _this[attr]= element.getAttribute(attr);
 1750+ });
 1751+ //@@todo process duration (for now just strip s) per:
 1752+ //http://www.w3.org/TR/SMIL3/smil-timing.html#Timing-ClockValueSyntax
 1753+ if(_this.dur)
 1754+ _this.dur = smilParseTime(_this.dur);
 1755+ },
 1756+ //returns the values of supported_attributes:
 1757+ getAttributeObj:function(){
 1758+ var elmObj = {};
 1759+ for(var i in this.supported_attributes){
 1760+ var attr = this.supported_attributes[i];
 1761+ if(this[attr])
 1762+ elmObj[ attr ] = this[attr];
 1763+ }
 1764+ return elmObj;
 1765+ },
 1766+ /*
 1767+ * the main animation loop called every MV_ANIMATION_CB_RATE or 34ms ~around 30frames per second~
 1768+ */
 1769+ run_transition:function(){
 1770+ //js_log('f:run_transition:' + this.interValCount);
 1771+
 1772+ //update the time from the video if native:
 1773+ if(typeof this.pClip.embed.vid !='undefined'){
 1774+ this.interValCount=0;
 1775+ this.pClip.embed.currentTime = this.pClip.embed.vid.currentTime;
 1776+ }
 1777+
 1778+ //}else{
 1779+ //relay on currentTime update grabs (every 250ms or so) (ie for images)
 1780+ // if(this.prev_curtime!=this.pClip.embed.currentTime){
 1781+ // this.prev_curtime = this.pClip.embed.currentTime;
 1782+ // this.interValCount=0;
 1783+ // }
 1784+ //}
 1785+ //start_time =asigned by doSmilActions
 1786+ //base_cur_time = pClip.embed.currentTime;
 1787+ //dur = asigned by attribute
 1788+ if(this.animation_state==0){
 1789+ mvTransLib.doInitTransition(this);
 1790+ this.animation_state=1;
 1791+ }
 1792+ //set percentage include difrence of currentTime to prev_curTime
 1793+ // ie updated in-between currentTime updates)
 1794+
 1795+ if(this.transAttrType=='transIn')
 1796+ var percentage = ( this.pClip.embed.currentTime +
 1797+ ( (this.interValCount*MV_ANIMATION_CB_RATE)/1000 )
 1798+ ) / this.dur ;
 1799+
 1800+ if(this.transAttrType=='transOut')
 1801+ var percentage = (this.pClip.embed.currentTime +
 1802+ ( (this.interValCount*MV_ANIMATION_CB_RATE)/1000 )
 1803+ - (this.pClip.dur - this.dur)
 1804+ ) /this.dur ;
 1805+
 1806+ /*js_log('percentage = ct:'+this.pClip.embed.currentTime + ' + ic:'+this.interValCount +' * cb:'+MV_ANIMATION_CB_RATE +
 1807+ ' / ' + this.dur + ' = ' + percentage );
 1808+ */
 1809+
 1810+ //js_log('cur percentage of transition: '+percentage);
 1811+ //update state based on current time + cur_time_offset (for now just use pClip.embed.currentTime)
 1812+ mvTransLib.doUpdate(this, percentage);
 1813+
 1814+ if( percentage >= 1 ){
 1815+ js_log("transition done update with percentage "+percentage);
 1816+ this.animation_state=2;
 1817+ clearInterval(this.timerId);
 1818+ mvTransLib.doCloseTransition(this)
 1819+ return true;
 1820+ }
 1821+
 1822+ this.interValCount++;
 1823+ //setInterval in we are still in running state and user is not using the playhead
 1824+ if( this.animation_state==1 ){
 1825+ if(!this.timerId){
 1826+ this.timerId = setInterval('document.getElementById(\'' + this.pClip.pp.id + '\').'+
 1827+ 'run_transition(\'' + this.pClip.pp.cur_clip.order + '\','+
 1828+ '\''+ this.transAttrType + '\')',
 1829+ MV_ANIMATION_CB_RATE);
 1830+ }
 1831+ }else{
 1832+ clearInterval(this.timerId);
 1833+ }
 1834+ return true;
 1835+ },
 1836+ clone:function(){
 1837+ var cObj = new this.constructor();
 1838+ for(var i in this)
 1839+ cObj[i]=this[i];
 1840+ return cObj;
 1841+ }
 1842+}
 1843+/*
 1844+ * takes an input
 1845+ * @time_str input time string
 1846+ * returns time in seconds
 1847+ *
 1848+ * @@todo process duration (for now just srip s) per:
 1849+ * http://www.w3.org/TR/SMIL3/smil-timing.html#Timing-ClockValueSyntax
 1850+ * (probably have to use a Time object to fully support the smil spec
 1851+ */
 1852+function smilParseTime(time_str){
 1853+ return parseInt(time_str.replace('s', ''));
 1854+}
 1855+/***************************
 1856+ * end SMIL specific code
 1857+ ***************************/
 1858+ var trackObj = function( initObj ){
 1859+ return this.init( initObj );
 1860+ }
 1861+ var supported_track_attr =
 1862+trackObj.prototype = {
 1863+ //eventualy should be something like "seq" per SMIL spec
 1864+ //http://www.w3.org/TR/SMIL3/smil-timing.html#edef-seq
 1865+ // but we don't really support anywhere near the full concept of seq containers yet either
 1866+ supported_attributes: new Array(
 1867+ 'title',
 1868+ 'desc:'
 1869+ ),
 1870+ disp_mode:'timeline_thumb',
 1871+ init : function(initObj){
 1872+ if(!initObj)
 1873+ initObj={};
 1874+ //make sure clips is new:
 1875+ this.clips = new Array();
 1876+
 1877+ var _this = this;
 1878+ $j.each(this.supported_attributes, function(i, attr){
 1879+ if(initObj[attr])
 1880+ _this[attr] = initObj[attr];
 1881+ });
 1882+ },
 1883+ //returns the values of supported_attributes:
 1884+ getAttributeObj:function(){
 1885+ var elmObj = {};
 1886+ for(var i in this.supported_attributes){
 1887+ var attr = this.supported_attributes[i];
 1888+ if(this[attr])
 1889+ elmObj[ attr ] = this[attr];
 1890+ }
 1891+ return elmObj;
 1892+ },
 1893+ addClip:function(clipObj, pos){
 1894+ js_log('pl_Track: AddClip at:' + pos);
 1895+ if( typeof pos == 'undefined' )
 1896+ pos = this.clips.length;
 1897+ //get everything after pos
 1898+ this.clips.splice(pos, 0, clipObj);
 1899+ //keep the clip order values accurate:
 1900+ this.reOrderClips();
 1901+ },
 1902+ reOrderClips:function(){
 1903+ for(var k in this.clips){
 1904+ this.clips[k].order=k;
 1905+ }
 1906+ },
 1907+ getClipCount:function(){
 1908+ return this.clips.length;
 1909+ },
 1910+ inheritEmbedObj: function(){
 1911+ $j.each(this.clips, function(i, clip){
 1912+ clip.embed.inheritEmbedObj();
 1913+ });
 1914+ }
 1915+};
 1916+
 1917+/* utility functions
 1918+ * (could be combined with other stuff)
 1919+ */
 1920+
 1921+function getAbsolutePos(objectId) {
 1922+ // Get an object left position from the upper left viewport corner
 1923+ o = document.getElementById(objectId);
 1924+ oLeft = o.offsetLeft; // Get left position from the parent object
 1925+ while(o.offsetParent!=null) { // Parse the parent hierarchy up to the document element
 1926+ oParent = o.offsetParent // Get parent object reference
 1927+ oLeft += oParent.offsetLeft // Add parent left position
 1928+ o = oParent
 1929+ }
 1930+ o = document.getElementById(objectId);
 1931+ oTop = o.offsetTop;
 1932+ while(o.offsetParent!=null) { // Parse the parent hierarchy up to the document element
 1933+ oParent = o.offsetParent // Get parent object reference
 1934+ oTop += oParent.offsetTop // Add parent top position
 1935+ o = oParent
 1936+ }
 1937+ return {x:oLeft,y:oTop};
 1938+}
 1939+String.prototype.htmlEntities = function(){
 1940+ var chars = new Array ('&','à','á','â','ã','ä','å','æ','ç','è','é',
 1941+ 'ê','ë','ì','í','î','ï','ð','ñ','ò','ó','ô',
 1942+ 'õ','ö','ø','ù','ú','û','ü','ý','þ','ÿ','À',
 1943+ 'Á','Â','Ã','Ä','Å','Æ','Ç','È','É','Ê','Ë',
 1944+ 'Ì','Í','Î','Ï','Ð','Ñ','Ò','Ó','Ô','Õ','Ö',
 1945+ 'Ø','Ù','Ú','Û','Ü','Ý','Þ','€','\"','ß','<',
 1946+ '>','¢','£','¤','¥','¦','§','¨','©','ª','«',
 1947+ '¬','­','®','¯','°','±','²','³','´','µ','¶',
 1948+ '·','¸','¹','º','»','¼','½','¾');
 1949+
 1950+ var entities = new Array ('amp','agrave','aacute','acirc','atilde','auml','aring',
 1951+ 'aelig','ccedil','egrave','eacute','ecirc','euml','igrave',
 1952+ 'iacute','icirc','iuml','eth','ntilde','ograve','oacute',
 1953+ 'ocirc','otilde','ouml','oslash','ugrave','uacute','ucirc',
 1954+ 'uuml','yacute','thorn','yuml','Agrave','Aacute','Acirc',
 1955+ 'Atilde','Auml','Aring','AElig','Ccedil','Egrave','Eacute',
 1956+ 'Ecirc','Euml','Igrave','Iacute','Icirc','Iuml','ETH','Ntilde',
 1957+ 'Ograve','Oacute','Ocirc','Otilde','Ouml','Oslash','Ugrave',
 1958+ 'Uacute','Ucirc','Uuml','Yacute','THORN','euro','quot','szlig',
 1959+ 'lt','gt','cent','pound','curren','yen','brvbar','sect','uml',
 1960+ 'copy','ordf','laquo','not','shy','reg','macr','deg','plusmn',
 1961+ 'sup2','sup3','acute','micro','para','middot','cedil','sup1',
 1962+ 'ordm','raquo','frac14','frac12','frac34');
 1963+
 1964+ newString = this;
 1965+ for (var i = 0; i < chars.length; i++)
 1966+ {
 1967+ myRegExp = new RegExp();
 1968+ myRegExp.compile(chars[i],'g')
 1969+ newString = newString.replace (myRegExp, '&' + entities[i] + ';');
 1970+ }
 1971+ return newString;
 1972+}
\ No newline at end of file
Property changes on: trunk/extensions/MetavidWiki/skins/mv_embed/libSequencer/mv_playlist.js
___________________________________________________________________
Added: svn:mergeinfo
Added: svn:eol-style
11973 + native

Status & tagging log