Index: branches/MwEmbedStandAlone/modules/SmilPlayer/mw.SmilLayout.js |
— | — | @@ -113,7 +113,7 @@ |
114 | 114 | } |
115 | 115 | }, |
116 | 116 | |
117 | | - drawElementThumb: function( $target, $node, relativeTime ){ |
| 117 | + drawElementThumb: function( $target, $node, relativeTime, callback){ |
118 | 118 | mw.log('SmilLayout::drawElementThumb: ' + $node.attr('id') + ' relative time:' + relativeTime ); |
119 | 119 | if( $target.length == 0 ){ |
120 | 120 | mw.log("Error drawElementThumb to empty target"); |
— | — | @@ -121,10 +121,12 @@ |
122 | 122 | } |
123 | 123 | // parse the time in case it came in as human input |
124 | 124 | relativeTime = this.smil.parseTime( relativeTime ); |
125 | | - switch ( this.smil.getRefType( $node )){ |
126 | | - case 'video': |
127 | | - this.getVideoCanvasThumb($target, $node, relativeTime ) |
128 | | - break; |
| 125 | + |
| 126 | + if( this.smil.getRefType( $node ) == 'video' ){ |
| 127 | + this.getVideoCanvasThumb($target, $node, relativeTime, callback ) |
| 128 | + return ; |
| 129 | + } |
| 130 | + switch ( this.smil.getRefType( $node ) ){ |
129 | 131 | case 'img': |
130 | 132 | // xxx we could eventually use canvas as well but for now just add it at 100% |
131 | 133 | $target.html( |
— | — | @@ -151,14 +153,20 @@ |
152 | 154 | , |
153 | 155 | $j('<span />') |
154 | 156 | .attr('title', titleStr) |
155 | | - .css({'position': 'absolute', 'left':'16px'}) |
| 157 | + .css({ |
| 158 | + 'position': 'absolute', |
| 159 | + 'left':'16px', |
| 160 | + 'font-size' : 'x-small' |
| 161 | + }) |
156 | 162 | .text( titleStr ) |
157 | 163 | ) |
158 | 164 | break; |
159 | | - } |
| 165 | + } |
| 166 | + if( callback ) |
| 167 | + callback(); |
160 | 168 | }, |
161 | 169 | |
162 | | - getVideoCanvasThumb: function($target, $node, relativeTime ){ |
| 170 | + getVideoCanvasThumb: function($target, $node, relativeTime, callback ){ |
163 | 171 | var _this = this; |
164 | 172 | var naturaSize = {}; |
165 | 173 | var drawElement = $j( '#' + this.smil.getPageDomId( $node ) ).get(0); |
— | — | @@ -172,22 +180,28 @@ |
173 | 181 | naturaSize.width = drawElement.videoWidth; |
174 | 182 | |
175 | 183 | // Draw the thumb via canvas grab |
176 | | - // NOTE I attempted to scale down the image using canvas but failed |
| 184 | + // NOTE canvas scale issue prevents redraw at thumb resolution |
177 | 185 | // xxx should revisit thumb size issue: |
178 | | - $target.html( $j('<canvas />') |
179 | | - .attr({ |
180 | | - height: naturaSize.height, |
181 | | - width : naturaSize.width |
182 | | - }).css( { |
183 | | - height:'100%', |
184 | | - widht:'100%' |
185 | | - }) |
186 | | - .addClass("ui-corner-all") |
187 | | - ) |
188 | | - .find( 'canvas') |
189 | | - .get(0) |
190 | | - .getContext('2d') |
191 | | - .drawImage( drawElement, 0, 0) |
| 186 | + try{ |
| 187 | + $target.html( $j('<canvas />') |
| 188 | + .attr({ |
| 189 | + height: naturaSize.height, |
| 190 | + width : naturaSize.width |
| 191 | + }).css( { |
| 192 | + height:'100%', |
| 193 | + widht:'100%' |
| 194 | + }) |
| 195 | + .addClass("ui-corner-all") |
| 196 | + ) |
| 197 | + .find( 'canvas') |
| 198 | + .get(0) |
| 199 | + .getContext('2d') |
| 200 | + .drawImage( drawElement, 0, 0) |
| 201 | + } catch (e){ |
| 202 | + mw.log("Error:: getVideoCanvasThumb : could not draw canvas image"); |
| 203 | + } |
| 204 | + if( callback ) |
| 205 | + callback(); |
192 | 206 | } |
193 | 207 | |
194 | 208 | // check if relativeTime transform matches current absolute time then render directly: |
— | — | @@ -201,7 +215,7 @@ |
202 | 216 | // span new draw element |
203 | 217 | var $tmpFrameNode = $node.clone(); |
204 | 218 | $tmpFrameNode.attr('id', $node.attr('id') + '_tmpFrameNode' ); |
205 | | - this.smil.getBuffer().bufferedSeek( $tmpFrameNode, relativeTime, function(){ |
| 219 | + this.smil.getBuffer().bufferedSeekRelativeTime( $tmpFrameNode, relativeTime, function(){ |
206 | 220 | // update the drawElement |
207 | 221 | drawElement = $j( '#' + _this.smil.getPageDomId( $tmpFrameNode ) ).get(0); |
208 | 222 | drawFrame( drawElement ); |
Index: branches/MwEmbedStandAlone/modules/SmilPlayer/mw.SmilBuffer.js |
— | — | @@ -295,8 +295,8 @@ |
296 | 296 | /** |
297 | 297 | * Clip ready for grabbing a frame such as a canvas thumb |
298 | 298 | */ |
299 | | - bufferedSeek: function( smilElement, relativeTime, callback ){ |
300 | | - mw.log("SmilBuffer::bufferedSeek:" + this.smil.getPageDomId( smilElement ) + ' time:' + relativeTime ); |
| 299 | + bufferedSeekRelativeTime: function( smilElement, relativeTime, callback ){ |
| 300 | + mw.log("SmilBuffer::bufferedSeekRelativeTime:" + this.smil.getPageDomId( smilElement ) + ' time:' + relativeTime ); |
301 | 301 | |
302 | 302 | var absoluteTime = relativeTime; |
303 | 303 | if( $j( smilElement ).attr('clipBegin') ){ |
Index: branches/MwEmbedStandAlone/modules/TimedText/remotes/RemoteMwTimedText.js |
— | — | @@ -158,7 +158,7 @@ |
159 | 159 | _this.embedByTitle( pt[1], callback); |
160 | 160 | return ; |
161 | 161 | } else { |
162 | | - mw.log( 'Error: addByTitle could not process redirect' ); |
| 162 | + mw.log( 'Error: getTitleResource could not process redirect' ); |
163 | 163 | callback( false ); |
164 | 164 | return false; |
165 | 165 | } |
Index: branches/MwEmbedStandAlone/modules/AddMedia/searchLibs/mediaWikiSearch.js |
— | — | @@ -28,33 +28,48 @@ |
29 | 29 | * @param {String} title Title of the resource to be added |
30 | 30 | * @param {Function} callback Function called once title resource acquired |
31 | 31 | */ |
32 | | - addByTitle:function( title , callback, redirect_count ) { |
| 32 | + getByTitle:function( title , callback ) { |
33 | 33 | |
34 | | - mw.log( "AddByTitle::" + title ); |
| 34 | + mw.log( "MediaWikiSearch:: getByTitle:" + title ); |
35 | 35 | |
36 | | - var _this = this; |
37 | | - if ( !redirect_count ) |
38 | | - redirect_count = 0; |
39 | | - if ( redirect_count > 5 ) { |
40 | | - mw.log( 'Error: addByTitle too many redirects' ); |
41 | | - callback( false ); |
42 | | - return false; |
43 | | - } |
| 36 | + var _this = this; |
| 37 | + |
44 | 38 | var request = { |
45 | | - 'titles':'File:' + title, |
46 | | - 'prop':'imageinfo|revisions|categories', |
47 | | - 'iiprop':'url|mime|size', |
48 | | - 'iiurlwidth': parseInt( this.rsd.thumb_width ), |
49 | | - 'rvprop':'content', |
| 39 | + 'titles' : 'File:' + title.replace(/File:|Image:/ig, ''), |
| 40 | + 'prop' : 'imageinfo|revisions|categories', |
| 41 | + 'iiprop' : 'url|mime|size|metadata', |
| 42 | + 'iiurlwidth' : parseInt( this.rsd.thumb_width ), |
| 43 | + 'rvprop' : 'content', |
50 | 44 | 'redirects' : true |
51 | 45 | } |
52 | | - mw.getJSON(this.provider.apiUrl, request, function( data ) { |
| 46 | + mw.getJSON( this.provider.apiUrl, request, function( data ) { |
53 | 47 | // call addSingleResult |
54 | 48 | callback( _this.addSingleResult( data ) ); |
55 | 49 | }); |
56 | 50 | }, |
57 | | - |
| 51 | + |
| 52 | + getResourceFromUrl: function( url, callback ){ |
| 53 | + this.getByTitle( this.getTitleKeyFromMwUrl( url ), callback ); |
| 54 | + }, |
58 | 55 | /** |
| 56 | + * Does best effort to get the title key from a mediawiki url |
| 57 | + */ |
| 58 | + getTitleKeyFromMwUrl: function( url ){ |
| 59 | + // try for title key param |
| 60 | + var titleKey = mw.parseUri( url ).queryKey['title']; |
| 61 | + if( titleKey ){ |
| 62 | + return titleKey; |
| 63 | + } |
| 64 | + // else try for title url map |
| 65 | + titleKey = url.replace( this.provider.detailsUrl.replace( '$1', ''), '' ); |
| 66 | + if( titleKey != url ){ |
| 67 | + return titleKey; |
| 68 | + } |
| 69 | + mw.log("Error: mediaWikiSearch:: getResourceFromUrl could not get title form url: " + url ); |
| 70 | + return false; |
| 71 | + }, |
| 72 | + |
| 73 | + /** |
59 | 74 | * Get recent upload by user and add them as results |
60 | 75 | * |
61 | 76 | * @param {String} user Name of the user |
— | — | @@ -88,7 +103,7 @@ |
89 | 104 | var resourceQuery = { |
90 | 105 | 'titles' : titleStr, |
91 | 106 | 'prop' : 'imageinfo|revisions|categories', |
92 | | - 'iiprop' : 'url|mime|size', |
| 107 | + 'iiprop' : 'url|mime|size|metadata', |
93 | 108 | 'iiurlwidth': parseInt( _this.rsd.thumb_width ), |
94 | 109 | 'rvprop':'content' |
95 | 110 | }; |
— | — | @@ -205,10 +220,16 @@ |
206 | 221 | 'desc' : page.revisions[0]['*'], |
207 | 222 | // add pointer to parent search obj: |
208 | 223 | 'pSobj' :_this, |
| 224 | + |
209 | 225 | 'meta': { |
210 | 226 | 'categories':page.categories |
211 | 227 | } |
212 | | - }; |
| 228 | + }; |
| 229 | + for( var i in page.imageinfo[0].metadata ){ |
| 230 | + if( page.imageinfo[0].metadata[i].name == 'length' ){ |
| 231 | + resource.duration = page.imageinfo[0].metadata[i].value; |
| 232 | + } |
| 233 | + } |
213 | 234 | |
214 | 235 | /* |
215 | 236 | //to use once we get the wiki-text parser in shape |
— | — | @@ -251,8 +272,10 @@ |
252 | 273 | this.resultsObj[page_id] = resource; |
253 | 274 | |
254 | 275 | // If returnFirst flag: |
255 | | - if ( returnFirst ) |
| 276 | + // xxx this is kind of hacky .. we should have abstract getter / adder to result list |
| 277 | + if ( returnFirst ){ |
256 | 278 | return this.resultsObj[page_id]; |
| 279 | + } |
257 | 280 | |
258 | 281 | |
259 | 282 | this.num_results++; |
Index: branches/MwEmbedStandAlone/modules/AddMedia/searchLibs/baseRemoteSearch.js |
— | — | @@ -67,6 +67,10 @@ |
68 | 68 | return this; |
69 | 69 | }, |
70 | 70 | |
| 71 | + getResourceFromUrl: function( url, callback ){ |
| 72 | + mw.log("Error getResourceFromUrl must be implemented by remoteSearch provider"); |
| 73 | + }, |
| 74 | + |
71 | 75 | /** |
72 | 76 | * Base search results |
73 | 77 | * Does some common initialisation for search results |
Index: branches/MwEmbedStandAlone/modules/AddMedia/searchLibs/flickrSearch.js |
— | — | @@ -15,8 +15,7 @@ |
16 | 16 | var flickrSearch = function ( options ) { |
17 | 17 | this.init( options ); |
18 | 18 | } |
19 | | -flickrSearch.prototype = { |
20 | | - detailsUrl : 'http://www.flickr.com/photos/', |
| 19 | +flickrSearch.prototype = { |
21 | 20 | // @@todo probably would be good to read the api-key from configuration |
22 | 21 | apikey : '2867787a545cc66c0bce6f2e57aca1d1', |
23 | 22 | // What license we are interested in |
Index: branches/MwEmbedStandAlone/modules/AddMedia/mw.UploadForm.js |
— | — | @@ -401,7 +401,7 @@ |
402 | 402 | remoteSearchDriver.addResourceEditLoader(); |
403 | 403 | |
404 | 404 | //Add the uploaded result |
405 | | - searchProvider.sObj.addByTitle( wTitle, function( resource ) { |
| 405 | + searchProvider.sObj.getByTitle( wTitle, function( resource ) { |
406 | 406 | // Update the recent uploads ( background task ) |
407 | 407 | remoteSearchDriver.showUserRecentUploads( uploadTargetId ); |
408 | 408 | // Pull up resource editor: |
Index: branches/MwEmbedStandAlone/modules/AddMedia/mw.RemoteSearchDriver.js |
— | — | @@ -297,7 +297,8 @@ |
298 | 298 | 'homepage': 'http://kaltura.com', |
299 | 299 | 'apiUrl': 'http://kaldev.kaltura.com/michael/aggregator.php', |
300 | 300 | |
301 | | - 'detailsUrl' : wgServer + wgArticlePath, |
| 301 | + 'detailsUrl' : 'http://videos.kaltura.com/$1', |
| 302 | + |
302 | 303 | 'lib': 'kaltura', |
303 | 304 | 'resource_prefix' : '', |
304 | 305 | 'tab_image':false |
— | — | @@ -310,6 +311,8 @@ |
311 | 312 | 'enabled': 1, |
312 | 313 | 'homepage': 'http://commons.wikimedia.org/wiki/Main_Page', |
313 | 314 | 'apiUrl': 'http://commons.wikimedia.org/w/api.php', |
| 315 | + 'detailsUrl' : 'http://commons.wikimedia.org/wiki/$1', |
| 316 | + |
314 | 317 | 'lib': 'mediaWiki', |
315 | 318 | 'tab_img': true, |
316 | 319 | |
— | — | @@ -335,6 +338,8 @@ |
336 | 339 | 'homepage': 'http://www.archive.org/about/about.php', |
337 | 340 | |
338 | 341 | 'apiUrl': 'http://www.archive.org/advancedsearch.php', |
| 342 | + 'detailsUrl' : 'http://www.archive.org/details/$1', |
| 343 | + |
339 | 344 | 'lib': 'archiveOrg', |
340 | 345 | 'local': false, |
341 | 346 | 'resource_prefix': 'AO_', |
— | — | @@ -346,9 +351,10 @@ |
347 | 352 | */ |
348 | 353 | 'flickr': { |
349 | 354 | 'enabled': 1, |
350 | | - 'homepage': 'http://www.flickr.com/about/', |
351 | | - |
| 355 | + 'homepage': 'http://www.flickr.com/about/', |
352 | 356 | 'apiUrl': 'http://www.flickr.com/services/rest/', |
| 357 | + 'detailsUrl' : 'http://www.flickr.com/photos/', |
| 358 | + |
353 | 359 | 'lib': 'flickr', |
354 | 360 | 'local': false, |
355 | 361 | // Just prefix with Flickr_ for now. |
— | — | @@ -363,6 +369,8 @@ |
364 | 370 | 'enabled': 1, |
365 | 371 | 'homepage': 'http://metavid.org/wiki/Metavid_Overview', |
366 | 372 | 'apiUrl': 'http://metavid.org/w/index.php?title=Special:MvExportSearch', |
| 373 | + 'detailsUrl' : 'http://metavid.org/wiki/Stream:$1', |
| 374 | + |
367 | 375 | 'lib': 'metavid', |
368 | 376 | 'local': false, |
369 | 377 | |
— | — | @@ -1631,7 +1639,21 @@ |
1632 | 1640 | callback( provider ); |
1633 | 1641 | } ); |
1634 | 1642 | }, |
| 1643 | + /** |
| 1644 | + * get a resource from a url loads the provider if not already initialized |
| 1645 | + */ |
| 1646 | + getResourceFromUrl: function ( provider, url, callback){ |
| 1647 | + if (!provider.sObj) { |
| 1648 | + this.loadSearchLib( provider, function( provider ){ |
| 1649 | + provider.sObj.getResourceFromUrl( url, callback); |
| 1650 | + }); |
| 1651 | + } |
| 1652 | + else { |
| 1653 | + provider.sObj.getResourceFromUrl( url, callback); |
| 1654 | + } |
| 1655 | + }, |
1635 | 1656 | |
| 1657 | + |
1636 | 1658 | /** |
1637 | 1659 | * Get a resource object from a resource id |
1638 | 1660 | * |
Index: branches/MwEmbedStandAlone/modules/Sequencer/mw.Sequencer.js |
— | — | @@ -124,12 +124,16 @@ |
125 | 125 | mw.log( "Sequencer::updateSmilXML" ); |
126 | 126 | var _this = this; |
127 | 127 | // Update the embedPlayer smil: |
128 | | - this.getSmil().updateFromString( smilXML ); |
| 128 | + this.getSmil().updateFromString( smilXML ); |
| 129 | + |
129 | 130 | // Get a duration ( forceRefresh to clear the cache ) |
130 | 131 | this.getEmbedPlayer().getDuration( true ); |
131 | 132 | |
132 | 133 | // Redraw the timeline |
133 | | - this.getTimeline().drawTimeline(); |
| 134 | + this.getTimeline().drawTimeline(); |
| 135 | + |
| 136 | + // if a tool is displayed update the tool: |
| 137 | + this.getTools().updateToolDisplay(); |
134 | 138 | }, |
135 | 139 | |
136 | 140 | /** |
Index: branches/MwEmbedStandAlone/modules/Sequencer/css/mw.style.Sequencer.css |
— | — | @@ -93,3 +93,12 @@ |
94 | 94 | padding-left: 5px; |
95 | 95 | padding-right: 5px; |
96 | 96 | } |
| 97 | + |
| 98 | +/* Vertical Tabs |
| 99 | +----------------------------------*/ |
| 100 | +.ui-tabs-vertical { width: 55em; } |
| 101 | +.ui-tabs-vertical .ui-tabs-nav { padding: .2em .1em .2em .2em; float: left; width: 12em; } |
| 102 | +.ui-tabs-vertical .ui-tabs-nav li { clear: left; width: 100%; border-bottom-width: 1px !important; border-right-width: 0 !important; margin: 0 -1px .2em 0; } |
| 103 | +.ui-tabs-vertical .ui-tabs-nav li a { display:block; } |
| 104 | +.ui-tabs-vertical .ui-tabs-nav li.ui-tabs-selected { padding-bottom: 0; padding-right: .1em; border-right-width: 1px; border-right-width: 1px; } |
| 105 | +.ui-tabs-vertical .ui-tabs-panel { padding: 1em; float: right; width: 40em;} |
Index: branches/MwEmbedStandAlone/modules/Sequencer/Sequencer.i18n.php |
— | — | @@ -27,8 +27,12 @@ |
28 | 28 | 'mwe-sequencer-audio-track' => 'Audio track', |
29 | 29 | 'mwe-sequencer-sequencer_credit_line' => 'Developed by [$1 Kaltura, Inc] in partnership with the [$1 Wikimedia Foundation]', |
30 | 30 | 'mwe-sequencer-no-sequence-create' => 'Sequence does not exists, You can [$1 start a sequence]', |
31 | | - 'mwe-sequencer-cliptool-trim' => 'Trim clip', |
32 | | - 'mwe-sequencer-cliptool-duration' => 'Set duration', |
| 31 | + |
| 32 | + 'mwe-sequencer-tools-trim' => 'Trim', |
| 33 | + 'mwe-sequencer-tools-trim-desc' => 'Set clip in and out points', |
| 34 | + 'mwe-sequencer-tools-duration' => 'Duration', |
| 35 | + 'mwe-sequencer-tools-duration-desc' => 'Set clip duration', |
| 36 | + |
33 | 37 | 'mwe-sequencer-preview' => 'Preview', |
34 | 38 | 'mwe-sequencer-apply-changes' => 'Apply changes', |
35 | 39 | 'mwe-sequencer-start-time' => 'Start time', |
Index: branches/MwEmbedStandAlone/modules/Sequencer/mw.SequencerAddMedia.js |
— | — | @@ -122,29 +122,13 @@ |
123 | 123 | // Check if input value can be handled by url |
124 | 124 | var inputValue = _this.sequencer.getMenuTarget().find('input.searchMedia').val(); |
125 | 125 | if( _this.sequencer.getAddByUrl().isUrl( inputValue) ){ |
126 | | - _this.sequencer.addByUrlDialog().addByUrl( remoteSearchDriver, inputValue ); |
| 126 | + _this.sequencer.getAddByUrl().addByUrlDialog( remoteSearchDriver, inputValue ); |
127 | 127 | } else { |
128 | 128 | // Else just use the remoteSearchDriver search interface |
129 | 129 | remoteSearchDriver.createUI(); |
130 | 130 | } |
131 | 131 | }); |
132 | | - }, |
133 | | - /** |
134 | | - * Handles url asset importing |
135 | | - * xxx should probably re factor into separate class |
136 | | - * |
137 | | - * Checks for commons ulr profile, future profiles could include flickr, youtube etc. |
138 | | - * tries to ascertain content type by url and directly load the media |
139 | | - * @param {String} url to be imported to the sequence |
140 | | - */ |
141 | | - proccessUrlRequest: function( url ){ |
142 | | - // Check if its a local domain ( we can directly request the "head" of the file to get its type ) |
143 | | - |
144 | | - // Check url type |
145 | | - var parsedUrl = mw.parseUri( url ); |
146 | | - if( host == 'commons.wikimedia.org' ){ |
147 | | - } |
148 | | - }, |
| 132 | + }, |
149 | 133 | |
150 | 134 | /** |
151 | 135 | * Get the resource object from a provided asset |
— | — | @@ -204,7 +188,10 @@ |
205 | 189 | if( resource.mime.indexOf( 'image/' ) != -1 ){ |
206 | 190 | tagType = 'img'; |
207 | 191 | } |
208 | | - if( resource.mime.indexOf( 'video/') != -1 ){ |
| 192 | + if( resource.mime.indexOf( 'video/') != -1 |
| 193 | + || |
| 194 | + resource.mime.indexOf( 'application/ogg' ) != -1 ) |
| 195 | + { |
209 | 196 | tagType = 'video'; |
210 | 197 | } |
211 | 198 | if( resource.mime.indexOf( 'audio/') != -1 ){ |
— | — | @@ -212,11 +199,19 @@ |
213 | 200 | } |
214 | 201 | var $smilRef = $j( '<' + tagType + ' />') |
215 | 202 | |
216 | | - // Set the default duration |
| 203 | + // Set the default duration for images |
217 | 204 | if( tagType == 'img' ){ |
218 | 205 | $smilRef.attr( 'dur', mw.getConfig( 'Sequencer.AddMediaImageDuration' ) ); |
219 | 206 | } |
220 | 207 | |
| 208 | + // Set the default duration to the media duration: |
| 209 | + if( resource.duration ){ |
| 210 | + // Set the media full duration |
| 211 | + $smilRef.attr( 'durationHint', resource.duration ); |
| 212 | + // By default the imported resource is its entire duration |
| 213 | + $smilRef.attr( 'dur', resource.duration ); |
| 214 | + } |
| 215 | + |
221 | 216 | // Set all available params |
222 | 217 | var resourceAttributeMap = { |
223 | 218 | 'type' : 'mime', |
Index: branches/MwEmbedStandAlone/modules/Sequencer/mw.SequencerTools.js |
— | — | @@ -14,27 +14,37 @@ |
15 | 15 | init: function( sequencer ){ |
16 | 16 | this.sequencer = sequencer; |
17 | 17 | }, |
| 18 | + // The current selected tool |
| 19 | + currentToolId: null, |
| 20 | + |
| 21 | + // JSON tools config |
18 | 22 | tools:{ |
19 | 23 | 'trim':{ |
20 | | - 'title': gM('mwe-sequencer-cliptool-trim'), |
21 | 24 | 'editWidgets' : [ 'trimTimeline' ], |
22 | 25 | 'editableAttributes' : ['clipBegin','dur' ], |
23 | | - 'editActions' : ['preview', 'cancel'] |
| 26 | + 'contentTypes': ['video', 'audio'] |
24 | 27 | }, |
25 | | - 'duration':{ |
26 | | - 'title': gM('mwe-sequencer-cliptool-duration'), |
| 28 | + 'duration':{ |
27 | 29 | 'editableAttributes' : [ 'dur' ], |
28 | | - 'editActions' : ['preview', 'cancel'] |
| 30 | + 'contentTypes': ['image'] |
| 31 | + }, |
| 32 | + 'panzoom' : { |
| 33 | + 'editableAttributes' : [ 'panZoom' ], |
| 34 | + 'contentTypes': ['video', 'image'] |
29 | 35 | } |
30 | 36 | }, |
31 | 37 | editableAttributes:{ |
32 | 38 | 'clipBegin':{ |
33 | 39 | 'type': 'time', |
34 | | - 'title' : gM('mwe-sequencer-start-time' ), |
| 40 | + 'title' : gM('mwe-sequencer-start-time' ) |
35 | 41 | }, |
36 | 42 | 'dur' :{ |
37 | 43 | 'type': 'time', |
38 | | - 'title' : gM('mwe-sequencer-clip-duration' ), |
| 44 | + 'title' : gM('mwe-sequencer-clip-duration' ) |
| 45 | + }, |
| 46 | + 'panZoom' :{ |
| 47 | + 'type' : 'panzoom', |
| 48 | + 'title' : gM('mwe-sequencer-clip-layout' ) |
39 | 49 | } |
40 | 50 | }, |
41 | 51 | editableTypes: { |
— | — | @@ -65,7 +75,7 @@ |
66 | 76 | 'preview' : { |
67 | 77 | 'icon' : 'play', |
68 | 78 | 'title' : gM('mwe-sequencer-preview'), |
69 | | - 'action': function( _this, smilClip, toolId ){ |
| 79 | + 'action': function( _this, smilClip ){ |
70 | 80 | _this.sequencer.getPlayer().previewClip( smilClip ); |
71 | 81 | // xxx todo update preview button to "pause" / "play" |
72 | 82 | } |
— | — | @@ -73,15 +83,22 @@ |
74 | 84 | 'cancel':{ |
75 | 85 | 'icon': 'close', |
76 | 86 | 'title' : gM('mwe-cancel'), |
77 | | - 'action' : function( _this, smilClip, toolId ){ |
78 | | - var tool = _this.tools[toolId]; |
79 | | - for( var i=0; i < tool.editableAttributes.length ; i++ ){ |
80 | | - var attributeName = tool.editableAttributes[i]; |
81 | | - var $editToolInput = $j('#' + _this.getEditToolId( toolId, attributeName ) ); |
82 | | - // Restore all original attribute values |
83 | | - smilClip.attr( attributeName, $editToolInput.data('initialValue') ); |
84 | | - } |
85 | | - |
| 87 | + 'action' : function( _this, smilClip ){ |
| 88 | + $j.each( |
| 89 | + _this.getToolSet( |
| 90 | + _this.sequencer.getSmil().getRefType( smilClip ) |
| 91 | + ), |
| 92 | + function( inx, toolId ){ |
| 93 | + var tool = _this.tools[toolId]; |
| 94 | + for( var i=0; i < tool.editableAttributes.length ; i++ ){ |
| 95 | + var attributeName = tool.editableAttributes[i]; |
| 96 | + var $editToolInput = $j('#' + _this.getEditToolInputId( toolId, attributeName ) ); |
| 97 | + // Restore all original attribute values |
| 98 | + smilClip.attr( attributeName, $editToolInput.data('initialValue') ); |
| 99 | + } |
| 100 | + } |
| 101 | + ); |
| 102 | + |
86 | 103 | // Update the clip duration : |
87 | 104 | _this.sequencer.getEmbedPlayer().getDuration( true ); |
88 | 105 | |
— | — | @@ -91,17 +108,30 @@ |
92 | 109 | ); |
93 | 110 | |
94 | 111 | // Close / empty the toolWindow |
95 | | - _this.sequencer.getEditToolTarget().html( |
96 | | - _this.getDefaultText() |
97 | | - ) |
| 112 | + _this.setDefaultText(); |
98 | 113 | } |
99 | 114 | } |
100 | 115 | }, |
101 | 116 | editWidgets: { |
102 | 117 | 'trimTimeline':{ |
103 | | - 'update': function( _this, target, smilClip ){ |
| 118 | + 'onChange': function( _this, target, smilClip ){ |
104 | 119 | var smil = _this.sequencer.getSmil(); |
105 | 120 | // Update the preview thumbs |
| 121 | + |
| 122 | + // (local function so it can be updated after the start time is done with its draw ) |
| 123 | + var updateDurationThumb = function(){ |
| 124 | + // Check the duration: |
| 125 | + var clipDur = $j('#editTool_trim_dur').val(); |
| 126 | + if( clipDur ){ |
| 127 | + // Render a thumbnail for the updated duration |
| 128 | + smil.getLayout().drawElementThumb( |
| 129 | + $j( target ).find('.trimEndThumb'), |
| 130 | + smilClip, |
| 131 | + clipDur |
| 132 | + ); |
| 133 | + } |
| 134 | + } |
| 135 | + |
106 | 136 | var clipBeginTime = $j('#editTool_trim_clipBegin').val(); |
107 | 137 | if( !clipBeginTime ){ |
108 | 138 | $j(target).find('.trimStartThumb').hide(); |
— | — | @@ -111,22 +141,10 @@ |
112 | 142 | smil.getLayout().drawElementThumb( |
113 | 143 | $j( target ).find('.trimStartThumb'), |
114 | 144 | smilClip, |
115 | | - 0 |
| 145 | + 0, |
| 146 | + updateDurationThumb() |
116 | 147 | ) |
117 | 148 | } |
118 | | - // Check the duration: |
119 | | - var clipDur = $j('#editTool_trim_dur').val(); |
120 | | - if( clipDur ){ |
121 | | - mw.log("Should update trimStartThumb::" + $j(smilClip).attr('clipBegin') ); |
122 | | - // Render a thumbnail for the updated duration |
123 | | - smil.getLayout().drawElementThumb( |
124 | | - $j( target ).find('.trimEndThumb'), |
125 | | - smilClip, |
126 | | - clipDur |
127 | | - ); |
128 | | - } |
129 | | - |
130 | | - mw.log( "editWidgets::trimTimeline:update:: " + clipBeginTime + ' dur: ' + clipDur); |
131 | 149 | }, |
132 | 150 | // Return the trimTimeline edit widget |
133 | 151 | 'draw': function( _this, target, smilClip ){ |
— | — | @@ -144,10 +162,10 @@ |
145 | 163 | |
146 | 164 | // Add a trim binding: |
147 | 165 | $j('#editTool_trim_clipBegin,#editTool_trim_dur').change(function(){ |
148 | | - _this.editWidgets.trimTimeline.update( _this, target, smilClip); |
| 166 | + _this.editWidgets.trimTimeline.onChange( _this, target, smilClip); |
149 | 167 | }) |
150 | 168 | // Update the thumbnails: |
151 | | - _this.editWidgets.trimTimeline.update( _this, target, smilClip); |
| 169 | + _this.editWidgets.trimTimeline.onChange( _this, target, smilClip); |
152 | 170 | |
153 | 171 | // Get the clip full duration to build out the timeline selector |
154 | 172 | smil.getBody().getClipAssetDuration( smilClip, function( fullClipDuration ) { |
— | — | @@ -162,13 +180,14 @@ |
163 | 181 | var sliderValues = [ |
164 | 182 | startSlider, |
165 | 183 | startSlider + timeToSlider( smil.parseTime( $j('#editTool_trim_dur').val() ) ) |
166 | | - ]; |
| 184 | + ]; |
167 | 185 | // Return a trim tool binded to smilClip id update value events. |
168 | 186 | $j(target).append( |
169 | 187 | $j('<div />') |
170 | 188 | .attr( 'id', _this.sequencer.id + '_trimTimeline' ) |
171 | 189 | .css({ |
172 | | - 'width': '100%', |
| 190 | + 'left' : '5px', |
| 191 | + 'right' : '15px', |
173 | 192 | 'margin': '5px' |
174 | 193 | }) |
175 | 194 | .slider({ |
— | — | @@ -186,23 +205,16 @@ |
187 | 206 | }, |
188 | 207 | change: function( event, ui ) { |
189 | 208 | var attributeValue = 0, sliderIndex = 0; |
190 | | - if( sliderValues[0] != ui.values[0] ){ |
191 | | - var attributeChanged = 'clipBegin'; |
192 | | - sliderIndex = 0; |
193 | | - attributeValue = sliderToTime( ui.values[ 0 ] ) |
194 | | - } else { |
195 | | - var attributeChanged = 'dur'; |
196 | | - sliderIndex = 1; |
197 | | - attributeValue = sliderToTime( ui.values[ 1 ]- ui.values[0] ) |
198 | | - } |
199 | | - sliderValues[ sliderIndex ] = ui.values[ sliderIndex ]; |
200 | 209 | |
201 | | - // update start and end time: |
202 | | - _this.editableTypes['time'].update( _this, smilClip, attributeChanged, attributeValue) |
203 | | - |
204 | | - // update the widget |
205 | | - _this.editWidgets.trimTimeline.update( _this, target, smilClip); |
| 210 | + // Update clipBegin |
| 211 | + _this.editableTypes['time'].update( _this, smilClip, 'clipBegin', sliderToTime( ui.values[ 0 ] ) ); |
206 | 212 | |
| 213 | + // Update dur |
| 214 | + _this.editableTypes['time'].update( _this, smilClip, 'dur', sliderToTime( ui.values[ 1 ]- ui.values[0] ) ); |
| 215 | + |
| 216 | + // update the widget display |
| 217 | + _this.editWidgets.trimTimeline.onChange( _this, target, smilClip); |
| 218 | + |
207 | 219 | // Register the edit state for undo / redo |
208 | 220 | _this.sequencer.getActionsEdit().registerEdit(); |
209 | 221 | |
— | — | @@ -220,85 +232,152 @@ |
221 | 233 | getDefaultText: function(){ |
222 | 234 | return gM('mwe-sequencer-no_selected_resource'); |
223 | 235 | }, |
224 | | - getEditToolId: function( toolId, attributeName){ |
| 236 | + setDefaultText: function(){ |
| 237 | + this.sequencer.getEditToolTarget().html( |
| 238 | + this.getDefaultText() |
| 239 | + ) |
| 240 | + }, |
| 241 | + getEditToolInputId: function( toolId, attributeName){ |
225 | 242 | return 'editTool_' + toolId + '_' + attributeName; |
226 | | - }, |
227 | | - |
228 | | - drawClipEditTools: function( $target, smilClip){ |
229 | | - |
| 243 | + }, |
| 244 | + /** |
| 245 | + * update the current displayed tool ( when an undo, redo or history jump changes smil state ) |
| 246 | + */ |
| 247 | + updateToolDisplay: function(){ |
| 248 | + var _this = this; |
| 249 | + // Update all tool input values:: trigger change event if changed |
| 250 | + var smilClip = this.getCurrentSmilClip(); |
| 251 | + |
| 252 | + $j.each( |
| 253 | + _this.getToolSet( |
| 254 | + _this.sequencer.getSmil().getRefType( smilClip ) |
| 255 | + ), |
| 256 | + function( inx, toolId ){ |
| 257 | + var tool = _this.tools[toolId]; |
| 258 | + for( var i=0; i < tool.editableAttributes.length ; i++ ){ |
| 259 | + var attributeName = tool.editableAttributes[i]; |
| 260 | + var $editToolInput = $j('#' + _this.getEditToolInputId( toolId, attributeName ) ); |
| 261 | + // Sync with smilClip value |
| 262 | + if( smilClip.attr( attributeName ) != $editToolInput.val() ){ |
| 263 | + $editToolInput.val( smilClip.attr( attributeName ) ); |
| 264 | + // trigger change event: |
| 265 | + $editToolInput.change(); |
| 266 | + } |
| 267 | + } |
| 268 | + } |
| 269 | + ); |
| 270 | + }, |
| 271 | + getToolSet: function( refType ){ |
| 272 | + var toolSet = []; |
| 273 | + for( var toolId in this.tools){ |
| 274 | + if( this.tools[toolId].contentTypes){ |
| 275 | + if( $j.inArray( refType, this.tools[toolId].contentTypes) != -1 ){ |
| 276 | + toolSet.push( toolId ); |
| 277 | + } |
| 278 | + } |
| 279 | + } |
| 280 | + return toolSet; |
| 281 | + }, |
| 282 | + drawClipEditTools: function( smilClip ){ |
| 283 | + var _this = this; |
230 | 284 | var toolId = ''; |
231 | | - // get the toolId based on what "ref type" smilClip is: |
232 | | - switch( this.sequencer.getSmil().getRefType( smilClip ) ){ |
233 | | - case 'video': |
234 | | - case 'audio': |
235 | | - toolId = 'trim'; |
236 | | - break; |
237 | | - default: |
238 | | - toolId = 'duration'; |
239 | | - break; |
240 | | - } |
| 285 | + var $target = this.sequencer.getEditToolTarget(); |
241 | 286 | |
| 287 | + // Set the current smilClip |
| 288 | + this.currentSmilClip = smilClip; |
242 | 289 | |
243 | | - // Make sure the toolid exists |
244 | | - if( !this.tools[ toolId ] ){ |
245 | | - mw.log("Error: tool " + toolId + ' not found'); |
246 | | - return ; |
247 | | - } |
248 | | - var tool = this.tools[ toolId ]; |
249 | 290 | |
250 | | - // Append the title: |
251 | 291 | $target.empty().append( |
252 | | - $j('<div />').addClass( 'editToolsContainer' ) |
253 | | - , |
254 | | - $j('<h3 />' ).append( |
255 | | - tool.title |
| 292 | + $j('<div />') |
| 293 | + .addClass( 'editToolsContainer' ) |
| 294 | + .append( |
| 295 | + $j('<ul />') |
256 | 296 | ) |
257 | 297 | ); |
258 | | - |
259 | | - // Build out the attribute list: |
260 | | - for( var i=0; i < tool.editableAttributes.length ; i++ ){ |
261 | | - attributeName = tool.editableAttributes[i]; |
262 | | - $target.append( |
263 | | - this.getEditableAttribute( smilClip, toolId, attributeName ) |
| 298 | + |
| 299 | + // get the toolId based on what "ref type" smilClip is: |
| 300 | + $j.each( this.getToolSet( this.sequencer.getSmil().getRefType( smilClip ) ), function( inx, toolId ){ |
| 301 | + |
| 302 | + var tool = _this.tools[ toolId ]; |
| 303 | + |
| 304 | + // set the currentTool if not already set |
| 305 | + if(!_this.currentToolId){ |
| 306 | + _this.currentToolId = toolId; |
| 307 | + } |
| 308 | + |
| 309 | + // Append the title to the ul list |
| 310 | + $target.find( 'ul').append( |
| 311 | + $j('<li />').append( |
| 312 | + $j('<a />') |
| 313 | + .attr('href', '#tooltab_' + toolId ) |
| 314 | + .text( gM('mwe-sequencer-tools-' + toolId) ) |
| 315 | + ) |
264 | 316 | ); |
265 | | - } |
| 317 | + |
| 318 | + // Append the tooltab container |
| 319 | + $target.append( |
| 320 | + $j('<div />') |
| 321 | + .attr('id', 'tooltab_' + toolId ) |
| 322 | + ) |
| 323 | + var $toolContainer = $target.find( '#tooltab_' + toolId ); |
| 324 | + |
| 325 | + // Build out the attribute list for the given tool: |
| 326 | + for( var i=0; i < tool.editableAttributes.length ; i++ ){ |
| 327 | + attributeName = tool.editableAttributes[i]; |
| 328 | + $toolContainer.append( |
| 329 | + _this.getEditableAttribute( smilClip, toolId, attributeName ) |
| 330 | + ); |
| 331 | + } |
| 332 | + |
| 333 | + // Output a float divider: |
| 334 | + $toolContainer.append( $j('<div />').addClass('ui-helper-clearfix') ); |
| 335 | + |
| 336 | + // Build out tool widgets |
| 337 | + if( tool.editWidgets ){ |
| 338 | + for( var i =0 ; i < tool.editWidgets.length ; i ++ ){ |
| 339 | + var editWidgetId = tool.editWidgets[i]; |
| 340 | + if( ! _this.editWidgets[editWidgetId] ){ |
| 341 | + mw.log("Error: not recogonized widget: " + editWidgetId); |
| 342 | + continue; |
| 343 | + } |
| 344 | + // Append a target for the edit widget: |
| 345 | + $toolContainer.append( |
| 346 | + $j('<div />') |
| 347 | + .attr('id', 'editWidgets_' + editWidgetId) |
| 348 | + ); |
| 349 | + // Draw the binded widget: |
| 350 | + _this.editWidgets[editWidgetId].draw( |
| 351 | + _this, |
| 352 | + $j( '#editWidgets_' + editWidgetId ), |
| 353 | + smilClip |
| 354 | + ) |
| 355 | + // Output a float divider: |
| 356 | + $toolContainer.append( $j('<div />').addClass( 'ui-helper-clearfix' ) ); |
| 357 | + } |
| 358 | + } |
| 359 | + }); |
266 | 360 | |
267 | | - // output a float divider: |
268 | | - $target.append( $j('<div />').addClass('ui-helper-clearfix') ); |
269 | | - |
270 | | - // Build out widgets |
271 | | - if( tool.editWidgets ){ |
272 | | - for( var i =0 ; i < tool.editWidgets.length ; i ++ ){ |
273 | | - var editWidgetId = tool.editWidgets[i]; |
274 | | - if( ! this.editWidgets[editWidgetId] ){ |
275 | | - mw.log("Error: not recogonized widget: " + editWidgetId); |
276 | | - continue; |
277 | | - } |
278 | | - // Append a target for the edit widget: |
279 | | - $target.append( |
280 | | - $j('<div />') |
281 | | - .attr('id', 'editWidgets_' + editWidgetId) |
282 | | - ); |
283 | | - // Draw the binded widget: |
284 | | - this.editWidgets[editWidgetId].draw( |
285 | | - this, |
286 | | - $j( '#editWidgets_' + editWidgetId ), |
287 | | - smilClip |
288 | | - ) |
289 | | - // Output a float divider: |
290 | | - $target.append( $j('<div />').addClass( 'ui-helper-clearfix' ) ); |
291 | | - } |
292 | | - } |
293 | | - |
294 | | - // Build out edit Actions buttons |
295 | | - for( var i=0; i < tool.editActions.length ; i++){ |
296 | | - var editActionId = tool.editActions[i]; |
| 361 | + // Add tab bindings |
| 362 | + $target.find('.editToolsContainer').tabs({ |
| 363 | + select: function(event, ui) { |
| 364 | + debugger; |
| 365 | + } |
| 366 | + }) |
| 367 | + // Build out global edit Actions buttons ( per 'current tool' ) |
| 368 | + for( var editActionId in this.editActions ){ |
297 | 369 | $target.append( |
298 | | - this.getEditAction( smilClip, toolId, editActionId ) |
| 370 | + this.getEditAction( smilClip, editActionId ) |
299 | 371 | ) |
300 | 372 | } |
301 | 373 | }, |
302 | | - getEditAction: function( smilClip, toolId, editActionId ){ |
| 374 | + getCurrentSmilClip: function(){ |
| 375 | + return this.currentSmilClip; |
| 376 | + }, |
| 377 | + getCurrentToolId: function(){ |
| 378 | + return this.currentToolId; |
| 379 | + }, |
| 380 | + |
| 381 | + getEditAction: function( smilClip, editActionId ){ |
303 | 382 | if(! this.editActions[ editActionId ]){ |
304 | 383 | mw.log("Error: getEditAction: " + editActionId + ' not found '); |
305 | 384 | return ; |
— | — | @@ -314,7 +393,7 @@ |
315 | 394 | 'margin': '5px' |
316 | 395 | }) |
317 | 396 | .click( function(){ |
318 | | - editAction.action( _this, smilClip, toolId ); |
| 397 | + editAction.action( _this, smilClip ); |
319 | 398 | }) |
320 | 399 | return $actionButton; |
321 | 400 | }, |
— | — | @@ -350,7 +429,7 @@ |
351 | 430 | |
352 | 431 | $j('<input />') |
353 | 432 | .attr( { |
354 | | - 'id' : _this.getEditToolId( toolId, attributeName), |
| 433 | + 'id' : _this.getEditToolInputId( toolId, attributeName), |
355 | 434 | 'size': 6 |
356 | 435 | }) |
357 | 436 | .data('initialValue', initialValue ) |
Index: branches/MwEmbedStandAlone/modules/Sequencer/mw.SequencerTimeline.js |
— | — | @@ -81,24 +81,49 @@ |
82 | 82 | return mw.getConfig( 'Sequencer.TimelineTrackHeight' ) |
83 | 83 | } |
84 | 84 | }, |
85 | | - // Get the selected sequence track index ( for now its always zero ) |
86 | | - getSelectedTrackIndex: function(){ |
87 | | - return 0; |
| 85 | + /* |
| 86 | + * Get the track index by type and then by number |
| 87 | + * @param {string} type Type of track 'audio' or 'video' |
| 88 | + * @param {Number=} trackNumber Optional if not set the first track index of selected type is returned |
| 89 | + */ |
| 90 | + getTrackIndexType: function( trackType, trackNumber ){ |
| 91 | + if( !trackNumber ) |
| 92 | + trackNumber = 0; |
| 93 | + var smilSequenceTracks = this.sequencer.getSmil().getBody().getSeqElements(); |
| 94 | + var returnTrackIndex = false; |
| 95 | + for(var trackIndex = 0; trackIndex < smilSequenceTracks.length; trackIndex ++){ |
| 96 | + if( $j( smilSequenceTracks[ trackIndex ]).attr('tracktype') == trackType ){ |
| 97 | + if( trackNumber == 0 ){ |
| 98 | + return trackIndex; |
| 99 | + } |
| 100 | + trackNumber--; |
| 101 | + } |
| 102 | + }; |
| 103 | + mw.log("Error: SequencerTimelin:: getTrackIndexType: offset to large ( " + |
| 104 | + trackOffset + ' or no track of type ' + type ); |
| 105 | + return false; |
88 | 106 | }, |
89 | 107 | |
90 | 108 | // Draw the timeline |
91 | | - drawTimeline: function(){ |
| 109 | + drawTimeline: function( callback ){ |
92 | 110 | var _this = this; |
93 | 111 | // xxx TODO support multiple tracks ::: |
94 | 112 | var smilSequenceTracks = this.sequencer.getSmil().getBody().getSeqElements(); |
95 | 113 | |
| 114 | + var trackStack =0; |
96 | 115 | // Draw all the tracks |
97 | 116 | $j.each(smilSequenceTracks, function( trackIndex, smilSequenceTrack ){ |
98 | | - _this.drawSequenceTrack( trackIndex, smilSequenceTrack ); |
| 117 | + trackStack++; |
| 118 | + _this.drawSequenceTrack( trackIndex, smilSequenceTrack, function(){ |
| 119 | + trackStack--; |
| 120 | + if( trackStack == 0 && callback ){ |
| 121 | + callback(); |
| 122 | + } |
| 123 | + }); |
99 | 124 | }) |
100 | 125 | }, |
101 | 126 | |
102 | | - drawSequenceTrack: function( trackIndex, smilSequenceTrack ){ |
| 127 | + drawSequenceTrack: function( trackIndex, smilSequenceTrack, callback){ |
103 | 128 | var _this = this; |
104 | 129 | // Tracks by default are video tracks |
105 | 130 | mw.log("SequenceTimeline::drawSequenceTrack: Track inx: " + |
— | — | @@ -126,16 +151,16 @@ |
127 | 152 | $clipTrackSet = $j( '#' + this.getTrackSetId( trackIndex )); |
128 | 153 | } |
129 | 154 | // Draw sequence track clips ( checks for dom updates to smilSequenceTrack ) |
130 | | - this.drawTrackClipsInterface( $clipTrackSet, smilSequenceTrack ); |
| 155 | + this.drawTrackClips( $clipTrackSet, smilSequenceTrack, callback ); |
131 | 156 | }, |
132 | 157 | |
133 | 158 | /** |
134 | | - * add Track Clips and Interface binding |
| 159 | + * Add Track Clips and Interface binding |
135 | 160 | */ |
136 | | - drawTrackClipsInterface: function( $clipTrackSet, smilSequenceTrack ){ |
| 161 | + drawTrackClips: function( $clipTrackSet, smilSequenceTrack, callback ){ |
137 | 162 | var _this = this; |
138 | | - mw.log( 'drawTrackClipsInterface:: existing lenght: ' + |
139 | | - $clipTrackSet.children() + ' id: ' + $clipTrackSet.attr('id') ); |
| 163 | + mw.log( 'drawTrackClips:: existing length: ' + |
| 164 | + $clipTrackSet.children().length + ' id: ' + $clipTrackSet.attr('id') ); |
140 | 165 | // Setup a local pointer to the smil engine: |
141 | 166 | var smil = this.sequencer.getSmil(); |
142 | 167 | |
— | — | @@ -147,12 +172,13 @@ |
148 | 173 | // Get all the refs that are children of the smilSequenceTrack with associated offsets and durations |
149 | 174 | // for now assume all tracks start at zero time: |
150 | 175 | var startOffset = 0; |
| 176 | + var thumbRenderStack = 0; |
151 | 177 | smil.getBody().getRefElementsRecurse( smilSequenceTrack, startOffset, function( $node ){ |
152 | | - var reRenderThumbFlag = false; |
153 | | - mw.log("ADD: " + _this.getTimelineClipId( $node ) + ' to ' + $clipTrackSet.attr('id') ); |
| 178 | + var reRenderThumbFlag = false; |
154 | 179 | // Draw the node onto the timeline if the clip is not already there: |
155 | 180 | var $timelineClip = $clipTrackSet.find( '#' + _this.getTimelineClipId( $node ) ) |
156 | | - if( $timelineClip.length == 0 ){ |
| 181 | + if( $timelineClip.length == 0 ){ |
| 182 | + mw.log(" ADD: " + _this.getTimelineClipId( $node ) + ' to ' + $clipTrackSet.attr('id') ); |
157 | 183 | $timelineClip = _this.getTimelineClip( smilSequenceTrack, $node ); |
158 | 184 | // Set the index order on the clip |
159 | 185 | $timelineClip.data( 'indexOrder', $clipTrackSet.children().length ); |
— | — | @@ -175,19 +201,24 @@ |
176 | 202 | } |
177 | 203 | } |
178 | 204 | |
179 | | - // xxx Check if the start time was changed to set reRenderThumbFlag |
180 | | - |
181 | | - if ( reRenderThumbFlag ){ |
182 | | - // issue a draw Thumb request ( since we reinserted into the dom ) |
183 | | - // Check Buffer for when the first frame of the smilNode can be grabbed: |
184 | | - smil.getBuffer().bufferedSeek( $node, 0, function(){ |
185 | | - //mw.log("getTrackClipInterface::bufferedSeek for " + smil.getPageDomId( $node )); |
186 | | - _this.drawClipThumb( $node , 0); |
| 205 | + // xxx Check if the start time was changed to set reRenderThumbFlag |
| 206 | + if ( reRenderThumbFlag ){ |
| 207 | + thumbRenderStack++; |
| 208 | + // Issue a relative draw Thumb request for the start time |
| 209 | + smil.getBuffer().bufferedSeekRelativeTime( $node, 0, function(){ |
| 210 | + mw.log("getTrackClipInterface::bufferedSeekRelativeTime for " + smil.getPageDomId( $node )); |
| 211 | + _this.drawClipThumb( $node , 0, function(){ |
| 212 | + thumbRenderStack--; |
| 213 | + if( thumbRenderStack == 0 ){ |
| 214 | + callback(); |
| 215 | + } |
| 216 | + }); |
187 | 217 | }); |
188 | 218 | } |
189 | 219 | |
190 | 220 | // Update the $previusClip |
191 | 221 | $previusClip = $timelineClip; |
| 222 | + |
192 | 223 | // Update the natural order index |
193 | 224 | seqOrder ++; |
194 | 225 | }); |
— | — | @@ -210,14 +241,14 @@ |
211 | 242 | ( this.timelineThumbSize.width + 12 ) |
212 | 243 | ); |
213 | 244 | |
214 | | - // Add global TrackClipInterface bindings: |
| 245 | + // Add TrackClipInterface bindings: |
215 | 246 | var keyBindings = this.sequencer.getKeyBindings(); |
216 | 247 | $j( keyBindings ).bind('escape', function(){ |
217 | 248 | // If a clips are selected deselect |
218 | 249 | var selectedClips = _this.getTimelineContainer().find( '.selectedClip' ) |
219 | 250 | if( selectedClips.length ){ |
220 | 251 | selectedClips.removeClass( 'selectedClip' ); |
221 | | - return; |
| 252 | + return false; |
222 | 253 | } |
223 | 254 | // Else trigger an exit request |
224 | 255 | _this.sequencer.getActionsSequence().exit(); |
— | — | @@ -312,8 +343,7 @@ |
313 | 344 | var smil = this.sequencer.getSmil(); |
314 | 345 | // get the smil element for the edit tool: |
315 | 346 | var smilClip = smil.$dom.find( '#' + $j( selectedClip ).data('smilId') ); |
316 | | - var toolTarget = this.sequencer.getEditToolTarget(); |
317 | | - this.sequencer.getTools().drawClipEditTools( toolTarget, smilClip ); |
| 347 | + this.sequencer.getTools().drawClipEditTools( smilClip ); |
318 | 348 | }, |
319 | 349 | |
320 | 350 | /** |
— | — | @@ -366,7 +396,12 @@ |
367 | 397 | var _this = this; |
368 | 398 | // Handle optional arguments |
369 | 399 | if( typeof trackIndex == 'undefined' ){ |
370 | | - trackIndex = this.getSelectedTrackIndex(); |
| 400 | + // default audio to audio track |
| 401 | + if( _this.sequencer.getSmil().getRefType( smilClip ) == 'audio' ){ |
| 402 | + trackIndex = this.getTrackIndexType('audio'); |
| 403 | + } else { |
| 404 | + trackIndex = this.getTrackIndexType('video'); |
| 405 | + } |
371 | 406 | } |
372 | 407 | var $clipTrackSet = $j( '#' + this.getTrackSetId( trackIndex ) ); |
373 | 408 | if( $clipTrackSet.length == 0 ){ |
— | — | @@ -389,27 +424,31 @@ |
390 | 425 | ) |
391 | 426 | } |
392 | 427 | |
393 | | - // Update the dom timeline |
394 | | - this.drawTimeline(); |
| 428 | + // Update the dom timeline |
| 429 | + _this.drawTimeline(function(){ |
| 430 | + |
| 431 | + // Invalidate / update embedPlayer duration / clip offsets |
| 432 | + _this.sequencer.getEmbedPlayer().getDuration( true ); |
| 433 | + |
| 434 | + // Register the insert edit action |
| 435 | + _this.sequencer.getActionsEdit().registerEdit(); |
| 436 | + |
| 437 | + // Select the current clip |
| 438 | + var $timelineClip = $clipTrackSet.find('#' + this.getTimelineClipId( smilClip ) ) |
| 439 | + if( $timelineClip.length == 0 ){ |
| 440 | + mw.log("Error: insertSmilClipEdit: could not find clip: " + this.getTimelineClipId( smilClip ) ); |
| 441 | + } |
| 442 | + _this.getTimelineContainer().find( '.selectedClip' ).removeClass( 'selectedClip' ); |
| 443 | + $timelineClip.addClass( 'selectedClip' ); |
| 444 | + |
| 445 | + // Seek to the added clip |
| 446 | + // xxx should have a callback for drawTimeline |
| 447 | + _this.seekToStartOfClip( $timelineClip ); |
| 448 | + |
| 449 | + // Display the edit interface |
| 450 | + _this.editClip( $timelineClip ); |
| 451 | + }); |
395 | 452 | |
396 | | - // Invalidate / update embedPlayer duration / clip offsets |
397 | | - this.sequencer.getEmbedPlayer().getDuration( true ); |
398 | | - |
399 | | - // Register the insert edit action |
400 | | - _this.sequencer.getActionsEdit().registerEdit(); |
401 | | - |
402 | | - // Select the current clip |
403 | | - var $timelineClip = $clipTrackSet.find('#' + this.getTimelineClipId( smilClip ) ) |
404 | | - if( $timelineClip.length == 0 ){ |
405 | | - mw.log("Error: insertSmilClipEdit: could not find clip: " + this.getTimelineClipId( smilClip ) ); |
406 | | - } |
407 | | - this.getTimelineContainer().find( '.selectedClip' ).removeClass( 'selectedClip' ); |
408 | | - $timelineClip.addClass( 'selectedClip' ); |
409 | | - // Seek to the added clip |
410 | | - this.seekToStartOfClip( $timelineClip ); |
411 | | - |
412 | | - // Display the edit interface with 'special' cancel button |
413 | | - this.editClip( $timelineClip ); |
414 | 453 | }, |
415 | 454 | |
416 | 455 | handleReorder: function ( movedClip ){ |
— | — | @@ -568,7 +607,7 @@ |
569 | 608 | }, |
570 | 609 | |
571 | 610 | // Draw a clip thumb into the timeline clip target |
572 | | - drawClipThumb: function ( $node , relativeTime ){ |
| 611 | + drawClipThumb: function ( $node , relativeTime, callback ){ |
573 | 612 | var _this = this; |
574 | 613 | var smil = this.sequencer.getSmil(); |
575 | 614 | |
— | — | @@ -655,23 +694,24 @@ |
656 | 695 | }) |
657 | 696 | .attr( 'src', smil.getAssetUrl( $node.attr('poster') ) ) |
658 | 697 | .load( function(){ |
659 | | - if( $thumbTarget.children().length == 0 ){ |
| 698 | + if( $thumbTarget.children().length == 0 ){ |
660 | 699 | $thumbTarget.html( img ); |
661 | 700 | } |
662 | 701 | }); |
663 | 702 | |
664 | 703 | // Sometimes the load event does not fire. Force the fallback image after 5 seconds |
665 | | - setTimeout( function(){ |
| 704 | + setTimeout( function(){ |
666 | 705 | if( $thumbTarget.children().length == 0 ){ |
667 | | - $thumbTarget.html( img ); |
| 706 | + mw.log( "SequencerTimeline::drawClipThumb: force image fallabck:: " + img.src); |
| 707 | + $thumbTarget.html( img ); |
668 | 708 | } |
669 | 709 | }, 5000); |
670 | 710 | } |
671 | 711 | |
672 | 712 | // Buffer the asset then render it into the layout target: |
673 | | - smil.getBuffer().bufferedSeek( $node, relativeTime, function(){ |
674 | | - // Add the seek, add to canvas and draw thumb request |
675 | | - smil.getLayout().drawElementThumb( $thumbTarget, $node, relativeTime ); |
| 713 | + smil.getBuffer().bufferedSeekRelativeTime( $node, relativeTime, function(){ |
| 714 | + // Add the seek, Add to canvas and draw thumb request |
| 715 | + smil.getLayout().drawElementThumb( $thumbTarget, $node, relativeTime, callback ); |
676 | 716 | |
677 | 717 | }) |
678 | 718 | }, |
Index: branches/MwEmbedStandAlone/modules/Sequencer/mw.SequencerAddByUrl.js |
— | — | @@ -17,7 +17,7 @@ |
18 | 18 | * Does a basic parseUri check to see if a string is likely a url: |
19 | 19 | */ |
20 | 20 | isUrl: function( inputString ){ |
21 | | - return ( mw.parseUri( inputString ).authority != mw.parseUri( inputString ).host ) ; |
| 21 | + return ( mw.parseUri( inputString ).protocol ) ; |
22 | 22 | }, |
23 | 23 | |
24 | 24 | /** |
— | — | @@ -27,12 +27,65 @@ |
28 | 28 | * Uses remoteSearchDriver to help in retrieving entry info |
29 | 29 | * @param {Object} remoteSearchDriver The remote search driver |
30 | 30 | */ |
31 | | - addByUrlDialog: function( remoteSearchDriver, url ){ |
| 31 | + addByUrlDialog: function( remoteSearchDriver, url ){ |
| 32 | + var _this = this; |
| 33 | + var $dialog = mw.addLoaderDialog( gM( 'mwe-sequencer-loading-asset' ) ); |
| 34 | + |
| 35 | + // Close / empty the toolWindow |
| 36 | + _this.sequencer.getTools().setDefaultText(); |
| 37 | + |
| 38 | + var foundImportUrl = false; |
32 | 39 | // See if the asset matches the detailsUrl key type of any enabled content provider: |
33 | 40 | $j.each( remoteSearchDriver.getEnabledProviders(), function(providerName, provider){ |
34 | | - |
| 41 | + if( mw.parseUri( provider.detailsUrl ).host == mw.parseUri( url).host ){ |
| 42 | + foundImportUrl = true ; |
| 43 | + |
| 44 | + mw.log("addByUrlDialog: matching host getResourceFromUrl::" |
| 45 | + + mw.parseUri( provider.detailsUrl ).host |
| 46 | + + ' == ' + mw.parseUri( url).host ); |
| 47 | + |
| 48 | + // Do special check for mediawiki templates and pages as 'special' smil types |
| 49 | + if( provider.lib == 'mediaWiki' ){ |
| 50 | + // xxx we should do a query to the api to determine namespace instead of hard coded checks |
| 51 | + remoteSearchDriver.loadSearchLib( provider, function( provider ){ |
| 52 | + var titleKey = provider.sObj.getTitleKeyFromMwUrl( url ); |
| 53 | + if( !titleKey ){ |
| 54 | + // continue for loop ( if we can't get a title from the mediaWiki url ) |
| 55 | + return true; |
| 56 | + } |
| 57 | + // Check the title type |
| 58 | + // xxx should use wgFormattedNamespacess |
| 59 | + if( titleKey.indexOf('File:') == 0 ){ |
| 60 | + // Asset is a file import resource as a file: |
| 61 | + remoteSearchDriver.getResourceFromUrl( provider, url, function( resource ){ |
| 62 | + if( ! resource ){ |
| 63 | + $dialog.html( 'Error loading asset'); |
| 64 | + return ; |
| 65 | + } |
| 66 | + // Get convert resource to smilClip and insert into the timeline |
| 67 | + _this |
| 68 | + .sequencer |
| 69 | + .getAddMedia() |
| 70 | + .getSmilClipFromResource( resource, function( smilClip ) { |
| 71 | + _this.sequencer.getTimeline().insertSmilClipEdit( smilClip ); |
| 72 | + mw.closeLoaderDialog(); |
| 73 | + }); |
| 74 | + }); |
| 75 | + } else { |
| 76 | + // xxx special Template resource import goes here |
| 77 | + } |
| 78 | + |
| 79 | + }); |
| 80 | + } else { |
| 81 | + mw.log(" only MediaWiki URLs supported as resources right now"); |
| 82 | + } |
| 83 | + } |
35 | 84 | }); |
36 | 85 | |
| 86 | + if( ! foundImportUrl ){ |
| 87 | + mw.closeLoaderDialog(); |
| 88 | + } |
| 89 | + // xxx support direct asset include |
37 | 90 | if( mw.getConfig( 'Sequencer.AddAssetByUrl' )){ |
38 | 91 | // try directly adding the asset |
39 | 92 | } |
Index: branches/MwEmbedStandAlone/modules/Sequencer/remotes/mw.MediaWikiRemoteSequencer.js |
— | — | @@ -177,7 +177,7 @@ |
178 | 178 | gM('mwe-sequencer-not-published', |
179 | 179 | $j('<a />').click( function(){ |
180 | 180 | _this.showEditor(); |
181 | | - }) |
| 181 | + }).css('cursor', 'pointer') |
182 | 182 | ) |
183 | 183 | ) |
184 | 184 | .addClass( 'ui-state-highlight' ) |
— | — | @@ -197,7 +197,7 @@ |
198 | 198 | gM('mwe-sequencer-published-out-of-date', |
199 | 199 | $j('<a />').click( function(){ |
200 | 200 | _this.showEditor(); |
201 | | - }) |
| 201 | + }).css('cursor', 'pointer') |
202 | 202 | ) |
203 | 203 | ).addClass( 'ui-state-highlight' ) |
204 | 204 | ) |