From 702a0af1e84abd575b4b1bc5adf8413de9b188e3 Mon Sep 17 00:00:00 2001 From: Caridy Date: Wed, 28 Jun 2017 12:38:35 -0400 Subject: [PATCH] fixes issue #306 and others: boolean attributes alignment with HTML --- src/modules/attributes.ts | 22 ++++------------------ test/attributes.js | 39 ++++++++++++++++++++++++--------------- 2 files changed, 28 insertions(+), 33 deletions(-) diff --git a/src/modules/attributes.ts b/src/modules/attributes.ts index a2fa0b0..875cdaf 100755 --- a/src/modules/attributes.ts +++ b/src/modules/attributes.ts @@ -3,22 +3,10 @@ import {Module} from './module'; export type Attrs = Record -const booleanAttrs = ["allowfullscreen", "async", "autofocus", "autoplay", "checked", "compact", "controls", "declare", - "default", "defaultchecked", "defaultmuted", "defaultselected", "defer", "disabled", - "enabled", "formnovalidate", "hidden", "indeterminate", "inert", "ismap", "itemscope", "loop", "multiple", - "muted", "nohref", "noresize", "noshade", "novalidate", "nowrap", "open", "pauseonexit", "readonly", - "required", "reversed", "scoped", "seamless", "selected", "sortable", "spellcheck", "translate", - "truespeed", "typemustmatch", "visible"]; - const xlinkNS = 'http://www.w3.org/1999/xlink'; const xmlNS = 'http://www.w3.org/XML/1998/namespace'; const colonChar = 58; const xChar = 120; -const booleanAttrsDict: {[attribute: string]: boolean} = Object.create(null); - -for (let i = 0, len = booleanAttrs.length; i < len; i++) { - booleanAttrsDict[booleanAttrs[i]] = true; -} function updateAttrs(oldVnode: VNode, vnode: VNode): void { var key: string, elm: Element = vnode.elm as Element, @@ -35,12 +23,10 @@ function updateAttrs(oldVnode: VNode, vnode: VNode): void { const cur = attrs[key]; const old = oldAttrs[key]; if (old !== cur) { - if (booleanAttrsDict[key]) { - if (cur) { - elm.setAttribute(key, ""); - } else { - elm.removeAttribute(key); - } + if (cur === true) { + elm.setAttribute(key, ""); + } else if (cur === false) { + elm.removeAttribute(key); } else { // because those in TypeScript are too restrictive: https://github.com/Microsoft/TSJS-lib-generator/pull/237 type SetAttribute = (name: string, value: string | number | boolean) => void; diff --git a/test/attributes.js b/test/attributes.js index 74538da..bef6e4d 100644 --- a/test/attributes.js +++ b/test/attributes.js @@ -13,31 +13,34 @@ describe('attributes', function() { vnode0 = elm; }); it('have their provided values', function() { - var vnode1 = h('div', {attrs: {href: '/foo', minlength: 1, value: true}}); + var vnode1 = h('div', {attrs: {href: '/foo', minlength: 1, selected: true, disabled: false}}); elm = patch(vnode0, vnode1).elm; assert.strictEqual(elm.getAttribute('href'), '/foo'); assert.strictEqual(elm.getAttribute('minlength'), '1'); - assert.strictEqual(elm.getAttribute('value'), 'true'); + assert.strictEqual(elm.hasAttribute('selected'), true); + assert.strictEqual(elm.getAttribute('selected'), ''); + assert.strictEqual(elm.hasAttribute('disabled'), false); }); it('can be memoized', function() { - var cachedAttrs = {href: '/foo', minlength: 1, value: true}; + var cachedAttrs = {href: '/foo', minlength: 1, selected: true}; var vnode1 = h('div', {attrs: cachedAttrs}); var vnode2 = h('div', {attrs: cachedAttrs}); elm = patch(vnode0, vnode1).elm; assert.strictEqual(elm.getAttribute('href'), '/foo'); assert.strictEqual(elm.getAttribute('minlength'), '1'); - assert.strictEqual(elm.getAttribute('value'), 'true'); + assert.strictEqual(elm.getAttribute('selected'), ''); elm = patch(vnode1, vnode2).elm; assert.strictEqual(elm.getAttribute('href'), '/foo'); assert.strictEqual(elm.getAttribute('minlength'), '1'); - assert.strictEqual(elm.getAttribute('value'), 'true'); + assert.strictEqual(elm.getAttribute('selected'), ''); }); it('are not omitted when falsy values are provided', function() { - var vnode1 = h('div', {attrs: {href: null, minlength: 0, value: false}}); + var vnode1 = h('div', {attrs: {href: null, minlength: 0, value: '', title:'undefined'}}); elm = patch(vnode0, vnode1).elm; assert.strictEqual(elm.getAttribute('href'), 'null'); assert.strictEqual(elm.getAttribute('minlength'), '0'); - assert.strictEqual(elm.getAttribute('value'), 'false'); + assert.strictEqual(elm.getAttribute('value'), ''); + assert.strictEqual(elm.getAttribute('title'), 'undefined'); }); it('are set correctly when namespaced', function() { var vnode1 = h('div', {attrs: {'xlink:href': '#foo'}}); @@ -63,26 +66,32 @@ describe('attributes', function() { assert.strictEqual(elm.hasAttribute('required'), true); assert.strictEqual(elm.getAttribute('required'), ''); assert.strictEqual(elm.hasAttribute('readonly'), true); - assert.strictEqual(elm.getAttribute('readonly'), ''); + assert.strictEqual(elm.getAttribute('readonly'), '1'); assert.strictEqual(elm.hasAttribute('noresize'), true); - assert.strictEqual(elm.getAttribute('noresize'), ''); + assert.strictEqual(elm.getAttribute('noresize'), 'truthy'); }); - it('is omitted if the value is falsy', function() { - var vnode1 = h('div', {attrs: {required: false, readonly: 0, noresize: null}}); + it('is omitted if the value is false', function() { + var vnode1 = h('div', {attrs: {required: false}}); elm = patch(vnode0, vnode1).elm; + assert.strictEqual(elm.hasAttribute('required'), false); assert.strictEqual(elm.getAttribute('required'), null); - assert.strictEqual(elm.getAttribute('readonly'), null); - assert.strictEqual(elm.getAttribute('noresize'), null); + }); + it('is not omitted if the value is falsy but casted to string', function() { + var vnode1 = h('div', {attrs: {readonly: 0, noresize: null}}); + elm = patch(vnode0, vnode1).elm; + assert.strictEqual(elm.getAttribute('readonly'), '0'); + assert.strictEqual(elm.getAttribute('noresize'), 'null'); }); }); describe('Object.prototype property', function() { it('is not considered as a boolean attribute and shouldn\'t be omitted', function() { var vnode1 = h('div', {attrs: {constructor: true}}); elm = patch(vnode0, vnode1).elm; - assert.strictEqual(elm.getAttribute('constructor'), 'true'); + assert.strictEqual(elm.hasAttribute('constructor'), true); + assert.strictEqual(elm.getAttribute('constructor'), ''); var vnode2 = h('div', {attrs: {constructor: false}}); elm = patch(vnode0, vnode2).elm; - assert.strictEqual(elm.getAttribute('constructor'), 'false'); + assert.strictEqual(elm.hasAttribute('constructor'), false); }); }); });