From 42a8a37e34aa3145b8f5c611615be48b7e5e7dc2 Mon Sep 17 00:00:00 2001 From: David LaPalomento Date: Mon, 20 Jul 2015 11:40:26 -0400 Subject: [PATCH] Add a very basic played() method Expose the played attribute on the HTML5 tech. Add a default implementation of played() to the base tech that tracks whether the video has played at all but doesn't provide valid ranges. --- src/js/tech/html5.js | 129 +++++++++++++++++++---------------- src/js/tech/tech.js | 26 +++++++ test/unit/tech/html5.test.js | 5 ++ test/unit/tech/tech.test.js | 9 +++ 4 files changed, 109 insertions(+), 60 deletions(-) diff --git a/src/js/tech/html5.js b/src/js/tech/html5.js index 82c9a2c5ed..16f71886ce 100644 --- a/src/js/tech/html5.js +++ b/src/js/tech/html5.js @@ -1,5 +1,5 @@ /** - * @file html5.js + * @file html5.js * HTML5 Media Controller - Wrapper for HTML5 Media API */ @@ -199,7 +199,7 @@ class Html5 extends Tech { /** * Paused for html5 tech * - * @return {Boolean} + * @return {Boolean} * @method paused */ paused() { return this.el_.paused; } @@ -207,7 +207,7 @@ class Html5 extends Tech { /** * Get current time * - * @return {Number} + * @return {Number} * @method currentTime */ currentTime() { return this.el_.currentTime; } @@ -215,7 +215,7 @@ class Html5 extends Tech { /** * Set current time * - * @param {Number} seconds Current time of video + * @param {Number} seconds Current time of video * @method setCurrentTime */ setCurrentTime(seconds) { @@ -246,7 +246,7 @@ class Html5 extends Tech { buffered() { return this.el_.buffered; } /** - * Get volume level + * Get volume level * * @return {Number} * @method volume @@ -254,7 +254,7 @@ class Html5 extends Tech { volume() { return this.el_.volume; } /** - * Set volume level + * Set volume level * * @param {Number} percentAsDecimal Volume percent as a decimal * @method setVolume @@ -262,7 +262,7 @@ class Html5 extends Tech { setVolume(percentAsDecimal) { this.el_.volume = percentAsDecimal; } /** - * Get if muted + * Get if muted * * @return {Boolean} * @method muted @@ -270,7 +270,7 @@ class Html5 extends Tech { muted() { return this.el_.muted; } /** - * Set muted + * Set muted * * @param {Boolean} If player is to be muted or note * @method setMuted @@ -278,7 +278,7 @@ class Html5 extends Tech { setMuted(muted) { this.el_.muted = muted; } /** - * Get player width + * Get player width * * @return {Number} * @method width @@ -286,7 +286,7 @@ class Html5 extends Tech { width() { return this.el_.offsetWidth; } /** - * Get player height + * Get player height * * @return {Number} * @method height @@ -294,9 +294,9 @@ class Html5 extends Tech { height() { return this.el_.offsetHeight; } /** - * Get if there is fullscreen support + * Get if there is fullscreen support * - * @return {Boolean} + * @return {Boolean} * @method supportsFullScreen */ supportsFullScreen() { @@ -356,8 +356,8 @@ class Html5 extends Tech { /** * Get/set video * - * @param {Object=} src Source object - * @return {Object} + * @param {Object=} src Source object + * @return {Object} * @method src */ src(src) { @@ -372,7 +372,7 @@ class Html5 extends Tech { /** * Set video * - * @param {Object} src Source object + * @param {Object} src Source object * @deprecated * @method setSrc */ @@ -386,97 +386,97 @@ class Html5 extends Tech { load(){ this.el_.load(); } /** - * Get current source + * Get current source * - * @return {Object} + * @return {Object} * @method currentSrc */ currentSrc() { return this.el_.currentSrc; } /** - * Get poster + * Get poster * - * @return {String} + * @return {String} * @method poster */ poster() { return this.el_.poster; } /** - * Set poster + * Set poster * * @param {String} val URL to poster image - * @method + * @method */ setPoster(val) { this.el_.poster = val; } /** - * Get preload attribute + * Get preload attribute * - * @return {String} + * @return {String} * @method preload */ preload() { return this.el_.preload; } /** - * Set preload attribute + * Set preload attribute * - * @param {String} val Value for preload attribute + * @param {String} val Value for preload attribute * @method setPreload */ setPreload(val) { this.el_.preload = val; } /** - * Get autoplay attribute + * Get autoplay attribute * - * @return {String} + * @return {String} * @method autoplay */ autoplay() { return this.el_.autoplay; } /** - * Set autoplay attribute + * Set autoplay attribute * - * @param {String} val Value for preload attribute + * @param {String} val Value for preload attribute * @method setAutoplay */ setAutoplay(val) { this.el_.autoplay = val; } /** - * Get controls attribute + * Get controls attribute * - * @return {String} + * @return {String} * @method controls */ controls() { return this.el_.controls; } /** - * Set controls attribute + * Set controls attribute * - * @param {String} val Value for controls attribute + * @param {String} val Value for controls attribute * @method setControls */ setControls(val) { this.el_.controls = !!val; } /** - * Get loop attribute + * Get loop attribute * - * @return {String} + * @return {String} * @method loop */ loop() { return this.el_.loop; } /** - * Set loop attribute + * Set loop attribute * - * @param {String} val Value for loop attribute + * @param {String} val Value for loop attribute * @method setLoop */ setLoop(val) { this.el_.loop = val; } /** - * Get error value + * Get error value * - * @return {String} + * @return {String} * @method error */ error() { return this.el_.error; } @@ -484,41 +484,41 @@ class Html5 extends Tech { /** * Get whether or not the player is in the "seeking" state * - * @return {Boolean} + * @return {Boolean} * @method seeking */ seeking() { return this.el_.seeking; } /** - * Get a TimeRanges object that represents the - * ranges of the media resource to which it is possible - * for the user agent to seek. + * Get a TimeRanges object that represents the + * ranges of the media resource to which it is possible + * for the user agent to seek. * - * @return {TimeRangeObject} + * @return {TimeRangeObject} * @method seekable */ seekable() { return this.el_.seekable; } /** - * Get if video ended + * Get if video ended * - * @return {Boolean} + * @return {Boolean} * @method ended */ ended() { return this.el_.ended; } /** * Get the value of the muted content attribute - * This attribute has no dynamic effect, it only + * This attribute has no dynamic effect, it only * controls the default state of the element * - * @return {Boolean} + * @return {Boolean} * @method defaultMuted */ defaultMuted() { return this.el_.defaultMuted; } /** - * Get desired speed at which the media resource is to play + * Get desired speed at which the media resource is to play * * @return {Number} * @method playbackRate @@ -526,7 +526,16 @@ class Html5 extends Tech { playbackRate() { return this.el_.playbackRate; } /** - * Set desired speed at which the media resource is to play + * Returns a TimeRanges object that represents the ranges of the + * media resource that the user agent has played. + * @return {TimeRangeObject} the range of points on the media + * timeline that has been reached through normal playback + * @see https://html.spec.whatwg.org/multipage/embedded-content.html#dom-media-played + */ + played() { return this.el_.played; } + + /** + * Set desired speed at which the media resource is to play * * @param {Number} val Speed at which the media resource is to play * @method setPlaybackRate @@ -547,22 +556,22 @@ class Html5 extends Tech { networkState() { return this.el_.networkState; } /** - * Get a value that expresses the current state of the element - * with respect to rendering the current playback position, from + * Get a value that expresses the current state of the element + * with respect to rendering the current playback position, from * the codes in the list below * HAVE_NOTHING (numeric value 0) * HAVE_METADATA (numeric value 1) * HAVE_CURRENT_DATA (numeric value 2) * HAVE_FUTURE_DATA (numeric value 3) * HAVE_ENOUGH_DATA (numeric value 4) - * + * * @return {Number} * @method readyState */ readyState() { return this.el_.readyState; } /** - * Get width of video + * Get width of video * * @return {Number} * @method videoWidth @@ -570,7 +579,7 @@ class Html5 extends Tech { videoWidth() { return this.el_.videoWidth; } /** - * Get height of video + * Get height of video * * @return {Number} * @method videoHeight @@ -578,9 +587,9 @@ class Html5 extends Tech { videoHeight() { return this.el_.videoHeight; } /** - * Get text tracks + * Get text tracks * - * @return {TextTrackList} + * @return {TextTrackList} * @method textTracks */ textTracks() { @@ -592,7 +601,7 @@ class Html5 extends Tech { } /** - * Creates and returns a text track object + * Creates and returns a text track object * * @param {String} kind Text track kind (subtitles, captions, descriptions * chapters and metadata) @@ -610,7 +619,7 @@ class Html5 extends Tech { } /** - * Creates and returns a remote text track object + * Creates and returns a remote text track object * * @param {Object} options The object should contain values for * kind, language, label and src (location of the WebVTT file) @@ -669,7 +678,7 @@ class Html5 extends Tech { } /** - * Remove remote text track from TextTrackList object + * Remove remote text track from TextTrackList object * * @param {TextTrackObject} track Texttrack object to remove * @method removeRemoteTextTrack diff --git a/src/js/tech/tech.js b/src/js/tech/tech.js index ace615c660..4e7e88f62d 100644 --- a/src/js/tech/tech.js +++ b/src/js/tech/tech.js @@ -30,6 +30,16 @@ class Tech extends Component { options.reportTouchActivity = false; super(null, options, ready); + // keep track of whether the current source has played at all to + // implement a very limited played() + this.hasStarted_ = false; + this.on('playing', function() { + this.hasStarted_ = true; + }); + this.on('loadstart', function() { + this.hasStarted_ = false; + }); + this.textTracks_ = options.textTracks; // Manually track progress in cases where the browser/flash player doesn't report it. @@ -246,6 +256,22 @@ class Tech extends Component { super.dispose(); } + /** + * Return the time ranges that have been played through for the + * current source. This implementation is incomplete. It does not + * track the played time ranges, only whether the source has played + * at all or not. + * @return {TimeRangeObject} a single time range if this video has + * played or an empty set of ranges if not. + * @method played + */ + played() { + if (this.hasStarted_) { + return createTimeRange(0, 0); + } + return createTimeRange(); + } + /** * Set current time * diff --git a/test/unit/tech/html5.test.js b/test/unit/tech/html5.test.js index 6f56963882..ca3a6bb861 100644 --- a/test/unit/tech/html5.test.js +++ b/test/unit/tech/html5.test.js @@ -69,6 +69,11 @@ test('test playbackRate', function() { strictEqual(tech.playbackRate(), 0.75); }); +test('should export played', function() { + tech.createEl(); + deepEqual(tech.played(), tech.el().played, 'returns the played attribute'); +}); + test('should remove the controls attribute when recreating the element', function() { var el; player.tagAttributes = { diff --git a/test/unit/tech/tech.test.js b/test/unit/tech/tech.test.js index de4486e58a..d53fb374ee 100644 --- a/test/unit/tech/tech.test.js +++ b/test/unit/tech/tech.test.js @@ -192,3 +192,12 @@ test('should handle unsupported sources with the source hanlder API', function() tech.setSource(''); ok(usedNative, 'native source handler was used when an unsupported source was set'); }); + +test('should track whether a video has played', function() { + let tech = new Tech(); + + equal(tech.played().length, 0, 'starts with zero length'); + + tech.trigger('playing'); + equal(tech.played().length, 1, 'has length after playing'); +});