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