OLD | NEW |
1 // Copyright 2014 The Chromium Authors. All rights reserved. | 1 // Copyright 2014 The Chromium Authors. All rights reserved. |
2 // Use of this source code is governed by a BSD-style license that can be | 2 // Use of this source code is governed by a BSD-style license that can be |
3 // found in the LICENSE file. | 3 // found in the LICENSE file. |
4 | 4 |
5 (function() { | 5 (function() { |
6 'use strict'; | 6 'use strict'; |
7 | 7 |
8 /** | 8 /** |
9 * @constructor | 9 * @constructor |
10 * @extends {PolymerElement} | 10 * @extends {PolymerElement} |
11 */ | 11 */ |
12 var TrackListElement = function() {}; | 12 var TrackListElement = function() {}; |
13 | 13 |
14 TrackListElement.prototype = { | 14 TrackListElement.prototype = { |
| 15 is: 'track-list', |
| 16 |
| 17 properties: { |
| 18 /** |
| 19 * List of tracks. |
| 20 * @type {Array<AudioPlayer.TrackInfo>} |
| 21 */ |
| 22 tracks: { |
| 23 type: Array, |
| 24 value: [], |
| 25 observer: 'tracksChanged' |
| 26 }, |
| 27 |
| 28 /** |
| 29 * Track index of the current track. |
| 30 * If the tracks property is empty, it should be -1. Otherwise, be a valid |
| 31 * track number. |
| 32 */ |
| 33 currentTrackIndex: { |
| 34 type: Number, |
| 35 value: -1, |
| 36 observer: 'currentTrackIndexChanged', |
| 37 notify: true |
| 38 }, |
| 39 |
| 40 /** |
| 41 * Whether shuffling play order is enabled or not. |
| 42 */ |
| 43 shuffle: { |
| 44 type: Boolean, |
| 45 value: false, |
| 46 observer: 'shuffleChanged' |
| 47 } |
| 48 }, |
| 49 |
15 /** | 50 /** |
16 * Initializes an element. This method is called automatically when the | 51 * Initializes an element. This method is called automatically when the |
17 * element is ready. | 52 * element is ready. |
18 */ | 53 */ |
19 ready: function() { | 54 ready: function() { |
20 this.observeTrackList(); | 55 this.observeTrackList(); |
21 | 56 |
22 window.addEventListener('resize', this.onWindowResize_.bind(this)); | 57 window.addEventListener('resize', this.onWindowResize_.bind(this)); |
23 }, | 58 }, |
24 | 59 |
25 observeTrackList: function() { | 60 observeTrackList: function() { |
26 // Unobserve the previous track list. | 61 // Unobserve the previous track list. |
27 if (this.unobserveTrackList_) | 62 if (this.unobserveTrackList_) |
28 this.unobserveTrackList_(); | 63 this.unobserveTrackList_(); |
29 | 64 |
30 // Observe the new track list. | 65 // Observe the new track list. |
31 var observer = this.tracksValueChanged_.bind(this); | 66 var observer = this.tracksValueChanged_.bind(this); |
32 Array.observe(this.tracks, observer); | 67 Array.observe(this.tracks, observer); |
33 | 68 |
34 // Set the function to unobserve it. | 69 // Set the function to unobserve it. |
35 this.unobserveTrackList_ = function(tracks, observer) { | 70 this.unobserveTrackList_ = function(tracks, observer) { |
36 Array.unobserve(tracks, observer); | 71 Array.unobserve(tracks, observer); |
37 }.bind(null, this.tracks, observer); | 72 }.bind(null, this.tracks, observer); |
38 }, | 73 }, |
39 | 74 |
40 /** | 75 /** |
41 * Registers handlers for changing of external variables | |
42 */ | |
43 observe: { | |
44 'model.shuffle': 'onShuffleChanged', | |
45 }, | |
46 | |
47 /** | |
48 * Model object of the Audio Player. | |
49 * @type {AudioPlayerModel} | |
50 */ | |
51 model: null, | |
52 | |
53 /** | |
54 * List of tracks. | |
55 * @type {Array<AudioPlayer.TrackInfo>} | |
56 */ | |
57 tracks: [], | |
58 | |
59 /** | |
60 * Play order of the tracks. Each value is the index of 'this.tracks'. | 76 * Play order of the tracks. Each value is the index of 'this.tracks'. |
61 * @type {Array<number>} | 77 * @type {Array<number>} |
62 */ | 78 */ |
63 playOrder: [], | 79 playOrder: [], |
64 | 80 |
65 /** | 81 /** |
66 * Track index of the current track. | 82 * Invoked when 'shuffle' property is changed. |
67 * If the tracks property is empty, it should be -1. Otherwise, be a valid | 83 * @param {boolean} newValue New value. |
68 * track number. | 84 * @param {boolean} oldValue Old value. |
69 * | |
70 * @type {number} | |
71 */ | 85 */ |
72 currentTrackIndex: -1, | 86 shuffleChanged: function(newValue, oldValue) { |
73 | |
74 /** | |
75 * Invoked when 'shuffle' property is changed. | |
76 * @param {boolean} oldValue Old value. | |
77 * @param {boolean} newValue New value. | |
78 */ | |
79 onShuffleChanged: function(oldValue, newValue) { | |
80 this.generatePlayOrder(true /* keep the current track */); | 87 this.generatePlayOrder(true /* keep the current track */); |
81 }, | 88 }, |
82 | 89 |
83 /** | 90 /** |
84 * Invoked when the current track index is changed. | 91 * Invoked when the current track index is changed. |
| 92 * @param {number} newValue new value. |
85 * @param {number} oldValue old value. | 93 * @param {number} oldValue old value. |
86 * @param {number} newValue new value. | |
87 */ | 94 */ |
88 currentTrackIndexChanged: function(oldValue, newValue) { | 95 currentTrackIndexChanged: function(newValue, oldValue) { |
89 if (oldValue === newValue) | 96 if (oldValue === newValue) |
90 return; | 97 return; |
91 | 98 |
92 if (!isNaN(oldValue) && 0 <= oldValue && oldValue < this.tracks.length) | 99 if (!isNaN(oldValue) && 0 <= oldValue && oldValue < this.tracks.length) |
93 this.tracks[oldValue].active = false; | 100 this.set('tracks.' + oldValue + '.active', false); |
94 | 101 |
95 if (0 <= newValue && newValue < this.tracks.length) { | 102 if (0 <= newValue && newValue < this.tracks.length) { |
96 var currentPlayOrder = this.playOrder.indexOf(newValue); | 103 var currentPlayOrder = this.playOrder.indexOf(newValue); |
97 if (currentPlayOrder !== -1) { | 104 if (currentPlayOrder !== -1) { |
98 // Success | 105 // Success |
99 this.tracks[newValue].active = true; | 106 this.set('tracks.' + newValue + '.active', true); |
100 | 107 |
101 this.ensureTrackInViewport_(newValue /* trackIndex */); | 108 this.ensureTrackInViewport_(newValue /* trackIndex */); |
102 return; | 109 return; |
103 } | 110 } |
104 } | 111 } |
105 | 112 |
106 // Invalid index | 113 // Invalid index |
107 if (this.tracks.length === 0) | 114 if (this.tracks.length === 0) |
108 this.currentTrackIndex = -1; | 115 this.currentTrackIndex = -1; |
109 else | 116 else |
110 this.generatePlayOrder(false /* no need to keep the current track */); | 117 this.generatePlayOrder(false /* no need to keep the current track */); |
111 }, | 118 }, |
112 | 119 |
113 /** | 120 /** |
114 * Invoked when 'tracks' property is changed. | 121 * Invoked when 'tracks' property is changed. |
| 122 * @param {Array<AudioPlayer.TrackInfo>} newValue New value. |
115 * @param {Array<AudioPlayer.TrackInfo>} oldValue Old value. | 123 * @param {Array<AudioPlayer.TrackInfo>} oldValue Old value. |
116 * @param {Array<AudioPlayer.TrackInfo>} newValue New value. | |
117 */ | 124 */ |
118 tracksChanged: function(oldValue, newValue) { | 125 tracksChanged: function(newValue, oldValue) { |
119 // Note: Sometimes both oldValue and newValue are null though the actual | 126 // Note: Sometimes both oldValue and newValue are null though the actual |
120 // values are not null. Maybe it's a bug of Polymer. | 127 // values are not null. Maybe it's a bug of Polymer. |
121 | 128 |
122 // Re-register the observer of 'this.tracks'. | 129 // Re-register the observer of 'this.tracks'. |
123 this.observeTrackList(); | 130 this.observeTrackList(); |
124 | 131 |
125 if (this.tracks.length !== 0) { | 132 if (this.tracks.length !== 0) { |
126 // Restore the active track. | 133 // Restore the active track. |
127 if (this.currentTrackIndex !== -1 && | 134 if (this.currentTrackIndex !== -1 && |
128 this.currentTrackIndex < this.tracks.length) { | 135 this.currentTrackIndex < this.tracks.length) { |
129 this.tracks[this.currentTrackIndex].active = true; | 136 this.set('tracks.' + this.currentTrackIndex + '.active', true); |
130 } | 137 } |
131 | 138 |
132 // Reset play order and current index. | 139 // Reset play order and current index. |
133 this.generatePlayOrder(false /* no need to keep the current track */); | 140 this.generatePlayOrder(false /* no need to keep the current track */); |
134 } else { | 141 } else { |
135 this.playOrder = []; | 142 this.playOrder = []; |
136 this.currentTrackIndex = -1; | 143 this.currentTrackIndex = -1; |
137 } | 144 } |
138 }, | 145 }, |
139 | 146 |
140 /** | 147 /** |
141 * Invoked when the value in the 'tracks' is changed. | 148 * Invoked when the value in the 'tracks' is changed. |
142 * @param {Array<Object>} changes The detail of the change. | 149 * @param {Array<Object>} changes The detail of the change. |
143 */ | 150 */ |
144 tracksValueChanged_: function(changes) { | 151 tracksValueChanged_: function(changes) { |
145 if (this.tracks.length === 0) | 152 if (this.tracks.length === 0) |
146 this.currentTrackIndex = -1; | 153 this.currentTrackIndex = -1; |
147 else | 154 else |
148 this.tracks[this.currentTrackIndex].active = true; | 155 this.set('tracks.' + this.currentTrackIndex + '.active', true); |
149 }, | 156 }, |
150 | 157 |
151 /** | 158 /** |
152 * Invoked when the track element is clicked. | 159 * Invoked when the track element is clicked. |
153 * @param {Event} event Click event. | 160 * @param {Event} event Click event. |
154 */ | 161 */ |
155 trackClicked: function(event) { | 162 trackClicked: function(event) { |
156 var index = ~~event.currentTarget.getAttribute('index'); | 163 var index = ~~event.currentTarget.getAttribute('index'); |
157 var track = this.tracks[index]; | 164 var track = this.tracks[index]; |
158 if (track) | 165 if (track) |
(...skipping 46 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
205 if (this.tracks.length === 0) { | 212 if (this.tracks.length === 0) { |
206 this.playOrder = []; | 213 this.playOrder = []; |
207 return; | 214 return; |
208 } | 215 } |
209 | 216 |
210 // Creates sequenced array. | 217 // Creates sequenced array. |
211 this.playOrder = | 218 this.playOrder = |
212 this.tracks. | 219 this.tracks. |
213 map(function(unused, index) { return index; }); | 220 map(function(unused, index) { return index; }); |
214 | 221 |
215 if (this.model && this.model.shuffle) { | 222 if (this.shuffle) { |
216 // Randomizes the play order array (Schwarzian-transform algorithm). | 223 // Randomizes the play order array (Schwarzian-transform algorithm). |
217 this.playOrder = this.playOrder | 224 this.playOrder = this.playOrder |
218 .map(function(a) { | 225 .map(function(a) { |
219 return {weight: Math.random(), index: a}; | 226 return {weight: Math.random(), index: a}; |
220 }) | 227 }) |
221 .sort(function(a, b) { return a.weight - b.weight }) | 228 .sort(function(a, b) { return a.weight - b.weight }) |
222 .map(function(a) { return a.index }); | 229 .map(function(a) { return a.index }); |
223 | 230 |
224 if (keepCurrentTrack) { | 231 if (keepCurrentTrack) { |
225 // Puts the current track at the beginning of the play order. | 232 // Puts the current track at the beginning of the play order. |
(...skipping 79 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
305 | 312 |
306 var newTrackIndex = this.playOrder[newPlayOrder]; | 313 var newTrackIndex = this.playOrder[newPlayOrder]; |
307 console.assert( | 314 console.assert( |
308 (0 <= newTrackIndex && newTrackIndex < this.tracks.length), | 315 (0 <= newTrackIndex && newTrackIndex < this.tracks.length), |
309 'Insufficient TrackList.playOrder. New Play Order: ' + newPlayOrder); | 316 'Insufficient TrackList.playOrder. New Play Order: ' + newPlayOrder); |
310 | 317 |
311 return newTrackIndex; | 318 return newTrackIndex; |
312 }, | 319 }, |
313 }; // TrackListElement.prototype for 'track-list' | 320 }; // TrackListElement.prototype for 'track-list' |
314 | 321 |
315 Polymer('track-list', TrackListElement.prototype); | 322 Polymer(TrackListElement.prototype); |
316 })(); // Anonymous closure | 323 })(); // Anonymous closure |
OLD | NEW |