diff --git a/src/js/lib.js b/src/js/lib.js index 52abda9f87..4567926467 100644 --- a/src/js/lib.js +++ b/src/js/lib.js @@ -391,6 +391,22 @@ vjs.IS_CHROME = (/Chrome/i).test(vjs.USER_AGENT); vjs.TOUCH_ENABLED = !!(('ontouchstart' in window) || window.DocumentTouch && document instanceof window.DocumentTouch); +/** + * Apply attributes to an HTML element. + * @param {Element} el Target element. + * @param {Object=} attributes Element attributes to be applied. + * @private + */ +vjs.setElementAttributes = function(el, attributes){ + vjs.obj.each(attributes, function(attrName, attrValue) { + if (attrValue === null || typeof attrValue === 'undefined' || attrValue === false) { + el.removeAttribute(attrName); + } else { + el.setAttribute(attrName,attrValue === true ? '' : attrValue); + } + }); +}; + /** * Get an element's attribute values, as defined on the HTML tag * Attributs are not the same as properties. They're defined on the tag @@ -400,7 +416,7 @@ vjs.TOUCH_ENABLED = !!(('ontouchstart' in window) || window.DocumentTouch && doc * @return {Object} * @private */ -vjs.getAttributeValues = function(tag){ +vjs.getElementAttributes = function(tag){ var obj, knownBooleans, attrs, attrName, attrVal; obj = {}; diff --git a/src/js/media/html5.js b/src/js/media/html5.js index 19dcc3cf7b..e6cc176e52 100644 --- a/src/js/media/html5.js +++ b/src/js/media/html5.js @@ -80,10 +80,13 @@ vjs.Html5.prototype.createEl = function(){ el = clone; player.tag = null; } else { - el = vjs.createEl('video', { - id:player.id() + '_html5_api', - className:'vjs-tech' - }); + el = vjs.createEl('video', {}); + vjs.setElementAttributes(el, + vjs.obj.merge(player.tagAttributes||{}, { + id:player.id() + '_html5_api', + 'class':'vjs-tech' + }) + ); } // associate the player with the new tag el['player'] = player; @@ -92,12 +95,14 @@ vjs.Html5.prototype.createEl = function(){ } // Update specific tag settings, in case they were overridden - var attrs = ['autoplay','preload','loop','muted']; - for (var i = attrs.length - 1; i >= 0; i--) { - var attr = attrs[i]; - if (player.options_[attr] !== null) { - el[attr] = player.options_[attr]; + var settingsAttrs = ['autoplay','preload','loop','muted']; + for (var i = settingsAttrs.length - 1; i >= 0; i--) { + var attr = settingsAttrs[i]; + var overwriteAttrs = {}; + if (typeof player.options_[attr] !== 'undefined') { + overwriteAttrs[attr] = player.options_[attr]; } + vjs.setElementAttributes(el, overwriteAttrs); } return el; diff --git a/src/js/player.js b/src/js/player.js index caa2e5d59d..c8a6bf000d 100644 --- a/src/js/player.js +++ b/src/js/player.js @@ -32,6 +32,8 @@ vjs.Player = vjs.Component.extend({ init: function(tag, options, ready){ this.tag = tag; // Store the original tag used to set options + this.tagAttributes = (tag) ? vjs.getElementAttributes(tag) : {}; // Store the tag attributes used to restore html5 tech + // Make sure tag ID exists tag.id = tag.id || 'vjs_video_' + vjs.guid++; @@ -135,7 +137,7 @@ vjs.Player.prototype.getTagSettings = function(tag){ 'tracks': [] }; - vjs.obj.merge(options, vjs.getAttributeValues(tag)); + vjs.obj.merge(options, vjs.getElementAttributes(tag)); // Get tag children settings if (tag.hasChildNodes()) { @@ -148,9 +150,9 @@ vjs.Player.prototype.getTagSettings = function(tag){ // Change case needed: http://ejohn.org/blog/nodename-case-sensitivity/ childName = child.nodeName.toLowerCase(); if (childName === 'source') { - options['sources'].push(vjs.getAttributeValues(child)); + options['sources'].push(vjs.getElementAttributes(child)); } else if (childName === 'track') { - options['tracks'].push(vjs.getAttributeValues(child)); + options['tracks'].push(vjs.getElementAttributes(child)); } } } diff --git a/test/unit/lib.js b/test/unit/lib.js index 1a24177c6d..a21cc35193 100644 --- a/test/unit/lib.js +++ b/test/unit/lib.js @@ -113,10 +113,10 @@ test('should read tag attributes from elements, including HTML5 in all browsers' document.getElementById('qunit-fixture').innerHTML += tags; - var vid1Vals = vjs.getAttributeValues(document.getElementById('vid1')); - var vid2Vals = vjs.getAttributeValues(document.getElementById('vid2')); - var sourceVals = vjs.getAttributeValues(document.getElementById('source')); - var trackVals = vjs.getAttributeValues(document.getElementById('track')); + var vid1Vals = vjs.getElementAttributes(document.getElementById('vid1')); + var vid2Vals = vjs.getElementAttributes(document.getElementById('vid2')); + var sourceVals = vjs.getElementAttributes(document.getElementById('source')); + var trackVals = vjs.getElementAttributes(document.getElementById('track')); // was using deepEqual, but ie8 would send all properties as attributes @@ -152,6 +152,22 @@ test('should read tag attributes from elements, including HTML5 in all browsers' equal(trackVals['title'], 'test'); }); + +test('should set tag attributes from object', function(){ + + var tags = ''; + + document.getElementById('qunit-fixture').innerHTML += tags; + var el = document.getElementById('vid1'); + vjs.setElementAttributes(el, {controls: false,'data-test': 'asdf'}); + + var vid1Vals = vjs.getElementAttributes(document.getElementById('vid1')); + + equal(vid1Vals['controls'], undefined); + equal(vid1Vals['id'], 'vid1'); + equal(vid1Vals['data-test'], 'asdf'); +}); + test('should get the right style values for an element', function(){ var el = document.createElement('div'); var container = document.createElement('div'); diff --git a/test/unit/player.js b/test/unit/player.js index 7eb6db94e6..09d67825db 100644 --- a/test/unit/player.js +++ b/test/unit/player.js @@ -73,7 +73,7 @@ test('should accept options from multiple sources and override in correct order' }); test('should get tag, source, and track settings', function(){ - // Partially tested in lib->getAttributeValues + // Partially tested in lib->getElementAttributes var fixture = document.getElementById('qunit-fixture'); @@ -482,3 +482,32 @@ test('player should handle different error types', function(){ vjs.log.error.restore(); }); +test('should restore all video tags attribute after a tech switch', function(){ + var fixture = document.getElementById('qunit-fixture'); + var html = ''; + fixture.innerHTML += html; + + var tag = document.getElementById('example_1'); + var player = new videojs.Player(tag, {techOrder:['html5']}); + var techOptions = vjs.obj.merge({ 'source': '', 'parentEl': player.el_ }, player.options_['html5']); + vjs.Html5.disposeMediaElement(player.tag); + player.tag = null; + player.tech = new vjs.Html5(player, techOptions); + + PlayerTest.htmlEqualWithSort(player.tech.el_.outerHTML, html.replace('example_1','example_1_html5_api')); +}); + +test('should restore all video tags attribute after a tech switch and keep options', function(){ + var fixture = document.getElementById('qunit-fixture'); + var html = ''; + fixture.innerHTML += html; + + var tag = document.getElementById('example_1'); + var player = new videojs.Player(tag, {techOrder:['html5'], autoplay:false}); + var techOptions = vjs.obj.merge({ 'source': '', 'parentEl': player.el_ }, player.options_['html5']); + vjs.Html5.disposeMediaElement(player.tag); + player.tag = null; + player.tech = new vjs.Html5(player, techOptions); + + PlayerTest.htmlEqualWithSort(player.tech.el_.outerHTML, html.replace('example_1','example_1_html5_api').replace(' autoplay=""','')); +}); diff --git a/test/unit/test-helpers.js b/test/unit/test-helpers.js index ee91ecb4c7..ac84970f94 100644 --- a/test/unit/test-helpers.js +++ b/test/unit/test-helpers.js @@ -17,5 +17,16 @@ var PlayerTest = { playerOptions['techOrder'] = ['mediaFaker']; return player = new videojs.Player(videoTag, playerOptions); + }, + htmlEqualWithSort : function(htmlResult,htmlExpected) { + function htmlTransform(str) { + str = str.replace(/[<|>]/g,' '); + str = str.trim(); + str = str.replace(/\s{2,}/g, ' '); + return str.split(' ').sort().join(' '); + } + htmlResult= htmlResult.split(' ').sort().join(' '); + equal(htmlTransform(htmlResult),htmlTransform(htmlExpected)); + } };