@oat-sa/tao-core-ui 1.5.4 → 1.6.3

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (43) hide show
  1. package/dist/ckeditor/ckConfigurator.js +9 -1
  2. package/dist/mediaEditor/mediaEditorComponent.js +5 -3
  3. package/dist/mediaEditor/plugins/mediaDimension/mediaDimensionComponent.js +46 -25
  4. package/dist/mediaplayer/css/player.css +104 -14
  5. package/dist/mediaplayer/css/player.css.map +1 -1
  6. package/dist/mediaplayer/players/html5.js +767 -0
  7. package/dist/mediaplayer/players/youtube.js +470 -0
  8. package/dist/mediaplayer/players.js +35 -0
  9. package/dist/mediaplayer/support.js +134 -0
  10. package/dist/mediaplayer/utils/reminder.js +198 -0
  11. package/dist/mediaplayer/utils/timeObserver.js +149 -0
  12. package/dist/mediaplayer/youtubeManager.js +177 -0
  13. package/dist/mediaplayer.js +1251 -1912
  14. package/dist/previewer.js +25 -19
  15. package/package.json +1 -1
  16. package/scss/basic.scss +1 -0
  17. package/scss/inc/_jquery.nouislider.scss +254 -0
  18. package/src/ckeditor/ckConfigurator.js +10 -1
  19. package/src/itemButtonList/css/item-button-list.css +225 -0
  20. package/src/itemButtonList/css/item-button-list.css.map +1 -0
  21. package/src/mediaEditor/mediaEditorComponent.js +25 -26
  22. package/src/mediaEditor/plugins/mediaDimension/mediaDimensionComponent.js +83 -63
  23. package/src/mediaplayer/css/player.css +104 -14
  24. package/src/mediaplayer/css/player.css.map +1 -1
  25. package/src/mediaplayer/players/html5.js +564 -0
  26. package/src/mediaplayer/players/youtube.js +323 -0
  27. package/src/mediaplayer/players.js +29 -0
  28. package/src/mediaplayer/scss/player.scss +125 -16
  29. package/src/mediaplayer/support.js +126 -0
  30. package/src/mediaplayer/tpl/audio.tpl +6 -0
  31. package/src/mediaplayer/tpl/player.tpl +11 -32
  32. package/src/mediaplayer/tpl/source.tpl +1 -0
  33. package/src/mediaplayer/tpl/video.tpl +6 -0
  34. package/src/mediaplayer/tpl/youtube.tpl +1 -0
  35. package/src/mediaplayer/utils/reminder.js +184 -0
  36. package/src/mediaplayer/utils/timeObserver.js +143 -0
  37. package/src/mediaplayer/youtubeManager.js +161 -0
  38. package/src/mediaplayer.js +1217 -1901
  39. package/src/previewer.js +40 -33
  40. package/src/searchModal/css/advancedSearch.css +190 -0
  41. package/src/searchModal/css/advancedSearch.css.map +1 -0
  42. package/src/searchModal/css/searchModal.css +506 -0
  43. package/src/searchModal/css/searchModal.css.map +1 -0
