mirror of https://github.com/sveltejs/svelte
parent
fdf371e2ff
commit
dca04b8d28
@ -1,38 +0,0 @@
|
|||||||
{
|
|
||||||
"root": true,
|
|
||||||
"rules": {
|
|
||||||
"indent": [ 2, "tab", { "SwitchCase": 1 } ],
|
|
||||||
"semi": [ 2, "always" ],
|
|
||||||
"keyword-spacing": [ 2, { "before": true, "after": true } ],
|
|
||||||
"space-before-blocks": [ 2, "always" ],
|
|
||||||
"no-mixed-spaces-and-tabs": [ 2, "smart-tabs" ],
|
|
||||||
"no-cond-assign": 0,
|
|
||||||
"no-unused-vars": 2,
|
|
||||||
"no-const-assign": 2,
|
|
||||||
"no-class-assign": 2,
|
|
||||||
"no-this-before-super": 2,
|
|
||||||
"no-unreachable": 2,
|
|
||||||
"valid-typeof": 2,
|
|
||||||
"quote-props": [ 2, "as-needed" ],
|
|
||||||
"arrow-spacing": 2,
|
|
||||||
"no-inner-declarations": 0
|
|
||||||
},
|
|
||||||
"env": {
|
|
||||||
"es6": true,
|
|
||||||
"browser": true,
|
|
||||||
"node": true,
|
|
||||||
"mocha": true
|
|
||||||
},
|
|
||||||
"extends": [
|
|
||||||
"eslint:recommended",
|
|
||||||
"plugin:import/errors",
|
|
||||||
"plugin:import/warnings"
|
|
||||||
],
|
|
||||||
"parserOptions": {
|
|
||||||
"ecmaVersion": 9,
|
|
||||||
"sourceType": "module"
|
|
||||||
},
|
|
||||||
"settings": {
|
|
||||||
"import/core-modules": [ "svelte" ]
|
|
||||||
}
|
|
||||||
}
|
|
@ -1,40 +0,0 @@
|
|||||||
const fs = require('fs');
|
|
||||||
const path = require('path');
|
|
||||||
const acorn = require('acorn');
|
|
||||||
|
|
||||||
const declarations = {};
|
|
||||||
|
|
||||||
fs.readdirSync(__dirname).forEach(file => {
|
|
||||||
if (!/^[a-z\-]+\.js$/.test(file)) return;
|
|
||||||
|
|
||||||
const source = fs.readFileSync(path.join(__dirname, file), 'utf-8');
|
|
||||||
const ast = acorn.parse(source, {
|
|
||||||
ecmaVersion: 9,
|
|
||||||
sourceType: 'module'
|
|
||||||
});
|
|
||||||
|
|
||||||
ast.body.forEach(node => {
|
|
||||||
if (node.type !== 'ExportNamedDeclaration') return;
|
|
||||||
|
|
||||||
const declaration = node.declaration;
|
|
||||||
if (!declaration) return;
|
|
||||||
|
|
||||||
const name = declaration.type === 'VariableDeclaration'
|
|
||||||
? declaration.declarations[0].id.name
|
|
||||||
: declaration.id.name;
|
|
||||||
|
|
||||||
const value = declaration.type === 'VariableDeclaration'
|
|
||||||
? declaration.declarations[0].init
|
|
||||||
: declaration;
|
|
||||||
|
|
||||||
declarations[name] = value ? source.slice(value.start, value.end) : 'null';
|
|
||||||
});
|
|
||||||
});
|
|
||||||
|
|
||||||
fs.writeFileSync(
|
|
||||||
'src/compile/shared.ts',
|
|
||||||
`// this file is auto-generated, do not edit it
|
|
||||||
const shared: Record<string, string> = ${JSON.stringify(declarations, null, '\t')};
|
|
||||||
|
|
||||||
export default shared;`
|
|
||||||
);
|
|
@ -1,102 +0,0 @@
|
|||||||
import { transitionManager, linear, generateRule, hash } from './transitions.js';
|
|
||||||
|
|
||||||
export function wrapAnimation(node, from, fn, params) {
|
|
||||||
if (!from) return;
|
|
||||||
|
|
||||||
const to = node.getBoundingClientRect();
|
|
||||||
if (from.left === to.left && from.right === to.right && from.top === to.top && from.bottom === to.bottom) return;
|
|
||||||
|
|
||||||
const info = fn(node, { from, to }, params);
|
|
||||||
|
|
||||||
const duration = 'duration' in info ? info.duration : 300;
|
|
||||||
const delay = 'delay' in info ? info.delay : 0;
|
|
||||||
const ease = info.easing || linear;
|
|
||||||
const start = window.performance.now() + delay;
|
|
||||||
const end = start + duration;
|
|
||||||
|
|
||||||
const program = {
|
|
||||||
a: 0,
|
|
||||||
t: 0,
|
|
||||||
b: 1,
|
|
||||||
delta: 1,
|
|
||||||
duration,
|
|
||||||
start,
|
|
||||||
end
|
|
||||||
};
|
|
||||||
|
|
||||||
const cssText = node.style.cssText;
|
|
||||||
|
|
||||||
const animation = {
|
|
||||||
pending: delay ? program : null,
|
|
||||||
program: delay ? null : program,
|
|
||||||
running: true,
|
|
||||||
|
|
||||||
start() {
|
|
||||||
if (info.css) {
|
|
||||||
if (delay) node.style.cssText = cssText;
|
|
||||||
|
|
||||||
const rule = generateRule(program, ease, info.css);
|
|
||||||
program.name = `__svelte_${hash(rule)}`;
|
|
||||||
|
|
||||||
transitionManager.addRule(rule, program.name);
|
|
||||||
|
|
||||||
node.style.animation = (node.style.animation || '')
|
|
||||||
.split(', ')
|
|
||||||
.filter(anim => anim && (program.delta < 0 || !/__svelte/.test(anim)))
|
|
||||||
.concat(`${program.name} ${program.duration}ms linear 1 forwards`)
|
|
||||||
.join(', ');
|
|
||||||
}
|
|
||||||
|
|
||||||
animation.program = program;
|
|
||||||
animation.pending = null;
|
|
||||||
},
|
|
||||||
|
|
||||||
update: now => {
|
|
||||||
const p = now - program.start;
|
|
||||||
const t = program.a + program.delta * ease(p / program.duration);
|
|
||||||
if (info.tick) info.tick(t, 1 - t);
|
|
||||||
},
|
|
||||||
|
|
||||||
done() {
|
|
||||||
if (info.tick) info.tick(1, 0);
|
|
||||||
animation.stop();
|
|
||||||
},
|
|
||||||
|
|
||||||
stop() {
|
|
||||||
if (info.css) transitionManager.deleteRule(node, program.name);
|
|
||||||
animation.running = false;
|
|
||||||
}
|
|
||||||
};
|
|
||||||
|
|
||||||
transitionManager.add(animation);
|
|
||||||
|
|
||||||
if (info.tick) info.tick(0, 1);
|
|
||||||
|
|
||||||
if (delay) {
|
|
||||||
if (info.css) node.style.cssText += info.css(0, 1);
|
|
||||||
} else {
|
|
||||||
animation.start();
|
|
||||||
}
|
|
||||||
|
|
||||||
return animation;
|
|
||||||
}
|
|
||||||
|
|
||||||
export function fixPosition(node) {
|
|
||||||
const style = getComputedStyle(node);
|
|
||||||
|
|
||||||
if (style.position !== 'absolute' && style.position !== 'fixed') {
|
|
||||||
const { width, height } = style;
|
|
||||||
const a = node.getBoundingClientRect();
|
|
||||||
node.style.position = 'absolute';
|
|
||||||
node.style.width = width;
|
|
||||||
node.style.height = height;
|
|
||||||
const b = node.getBoundingClientRect();
|
|
||||||
|
|
||||||
if (a.left !== b.left || a.top !== b.top) {
|
|
||||||
const style = getComputedStyle(node);
|
|
||||||
const transform = style.transform === 'none' ? '' : style.transform;
|
|
||||||
|
|
||||||
node.style.transform = `${transform} translate(${a.left - b.left}px, ${a.top - b.top}px)`;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
@ -1,60 +0,0 @@
|
|||||||
import { assign, isPromise } from './utils.js';
|
|
||||||
import { groupOutros } from './transitions.js';
|
|
||||||
|
|
||||||
export function handlePromise(promise, info) {
|
|
||||||
var token = info.token = {};
|
|
||||||
|
|
||||||
function update(type, index, key, value) {
|
|
||||||
if (info.token !== token) return;
|
|
||||||
|
|
||||||
info.resolved = key && { [key]: value };
|
|
||||||
|
|
||||||
const child_ctx = assign(assign({}, info.ctx), info.resolved);
|
|
||||||
const block = type && (info.current = type)(info.component, child_ctx);
|
|
||||||
|
|
||||||
if (info.block) {
|
|
||||||
if (info.blocks) {
|
|
||||||
info.blocks.forEach((block, i) => {
|
|
||||||
if (i !== index && block) {
|
|
||||||
groupOutros();
|
|
||||||
block.o(() => {
|
|
||||||
block.d(1);
|
|
||||||
info.blocks[i] = null;
|
|
||||||
});
|
|
||||||
}
|
|
||||||
});
|
|
||||||
} else {
|
|
||||||
info.block.d(1);
|
|
||||||
}
|
|
||||||
|
|
||||||
block.c();
|
|
||||||
block[block.i ? 'i' : 'm'](info.mount(), info.anchor);
|
|
||||||
|
|
||||||
info.component.root.set({}); // flush any handlers that were created
|
|
||||||
}
|
|
||||||
|
|
||||||
info.block = block;
|
|
||||||
if (info.blocks) info.blocks[index] = block;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (isPromise(promise)) {
|
|
||||||
promise.then(value => {
|
|
||||||
update(info.then, 1, info.value, value);
|
|
||||||
}, error => {
|
|
||||||
update(info.catch, 2, info.error, error);
|
|
||||||
});
|
|
||||||
|
|
||||||
// if we previously had a then/catch block, destroy it
|
|
||||||
if (info.current !== info.pending) {
|
|
||||||
update(info.pending, 0);
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
} else {
|
|
||||||
if (info.current !== info.then) {
|
|
||||||
update(info.then, 1, info.value, promise);
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
|
|
||||||
info.resolved = { [info.value]: promise };
|
|
||||||
}
|
|
||||||
}
|
|
@ -1,243 +0,0 @@
|
|||||||
export function append(target, node) {
|
|
||||||
target.appendChild(node);
|
|
||||||
}
|
|
||||||
|
|
||||||
export function insert(target, node, anchor) {
|
|
||||||
target.insertBefore(node, anchor);
|
|
||||||
}
|
|
||||||
|
|
||||||
export function detachNode(node) {
|
|
||||||
node.parentNode.removeChild(node);
|
|
||||||
}
|
|
||||||
|
|
||||||
export function detachBetween(before, after) {
|
|
||||||
while (before.nextSibling && before.nextSibling !== after) {
|
|
||||||
before.parentNode.removeChild(before.nextSibling);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
export function detachBefore(after) {
|
|
||||||
while (after.previousSibling) {
|
|
||||||
after.parentNode.removeChild(after.previousSibling);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
export function detachAfter(before) {
|
|
||||||
while (before.nextSibling) {
|
|
||||||
before.parentNode.removeChild(before.nextSibling);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
export function reinsertBetween(before, after, target) {
|
|
||||||
while (before.nextSibling && before.nextSibling !== after) {
|
|
||||||
target.appendChild(before.parentNode.removeChild(before.nextSibling));
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
export function reinsertChildren(parent, target) {
|
|
||||||
while (parent.firstChild) target.appendChild(parent.firstChild);
|
|
||||||
}
|
|
||||||
|
|
||||||
export function reinsertAfter(before, target) {
|
|
||||||
while (before.nextSibling) target.appendChild(before.nextSibling);
|
|
||||||
}
|
|
||||||
|
|
||||||
export function reinsertBefore(after, target) {
|
|
||||||
var parent = after.parentNode;
|
|
||||||
while (parent.firstChild !== after) target.appendChild(parent.firstChild);
|
|
||||||
}
|
|
||||||
|
|
||||||
export function destroyEach(iterations, detach) {
|
|
||||||
for (var i = 0; i < iterations.length; i += 1) {
|
|
||||||
if (iterations[i]) iterations[i].d(detach);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
export function createFragment() {
|
|
||||||
return document.createDocumentFragment();
|
|
||||||
}
|
|
||||||
|
|
||||||
export function createElement(name) {
|
|
||||||
return document.createElement(name);
|
|
||||||
}
|
|
||||||
|
|
||||||
export function createSvgElement(name) {
|
|
||||||
return document.createElementNS('http://www.w3.org/2000/svg', name);
|
|
||||||
}
|
|
||||||
|
|
||||||
export function createText(data) {
|
|
||||||
return document.createTextNode(data);
|
|
||||||
}
|
|
||||||
|
|
||||||
export function createComment() {
|
|
||||||
return document.createComment('');
|
|
||||||
}
|
|
||||||
|
|
||||||
export function addListener(node, event, handler, options) {
|
|
||||||
node.addEventListener(event, handler, options);
|
|
||||||
}
|
|
||||||
|
|
||||||
export function removeListener(node, event, handler, options) {
|
|
||||||
node.removeEventListener(event, handler, options);
|
|
||||||
}
|
|
||||||
|
|
||||||
export function setAttribute(node, attribute, value) {
|
|
||||||
if (value == null) node.removeAttribute(attribute);
|
|
||||||
else node.setAttribute(attribute, value);
|
|
||||||
}
|
|
||||||
|
|
||||||
export function setAttributes(node, attributes) {
|
|
||||||
for (var key in attributes) {
|
|
||||||
if (key === 'style') {
|
|
||||||
node.style.cssText = attributes[key];
|
|
||||||
} else if (key in node) {
|
|
||||||
node[key] = attributes[key];
|
|
||||||
} else {
|
|
||||||
setAttribute(node, key, attributes[key]);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
export function setCustomElementData(node, prop, value) {
|
|
||||||
if (prop in node) {
|
|
||||||
node[prop] = value;
|
|
||||||
} else if (value) {
|
|
||||||
setAttribute(node, prop, value);
|
|
||||||
} else {
|
|
||||||
node.removeAttribute(prop);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
export function setXlinkAttribute(node, attribute, value) {
|
|
||||||
node.setAttributeNS('http://www.w3.org/1999/xlink', attribute, value);
|
|
||||||
}
|
|
||||||
|
|
||||||
export function getBindingGroupValue(group) {
|
|
||||||
var value = [];
|
|
||||||
for (var i = 0; i < group.length; i += 1) {
|
|
||||||
if (group[i].checked) value.push(group[i].__value);
|
|
||||||
}
|
|
||||||
return value;
|
|
||||||
}
|
|
||||||
|
|
||||||
export function toNumber(value) {
|
|
||||||
return value === '' ? undefined : +value;
|
|
||||||
}
|
|
||||||
|
|
||||||
export function timeRangesToArray(ranges) {
|
|
||||||
var array = [];
|
|
||||||
for (var i = 0; i < ranges.length; i += 1) {
|
|
||||||
array.push({ start: ranges.start(i), end: ranges.end(i) });
|
|
||||||
}
|
|
||||||
return array;
|
|
||||||
}
|
|
||||||
|
|
||||||
export function children (element) {
|
|
||||||
return Array.from(element.childNodes);
|
|
||||||
}
|
|
||||||
|
|
||||||
export function claimElement (nodes, name, attributes, svg) {
|
|
||||||
for (var i = 0; i < nodes.length; i += 1) {
|
|
||||||
var node = nodes[i];
|
|
||||||
if (node.nodeName === name) {
|
|
||||||
for (var j = 0; j < node.attributes.length; j += 1) {
|
|
||||||
var attribute = node.attributes[j];
|
|
||||||
if (!attributes[attribute.name]) node.removeAttribute(attribute.name);
|
|
||||||
}
|
|
||||||
return nodes.splice(i, 1)[0]; // TODO strip unwanted attributes
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
return svg ? createSvgElement(name) : createElement(name);
|
|
||||||
}
|
|
||||||
|
|
||||||
export function claimText (nodes, data) {
|
|
||||||
for (var i = 0; i < nodes.length; i += 1) {
|
|
||||||
var node = nodes[i];
|
|
||||||
if (node.nodeType === 3) {
|
|
||||||
node.data = data;
|
|
||||||
return nodes.splice(i, 1)[0];
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
return createText(data);
|
|
||||||
}
|
|
||||||
|
|
||||||
export function setData(text, data) {
|
|
||||||
text.data = '' + data;
|
|
||||||
}
|
|
||||||
|
|
||||||
export function setInputType(input, type) {
|
|
||||||
try {
|
|
||||||
input.type = type;
|
|
||||||
} catch (e) {}
|
|
||||||
}
|
|
||||||
|
|
||||||
export function setStyle(node, key, value) {
|
|
||||||
node.style.setProperty(key, value);
|
|
||||||
}
|
|
||||||
|
|
||||||
export function selectOption(select, value) {
|
|
||||||
for (var i = 0; i < select.options.length; i += 1) {
|
|
||||||
var option = select.options[i];
|
|
||||||
|
|
||||||
if (option.__value === value) {
|
|
||||||
option.selected = true;
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
export function selectOptions(select, value) {
|
|
||||||
for (var i = 0; i < select.options.length; i += 1) {
|
|
||||||
var option = select.options[i];
|
|
||||||
option.selected = ~value.indexOf(option.__value);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
export function selectValue(select) {
|
|
||||||
var selectedOption = select.querySelector(':checked') || select.options[0];
|
|
||||||
return selectedOption && selectedOption.__value;
|
|
||||||
}
|
|
||||||
|
|
||||||
export function selectMultipleValue(select) {
|
|
||||||
return [].map.call(select.querySelectorAll(':checked'), function(option) {
|
|
||||||
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';
|
|
||||||
|
|
||||||
let win;
|
|
||||||
|
|
||||||
object.onload = () => {
|
|
||||||
win = object.contentDocument.defaultView;
|
|
||||||
win.addEventListener('resize', fn);
|
|
||||||
};
|
|
||||||
|
|
||||||
if (/Trident/.test(navigator.userAgent)) {
|
|
||||||
element.appendChild(object);
|
|
||||||
object.data = 'about:blank';
|
|
||||||
} else {
|
|
||||||
object.data = 'about:blank';
|
|
||||||
element.appendChild(object);
|
|
||||||
}
|
|
||||||
|
|
||||||
return {
|
|
||||||
cancel: () => {
|
|
||||||
win && win.removeEventListener && win.removeEventListener('resize', fn);
|
|
||||||
element.removeChild(object);
|
|
||||||
}
|
|
||||||
};
|
|
||||||
}
|
|
||||||
|
|
||||||
export function toggleClass(element, name, toggle) {
|
|
||||||
element.classList.toggle(name, !!toggle);
|
|
||||||
}
|
|
@ -1,186 +0,0 @@
|
|||||||
import { assign } from './utils.js';
|
|
||||||
import { noop } from './utils.js';
|
|
||||||
export * from './animations.js';
|
|
||||||
export * from './await-block.js';
|
|
||||||
export * from './dom.js';
|
|
||||||
export * from './keyed-each.js';
|
|
||||||
export * from './spread.js';
|
|
||||||
export * from './ssr.js';
|
|
||||||
export * from './transitions.js';
|
|
||||||
export * from './utils.js';
|
|
||||||
|
|
||||||
export function blankObject() {
|
|
||||||
return Object.create(null);
|
|
||||||
}
|
|
||||||
|
|
||||||
export function destroy(detach) {
|
|
||||||
this.destroy = noop;
|
|
||||||
this.fire('destroy');
|
|
||||||
this.set = noop;
|
|
||||||
|
|
||||||
this._fragment.d(detach !== false);
|
|
||||||
this._fragment = null;
|
|
||||||
this._state = {};
|
|
||||||
}
|
|
||||||
|
|
||||||
export function destroyDev(detach) {
|
|
||||||
destroy.call(this, detach);
|
|
||||||
this.destroy = function() {
|
|
||||||
console.warn('Component was already destroyed');
|
|
||||||
};
|
|
||||||
}
|
|
||||||
|
|
||||||
export function _differs(a, b) {
|
|
||||||
return a != a ? b == b : a !== b || ((a && typeof a === 'object') || typeof a === 'function');
|
|
||||||
}
|
|
||||||
|
|
||||||
export function _differsImmutable(a, b) {
|
|
||||||
return a != a ? b == b : a !== b;
|
|
||||||
}
|
|
||||||
|
|
||||||
export function fire(eventName, data) {
|
|
||||||
var handlers =
|
|
||||||
eventName in this._handlers && this._handlers[eventName].slice();
|
|
||||||
if (!handlers) return;
|
|
||||||
|
|
||||||
for (var i = 0; i < handlers.length; i += 1) {
|
|
||||||
var handler = handlers[i];
|
|
||||||
|
|
||||||
if (!handler.__calling) {
|
|
||||||
try {
|
|
||||||
handler.__calling = true;
|
|
||||||
handler.call(this, data);
|
|
||||||
} finally {
|
|
||||||
handler.__calling = false;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
export function flush(component) {
|
|
||||||
component._lock = true;
|
|
||||||
callAll(component._beforecreate);
|
|
||||||
callAll(component._oncreate);
|
|
||||||
callAll(component._aftercreate);
|
|
||||||
component._lock = false;
|
|
||||||
}
|
|
||||||
|
|
||||||
export function get() {
|
|
||||||
return this._state;
|
|
||||||
}
|
|
||||||
|
|
||||||
export function init(component, options) {
|
|
||||||
component._handlers = blankObject();
|
|
||||||
component._slots = blankObject();
|
|
||||||
component._bind = options._bind;
|
|
||||||
component._staged = {};
|
|
||||||
|
|
||||||
component.options = options;
|
|
||||||
component.root = options.root || component;
|
|
||||||
component.store = options.store || component.root.store;
|
|
||||||
|
|
||||||
if (!options.root) {
|
|
||||||
component._beforecreate = [];
|
|
||||||
component._oncreate = [];
|
|
||||||
component._aftercreate = [];
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
export function on(eventName, handler) {
|
|
||||||
var handlers = this._handlers[eventName] || (this._handlers[eventName] = []);
|
|
||||||
handlers.push(handler);
|
|
||||||
|
|
||||||
return {
|
|
||||||
cancel: function() {
|
|
||||||
var index = handlers.indexOf(handler);
|
|
||||||
if (~index) handlers.splice(index, 1);
|
|
||||||
}
|
|
||||||
};
|
|
||||||
}
|
|
||||||
|
|
||||||
export function set(newState) {
|
|
||||||
this._set(assign({}, newState));
|
|
||||||
if (this.root._lock) return;
|
|
||||||
flush(this.root);
|
|
||||||
}
|
|
||||||
|
|
||||||
export function _set(newState) {
|
|
||||||
var oldState = this._state,
|
|
||||||
changed = {},
|
|
||||||
dirty = false;
|
|
||||||
|
|
||||||
newState = assign(this._staged, newState);
|
|
||||||
this._staged = {};
|
|
||||||
|
|
||||||
for (var key in newState) {
|
|
||||||
if (this._differs(newState[key], oldState[key])) changed[key] = dirty = true;
|
|
||||||
}
|
|
||||||
if (!dirty) return;
|
|
||||||
|
|
||||||
this._state = assign(assign({}, oldState), newState);
|
|
||||||
this._recompute(changed, this._state);
|
|
||||||
if (this._bind) this._bind(changed, this._state);
|
|
||||||
|
|
||||||
if (this._fragment) {
|
|
||||||
this.fire("state", { changed: changed, current: this._state, previous: oldState });
|
|
||||||
this._fragment.p(changed, this._state);
|
|
||||||
this.fire("update", { changed: changed, current: this._state, previous: oldState });
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
export function _stage(newState) {
|
|
||||||
assign(this._staged, newState);
|
|
||||||
}
|
|
||||||
|
|
||||||
export function setDev(newState) {
|
|
||||||
if (typeof newState !== 'object') {
|
|
||||||
throw new Error(
|
|
||||||
this._debugName + '.set was called without an object of data key-values to update.'
|
|
||||||
);
|
|
||||||
}
|
|
||||||
|
|
||||||
this._checkReadOnly(newState);
|
|
||||||
set.call(this, newState);
|
|
||||||
}
|
|
||||||
|
|
||||||
export function callAll(fns) {
|
|
||||||
while (fns && fns.length) fns.shift()();
|
|
||||||
}
|
|
||||||
|
|
||||||
export function _mount(target, anchor) {
|
|
||||||
this._fragment[this._fragment.i ? 'i' : 'm'](target, anchor || null);
|
|
||||||
}
|
|
||||||
|
|
||||||
export var PENDING = {};
|
|
||||||
export var SUCCESS = {};
|
|
||||||
export var FAILURE = {};
|
|
||||||
|
|
||||||
export function removeFromStore() {
|
|
||||||
this.store._remove(this);
|
|
||||||
}
|
|
||||||
|
|
||||||
export var proto = {
|
|
||||||
destroy,
|
|
||||||
get,
|
|
||||||
fire,
|
|
||||||
on,
|
|
||||||
set,
|
|
||||||
_recompute: noop,
|
|
||||||
_set,
|
|
||||||
_stage,
|
|
||||||
_mount,
|
|
||||||
_differs
|
|
||||||
};
|
|
||||||
|
|
||||||
export var protoDev = {
|
|
||||||
destroy: destroyDev,
|
|
||||||
get,
|
|
||||||
fire,
|
|
||||||
on,
|
|
||||||
set: setDev,
|
|
||||||
_recompute: noop,
|
|
||||||
_set,
|
|
||||||
_stage,
|
|
||||||
_mount,
|
|
||||||
_differs
|
|
||||||
};
|
|
@ -1,123 +0,0 @@
|
|||||||
export function destroyBlock(block, lookup) {
|
|
||||||
block.d(1);
|
|
||||||
lookup[block.key] = null;
|
|
||||||
}
|
|
||||||
|
|
||||||
export function outroAndDestroyBlock(block, lookup) {
|
|
||||||
block.o(function() {
|
|
||||||
destroyBlock(block, lookup);
|
|
||||||
});
|
|
||||||
}
|
|
||||||
|
|
||||||
export function fixAndOutroAndDestroyBlock(block, lookup) {
|
|
||||||
block.f();
|
|
||||||
outroAndDestroyBlock(block, lookup);
|
|
||||||
}
|
|
||||||
|
|
||||||
export function updateKeyedEach(old_blocks, component, changed, get_key, dynamic, ctx, list, lookup, node, destroy, create_each_block, intro_method, next, get_context) {
|
|
||||||
var o = old_blocks.length;
|
|
||||||
var n = list.length;
|
|
||||||
|
|
||||||
var i = o;
|
|
||||||
var old_indexes = {};
|
|
||||||
while (i--) old_indexes[old_blocks[i].key] = i;
|
|
||||||
|
|
||||||
var new_blocks = [];
|
|
||||||
var new_lookup = {};
|
|
||||||
var deltas = {};
|
|
||||||
|
|
||||||
var i = n;
|
|
||||||
while (i--) {
|
|
||||||
var child_ctx = get_context(ctx, list, i);
|
|
||||||
var key = get_key(child_ctx);
|
|
||||||
var block = lookup[key];
|
|
||||||
|
|
||||||
if (!block) {
|
|
||||||
block = create_each_block(component, key, child_ctx);
|
|
||||||
block.c();
|
|
||||||
} else if (dynamic) {
|
|
||||||
block.p(changed, child_ctx);
|
|
||||||
}
|
|
||||||
|
|
||||||
new_blocks[i] = new_lookup[key] = block;
|
|
||||||
|
|
||||||
if (key in old_indexes) deltas[key] = Math.abs(i - old_indexes[key]);
|
|
||||||
}
|
|
||||||
|
|
||||||
var will_move = {};
|
|
||||||
var did_move = {};
|
|
||||||
|
|
||||||
function insert(block) {
|
|
||||||
block[intro_method](node, next);
|
|
||||||
lookup[block.key] = block;
|
|
||||||
next = block.first;
|
|
||||||
n--;
|
|
||||||
}
|
|
||||||
|
|
||||||
while (o && n) {
|
|
||||||
var new_block = new_blocks[n - 1];
|
|
||||||
var old_block = old_blocks[o - 1];
|
|
||||||
var new_key = new_block.key;
|
|
||||||
var old_key = old_block.key;
|
|
||||||
|
|
||||||
if (new_block === old_block) {
|
|
||||||
// do nothing
|
|
||||||
next = new_block.first;
|
|
||||||
o--;
|
|
||||||
n--;
|
|
||||||
}
|
|
||||||
|
|
||||||
else if (!new_lookup[old_key]) {
|
|
||||||
// remove old block
|
|
||||||
destroy(old_block, lookup);
|
|
||||||
o--;
|
|
||||||
}
|
|
||||||
|
|
||||||
else if (!lookup[new_key] || will_move[new_key]) {
|
|
||||||
insert(new_block);
|
|
||||||
}
|
|
||||||
|
|
||||||
else if (did_move[old_key]) {
|
|
||||||
o--;
|
|
||||||
|
|
||||||
} else if (deltas[new_key] > deltas[old_key]) {
|
|
||||||
did_move[new_key] = true;
|
|
||||||
insert(new_block);
|
|
||||||
|
|
||||||
} else {
|
|
||||||
will_move[old_key] = true;
|
|
||||||
o--;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
while (o--) {
|
|
||||||
var old_block = old_blocks[o];
|
|
||||||
if (!new_lookup[old_block.key]) destroy(old_block, lookup);
|
|
||||||
}
|
|
||||||
|
|
||||||
while (n) insert(new_blocks[n - 1]);
|
|
||||||
|
|
||||||
return new_blocks;
|
|
||||||
}
|
|
||||||
|
|
||||||
export function measure(blocks) {
|
|
||||||
const rects = {};
|
|
||||||
let i = blocks.length;
|
|
||||||
while (i--) rects[blocks[i].key] = blocks[i].node.getBoundingClientRect();
|
|
||||||
return rects;
|
|
||||||
}
|
|
||||||
|
|
||||||
export function animate(blocks, rects, fn, params) {
|
|
||||||
let i = blocks.length;
|
|
||||||
while (i--) {
|
|
||||||
const block = blocks[i];
|
|
||||||
const from = rects[block.key];
|
|
||||||
|
|
||||||
if (!from) continue;
|
|
||||||
const to = block.node.getBoundingClientRect();
|
|
||||||
|
|
||||||
if (from.left === to.left && from.right === to.right && from.top === to.top && from.bottom === to.bottom) continue;
|
|
||||||
|
|
||||||
|
|
||||||
}
|
|
||||||
}
|
|
@ -1,37 +0,0 @@
|
|||||||
export function getSpreadUpdate(levels, updates) {
|
|
||||||
var update = {};
|
|
||||||
|
|
||||||
var to_null_out = {};
|
|
||||||
var accounted_for = {};
|
|
||||||
|
|
||||||
var i = levels.length;
|
|
||||||
while (i--) {
|
|
||||||
var o = levels[i];
|
|
||||||
var n = updates[i];
|
|
||||||
|
|
||||||
if (n) {
|
|
||||||
for (var key in o) {
|
|
||||||
if (!(key in n)) to_null_out[key] = 1;
|
|
||||||
}
|
|
||||||
|
|
||||||
for (var key in n) {
|
|
||||||
if (!accounted_for[key]) {
|
|
||||||
update[key] = n[key];
|
|
||||||
accounted_for[key] = 1;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
levels[i] = n;
|
|
||||||
} else {
|
|
||||||
for (var key in o) {
|
|
||||||
accounted_for[key] = 1;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
for (var key in to_null_out) {
|
|
||||||
if (!(key in update)) update[key] = undefined;
|
|
||||||
}
|
|
||||||
|
|
||||||
return update;
|
|
||||||
}
|
|
@ -1,63 +0,0 @@
|
|||||||
// https://html.spec.whatwg.org/multipage/syntax.html#attributes-2
|
|
||||||
// https://infra.spec.whatwg.org/#noncharacter
|
|
||||||
export const invalidAttributeNameCharacter = /[\s'">\/=\u{FDD0}-\u{FDEF}\u{FFFE}\u{FFFF}\u{1FFFE}\u{1FFFF}\u{2FFFE}\u{2FFFF}\u{3FFFE}\u{3FFFF}\u{4FFFE}\u{4FFFF}\u{5FFFE}\u{5FFFF}\u{6FFFE}\u{6FFFF}\u{7FFFE}\u{7FFFF}\u{8FFFE}\u{8FFFF}\u{9FFFE}\u{9FFFF}\u{AFFFE}\u{AFFFF}\u{BFFFE}\u{BFFFF}\u{CFFFE}\u{CFFFF}\u{DFFFE}\u{DFFFF}\u{EFFFE}\u{EFFFF}\u{FFFFE}\u{FFFFF}\u{10FFFE}\u{10FFFF}]/u;
|
|
||||||
|
|
||||||
export function spread(args) {
|
|
||||||
const attributes = Object.assign({}, ...args);
|
|
||||||
let str = '';
|
|
||||||
|
|
||||||
Object.keys(attributes).forEach(name => {
|
|
||||||
if (invalidAttributeNameCharacter.test(name)) return;
|
|
||||||
|
|
||||||
const value = attributes[name];
|
|
||||||
if (value === undefined) return;
|
|
||||||
if (value === true) str += " " + name;
|
|
||||||
|
|
||||||
const escaped = String(value)
|
|
||||||
.replace(/"/g, '"')
|
|
||||||
.replace(/'/g, ''');
|
|
||||||
|
|
||||||
str += " " + name + "=" + JSON.stringify(escaped);
|
|
||||||
});
|
|
||||||
|
|
||||||
return str;
|
|
||||||
}
|
|
||||||
|
|
||||||
export const escaped = {
|
|
||||||
'"': '"',
|
|
||||||
"'": ''',
|
|
||||||
'&': '&',
|
|
||||||
'<': '<',
|
|
||||||
'>': '>'
|
|
||||||
};
|
|
||||||
|
|
||||||
export function escape(html) {
|
|
||||||
return String(html).replace(/["'&<>]/g, match => escaped[match]);
|
|
||||||
}
|
|
||||||
|
|
||||||
export function each(items, assign, fn) {
|
|
||||||
let str = '';
|
|
||||||
for (let i = 0; i < items.length; i += 1) {
|
|
||||||
str += fn(assign(items[i], i));
|
|
||||||
}
|
|
||||||
return str;
|
|
||||||
}
|
|
||||||
|
|
||||||
export const missingComponent = {
|
|
||||||
_render: () => ''
|
|
||||||
};
|
|
||||||
|
|
||||||
export function validateSsrComponent(component, name) {
|
|
||||||
if (!component || !component._render) {
|
|
||||||
if (name === 'svelte:component') name += ' this={...}';
|
|
||||||
throw new Error(`<${name}> is not a valid SSR component. You may need to review your build config to ensure that dependencies are compiled, rather than imported as pre-compiled modules`);
|
|
||||||
}
|
|
||||||
|
|
||||||
return component;
|
|
||||||
}
|
|
||||||
|
|
||||||
export function debug(file, line, column, values) {
|
|
||||||
console.log(`{@debug} ${file ? file + ' ' : ''}(${line}:${column})`);
|
|
||||||
console.log(values);
|
|
||||||
return '';
|
|
||||||
}
|
|
@ -1,256 +0,0 @@
|
|||||||
import { createElement } from './dom.js';
|
|
||||||
import { noop, run } from './utils.js';
|
|
||||||
|
|
||||||
export function linear(t) {
|
|
||||||
return t;
|
|
||||||
}
|
|
||||||
|
|
||||||
export function generateRule({ a, b, delta, duration }, ease, fn) {
|
|
||||||
const step = 16.666 / duration;
|
|
||||||
let keyframes = '{\n';
|
|
||||||
|
|
||||||
for (let p = 0; p <= 1; p += step) {
|
|
||||||
const t = a + delta * ease(p);
|
|
||||||
keyframes += p * 100 + `%{${fn(t, 1 - t)}}\n`;
|
|
||||||
}
|
|
||||||
|
|
||||||
return keyframes + `100% {${fn(b, 1 - b)}}\n}`;
|
|
||||||
}
|
|
||||||
|
|
||||||
// https://github.com/darkskyapp/string-hash/blob/master/index.js
|
|
||||||
export function hash(str) {
|
|
||||||
let hash = 5381;
|
|
||||||
let i = str.length;
|
|
||||||
|
|
||||||
while (i--) hash = ((hash << 5) - hash) ^ str.charCodeAt(i);
|
|
||||||
return hash >>> 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
export function wrapTransition(component, node, fn, params, intro) {
|
|
||||||
let obj = fn.call(component, node, params);
|
|
||||||
let duration;
|
|
||||||
let ease;
|
|
||||||
let cssText;
|
|
||||||
|
|
||||||
let initialised = false;
|
|
||||||
|
|
||||||
return {
|
|
||||||
t: intro ? 0 : 1,
|
|
||||||
running: false,
|
|
||||||
program: null,
|
|
||||||
pending: null,
|
|
||||||
|
|
||||||
run(b, callback) {
|
|
||||||
if (typeof obj === 'function') {
|
|
||||||
transitionManager.wait().then(() => {
|
|
||||||
obj = obj();
|
|
||||||
this._run(b, callback);
|
|
||||||
});
|
|
||||||
} else {
|
|
||||||
this._run(b, callback);
|
|
||||||
}
|
|
||||||
},
|
|
||||||
|
|
||||||
_run(b, callback) {
|
|
||||||
duration = obj.duration || 300;
|
|
||||||
ease = obj.easing || linear;
|
|
||||||
|
|
||||||
const program = {
|
|
||||||
start: window.performance.now() + (obj.delay || 0),
|
|
||||||
b,
|
|
||||||
callback: callback || noop
|
|
||||||
};
|
|
||||||
|
|
||||||
if (intro && !initialised) {
|
|
||||||
if (obj.css && obj.delay) {
|
|
||||||
cssText = node.style.cssText;
|
|
||||||
node.style.cssText += obj.css(0, 1);
|
|
||||||
}
|
|
||||||
|
|
||||||
if (obj.tick) obj.tick(0, 1);
|
|
||||||
initialised = true;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (!b) {
|
|
||||||
program.group = outros.current;
|
|
||||||
outros.current.remaining += 1;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (obj.delay) {
|
|
||||||
this.pending = program;
|
|
||||||
} else {
|
|
||||||
this.start(program);
|
|
||||||
}
|
|
||||||
|
|
||||||
if (!this.running) {
|
|
||||||
this.running = true;
|
|
||||||
transitionManager.add(this);
|
|
||||||
}
|
|
||||||
},
|
|
||||||
|
|
||||||
start(program) {
|
|
||||||
component.fire(`${program.b ? 'intro' : 'outro'}.start`, { node });
|
|
||||||
|
|
||||||
program.a = this.t;
|
|
||||||
program.delta = program.b - program.a;
|
|
||||||
program.duration = duration * Math.abs(program.b - program.a);
|
|
||||||
program.end = program.start + program.duration;
|
|
||||||
|
|
||||||
if (obj.css) {
|
|
||||||
if (obj.delay) node.style.cssText = cssText;
|
|
||||||
|
|
||||||
const rule = generateRule(program, ease, obj.css);
|
|
||||||
transitionManager.addRule(rule, program.name = '__svelte_' + hash(rule));
|
|
||||||
|
|
||||||
node.style.animation = (node.style.animation || '')
|
|
||||||
.split(', ')
|
|
||||||
.filter(anim => anim && (program.delta < 0 || !/__svelte/.test(anim)))
|
|
||||||
.concat(`${program.name} ${program.duration}ms linear 1 forwards`)
|
|
||||||
.join(', ');
|
|
||||||
}
|
|
||||||
|
|
||||||
this.program = program;
|
|
||||||
this.pending = null;
|
|
||||||
},
|
|
||||||
|
|
||||||
update(now) {
|
|
||||||
const program = this.program;
|
|
||||||
if (!program) return;
|
|
||||||
|
|
||||||
const p = now - program.start;
|
|
||||||
this.t = program.a + program.delta * ease(p / program.duration);
|
|
||||||
if (obj.tick) obj.tick(this.t, 1 - this.t);
|
|
||||||
},
|
|
||||||
|
|
||||||
done() {
|
|
||||||
const program = this.program;
|
|
||||||
this.t = program.b;
|
|
||||||
|
|
||||||
if (obj.tick) obj.tick(this.t, 1 - this.t);
|
|
||||||
|
|
||||||
component.fire(`${program.b ? 'intro' : 'outro'}.end`, { node });
|
|
||||||
|
|
||||||
if (!program.b && !program.invalidated) {
|
|
||||||
program.group.callbacks.push(() => {
|
|
||||||
program.callback();
|
|
||||||
if (obj.css) transitionManager.deleteRule(node, program.name);
|
|
||||||
});
|
|
||||||
|
|
||||||
if (--program.group.remaining === 0) {
|
|
||||||
program.group.callbacks.forEach(run);
|
|
||||||
}
|
|
||||||
} else {
|
|
||||||
if (obj.css) transitionManager.deleteRule(node, program.name);
|
|
||||||
}
|
|
||||||
|
|
||||||
this.running = !!this.pending;
|
|
||||||
},
|
|
||||||
|
|
||||||
abort(reset) {
|
|
||||||
if (this.program) {
|
|
||||||
if (reset && obj.tick) obj.tick(1, 0);
|
|
||||||
if (obj.css) transitionManager.deleteRule(node, this.program.name);
|
|
||||||
this.program = this.pending = null;
|
|
||||||
this.running = false;
|
|
||||||
}
|
|
||||||
},
|
|
||||||
|
|
||||||
invalidate() {
|
|
||||||
if (this.program) {
|
|
||||||
this.program.invalidated = true;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
};
|
|
||||||
}
|
|
||||||
|
|
||||||
export let outros = {};
|
|
||||||
|
|
||||||
export function groupOutros() {
|
|
||||||
outros.current = {
|
|
||||||
remaining: 0,
|
|
||||||
callbacks: []
|
|
||||||
};
|
|
||||||
}
|
|
||||||
|
|
||||||
export var transitionManager = {
|
|
||||||
running: false,
|
|
||||||
transitions: [],
|
|
||||||
bound: null,
|
|
||||||
stylesheet: null,
|
|
||||||
activeRules: {},
|
|
||||||
promise: null,
|
|
||||||
|
|
||||||
add(transition) {
|
|
||||||
this.transitions.push(transition);
|
|
||||||
|
|
||||||
if (!this.running) {
|
|
||||||
this.running = true;
|
|
||||||
requestAnimationFrame(this.bound || (this.bound = this.next.bind(this)));
|
|
||||||
}
|
|
||||||
},
|
|
||||||
|
|
||||||
addRule(rule, name) {
|
|
||||||
if (!this.stylesheet) {
|
|
||||||
const style = createElement('style');
|
|
||||||
document.head.appendChild(style);
|
|
||||||
transitionManager.stylesheet = style.sheet;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (!this.activeRules[name]) {
|
|
||||||
this.activeRules[name] = true;
|
|
||||||
this.stylesheet.insertRule(`@keyframes ${name} ${rule}`, this.stylesheet.cssRules.length);
|
|
||||||
}
|
|
||||||
},
|
|
||||||
|
|
||||||
next() {
|
|
||||||
this.running = false;
|
|
||||||
|
|
||||||
const now = window.performance.now();
|
|
||||||
let i = this.transitions.length;
|
|
||||||
|
|
||||||
while (i--) {
|
|
||||||
const transition = this.transitions[i];
|
|
||||||
|
|
||||||
if (transition.program && now >= transition.program.end) {
|
|
||||||
transition.done();
|
|
||||||
}
|
|
||||||
|
|
||||||
if (transition.pending && now >= transition.pending.start) {
|
|
||||||
transition.start(transition.pending);
|
|
||||||
}
|
|
||||||
|
|
||||||
if (transition.running) {
|
|
||||||
transition.update(now);
|
|
||||||
this.running = true;
|
|
||||||
} else if (!transition.pending) {
|
|
||||||
this.transitions.splice(i, 1);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
if (this.running) {
|
|
||||||
requestAnimationFrame(this.bound);
|
|
||||||
} else if (this.stylesheet) {
|
|
||||||
let i = this.stylesheet.cssRules.length;
|
|
||||||
while (i--) this.stylesheet.deleteRule(i);
|
|
||||||
this.activeRules = {};
|
|
||||||
}
|
|
||||||
},
|
|
||||||
|
|
||||||
deleteRule(node, name) {
|
|
||||||
node.style.animation = node.style.animation
|
|
||||||
.split(', ')
|
|
||||||
.filter(anim => anim && anim.indexOf(name) === -1)
|
|
||||||
.join(', ');
|
|
||||||
},
|
|
||||||
|
|
||||||
wait() {
|
|
||||||
if (!transitionManager.promise) {
|
|
||||||
transitionManager.promise = Promise.resolve();
|
|
||||||
transitionManager.promise.then(() => {
|
|
||||||
transitionManager.promise = null;
|
|
||||||
});
|
|
||||||
}
|
|
||||||
|
|
||||||
return transitionManager.promise;
|
|
||||||
}
|
|
||||||
};
|
|
@ -1,43 +0,0 @@
|
|||||||
export function noop() {}
|
|
||||||
|
|
||||||
export function assign(tar, src) {
|
|
||||||
for (var k in src) tar[k] = src[k];
|
|
||||||
return tar;
|
|
||||||
}
|
|
||||||
|
|
||||||
export function assignTrue(tar, src) {
|
|
||||||
for (var k in src) tar[k] = 1;
|
|
||||||
return tar;
|
|
||||||
}
|
|
||||||
|
|
||||||
export function isPromise(value) {
|
|
||||||
return value && typeof value.then === 'function';
|
|
||||||
}
|
|
||||||
|
|
||||||
export function callAfter(fn, i) {
|
|
||||||
if (i === 0) fn();
|
|
||||||
return () => {
|
|
||||||
if (!--i) fn();
|
|
||||||
};
|
|
||||||
}
|
|
||||||
|
|
||||||
export function addLoc(element, file, line, column, char) {
|
|
||||||
element.__svelte_meta = {
|
|
||||||
loc: { file, line, column, char }
|
|
||||||
};
|
|
||||||
}
|
|
||||||
|
|
||||||
export function exclude(src, prop) {
|
|
||||||
const tar = {};
|
|
||||||
for (const k in src) k === prop || (tar[k] = src[k]);
|
|
||||||
return tar;
|
|
||||||
}
|
|
||||||
|
|
||||||
export function run(fn) {
|
|
||||||
fn();
|
|
||||||
}
|
|
||||||
|
|
||||||
export function run_all(fns) {
|
|
||||||
let i = fns.length;
|
|
||||||
while (i--) fns[i]();
|
|
||||||
}
|
|
Loading…
Reference in new issue