Index: branches/MwEmbedStandAlone/mwEmbed.js |
— | — | @@ -1038,22 +1038,15 @@ |
1039 | 1039 | } |
1040 | 1040 | |
1041 | 1041 | /** |
1042 | | - * Mobile Safari has special properties for html5 video:: |
1043 | | - * |
1044 | | - * NOTE: should be moved to browser detection script |
| 1042 | + * Close the loader dialog created with addLoaderDialog |
1045 | 1043 | */ |
1046 | | - mw.isMobileSafari = function() { |
1047 | | - // check mobile safari foce ( for debug ) |
1048 | | - if( mw.getConfig( 'forceMobileSafari' ) ){ |
1049 | | - return true; |
| 1044 | + mw.closeLoaderDialog = function() { |
| 1045 | + // Make sure the dialog resource is present |
| 1046 | + if( !mw.isset( '$j.ui.dialog' ) ) { |
| 1047 | + return false; |
1050 | 1048 | } |
1051 | | - if ((navigator.userAgent.indexOf('iPhone') != -1) || |
1052 | | - (navigator.userAgent.indexOf('iPod') != -1) || |
1053 | | - (navigator.userAgent.indexOf('iPad') != -1)) { |
1054 | | - return true; |
1055 | | - } |
1056 | | - return false; |
1057 | | - } |
| 1049 | + $j( '#mwTempLoaderDialog' ).dialog( 'destroy' ).remove(); |
| 1050 | + } |
1058 | 1051 | |
1059 | 1052 | /** |
1060 | 1053 | * Add a (temporary) dialog window: |
— | — | @@ -1127,20 +1120,26 @@ |
1128 | 1121 | $j( '#mwTempLoaderDialog' ).dialog( options ); |
1129 | 1122 | } ); |
1130 | 1123 | return $j( '#mwTempLoaderDialog' ); |
1131 | | - } |
| 1124 | + } |
1132 | 1125 | |
1133 | 1126 | /** |
1134 | | - * Close the loader dialog created with addLoaderDialog |
| 1127 | + * Mobile Safari has special properties for html5 video:: |
| 1128 | + * |
| 1129 | + * NOTE: should be moved to browser detection script |
1135 | 1130 | */ |
1136 | | - mw.closeLoaderDialog = function() { |
1137 | | - // Make sure the dialog resource is present |
1138 | | - if( !mw.isset( '$j.ui.dialog' ) ) { |
1139 | | - return false; |
| 1131 | + mw.isMobileSafari = function() { |
| 1132 | + // check mobile safari foce ( for debug ) |
| 1133 | + if( mw.getConfig( 'forceMobileSafari' ) ){ |
| 1134 | + return true; |
1140 | 1135 | } |
1141 | | - $j( '#mwTempLoaderDialog' ).dialog( 'destroy' ).remove(); |
| 1136 | + if ((navigator.userAgent.indexOf('iPhone') != -1) || |
| 1137 | + (navigator.userAgent.indexOf('iPod') != -1) || |
| 1138 | + (navigator.userAgent.indexOf('iPad') != -1)) { |
| 1139 | + return true; |
| 1140 | + } |
| 1141 | + return false; |
1142 | 1142 | } |
1143 | 1143 | |
1144 | | - |
1145 | 1144 | /** |
1146 | 1145 | * Similar to php isset function checks if the variable exists. Does a safe |
1147 | 1146 | * check of a descendant method or variable |
— | — | @@ -1796,13 +1795,15 @@ |
1797 | 1796 | |
1798 | 1797 | /** |
1799 | 1798 | * getAbsoluteUrl takes a src and returns the absolute location given the |
1800 | | - * document.URL |
| 1799 | + * document.URL or a contextUrl param |
1801 | 1800 | * |
1802 | | - * @param {String} |
1803 | | - * src path or url |
| 1801 | + * @param {String} src path or url |
| 1802 | + * @param {String} contextUrl The domain / context for creating an absolute url |
| 1803 | + * from a relative path |
1804 | 1804 | * @return {String} absolute url |
1805 | 1805 | */ |
1806 | 1806 | mw.absoluteUrl = function( src, contextUrl ) { |
| 1807 | + |
1807 | 1808 | var parsedSrc = mw.parseUri( src ); |
1808 | 1809 | // Source is already absolute return: |
1809 | 1810 | if( parsedSrc.protocol != '') { |
— | — | @@ -1810,7 +1811,7 @@ |
1811 | 1812 | } |
1812 | 1813 | |
1813 | 1814 | // Get parent Url location the context URL |
1814 | | - if( contextUrl) { |
| 1815 | + if( contextUrl ) { |
1815 | 1816 | var parsedUrl = mw.parseUri( contextUrl ); |
1816 | 1817 | } else { |
1817 | 1818 | var parsedUrl = mw.parseUri( document.URL ); |
Index: branches/MwEmbedStandAlone/modules/Sequencer/loader.js |
— | — | @@ -5,12 +5,12 @@ |
6 | 6 | // Wrap in mw to not pollute global namespace |
7 | 7 | ( function( mw ) { |
8 | 8 | |
9 | | - mw.addResourcePaths( { |
10 | | - "mw.Sequencer" : "mw.Sequencer.js", |
11 | | - |
| 9 | + mw.addResourcePaths( { |
12 | 10 | "mw.Sequencer" : "mw.Sequencer.js", |
13 | 11 | "mw.style.Sequencer" : "mw.style.Sequencer.css", |
14 | 12 | |
| 13 | + "mw.SequencerConfig" : "mw.SequencerConfig.js", |
| 14 | + |
15 | 15 | "mw.SequencerAddMedia" : "mw.SequencerAddMedia.js", |
16 | 16 | "mw.SequencerPlayer" : "mw.SequencerPlayer.js", |
17 | 17 | "mw.SequencerTimeline" : "mw.SequencerTimeline.js", |
— | — | @@ -32,15 +32,6 @@ |
33 | 33 | |
34 | 34 | } ); |
35 | 35 | |
36 | | - mw.setDefaultConfig({ |
37 | | - // If the sequencer should attribute kaltura |
38 | | - "Sequencer.KalturaAttribution" : true, |
39 | | - |
40 | | - // The size of the undo stack |
41 | | - "Sequencer.numberOfUndos" : 100 |
42 | | - }) |
43 | | - |
44 | | - |
45 | 36 | /** |
46 | 37 | * The FirefoggRender sub module |
47 | 38 | */ |
— | — | @@ -57,8 +48,9 @@ |
58 | 49 | // Make sure we have the required mwEmbed libs: |
59 | 50 | return [ |
60 | 51 | [ // Load the EmbedPlayer Module ( includes lots of dependent classes ) |
61 | | - 'EmbedPlayer', |
62 | | - 'mw.Sequencer' |
| 52 | + 'EmbedPlayer', |
| 53 | + 'mw.Sequencer', |
| 54 | + 'mw.SequencerConfig' |
63 | 55 | ], |
64 | 56 | [ |
65 | 57 | '$j.contextMenu', |
Index: branches/MwEmbedStandAlone/modules/Sequencer/mw.Sequencer.js |
— | — | @@ -228,7 +228,7 @@ |
229 | 229 | |
230 | 230 | /* timeline container */ |
231 | 231 | 'south__minSize' : 160, |
232 | | - 'south__size' : 150, |
| 232 | + 'south__size' : 200, |
233 | 233 | 'south__onresize' : function(){ |
234 | 234 | _this.getTimeline().resizeTimeline(); |
235 | 235 | } |
Index: branches/MwEmbedStandAlone/modules/Sequencer/css/mw.style.Sequencer.css |
— | — | @@ -6,7 +6,7 @@ |
7 | 7 | top: 4px; |
8 | 8 | left:4px; |
9 | 9 | right: 4px; |
10 | | - bottom: 4px; |
| 10 | + |
11 | 11 | } |
12 | 12 | |
13 | 13 | .mwe-sequencer .trackNameContainer{ |
— | — | @@ -28,7 +28,6 @@ |
29 | 29 | } |
30 | 30 | |
31 | 31 | .mwe-sequencer .trackNames{ |
32 | | - height: 100px; |
33 | 32 | background-color: #EEE; |
34 | 33 | border: solid thin #999; |
35 | 34 | padding:4px |
— | — | @@ -56,14 +55,18 @@ |
57 | 56 | background-color:#6F6; |
58 | 57 | border:2px dashed #000; |
59 | 58 | } |
60 | | -.mwe-sequencer .timelineClip:hover{ |
| 59 | +.mwe-sequencer .timelineClip:hover{ |
61 | 60 | border: 2px solid #66F; |
62 | 61 | } |
63 | 62 | .mwe-sequencer .selectedClip{ |
64 | | - border: 2px solid #F66; |
| 63 | + margin-top: 1px; |
| 64 | + margin-left: 1px; |
| 65 | + border: 4px solid #F66; |
65 | 66 | } |
66 | 67 | .mwe-sequencer .selectedClip:hover{ |
67 | | - border: 2px solid #F22; |
| 68 | + margin-top: 1px; |
| 69 | + margin-left: 1px; |
| 70 | + border: 4px solid #F22; |
68 | 71 | } |
69 | 72 | |
70 | 73 | .mwe-sequencer .trimStartThumb, .trimEndThumb { |
Index: branches/MwEmbedStandAlone/modules/Sequencer/Sequencer.i18n.php |
— | — | @@ -11,6 +11,7 @@ |
12 | 12 | 'mwe-sequencer-loading-timeline' => 'Loading timeline ...', |
13 | 13 | 'mwe-sequencer-loading-player' => 'Loading player ...', |
14 | 14 | 'mwe-sequencer-loading-menu' => 'Loading menu ...', |
| 15 | + 'mwe-sequencer-loading-asset' => 'Loading asset ...', |
15 | 16 | |
16 | 17 | 'mwe-sequencer-no_selected_resource' => '<h3>No resource selected</h3> Select a clip to enable editing.', |
17 | 18 | 'mwe-sequencer-no-sequence-start-new' => 'Empty sequence, [$1 browser for assets] to create a new sequence', |
Index: branches/MwEmbedStandAlone/modules/Sequencer/mw.SequencerAddMedia.js |
— | — | @@ -10,10 +10,12 @@ |
11 | 11 | }; |
12 | 12 | |
13 | 13 | // Set up the mvSequencer object |
14 | | -mw.SequencerAddMedia.prototype = { |
| 14 | +mw.SequencerAddMedia.prototype = { |
| 15 | + |
15 | 16 | init: function( sequencer ){ |
16 | 17 | this.sequencer = sequencer; |
17 | 18 | }, |
| 19 | + |
18 | 20 | // Get the menu widget that drives the search and upload tab selection |
19 | 21 | getMenuWidget: function(){ |
20 | 22 | var _this = this; |
— | — | @@ -48,7 +50,7 @@ |
49 | 51 | return false; |
50 | 52 | }), |
51 | 53 | |
52 | | - //input button |
| 54 | + // Input button |
53 | 55 | $j.button({ |
54 | 56 | // The text of the button link |
55 | 57 | 'text' : gM('mwe-sequencer-get-media'), |
— | — | @@ -74,7 +76,7 @@ |
75 | 77 | .empty() |
76 | 78 | .loadingSpinner(); |
77 | 79 | |
78 | | - if( ! this.remoteSearchDriver ){ |
| 80 | + if( ! _this.remoteSearchDriver ){ |
79 | 81 | // set the tool target to loading |
80 | 82 | mw.load( 'AddMedia.addMediaWizard', function(){ |
81 | 83 | _this.remoteSearchDriver = new mw.RemoteSearchDriver({ |
— | — | @@ -83,19 +85,26 @@ |
84 | 86 | 'displaySearchInput': false, |
85 | 87 | 'default_query' : inputValue, |
86 | 88 | 'displayResourceInfoIcons' : false, |
87 | | - 'resourceSelectionCallback' : function( resource ){ |
88 | | - _this.insertResourceDialog( resource ) |
| 89 | + 'resourceSelectionCallback' : function( resource ){ |
| 90 | + mw.addLoaderDialog( gM( 'mwe-sequencer-loading-asset' ) ); |
| 91 | + // Get convert resource to smilClip and insert into the timeline |
| 92 | + _this.getSmilClipFromResource( resource, function( smilClip ) { |
| 93 | + _this.sequencer.getTimeline().insertSmilClipEdit( smilClip ); |
| 94 | + mw.closeLoaderDialog(); |
| 95 | + }); |
89 | 96 | return false; |
90 | 97 | }, |
91 | 98 | 'displaySearchResultsCallback' : function(){ |
92 | 99 | _this.addSearchResultsDrag(); |
93 | 100 | } |
94 | | - }) |
95 | | - .createUI() |
| 101 | + }); |
| 102 | + // Create the search user interface: |
| 103 | + _this.remoteSearchDriver.createUI(); |
96 | 104 | }); |
97 | 105 | } else { |
98 | 106 | this.remoteSearchDriver.createUI() |
99 | 107 | } |
| 108 | + |
100 | 109 | }, |
101 | 110 | /** |
102 | 111 | * Get the resource object from a provided asset |
— | — | @@ -136,77 +145,82 @@ |
137 | 146 | revert: 'invalid' |
138 | 147 | }); |
139 | 148 | }, |
140 | | - insertAssetDialog: function( assetElement, sequenceTrack, order ){ |
141 | | - this.insertResourceDialog( |
142 | | - this.getResourceFromAsset( assetElement ), |
143 | | - sequenceTrack, |
144 | | - order |
145 | | - ); |
| 149 | + |
| 150 | + /** |
| 151 | + * Take a dom element asset from search results and |
| 152 | + * convert to a smil ref node that can be inserted into |
| 153 | + * a smil xml tree |
| 154 | + */ |
| 155 | + getSmilClipFromAsset: function( assetElement, callback ){ |
| 156 | + var resource = this.getResourceFromAsset( assetElement ) |
| 157 | + this.getSmilClipFromResource ( resource, callback ); |
146 | 158 | }, |
147 | 159 | /** |
148 | | - * Create an insert resource dialog, expose basic in-out points or / duration |
149 | | - * xxx todo if resource needs to be imported run import dialog from remoteResourceDrive |
150 | | - * buttons include insert at end or insert after current |
| 160 | + * Take an addMedia 'resource' and convert to a smil |
| 161 | + * ref node that can be inserted into a smil xml tree |
151 | 162 | */ |
152 | | - insertResourceDialog: function( resource, sequenceTrack, order ){ |
153 | | - var buttons = {}; |
154 | | - var cat = resource; |
155 | | - debugger; |
156 | | - // Get an xml smil ref pointer: ( per the supplied content type ) |
157 | | - var smilRef = this.getSmilRefFromResource( resource ); |
158 | | - |
159 | | - // Build out the resource dialog content: |
160 | | - var $content = |
161 | | - $j('<div />').append( |
162 | | - $j('<div />') |
163 | | - .addClass( 'sequencerEditTools' ) |
164 | | - .css({ |
165 | | - 'width' : '50%', |
166 | | - 'height' : '100%', |
167 | | - 'overflow': 'auto', |
168 | | - 'position' : 'absolute', |
169 | | - 'top' : '0px', |
170 | | - 'left': '0px' |
171 | | - }), |
172 | | - |
173 | | - $j('<div />') |
174 | | - .css({ |
175 | | - 'position' : 'absolute' |
176 | | - 'top' : '0px', |
177 | | - 'right': '0px', |
178 | | - 'width' : '50%', |
179 | | - 'height' : '100%' |
180 | | - }) |
181 | | - .append( |
182 | | - // the div |
183 | | - ) |
184 | | - ) |
185 | | - // Build out the edit tools |
186 | | - $content.find( '.sequencerEditTools' ) |
| 163 | + getSmilClipFromResource: function( resource, callback ){ |
| 164 | + var tagType = 'ref'; |
| 165 | + if( resource.mime.indexOf( 'image/' ) != -1 ){ |
| 166 | + tagType = 'img'; |
| 167 | + } |
| 168 | + if( resource.mime.indexOf( 'video/') != -1 ){ |
| 169 | + tagType = 'video'; |
| 170 | + } |
| 171 | + if( resource.mime.indexOf( 'audio/') != -1 ){ |
| 172 | + tagType = 'audio'; |
| 173 | + } |
| 174 | + var $smilRef = $j( '<' + tagType + ' />') |
187 | 175 | |
188 | | - // Insert after last selected clip ( or at end ) |
189 | | - buttons[ gM('mwe-sequencer-insert') ] = function() { |
190 | | - // call a function that inserts into smil and timeline ( getTimeline() ) |
191 | | - alert(' insert resource') |
| 176 | + // Set the default duration |
| 177 | + if( tagType == 'img' ){ |
| 178 | + $smilRef.attr( 'dur', mw.getConfig( 'Sequencer.AddMediaImageDuration' ) ); |
192 | 179 | } |
193 | | - // cancel |
194 | | - buttons[ gM('mwe-cancel') ] = function(){ |
195 | | - $j( this ).dialog( 'close' ); |
196 | | - }; |
197 | | - |
198 | | - mw.addDialog({ |
199 | | - 'title' : gM('mwe-sequencer-insert-resource'), |
200 | | - 'dragable' : true, |
201 | | - 'height' : 480, |
202 | | - 'width' : 800, |
203 | | - 'resizable' : true, |
204 | | - 'content' : resourceEdit.getUi() |
205 | | - 'buttons' : buttons |
206 | | - }); |
207 | | - }, |
208 | | - |
209 | | - getSmilRefFromResource: function( resource ){ |
210 | | - |
| 180 | + |
| 181 | + // Set all available params |
| 182 | + var resourceAttributeMap = { |
| 183 | + 'type' : 'mime', |
| 184 | + 'title' : 'title', |
| 185 | + 'src' : 'src', |
| 186 | + 'poster' : 'poster' |
| 187 | + } |
| 188 | + for( var i in resourceAttributeMap ){ |
| 189 | + if( resource[i] ){ |
| 190 | + $smilRef.attr( resourceAttributeMap[i], resource[i] ); |
| 191 | + } |
| 192 | + } |
| 193 | + var resourceParamMap = { |
| 194 | + 'content_provider_id' : 'apiProvider', |
| 195 | + 'id' : 'apiTitleKey' |
| 196 | + } |
| 197 | + for( var i in resourceParamMap ){ |
| 198 | + if( resource[i] ){ |
| 199 | + $smilRef.append( |
| 200 | + $j( '<param />') |
| 201 | + .attr({ |
| 202 | + 'name' : resourceParamMap[i], |
| 203 | + 'value' : resource[i] |
| 204 | + }) |
| 205 | + ) |
| 206 | + } |
| 207 | + } |
| 208 | + // Make sure we have source for the asset. |
| 209 | + if( $smilRef.attr('src') ){ |
| 210 | + callback( $smilRef.get(0) ) |
| 211 | + } else { |
| 212 | + // the resource includes a pointer to its parent search object |
| 213 | + // from the search object grab the image object for the target resolution |
| 214 | + resource.pSobj.getImageObj( |
| 215 | + resource, |
| 216 | + { |
| 217 | + 'width' : mw.getConfig( 'Sequencer.AddMediaImageWidth' ) |
| 218 | + }, |
| 219 | + function( imageObj ){ |
| 220 | + $smilRef.attr('src', imageObj.url ) |
| 221 | + callback( $smilRef.get(0) ); |
| 222 | + } |
| 223 | + ) |
| 224 | + } |
211 | 225 | } |
212 | 226 | } |
213 | 227 | |
Index: branches/MwEmbedStandAlone/modules/Sequencer/mw.SequencerTools.js |
— | — | @@ -68,6 +68,7 @@ |
69 | 69 | 'title' : gM('mwe-sequencer-preview'), |
70 | 70 | 'action': function( _this, smilClip, toolId ){ |
71 | 71 | _this.sequencer.getPlayer().previewClip( smilClip ); |
| 72 | + // xxx todo update preview button to "pause" / "play" |
72 | 73 | } |
73 | 74 | }, |
74 | 75 | 'cancel':{ |
Index: branches/MwEmbedStandAlone/modules/Sequencer/mw.SequencerConfig.js |
— | — | @@ -0,0 +1,32 @@ |
| 2 | +/** |
| 3 | + * Master default configuration for sequencer |
| 4 | + * |
| 5 | + * Do not modify this file rather after including mwEmbed |
| 6 | + * set any of these configuration values via |
| 7 | + * the mw.setConfig() method |
| 8 | + * |
| 9 | + */ |
| 10 | + |
| 11 | +// Define the class name |
| 12 | +mw.SequencerConfig = true; |
| 13 | + |
| 14 | +mw.setDefaultConfig({ |
| 15 | + // If the sequencer should attribute kaltura |
| 16 | + "Sequencer.KalturaAttribution" : true, |
| 17 | + |
| 18 | + // The size of the undo stack |
| 19 | + "Sequencer.numberOfUndos" : 100, |
| 20 | + |
| 21 | + // Default image duration |
| 22 | + "Sequencer.AddMediaImageDuration" : 2, |
| 23 | + |
| 24 | + // Default image source width |
| 25 | + "Sequencer.AddMediaImageWidth" : 640, |
| 26 | + |
| 27 | + // Default timeline "video / image" clip thumb size |
| 28 | + "Sequencer.TimelineVideoThumbSize" : 100, |
| 29 | + |
| 30 | + // Default timeline "audio / collapsed" size |
| 31 | + "Sequencer.TimelineVideoThumbSize" : 30 |
| 32 | +}) |
| 33 | + |
\ No newline at end of file |
Index: branches/MwEmbedStandAlone/modules/Sequencer/mw.SequencerTimeline.js |
— | — | @@ -1,5 +1,5 @@ |
2 | 2 | |
3 | | -//Wrap in mw closure to avoid global leakage |
| 3 | +// Wrap in mw closure to avoid global leakage |
4 | 4 | ( function( mw ) { |
5 | 5 | |
6 | 6 | mw.SequencerTimeline = function( sequencer ) { |
— | — | @@ -11,7 +11,7 @@ |
12 | 12 | // Lazy init $timelineTracksContainer |
13 | 13 | $timelineTracksContainer : null, |
14 | 14 | |
15 | | - // store a pointer to the track layout |
| 15 | + // Pointer to the track layout |
16 | 16 | trackLayout: null, |
17 | 17 | |
18 | 18 | //Default height width of timeline clip: |
— | — | @@ -27,6 +27,7 @@ |
28 | 28 | getTimelineContainer: function(){ |
29 | 29 | return this.sequencer.getContainer().find('.mwseq-timeline'); |
30 | 30 | }, |
| 31 | + |
31 | 32 | /** |
32 | 33 | * xxx needs to support multiple tracks |
33 | 34 | */ |
— | — | @@ -43,9 +44,10 @@ |
44 | 45 | $j('<div />') |
45 | 46 | .addClass( 'ui-layout-center clipTrackSetContainer') |
46 | 47 | ) |
| 48 | + .css( 'height', this.getTimelineContainerHeight() ) |
47 | 49 | ) |
48 | 50 | // Apply layout control to track name / clipTrackSet division |
49 | | - this.getTimelineContainer().find( '.timelineTrackContainer') |
| 51 | + this.trackLayout = this.getTimelineContainer().find( '.timelineTrackContainer') |
50 | 52 | .layout( { |
51 | 53 | 'applyDefaultStyles': true, |
52 | 54 | 'west__size' : 150, |
— | — | @@ -56,61 +58,82 @@ |
57 | 59 | return this.getTimelineContainer().find( '.timelineTrackContainer'); |
58 | 60 | }, |
59 | 61 | resizeTimeline: function(){ |
60 | | - this.getTimelineContainer().find( '.timelineTrackContainer').resizeAll(); |
| 62 | + this.trackLayout.resizeAll(); |
61 | 63 | }, |
| 64 | + getTimelineContainerHeight: function(){ |
| 65 | + var timelineHeight = 0; |
| 66 | + var smilSequenceTracks = this.sequencer.getSmil().getBody().getSeqElements(); |
| 67 | + $j.each(smilSequenceTracks, function( trackIndex, smilSequenceTrack ){ |
| 68 | + _this.drawSequenceTrack( trackIndex, smilSequenceTrack ); |
| 69 | + }) |
| 70 | + }, |
| 71 | + // Get the selected sequence track index ( for now its always zero ) |
| 72 | + getSelectedTrackIndex: function(){ |
| 73 | + return 0; |
| 74 | + }, |
62 | 75 | |
63 | 76 | // Draw the timeline |
64 | | - drawTimeline: function(){ |
| 77 | + drawTimeline: function(){ |
| 78 | + var _this = this; |
65 | 79 | // xxx TODO support multiple tracks ::: |
66 | | - var seqTracks = this.sequencer.getSmil().getBody().getSeqElements(); |
67 | | - // For now just one video track: |
68 | | - this.drawSequenceTrack( 0, seqTracks[ 0 ], 'video'); |
| 80 | + var smilSequenceTracks = this.sequencer.getSmil().getBody().getSeqElements(); |
| 81 | + |
| 82 | + // Draw all the tracks |
| 83 | + $j.each(smilSequenceTracks, function( trackIndex, smilSequenceTrack ){ |
| 84 | + _this.drawSequenceTrack( trackIndex, smilSequenceTrack ); |
| 85 | + }) |
69 | 86 | }, |
70 | 87 | |
71 | | - drawSequenceTrack: function( trackIndex, sequenceNode, trackType ){ |
| 88 | + drawSequenceTrack: function( trackIndex, smilSequenceTrack ){ |
72 | 89 | var _this = this; |
| 90 | + // Tracks by default are video tracks |
| 91 | + var trackType = ( $j( smilSequenceTrack ).attr('tracktype') ) ? $j ( smilSequenceTrack ).attr('tracktype') : 'video' |
73 | 92 | mw.log("SequenceTimeline::drawSequenceTrack: Track inx: " + trackIndex + ' trackType:' + trackType ); |
74 | 93 | // Check if we already have a container for this track set |
75 | 94 | |
76 | | - // Add / update the sequence track name if not present |
77 | | - // xxx check for specific sequenceTrack updates that require interface update |
78 | | - if( this.getTracksContainer().find('.trackNamesContainer').children().length == 0 ){ |
79 | | - this.getTracksContainer().find('.trackNamesContainer').append( |
80 | | - this.getTrackNameInterface( trackIndex, sequenceNode, trackType ) |
| 95 | + // Add sequence track name if not present |
| 96 | + var $clipTrackName = $j( '#' + this.getTrackNameInterfaceId( trackIndex ) ); |
| 97 | + if( $clipTrackName.length == 0 ) { |
| 98 | + $clipTrackName = this.getTracksContainer().find('.trackNamesContainer').append( |
| 99 | + this.getTrackNameInterface( trackIndex, smilSequenceTrack, trackType ) |
81 | 100 | ) |
82 | | - }; |
83 | | - // Add Sequence track clips |
84 | | - // xxx check for specific sequenceTrack updates that require interface update |
85 | | - this.drawTrackClipsInterface( trackIndex ,sequenceNode , trackType ); |
| 101 | + } |
| 102 | + // xxx check for specific smilSequenceTrack updates that require TrackNameInterface update |
| 103 | + |
| 104 | + |
| 105 | + // Add Sequence track container if not present |
| 106 | + var $clipTrackSet = $j( '#' + this.getTrackSetId( trackIndex )) |
| 107 | + if( $clipTrackSet.length == 0 ) { |
| 108 | + $clipTrackSet = this.getTracksContainer().find('.clipTrackSetContainer').append( |
| 109 | + this.getClipTrackSet( trackIndex ) |
| 110 | + ).find( '.clipTrackSet'); |
| 111 | + } |
| 112 | + // Draw sequence track clips ( checks for dom updates to smilSequenceTrack ) |
| 113 | + this.drawTrackClipsInterface( $clipTrackSet, smilSequenceTrack , trackType ); |
86 | 114 | }, |
87 | 115 | |
88 | 116 | /** |
89 | 117 | * add Track Clips and Interface binding |
90 | 118 | */ |
91 | | - drawTrackClipsInterface: function( trackIndex, sequenceNode, trackType ){ |
| 119 | + drawTrackClipsInterface: function( $clipTrackSet, smilSequenceTrack, trackType ){ |
92 | 120 | var _this = this; |
| 121 | + mw.log( '') |
93 | 122 | // Setup a local pointer to the smil engine: |
94 | 123 | var smil = this.sequencer.getSmil(); |
95 | | - |
96 | | - var $clipTrackSet = this.getTracksContainer().find('.clipTrackSetContainer').find( '.clipTrackSet' ); |
97 | | - // Add the $clipTrackSet if not already in dom: |
98 | | - if( $clipTrackSet.length == 0 ){ |
99 | | - $clipTrackSet = this.getTracksContainer().find('.clipTrackSetContainer').append( |
100 | | - this.getClipTrackSet( trackIndex ) |
101 | | - ).find( '.clipTrackSet'); |
102 | | - } |
| 124 | + |
103 | 125 | var $previusClip = null; |
104 | 126 | |
105 | 127 | var seqOrder = 0; |
106 | 128 | var reOrderTimelineFlag = false; |
107 | 129 | |
108 | | - // Get all the refs that are children of the sequenceNode with associated offsets and durations |
| 130 | + // Get all the refs that are children of the smilSequenceTrack with associated offsets and durations |
109 | 131 | // for now assume all tracks start at zero time: |
110 | 132 | var startOffset = 0; |
111 | | - smil.getBody().getRefElementsRecurse( sequenceNode, startOffset, function( $node ){ |
| 133 | + smil.getBody().getRefElementsRecurse( smilSequenceTrack, startOffset, function( $node ){ |
112 | 134 | var reRenderThumbFlag = false; |
| 135 | + mw.log("ADD: " + _this.getTimelineClipId( $node ) + ' to ' + $clipTrackSet.attr('id') ); |
113 | 136 | // Draw the node onto the timeline if the clip is not already there: |
114 | | - var $timelineClip = $clipTrackSet.find('#' + _this.getTimelineClipId( $node ) ) |
| 137 | + var $timelineClip = $clipTrackSet.find( '#' + _this.getTimelineClipId( $node ) ) |
115 | 138 | if( $timelineClip.length == 0 ){ |
116 | 139 | $timelineClip = _this.getTimelineClip( $clipTrackSet, $node ); |
117 | 140 | if( $previusClip ){ |
— | — | @@ -152,7 +175,7 @@ |
153 | 176 | // Check if we need to re-sort the list |
154 | 177 | if( reOrderTimelineFlag ){ |
155 | 178 | // move every node in-order to the end. |
156 | | - smil.getBody().getRefElementsRecurse( sequenceNode, startOffset, function( $node ){ |
| 179 | + smil.getBody().getRefElementsRecurse( smilSequenceTrack, startOffset, function( $node ){ |
157 | 180 | var $timelineClip = $clipTrackSet.find('#' + _this.getTimelineClipId( $node ) ) |
158 | 181 | $timelineClip.appendTo( $clipTrackSet ); |
159 | 182 | }); |
— | — | @@ -160,9 +183,8 @@ |
161 | 184 | $clipTrackSet.children().each(function (inx, clip){ |
162 | 185 | $j( clip ).data('indexOrder', inx); |
163 | 186 | }); |
164 | | - } |
| 187 | + } |
165 | 188 | |
166 | | - |
167 | 189 | // Give the track set a width relative to the number of clips |
168 | 190 | $clipTrackSet.css('width', ($clipTrackSet.find( '.timelineClip' ).length + 1) * |
169 | 191 | ( this.timelineThumbSize.width + 12 ) |
— | — | @@ -258,9 +280,9 @@ |
259 | 281 | editClip: function( selectedClip ){ |
260 | 282 | var smil = this.sequencer.getSmil(); |
261 | 283 | // get the smil element for the edit tool: |
262 | | - var smilClip = smil.$dom.find('#' + $j( selectedClip ).data('smilId') ); |
| 284 | + var smilClip = smil.$dom.find( '#' + $j( selectedClip ).data('smilId') ); |
263 | 285 | var toolTarget = this.sequencer.getEditToolTarget(); |
264 | | - this.sequencer.getEditTools().drawClipEditTools( toolTarget, previewTarget, smilClip ); |
| 286 | + this.sequencer.getEditTools().drawClipEditTools( toolTarget, smilClip ); |
265 | 287 | }, |
266 | 288 | |
267 | 289 | /** |
— | — | @@ -285,15 +307,79 @@ |
286 | 308 | }, |
287 | 309 | |
288 | 310 | /** |
289 | | - * handles assets dropped into the timeline |
| 311 | + * Handles assets dropped into the timeline |
| 312 | + * xxx TODO right now hard coded to "AddMedia" but eventually we |
| 313 | + * want to support desktop drag and drop |
290 | 314 | */ |
291 | 315 | handleDropAsset: function( asset ){ |
| 316 | + var _this = this; |
292 | 317 | // Get the newAsset resource object |
293 | 318 | var clipIndex = $j( asset ).index(); |
294 | | - var trackIndex = $j( asset ).parent().data('trackIndex); |
295 | | - this.sequencer.getAddMedia().insertAssetDialog( asset, trackIndex, clipIndex ); |
| 319 | + // Get the trackIndex for target track |
| 320 | + var trackIndex = $j( asset ).parent().data( 'trackIndex' ); |
| 321 | + |
| 322 | + mw.addLoaderDialog( gM( 'mwe-sequencer-loading-asset' ) ); |
| 323 | + |
| 324 | + this.sequencer.getAddMedia().getSmilClipFromAsset( asset, function( smilClip ){ |
| 325 | + $j( asset ).remove(); |
| 326 | + _this.insertSmilClipEdit( smilClip, trackIndex, clipIndex ); |
| 327 | + mw.closeLoaderDialog(); |
| 328 | + }); |
296 | 329 | }, |
297 | 330 | |
| 331 | + /** |
| 332 | + * Insert a smilClip to the smil dom and sequencer and display the edit |
| 333 | + * interface with a 'cancel' insert button |
| 334 | + */ |
| 335 | + insertSmilClipEdit: function( smilClip, trackIndex, clipIndex ){ |
| 336 | + // Handle optional arguments |
| 337 | + if( typeof trackIndex != 'undefined' ){ |
| 338 | + trackIndex = this.getSelectedTrackIndex(); |
| 339 | + } |
| 340 | + var $clipTrackSet = $j( '#' + this.getTrackSetId( trackIndex ) ); |
| 341 | + if( $clipTrackSet.length == 0 ){ |
| 342 | + mw.log( "Error: insertSmilClipEdit could not find track " + trackIndex + " in inteface" ); |
| 343 | + return ; |
| 344 | + } |
| 345 | + |
| 346 | + // Before insert ensure the smilClip has an id: |
| 347 | + this.sequencer.getSmil().getBody().assignIds( $j( smilClip ) ); |
| 348 | + |
| 349 | + // Add the smil resource to the smil track |
| 350 | + var $smilSequenceTrack = $j( this.sequencer.getSmil().getBody().getSeqElements()[ trackIndex ] ); |
| 351 | + if( typeof clipIndex == 'undefined' || clipIndex >= $smilSequenceTrack.children().length ){ |
| 352 | + $smilSequenceTrack.append( |
| 353 | + $j( smilClip ).get(0) |
| 354 | + ) |
| 355 | + } else { |
| 356 | + $smilSequenceTrack.children().eq( clipIndex ).before( |
| 357 | + $j( smilClip ).get(0) |
| 358 | + ) |
| 359 | + } |
| 360 | + |
| 361 | + // Update the dom timeline |
| 362 | + this.drawTimeline(); |
| 363 | + |
| 364 | + // Invalidate / update embedPlayer duration / clip offsets |
| 365 | + this.sequencer.getEmbedPlayer().getDuration( true ); |
| 366 | + |
| 367 | + // Register the insert edit action |
| 368 | + _this.sequencer.getActionsEdit().registerEdit(); |
| 369 | + |
| 370 | + // Select the current clip |
| 371 | + var $timelineClip = $clipTrackSet.find('#' + this.getTimelineClipId( smilClip ) ) |
| 372 | + if( $timelineClip.length == 0 ){ |
| 373 | + mw.log("Error: insertSmilClipEdit: could not find clip: " + this.getTimelineClipId( smilClip ) ); |
| 374 | + } |
| 375 | + this.getTimelineContainer().find( '.selectedClip' ).removeClass( 'selectedClip' ); |
| 376 | + $timelineClip.addClass( 'selectedClip' ); |
| 377 | + // Seek to the added clip |
| 378 | + this.seekToStartOfClip( $timelineClip ); |
| 379 | + |
| 380 | + // Display the edit interface with 'special' cancel button |
| 381 | + this.editClip( $timelineClip ); |
| 382 | + }, |
| 383 | + |
298 | 384 | handleReorder: function ( movedClip ){ |
299 | 385 | var _this = this; |
300 | 386 | var smil = this.sequencer.getSmil(); |
— | — | @@ -340,6 +426,7 @@ |
341 | 427 | // Register the edit state for undo / redo |
342 | 428 | _this.sequencer.getActionsEdit().registerEdit(); |
343 | 429 | }, |
| 430 | + |
344 | 431 | /** |
345 | 432 | * Handle multiple selections based on what clips was just "cliked" |
346 | 433 | */ |
— | — | @@ -351,7 +438,13 @@ |
352 | 439 | |
353 | 440 | |
354 | 441 | // Add the selectedClip class to the clickClip |
355 | | - if( $j( clickClip ).hasClass( 'selectedClip') && $target.find( '.selectedClip' ).length == 1 ){ |
| 442 | + if( $j( clickClip ).hasClass( 'selectedClip') && |
| 443 | + ( |
| 444 | + $target.find( '.selectedClip' ).length == 1 |
| 445 | + || |
| 446 | + keyBindings.ctrlDown |
| 447 | + ) |
| 448 | + ){ |
356 | 449 | $j( clickClip ).removeClass( 'selectedClip' ); |
357 | 450 | }else { |
358 | 451 | $j( clickClip ).addClass( 'selectedClip' ); |
— | — | @@ -367,11 +460,9 @@ |
368 | 461 | } |
369 | 462 | } ); |
370 | 463 | } |
| 464 | + |
371 | 465 | // Seek to the current clip time ( startOffset of current ) |
372 | | - var seekTime = smil.$dom.find('#' + $j( clickClip ).data('smilId') ).data( 'startOffset' ) |
373 | | - embedPlayer.setCurrentTime( seekTime, function(){ |
374 | | - mw.log("handleMultiSelect::seek done") |
375 | | - }); |
| 466 | + this.seekToStartOfClip( clickClip ); |
376 | 467 | |
377 | 468 | // if shift select is down select the in-between clips |
378 | 469 | if( keyBindings.shiftDown ){ |
— | — | @@ -400,6 +491,20 @@ |
401 | 492 | // xxx check if selected clip has changed hide tool edit interface |
402 | 493 | }, |
403 | 494 | |
| 495 | + /** |
| 496 | + * Seek to the start of a given timelineClip |
| 497 | + */ |
| 498 | + seekToStartOfClip: function( timelineClip ){ |
| 499 | + var seekTime = this.sequencer |
| 500 | + .getSmil() |
| 501 | + .$dom.find( '#' + $j( timelineClip ).data('smilId') ) |
| 502 | + .data( 'startOffset' ); |
| 503 | + |
| 504 | + this.sequencer.getEmbedPlayer().setCurrentTime( seekTime, function(){ |
| 505 | + mw.log("handleMultiSelect::seek done") |
| 506 | + }); |
| 507 | + }, |
| 508 | + |
404 | 509 | getTimelineClipId: function( $node ){ |
405 | 510 | return this.sequencer.getSmil().getPageDomId( $node ) + '_timelineClip'; |
406 | 511 | }, |
— | — | @@ -429,7 +534,7 @@ |
430 | 535 | .addClass( 'clipEditLink ui-state-default ui-corner-all' ) |
431 | 536 | .append( |
432 | 537 | $j('<span />') |
433 | | - .addClass( 'ui-icon ui-icon-scissors' ) |
| 538 | + .addClass( 'ui-icon ui-icon-wrench' ) |
434 | 539 | ) |
435 | 540 | .hide() |
436 | 541 | .buttonHover() |
— | — | @@ -453,10 +558,9 @@ |
454 | 559 | ) |
455 | 560 | .hide() |
456 | 561 | .buttonHover() |
457 | | - .click( function(){ |
458 | | - // de-select any other selected clips |
459 | | - _this.getTimelineContainer().removeClass( 'selectedClip' ); |
460 | | - // add the selected clip class to the current: |
| 562 | + .click( function(){ |
| 563 | + // Remove the associated clip: |
| 564 | + _this.getTimelineContainer().removeClass( 'selectedClip' ); |
461 | 565 | $timelineClip.addClass( 'selectedClip' ); |
462 | 566 | _this.removeSelectedClips(); |
463 | 567 | }) |
— | — | @@ -512,44 +616,47 @@ |
513 | 617 | * features to add :: expand collapse, hide, mute etc. |
514 | 618 | * for now just audio or video with icon |
515 | 619 | */ |
516 | | - getTrackNameInterface: function( trackIndex, sequenceNode, trackType ){ |
517 | | - var $trackNameInterface = |
| 620 | + getTrackNameInterface: function( trackIndex, smilSequenceTrack ){ |
| 621 | + var $trackNameContainer = $j('<div />') |
| 622 | + .attr('id', this.getTrackNameInterfaceId( trackIndex ) ) |
| 623 | + .addClass('trackNames ui-corner-all') |
| 624 | + |
| 625 | + var $trackNameTitle = |
518 | 626 | $j('<a />') |
519 | 627 | .attr('href','#') |
520 | | - .addClass( "ui-icon_link" ); |
521 | | - if( trackType == 'video'){ |
522 | | - $trackNameInterface.append( |
523 | | - $j('<span />').addClass( 'ui-icon ui-icon-video'), |
524 | | - $j('<span />').text( gM( 'mwe-sequencer-video-track' ) ) |
525 | | - ) |
| 628 | + .addClass( "ui-icon_link" ); |
| 629 | + if( $j( smilSequenceTrack).attr('tracktype') == 'audio' ){ |
| 630 | + $trackNameTitle.append( |
| 631 | + $j('<span />').addClass( 'ui-icon ui-icon-volume-on'), |
| 632 | + $j('<span />').text( gM( 'mwe-sequencer-audio-track' ) ) |
| 633 | + ) |
| 634 | + $trackNameContainer.css( 'height' , '30px' ); |
526 | 635 | } else { |
527 | | - $trackNameInterface.append( |
528 | | - $j('<span />').addClass( 'ui-icon ui-icon-volume-on'), |
529 | | - $j('<span />').text( gM( 'mwe-sequencer-audio-track' ) ) |
530 | | - ) |
| 636 | + // for now default to "video" tracktype |
| 637 | + $trackNameTitle.append( |
| 638 | + $j('<span />').addClass( 'ui-icon ui-icon-video'), |
| 639 | + $j('<span />').text( gM( 'mwe-sequencer-video-track' ) ) |
| 640 | + ) |
| 641 | + $trackNameContainer.css( 'height' , '100px' ); |
531 | 642 | } |
| 643 | + // Add the track title as a tool tip |
| 644 | + if ( $j( smilSequenceTrack ).attr('title') ){ |
| 645 | + $trackNameTitle.find('span').attr('title', $j( smilSequenceTrack ).attr('title') ); |
| 646 | + } |
| 647 | + |
| 648 | + $trackNameContainer.append( $trackNameTitle ) |
532 | 649 | // Wrap the track name in a box that matches the trackNames |
533 | | - return $j('<div />') |
534 | | - .attr('id', this.sequencer.getId() + '_trackName_' + trackIndex) |
535 | | - .addClass('trackNames ui-corner-all') |
536 | | - .append( |
537 | | - $trackNameInterface |
538 | | - ) |
| 650 | + return |
539 | 651 | }, |
540 | | - |
541 | | - getSequenceTrackTitle: function( sequenceNode ){ |
542 | | - if( $j( sequenceNode).attr('title') ){ |
543 | | - return $j( sequenceNode).attr('title'); |
544 | | - } |
545 | | - // Else return an empty string ( for now ) |
546 | | - return '' |
| 652 | + getTrackNameInterfaceId: function(trackIndex ){ |
| 653 | + return this.sequencer.getId() + '_trackName_' + trackIndex; |
547 | 654 | }, |
548 | 655 | |
549 | | - getSequenceTrackId: function( index, sequenceNode ){ |
550 | | - if( ! $j( sequenceNode ).data('id') ){ |
551 | | - $j( sequenceNode ).data('id', this.sequencer.getId() + '_sequenceTrack_' + index ); |
| 656 | + getSequenceTrackId: function( index, smilSequenceTrack ){ |
| 657 | + if( ! $j( smilSequenceTrack ).data('id') ){ |
| 658 | + $j( smilSequenceTrack ).data('id', this.sequencer.getId() + '_sequenceTrack_' + index ); |
552 | 659 | } |
553 | | - return $j( sequenceNode ).data('id'); |
| 660 | + return $j( smilSequenceTrack ).data('id'); |
554 | 661 | } |
555 | 662 | } |
556 | 663 | |
Index: branches/MwEmbedStandAlone/libraries/jquery/jquery.ui/ui/ui.draggable.js |
— | — | @@ -580,8 +580,11 @@ |
581 | 581 | t.css("cursor", o.cursor); |
582 | 582 | }, |
583 | 583 | stop: function(event, ui) { |
584 | | - var o = $(this).data('draggable').options; |
585 | | - if (o._cursor) $('body').css("cursor", o._cursor); |
| 584 | + // ensure draggable data options exist |
| 585 | + if( $(this).data('draggable') ){ |
| 586 | + var o = $(this).data('draggable').options; |
| 587 | + if (o._cursor) $('body').css("cursor", o._cursor); |
| 588 | + } |
586 | 589 | } |
587 | 590 | }); |
588 | 591 | |