@@ -1,4 +1,4 @@
1
- define(['jquery', 'lodash', 'async', 'util/urlParser', 'core/eventifier', 'core/mimetype', 'core/store', 'handlebars', 'i18n', 'lib/dompurify/purify', 'css!ui/mediaplayer/css/player.css', 'nouislider'], function ($$1, _, async, UrlParser, eventifier, mimetype, store, Handlebars, __, DOMPurify, player_css, nouislider) { 'use strict';
1
+ define(['jquery', 'lodash', 'async', 'util/urlParser', 'core/eventifier', 'core/mimetype', 'core/store', 'ui/mediaplayer/support', 'ui/mediaplayer/players', 'handlebars', 'i18n', 'lib/dompurify/purify', 'css!ui/mediaplayer/css/player.css', 'nouislider'], function ($$1, _, async, UrlParser, eventifier, mimetype, store, support, players, Handlebars, __, DOMPurify, player_css, nouislider) { 'use strict';
2
2
 
3
3
  $$1 = $$1 && $$1.hasOwnProperty('default') ? $$1['default'] : $$1;
4
4
  _ = _ && _.hasOwnProperty('default') ? _['default'] : _;
@@ -7,6 +7,8 @@ define(['jquery', 'lodash', 'async', 'util/urlParser', 'core/eventifier', 'core/
7
7
  eventifier = eventifier && eventifier.hasOwnProperty('default') ? eventifier['default'] : eventifier;
8
8
  mimetype = mimetype && mimetype.hasOwnProperty('default') ? mimetype['default'] : mimetype;
9
9
  store = store && store.hasOwnProperty('default') ? store['default'] : store;
10
+ support = support && support.hasOwnProperty('default') ? support['default'] : support;
11
+ players = players && players.hasOwnProperty('default') ? players['default'] : players;
10
12
  Handlebars = Handlebars && Handlebars.hasOwnProperty('default') ? Handlebars['default'] : Handlebars;
11
13
  __ = __ && __.hasOwnProperty('default') ? __['default'] : __;
12
14
  DOMPurify = DOMPurify && DOMPurify.hasOwnProperty('default') ? DOMPurify['default'] : DOMPurify;
@@ -125,146 +127,36 @@ define(['jquery', 'lodash', 'async', 'util/urlParser', 'core/eventifier', 'core/
125
127
  var Template = Handlebars.template(function (Handlebars,depth0,helpers,partials,data) {
126
128
  this.compilerInfo = [4,'>= 1.0.0'];
127
129
  helpers = this.merge(helpers, Handlebars.helpers); data = data || {};
128
- var buffer = "", stack1, helper, options, functionType="function", escapeExpression=this.escapeExpression, self=this, helperMissing=helpers.helperMissing;
129
-
130
- function program1(depth0,data) {
131
-
132
- var buffer = "", stack1;
133
- buffer += "\n ";
134
- stack1 = helpers['if'].call(depth0, ((stack1 = (depth0 && depth0.is)),stack1 == null || stack1 === false ? stack1 : stack1.youtube), {hash:{},inverse:self.program(5, program5, data),fn:self.program(2, program2, data),data:data});
135
- if(stack1 || stack1 === 0) { buffer += stack1; }
136
- buffer += "\n ";
137
- return buffer;
138
- }
139
- function program2(depth0,data) {
140
-
141
- var buffer = "", stack1;
142
- buffer += "\n ";
143
- stack1 = helpers.each.call(depth0, (depth0 && depth0.sources), {hash:{},inverse:self.noop,fn:self.program(3, program3, data),data:data});
144
- if(stack1 || stack1 === 0) { buffer += stack1; }
145
- buffer += "\n ";
146
- return buffer;
147
- }
148
- function program3(depth0,data) {
149
-
150
- var buffer = "", stack1, helper;
151
- buffer += "\n <div class=\"media video youtube\" data-video-src=\"";
152
- if (helper = helpers.src) { stack1 = helper.call(depth0, {hash:{},data:data}); }
153
- else { helper = (depth0 && depth0.src); stack1 = typeof helper === functionType ? helper.call(depth0, {hash:{},data:data}) : helper; }
154
- buffer += escapeExpression(stack1)
155
- + "\" data-video-id=\"";
156
- if (helper = helpers.id) { stack1 = helper.call(depth0, {hash:{},data:data}); }
157
- else { helper = (depth0 && depth0.id); stack1 = typeof helper === functionType ? helper.call(depth0, {hash:{},data:data}) : helper; }
158
- buffer += escapeExpression(stack1)
159
- + "\" data-type=\"youtube\"></div>\n ";
160
- return buffer;
161
- }
162
-
163
- function program5(depth0,data) {
164
-
165
- var buffer = "", stack1, helper, options;
166
- buffer += "\n <video class=\"media video\" poster=\"";
167
- if (helper = helpers.poster) { stack1 = helper.call(depth0, {hash:{},data:data}); }
168
- else { helper = (depth0 && depth0.poster); stack1 = typeof helper === functionType ? helper.call(depth0, {hash:{},data:data}) : helper; }
169
- buffer += escapeExpression(stack1)
170
- + "\" controls ";
171
- stack1 = helpers['if'].call(depth0, ((stack1 = (depth0 && depth0.is)),stack1 == null || stack1 === false ? stack1 : stack1.cors), {hash:{},inverse:self.noop,fn:self.program(6, program6, data),data:data});
172
- if(stack1 || stack1 === 0) { buffer += stack1; }
173
- buffer += ">\n ";
174
- stack1 = helpers.each.call(depth0, (depth0 && depth0.sources), {hash:{},inverse:self.noop,fn:self.program(8, program8, data),data:data});
175
- if(stack1 || stack1 === 0) { buffer += stack1; }
176
- buffer += "\n\n "
177
- + escapeExpression((helper = helpers.__ || (depth0 && depth0.__),options={hash:{},data:data},helper ? helper.call(depth0, "Your browser doesn’t support the video player.", options) : helperMissing.call(depth0, "__", "Your browser doesn’t support the video player.", options)))
178
- + "\n ";
179
- stack1 = helpers['if'].call(depth0, (depth0 && depth0.link), {hash:{},inverse:self.noop,fn:self.program(10, program10, data),data:data});
180
- if(stack1 || stack1 === 0) { buffer += stack1; }
181
- buffer += "\n </video>\n ";
182
- return buffer;
183
- }
184
- function program6(depth0,data) {
185
-
186
-
187
- return "crossorigin";
188
- }
189
-
190
- function program8(depth0,data) {
191
-
192
- var buffer = "", stack1, helper;
193
- buffer += "\n <source src=\"";
194
- if (helper = helpers.src) { stack1 = helper.call(depth0, {hash:{},data:data}); }
195
- else { helper = (depth0 && depth0.src); stack1 = typeof helper === functionType ? helper.call(depth0, {hash:{},data:data}) : helper; }
196
- buffer += escapeExpression(stack1)
197
- + "\" type=\"";
198
- if (helper = helpers.type) { stack1 = helper.call(depth0, {hash:{},data:data}); }
199
- else { helper = (depth0 && depth0.type); stack1 = typeof helper === functionType ? helper.call(depth0, {hash:{},data:data}) : helper; }
200
- buffer += escapeExpression(stack1)
201
- + "\">\n ";
202
- return buffer;
203
- }
204
-
205
- function program10(depth0,data) {
206
-
207
- var buffer = "", stack1, helper, options;
208
- buffer += "\n <a href=\"";
209
- if (helper = helpers.link) { stack1 = helper.call(depth0, {hash:{},data:data}); }
210
- else { helper = (depth0 && depth0.link); stack1 = typeof helper === functionType ? helper.call(depth0, {hash:{},data:data}) : helper; }
211
- buffer += escapeExpression(stack1)
212
- + "\">"
213
- + escapeExpression((helper = helpers.__ || (depth0 && depth0.__),options={hash:{},data:data},helper ? helper.call(depth0, "Please download the video and view offline.", options) : helperMissing.call(depth0, "__", "Please download the video and view offline.", options)))
214
- + "</a>\n ";
215
- return buffer;
216
- }
130
+ var buffer = "", stack1, helper, options, functionType="function", escapeExpression=this.escapeExpression, helperMissing=helpers.helperMissing;
217
131
 
218
- function program12(depth0,data) {
219
-
220
- var buffer = "", stack1, helper, options;
221
- buffer += "\n <audio class=\"media audio\" controls ";
222
- stack1 = helpers['if'].call(depth0, ((stack1 = (depth0 && depth0.is)),stack1 == null || stack1 === false ? stack1 : stack1.cors), {hash:{},inverse:self.noop,fn:self.program(6, program6, data),data:data});
223
- if(stack1 || stack1 === 0) { buffer += stack1; }
224
- buffer += ">\n ";
225
- stack1 = helpers.each.call(depth0, (depth0 && depth0.sources), {hash:{},inverse:self.noop,fn:self.program(8, program8, data),data:data});
226
- if(stack1 || stack1 === 0) { buffer += stack1; }
227
- buffer += "\n\n "
228
- + escapeExpression((helper = helpers.__ || (depth0 && depth0.__),options={hash:{},data:data},helper ? helper.call(depth0, "Your browser doesn’t support the audio player.", options) : helperMissing.call(depth0, "__", "Your browser doesn’t support the audio player.", options)))
229
- + "\n ";
230
- stack1 = helpers['if'].call(depth0, (depth0 && depth0.link), {hash:{},inverse:self.noop,fn:self.program(13, program13, data),data:data});
231
- if(stack1 || stack1 === 0) { buffer += stack1; }
232
- buffer += "\n </audio>\n ";
233
- return buffer;
234
- }
235
- function program13(depth0,data) {
236
-
237
- var buffer = "", stack1, helper, options;
238
- buffer += "\n <a href=\"";
239
- if (helper = helpers.link) { stack1 = helper.call(depth0, {hash:{},data:data}); }
240
- else { helper = (depth0 && depth0.link); stack1 = typeof helper === functionType ? helper.call(depth0, {hash:{},data:data}) : helper; }
241
- buffer += escapeExpression(stack1)
242
- + "\">"
243
- + escapeExpression((helper = helpers.__ || (depth0 && depth0.__),options={hash:{},data:data},helper ? helper.call(depth0, "Please download the track and listen offline.", options) : helperMissing.call(depth0, "__", "Please download the track and listen offline.", options)))
244
- + "</a>\n ";
245
- return buffer;
246
- }
247
132
 
248
133
  buffer += "<div class=\"mediaplayer ";
249
134
  if (helper = helpers.type) { stack1 = helper.call(depth0, {hash:{},data:data}); }
250
135
  else { helper = (depth0 && depth0.type); stack1 = typeof helper === functionType ? helper.call(depth0, {hash:{},data:data}) : helper; }
251
136
  buffer += escapeExpression(stack1)
252
- + "\">\n <div class=\"player\">\n ";
253
- stack1 = helpers['if'].call(depth0, ((stack1 = (depth0 && depth0.is)),stack1 == null || stack1 === false ? stack1 : stack1.video), {hash:{},inverse:self.program(12, program12, data),fn:self.program(1, program1, data),data:data});
254
- if(stack1 || stack1 === 0) { buffer += stack1; }
255
- buffer += "\n <div class=\"overlay\">\n <a class=\"action play\" data-control=\"play\"><span class=\"icon icon-play\" title=\""
137
+ + "\">\n <div class=\"player\">\n <div class=\"player-overlay\">\n <a class=\"action play\" data-control=\"play\"><span class=\"icon icon-play\" title=\""
256
138
  + escapeExpression((helper = helpers.__ || (depth0 && depth0.__),options={hash:{},data:data},helper ? helper.call(depth0, "Play", options) : helperMissing.call(depth0, "__", "Play", options)))
257
139
  + "\"></span></a>\n <a class=\"action play\" data-control=\"pause\"><span class=\"icon icon-pause\" title=\""
258
140
  + escapeExpression((helper = helpers.__ || (depth0 && depth0.__),options={hash:{},data:data},helper ? helper.call(depth0, "Pause", options) : helperMissing.call(depth0, "__", "Pause", options)))
259
- + "\"></span></a>\n </div>\n </div>\n <div class=\"controls\">\n <div class=\"bar\">\n <div class=\"control actions playback\">\n <a class=\"action play\" data-control=\"play\" title=\""
141
+ + "\"></span></a>\n <a class=\"action reload\" data-control=\"start\">\n <span class=\"icon icon-play\" title=\""
142
+ + escapeExpression((helper = helpers.__ || (depth0 && depth0.__),options={hash:{},data:data},helper ? helper.call(depth0, "Start", options) : helperMissing.call(depth0, "__", "Start", options)))
143
+ + "\"></span>\n <div class=\"message\">"
144
+ + escapeExpression((helper = helpers.__ || (depth0 && depth0.__),options={hash:{},data:data},helper ? helper.call(depth0, "Click to start", options) : helperMissing.call(depth0, "__", "Click to start", options)))
145
+ + "</div>\n </a>\n <a class=\"action reload\" data-control=\"reload\">\n <div class=\"icon icon-reload\" title=\""
146
+ + escapeExpression((helper = helpers.__ || (depth0 && depth0.__),options={hash:{},data:data},helper ? helper.call(depth0, "Reload", options) : helperMissing.call(depth0, "__", "Reload", options)))
147
+ + "\"></div>\n <div class=\"message\">"
148
+ + escapeExpression((helper = helpers.__ || (depth0 && depth0.__),options={hash:{},data:data},helper ? helper.call(depth0, "You are encountering a prolonged connectivity loss.", options) : helperMissing.call(depth0, "__", "You are encountering a prolonged connectivity loss.", options)))
149
+ + " "
150
+ + escapeExpression((helper = helpers.__ || (depth0 && depth0.__),options={hash:{},data:data},helper ? helper.call(depth0, "Click to reload.", options) : helperMissing.call(depth0, "__", "Click to reload.", options)))
151
+ + "</div>\n </a>\n </div>\n </div>\n <div class=\"controls\">\n <div class=\"bar\">\n <div class=\"control actions playback\">\n <a class=\"action play\" data-control=\"play\" title=\""
260
152
  + escapeExpression((helper = helpers.__ || (depth0 && depth0.__),options={hash:{},data:data},helper ? helper.call(depth0, "Play", options) : helperMissing.call(depth0, "__", "Play", options)))
261
153
  + "\"><span class=\"icon icon-play\"></span></a>\n <a class=\"action play\" data-control=\"pause\" title=\""
262
154
  + escapeExpression((helper = helpers.__ || (depth0 && depth0.__),options={hash:{},data:data},helper ? helper.call(depth0, "Pause", options) : helperMissing.call(depth0, "__", "Pause", options)))
263
155
  + "\"><span class=\"icon icon-pause\"></span></a>\n </div>\n <div class=\"control seek\"><div class=\"slider\"></div></div>\n <div class=\"control infos timer\">\n <span class=\"info time\" data-control=\"time-cur\" title=\""
264
156
  + escapeExpression((helper = helpers.__ || (depth0 && depth0.__),options={hash:{},data:data},helper ? helper.call(depth0, "Current playback position", options) : helperMissing.call(depth0, "__", "Current playback position", options)))
265
- + "\">00:00</span>\n <span class=\"info time\" data-control=\"time-end\" title=\""
157
+ + "\">--:--</span>\n <span class=\"info time\" data-control=\"time-end\" title=\""
266
158
  + escapeExpression((helper = helpers.__ || (depth0 && depth0.__),options={hash:{},data:data},helper ? helper.call(depth0, "Total duration", options) : helperMissing.call(depth0, "__", "Total duration", options)))
267
- + "\">00:00</span>\n </div>\n <div class=\"control actions sound\">\n <div class=\"volume\"><div class=\"slider\"></div></div>\n <a class=\"action mute\" data-control=\"mute\" title=\""
159
+ + "\">--:--</span>\n </div>\n <div class=\"control actions sound\">\n <div class=\"volume\"><div class=\"slider\"></div></div>\n <a class=\"action mute\" data-control=\"mute\" title=\""
268
160
  + escapeExpression((helper = helpers.__ || (depth0 && depth0.__),options={hash:{},data:data},helper ? helper.call(depth0, "Mute", options) : helperMissing.call(depth0, "__", "Mute", options)))
269
161
  + "\"><span class=\"icon icon-sound\"></span></a>\n <a class=\"action mute\" data-control=\"unmute\" title=\""
270
162
  + escapeExpression((helper = helpers.__ || (depth0 && depth0.__),options={hash:{},data:data},helper ? helper.call(depth0, "Restore sound", options) : helperMissing.call(depth0, "__", "Restore sound", options)))
@@ -293,151 +185,88 @@ define(['jquery', 'lodash', 'async', 'util/urlParser', 'core/eventifier', 'core/
293
185
  * along with this program; if not, write to the Free Software
294
186
  * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
295
187
  *
296
- * Copyright (c) 2015 (original work) Open Assessment Technologies SA ;
188
+ * Copyright (c) 2015-2021 (original work) Open Assessment Technologies SA ;
297
189
  */
298
190
  /**
299
191
  * CSS namespace
300
192
  * @type {String}
301
- * @private
302
- */
303
-
304
- var _ns = '.mediaplayer';
305
- /**
306
- * A Regex to extract ID from Youtube URLs
307
- * @type {RegExp}
308
- * @private
309
193
  */
310
194
 
311
- var _reYoutube = /([?&\/]v[=\/])([\w-]+)([&\/]?)/;
312
- /**
313
- * A Regex to detect Apple mobile browsers
314
- * @type {RegExp}
315
- * @private
316
- */
317
-
318
- var _reAppleMobiles = /ip(hone|od)/i;
319
- /**
320
- * Array slice method needed to slice arguments
321
- * @type {Function}
322
- * @private
323
- */
324
-
325
- var _slice = [].slice;
195
+ var ns = '.mediaplayer';
326
196
  /**
327
197
  * Minimum value of the volume
328
198
  * @type {Number}
329
- * @private
330
199
  */
331
200
 
332
- var _volumeMin = 0;
201
+ var volumeMin = 0;
333
202
  /**
334
203
  * Maximum value of the volume
335
204
  * @type {Number}
336
- * @private
337
- */
338
-
339
- var _volumeMax = 100;
340
- /**
341
- * Range value of the volume
342
- * @type {Number}
343
- * @private
344
205
  */
345
206
 
346
- var _volumeRange = _volumeMax - _volumeMin;
207
+ var volumeMax = 100;
347
208
  /**
348
- * Threshold (minium requires space above the player) to display the volume
209
+ * Threshold (minimum required space above the player) to display the volume
349
210
  * above the bar.
350
211
  * @type {Number}
351
212
  */
352
213
 
353
-
354
214
  var volumePositionThreshold = 200;
355
215
  /**
356
216
  * Some default values
357
217
  * @type {Object}
358
- * @private
359
218
  */
360
219
 
361
- var _defaults = {
220
+ var defaults = {
362
221
  type: 'video/mp4',
363
222
  video: {
364
- width: 480,
365
- height: 270,
366
- minWidth: 200,
367
- minHeight: 200
223
+ width: '100%',
224
+ height: 'auto'
368
225
  },
369
226
  audio: {
370
- width: 400,
371
- height: 30,
372
- minWidth: 200,
373
- minHeight: 36
227
+ width: '100%',
228
+ height: 'auto'
229
+ },
230
+ youtube: {
231
+ width: 640,
232
+ height: 360
374
233
  },
375
234
  options: {
376
- volume: Math.floor(_volumeRange * 0.8),
235
+ volume: 80,
377
236
  startMuted: false,
378
237
  maxPlays: 0,
379
238
  replayTimeout: 0,
380
239
  canPause: true,
381
240
  canSeek: true,
382
241
  loop: false,
383
- autoStart: false
242
+ autoStart: false,
243
+ preview: true,
244
+ debug: false
384
245
  }
385
246
  };
386
- /**
387
- * A list of MIME types with codec declaration
388
- * @type {Object}
389
- * @private
390
- */
391
-
392
- var _mimeTypes = {
393
- // video
394
- 'video/webm': 'video/webm; codecs="vp8, vorbis"',
395
- 'video/mp4': 'video/mp4; codecs="avc1.42E01E, mp4a.40.2"',
396
- 'video/ogg': 'video/ogg; codecs="theora, vorbis"',
397
- // audio
398
- 'audio/mpeg': 'audio/mpeg;',
399
- 'audio/mp4': 'audio/mp4; codecs="mp4a.40.5"',
400
- 'audio/ogg': 'audio/ogg; codecs="vorbis"',
401
- 'audio/wav': 'audio/wav; codecs="1"'
402
- };
403
- /**
404
- * Extracts the ID of a Youtube video from an URL
405
- * @param {String} url
406
- * @returns {String}
407
- * @private
408
- */
409
-
410
- var _extractYoutubeId = function _extractYoutubeId(url) {
411
- var res = _reYoutube.exec(url);
412
-
413
- return res && res[2] || url;
414
- };
415
247
  /**
416
248
  * Ensures a value is a number
417
249
  * @param {Number|String} value
418
250
  * @returns {Number}
419
- * @private
420
251
  */
421
252
 
422
-
423
- var _ensureNumber = function _ensureNumber(value) {
424
- value = parseFloat(value);
425
- return isFinite(value) ? value : 0;
253
+ var ensureNumber = function ensureNumber(value) {
254
+ var floatValue = parseFloat(value);
255
+ return isFinite(floatValue) ? floatValue : 0;
426
256
  };
427
257
  /**
428
258
  * Format a number to string with leading zeros
429
259
  * @param {Number} n
430
260
  * @param {Number} len
431
261
  * @returns {String}
432
- * @private
433
262
  */
434
263
 
435
264
 
436
- var _leadingZero = function _leadingZero(n, len) {
265
+ var leadingZero = function leadingZero(n, len) {
437
266
  var value = n.toString();
438
267
 
439
268
  while (value.length < len) {
440
- value = '0' + value;
269
+ value = "0".concat(value);
441
270
  }
442
271
 
443
272
  return value;
@@ -446,11 +275,10 @@ define(['jquery', 'lodash', 'async', 'util/urlParser', 'core/eventifier', 'core/
446
275
  * Formats a time value to string
447
276
  * @param {Number} time
448
277
  * @returns {String}
449
- * @private
450
278
  */
451
279
 
452
280
 
453
- var _timerFormat = function _timerFormat(time) {
281
+ var timerFormat = function timerFormat(time) {
454
282
  var seconds = Math.floor(time % 60);
455
283
  var minutes = Math.floor(time / 60) % 60;
456
284
  var hours = Math.floor(time / 3600);
@@ -460,30 +288,28 @@ define(['jquery', 'lodash', 'async', 'util/urlParser', 'core/eventifier', 'core/
460
288
  parts.push(hours);
461
289
  }
462
290
 
463
- parts.push(_leadingZero(minutes, 2));
464
- parts.push(_leadingZero(seconds, 2));
291
+ parts.push(leadingZero(minutes, 2));
292
+ parts.push(leadingZero(seconds, 2));
465
293
  return parts.join(':');
466
294
  };
467
295
  /**
468
296
  * Checks if a type needs to be adjusted
469
297
  * @param {String} type
470
298
  * @returns {Boolean}
471
- * @private
472
299
  */
473
300
 
474
301
 
475
- var _needTypeAdjust = function _needTypeAdjust(type) {
302
+ var needTypeAdjust = function needTypeAdjust(type) {
476
303
  return 'string' === typeof type && type.indexOf('application') === 0;
477
304
  };
478
305
  /**
479
306
  * Adjust bad type by apllying heuristic on URI
480
307
  * @param {Object|String} source
481
308
  * @returns {String}
482
- * @private
483
309
  */
484
310
 
485
311
 
486
- var _getAdjustedType = function _getAdjustedType(source) {
312
+ var getAdjustedType = function getAdjustedType(source) {
487
313
  var type = 'video/ogg';
488
314
  var url = source && source.src || source;
489
315
  var ext = url && url.substr(-4);
@@ -498,11 +324,10 @@ define(['jquery', 'lodash', 'async', 'util/urlParser', 'core/eventifier', 'core/
498
324
  * Extract a list of media sources from a config object
499
325
  * @param {Object} config
500
326
  * @returns {Array}
501
- * @private
502
327
  */
503
328
 
504
329
 
505
- var _configToSources = function _configToSources(config) {
330
+ var configToSources = function configToSources(config) {
506
331
  var sources = config.sources || [];
507
332
  var url = config.url;
508
333
 
@@ -522,1973 +347,1495 @@ define(['jquery', 'lodash', 'async', 'util/urlParser', 'core/eventifier', 'core/
522
347
  };
523
348
  /**
524
349
  * Checks if the browser can play media
525
- * @param {HTMLMediaElement} media The media element on which check support
526
- * @param {String} [mimeType] An optional MIME type to precise the support
350
+ * @param {String} sizeProps Width or Height
527
351
  * @returns {Boolean}
528
- * @private
529
352
  */
530
353
 
531
354
 
532
- var _checkSupport = function _checkSupport(media, mimeType) {
533
- var support = !!media.canPlayType;
534
-
535
- if (mimeType && support) {
536
- support = !!media.canPlayType(_mimeTypes[mimeType] || mimeType).replace(/no/, '');
537
- }
538
-
539
- return support;
355
+ var isResponsiveSize = function isResponsiveSize(sizeProps) {
356
+ return /%/.test(sizeProps) || sizeProps === 'auto';
540
357
  };
541
358
  /**
542
- * Support dection
543
- * @type {Object}
544
- * @private
359
+ * Builds a media player instance
360
+ * @param {Object} config
361
+ * @param {String} config.type - The type of media to play, say `audio`, `video`, or `youtube`. The default is `video`.
362
+ * It might also contain the MIME type of the media as a shorthand.
363
+ * @param {String|Array} [config.url] - The URL to the media. If several media are proposed as alternatives,
364
+ * please look at the `sources` option instead.
365
+ * @param {String} [config.mimeType] - The MIME type of the media. If omitted, the player will try to extract it
366
+ * from the `type` property, otherwise it will request the server to get the content-type.
367
+ * @param {Array} [config.sources] - A list of URL if several media can be proposed. Each entry may be either a
368
+ * string (single URL), or an object containing both the URL and the MIME type ({src: string, type: string}).
369
+ * @param {String|jQuery|HTMLElement} [config.renderTo] - An optional container in which renders the player
370
+ * @param {Boolean} [config.canSeek] - The player allows to reach an arbitrary position within the media using the duration bar
371
+ * @param {Boolean} [config.loop] - The media will be played continuously
372
+ * @param {Boolean} [config.canPause] - The player can be paused
373
+ * @param {Boolean} [config.startMuted] - The player should be initially muted
374
+ * @param {Boolean} [config.autoStart] - The player starts as soon as it is displayed
375
+ * @param {Number} [config.autoStartAt] - The time position at which the player should start
376
+ * @param {Number} [config.maxPlays] - Sets a few number of plays (default: infinite)
377
+ * @param {Number} [config.replayTimeout] - disable the possibility to replay a media after this timeout, in seconds (default: 0)
378
+ * @param {Number} [config.volume] - Sets the sound volume (default: 80)
379
+ * @param {Number} [config.width] - Sets the width of the player (default: depends on media type)
380
+ * @param {Number} [config.height] - Sets the height of the player (default: depends on media type)
381
+ * @param {Boolean} [config.preview] - Enables the media preview (load media metadata)
382
+ * @param {Boolean} [config.debug] - Enables the debug mode
383
+ * @param {number} [config.config.stalledDetectionDelay] - The delay before considering a media is stalled
384
+ * @event render - Event triggered when the player is rendering
385
+ * @event error - Event triggered when the player throws an unrecoverable error
386
+ * @event ready - Event triggered when the player is fully ready
387
+ * @event play - Event triggered when the playback is starting
388
+ * @event update - Event triggered while the player is playing
389
+ * @event pause - Event triggered when the playback is paused
390
+ * @event ended - Event triggered when the playback is ended
391
+ * @event limitreached - Event triggered when the play limit has been reached
392
+ * @event destroy - Event triggered when the player is destroying
393
+ * @returns {mediaplayer}
545
394
  */
546
395
 
547
396
 
548
- var _support = {
397
+ function mediaplayerFactory(config) {
549
398
  /**
550
- * Checks if the browser can play video and audio
551
- * @param {String} [type] The type of media (audio or video)
552
- * @param {String} [mime] A media MIME type to check
553
- * @returns {Boolean}
399
+ * Defines a media player object
400
+ * @type {Object}
554
401
  */
555
- canPlay: function canPlay(type, mime) {
556
- if (type) {
557
- switch (type.toLowerCase()) {
558
- case 'audio':
559
- return this.canPlayAudio(mime);
560
-
561
- case 'youtube':
562
- case 'video':
563
- return this.canPlayVideo(mime);
564
-
565
- default:
566
- return false;
567
- }
568
- }
402
+ var mediaplayer = {
403
+ /**
404
+ * Initializes the media player
405
+ * @param {Object} config
406
+ * @returns {mediaplayer}
407
+ */
408
+ init: function init(config) {
409
+ var _this = this;
569
410
 
570
- return this.canPlayAudio() && this.canPlayVideo();
571
- },
411
+ // load the config set, discard null values in order to allow defaults to be set
412
+ this.config = _.omit(config || {}, function (value) {
413
+ return typeof value === 'undefined' || value === null;
414
+ });
572
415
 
573
- /**
574
- * Checks if the browser can play audio
575
- * @param {String} [mime] A media MIME type to check
576
- * @returns {Boolean}
577
- */
578
- canPlayAudio: function canPlayAudio(mime) {
579
- if (!this._mediaAudio) {
580
- this._mediaAudio = document.createElement('audio');
581
- }
416
+ _.defaults(this.config, defaults.options);
582
417
 
583
- return _checkSupport(this._mediaAudio, mime);
584
- },
418
+ if (!this.config.mimeType && 'string' === typeof this.config.type && this.config.type.indexOf('/') > 0) {
419
+ this.config.mimeType = this.config.type;
420
+ }
585
421
 
586
- /**
587
- * Checks if the browser can play video
588
- * @param {String} [mime] A media MIME type to check
589
- * @returns {Boolean}
590
- */
591
- canPlayVideo: function canPlayVideo(mime) {
592
- if (!this._mediaVideo) {
593
- this._mediaVideo = document.createElement('video');
594
- }
422
+ this._setType(this.config.type || defaults.type);
595
423
 
596
- return _checkSupport(this._mediaVideo, mime);
597
- },
424
+ this._reset();
598
425
 
599
- /**
600
- * Checks if the browser allows to control the media playback
601
- * @returns {Boolean}
602
- */
603
- canControl: function canControl() {
604
- return !_reAppleMobiles.test(navigator.userAgent);
605
- }
606
- };
607
- /**
608
- * A local manager for Youtube players.
609
- * Relies on https://developers.google.com/youtube/iframe_api_reference
610
- * @type {Object}
611
- * @private
612
- */
426
+ this._updateVolumeFromStore();
613
427
 
614
- var _youtubeManager = {
615
- /**
616
- * The Youtube API injection state
617
- * @type {Boolean}
618
- */
619
- injected: false,
428
+ this._initEvents();
620
429
 
621
- /**
622
- * The Youtube API ready state
623
- * @type {Boolean}
624
- */
625
- ready: false,
430
+ this._initSources(function () {
431
+ if (!_this.is('youtube')) {
432
+ _.forEach(_this.config.sources, function (source) {
433
+ if (source && source.type && source.type.indexOf('audio') === 0) {
434
+ _this._setType(source.type);
626
435
 
627
- /**
628
- * A list of pending players
629
- * @type {Array}
630
- */
631
- pending: [],
436
+ _this._initType();
632
437
 
633
- /**
634
- * Add a Youtube player
635
- * @param {String|jQuery|HTMLElement} elem
636
- * @param {Object} player
637
- * @param {Object} [options]
638
- * @param {Boolean} [options.controls]
639
- */
640
- add: function add(elem, player, options) {
641
- if (this.ready) {
642
- this.create(elem, player, options);
643
- } else {
644
- this.pending.push([elem, player, options]);
438
+ return false;
439
+ }
440
+ });
441
+ }
645
442
 
646
- if (!this.injected) {
647
- this.injectApi();
648
- }
649
- }
650
- },
443
+ if (_this.config.renderTo) {
444
+ _.defer(function () {
445
+ return _this.render();
446
+ });
447
+ }
448
+ });
651
449
 
652
- /**
653
- * Removes a pending Youtube player
654
- * @param {String|jQuery|HTMLElement} elem
655
- * @param {Object} player
656
- */
657
- remove: function remove(elem, player) {
658
- var pending = this.pending;
450
+ return this;
451
+ },
452
+
453
+ /**
454
+ * Uninstalls the media player
455
+ * @returns {mediaplayer}
456
+ */
457
+ destroy: function destroy() {
458
+ /**
459
+ * Triggers a destroy event
460
+ * @event mediaplayer#destroy
461
+ */
462
+ this.trigger('destroy');
659
463
 
660
- _.forEach(pending, function (args, idx) {
661
- if (args && elem === args[0] && player === args[1]) {
662
- pending[idx] = null;
464
+ if (this.player) {
465
+ this.player.destroy();
663
466
  }
664
- });
665
- },
666
467
 
667
- /**
668
- * Install a Youtube player. The Youtube API must be ready
669
- * @param {String|jQuery|HTMLElement} elem
670
- * @param {Object} player
671
- * @param {Object} [options]
672
- * @param {Boolean} [options.controls]
673
- */
674
- create: function create(elem, player, options) {
675
- var $elem;
468
+ if (this.$component) {
469
+ this._unbindEvents();
676
470
 
677
- if (!this.ready) {
678
- return this.add(elem, player, options);
679
- }
471
+ this._destroySlider(this.$seekSlider);
680
472
 
681
- if (!options) {
682
- options = {};
683
- }
473
+ this._destroySlider(this.$volumeSlider);
684
474
 
685
- $elem = $$1(elem);
686
- new window.YT.Player($elem.get(0), {
687
- height: $elem.width(),
688
- width: $elem.height(),
689
- videoId: $elem.data('videoId'),
690
- playerVars: {
691
- //hd: true,
692
- autoplay: 0,
693
- controls: options.controls ? 1 : 0,
694
- rel: 0,
695
- showinfo: 0,
696
- wmode: 'transparent',
697
- modestbranding: 1,
698
- disablekb: 1,
699
- playsinline: 1,
700
- enablejsapi: 1,
701
- origin: location.hostname
702
- },
703
- events: {
704
- onReady: player.onReady.bind(player),
705
- onStateChange: player.onStateChange.bind(player)
475
+ this.$component.remove();
706
476
  }
707
- });
708
- },
709
477
 
710
- /**
711
- * Called when the Youtube API is ready. Should install all pending players.
712
- */
713
- apiReady: function apiReady() {
714
- var self = this;
715
- var pending = this.pending;
716
- this.pending = [];
717
- this.ready = true;
718
-
719
- _.forEach(pending, function (args) {
720
- if (args) {
721
- self.create.apply(self, args);
478
+ this._reset();
479
+
480
+ return this;
481
+ },
482
+
483
+ /**
484
+ * Renders the media player according to the media type
485
+ * @param {String|jQuery|HTMLElement} [to]
486
+ * @returns {mediaplayer}
487
+ */
488
+ render: function render(to) {
489
+ var renderTo = to || this.config.renderTo || this.$container;
490
+
491
+ if (this.$component) {
492
+ this.destroy();
722
493
  }
723
- });
724
- },
725
494
 
726
- /**
727
- * Checks if the Youtube API is ready to use
728
- * @returns {Boolean}
729
- */
730
- isApiReady: function isApiReady() {
731
- var apiReady = typeof window.YT !== 'undefined' && typeof window.YT.Player !== 'undefined';
495
+ this._initState();
732
496
 
733
- if (apiReady && !this.ready) {
734
- _youtubeManager.apiReady();
735
- }
497
+ this._buildDom();
736
498
 
737
- return apiReady;
738
- },
499
+ if (this.config.preview) {
500
+ this._updateDuration(0);
739
501
 
740
- /**
741
- * Injects the Youtube API into the page
742
- */
743
- injectApi: function injectApi() {
744
- var self = this;
745
-
746
- if (!self.isApiReady()) {
747
- window.require(['https://www.youtube.com/iframe_api'], function () {
748
- var check = function check() {
749
- if (!self.isApiReady()) {
750
- setTimeout(check, 100);
751
- }
752
- };
502
+ this._updatePosition(0);
503
+ }
753
504
 
754
- check();
755
- });
756
- }
505
+ this._bindEvents();
757
506
 
758
- this.injected = true;
759
- }
760
- };
761
- /**
762
- * Defines a player object dedicated to youtube media
763
- * @param {mediaplayer} mediaplayer
764
- * @private
765
- */
507
+ this._playingState(false, true);
766
508
 
767
- var _youtubePlayer = function _youtubePlayer(mediaplayer) {
768
- var $media;
769
- var media;
770
- var player;
771
- var interval;
772
- var destroyed;
773
- var initWidth, initHeight;
509
+ this._initPlayer();
774
510
 
775
- function loopEvents(callback) {
776
- _.forEach(['onStateChange', 'onPlaybackQualityChange', 'onPlaybackRateChange', 'onError', 'onApiChange'], callback);
777
- }
511
+ this._initSize(); // Resize for old items with defined height to avoid big jump
778
512
 
779
- if (mediaplayer) {
780
- player = {
781
- init: function _youtubePlayerInit() {
782
- $media = mediaplayer.$media;
783
- media = null;
784
- destroyed = false;
785
513
 
786
- if ($media) {
787
- _youtubeManager.add($media, this, {
788
- controls: mediaplayer.is('nogui')
789
- });
790
- }
514
+ if (this.config.height && this.config.height !== 'auto') {
515
+ this.resize('100%', 'auto');
516
+ } else {
517
+ this.resize(this.config.width, this.config.height);
518
+ }
791
519
 
792
- return !!$media;
793
- },
794
- onReady: function _youtubePlayerOnReady(event) {
795
- var callbacks = this._callbacks;
796
- media = event.target;
797
- $media = $$1(media.getIframe());
798
- this._callbacks = null;
520
+ this.config.is.rendered = true;
799
521
 
800
- if (!destroyed) {
522
+ if (renderTo) {
523
+ this.$container = $$1(renderTo).append(this.$component);
524
+ } // add class if it is stalled
801
525
 
802
- if (initWidth && initHeight) {
803
- this.setSize(initWidth, initHeight);
804
- }
805
526
 
806
- mediaplayer._onReady();
527
+ if (this.is('stalled')) {
528
+ this._setState('stalled', true);
529
+ }
530
+ /**
531
+ * Triggers a render event
532
+ * @event mediaplayer#render
533
+ * @param {jQuery} $component
534
+ */
807
535
 
808
- if (callbacks) {
809
- _.forEach(callbacks, function (cb) {
810
- cb();
811
- });
812
- }
813
- } else {
814
- this.destroy();
815
- }
816
- },
817
- onStateChange: function _youtubePlayerOnStateChange(event) {
818
- this.stopPolling();
819
536
 
820
- if (!destroyed) {
821
- switch (event.data) {
822
- // ended
823
- case 0:
824
- mediaplayer._onEnd();
537
+ this.trigger('render', this.$component);
538
+ return this;
539
+ },
825
540
 
826
- break;
827
- // playing
541
+ /**
542
+ * Reloads media player after it was stalled
543
+ */
544
+ reload: function reload() {
545
+ /**
546
+ * Triggers a reload event
547
+ * @event mediaplayer#reload
548
+ */
549
+ this.trigger('reload');
828
550
 
829
- case 1:
830
- mediaplayer._onPlay();
551
+ if (this.player) {
552
+ this.player.recover();
553
+ }
831
554
 
832
- this.startPolling();
833
- break;
834
- // paused
555
+ this._setState('stalled', false);
835
556
 
836
- case 2:
837
- mediaplayer._onPause();
557
+ this.setInitialStates();
558
+ },
838
559
 
839
- break;
840
- }
841
- }
842
- },
843
- stopPolling: function _youtubePlayerStopPolling() {
844
- if (interval) {
845
- clearInterval(interval);
846
- interval = null;
847
- }
848
- },
849
- startPolling: function _youtubePlayerStartPolling() {
850
- interval = setInterval(function () {
851
- mediaplayer._onTimeUpdate();
852
- }, mediaplayerFactory.youtubePolling);
853
- },
854
- destroy: function _youtubePlayerDestroy() {
855
- destroyed = true;
856
-
857
- if (media) {
858
- loopEvents(function (ev) {
859
- media.removeEventListener(ev);
860
- });
861
- media.destroy();
862
- } else {
863
- _youtubeManager.remove($media, this);
864
- }
560
+ /**
561
+ * Set initial states
562
+ */
563
+ setInitialStates: function setInitialStates() {
564
+ if (!this.is('stalled')) {
565
+ this._setState('ready', true);
566
+ }
865
567
 
866
- this.stopPolling();
867
- $media = null;
868
- media = null;
869
- },
870
- getPosition: function _youtubePlayerGetPosition() {
871
- if (media) {
872
- return media.getCurrentTime();
873
- }
568
+ this._setState('canplay', true);
874
569
 
875
- return 0;
876
- },
877
- getDuration: function _youtubePlayerGetDuration() {
878
- if (media) {
879
- return media.getDuration();
880
- }
570
+ this._setState('canpause', this.config.canPause);
881
571
 
882
- return 0;
883
- },
884
- getVolume: function _youtubePlayerGetVolume() {
885
- var value = 0;
572
+ this._setState('canseek', this.config.canSeek);
886
573
 
887
- if (media) {
888
- value = media.getVolume() * _volumeRange / 100 + _volumeMin;
889
- }
574
+ this._setState('loading', false);
575
+ },
890
576
 
891
- return value;
892
- },
893
- setVolume: function _youtubePlayerSetVolume(value) {
894
- if (media) {
895
- media.setVolume((parseFloat(value) - _volumeMin) / _volumeRange * 100);
896
- }
897
- },
898
- setSize: function _youtubePlayerSetSize(width, height) {
899
- if ($media) {
900
- $media.width(width).height(height);
901
- }
577
+ /**
578
+ * Sets the start position inside the media
579
+ * @param {Number} time - The start position in seconds
580
+ * @param {*} [internal] - Internal use
581
+ * @returns {mediaplayer}
582
+ */
583
+ seek: function seek(time, internal) {
584
+ if (this._canPlay()) {
585
+ this._updatePosition(time, internal);
902
586
 
903
- if (media) {
904
- media.setSize(width, height);
905
- } else {
906
- initWidth = width;
907
- initHeight = height;
908
- }
909
- },
910
- seek: function _youtubePlayerSeek(value) {
911
- if (media) {
912
- media.seekTo(parseFloat(value), true);
913
- }
914
- },
915
- play: function _youtubePlayerPlay() {
916
- if (media) {
917
- media.playVideo();
918
- }
919
- },
920
- pause: function _youtubePlayerPause() {
921
- if (media) {
922
- media.pauseVideo();
923
- }
924
- },
925
- stop: function _youtubePlayerStop() {
926
- if (media) {
927
- media.stopVideo();
587
+ this.execute('seek', this.position);
928
588
 
929
- mediaplayer._onEnd();
930
- }
931
- },
932
- mute: function _youtubePlayerMute(state) {
933
- if (media) {
934
- media[state ? 'mute' : 'unMute']();
935
- }
936
- },
937
- isMuted: function _youtubePlayerIsMuted() {
938
- if (media) {
939
- return media.isMuted();
589
+ if (!this.is('ready')) {
590
+ this.autoStartAt = this.position;
940
591
  }
941
592
 
942
- return false;
943
- },
944
- addMedia: function _youtubePlayerSetMedia(url) {
945
- var id = _extractYoutubeId(url);
593
+ this.loop = !!this.config.loop;
594
+ }
946
595
 
947
- var cb = id && function () {
948
- media.cueVideoById(id);
949
- };
596
+ return this;
597
+ },
950
598
 
951
- if (cb) {
952
- if (media) {
953
- cb();
954
- } else {
955
- this._callbacks = this._callbacks || [];
599
+ /**
600
+ * Plays the media
601
+ * @param {Number} [time] - An optional start position in seconds
602
+ * @returns {mediaplayer}
603
+ */
604
+ play: function play(time) {
605
+ if (this._canPlay()) {
606
+ if (typeof time !== 'undefined') {
607
+ this.seek(time);
608
+ }
956
609
 
957
- this._callbacks.push(cb);
958
- }
610
+ this.execute('play');
959
611
 
960
- return true;
612
+ if (!this.is('ready')) {
613
+ this.autoStart = true;
961
614
  }
962
615
 
963
- return false;
964
- },
965
- setMedia: function _youtubePlayerSetMedia(url) {
966
- var id = _extractYoutubeId(url);
616
+ this.loop = !!this.config.loop;
967
617
 
968
- var cb = id && function () {
969
- media.loadVideoById(id);
970
- };
618
+ if (this.timerId) {
619
+ cancelAnimationFrame(this.timerId);
620
+ }
621
+ }
971
622
 
972
- if (cb) {
973
- if (media) {
974
- cb();
975
- } else {
976
- this._callbacks = [cb];
977
- }
623
+ return this;
624
+ },
978
625
 
979
- return true;
626
+ /**
627
+ * Pauses the media
628
+ * @param {Number} [time] - An optional time position in seconds
629
+ * @returns {mediaplayer}
630
+ */
631
+ pause: function pause(time) {
632
+ if (this._canPause()) {
633
+ if (typeof time !== 'undefined') {
634
+ this.seek(time);
980
635
  }
981
636
 
982
- return false;
637
+ this.execute('pause');
638
+
639
+ if (!this.is('ready')) {
640
+ this.autoStart = false;
641
+ }
983
642
  }
984
- };
985
- }
986
643
 
987
- return player;
988
- };
989
- /**
990
- * Defines a player object dedicated to native player
991
- * @param {mediaplayer} mediaplayer
992
- * @private
993
- */
644
+ return this;
645
+ },
994
646
 
647
+ /**
648
+ * Resumes the media
649
+ * @returns {mediaplayer}
650
+ */
651
+ resume: function resume() {
652
+ if (this._canResume()) {
653
+ this.play();
654
+ }
995
655
 
996
- var _nativePlayer = function _nativePlayer(mediaplayer) {
997
- var $media;
998
- var media;
999
- var player;
1000
- var played;
656
+ return this;
657
+ },
1001
658
 
1002
- if (mediaplayer) {
1003
- player = {
1004
- init: function _nativePlayerInit() {
1005
- var result = false;
1006
- var mediaElem;
1007
- $media = mediaplayer.$media;
1008
- media = null;
1009
- played = false;
659
+ /**
660
+ * Stops the playback
661
+ * @returns {mediaplayer}
662
+ */
663
+ stop: function stop() {
664
+ this.loop = false;
665
+ this.execute('stop');
1010
666
 
1011
- if ($media) {
1012
- mediaElem = $media.get(0);
667
+ if (!this.is('ready')) {
668
+ this.autoStart = false;
669
+ }
1013
670
 
1014
- if (mediaElem && mediaElem.canPlayType) {
1015
- media = mediaElem;
1016
- result = true;
1017
- }
671
+ return this;
672
+ },
1018
673
 
1019
- if (!mediaplayer.is('nogui')) {
1020
- $media.removeAttr('controls');
1021
- }
674
+ /**
675
+ * Starts the media
676
+ * @returns {mediaplayer}
677
+ */
678
+ start: function start() {
679
+ this._setState('preview', true);
1022
680
 
1023
- $media.on('play' + _ns, function () {
1024
- played = true;
1025
-
1026
- mediaplayer._onPlay();
1027
- }).on('pause' + _ns, function () {
1028
- mediaplayer._onPause();
1029
- }).on('ended' + _ns, function () {
1030
- played = false;
1031
-
1032
- mediaplayer._onEnd();
1033
- }).on('timeupdate' + _ns, function () {
1034
- mediaplayer._onTimeUpdate();
1035
- }).on('loadstart', function () {
1036
- if (media.networkState === HTMLMediaElement.NETWORK_NO_SOURCE) {
1037
- mediaplayer._onError();
1038
- }
1039
- }).on('error' + _ns, function () {
1040
- if (media.networkState === HTMLMediaElement.NETWORK_NO_SOURCE) {
1041
- mediaplayer._onError();
1042
- } else {
1043
- mediaplayer._onRecoverError(); // recover from playing error
681
+ this._setState('loading', true);
1044
682
 
683
+ this.play();
684
+ },
1045
685
 
1046
- if (media.networkState === HTMLMediaElement.NETWORK_LOADING && mediaplayer.is('playing')) {
1047
- mediaplayer.render();
1048
- }
1049
- }
1050
- }).on('loadedmetadata' + _ns, function () {
1051
- if (mediaplayer.is('error')) {
1052
- mediaplayer._onRecoverError();
1053
- }
686
+ /**
687
+ * Restarts the media from the beginning
688
+ * @returns {mediaplayer}
689
+ */
690
+ restart: function restart() {
691
+ this.play(0);
692
+ return this;
693
+ },
1054
694
 
1055
- mediaplayer._onReady();
1056
- });
1057
- }
695
+ /**
696
+ * Rewind the media to the beginning
697
+ * @returns {mediaplayer}
698
+ */
699
+ rewind: function rewind() {
700
+ this.seek(0);
701
+ return this;
702
+ },
1058
703
 
1059
- return result;
1060
- },
1061
- destroy: function _nativePlayerDestroy() {
1062
- if ($media) {
1063
- $media.off(_ns).attr('controls', '');
1064
- }
704
+ /**
705
+ * Mutes the media
706
+ * @param {Boolean} [state] - A flag to set the mute state (default: true)
707
+ * @returns {mediaplayer}
708
+ */
709
+ mute: function mute(state) {
710
+ if (typeof state === 'undefined') {
711
+ state = true;
712
+ }
1065
713
 
1066
- this.stop();
1067
- $media = null;
1068
- media = null;
1069
- played = false;
1070
- },
1071
- getPosition: function _nativePlayerGetPosition() {
1072
- if (media) {
1073
- return media.currentTime;
1074
- }
714
+ this.execute('mute', state);
1075
715
 
1076
- return 0;
1077
- },
1078
- getDuration: function _nativePlayerGetDuration() {
1079
- if (media) {
1080
- return media.duration;
1081
- }
716
+ this._setState('muted', state);
1082
717
 
1083
- return 0;
1084
- },
1085
- getVolume: function _nativePlayerGetVolume() {
1086
- var value = 0;
718
+ if (!this.is('ready')) {
719
+ this.startMuted = state;
720
+ }
1087
721
 
1088
- if (media) {
1089
- value = parseFloat(media.volume) * _volumeRange + _volumeMin;
1090
- }
722
+ return this;
723
+ },
1091
724
 
1092
- return value;
1093
- },
1094
- setVolume: function _nativePlayerSetVolume(value) {
1095
- if (media) {
1096
- media.volume = (parseFloat(value) - _volumeMin) / _volumeRange;
1097
- }
1098
- },
1099
- setSize: function _nativePlayerSetSize(width, height) {
1100
- if ($media) {
1101
- $media.width(width).height(height);
1102
- }
1103
- },
1104
- seek: function _nativePlayerSeek(value) {
1105
- if (media) {
1106
- media.currentTime = parseFloat(value);
1107
-
1108
- if (!played) {
1109
- this.play();
1110
- }
1111
- }
1112
- },
1113
- play: function _nativePlayerPlay() {
1114
- if (media) {
1115
- media.play();
1116
- }
1117
- },
1118
- pause: function _nativePlayerPause() {
1119
- if (media) {
1120
- media.pause();
1121
- }
1122
- },
1123
- stop: function _nativePlayerStop() {
1124
- if (media && played) {
1125
- media.currentTime = media.duration;
1126
- }
1127
- },
1128
- mute: function _nativePlayerMute(state) {
1129
- if (media) {
1130
- media.muted = !!state;
1131
- }
1132
- },
1133
- isMuted: function _nativePlayerIsMuted() {
1134
- if (media) {
1135
- return !!media.muted;
1136
- }
1137
-
1138
- return false;
1139
- },
1140
- addMedia: function _nativePlayerSetMedia(url, type) {
1141
- type = type || _defaults.type;
1142
-
1143
- if (media) {
1144
- if (!_checkSupport(media, type)) {
1145
- return false;
1146
- }
1147
- }
1148
-
1149
- if (url && $media) {
1150
- $media.append('<source src="' + url + '" type="' + (_mimeTypes[type] || type) + '" />');
1151
- return true;
1152
- }
1153
-
1154
- return false;
1155
- },
1156
- setMedia: function _nativePlayerSetMedia(url, type) {
1157
- if ($media) {
1158
- $media.empty();
1159
- return this.addMedia(url, type);
1160
- }
1161
-
1162
- return false;
1163
- }
1164
- };
1165
- }
1166
-
1167
- return player;
1168
- };
1169
- /**
1170
- * Defines the list of available players
1171
- * @type {Object}
1172
- * @private
1173
- */
1174
-
1175
-
1176
- var _players = {
1177
- audio: _nativePlayer,
1178
- video: _nativePlayer,
1179
- youtube: _youtubePlayer
1180
- };
1181
- /**
1182
- * Defines a media player object
1183
- * @type {Object}
1184
- */
1185
-
1186
- var mediaplayer = {
1187
- /**
1188
- * Initializes the media player
1189
- * @param {Object} config
1190
- * @param {String} config.type - The type of media to play
1191
- * @param {String|Array} config.url - The URL to the media
1192
- * @param {String|jQuery|HTMLElement} [config.renderTo] - An optional container in which renders the player
1193
- * @param {Boolean} [config.loop] - The media will be played continuously
1194
- * @param {Boolean} [config.canPause] - The play can be paused
1195
- * @param {Boolean} [config.canSeek] - The player allows to reach an arbitrary position within the media using the duration bar
1196
- * @param {Boolean} [config.startMuted] - The player should be initially muted
1197
- * @param {Boolean} [config.autoStart] - The player starts as soon as it is displayed
1198
- * @param {Number} [config.autoStartAt] - The time position at which the player should start
1199
- * @param {Number} [config.maxPlays] - Sets a few number of plays (default: infinite)
1200
- * @param {Number} [config.replayTimeout] - disable the possibility to replay a media after this timeout, in seconds (default: 0)
1201
- * @param {Number} [config.volume] - Sets the sound volume (default: 80)
1202
- * @param {Number} [config.width] - Sets the width of the player (default: depends on media type)
1203
- * @param {Number} [config.height] - Sets the height of the player (default: depends on media type)
1204
- * @returns {mediaplayer}
1205
- */
1206
- init: function init(config) {
1207
- var self = this; // load the config set, discard null values in order to allow defaults to be set
1208
-
1209
- this.config = _.omit(config || {}, function (value) {
1210
- return typeof value === 'undefined' || value === null;
1211
- });
725
+ /**
726
+ * Restore the sound of the media after a mute
727
+ * @returns {mediaplayer}
728
+ */
729
+ unmute: function unmute() {
730
+ this.mute(false);
731
+ return this;
732
+ },
1212
733
 
1213
- _.defaults(this.config, _defaults.options);
734
+ /**
735
+ * Sets the sound volume of the media being played
736
+ * @param {Number} value - A value between 0 and 100
737
+ * @param {*} [internal] - Internal use
738
+ * @returns {mediaplayer}
739
+ */
740
+ setVolume: function setVolume(value, internal) {
741
+ this._updateVolume(value, internal);
1214
742
 
1215
- this._setType(this.config.type || _defaults.type);
743
+ this.execute('setVolume', this.volume);
744
+ return this;
745
+ },
1216
746
 
1217
- this._reset();
747
+ /**
748
+ * Gets the sound volume applied to the media being played
749
+ * @returns {Number} Returns a value between 0 and 100
750
+ */
751
+ getVolume: function getVolume() {
752
+ return this.volume;
753
+ },
1218
754
 
1219
- this._updateVolumeFromStore();
755
+ /**
756
+ * Gets the current displayed position inside the media
757
+ * @returns {Number}
758
+ */
759
+ getPosition: function getPosition() {
760
+ return this.position;
761
+ },
1220
762
 
1221
- this._initEvents();
763
+ /**
764
+ * Gets the duration of the media
765
+ * @returns {Number}
766
+ */
767
+ getDuration: function getDuration() {
768
+ return this.duration;
769
+ },
1222
770
 
1223
- this._initSources(function () {
1224
- if (!self.is('youtube')) {
1225
- _.each(self.config.sources, function (source) {
1226
- if (source && source.type && source.type.indexOf('audio') === 0) {
1227
- self._setType(source.type);
771
+ /**
772
+ * Gets the number of times the media has been played
773
+ * @returns {Number}
774
+ */
775
+ getTimesPlayed: function getTimesPlayed() {
776
+ return this.timesPlayed;
777
+ },
1228
778
 
1229
- self._initType();
779
+ /**
780
+ * Gets the type of player
781
+ * @returns {String}
782
+ */
783
+ getType: function getType() {
784
+ return this.type;
785
+ },
1230
786
 
1231
- return false;
1232
- }
1233
- });
1234
- }
787
+ /**
788
+ * Gets the DOM container
789
+ * @returns {jQuery}
790
+ */
791
+ getContainer: function getContainer() {
792
+ if (!this.$container && this.$component) {
793
+ var $container = this.$component.parent();
1235
794
 
1236
- if (self.config.renderTo) {
1237
- _.defer(function () {
1238
- self.render();
1239
- });
795
+ if ($container.length) {
796
+ this.$container = $container;
797
+ }
1240
798
  }
1241
- });
1242
799
 
1243
- return this;
1244
- },
800
+ return this.$container;
801
+ },
1245
802
 
1246
- /**
1247
- * Uninstalls the media player
1248
- * @returns {mediaplayer}
1249
- */
1250
- destroy: function destroy() {
1251
803
  /**
1252
- * Triggers a destroy event
1253
- * @event mediaplayer#destroy
804
+ * Gets the underlying DOM element
805
+ * @returns {jQuery}
1254
806
  */
1255
- this.trigger('destroy');
807
+ getElement: function getElement() {
808
+ return this.$component;
809
+ },
1256
810
 
1257
- if (this.player) {
1258
- this.player.destroy();
1259
- }
811
+ /**
812
+ * Gets the list of media
813
+ * @returns {Array}
814
+ */
815
+ getSources: function getSources() {
816
+ return this.config.sources.slice();
817
+ },
1260
818
 
1261
- if (this.$component) {
1262
- this._unbindEvents();
819
+ /**
820
+ * Sets the media source. If a source has been already set, it will be replaced.
821
+ * @param {String|Object} src - The media URL, or an object containing the source and the type
822
+ * @param {Function} [callback] - A function called to provide the added media source object
823
+ * @returns {mediaplayer}
824
+ */
825
+ setSource: function setSource(src, callback) {
826
+ var _this2 = this;
1263
827
 
1264
- this._destroySlider(this.$seekSlider);
828
+ this._getSource(src, function (source) {
829
+ _this2.config.sources = [source];
1265
830
 
1266
- this._destroySlider(this.$volumeSlider);
831
+ if (_this2.is('rendered')) {
832
+ _this2.player.setMedia(source.src, source.type);
833
+ }
1267
834
 
1268
- this.$component.remove();
1269
- }
835
+ if (callback) {
836
+ callback.call(_this2, source);
837
+ }
838
+ });
1270
839
 
1271
- this._reset();
840
+ return this;
841
+ },
1272
842
 
1273
- return this;
1274
- },
843
+ /**
844
+ * Adds a media source.
845
+ * @param {String|Object} src - The media URL, or an object containing the source and the type
846
+ * @param {Function} [callback] - A function called to provide the added media source object
847
+ * @returns {mediaplayer}
848
+ */
849
+ addSource: function addSource(src, callback) {
850
+ var _this3 = this;
1275
851
 
1276
- /**
1277
- * Renders the media player according to the media type
1278
- * @param {String|jQuery|HTMLElement} [to]
1279
- * @returns {mediaplayer}
1280
- */
1281
- render: function render(to) {
1282
- var renderTo = to || this.config.renderTo || this.$container;
852
+ this._getSource(src, function (source) {
853
+ _this3.config.sources.push(source);
1283
854
 
1284
- if (this.$component) {
1285
- this.destroy();
1286
- }
855
+ if (_this3.is('rendered')) {
856
+ _this3.player.addMedia(source.src, source.type);
857
+ }
1287
858
 
1288
- this._initState();
859
+ if (callback) {
860
+ callback.call(_this3, source);
861
+ }
862
+ });
1289
863
 
1290
- this._buildDom();
864
+ return this;
865
+ },
1291
866
 
1292
- this._updateDuration(0);
867
+ /**
868
+ * Tells if the media is in a particular state
869
+ * @param {String} state
870
+ * @returns {Boolean}
871
+ */
872
+ is: function is(state) {
873
+ return !!this.config.is[state];
874
+ },
1293
875
 
1294
- this._updatePosition(0);
876
+ /**
877
+ * Changes the size of the player
878
+ * @param {Number} width
879
+ * @param {Number} height
880
+ * @returns {mediaplayer}
881
+ */
882
+ resize: function resize(width, height) {
883
+ if (isResponsiveSize(width) && !isResponsiveSize(height) || this.is('youtube')) {
884
+ // responsive width height should be auto
885
+ // for youtube iframe height is limited by ration
886
+ height = 'auto';
887
+ }
1295
888
 
1296
- this._bindEvents();
889
+ this.execute('setSize', width, height);
890
+ return this;
891
+ },
1297
892
 
1298
- this._playingState(false, true);
893
+ /**
894
+ * Enables the media player
895
+ * @returns {mediaplayer}
896
+ */
897
+ enable: function enable() {
898
+ this._fromState('disabled');
1299
899
 
1300
- this._initPlayer();
900
+ return this;
901
+ },
1301
902
 
1302
- this._initSize();
903
+ /**
904
+ * Disables the media player
905
+ * @returns {mediaplayer}
906
+ */
907
+ disable: function disable() {
908
+ this._toState('disabled');
1303
909
 
1304
- this.resize(this.config.width, this.config.height);
1305
- this.config.is.rendered = true;
910
+ this.trigger('disabled');
911
+ return this;
912
+ },
1306
913
 
1307
- if (renderTo) {
1308
- this.$container = $$1(renderTo).append(this.$component);
1309
- }
1310
914
  /**
1311
- * Triggers a render event
1312
- * @event mediaplayer#render
1313
- * @param {jQuery} $component
915
+ * Shows the media player
916
+ * @returns {mediaplayer}
1314
917
  */
918
+ show: function show() {
919
+ this._fromState('hidden');
1315
920
 
921
+ return this;
922
+ },
1316
923
 
1317
- this.trigger('render', this.$component);
1318
- return this;
1319
- },
1320
-
1321
- /**
1322
- * Sets the start position inside the media
1323
- * @param {Number} time - The start position in seconds
1324
- * @param {*} [internal] - Internal use
1325
- * @returns {mediaplayer}
1326
- */
1327
- seek: function seek(time, internal) {
1328
- if (this._canPlay()) {
1329
- this._updatePosition(time, internal);
924
+ /**
925
+ * hides the media player
926
+ * @returns {mediaplayer}
927
+ */
928
+ hide: function hide() {
929
+ this._toState('hidden');
1330
930
 
1331
- this.execute('seek', this.position);
931
+ return this;
932
+ },
1332
933
 
1333
- if (!this.is('ready')) {
1334
- this.autoStartAt = this.position;
934
+ /**
935
+ * get media original size
936
+ * @returns {Object}
937
+ */
938
+ getMediaOriginalSize: function getMediaOriginalSize() {
939
+ if (this.is('youtube')) {
940
+ return defaults.youtube;
1335
941
  }
1336
942
 
1337
- this.loop = !!this.config.loop;
1338
- }
1339
-
1340
- return this;
1341
- },
1342
-
1343
- /**
1344
- * Plays the media
1345
- * @param {Number} [time] - An optional start position in seconds
1346
- * @returns {mediaplayer}
1347
- */
1348
- play: function play(time) {
1349
- if (this._canPlay()) {
1350
- if (typeof time !== 'undefined') {
1351
- this.seek(time);
943
+ if (this.is('video') && this.player) {
944
+ return this.player.getMediaSize();
1352
945
  }
1353
946
 
1354
- this.execute('play');
947
+ return {};
948
+ },
1355
949
 
1356
- if (!this.is('ready')) {
1357
- this.autoStart = true;
950
+ /**
951
+ * Ensures the right media type is set
952
+ * @param {String} type
953
+ * @private
954
+ */
955
+ _setType: function _setType(type) {
956
+ if (type.indexOf('youtube') !== -1) {
957
+ this.type = 'youtube';
958
+ } else if (type.indexOf('audio') === 0) {
959
+ this.type = 'audio';
960
+ } else {
961
+ this.type = 'video';
1358
962
  }
963
+ },
1359
964
 
1360
- this.loop = !!this.config.loop;
965
+ /**
966
+ * Ensures the type is correctly applied
967
+ * @private
968
+ */
969
+ _initType: function _initType() {
970
+ var is = this.config.is;
971
+ is.youtube = 'youtube' === this.type;
972
+ is.video = 'video' === this.type || 'youtube' === this.type;
973
+ is.audio = 'audio' === this.type;
974
+ },
1361
975
 
1362
- if (this.timerId) {
1363
- cancelAnimationFrame(this.timerId);
1364
- }
1365
- }
976
+ /**
977
+ * Gets a source descriptor.
978
+ * @param {String|Object} src - The media URL, or an object containing the source and the type
979
+ * @param {Function} callback - A function called to provide the media source object
980
+ */
981
+ _getSource: function _getSource(src, callback) {
982
+ var _this4 = this;
1366
983
 
1367
- return this;
1368
- },
984
+ var source;
1369
985
 
1370
- /**
1371
- * Pauses the media
1372
- * @param {Number} [time] - An optional time position in seconds
1373
- * @returns {mediaplayer}
1374
- */
1375
- pause: function pause(time) {
1376
- if (this._canPause()) {
1377
- if (typeof time !== 'undefined') {
1378
- this.seek(time);
1379
- }
986
+ var done = function done() {
987
+ if (needTypeAdjust(source.type)) {
988
+ source.type = getAdjustedType(source);
989
+ }
1380
990
 
1381
- this.execute('pause');
991
+ callback.call(_this4, source);
992
+ };
1382
993
 
1383
- if (!this.is('ready')) {
1384
- this.autoStart = false;
994
+ if (_.isString(src)) {
995
+ source = {
996
+ src: src
997
+ };
998
+ } else {
999
+ source = _.clone(src);
1385
1000
  }
1386
- }
1387
-
1388
- return this;
1389
- },
1390
-
1391
- /**
1392
- * Resumes the media
1393
- * @returns {mediaplayer}
1394
- */
1395
- resume: function resume() {
1396
- if (this._canResume()) {
1397
- this.play();
1398
- }
1399
-
1400
- return this;
1401
- },
1402
-
1403
- /**
1404
- * Stops the playback
1405
- * @returns {mediaplayer}
1406
- */
1407
- stop: function stop() {
1408
- this.loop = false;
1409
- this.execute('stop');
1410
-
1411
- if (!this.is('ready')) {
1412
- this.autoStart = false;
1413
- }
1414
-
1415
- return this;
1416
- },
1417
-
1418
- /**
1419
- * Restarts the media from the beginning
1420
- * @returns {mediaplayer}
1421
- */
1422
- restart: function restart() {
1423
- this.play(0);
1424
- return this;
1425
- },
1426
-
1427
- /**
1428
- * Rewind the media to the beginning
1429
- * @returns {mediaplayer}
1430
- */
1431
- rewind: function rewind() {
1432
- this.seek(0);
1433
- return this;
1434
- },
1435
-
1436
- /**
1437
- * Mutes the media
1438
- * @param {Boolean} [state] - A flag to set the mute state (default: true)
1439
- * @returns {mediaplayer}
1440
- */
1441
- mute: function mute(state) {
1442
- if (typeof state === 'undefined') {
1443
- state = true;
1444
- }
1445
-
1446
- this.execute('mute', state);
1447
-
1448
- this._setState('muted', state);
1449
-
1450
- if (!this.is('ready')) {
1451
- this.startMuted = state;
1452
- }
1453
-
1454
- return this;
1455
- },
1456
-
1457
- /**
1458
- * Restore the sound of the media after a mute
1459
- * @returns {mediaplayer}
1460
- */
1461
- unmute: function unmute() {
1462
- this.mute(false);
1463
- return this;
1464
- },
1465
-
1466
- /**
1467
- * Sets the sound volume of the media being played
1468
- * @param {Number} value - A value between 0 and 100
1469
- * @param {*} [internal] - Internal use
1470
- * @returns {mediaplayer}
1471
- */
1472
- setVolume: function setVolume(value, internal) {
1473
- this._updateVolume(value, internal);
1474
-
1475
- this.execute('setVolume', this.volume);
1476
- return this;
1477
- },
1478
-
1479
- /**
1480
- * Gets the sound volume applied to the media being played
1481
- * @returns {Number} Returns a value between 0 and 100
1482
- */
1483
- getVolume: function getVolume() {
1484
- return this.volume;
1485
- },
1486
-
1487
- /**
1488
- * Gets the current displayed position inside the media
1489
- * @returns {Number}
1490
- */
1491
- getPosition: function getPosition() {
1492
- return this.position;
1493
- },
1494
-
1495
- /**
1496
- * Gets the duration of the media
1497
- * @returns {Number}
1498
- */
1499
- getDuration: function getDuration() {
1500
- return this.duration;
1501
- },
1502
-
1503
- /**
1504
- * Gets the number of times the media has been played
1505
- * @returns {Number}
1506
- */
1507
- getTimesPlayed: function getTimesPlayed() {
1508
- return this.timesPlayed;
1509
- },
1510
1001
 
1511
- /**
1512
- * Gets the type of player
1513
- * @returns {String}
1514
- */
1515
- getType: function getType() {
1516
- return this.type;
1517
- },
1518
-
1519
- /**
1520
- * Gets the DOM container
1521
- * @returns {jQuery}
1522
- */
1523
- getContainer: function getContainer() {
1524
- var $container;
1525
-
1526
- if (!this.$container && this.$component) {
1527
- $container = this.$component.parent();
1528
-
1529
- if ($container.length) {
1530
- this.$container = $container;
1002
+ if (!source.type) {
1003
+ if (this.is('youtube')) {
1004
+ source.type = defaults.type;
1005
+ } else if (this.config.mimeType) {
1006
+ source.type = this.config.mimeType;
1007
+ }
1531
1008
  }
1532
- }
1533
-
1534
- return this.$container;
1535
- },
1536
1009
 
1537
- /**
1538
- * Gets the underlying DOM element
1539
- * @returns {jQuery}
1540
- */
1541
- getElement: function getElement() {
1542
- return this.$component;
1543
- },
1544
-
1545
- /**
1546
- * Gets the list of media
1547
- * @returns {Array}
1548
- */
1549
- getSources: function getSources() {
1550
- return this.config.sources.slice();
1551
- },
1552
-
1553
- /**
1554
- * Sets the media source. If a source has been already set, it will be replaced.
1555
- * @param {String|Object} src - The media URL, or an object containing the source and the type
1556
- * @param {Function} [callback] - A function called to provide the added media source object
1557
- * @returns {mediaplayer}
1558
- */
1559
- setSource: function setSource(src, callback) {
1560
- this._getSource(src, function (source) {
1561
- this.config.sources = [source];
1562
-
1563
- if (this.is('rendered')) {
1564
- this.player.setMedia(source.src, source.type);
1565
- }
1010
+ if (!source.type) {
1011
+ mimetype.getResourceType(source.src, function (err, type) {
1012
+ if (err) {
1013
+ type = defaults.type;
1014
+ }
1566
1015
 
1567
- if (callback) {
1568
- callback.call(this, source);
1016
+ source.type = type;
1017
+ done();
1018
+ });
1019
+ } else {
1020
+ done();
1569
1021
  }
1570
- });
1022
+ },
1571
1023
 
1572
- return this;
1573
- },
1024
+ /**
1025
+ * Ensures the sources are correctly set
1026
+ * @param {Function} callback - A function called once all sources have been initialized
1027
+ * @private
1028
+ */
1029
+ _initSources: function _initSources(callback) {
1030
+ var _this5 = this;
1031
+
1032
+ var sources = configToSources(this.config);
1033
+ this.config.sources = [];
1034
+ async.each(sources, function (source, cb) {
1035
+ _this5.addSource(source, function (src) {
1036
+ return cb(null, src);
1037
+ });
1038
+ }, callback);
1039
+ },
1574
1040
 
1575
- /**
1576
- * Adds a media source.
1577
- * @param {String|Object} src - The media URL, or an object containing the source and the type
1578
- * @param {Function} [callback] - A function called to provide the added media source object
1579
- * @returns {mediaplayer}
1580
- */
1581
- addSource: function addSource(src, callback) {
1582
- this._getSource(src, function (source) {
1583
- this.config.sources.push(source);
1041
+ /**
1042
+ * Installs the events manager onto the instance
1043
+ * @private
1044
+ */
1045
+ _initEvents: function _initEvents() {
1046
+ eventifier(this);
1047
+ var triggerEvent = this.trigger;
1584
1048
 
1585
- if (this.is('rendered')) {
1586
- this.player.addMedia(source.src, source.type);
1587
- }
1049
+ this.trigger = function trigger(eventName) {
1050
+ for (var _len = arguments.length, args = new Array(_len > 1 ? _len - 1 : 0), _key = 1; _key < _len; _key++) {
1051
+ args[_key - 1] = arguments[_key];
1052
+ }
1588
1053
 
1589
- if (callback) {
1590
- callback.call(this, source);
1591
- }
1592
- });
1054
+ if (this.$component) {
1055
+ var _this$$component;
1593
1056
 
1594
- return this;
1595
- },
1057
+ (_this$$component = this.$component).trigger.apply(_this$$component, [eventName + ns].concat(args));
1058
+ }
1596
1059
 
1597
- /**
1598
- * Tells if the media is in a particular state
1599
- * @param {String} state
1600
- * @returns {Boolean}
1601
- */
1602
- is: function is(state) {
1603
- return !!this.config.is[state];
1604
- },
1060
+ return triggerEvent.call.apply(triggerEvent, [this, eventName].concat(args));
1061
+ };
1062
+ },
1605
1063
 
1606
- /**
1607
- * Changes the size of the player
1608
- * @param {Number} width
1609
- * @param {Number} height
1610
- * @returns {mediaplayer}
1611
- */
1612
- resize: function resize(width, height) {
1613
- var type = this.is('video') ? 'video' : 'audio';
1614
- var defaults = _defaults[type] || _defaults.video;
1615
- width = Math.max(defaults.minWidth, width);
1616
- height = Math.max(defaults.minHeight, height);
1617
- this.config.width = width;
1618
- this.config.height = height;
1619
-
1620
- if (this.$component) {
1621
- height -= this.$component.outerHeight() - this.$component.height();
1622
- width -= this.$component.outerWidth() - this.$component.width();
1623
- this.$component.width(width).height(height);
1624
-
1625
- if (!this.is('nogui')) {
1626
- height -= this.$controls.outerHeight();
1064
+ /**
1065
+ * Ensures the right size is set according to the media type
1066
+ * @private
1067
+ */
1068
+ _initSize: function _initSize() {
1069
+ var type = this.is('video') ? 'video' : 'audio';
1070
+ var mediaConfig = defaults[type] || defaults.video;
1071
+ this.config.width = this.config.width || mediaConfig.width;
1072
+ this.config.height = this.config.height || mediaConfig.height;
1073
+
1074
+ if (isResponsiveSize(this.config.width) && !isResponsiveSize(this.config.height) || this.is('youtube')) {
1075
+ // responsive width height should be auto
1076
+ // for youtube iframe height is limited by ration
1077
+ this.config.height = 'auto';
1627
1078
  }
1628
- }
1629
-
1630
- this.execute('setSize', width, height);
1631
- return this;
1632
- },
1633
-
1634
- /**
1635
- * Enables the media player
1636
- * @returns {mediaplayer}
1637
- */
1638
- enable: function enable() {
1639
- this._fromState('disabled');
1640
-
1641
- return this;
1642
- },
1079
+ },
1643
1080
 
1644
- /**
1645
- * Disables the media player
1646
- * @returns {mediaplayer}
1647
- */
1648
- disable: function disable() {
1649
- this._toState('disabled');
1650
-
1651
- this.trigger('disabled');
1652
- return this;
1653
- },
1654
-
1655
- /**
1656
- * Shows the media player
1657
- * @returns {mediaplayer}
1658
- */
1659
- show: function show() {
1660
- this._fromState('hidden');
1661
-
1662
- return this;
1663
- },
1081
+ /**
1082
+ * Initializes the right player instance
1083
+ * @private
1084
+ */
1085
+ _initPlayer: function _initPlayer() {
1086
+ var _this6 = this;
1087
+
1088
+ var playerFactory = players[this.type];
1089
+ var error;
1090
+
1091
+ if (support.canPlay(this.type)) {
1092
+ if (_.isFunction(playerFactory)) {
1093
+ var playerConfig = {
1094
+ type: this.getType(),
1095
+ sources: this.getSources(),
1096
+ preview: this.config.preview,
1097
+ debug: this.config.debug,
1098
+ stalledDetectionDelay: this.config.stalledDetectionDelay
1099
+ };
1100
+ this.player = playerFactory(this.$player, playerConfig).on('resize', function (width, height) {
1101
+ if (_this6.$component) {
1102
+ _this6.$component.width(width).height(height);
1103
+ }
1104
+ }).on('ready', function () {
1105
+ return _this6._onReady();
1106
+ }).on('play', function () {
1107
+ return _this6._onPlay();
1108
+ }).on('pause', function () {
1109
+ return _this6._onPause();
1110
+ }).on('timeupdate', function () {
1111
+ return _this6._onTimeUpdate();
1112
+ }).on('stalled', function () {
1113
+ return _this6._onStalled();
1114
+ }).on('playing', function () {
1115
+ return _this6._onPlaying();
1116
+ }).on('end', function () {
1117
+ return _this6._onEnd();
1118
+ }).on('error', function () {
1119
+ return _this6._onError();
1120
+ });
1121
+ }
1664
1122
 
1665
- /**
1666
- * hides the media player
1667
- * @returns {mediaplayer}
1668
- */
1669
- hide: function hide() {
1670
- this._toState('hidden');
1123
+ if (this.player) {
1124
+ error = !this.player.init();
1125
+ } else {
1126
+ error = true;
1127
+ }
1128
+ } else {
1129
+ error = true;
1130
+ }
1671
1131
 
1672
- return this;
1673
- },
1132
+ this._setState('error', error);
1674
1133
 
1675
- /**
1676
- * Ensures the right media type is set
1677
- * @param {String} type
1678
- * @private
1679
- */
1680
- _setType: function _setType(type) {
1681
- if (type.indexOf('youtube') !== -1) {
1682
- this.type = 'youtube';
1683
- } else if (type.indexOf('audio') === 0) {
1684
- this.type = 'audio';
1685
- } else {
1686
- this.type = 'video';
1687
- }
1688
- },
1134
+ this._setState('nogui', !support.canControl());
1689
1135
 
1690
- /**
1691
- * Ensures the type is correctly applied
1692
- * @private
1693
- */
1694
- _initType: function _initType() {
1695
- var is = this.config.is;
1696
- is.youtube = 'youtube' === this.type;
1697
- is.video = 'video' === this.type || 'youtube' === this.type;
1698
- is.audio = 'audio' === this.type;
1699
- },
1136
+ this._setState('preview', this.config.preview);
1700
1137
 
1701
- /**
1702
- * Gets a source descriptor.
1703
- * @param {String|Object} src - The media URL, or an object containing the source and the type
1704
- * @param {Function} callback - A function called to provide the media source object
1705
- */
1706
- _getSource: function _getSource(src, callback) {
1707
- var self = this;
1708
- var source;
1138
+ this._setState('loading', !error);
1709
1139
 
1710
- if (_.isString(src)) {
1711
- source = {
1712
- src: src
1713
- };
1714
- } else {
1715
- source = _.clone(src);
1716
- }
1140
+ if (error) {
1141
+ this._setState('ready', true);
1717
1142
 
1718
- if (this.is('youtube') && !source.type) {
1719
- source.type = _defaults.type;
1720
- }
1721
-
1722
- if (!source.type) {
1723
- mimetype.getResourceType(source.src, function (err, type) {
1724
- if (err) {
1725
- type = _defaults.type;
1726
- }
1727
-
1728
- source.type = type;
1729
- done();
1730
- });
1731
- } else {
1732
- done();
1733
- }
1734
-
1735
- function done() {
1736
- if (_needTypeAdjust(source.type)) {
1737
- source.type = _getAdjustedType(source);
1143
+ this.trigger('ready');
1738
1144
  }
1145
+ },
1739
1146
 
1740
- if (self.is('youtube')) {
1741
- source.id = _extractYoutubeId(source.src);
1147
+ /**
1148
+ * Initializes the player state
1149
+ * @private
1150
+ */
1151
+ _initState: function _initState() {
1152
+ var isCORS = false;
1153
+ var page;
1154
+
1155
+ if (!this.is('youtube')) {
1156
+ page = new UrlParser(window.location);
1157
+ isCORS = _.some(this.config.sources, function (source) {
1158
+ return !page.sameDomain(source.src);
1159
+ });
1742
1160
  }
1743
1161
 
1744
- callback.call(self, source);
1745
- }
1746
- },
1747
-
1748
- /**
1749
- * Ensures the sources are correctly set
1750
- * @param {Function} callback - A function called once all sources have been initialized
1751
- * @private
1752
- */
1753
- _initSources: function _initSources(callback) {
1754
- var self = this;
1755
-
1756
- var sources = _configToSources(this.config);
1162
+ this._setState('cors', isCORS);
1757
1163
 
1758
- this.config.sources = [];
1759
- async.each(sources, function (source, cb) {
1760
- self.addSource(source, function (src) {
1761
- cb(null, src);
1762
- });
1763
- }, callback);
1764
- },
1765
-
1766
- /**
1767
- * Installs the events manager onto the instance
1768
- * @private
1769
- */
1770
- _initEvents: function _initEvents() {
1771
- var triggerEvent;
1772
- eventifier(this);
1773
- triggerEvent = this.trigger;
1164
+ this._setState('ready', false);
1165
+ },
1774
1166
 
1775
- this.trigger = function trigger(eventName) {
1776
- if (this.$component) {
1777
- this.$component.trigger(eventName + _ns, _slice.call(arguments, 1));
1778
- }
1167
+ /**
1168
+ * Resets the internals attributes
1169
+ * @private
1170
+ */
1171
+ _reset: function _reset() {
1172
+ this.config.is = {};
1779
1173
 
1780
- return triggerEvent.apply(this, arguments);
1781
- };
1782
- },
1174
+ this._initType();
1783
1175
 
1784
- /**
1785
- * Ensures the right size is set according to the media type
1786
- * @private
1787
- */
1788
- _initSize: function _initSize() {
1789
- var type = this.is('video') ? 'video' : 'audio';
1790
- var defaults = _defaults[type] || _defaults.video;
1791
- this.config.width = _.parseInt(this.config.width) || defaults.width;
1792
- this.config.height = _.parseInt(this.config.height) || defaults.height;
1793
- },
1176
+ this.$component = null;
1177
+ this.$container = null;
1178
+ this.$player = null;
1179
+ this.$controls = null;
1180
+ this.$seek = null;
1181
+ this.$seekSlider = null;
1182
+ this.$sound = null;
1183
+ this.$volume = null;
1184
+ this.$volumeControl = null;
1185
+ this.$volumeSlider = null;
1186
+ this.$position = null;
1187
+ this.$duration = null;
1188
+ this.player = null;
1189
+ this.duration = 0;
1190
+ this.position = 0;
1191
+ this.timesPlayed = 0;
1192
+ this.volume = this.config.volume;
1193
+ this.autoStart = this.config.autoStart;
1194
+ this.autoStartAt = this.config.autoStartAt;
1195
+ this.startMuted = this.config.startMuted;
1196
+ },
1794
1197
 
1795
- /**
1796
- * Initializes the right player instance
1797
- * @private
1798
- */
1799
- _initPlayer: function _initPlayer() {
1800
- var player = _players[this.type];
1801
- var error;
1198
+ /**
1199
+ * Builds the DOM content
1200
+ * @private
1201
+ */
1202
+ _buildDom: function _buildDom() {
1203
+ var configForTemplate = _.clone(this.config);
1204
+
1205
+ configForTemplate.type = this.type;
1206
+ this.$component = $$1(playerTpl(configForTemplate));
1207
+ this.$player = this.$component.find('.player');
1208
+ this.$controls = this.$component.find('.controls');
1209
+ this.$seek = this.$controls.find('.seek .slider');
1210
+ this.$sound = this.$controls.find('.sound');
1211
+ this.$volumeControl = this.$controls.find('.volume');
1212
+ this.$volume = this.$controls.find('.volume .slider');
1213
+ this.$position = this.$controls.find('[data-control="time-cur"]');
1214
+ this.$duration = this.$controls.find('[data-control="time-end"]');
1215
+ this.$volumeSlider = this._renderSlider(this.$volume, this.volume, volumeMin, volumeMax, true);
1216
+ },
1802
1217
 
1803
- if (_support.canPlay(this.type)) {
1804
- if (_.isFunction(player)) {
1805
- this.player = player(this);
1806
- }
1218
+ /**
1219
+ * Renders a slider onto an element
1220
+ * @param {jQuery} $elt - The element on which renders the slider
1221
+ * @param {Number} [value] - The current value of the slider
1222
+ * @param {Number} [min] - The min value of the slider
1223
+ * @param {Number} [max] - The max value of the slider
1224
+ * @param {Boolean} [vertical] - Tells if the slider must be vertical
1225
+ * @returns {jQuery} - Returns the element
1226
+ * @private
1227
+ */
1228
+ _renderSlider: function _renderSlider($elt, value, min, max, vertical) {
1229
+ var orientation, direction;
1807
1230
 
1808
- if (this.player) {
1809
- error = !this.player.init();
1231
+ if (vertical) {
1232
+ orientation = 'vertical';
1233
+ direction = 'rtl';
1810
1234
  } else {
1811
- error = true;
1235
+ orientation = 'horizontal';
1236
+ direction = 'ltr';
1812
1237
  }
1813
- } else {
1814
- error = true;
1815
- }
1816
-
1817
- this._setState('error', error);
1818
1238
 
1819
- this._setState('nogui', !_support.canControl());
1820
-
1821
- this._setState('loading', true);
1822
- },
1823
-
1824
- /**
1825
- * Initializes the player state
1826
- * @private
1827
- */
1828
- _initState: function _initState() {
1829
- var isCORS = false;
1830
- var page;
1831
-
1832
- if (!this.is('youtube')) {
1833
- page = new UrlParser(window.location);
1834
- isCORS = _.some(this.config.sources, function (source) {
1835
- return !page.sameDomain(source.src);
1239
+ return $elt.noUiSlider({
1240
+ start: ensureNumber(value) || 0,
1241
+ step: 1,
1242
+ connect: 'lower',
1243
+ orientation: orientation,
1244
+ direction: direction,
1245
+ animate: true,
1246
+ range: {
1247
+ min: ensureNumber(min) || 0,
1248
+ max: ensureNumber(max) || 0
1249
+ }
1836
1250
  });
1837
- }
1838
-
1839
- this._setState('cors', isCORS);
1840
-
1841
- this._setState('ready', false);
1842
- },
1843
-
1844
- /**
1845
- * Resets the internals attributes
1846
- * @private
1847
- */
1848
- _reset: function _reset() {
1849
- this.config.is = {};
1850
-
1851
- this._initType();
1852
-
1853
- this.$component = null;
1854
- this.$container = null;
1855
- this.$player = null;
1856
- this.$media = null;
1857
- this.$controls = null;
1858
- this.$seek = null;
1859
- this.$seekSlider = null;
1860
- this.$sound = null;
1861
- this.$volume = null;
1862
- this.$volumeControl = null;
1863
- this.$volumeSlider = null;
1864
- this.$position = null;
1865
- this.$duration = null;
1866
- this.player = null;
1867
- this.duration = 0;
1868
- this.position = 0;
1869
- this.timesPlayed = 0;
1870
- this.volume = this.config.volume;
1871
- this.autoStart = this.config.autoStart;
1872
- this.autoStartAt = this.config.autoStartAt;
1873
- this.startMuted = this.config.startMuted;
1874
- },
1251
+ },
1875
1252
 
1876
- /**
1877
- * Builds the DOM content
1878
- * @private
1879
- */
1880
- _buildDom: function _buildDom() {
1881
- this.$component = $$1(playerTpl(this.config));
1882
- this.$player = this.$component.find('.player');
1883
- this.$media = this.$component.find('.media');
1884
- this.$controls = this.$component.find('.controls');
1885
- this.$seek = this.$controls.find('.seek .slider');
1886
- this.$sound = this.$controls.find('.sound');
1887
- this.$volumeControl = this.$controls.find('.volume');
1888
- this.$volume = this.$controls.find('.volume .slider');
1889
- this.$position = this.$controls.find('[data-control="time-cur"]');
1890
- this.$duration = this.$controls.find('[data-control="time-end"]');
1891
- this.$volumeSlider = this._renderSlider(this.$volume, this.volume, _volumeMin, _volumeMax, true);
1892
- },
1893
-
1894
- /**
1895
- * Renders a slider onto an element
1896
- * @param {jQuery} $elt - The element on which renders the slider
1897
- * @param {Number} [value] - The current value of the slider
1898
- * @param {Number} [min] - The min value of the slider
1899
- * @param {Number} [max] - The max value of the slider
1900
- * @param {Boolean} [vertical] - Tells if the slider must be vertical
1901
- * @returns {jQuery} - Returns the element
1902
- * @private
1903
- */
1904
- _renderSlider: function _renderSlider($elt, value, min, max, vertical) {
1905
- var orientation, direction;
1906
-
1907
- if (vertical) {
1908
- orientation = 'vertical';
1909
- direction = 'rtl';
1910
- } else {
1911
- orientation = 'horizontal';
1912
- direction = 'ltr';
1913
- }
1914
-
1915
- return $elt.noUiSlider({
1916
- start: _ensureNumber(value) || 0,
1917
- step: 1,
1918
- connect: 'lower',
1919
- orientation: orientation,
1920
- direction: direction,
1921
- animate: true,
1922
- range: {
1923
- min: _ensureNumber(min) || 0,
1924
- max: _ensureNumber(max) || 0
1253
+ /**
1254
+ * Destroys a slider bound to an element
1255
+ * @param {jQuery} $elt
1256
+ * @private
1257
+ */
1258
+ _destroySlider: function _destroySlider($elt) {
1259
+ if ($elt) {
1260
+ $elt.get(0).destroy();
1925
1261
  }
1926
- });
1927
- },
1262
+ },
1928
1263
 
1929
- /**
1930
- * Destroys a slider bound to an element
1931
- * @param {jQuery} $elt
1932
- * @private
1933
- */
1934
- _destroySlider: function _destroySlider($elt) {
1935
- if ($elt) {
1936
- $elt.get(0).destroy();
1937
- }
1938
- },
1264
+ /**
1265
+ * Binds events onto the rendered player
1266
+ * @private
1267
+ */
1268
+ _bindEvents: function _bindEvents() {
1269
+ var _this7 = this;
1939
1270
 
1940
- /**
1941
- * Binds events onto the rendered player
1942
- * @private
1943
- */
1944
- _bindEvents: function _bindEvents() {
1945
- var self = this;
1946
- var overing = false;
1947
- this.$component.on('contextmenu' + _ns, function (event) {
1948
- event.preventDefault();
1949
- });
1950
- this.$controls.on('click' + _ns, '.action', function (event) {
1951
- var $target = $$1(event.target);
1952
- var $action = $target.closest('.action');
1953
- var id = $action.data('control');
1271
+ var overing = false;
1272
+ this.$component.on("contextmenu".concat(ns), function (event) {
1273
+ return event.preventDefault();
1274
+ });
1275
+ this.$controls.on("click".concat(ns), '.action', function (event) {
1276
+ var $target = $$1(event.target);
1277
+ var $action = $target.closest('.action');
1278
+ var id = $action.data('control');
1954
1279
 
1955
- if (_.isFunction(self[id])) {
1956
- self[id]();
1957
- }
1958
- });
1959
- this.$player.on('click' + _ns, function () {
1960
- if (self.is('playing')) {
1961
- self.pause();
1962
- } else {
1963
- self.play();
1964
- }
1965
- });
1966
- this.$seek.on('change' + _ns, function (event, value) {
1967
- self.seek(value, true);
1968
- });
1969
- $$1(document).on('updateVolume' + _ns, function (event, value) {
1970
- self.setVolume(value);
1971
- });
1972
- this.$volume.on('change' + _ns, function (event, value) {
1973
- self.unmute();
1974
- $$1(document).trigger('updateVolume' + _ns, value);
1975
- self.setVolume(value, true);
1976
- });
1977
- this.$sound.on('mouseover' + _ns, 'a', function () {
1978
- var position;
1280
+ if (_.isFunction(_this7[id])) {
1281
+ _this7[id]();
1282
+ }
1283
+ });
1284
+ this.$player.on("click".concat(ns), function (event) {
1285
+ var $target = $$1(event.target);
1286
+ var $action = $target.closest('.action'); // if action was clicked
1979
1287
 
1980
- if (!overing && !self.$volumeControl.hasClass('up') && !self.$volumeControl.hasClass('down')) {
1981
- overing = true;
1982
- position = self.$controls[0].getBoundingClientRect();
1288
+ if ($action.length) {
1289
+ var id = $action.data('control');
1983
1290
 
1984
- if (position && position.top && position.top < volumePositionThreshold) {
1985
- self.$volumeControl.addClass('down');
1291
+ if (_.isFunction(_this7[id])) {
1292
+ _this7[id]();
1293
+ }
1986
1294
  } else {
1987
- self.$volumeControl.addClass('up');
1988
- } //close the volume control after 15s
1295
+ // default action is toggle play
1296
+ if (_this7.is('playing')) {
1297
+ _this7.pause();
1298
+ } else {
1299
+ _this7.play();
1300
+ }
1301
+ }
1302
+ });
1303
+ this.$seek.on("change".concat(ns), function (event, value) {
1304
+ _this7.seek(value, true);
1305
+ });
1306
+ $$1(document).on("updateVolume".concat(ns), function (event, value) {
1307
+ _this7.setVolume(value);
1308
+ });
1309
+ this.$volume.on("change".concat(ns), function (event, value) {
1310
+ _this7.unmute();
1989
1311
 
1312
+ $$1(document).trigger("updateVolume".concat(ns), value);
1990
1313
 
1991
- self.overingTimer = _.delay(function () {
1992
- if (self.$volumeControl) {
1993
- self.$volumeControl.removeClass('up down');
1994
- }
1314
+ _this7.setVolume(value, true);
1315
+ });
1316
+ this.$sound.on("mouseover".concat(ns), 'a', function () {
1317
+ var position;
1995
1318
 
1996
- overing = false;
1997
- }, 15000);
1998
- self.$volumeControl.one('mouseleave' + _ns, function () {
1999
- self.$volumeControl.removeClass('up down');
2000
- overing = false;
2001
- });
2002
- }
2003
- });
2004
- },
1319
+ if (!overing && !_this7.$volumeControl.hasClass('up') && !_this7.$volumeControl.hasClass('down')) {
1320
+ overing = true;
1321
+ position = _this7.$controls[0].getBoundingClientRect();
2005
1322
 
2006
- /**
2007
- * Unbinds events from the rendered player
2008
- * @private
2009
- */
2010
- _unbindEvents: function _unbindEvents() {
2011
- this.$component.off(_ns);
2012
- this.$player.off(_ns);
2013
- this.$controls.off(_ns);
2014
- this.$seek.off(_ns);
2015
- this.$volume.off(_ns); //if the volume is opened and the player destroyed,
2016
- //prevent the callback to run
2017
-
2018
- if (this.overingTimer) {
2019
- clearTimeout(this.overingTimer);
2020
- }
1323
+ if (position && position.top && position.top < volumePositionThreshold) {
1324
+ _this7.$volumeControl.addClass('down');
1325
+ } else {
1326
+ _this7.$volumeControl.addClass('up');
1327
+ } //close the volume control after 15s
2021
1328
 
2022
- $$1(document).off(_ns);
2023
- },
2024
1329
 
2025
- /**
2026
- * Updates the volume slider
2027
- * @param {Number} value
2028
- * @private
2029
- */
2030
- _updateVolumeSlider: function _updateVolumeSlider(value) {
2031
- if (this.$volumeSlider) {
2032
- this.$volumeSlider.val(value);
2033
- }
2034
- },
1330
+ _this7.overingTimer = _.delay(function () {
1331
+ if (_this7.$volumeControl) {
1332
+ _this7.$volumeControl.removeClass('up down');
1333
+ }
2035
1334
 
2036
- /**
2037
- * Updates the displayed volume
2038
- * @param {Number} value
2039
- * @param {*} [internal]
2040
- * @private
2041
- */
2042
- _updateVolume: function _updateVolume(value, internal) {
2043
- this.volume = Math.max(_volumeMin, Math.min(_volumeMax, parseFloat(value)));
1335
+ overing = false;
1336
+ }, 15000);
2044
1337
 
2045
- this._storeVolume(this.volume);
1338
+ _this7.$volumeControl.one("mouseleave".concat(ns), function () {
1339
+ _this7.$volumeControl.removeClass('up down');
2046
1340
 
2047
- if (!internal) {
2048
- this._updateVolumeSlider(value);
2049
- }
2050
- },
1341
+ overing = false;
1342
+ });
1343
+ }
1344
+ });
1345
+ },
2051
1346
 
2052
- /**
2053
- * Updates the time slider
2054
- * @param {Number} value
2055
- * @private
2056
- */
2057
- _updatePositionSlider: function _updatePositionSlider(value) {
2058
- if (this.$seekSlider) {
2059
- this.$seekSlider.val(value);
2060
- }
2061
- },
1347
+ /**
1348
+ * Unbinds events from the rendered player
1349
+ * @private
1350
+ */
1351
+ _unbindEvents: function _unbindEvents() {
1352
+ this.$component.off(ns);
1353
+ this.$player.off(ns);
1354
+ this.$controls.off(ns);
1355
+ this.$seek.off(ns);
1356
+ this.$volume.off(ns); //if the volume is opened and the player destroyed,
1357
+ //prevent the callback to run
1358
+
1359
+ if (this.overingTimer) {
1360
+ clearTimeout(this.overingTimer);
1361
+ }
2062
1362
 
2063
- /**
2064
- * Updates the time label
2065
- * @param {Number} value
2066
- * @private
2067
- */
2068
- _updatePositionLabel: function _updatePositionLabel(value) {
2069
- if (this.$position) {
2070
- this.$position.text(_timerFormat(value));
2071
- }
2072
- },
1363
+ $$1(document).off(ns);
1364
+ },
2073
1365
 
2074
- /**
2075
- * Updates the displayed time position
2076
- * @param {Number} value
2077
- * @param {*} [internal]
2078
- * @private
2079
- */
2080
- _updatePosition: function _updatePosition(value, internal) {
2081
- this.position = Math.max(0, Math.min(this.duration, parseFloat(value)));
1366
+ /**
1367
+ * Updates the volume slider
1368
+ * @param {Number} value
1369
+ * @private
1370
+ */
1371
+ _updateVolumeSlider: function _updateVolumeSlider(value) {
1372
+ if (this.$volumeSlider) {
1373
+ this.$volumeSlider.val(value);
1374
+ }
1375
+ },
2082
1376
 
2083
- if (!internal) {
2084
- this._updatePositionSlider(this.position);
2085
- }
1377
+ /**
1378
+ * Updates the displayed volume
1379
+ * @param {Number} value
1380
+ * @param {*} [internal]
1381
+ * @private
1382
+ */
1383
+ _updateVolume: function _updateVolume(value, internal) {
1384
+ this.volume = Math.max(volumeMin, Math.min(volumeMax, parseFloat(value)));
2086
1385
 
2087
- this._updatePositionLabel(this.position);
2088
- },
1386
+ this._storeVolume(this.volume);
2089
1387
 
2090
- /**
2091
- * Updates the duration slider
2092
- * @param {Number} value
2093
- * @private
2094
- */
2095
- _updateDurationSlider: function _updateDurationSlider(value) {
2096
- if (this.$seekSlider) {
2097
- this._destroySlider(this.$seekSlider);
1388
+ if (!internal) {
1389
+ this._updateVolumeSlider(value);
1390
+ }
1391
+ },
2098
1392
 
2099
- this.$seekSlider = null;
2100
- }
1393
+ /**
1394
+ * Updates the time slider
1395
+ * @param {Number} value
1396
+ * @private
1397
+ */
1398
+ _updatePositionSlider: function _updatePositionSlider(value) {
1399
+ if (this.$seekSlider) {
1400
+ this.$seekSlider.val(value);
1401
+ }
1402
+ },
2101
1403
 
2102
- if (value && isFinite(value)) {
2103
- this.$seekSlider = this._renderSlider(this.$seek, 0, 0, value);
2104
- this.$seekSlider.attr('disabled', !this.config.canSeek);
2105
- }
2106
- },
1404
+ /**
1405
+ * Updates the time label
1406
+ * @param {Number} value
1407
+ * @private
1408
+ */
1409
+ _updatePositionLabel: function _updatePositionLabel(value) {
1410
+ if (this.$position) {
1411
+ this.$position.text(timerFormat(value));
1412
+ }
1413
+ },
2107
1414
 
2108
- /**
2109
- * Updates the duration label
2110
- * @param {Number} value
2111
- * @private
2112
- */
2113
- _updateDurationLabel: function _updateDurationLabel(value) {
2114
- if (this.$duration) {
2115
- if (value && isFinite(value)) {
2116
- this.$duration.text(_timerFormat(value)).show();
2117
- } else {
2118
- this.$duration.hide();
1415
+ /**
1416
+ * Updates the displayed time position
1417
+ * @param {Number} value
1418
+ * @param {*} [internal]
1419
+ * @private
1420
+ */
1421
+ _updatePosition: function _updatePosition(value, internal) {
1422
+ this.position = Math.max(0, Math.min(this.duration || +Infinity, parseFloat(value)));
1423
+
1424
+ if (!internal && this.duration) {
1425
+ this._updatePositionSlider(this.position);
2119
1426
  }
2120
- }
2121
- },
2122
1427
 
2123
- /**
2124
- * Updates the displayed duration
2125
- * @param {Number} value
2126
- * @private
2127
- */
2128
- _updateDuration: function _updateDuration(value) {
2129
- this.duration = Math.abs(parseFloat(value));
1428
+ this._updatePositionLabel(this.position);
1429
+ },
2130
1430
 
2131
- this._updateDurationSlider(this.duration);
1431
+ /**
1432
+ * Updates the duration slider
1433
+ * @param {Number} value
1434
+ * @private
1435
+ */
1436
+ _updateDurationSlider: function _updateDurationSlider(value) {
1437
+ if (this.$seekSlider) {
1438
+ this._destroySlider(this.$seekSlider);
2132
1439
 
2133
- this._updateDurationLabel(this.duration);
2134
- },
1440
+ this.$seekSlider = null;
1441
+ }
2135
1442
 
2136
- /**
2137
- * Event called when the media is ready
2138
- * @private
2139
- */
2140
- _onReady: function _onReady() {
2141
- this._updateDuration(this.player.getDuration());
1443
+ if (value && isFinite(value)) {
1444
+ this.$seekSlider = this._renderSlider(this.$seek, 0, 0, value);
1445
+ this.$seekSlider.attr('disabled', !this.config.canSeek);
1446
+ }
1447
+ },
1448
+
1449
+ /**
1450
+ * Updates the duration label
1451
+ * @param {Number} value
1452
+ * @private
1453
+ */
1454
+ _updateDurationLabel: function _updateDurationLabel(value) {
1455
+ if (this.$duration) {
1456
+ if (value && isFinite(value)) {
1457
+ this.$duration.text(timerFormat(value)).show();
1458
+ } else {
1459
+ this.$duration.hide();
1460
+ }
1461
+ }
1462
+ },
2142
1463
 
2143
- this._setState('ready', true);
1464
+ /**
1465
+ * Updates the displayed duration
1466
+ * @param {Number|String} value
1467
+ * @private
1468
+ */
1469
+ _updateDuration: function _updateDuration(value) {
1470
+ var duration = Math.abs(parseFloat(value));
2144
1471
 
2145
- this._setState('canplay', true);
1472
+ if (duration !== this.duration) {
1473
+ this.duration = duration;
2146
1474
 
2147
- this._setState('canpause', this.config.canPause);
1475
+ this._updateDurationSlider(this.duration);
2148
1476
 
2149
- this._setState('canseek', this.config.canSeek);
1477
+ this._updateDurationLabel(this.duration);
1478
+ }
1479
+ },
2150
1480
 
2151
- this._setState('loading', false);
2152
1481
  /**
2153
- * Triggers a media ready event
2154
- * @event mediaplayer#ready
1482
+ * Event called when the media is ready
1483
+ * @private
2155
1484
  */
1485
+ _onReady: function _onReady() {
1486
+ if (this.is('error')) {
1487
+ this._setState('error', false);
1488
+ }
2156
1489
 
1490
+ var duration = this.player.getDuration();
1491
+ var timePreview = this.config.preview || duration;
2157
1492
 
2158
- this.trigger('ready'); // set the initial state
1493
+ if (timePreview) {
1494
+ this._updateDuration(duration);
1495
+ }
2159
1496
 
2160
- this.setVolume(this.volume);
2161
- this.mute(!!this.startMuted);
1497
+ this.setInitialStates();
1498
+ /**
1499
+ * Triggers a media ready event
1500
+ * @event mediaplayer#ready
1501
+ */
2162
1502
 
2163
- if (this.autoStartAt) {
2164
- this.seek(this.autoStartAt);
2165
- } else if (this.autoStart) {
2166
- this.play();
2167
- }
2168
- },
1503
+ this.trigger('ready'); // set the initial state
2169
1504
 
2170
- /**
2171
- * Update volume in DBIndex store
2172
- * @param {Number} volume
2173
- * @private
2174
- */
2175
- _storeVolume: function _storeVolume(volume) {
2176
- return store('mediaVolume').then(function (volumeStore) {
2177
- volumeStore.setItem('volume', volume);
2178
- });
2179
- },
1505
+ this.setVolume(this.volume);
1506
+ this.mute(!!this.startMuted);
2180
1507
 
2181
- /**
2182
- * Get volume from DBIndex store
2183
- * @private
2184
- */
2185
- _updateVolumeFromStore: function _updateVolumeFromStore() {
2186
- var self = this;
2187
- return store('mediaVolume').then(function (volumeStore) {
2188
- return volumeStore.getItem('volume');
2189
- }).then(function (volume) {
2190
- if (_.isNumber(volume)) {
2191
- self.volume = Math.max(_volumeMin, Math.min(_volumeMax, parseFloat(volume)));
2192
- self.setVolume(self.volume);
1508
+ if (this.autoStartAt) {
1509
+ this.seek(this.autoStartAt);
1510
+ } else if (this.autoStart) {
1511
+ this.play();
2193
1512
  }
2194
- });
2195
- },
2196
1513
 
2197
- /**
2198
- * Event called when the media throws unrecoverable error
2199
- * @private
2200
- */
2201
- _onError: function _onError() {
2202
- this._setState('error', true);
1514
+ if (this.config.preview && this.$container && this.config.height && this.config.height !== 'auto') {
1515
+ this._setMaxHeight();
1516
+ }
1517
+ },
1518
+
1519
+ /**
1520
+ * Set max height limit for container
1521
+ * using by old media items with defined height.
1522
+ * @private
1523
+ */
1524
+ _setMaxHeight: function _setMaxHeight() {
1525
+ var $video = this.$container.find('video.video');
1526
+ var controlsHeight = parseInt(window.getComputedStyle(this.$controls[0]).height);
1527
+ var scale = $video.height() / this.config.height;
1528
+ var playerWidth = this.$container.find('.player').width();
1529
+ var videoWidth = $video.width() / scale;
1530
+
1531
+ if (videoWidth > playerWidth) {
1532
+ this.execute('setSize', '100%', 'auto');
1533
+ } else {
1534
+ this.$component.css({
1535
+ maxHeight: "".concat(this.config.height + controlsHeight, "px")
1536
+ });
1537
+ this.execute('setSize', Math.floor(videoWidth), 'auto');
1538
+ }
1539
+ },
2203
1540
 
2204
- this._setState('loading', false);
2205
1541
  /**
2206
- * Triggers an unrecoverable media error event
2207
- * @event mediaplayer#error
1542
+ * Update volume in DBIndex store
1543
+ * @param {Number} volume
1544
+ * @returns {Promise}
1545
+ * @private
2208
1546
  */
1547
+ _storeVolume: function _storeVolume(volume) {
1548
+ return store('mediaVolume').then(function (volumeStore) {
1549
+ return volumeStore.setItem('volume', volume);
1550
+ });
1551
+ },
2209
1552
 
1553
+ /**
1554
+ * Get volume from DBIndex store
1555
+ * @returns {Promise}
1556
+ * @private
1557
+ */
1558
+ _updateVolumeFromStore: function _updateVolumeFromStore() {
1559
+ var _this8 = this;
2210
1560
 
2211
- this.trigger('error');
2212
- },
1561
+ return store('mediaVolume').then(function (volumeStore) {
1562
+ return volumeStore.getItem('volume');
1563
+ }).then(function (volume) {
1564
+ if (_.isNumber(volume)) {
1565
+ _this8.volume = Math.max(volumeMin, Math.min(volumeMax, parseFloat(volume)));
1566
+
1567
+ _this8.setVolume(_this8.volume);
1568
+ }
1569
+ });
1570
+ },
2213
1571
 
2214
- /**
2215
- * Event called when the media throws recoverable error
2216
- * @private
2217
- */
2218
- _onRecoverError: function _onRecoverError() {
2219
- this._setState('error', false);
2220
1572
  /**
2221
- * Triggers a recoverable media error event
2222
- * @event mediaplayer#recovererror
1573
+ * Event called when the media throws unrecoverable error
1574
+ * @private
2223
1575
  */
1576
+ _onError: function _onError() {
1577
+ this._setState('error', true);
2224
1578
 
1579
+ this._setState('loading', false);
1580
+ /**
1581
+ * Triggers an unrecoverable media error event
1582
+ * @event mediaplayer#error
1583
+ */
2225
1584
 
2226
- this.trigger('recovererror');
2227
- },
2228
1585
 
2229
- /**
2230
- * Event called when the media is played
2231
- * @private
2232
- */
2233
- _onPlay: function _onPlay() {
2234
- this._playingState(true);
1586
+ this.trigger('error');
1587
+ },
1588
+
2235
1589
  /**
2236
- * Triggers a media playback event
2237
- * @event mediaplayer#play
1590
+ * Event called when the media is played
1591
+ * @private
2238
1592
  */
1593
+ _onPlay: function _onPlay() {
1594
+ this._playingState(true);
1595
+
1596
+ this._setState('preview', true);
1597
+ /**
1598
+ * Triggers a media playback event
1599
+ * @event mediaplayer#play
1600
+ */
2239
1601
 
2240
1602
 
2241
- this.trigger('play', this.$media[0]);
2242
- },
1603
+ this.trigger('play', this.player && this.player.getMedia());
1604
+ },
2243
1605
 
2244
- /**
2245
- * Event called when the media is paused
2246
- * @private
2247
- */
2248
- _onPause: function _onPause() {
2249
- this._playingState(false);
2250
1606
  /**
2251
- * Triggers a media paused event
2252
- * @event mediaplayer#pause
1607
+ * Event called when the media is paused
1608
+ * @private
2253
1609
  */
1610
+ _onPause: function _onPause() {
1611
+ this._playingState(false);
1612
+ /**
1613
+ * Triggers a media paused event
1614
+ * @event mediaplayer#pause
1615
+ */
2254
1616
 
2255
1617
 
2256
- this.trigger('pause');
2257
- },
1618
+ this.trigger('pause');
1619
+ },
2258
1620
 
2259
- /**
2260
- * Event called when the media is ended
2261
- * @private
2262
- */
2263
- _onEnd: function _onEnd() {
2264
- this.timesPlayed++;
1621
+ /**
1622
+ * Event called when the media is ended
1623
+ * @private
1624
+ */
1625
+ _onEnd: function _onEnd() {
1626
+ this.timesPlayed++;
1627
+
1628
+ this._playingState(false, true);
2265
1629
 
2266
- this._playingState(false, true);
1630
+ this._updatePosition(0); // disable when the play limit is reached
2267
1631
 
2268
- this._updatePosition(0); // disable GUI when the play limit is reached
1632
+
1633
+ if (this._playLimitReached()) {
1634
+ if (!this.is('disabled')) {
1635
+ this.disable();
1636
+ }
1637
+ /**
1638
+ * Triggers a play limit reached event
1639
+ * @event mediaplayer#limitreached
1640
+ */
2269
1641
 
2270
1642
 
2271
- if (this._playLimitReached()) {
2272
- this._disableGUI();
1643
+ this.trigger('limitreached');
1644
+ } else if (this.loop) {
1645
+ this.restart();
1646
+ } else if (parseInt(this.config.replayTimeout, 10) > 0) {
1647
+ this.replayTimeoutStartMs = new window.Date().getTime();
1648
+
1649
+ this._replayTimeout();
1650
+ }
2273
1651
  /**
2274
- * Triggers a play limit reached event
2275
- * @event mediaplayer#limitreached
1652
+ * Triggers a media ended event
1653
+ * @event mediaplayer#ended
2276
1654
  */
2277
1655
 
2278
1656
 
2279
- this.trigger('limitreached');
2280
- } else if (this.loop) {
2281
- this.restart();
2282
- } else if (parseInt(this.config.replayTimeout, 10) > 0) {
2283
- this.replayTimeoutStartMs = new window.Date().getTime();
1657
+ this.trigger('ended');
1658
+ },
2284
1659
 
2285
- this._replayTimeout();
2286
- }
2287
1660
  /**
2288
- * Triggers a media ended event
2289
- * @event mediaplayer#ended
1661
+ * Event called when the playback is playing
1662
+ * @private
2290
1663
  */
1664
+ _onPlaying: function _onPlaying() {
1665
+ this._setState('preview', true);
2291
1666
 
1667
+ this._setState('stalled', false);
2292
1668
 
2293
- this.trigger('ended');
2294
- },
1669
+ this._setState('ready', true);
1670
+ },
2295
1671
 
2296
- /**
2297
- * Event called when the time position has changed
2298
- * @private
2299
- */
2300
- _onTimeUpdate: function _onTimeUpdate() {
2301
- this._updatePosition(this.player.getPosition());
2302
1672
  /**
2303
- * Triggers a media time update event
2304
- * @event mediaplayer#update
1673
+ * Event called when the playback is stalled
1674
+ * @private
2305
1675
  */
1676
+ _onStalled: function _onStalled() {
1677
+ this._setState('stalled', true);
2306
1678
 
1679
+ this._setState('ready', false);
1680
+ },
2307
1681
 
2308
- this.trigger('update');
2309
- },
1682
+ /**
1683
+ * Event called when the time position has changed
1684
+ * @private
1685
+ */
1686
+ _onTimeUpdate: function _onTimeUpdate() {
1687
+ this._updatePosition(this.player.getPosition());
1688
+ /**
1689
+ * Triggers a media time update event
1690
+ * @event mediaplayer#update
1691
+ */
2310
1692
 
2311
- /**
2312
- * Run a timer to disable the possibility of replaying a media
2313
- * @private
2314
- */
2315
- _replayTimeout: function _replayTimeout() {
2316
- var nowMs = new window.Date().getTime(),
2317
- elapsedSeconds = Math.floor((nowMs - this.replayTimeoutStartMs) / 1000);
2318
- this.timerId = requestAnimationFrame(this._replayTimeout.bind(this));
2319
1693
 
2320
- if (elapsedSeconds >= parseInt(this.config.replayTimeout, 10)) {
2321
- this._disableGUI();
1694
+ this.trigger('update');
1695
+ },
2322
1696
 
2323
- this.disable();
2324
- cancelAnimationFrame(this.timerId);
2325
- }
2326
- },
1697
+ /**
1698
+ * Run a timer to disable the possibility of replaying a media
1699
+ * @private
1700
+ */
1701
+ _replayTimeout: function _replayTimeout() {
1702
+ var nowMs = new window.Date().getTime(),
1703
+ elapsedSeconds = Math.floor((nowMs - this.replayTimeoutStartMs) / 1000);
1704
+ this.timerId = requestAnimationFrame(this._replayTimeout.bind(this));
2327
1705
 
2328
- /**
2329
- * Disable the player GUI
2330
- * @private
2331
- */
2332
- _disableGUI: function disableGUI() {
2333
- this._setState('ready', false);
1706
+ if (elapsedSeconds >= parseInt(this.config.replayTimeout, 10)) {
1707
+ this.disable();
1708
+ cancelAnimationFrame(this.timerId);
1709
+ }
1710
+ },
2334
1711
 
2335
- this._setState('canplay', false);
2336
- },
1712
+ /**
1713
+ * Checks if the play limit has been reached
1714
+ * @returns {Boolean}
1715
+ * @private
1716
+ */
1717
+ _playLimitReached: function _playLimitReached() {
1718
+ return this.config.maxPlays && this.timesPlayed >= this.config.maxPlays;
1719
+ },
2337
1720
 
2338
- /**
2339
- * Checks if the play limit has been reached
2340
- * @returns {Boolean}
2341
- * @private
2342
- */
2343
- _playLimitReached: function _playLimitReached() {
2344
- return this.config.maxPlays && this.timesPlayed >= this.config.maxPlays;
2345
- },
1721
+ /**
1722
+ * Checks if the media can be played
1723
+ * @returns {Boolean}
1724
+ * @private
1725
+ */
1726
+ _canPlay: function _canPlay() {
1727
+ return (this.is('ready') || this.is('stalled')) && !this.is('disabled') && !this.is('hidden') && !this._playLimitReached();
1728
+ },
2346
1729
 
2347
- /**
2348
- * Checks if the media can be played
2349
- * @returns {Boolean}
2350
- * @private
2351
- */
2352
- _canPlay: function _canPlay() {
2353
- return this.is('ready') && !this.is('disabled') && !this.is('hidden') && !this._playLimitReached();
2354
- },
1730
+ /**
1731
+ * Checks if the media can be paused
1732
+ * @returns {Boolean}
1733
+ * @private
1734
+ */
1735
+ _canPause: function _canPause() {
1736
+ return !!this.config.canPause;
1737
+ },
2355
1738
 
2356
- /**
2357
- * Checks if the media can be paused
2358
- * @returns {Boolean}
2359
- * @private
2360
- */
2361
- _canPause: function _canPause() {
2362
- return !!this.config.canPause;
2363
- },
1739
+ /**
1740
+ * Checks if the media can be sought
1741
+ * @returns {Boolean}
1742
+ * @private
1743
+ */
1744
+ _canSeek: function _canSeek() {
1745
+ return !!this.config.canSeek;
1746
+ },
2364
1747
 
2365
- /**
2366
- * Checks if the media can be sought
2367
- * @returns {Boolean}
2368
- * @private
2369
- */
2370
- _canSeek: function _canSeek() {
2371
- return !!this.config.canSeek;
2372
- },
1748
+ /**
1749
+ * Checks if the playback can be resumed
1750
+ * @returns {Boolean}
1751
+ * @private
1752
+ */
1753
+ _canResume: function _canResume() {
1754
+ return this.is('paused') && this._canPlay();
1755
+ },
2373
1756
 
2374
- /**
2375
- * Checks if the playback can be resumed
2376
- * @returns {Boolean}
2377
- * @private
2378
- */
2379
- _canResume: function _canResume() {
2380
- return this.is('paused') && this._canPlay();
2381
- },
1757
+ /**
1758
+ * Sets the media is in a particular state
1759
+ * @param {String} name
1760
+ * @param {Boolean} value
1761
+ * @returns {mediaplayer}
1762
+ */
1763
+ _setState: function _setState(name, value) {
1764
+ value = !!value;
1765
+ this.config.is[name] = value;
2382
1766
 
2383
- /**
2384
- * Sets the media is in a particular state
2385
- * @param {String} name
2386
- * @param {Boolean} value
2387
- * @returns {mediaplayer}
2388
- */
2389
- _setState: function _setState(name, value) {
2390
- value = !!value;
2391
- this.config.is[name] = value;
1767
+ if (this.$component) {
1768
+ this.$component.toggleClass(name, value);
1769
+ }
2392
1770
 
2393
- if (this.$component) {
2394
- this.$component.toggleClass(name, value);
2395
- }
1771
+ return this;
1772
+ },
2396
1773
 
2397
- return this;
2398
- },
1774
+ /**
1775
+ * Restores the media player from a particular state and resumes the playback
1776
+ * @param {String} stateName
1777
+ * @returns {mediaplayer}
1778
+ * @private
1779
+ */
1780
+ _fromState: function _fromState(stateName) {
1781
+ this._setState(stateName, false);
2399
1782
 
2400
- /**
2401
- * Restores the media player from a particular state and resumes the playback
2402
- * @param {String} stateName
2403
- * @returns {mediaplayer}
2404
- * @private
2405
- */
2406
- _fromState: function _fromState(stateName) {
2407
- this._setState(stateName, false);
1783
+ this.resume();
1784
+ return this;
1785
+ },
2408
1786
 
2409
- this.resume();
2410
- return this;
2411
- },
1787
+ /**
1788
+ * Sets the media player to a particular state and pauses the playback
1789
+ * @param {String} stateName
1790
+ * @returns {mediaplayer}
1791
+ * @private
1792
+ */
1793
+ _toState: function _toState(stateName) {
1794
+ this.pause();
2412
1795
 
2413
- /**
2414
- * Sets the media player to a particular state and pauses the playback
2415
- * @param {String} stateName
2416
- * @returns {mediaplayer}
2417
- * @private
2418
- */
2419
- _toState: function _toState(stateName) {
2420
- this.pause();
1796
+ this._setState(stateName, true);
2421
1797
 
2422
- this._setState(stateName, true);
1798
+ return this;
1799
+ },
2423
1800
 
2424
- return this;
2425
- },
1801
+ /**
1802
+ * Sets the playing state
1803
+ * @param {Boolean} state
1804
+ * @param {Boolean} [ended]
1805
+ * @returns {mediaplayer}
1806
+ * @private
1807
+ */
1808
+ _playingState: function _playingState(state, ended) {
1809
+ this._setState('playing', !!state);
2426
1810
 
2427
- /**
2428
- * Sets the playing state
2429
- * @param {Boolean} state
2430
- * @param {Boolean} [ended]
2431
- * @returns {mediaplayer}
2432
- * @private
2433
- */
2434
- _playingState: function _playingState(state, ended) {
2435
- this._setState('playing', !!state);
1811
+ this._setState('paused', !state);
2436
1812
 
2437
- this._setState('paused', !state);
1813
+ this._setState('ended', !!ended);
2438
1814
 
2439
- this._setState('ended', !!ended);
1815
+ return this;
1816
+ },
2440
1817
 
2441
- return this;
2442
- },
1818
+ /**
1819
+ * Executes a command onto the media
1820
+ * @param {String} command - The name of the command to execute
1821
+ * @param {*} args - additional arguments
1822
+ * @returns {*}
1823
+ * @private
1824
+ */
1825
+ execute: function execute(command) {
1826
+ if (this.player && 'function' === typeof this.player[command]) {
1827
+ var _this$player;
2443
1828
 
2444
- /**
2445
- * Executes a command onto the media
2446
- * @param {String} command - The name of the command to execute
2447
- * @returns {*}
2448
- * @private
2449
- */
2450
- execute: function execute(command) {
2451
- var ctx = this.player;
2452
- var method = ctx && ctx[command];
1829
+ for (var _len2 = arguments.length, args = new Array(_len2 > 1 ? _len2 - 1 : 0), _key2 = 1; _key2 < _len2; _key2++) {
1830
+ args[_key2 - 1] = arguments[_key2];
1831
+ }
2453
1832
 
2454
- if (_.isFunction(method)) {
2455
- return method.apply(ctx, _slice.call(arguments, 1));
1833
+ return (_this$player = this.player)[command].apply(_this$player, args);
1834
+ }
2456
1835
  }
2457
- }
2458
- };
2459
- /**
2460
- * Builds a media player instance
2461
- * @param {Object} config
2462
- * @param {String} config.type - The type of media to play
2463
- * @param {String|Array} config.url - The URL to the media
2464
- * @param {String|jQuery|HTMLElement} [config.renderTo] - An optional container in which renders the player
2465
- * @param {Boolean} [config.loop] - The media will be played continuously
2466
- * @param {Boolean} [config.canPause] - The play can be paused
2467
- * @param {Boolean} [config.startMuted] - The player should be initially muted
2468
- * @param {Boolean} [config.autoStart] - The player starts as soon as it is displayed
2469
- * @param {Number} [config.autoStartAt] - The time position at which the player should start
2470
- * @param {Number} [config.maxPlays] - Sets a few number of plays (default: infinite)
2471
- * @param {Number} [config.volume] - Sets the sound volume (default: 80)
2472
- * @param {Number} [config.width] - Sets the width of the player (default: depends on media type)
2473
- * @param {Number} [config.height] - Sets the height of the player (default: depends on media type)
2474
- * @event render - Event triggered when the player is rendering
2475
- * @event error - Event triggered when the player throws an unrecoverable error
2476
- * @event recovererror - Event triggered when the player throws a recoverable error
2477
- * @event ready - Event triggered when the player is fully ready
2478
- * @event play - Event triggered when the playback is starting
2479
- * @event update - Event triggered while the player is playing
2480
- * @event pause - Event triggered when the playback is paused
2481
- * @event ended - Event triggered when the playback is ended
2482
- * @event limitreached - Event triggered when the play limit has been reached
2483
- * @event destroy - Event triggered when the player is destroying
2484
- * @returns {mediaplayer}
2485
- */
2486
-
2487
- var mediaplayerFactory = function mediaplayerFactory(config) {
2488
- var player = _.clone(mediaplayer);
2489
-
2490
- return player.init(config);
2491
- };
1836
+ };
1837
+ return mediaplayer.init(config);
1838
+ }
2492
1839
  /**
2493
1840
  * Tells if the browser can play audio and video
2494
1841
  * @param {String} [type] The type of media (audio or video)
@@ -2498,7 +1845,7 @@ define(['jquery', 'lodash', 'async', 'util/urlParser', 'core/eventifier', 'core/
2498
1845
 
2499
1846
 
2500
1847
  mediaplayerFactory.canPlay = function canPlay(type, mime) {
2501
- return _support.canPlay(type, mime);
1848
+ return support.canPlay(type, mime);
2502
1849
  };
2503
1850
  /**
2504
1851
  * Tells if the browser can play audio
@@ -2508,7 +1855,7 @@ define(['jquery', 'lodash', 'async', 'util/urlParser', 'core/eventifier', 'core/
2508
1855
 
2509
1856
 
2510
1857
  mediaplayerFactory.canPlayAudio = function canPlayAudio(mime) {
2511
- return _support.canPlayAudio(mime);
1858
+ return support.canPlayAudio(mime);
2512
1859
  };
2513
1860
  /**
2514
1861
  * Tells if the browser can play video
@@ -2518,7 +1865,7 @@ define(['jquery', 'lodash', 'async', 'util/urlParser', 'core/eventifier', 'core/
2518
1865
 
2519
1866
 
2520
1867
  mediaplayerFactory.canPlayVideo = function canPlayVideo(mime) {
2521
- return _support.canPlayVideo(mime);
1868
+ return support.canPlayVideo(mime);
2522
1869
  };
2523
1870
  /**
2524
1871
  * Checks if the browser allows to control the media playback
@@ -2527,16 +1874,8 @@ define(['jquery', 'lodash', 'async', 'util/urlParser', 'core/eventifier', 'core/
2527
1874
 
2528
1875
 
2529
1876
  mediaplayerFactory.canControl = function canControl() {
2530
- return _support.canControl();
1877
+ return support.canControl();
2531
1878
  };
2532
- /**
2533
- * The polling interval used to update the progress bar while playing a YouTube video.
2534
- * Note : the YouTube API does not provide events to update this progress bar...
2535
- * @type {Number}
2536
- */
2537
-
2538
-
2539
- mediaplayerFactory.youtubePolling = 100;
2540
1879
 
2541
1880
  return mediaplayerFactory;
2542
1881