From 2866b11c7d43b6a9ae9bc573d1d42c032ff14aee Mon Sep 17 00:00:00 2001 From: Rich Harris Date: Sun, 29 Apr 2018 18:32:28 -0400 Subject: [PATCH 1/6] WIP towards #984 --- src/compile/nodes/Binding.ts | 17 +- src/compile/nodes/Element.ts | 9 +- src/shared/dom.js | 25 +++ src/validate/html/validateElement.ts | 2 +- .../bind-width-height.solo/expected-bundle.js | 178 ++++++++++++++++++ .../bind-width-height.solo/expected.js | 50 +++++ .../samples/bind-width-height.solo/input.html | 3 + 7 files changed, 278 insertions(+), 6 deletions(-) create mode 100644 test/js/samples/bind-width-height.solo/expected-bundle.js create mode 100644 test/js/samples/bind-width-height.solo/expected.js create mode 100644 test/js/samples/bind-width-height.solo/input.html diff --git a/src/compile/nodes/Binding.ts b/src/compile/nodes/Binding.ts index 3c56da0f43..bbe8aa46ac 100644 --- a/src/compile/nodes/Binding.ts +++ b/src/compile/nodes/Binding.ts @@ -14,6 +14,9 @@ const readOnlyMediaAttributes = new Set([ 'played' ]); +// TODO a lot of this element-specific stuff should live in Element — +// Binding should ideally be agnostic between Element and Component + export default class Binding extends Node { name: string; value: Expression; @@ -57,7 +60,10 @@ export default class Binding extends Node { const node: Element = this.parent; const needsLock = node.name !== 'input' || !/radio|checkbox|range|color/.test(node.getStaticAttributeValue('type')); - const isReadOnly = node.isMediaNode() && readOnlyMediaAttributes.has(this.name); + const isReadOnly = ( + (node.isMediaNode() && readOnlyMediaAttributes.has(this.name)) || + this.name === 'width' || this.name === 'height' + ); let updateCondition: string; @@ -103,8 +109,7 @@ export default class Binding extends Node { if (this.name === 'currentTime' || this.name === 'volume') { updateCondition = `!isNaN(${snippet})`; - if (this.name === 'currentTime') - initialUpdate = null; + if (this.name === 'currentTime') initialUpdate = null; } if (this.name === 'paused') { @@ -117,6 +122,12 @@ export default class Binding extends Node { initialUpdate = null; } + // bind:width and bind:height + if (this.name === 'width' || this.name === 'height') { + initialUpdate = null; + updateDom = null; + } + return { name: this.name, object: name, diff --git a/src/compile/nodes/Element.ts b/src/compile/nodes/Element.ts index a025eb7b05..3b84b0c369 100644 --- a/src/compile/nodes/Element.ts +++ b/src/compile/nodes/Element.ts @@ -262,7 +262,7 @@ export default class Element extends Node { parentNode; block.addVariable(name); - const renderStatement = getRenderStatement(this.compiler, this.namespace, this.name); + const renderStatement = getRenderStatement(this.namespace, this.name); block.builders.create.addLine( `${name} = ${renderStatement};` ); @@ -916,7 +916,6 @@ export default class Element extends Node { } function getRenderStatement( - compiler: Compiler, namespace: string, name: string ) { @@ -971,6 +970,12 @@ const events = [ node.name === 'input' && /radio|checkbox|range/.test(node.getStaticAttributeValue('type')) }, + { + eventNames: ['resize'], + filter: (node: Element, name: string) => + (name === 'width' || name === 'height') + }, + // media events { eventNames: ['timeupdate'], diff --git a/src/shared/dom.js b/src/shared/dom.js index 0eb53585d7..5661a121c1 100644 --- a/src/shared/dom.js +++ b/src/shared/dom.js @@ -193,3 +193,28 @@ export function selectMultipleValue(select) { return option.__value; }); } + +export function addResizeListener(element, fn) { + if (getComputedStyle(element).position === 'static') { + element.style.position = 'relative'; + } + + const object = document.createElement('object'); + object.setAttribute('style', 'display: block; position: absolute; top: 0; left: 0; height: 100%; width: 100%; overflow: hidden; pointer-events: none; z-index: -1;'); + object.type = 'text/html'; + + if (isIE) element.appendChild(object); + object.data = 'about:blank'; + if (!isIE) element.appendChild(object); + + object.onload = () => { + object.contentDocument.defaultView.addEventListener('resize', fn); + }; + + return { + cancel: () => { + object.contentDocument.defaultView.removeEventListener('resize', fn); + element.removeChild(object); + } + }; +} \ No newline at end of file diff --git a/src/validate/html/validateElement.ts b/src/validate/html/validateElement.ts index 83de0b49aa..3e73d390b1 100644 --- a/src/validate/html/validateElement.ts +++ b/src/validate/html/validateElement.ts @@ -157,7 +157,7 @@ export default function validateElement( message: `'${name}' binding can only be used with