From c5f88c703b139506ee478b2da69b950efb5546e5 Mon Sep 17 00:00:00 2001 From: Erik Arvidsson Date: Mon, 28 Oct 2013 18:43:13 -0400 Subject: [PATCH] Add Audio and Option constructors --- build.json | 3 + shadowdom.js | 3 + src/wrappers/HTMLAudioElement.js | 42 ++++++++++++++ src/wrappers/HTMLImageElement.js | 5 +- src/wrappers/HTMLMediaElement.js | 22 +++++++ src/wrappers/HTMLOptionElement.js | 63 +++++++++++++++++++++ src/wrappers/elements-with-form-property.js | 2 +- src/wrappers/override-constructors.js | 2 - test/js/HTMLAudioElement.js | 50 ++++++++++++++++ test/js/HTMLOptionElement.js | 61 ++++++++++++++++++++ test/test.main.js | 1 + 11 files changed, 249 insertions(+), 5 deletions(-) create mode 100644 src/wrappers/HTMLAudioElement.js create mode 100644 src/wrappers/HTMLMediaElement.js create mode 100644 src/wrappers/HTMLOptionElement.js create mode 100644 test/js/HTMLAudioElement.js diff --git a/build.json b/build.json index dd98232..c959cec 100644 --- a/build.json +++ b/build.json @@ -15,6 +15,9 @@ "src/wrappers/HTMLImageElement.js", "src/wrappers/HTMLShadowElement.js", "src/wrappers/HTMLTemplateElement.js", + "src/wrappers/HTMLMediaElement.js", + "src/wrappers/HTMLAudioElement.js", + "src/wrappers/HTMLOptionElement.js", "src/wrappers/HTMLUnknownElement.js", "src/wrappers/CanvasRenderingContext2D.js", "src/wrappers/WebGLRenderingContext.js", diff --git a/shadowdom.js b/shadowdom.js index 3d5785e..52e44dc 100644 --- a/shadowdom.js +++ b/shadowdom.js @@ -31,6 +31,9 @@ 'src/wrappers/HTMLImageElement.js', 'src/wrappers/HTMLShadowElement.js', 'src/wrappers/HTMLTemplateElement.js', + 'src/wrappers/HTMLMediaElement.js', + 'src/wrappers/HTMLAudioElement.js', + 'src/wrappers/HTMLOptionElement.js', 'src/wrappers/HTMLUnknownElement.js', 'src/wrappers/CanvasRenderingContext2D.js', 'src/wrappers/WebGLRenderingContext.js', diff --git a/src/wrappers/HTMLAudioElement.js b/src/wrappers/HTMLAudioElement.js new file mode 100644 index 0000000..3b4f375 --- /dev/null +++ b/src/wrappers/HTMLAudioElement.js @@ -0,0 +1,42 @@ +// Copyright 2013 The Polymer Authors. All rights reserved. +// Use of this source code is goverened by a BSD-style +// license that can be found in the LICENSE file. + +(function(scope) { + 'use strict'; + + var HTMLMediaElement = scope.wrappers.HTMLMediaElement; + var registerWrapper = scope.registerWrapper; + var unwrap = scope.unwrap; + var rewrap = scope.rewrap; + + var OriginalHTMLAudioElement = window.HTMLAudioElement; + + function HTMLAudioElement(node) { + HTMLMediaElement.call(this, node); + } + HTMLAudioElement.prototype = Object.create(HTMLMediaElement.prototype); + + registerWrapper(OriginalHTMLAudioElement, HTMLAudioElement, + document.createElement('audio')); + + function Audio(src) { + if (!(this instanceof Audio)) { + throw new TypeError( + 'DOM object constructor cannot be called as a function.'); + } + + var node = unwrap(document.createElement('audio')); + HTMLMediaElement.call(this, node); + rewrap(node, this); + + node.setAttribute('preload', 'auto'); + if (src !== undefined) + node.setAttribute('src', src); + } + + Audio.prototype = HTMLAudioElement.prototype; + + scope.wrappers.HTMLAudioElement = HTMLAudioElement; + scope.wrappers.Audio = Audio; +})(this.ShadowDOMPolyfill); diff --git a/src/wrappers/HTMLImageElement.js b/src/wrappers/HTMLImageElement.js index 8168413..f85a009 100644 --- a/src/wrappers/HTMLImageElement.js +++ b/src/wrappers/HTMLImageElement.js @@ -27,12 +27,13 @@ } var node = unwrap(document.createElement('img')); + HTMLElement.call(this, node); + rewrap(node, this); + if (width !== undefined) node.width = width; if (height !== undefined) node.height = height; - HTMLElement.call(this, node); - rewrap(node, this); } Image.prototype = HTMLImageElement.prototype; diff --git a/src/wrappers/HTMLMediaElement.js b/src/wrappers/HTMLMediaElement.js new file mode 100644 index 0000000..325b080 --- /dev/null +++ b/src/wrappers/HTMLMediaElement.js @@ -0,0 +1,22 @@ +// Copyright 2013 The Polymer Authors. All rights reserved. +// Use of this source code is goverened by a BSD-style +// license that can be found in the LICENSE file. + +(function(scope) { + 'use strict'; + + var HTMLElement = scope.wrappers.HTMLElement; + var registerWrapper = scope.registerWrapper; + + var OriginalHTMLMediaElement = window.HTMLMediaElement; + + function HTMLMediaElement(node) { + HTMLElement.call(this, node); + } + HTMLMediaElement.prototype = Object.create(HTMLElement.prototype); + + registerWrapper(OriginalHTMLMediaElement, HTMLMediaElement, + document.createElement('audio')); + + scope.wrappers.HTMLMediaElement = HTMLMediaElement; +})(this.ShadowDOMPolyfill); diff --git a/src/wrappers/HTMLOptionElement.js b/src/wrappers/HTMLOptionElement.js new file mode 100644 index 0000000..cee1cfc --- /dev/null +++ b/src/wrappers/HTMLOptionElement.js @@ -0,0 +1,63 @@ +// Copyright 2013 The Polymer Authors. All rights reserved. +// Use of this source code is goverened by a BSD-style +// license that can be found in the LICENSE file. + +(function(scope) { + 'use strict'; + + var HTMLElement = scope.wrappers.HTMLElement; + var mixin = scope.mixin; + var registerWrapper = scope.registerWrapper; + var rewrap = scope.rewrap; + var unwrap = scope.unwrap; + var wrap = scope.wrap; + + var OriginalHTMLOptionElement = window.HTMLOptionElement; + + function trimText(s) { + return s.replace(/\s+/g, ' ').trim(); + } + + function HTMLOptionElement(node) { + HTMLElement.call(this, node); + } + HTMLOptionElement.prototype = Object.create(HTMLElement.prototype); + mixin(HTMLOptionElement.prototype, { + get text() { + return trimText(this.textContent); + }, + set text(value) { + this.textContent = trimText(String(value)); + }, + get form() { + return wrap(unwrap(this).form); + } + }); + + registerWrapper(OriginalHTMLOptionElement, HTMLOptionElement, + document.createElement('option')); + + function Option(text, value, defaultSelected, selected) { + if (!(this instanceof Option)) { + throw new TypeError( + 'DOM object constructor cannot be called as a function.'); + } + + var node = unwrap(document.createElement('option')); + HTMLElement.call(this, node); + rewrap(node, this); + + if (text !== undefined) + node.text = text; + if (value !== undefined) + node.setAttribute('value', value); + if (defaultSelected === true) + node.setAttribute('selected', ''); + node.selected = selected === true; + } + + Option.prototype = HTMLOptionElement.prototype; + + scope.wrappers.HTMLOptionElement = HTMLOptionElement; + scope.wrappers.Option = Option; +})(this.ShadowDOMPolyfill); diff --git a/src/wrappers/elements-with-form-property.js b/src/wrappers/elements-with-form-property.js index 1617ada..b07778e 100644 --- a/src/wrappers/elements-with-form-property.js +++ b/src/wrappers/elements-with-form-property.js @@ -20,7 +20,7 @@ 'HTMLLabelElement', 'HTMLLegendElement', 'HTMLObjectElement', - 'HTMLOptionElement', + // HTMLOptionElement is handled in HTMLOptionElement.js 'HTMLOutputElement', 'HTMLSelectElement', 'HTMLTextAreaElement', diff --git a/src/wrappers/override-constructors.js b/src/wrappers/override-constructors.js index 2b0af6d..18f88fc 100644 --- a/src/wrappers/override-constructors.js +++ b/src/wrappers/override-constructors.js @@ -13,7 +13,6 @@ 'a': 'HTMLAnchorElement', 'applet': 'HTMLAppletElement', 'area': 'HTMLAreaElement', - 'audio': 'HTMLAudioElement', 'br': 'HTMLBRElement', 'base': 'HTMLBaseElement', 'body': 'HTMLBodyElement', @@ -42,7 +41,6 @@ 'link': 'HTMLLinkElement', 'map': 'HTMLMapElement', 'marquee': 'HTMLMarqueeElement', - // 'media', Covered by audio and video 'menu': 'HTMLMenuElement', 'menuitem': 'HTMLMenuItemElement', 'meta': 'HTMLMetaElement', diff --git a/test/js/HTMLAudioElement.js b/test/js/HTMLAudioElement.js new file mode 100644 index 0000000..8716329 --- /dev/null +++ b/test/js/HTMLAudioElement.js @@ -0,0 +1,50 @@ +/* + * Copyright 2013 The Polymer Authors. All rights reserved. + * Use of this source code is goverened by a BSD-style + * license that can be found in the LICENSE file. + */ + +suite('HTMLAudioElement', function() { + + test('instanceof', function() { + var audio = document.createElement('audio'); + assert.instanceOf(audio, HTMLAudioElement); + assert.instanceOf(audio, Audio); + assert.instanceOf(audio, HTMLMediaElement); + assert.instanceOf(audio, HTMLElement); + }); + + test('Audio', function() { + var audio = new Audio(); + assert.instanceOf(audio, HTMLAudioElement); + assert.instanceOf(audio, Audio); + assert.instanceOf(audio, HTMLMediaElement); + assert.instanceOf(audio, HTMLElement); + }); + + test('Audio arguments', function() { + var audio = new Audio(); + assert.isFalse(audio.hasAttribute('src')); + assert.equal(audio.getAttribute('preload', 'auto')); + + var src = 'foo.wav'; + var audio = new Audio(src); + assert.equal(audio.getAttribute('src', 'foo.wav')); + }); + + test('Audio called as function', function() { + assert.throws(Audio, TypeError); + }); + + test('Audio basics', function() { + var audio = new Audio(); + assert.equal('audio', audio.localName); + + var div = document.createElement('div'); + div.appendChild(audio); + + assert.equal(div.firstChild, audio); + assert.equal('
', div.outerHTML); + }); + +}); diff --git a/test/js/HTMLOptionElement.js b/test/js/HTMLOptionElement.js index 3823a35..cfe6326 100644 --- a/test/js/HTMLOptionElement.js +++ b/test/js/HTMLOptionElement.js @@ -15,4 +15,65 @@ suite('HTMLOptionElement', function() { assert.equal(option.form, form); }); + test('instanceof', function() { + var option = document.createElement('option'); + assert.instanceOf(option, HTMLOptionElement); + assert.instanceOf(option, Option); + assert.instanceOf(option, HTMLElement); + }); + + test('Option', function() { + var option = new Option(); + assert.instanceOf(option, HTMLOptionElement); + assert.instanceOf(option, Option); + assert.instanceOf(option, HTMLElement); + }); + + test('Option arguments', function() { + var option = new Option(); + assert.equal(option.text, ''); + assert.equal(option.value, ''); + assert.isFalse(option.defaultSelected); + assert.isFalse(option.selected); + + var option = new Option(' more text '); + assert.equal(option.text, 'more text'); + assert.equal(option.value, 'more text'); + assert.isFalse(option.defaultSelected); + assert.isFalse(option.selected); + + var option = new Option('text', 'value'); + assert.equal(option.text, 'text'); + assert.equal(option.value, 'value'); + assert.isFalse(option.defaultSelected); + assert.isFalse(option.selected); + + var option = new Option('text', 'value', true); + assert.equal(option.text, 'text'); + assert.equal(option.value, 'value'); + assert.isTrue(option.defaultSelected); + assert.isFalse(option.selected); + + var option = new Option('text', 'value', true, true); + assert.equal(option.text, 'text'); + assert.equal(option.value, 'value'); + assert.isTrue(option.defaultSelected); + assert.isTrue(option.selected); + }); + + test('Option called as function', function() { + assert.throws(Option, TypeError); + }); + + test('Option basics', function() { + var option = new Option(); + assert.equal('option', option.localName); + + var select = document.createElement('select'); + select.appendChild(option); + + assert.equal(select.firstChild, option); + assert.equal('', select.outerHTML); + }); + }); diff --git a/test/test.main.js b/test/test.main.js index 86b653f..3f2da9a 100644 --- a/test/test.main.js +++ b/test/test.main.js @@ -54,6 +54,7 @@ var modules = [ 'Comment.js', 'Document.js', 'Element.js', + 'HTMLAudioElement.js', 'HTMLBodyElement.js', 'HTMLButtonElement.js', 'HTMLCanvasElement.js',