1. 1 : /**
  2. 2 : * @file track-list.js
  3. 3 : */
  4. 4 : import EventTarget from '../event-target';
  5. 5 : import {isEvented} from '../mixins/evented';
  6. 6 :
  7. 7 : /**
  8. 8 : * Common functionaliy between {@link TextTrackList}, {@link AudioTrackList}, and
  9. 9 : * {@link VideoTrackList}
  10. 10 : *
  11. 11 : * @extends EventTarget
  12. 12 : */
  13. 13 : class TrackList extends EventTarget {
  14. 14 : /**
  15. 15 : * Create an instance of this class
  16. 16 : *
  17. 17 : * @param {Track[]} tracks
  18. 18 : * A list of tracks to initialize the list with.
  19. 19 : *
  20. 20 : * @abstract
  21. 21 : */
  22. 22 : constructor(tracks = []) {
  23. 23 : super();
  24. 24 :
  25. 25 : this.tracks_ = [];
  26. 26 :
  27. 27 : /**
  28. 28 : * @memberof TrackList
  29. 29 : * @member {number} length
  30. 30 : * The current number of `Track`s in the this Trackist.
  31. 31 : * @instance
  32. 32 : */
  33. 33 : Object.defineProperty(this, 'length', {
  34. 34 : get() {
  35. 35 : return this.tracks_.length;
  36. 36 : }
  37. 37 : });
  38. 38 :
  39. 39 : for (let i = 0; i < tracks.length; i++) {
  40. 40 : this.addTrack(tracks[i]);
  41. 41 : }
  42. 42 : }
  43. 43 :
  44. 44 : /**
  45. 45 : * Add a {@link Track} to the `TrackList`
  46. 46 : *
  47. 47 : * @param {Track} track
  48. 48 : * The audio, video, or text track to add to the list.
  49. 49 : *
  50. 50 : * @fires TrackList#addtrack
  51. 51 : */
  52. 52 : addTrack(track) {
  53. 53 : const index = this.tracks_.length;
  54. 54 :
  55. 55 : if (!('' + index in this)) {
  56. 56 : Object.defineProperty(this, index, {
  57. 57 : get() {
  58. 58 : return this.tracks_[index];
  59. 59 : }
  60. 60 : });
  61. 61 : }
  62. 62 :
  63. 63 : // Do not add duplicate tracks
  64. 64 : if (this.tracks_.indexOf(track) === -1) {
  65. 65 : this.tracks_.push(track);
  66. 66 : /**
  67. 67 : * Triggered when a track is added to a track list.
  68. 68 : *
  69. 69 : * @event TrackList#addtrack
  70. 70 : * @type {EventTarget~Event}
  71. 71 : * @property {Track} track
  72. 72 : * A reference to track that was added.
  73. 73 : */
  74. 74 : this.trigger({
  75. 75 : track,
  76. 76 : type: 'addtrack',
  77. 77 : target: this
  78. 78 : });
  79. 79 : }
  80. 80 :
  81. 81 : /**
  82. 82 : * Triggered when a track label is changed.
  83. 83 : *
  84. 84 : * @event TrackList#addtrack
  85. 85 : * @type {EventTarget~Event}
  86. 86 : * @property {Track} track
  87. 87 : * A reference to track that was added.
  88. 88 : */
  89. 89 : track.labelchange_ = () => {
  90. 90 : this.trigger({
  91. 91 : track,
  92. 92 : type: 'labelchange',
  93. 93 : target: this
  94. 94 : });
  95. 95 : };
  96. 96 :
  97. 97 : if (isEvented(track)) {
  98. 98 : track.addEventListener('labelchange', track.labelchange_);
  99. 99 : }
  100. 100 : }
  101. 101 :
  102. 102 : /**
  103. 103 : * Remove a {@link Track} from the `TrackList`
  104. 104 : *
  105. 105 : * @param {Track} rtrack
  106. 106 : * The audio, video, or text track to remove from the list.
  107. 107 : *
  108. 108 : * @fires TrackList#removetrack
  109. 109 : */
  110. 110 : removeTrack(rtrack) {
  111. 111 : let track;
  112. 112 :
  113. 113 : for (let i = 0, l = this.length; i < l; i++) {
  114. 114 : if (this[i] === rtrack) {
  115. 115 : track = this[i];
  116. 116 : if (track.off) {
  117. 117 : track.off();
  118. 118 : }
  119. 119 :
  120. 120 : this.tracks_.splice(i, 1);
  121. 121 :
  122. 122 : break;
  123. 123 : }
  124. 124 : }
  125. 125 :
  126. 126 : if (!track) {
  127. 127 : return;
  128. 128 : }
  129. 129 :
  130. 130 : /**
  131. 131 : * Triggered when a track is removed from track list.
  132. 132 : *
  133. 133 : * @event TrackList#removetrack
  134. 134 : * @type {EventTarget~Event}
  135. 135 : * @property {Track} track
  136. 136 : * A reference to track that was removed.
  137. 137 : */
  138. 138 : this.trigger({
  139. 139 : track,
  140. 140 : type: 'removetrack',
  141. 141 : target: this
  142. 142 : });
  143. 143 : }
  144. 144 :
  145. 145 : /**
  146. 146 : * Get a Track from the TrackList by a tracks id
  147. 147 : *
  148. 148 : * @param {string} id - the id of the track to get
  149. 149 : * @method getTrackById
  150. 150 : * @return {Track}
  151. 151 : * @private
  152. 152 : */
  153. 153 : getTrackById(id) {
  154. 154 : let result = null;
  155. 155 :
  156. 156 : for (let i = 0, l = this.length; i < l; i++) {
  157. 157 : const track = this[i];
  158. 158 :
  159. 159 : if (track.id === id) {
  160. 160 : result = track;
  161. 161 : break;
  162. 162 : }
  163. 163 : }
  164. 164 :
  165. 165 : return result;
  166. 166 : }
  167. 167 : }
  168. 168 :
  169. 169 : /**
  170. 170 : * Triggered when a different track is selected/enabled.
  171. 171 : *
  172. 172 : * @event TrackList#change
  173. 173 : * @type {EventTarget~Event}
  174. 174 : */
  175. 175 :
  176. 176 : /**
  177. 177 : * Events that can be called with on + eventName. See {@link EventHandler}.
  178. 178 : *
  179. 179 : * @property {Object} TrackList#allowedEvents_
  180. 180 : * @private
  181. 181 : */
  182. 182 : TrackList.prototype.allowedEvents_ = {
  183. 183 : change: 'change',
  184. 184 : addtrack: 'addtrack',
  185. 185 : removetrack: 'removetrack',
  186. 186 : labelchange: 'labelchange'
  187. 187 : };
  188. 188 :
  189. 189 : // emulate attribute EventHandler support to allow for feature detection
  190. 190 : for (const event in TrackList.prototype.allowedEvents_) {
  191. 191 : TrackList.prototype['on' + event] = null;
  192. 192 : }
  193. 193 :
  194. 194 : export default TrackList;