diff --git a/site/content/examples/parallax/App.html b/site/content/examples/parallax/App.html
index fa2399d6f8..c7781e7a3f 100644
--- a/site/content/examples/parallax/App.html
+++ b/site/content/examples/parallax/App.html
@@ -1,3 +1,7 @@
+
+
diff --git a/site/src/routes/index.html b/site/src/routes/index.html
index f058be3a82..9cb7be24f8 100644
--- a/site/src/routes/index.html
+++ b/site/src/routes/index.html
@@ -112,7 +112,7 @@
Svelte • The magical disappearing UI framework
-
+
diff --git a/site/static/workers/compiler.js b/site/static/workers/compiler.js
index 7759c492a3..c20b416588 100644
--- a/site/static/workers/compiler.js
+++ b/site/static/workers/compiler.js
@@ -21,7 +21,8 @@ self.addEventListener('message', async event => {
});
const commonCompilerOptions = {
- dev: false
+ dev: false,
+ css: false
};
function compile({ source, options, entry }) {
diff --git a/src/compile/render-dom/wrappers/Window.ts b/src/compile/render-dom/wrappers/Window.ts
index 29e8ab82d3..98e4e65f65 100644
--- a/src/compile/render-dom/wrappers/Window.ts
+++ b/src/compile/render-dom/wrappers/Window.ts
@@ -68,9 +68,9 @@ export default class WindowWrapper extends Wrapper {
});
});
- const lock = block.getUniqueName(`window_updating`);
- const clear = block.getUniqueName(`clear_window_updating`);
- const timeout = block.getUniqueName(`window_updating_timeout`);
+ const scrolling = block.getUniqueName(`scrolling`);
+ const clear_scrolling = block.getUniqueName(`clear_scrolling`);
+ const scrolling_timeout = block.getUniqueName(`scrolling_timeout`);
Object.keys(events).forEach(event => {
const handler_name = block.getUniqueName(`onwindow${event}`);
@@ -78,9 +78,9 @@ export default class WindowWrapper extends Wrapper {
if (event === 'scroll') {
// TODO other bidirectional bindings...
- block.addVariable(lock, 'false');
- block.addVariable(clear, `function() { ${lock} = false; }`);
- block.addVariable(timeout);
+ block.addVariable(scrolling, 'false');
+ block.addVariable(clear_scrolling, `() => { ${scrolling} = false }`);
+ block.addVariable(scrolling_timeout);
const condition = [
bindings.scrollX && `"${bindings.scrollX}" in this._state`,
@@ -97,58 +97,61 @@ export default class WindowWrapper extends Wrapper {
${x && `${x} = window.pageXOffset;`}
${y && `${y} = window.pageYOffset;`}
`);
+
+ block.event_listeners.push(deindent`
+ @addListener(window, "${event}", () => {
+ ${scrolling} = true;
+ clearTimeout(${scrolling_timeout});
+ ${scrolling_timeout} = setTimeout(${clear_scrolling}, 100);
+ ctx.${handler_name}();
+ })
+ `);
} else {
props.forEach(prop => {
renderer.metaBindings.addLine(
`this._state.${prop.name} = window.${prop.value};`
);
});
+
+ block.event_listeners.push(deindent`
+ @addListener(window, "${event}", ctx.${handler_name});
+ `);
}
component.declarations.push(handler_name);
component.template_references.add(handler_name);
component.partly_hoisted.push(deindent`
function ${handler_name}() {
- ${event === 'scroll' && deindent`
- if (${lock}) return;
- ${lock} = true;
- `}
${props.map(prop => `${prop.name} = window.${prop.value}; $$make_dirty('${prop.name}');`)}
- ${event === 'scroll' && `${lock} = false;`}
}
`);
+
+
block.builders.init.addBlock(deindent`
- window.addEventListener("${event}", ctx.${handler_name});
@add_render_callback(ctx.${handler_name});
`);
- block.builders.destroy.addBlock(deindent`
- window.removeEventListener("${event}", ctx.${handler_name});
- `);
-
component.has_reactive_assignments = true;
});
// special case... might need to abstract this out if we add more special cases
if (bindings.scrollX || bindings.scrollY) {
- block.builders.init.addBlock(deindent`
- #component.$on("state", ({ changed, current }) => {
- if (${
- [bindings.scrollX, bindings.scrollY].map(
- binding => binding && `changed["${binding}"]`
- ).filter(Boolean).join(' || ')
- } && !${lock}) {
- ${lock} = true;
- clearTimeout(${timeout});
- window.scrollTo(${
- bindings.scrollX ? `current["${bindings.scrollX}"]` : `window.pageXOffset`
- }, ${
- bindings.scrollY ? `current["${bindings.scrollY}"]` : `window.pageYOffset`
- });
- ${timeout} = setTimeout(${clear}, 100);
- }
- });
+ block.builders.update.addBlock(deindent`
+ if (${
+ [bindings.scrollX, bindings.scrollY].filter(Boolean).map(
+ b => `changed.${b}`
+ ).join(' || ')
+ } && !${scrolling}) {
+ ${scrolling} = true;
+ clearTimeout(${scrolling_timeout});
+ window.scrollTo(${
+ bindings.scrollX ? `current["${bindings.scrollX}"]` : `window.pageXOffset`
+ }, ${
+ bindings.scrollY ? `current["${bindings.scrollY}"]` : `window.pageYOffset`
+ });
+ ${scrolling_timeout} = setTimeout(${clear_scrolling}, 100);
+ }
`);
}
diff --git a/test/js/samples/window-binding-scroll/expected.js b/test/js/samples/window-binding-scroll/expected.js
index fee92a8d45..0600a211ee 100644
--- a/test/js/samples/window-binding-scroll/expected.js
+++ b/test/js/samples/window-binding-scroll/expected.js
@@ -1,26 +1,22 @@
/* generated by Svelte vX.Y.Z */
-import { SvelteComponent as SvelteComponent_1, add_render_callback, append, createElement, createText, detachNode, flush, init, insert, run, safe_not_equal, setData } from "svelte/internal";
+import { SvelteComponent as SvelteComponent_1, addListener, add_render_callback, append, createElement, createText, detachNode, flush, init, insert, run, safe_not_equal, setData } from "svelte/internal";
function create_fragment(component, ctx) {
- var window_updating = false, clear_window_updating = function() { window_updating = false; }, window_updating_timeout, p, text0, text1, current;
+ var scrolling = false, clear_scrolling = () => { scrolling = false }, scrolling_timeout, p, text0, text1, current, dispose;
- window.addEventListener("scroll", ctx.onwindowscroll);
add_render_callback(ctx.onwindowscroll);
- component.$on("state", ({ changed, current }) => {
- if (changed["y"] && !window_updating) {
- window_updating = true;
- clearTimeout(window_updating_timeout);
- window.scrollTo(window.pageXOffset, current["y"]);
- window_updating_timeout = setTimeout(clear_window_updating, 100);
- }
- });
-
return {
c() {
p = createElement("p");
text0 = createText("scrolled to ");
text1 = createText(ctx.y);
+ dispose = addListener(window, "scroll", () => {
+ scrolling = true;
+ clearTimeout(scrolling_timeout);
+ scrolling_timeout = setTimeout(clear_scrolling, 100);
+ ctx.onwindowscroll();
+ });
},
m(target, anchor) {
@@ -31,6 +27,13 @@ function create_fragment(component, ctx) {
},
p(changed, ctx) {
+ if (changed.y && !scrolling) {
+ scrolling = true;
+ clearTimeout(scrolling_timeout);
+ window.scrollTo(window.pageXOffset, current["y"]);
+ scrolling_timeout = setTimeout(clear_scrolling, 100);
+ }
+
if (changed.y) {
setData(text1, ctx.y);
}
@@ -44,11 +47,11 @@ function create_fragment(component, ctx) {
o: run,
d(detach) {
- window.removeEventListener("scroll", ctx.onwindowscroll);
-
if (detach) {
detachNode(p);
}
+
+ dispose();
}
};
}
@@ -57,10 +60,7 @@ function define($$self, $$props, $$make_dirty) {
let { y } = $$props;
function onwindowscroll() {
- if (window_updating) return;
- window_updating = true;
y = window.pageYOffset; $$make_dirty('y');
- window_updating = false;
}
$$self.$$.get = () => ({ y, onwindowscroll });