From 297ea67ebe01ecca8168dbf694cca38f22eae472 Mon Sep 17 00:00:00 2001 From: Rich Harris Date: Thu, 4 Jan 2018 21:30:52 -0500 Subject: [PATCH] lock scroll bindings to allow tweening - fixes #1071 --- src/generators/nodes/Window.ts | 16 +++++++++++++--- .../window-binding-scroll/expected-bundle.js | 7 +++++-- .../js/samples/window-binding-scroll/expected.js | 7 +++++-- 3 files changed, 23 insertions(+), 7 deletions(-) diff --git a/src/generators/nodes/Window.ts b/src/generators/nodes/Window.ts index 6396577003..f8741464c2 100644 --- a/src/generators/nodes/Window.ts +++ b/src/generators/nodes/Window.ts @@ -1,3 +1,4 @@ +import CodeBuilder from '../../utils/CodeBuilder'; import deindent from '../../utils/deindent'; import { stringify } from '../../utils/stringify'; import flattenReference from '../../utils/flattenReference'; @@ -106,6 +107,7 @@ export default class Window extends Node { }); const lock = block.getUniqueName(`window_updating`); + const timeout = block.getUniqueName(`window_updating_timeout`); Object.keys(events).forEach(event => { const handlerName = block.getUniqueName(`onwindow${event}`); @@ -114,10 +116,14 @@ export default class Window extends Node { if (event === 'scroll') { // TODO other bidirectional bindings... block.addVariable(lock, 'false'); + block.addVariable(timeout,); } const handlerBody = deindent` - ${event === 'scroll' && `${lock} = true;`} + ${event === 'scroll' && deindent` + if (${lock}) return; + ${lock} = true; + `} ${generator.options.dev && `component._updatingReadonlyProperty = true;`} #component.set({ @@ -146,7 +152,8 @@ export default class Window extends Node { block.builders.init.addBlock(deindent` function ${observerCallback}() { - if (${lock}) return; + ${lock} = true; + clearTimeout(${timeout}); var x = ${bindings.scrollX ? `#component.get("${bindings.scrollX}")` : `window.scrollX`}; @@ -154,6 +161,7 @@ export default class Window extends Node { ? `#component.get("${bindings.scrollY}")` : `window.scrollY`}; window.scrollTo(x, y); + ${timeout} = setTimeout(function() { ${lock} = false; }, 100); } `); @@ -170,8 +178,10 @@ export default class Window extends Node { block.builders.init.addBlock(deindent` #component.observe("${bindings.scrollX || bindings.scrollY}", function(${isX ? 'x' : 'y'}) { - if (${lock}) return; + ${lock} = true; + clearTimeout(${timeout}); window.scrollTo(${isX ? 'x, window.scrollY' : 'window.scrollX, y'}); + ${timeout} = setTimeout(function() { ${lock} = false; }, 100); }); `); } diff --git a/test/js/samples/window-binding-scroll/expected-bundle.js b/test/js/samples/window-binding-scroll/expected-bundle.js index b3dbd98a57..66bdfbdfb6 100644 --- a/test/js/samples/window-binding-scroll/expected-bundle.js +++ b/test/js/samples/window-binding-scroll/expected-bundle.js @@ -190,9 +190,10 @@ var proto = { /* generated by Svelte vX.Y.Z */ function create_main_fragment(state, component) { - var window_updating = false, p, text, text_1; + var window_updating = false, window_updating_timeout, p, text, text_1; function onwindowscroll(event) { + if (window_updating) return; window_updating = true; component.set({ @@ -203,8 +204,10 @@ function create_main_fragment(state, component) { window.addEventListener("scroll", onwindowscroll); component.observe("y", function(y) { - if (window_updating) return; + window_updating = true; + clearTimeout(window_updating_timeout); window.scrollTo(window.scrollX, y); + window_updating_timeout = setTimeout(function() { window_updating = false; }, 100); }); return { diff --git a/test/js/samples/window-binding-scroll/expected.js b/test/js/samples/window-binding-scroll/expected.js index 0387b24a05..8316428617 100644 --- a/test/js/samples/window-binding-scroll/expected.js +++ b/test/js/samples/window-binding-scroll/expected.js @@ -2,9 +2,10 @@ import { appendNode, assign, createElement, createText, detachNode, init, insertNode, proto } from "svelte/shared.js"; function create_main_fragment(state, component) { - var window_updating = false, p, text, text_1; + var window_updating = false, window_updating_timeout, p, text, text_1; function onwindowscroll(event) { + if (window_updating) return; window_updating = true; component.set({ @@ -15,8 +16,10 @@ function create_main_fragment(state, component) { window.addEventListener("scroll", onwindowscroll); component.observe("y", function(y) { - if (window_updating) return; + window_updating = true; + clearTimeout(window_updating_timeout); window.scrollTo(window.scrollX, y); + window_updating_timeout = setTimeout(function() { window_updating = false; }, 100); }); return {