From 193a68576623c7d0348c84c6b34e15207242ae61 Mon Sep 17 00:00:00 2001 From: taoqf Date: Thu, 6 Feb 2020 11:36:32 +0800 Subject: [PATCH] :bug: issue #17 --- src/nodes/html.ts | 52 ++++++++++++++++++++++++++++-------------- test/html.js | 58 +++++++++++++++++++++++++++++++++++++++++------ 2 files changed, 86 insertions(+), 24 deletions(-) diff --git a/src/nodes/html.ts b/src/nodes/html.ts index 338d4af..1890224 100644 --- a/src/nodes/html.ts +++ b/src/nodes/html.ts @@ -431,37 +431,55 @@ export default class HTMLElement extends Node { return attrs; } + public removeAttribute(key: string) { + const attrs = this.rawAttributes; + delete attrs[key]; + // Update this.attribute + if (this._attrs) { + delete this._attrs[key]; + } + // Update rawString + this.rawAttrs = Object.keys(attrs).map((name) => { + const val = JSON.stringify(attrs[name]); + if (val === undefined || val === 'null') { + return name; + } else { + return name + '=' + val; + } + }).join(' '); + } + + public hasAttribute(key: string) { + console.error(this.attributes, key); + return key in this.attributes; + } + /** * Get an attribute * @return {string} value of the attribute */ - getAttribute(key: string) { - return this.attributes[key] || null; + public getAttribute(key: string) { + return this.attributes[key]; } /** * Set an attribute value to the HTMLElement * @param {string} key The attribute name - * @param {string|number} value The value to set, or null / undefined to remove an attribute + * @param {string} value The value to set, or null / undefined to remove an attribute */ - setAttribute(key: string, value: string | number) { + public setAttribute(key: string, value: string) { + if (arguments.length < 2) { + throw new Error('Failed to execute \'setAttribute\' on \'Element\''); + } const attrs = this.rawAttributes; - if (value === undefined || value === null) { - delete attrs[key]; - // Update this.attribute - if (this._attrs && this._attrs[key]) { - delete this._attrs[key]; - } - } else { - attrs[key] = String(value); - if (this._attrs) { - this._attrs[key] = decode(attrs[key]); - } + attrs[key] = String(value); + if (this._attrs) { + this._attrs[key] = decode(attrs[key]); } // Update rawString this.rawAttrs = Object.keys(attrs).map((name) => { const val = JSON.stringify(attrs[name]); - if (val === undefined || val === null) { + if (val === undefined || val === 'null') { return name; } else { return name + '=' + val; @@ -473,7 +491,7 @@ export default class HTMLElement extends Node { * Replace all the attributes of the HTMLElement by the provided attributes * @param {Attributes} attributes the new attribute set */ - setAttributes(attributes: Attributes) { + public setAttributes(attributes: Attributes) { // Invalidate current this.attributes if (this._attrs) { delete this._attrs; diff --git a/test/html.js b/test/html.js index 2dca353..8ba5645 100644 --- a/test/html.js +++ b/test/html.js @@ -329,6 +329,19 @@ describe('HTML Parser', function () { var root = parseHTML('

'); should.equal(root.firstChild.getAttribute('b'), null); }); + + it('should return empty string as broser behavior', function () { + var root = parseHTML(''); + var input = root.firstChild; + input.getAttribute('required').should.eql(''); + }); + + it('should return null as broser behavior', function () { + var root = parseHTML(''); + var input = root.firstChild; + input.setAttribute('readonly', null); + input.getAttribute('readonly').should.eql('null'); + }); }); describe('#setAttribute', function () { @@ -351,14 +364,20 @@ describe('HTML Parser', function () { }); root.firstChild.toString().should.eql('

'); }); - it('should remove an attribute from the element', function () { + it('should convert value to string', function () { var root = parseHTML('

'); - root.firstChild.setAttribute('b', null); - root.firstChild.setAttribute('c'); - root.firstChild.attributes.should.eql({ - 'a': '12', - }); - root.firstChild.toString().should.eql('

'); + var p = root.firstChild; + p.setAttribute('b', null); + p.setAttribute('c', undefined); + p.getAttribute('b').should.eql('null'); + p.getAttribute('c').should.eql('undefined'); + p.toString().should.eql('

'); + }); + it('should throw type Error', function () { + var root = parseHTML('

'); + var p = root.firstChild; + should.throws(function () { p.setAttribute('b') }); + should.throws(function () { p.setAttribute() }); }); it('should keep quotes arount value', function () { var root = parseHTML('

'); @@ -389,6 +408,21 @@ describe('HTML Parser', function () { }); }); + describe('#removeAttribute', function () { + var root = parseHTML(''); + var input = root.firstChild; + input.removeAttribute('required'); + input.toString().should.eql(''); + }); + + describe('#hasAttribute', function () { + var root = parseHTML(''); + var input = root.firstChild; + input.hasAttribute('required').should.eql(true); + input.removeAttribute('required'); + input.hasAttribute('required').should.eql(false); + }); + describe('#querySelector()', function () { it('should return correct elements in DOM tree', function () { var root = parseHTML('
'); @@ -469,6 +503,16 @@ describe('HTML Parser', function () { root.toString().should.eql('
abc
'); }); }); + + describe('encode/decode', function () { + it('should decode attributes value', function () { + var root = parseHTML('Verissimo, Ilaria D'Amico: «Sogno una bambina. Buffon mi ha chiesto in moglie tante volte»'); + root.firstChild.getAttribute('alt').should.eql(`Verissimo, Ilaria D'Amico: «Sogno una bambina. Buffon mi ha chiesto in moglie tante volte»`); + root.firstChild.attributes.alt.should.eql(`Verissimo, Ilaria D'Amico: «Sogno una bambina. Buffon mi ha chiesto in moglie tante volte»`); + root.firstChild.setAttribute('alt', '«Sogno'); + root.firstChild.getAttribute('alt').should.eql('«Sogno'); + }); + }); }); describe('stringify', function () {