soot
Version:
vDom library
1,439 lines (1,425 loc) • 49.8 kB
JavaScript
'use strict';
Object.defineProperty(exports, '__esModule', { value: true });
var NO_OP = "$NO_OP";
var ERROR_MSG = "Error";
var isArray = Array.isArray;
function isStatefulComponent(o) {
return !isUndefined(o.prototype) && !isUndefined(o.prototype.render);
}
function isStringOrNumber(o) {
var type = typeof o;
return type === "string" || type === "number";
}
function isNullOrUndef(o) {
return isUndefined(o) || isNull(o);
}
function isInvalid(o) {
return isNull(o) || o === false || isTrue(o) || isUndefined(o);
}
function isFunction(o) {
return typeof o === "function";
}
function isString(o) {
return typeof o === "string";
}
function isNull(o) {
return o === null;
}
function isTrue(o) {
return o === true;
}
function isUndefined(o) {
return o === void 0;
}
function isObject(o) {
return typeof o === "object";
}
/**
* Throws error
* @param {string?} message
*/
function throwError(message) {
if (!message) {
message = ERROR_MSG;
}
throw new Error("Soot Error: " + message);
}
function warning(message) {
// tslint:disable-next-line:no-console
console.warn(message);
}
function combineFrom(first, second) {
var out = {};
if (first) {
for (var key in first) {
out[key] = first[key];
}
}
if (second) {
for (var key in second) {
out[key] = second[key];
}
}
return out;
}
// tslint:disable-next-line
/**
* Creates virtual node
* @param {number} flags
* @param {*} type
* @param {string|null?} className
* @param {Object?} children
* @param {Object?} props
* @param {*?} key
* @param {Object|Function?} ref
* @returns {Object} returns new virtual node
*/
function V(flags, type, className, children, props, key, ref) {
if ((flags & 8 /* ComponentUnknown */) > 0) {
flags = isStatefulComponent(type)
? 2 /* ComponentClass */
: 4 /* ComponentFunction */;
}
if ((flags & 14 /* Component */) > 0) {
var defaultProps = type.defaultProps;
if (!isNullOrUndef(defaultProps)) {
if (!props) {
props = defaultProps;
}
else {
for (var prop in defaultProps) {
if (isUndefined(props[prop])) {
props[prop] = defaultProps[prop];
}
}
}
}
}
else {
if (props) {
if (className === null) {
className = props.hasOwnProperty("className") ? props.className : null;
}
if (children === null) {
children = props.hasOwnProperty("children") ? props.children : null;
}
}
}
var vNode = {
c: isUndefined(children) ? null : children,
cN: isUndefined(className) ? null : className,
f: flags,
k: isUndefined(key) ? null : key,
p: isUndefined(props) ? null : props,
r: isUndefined(ref) ? null : ref,
t: type
};
return vNode;
}
function isVNode(o) {
return !!o.f;
}
/**
* Links given data to event as first parameter
* @param {*} data data to be linked, it will be available in function as first parameter
* @param {Function} event Function to be called when event occurs
* @returns {Object} Return null when event is not valid, to avoid creating unnecessary event handlers
*/
function linkEvent(data, event) {
if (isFunction(event)) {
return { data: data, event: event };
}
return null;
}
function createIV(input, pos, key) {
return {
b: null,
c: null,
d: null,
f: 0,
i: null,
k: key,
p: pos,
v: input
};
}
var xlinkNS = "http://www.w3.org/1999/xlink";
var xmlNS = "http://www.w3.org/XML/1998/namespace";
var svgNS = "http://www.w3.org/2000/svg";
var booleanProps = new Set();
booleanProps.add("muted");
booleanProps.add("scoped");
booleanProps.add("loop");
booleanProps.add("open");
booleanProps.add("checked");
booleanProps.add("default");
booleanProps.add("capture");
booleanProps.add("disabled");
booleanProps.add("readOnly");
booleanProps.add("required");
booleanProps.add("autoplay");
booleanProps.add("controls");
booleanProps.add("seamless");
booleanProps.add("reversed");
booleanProps.add("allowfullscreen");
booleanProps.add("novalidate");
booleanProps.add("hidden");
booleanProps.add("autofocus");
booleanProps.add("selected");
booleanProps.add("multiple");
var namespaces = new Map();
namespaces.set("xlink:href", xlinkNS);
namespaces.set("xlink:arcrole", xlinkNS);
namespaces.set("xlink:actuate", xlinkNS);
namespaces.set("xlink:show", xlinkNS);
namespaces.set("xlink:role", xlinkNS);
namespaces.set("xlink:title", xlinkNS);
namespaces.set("xlink:type", xlinkNS);
namespaces.set("xml:base", xmlNS);
namespaces.set("xml:lang", xmlNS);
namespaces.set("xml:space", xmlNS);
var skipProps = new Set();
skipProps.add("children");
skipProps.add("ref");
skipProps.add("key");
skipProps.add("className");
var syntheticEvents = new Set();
syntheticEvents.add("onClick");
syntheticEvents.add("onMouseDown");
syntheticEvents.add("onMouseUp");
syntheticEvents.add("onMouseMove");
syntheticEvents.add("onSubmit");
syntheticEvents.add("onDblClick");
syntheticEvents.add("onKeyDown");
syntheticEvents.add("onKeyUp");
syntheticEvents.add("onKeyPress");
function unmount(iv, parentDom) {
var input = iv.v;
if (isStringOrNumber(input)) {
if (!isNull(parentDom)) {
removeChild(parentDom, iv.d);
}
}
else {
// It's vNode
var flags = input.f;
var dom = iv.d;
var ref = input.r;
var props = input.p;
var childIVs = iv.c;
if ((flags & 241 /* Element */) > 0) {
if (isFunction(ref)) {
ref(null);
}
if (!isNull(childIVs)) {
if (isArray(childIVs)) {
for (var i = 0, len = childIVs.length; i < len; i++) {
unmount(childIVs[i], null);
}
}
else {
unmount(childIVs, null);
}
}
// Remove synthetic events
if (!isNull(props)) {
for (var name_1 in props) {
if (syntheticEvents.has(name_1)) {
handleEvent(name_1, null, dom);
}
}
}
}
else if ((flags & 14 /* Component */) > 0) {
if ((flags & 2 /* ComponentClass */) > 0) {
var instance = iv.i;
if (isFunction(instance.componentWillUnmount)) {
instance.componentWillUnmount();
}
if (isFunction(ref)) {
ref(null);
}
instance.__UN = true;
iv.i = null;
}
else {
if (!isNullOrUndef(ref)) {
if (isFunction(ref.onComponentWillUnmount)) {
ref.onComponentWillUnmount(dom, props);
}
}
}
iv.b = null;
if (!isNull(childIVs) && !isInvalid(childIVs.v)) {
unmount(childIVs, null);
}
}
if (!isNull(parentDom) && !isNull(dom)) {
removeChild(parentDom, dom);
}
}
}
// We need EMPTY_OBJ defined in one place.
// Its used for comparison so we cant inline it into shared
var EMPTY_OBJ = {};
if (process.env.NODE_ENV !== "production") {
Object.freeze(EMPTY_OBJ);
}
function replaceDOM(iv, parentDom, newDOM) {
unmount(iv, null);
replaceChild(parentDom, newDOM, iv.d);
iv.d = newDOM;
}
function setTextContent(dom, text) {
if (text !== "") {
dom.textContent = text;
}
else {
dom.appendChild(document.createTextNode(""));
}
}
function appendChild(parentDom, dom) {
parentDom.appendChild(dom);
}
function insertOrAppend(iv, parentDom, newNode, nextNode) {
if (isNull(nextNode)) {
appendChild(parentDom, newNode);
}
else {
parentDom.insertBefore(newNode, nextNode);
}
iv.d = newNode;
}
function replaceWithNewNode(iv, nextInput, parentDom, lifecycle, isSVG) {
var oldNode = iv.d;
unmount(iv, null);
var newDom = mount(iv, nextInput, parentDom, lifecycle, isSVG, false);
if (isNull(newDom)) {
removeChild(parentDom, oldNode);
}
else {
replaceChild(parentDom, newDom, oldNode);
}
iv.d = newDom;
}
function replaceChild(parentDom, nextDom, lastDom) {
parentDom.replaceChild(nextDom, lastDom);
}
function removeChild(parentDom, dom) {
parentDom.removeChild(dom);
}
function removeAllChildren(parentIV, dom, children) {
for (var i = 0, len = children.length; i < len; i++) {
unmount(children[i], null);
}
parentIV.c = null;
parentIV.f = 1 /* HasInvalidChildren */;
dom.textContent = "";
}
function mount(iv, input, parentDom, lifecycle, isSVG, insertIntoDOM) {
// Text - Number
if (isStringOrNumber(input)) {
return mountText(iv, input, parentDom, insertIntoDOM);
}
else {
// VNode
var flags = input.f;
if ((flags & 241 /* Element */) > 0) {
return mountElement(iv, input, parentDom, lifecycle, isSVG, insertIntoDOM);
}
else if ((flags & 14 /* Component */) > 0) {
return mountComponent(iv, input, parentDom, lifecycle, isSVG, (flags & 2 /* ComponentClass */) > 0, insertIntoDOM);
}
else {
if (process.env.NODE_ENV !== "production") {
if (typeof input === "object") {
throwError("mount() received an object that's not a valid VNode, you should stringify it first. Object: \"" + JSON.stringify(input) + "\".");
}
else {
throwError("mount() expects a valid VNode, instead it received an object with the type \"" + typeof input + "\".");
}
}
throwError();
}
}
}
function mountText(iv, text, parentDom, insertIntoDom) {
var dom = document.createTextNode(text);
if (insertIntoDom) {
iv.d = dom;
appendChild(parentDom, dom);
}
iv.f = 8 /* HasTextChildren */;
return dom;
}
function mountElement(iv, vNode, parentDom, lifecycle, isSVG, insertIntoDom) {
var dom;
var flags = vNode.f;
var tag = vNode.t;
isSVG = isSVG || (flags & 16 /* SvgElement */) > 0;
if (isSVG) {
dom = document.createElementNS(svgNS, tag);
}
else {
dom = document.createElement(tag);
}
var children = vNode.c;
var props = vNode.p;
var className = vNode.cN;
var ref = vNode.r;
if (!isInvalid(children)) {
if (isStringOrNumber(children)) {
// Text
setTextContent(dom, children);
iv.f = 8 /* HasTextChildren */;
}
else {
var childrenIsSVG = isSVG === true && tag !== "foreignObject";
if (isArray(children)) {
// Array
mountArrayChildren(iv, children, dom, lifecycle, childrenIsSVG, false);
}
else {
// VNode
var childIV = createIV(children, 0, null);
iv.c = childIV;
iv.f = 16 /* HasBasicChildren */;
mount(childIV, children, dom, lifecycle, childrenIsSVG, true);
}
}
}
else {
iv.f = 1 /* HasInvalidChildren */;
}
if (!isNull(props)) {
for (var prop in props) {
patchProp(prop, null, props[prop], dom, isSVG);
}
}
if (!isNull(className)) {
if (isSVG) {
dom.setAttribute("class", className);
}
else {
dom.className = className;
}
}
if (isFunction(ref)) {
lifecycle.push((function () { return ref(dom); }));
}
if (insertIntoDom) {
iv.d = dom;
appendChild(parentDom, dom);
}
return dom;
}
function mountArrayChildren(iv, children, dom, lifecycle, isSVG, isKeyed) {
iv.c = null;
iv.f = 1 /* HasInvalidChildren */; // default to invalid
for (var i = 0, len = children.length; i < len; i++) {
var child = children[i];
if (!isInvalid(child)) {
if (iv.c === null) {
iv.c = [];
isKeyed =
isKeyed || isObject(child)
? !isNullOrUndef(child.k)
: false;
iv.f = isKeyed ? 2 /* HasKeyedChildren */ : 4 /* HasNonKeydChildren */;
}
var childIV = createIV(child, i, child.k);
iv.c.push(childIV);
mount(childIV, child, dom, lifecycle, isSVG, true);
}
}
}
function mountComponent(iv, vNode, parentDom, lifecycle, isSVG, isClass, insertIntoDom) {
var dom = null;
var type = vNode.t;
var props = vNode.p || EMPTY_OBJ;
var childIV;
var renderOutput;
var instance;
var ref = vNode.r;
if (isClass) {
instance = new type(props);
iv.i = instance;
instance.__BS = false;
instance.__PN = parentDom;
if (instance.p === EMPTY_OBJ) {
instance.p = props;
}
instance.__LC = lifecycle;
instance.__PSS = true;
instance.__SVG = isSVG;
if (isFunction(instance.componentWillMount)) {
instance.__BR = true;
instance.componentWillMount();
instance.__BR = false;
}
renderOutput = instance.render(props, instance.state);
instance.__PSS = false;
instance.__IV = iv;
}
else {
renderOutput = type(props);
}
if (!isInvalid(renderOutput)) {
iv.c = childIV = createIV(renderOutput, 0, null);
childIV.d = dom = mount(childIV, renderOutput, parentDom, lifecycle, isSVG, false);
iv.f = 16 /* HasBasicChildren */;
if (isObject(renderOutput)) {
if ((renderOutput.f & 14 /* Component */) > 0) {
childIV.b = iv;
}
}
}
else {
iv.f = 1 /* HasInvalidChildren */;
}
if (isClass) {
if (isFunction(ref)) {
ref(instance);
}
if (isFunction(instance.componentDidMount)) {
lifecycle.push((function () { return instance.componentDidMount(); }));
}
}
else {
if (!isNull(ref)) {
if (isFunction(ref.onComponentWillMount)) {
ref.onComponentWillMount(props);
}
if (isFunction(ref.onComponentDidMount)) {
lifecycle.push((function () { return ref.onComponentDidMount(dom, props); }));
}
}
}
if (insertIntoDom && !isNull(dom)) {
iv.d = dom;
appendChild(parentDom, dom);
}
return dom;
}
var roots = new Map();
var queue = false;
if (process.env.NODE_ENV !== "production") {
if (document.body === null) {
warning('Soot warning: you cannot initialize soot without "document.body". Wait on "DOMContentLoaded" event, add script to bottom of body, or use async/defer attributes on script tag.');
}
}
function triggerLifecycle(listeners) {
for (var i = 0, len = listeners.length; i < len; i++) {
listeners[i]();
}
listeners.length = 0;
}
var delegatedEvents = new Map();
function handleEvent(name, nextEvent, dom) {
var delegatedRoots = delegatedEvents.get(name);
if (nextEvent) {
if (!delegatedRoots) {
delegatedRoots = { items: new Map(), docEvent: null };
delegatedRoots.docEvent = attachEventToDocument(name, delegatedRoots);
delegatedEvents.set(name, delegatedRoots);
}
delegatedRoots.items.set(dom, nextEvent);
}
else if (delegatedRoots) {
var items = delegatedRoots.items;
if (items.delete(dom)) {
// If any items were deleted, check if listener need to be removed
if (items.size === 0) {
document.removeEventListener(normalizeEventName(name), delegatedRoots.docEvent);
delegatedEvents.delete(name);
}
}
}
}
function normalizeEventName(name) {
return name.substr(2).toLowerCase();
}
function stopPropagation() {
this.cancelBubble = true;
this.stopImmediatePropagation();
}
function attachEventToDocument(name, delegatedRoots) {
var docEvent = function (event) {
var items = delegatedRoots.items;
var count = items.size;
if (count > 0) {
var isClick = event.type === "click";
queue = true;
event.stopPropagation = stopPropagation;
var dom_1 = event.target;
Object.defineProperty(event, "currentTarget", {
configurable: true,
get: function () {
return dom_1;
}
});
while (count > 0) {
var eventsToTrigger = items.get(dom_1);
if (!isUndefined(eventsToTrigger)) {
count--;
if (isFunction(eventsToTrigger)) {
eventsToTrigger(event);
}
else {
eventsToTrigger.event(eventsToTrigger.data, event);
}
if (event.cancelBubble) {
break;
}
}
dom_1 = dom_1.parentNode;
// Html Nodes can be nested fe: span inside button in that scenario browser does not handle disabled attribute on parent,
// because the event listener is on document.body
// Don't process clicks on disabled elements
if (isNull(dom_1) || (isClick && dom_1.disabled)) {
break;
}
}
flushSetStates();
queue = false;
}
};
document.addEventListener(normalizeEventName(name), docEvent);
return docEvent;
}
/**
* Renders virtual node tree into parent node.
* @param {VNode | null | string | number} input v to be rendered
* @param {*} parentDom DOM node which content will be replaced by virtual node
* @param {Function?} callback Callback to be called after rendering has finished
* @returns {void}
*/
function render(input, parentDom, callback) {
if (input === NO_OP) {
return;
}
queue = true;
var root = roots.get(parentDom);
var rootIV;
var lifecycle;
if (root === undefined) {
if (isInvalid(input)) {
return;
}
rootIV = createIV(input, 0, null);
lifecycle = [];
mount(rootIV, input, parentDom, lifecycle, false, true);
roots.set(parentDom, {
iv: rootIV,
lifeCycle: lifecycle
});
}
else {
rootIV = root.iv;
lifecycle = root.lifeCycle;
if (isNullOrUndef(input) && !isInvalid(rootIV.v)) {
unmount(rootIV, parentDom);
roots.delete(parentDom);
}
else {
patch(rootIV, input, parentDom, lifecycle, false);
}
}
triggerLifecycle(lifecycle);
if (!isNullOrUndef(callback)) {
callback();
}
flushSetStates();
queue = false;
}
function patch(iv, nextInput, parentDom, lifecycle, isSVG) {
var lastInput = iv.v;
if (lastInput !== nextInput) {
if (isStringOrNumber(nextInput)) {
if (isStringOrNumber(lastInput)) {
iv.d.nodeValue = nextInput;
}
else {
replaceDOM(iv, parentDom, mountText(iv, nextInput, null, false));
}
}
else if (isStringOrNumber(lastInput)) {
replaceDOM(iv, parentDom, mount(iv, nextInput, parentDom, lifecycle, isSVG, false));
}
else {
var lastFlags = lastInput.f;
var nextFlags = nextInput.f;
if ((nextFlags & 241 /* Element */) > 0) {
if ((lastFlags & 241 /* Element */) > 0) {
patchElement(iv, lastInput, nextInput, parentDom, lifecycle, isSVG);
}
else {
replaceDOM(iv, parentDom, mountElement(iv, nextInput, parentDom, lifecycle, isSVG, false));
}
}
else if ((nextFlags & 14 /* Component */) > 0) {
var isClass = (nextFlags & 2 /* ComponentClass */) > 0;
if ((lastFlags & 14 /* Component */) > 0) {
var lastType = lastInput.t;
var nextType = nextInput.t;
var lastKey = lastInput.k;
var nextKey = nextInput.k;
if (lastType !== nextType || lastKey !== nextKey) {
replaceWithNewNode(iv, nextInput, parentDom, lifecycle, isSVG);
}
else {
var nextProps = nextInput.p || EMPTY_OBJ;
if (isClass) {
var instance = iv.i;
instance.__IV = iv;
if (!instance.__UN) {
handleUpdate(instance, instance.state, nextProps, false, isSVG, lifecycle, parentDom);
}
}
else {
var shouldUpdate = true;
var lastProps = lastInput.p;
var nextHooks = nextInput.r;
var nextHooksDefined = !isNullOrUndef(nextHooks);
if (lastKey !== nextKey) {
shouldUpdate = true;
}
else {
if (nextHooksDefined &&
!isNullOrUndef(nextHooks.onComponentShouldUpdate)) {
shouldUpdate = nextHooks.onComponentShouldUpdate(lastProps, nextProps);
}
}
if (shouldUpdate !== false) {
if (nextHooksDefined &&
!isNullOrUndef(nextHooks.onComponentWillUpdate)) {
nextHooks.onComponentWillUpdate(lastProps, nextProps);
}
var renderOutput = nextType(nextProps);
if (renderOutput !== NO_OP) {
patchChildren(iv, renderOutput, parentDom, lifecycle, isSVG);
iv.d = iv.c === null ? null : iv.c.d;
if (nextHooksDefined &&
!isNullOrUndef(nextHooks.onComponentDidUpdate)) {
nextHooks.onComponentDidUpdate(lastProps, nextProps);
}
}
}
}
}
}
else {
replaceDOM(iv, parentDom, mountComponent(iv, nextInput, parentDom, lifecycle, isSVG, isClass, false));
}
}
}
}
iv.v = nextInput;
}
function patchChildren(parentIV, nextInput, parentDOM, lifecycle, childrenIsSVG) {
var childFlags = parentIV.f;
var childIVs = parentIV.c;
if ((childFlags & 8 /* HasTextChildren */) > 0) {
if (isInvalid(nextInput)) {
removeChild(parentDOM, parentDOM.firstChild);
parentIV.f = 1 /* HasInvalidChildren */;
}
else if (isStringOrNumber(nextInput)) {
parentDOM.firstChild.nodeValue = nextInput;
}
else if (isVNode(nextInput)) {
childIVs = createIV(nextInput, 0, null);
var newDOM = mount(childIVs, nextInput, parentDOM, lifecycle, childrenIsSVG, false);
replaceChild(parentDOM, newDOM, parentDOM.firstChild);
childIVs.d = newDOM;
parentIV.c = childIVs;
parentIV.f = 16 /* HasBasicChildren */;
}
else {
parentDOM.removeChild(parentDOM.firstChild);
mountArrayChildren(parentIV, nextInput, parentDOM, lifecycle, childrenIsSVG, false);
}
}
else if ((childFlags & 1 /* HasInvalidChildren */) > 0) {
if (!isInvalid(nextInput)) {
if (isStringOrNumber(nextInput)) {
setTextContent(parentDOM, nextInput);
parentIV.f = 8 /* HasTextChildren */;
}
else if (isVNode(nextInput)) {
childIVs = createIV(nextInput, 0, null);
mount(childIVs, nextInput, parentDOM, lifecycle, childrenIsSVG, true);
parentIV.c = childIVs;
parentIV.f = 16 /* HasBasicChildren */;
}
else {
mountArrayChildren(parentIV, nextInput, parentDOM, lifecycle, childrenIsSVG, false);
}
}
}
else if ((childFlags & 16 /* HasBasicChildren */) > 0) {
if (isInvalid(nextInput)) {
unmount(childIVs, parentDOM);
parentIV.c = null;
parentIV.f = 1 /* HasInvalidChildren */;
}
else if (isVNode(nextInput)) {
patch(childIVs, nextInput, parentDOM, lifecycle, childrenIsSVG);
}
else if (isStringOrNumber(nextInput)) {
replaceWithNewNode(childIVs, nextInput, parentDOM, lifecycle, childrenIsSVG);
}
else {
unmount(childIVs, parentDOM);
mountArrayChildren(parentIV, nextInput, parentDOM, lifecycle, childrenIsSVG, false);
}
}
else {
// Multiple children
if (isInvalid(nextInput)) {
removeAllChildren(parentIV, parentDOM, childIVs);
}
else if (isArray(nextInput)) {
var lastLength = childIVs === null ? 0 : childIVs.length;
var nextLength = nextInput.length;
if (lastLength === 0) {
if (nextLength > 0) {
mountArrayChildren(parentIV, nextInput, parentDOM, lifecycle, childrenIsSVG, false);
}
}
else if (nextLength === 0) {
removeAllChildren(parentIV, parentDOM, childIVs);
}
else if ((childFlags & 2 /* HasKeyedChildren */) > 0 &&
(nextInput.length > 0 &&
!isNullOrUndef(nextInput[0]) &&
!isNullOrUndef(nextInput[0].k))) {
patchKeyedChildren(parentIV, childIVs, nextInput, parentDOM, lifecycle, childrenIsSVG, lastLength, nextLength);
}
else {
patchNonKeyedChildren(childIVs, nextInput, parentDOM, lifecycle, childrenIsSVG, lastLength, nextLength);
}
}
else if (isStringOrNumber(nextInput)) {
removeAllChildren(parentIV, parentDOM, childIVs);
setTextContent(parentDOM, nextInput);
parentIV.f = 8 /* HasTextChildren */;
}
else {
// vNode
removeAllChildren(parentIV, parentDOM, childIVs);
childIVs = createIV(nextInput, 0, null);
mount(childIVs, nextInput, parentDOM, lifecycle, childrenIsSVG, true);
parentIV.c = childIVs;
parentIV.f = 16 /* HasBasicChildren */;
}
}
}
function patchElement(iv, lastVNode, nextVNode, parentDom, lifecycle, isSVG) {
var nextTag = nextVNode.t;
var lastTag = lastVNode.t;
if (lastTag !== nextTag) {
replaceWithNewNode(iv, nextVNode, parentDom, lifecycle, isSVG);
}
else {
var dom_2 = iv.d;
var lastProps = lastVNode.p;
var nextProps = nextVNode.p;
var lastChildren = lastVNode.c;
var nextChildren = nextVNode.c;
var nextFlags = nextVNode.f;
var nextRef_1 = nextVNode.r;
var lastClassName = lastVNode.cN;
var nextClassName = nextVNode.cN;
isSVG = isSVG || (nextFlags & 16 /* SvgElement */) > 0;
if (lastChildren !== nextChildren) {
var childrenIsSVG = isSVG === true && nextVNode.t !== "foreignObject";
patchChildren(iv, nextChildren, dom_2, lifecycle, childrenIsSVG);
}
if (lastProps !== nextProps) {
var prop = void 0;
if (isNull(lastProps)) {
if (!isNull(nextProps)) {
for (prop in nextProps) {
patchProp(prop, null, nextProps[prop], dom_2, isSVG);
}
}
}
else {
if (isNull(nextProps)) {
for (prop in lastProps) {
removeProp(prop, dom_2, nextFlags);
}
}
else {
for (prop in nextProps) {
patchProp(prop, lastProps[prop], nextProps[prop], dom_2, isSVG);
}
for (prop in lastProps) {
if (!nextProps.hasOwnProperty(prop)) {
removeProp(prop, dom_2, nextFlags);
}
}
}
}
}
if (lastClassName !== nextClassName) {
if (isNullOrUndef(nextClassName)) {
dom_2.removeAttribute("class");
}
else {
if (isSVG) {
dom_2.setAttribute("class", nextClassName);
}
else {
dom_2.className = nextClassName;
}
}
}
if (lastVNode.r !== nextRef_1) {
if (isFunction(nextRef_1)) {
lifecycle.push((function () { return nextRef_1(dom_2); }));
}
}
}
}
function removeProp(prop, dom, nextFlags) {
if (prop === "value") {
// When removing value of select element, it needs to be set to null instead empty string, because empty string is valid value for option which makes that option selected
// MS IE/Edge don't follow html spec for textArea and v elements and we need to set empty string to value in those cases to avoid "null" and "undefined" texts
dom.value = (nextFlags & 128 /* SelectElement */) > 0 ? null : "";
}
else if (prop === "style") {
dom.removeAttribute("style");
}
else if (isAttrAnEvent(prop)) {
handleEvent(prop, null, dom);
}
else {
dom.removeAttribute(prop);
}
}
function patchNonKeyedChildren(childIVs, nextChildren, parentDOM, lifecycle, isSVG, lastIVsLength, nextChildrenLength) {
var nextChild;
var iteratedIV = childIVs[0];
var pos = iteratedIV.p;
var nextNode = iteratedIV.d;
var newChildIVs;
var updatedIVs = 0;
var addedIVs = 0;
for (var j = 0; j < nextChildrenLength; j++) {
nextChild = nextChildren[j];
if (pos === j) {
if (isInvalid(nextChild)) {
unmount(iteratedIV, parentDOM);
lastIVsLength--;
childIVs.splice(addedIVs + updatedIVs, 1);
}
else {
patch(iteratedIV, nextChild, parentDOM, lifecycle, isSVG);
updatedIVs++;
}
if (updatedIVs < lastIVsLength) {
iteratedIV = childIVs[addedIVs + updatedIVs];
pos = iteratedIV.p;
nextNode = iteratedIV.d;
}
else {
nextNode = null;
}
}
else if (!isInvalid(nextChild)) {
newChildIVs = createIV(nextChild, j, null);
insertOrAppend(newChildIVs, parentDOM, mount(newChildIVs, nextChild, parentDOM, lifecycle, isSVG, false), nextNode);
childIVs.splice(j, 0, newChildIVs);
addedIVs++;
}
}
if (updatedIVs < lastIVsLength) {
var firstIndex = updatedIVs;
do {
unmount(childIVs[addedIVs + updatedIVs++], parentDOM);
} while (updatedIVs < lastIVsLength);
childIVs.splice(firstIndex, lastIVsLength - firstIndex); // Remove dead IVs
}
}
function patchKeyedChildren(parentIV, a, b, parentDOM, lifecycle, isSVG, aLength, bLength) {
var aEnd = aLength - 1;
var bEnd = bLength - 1;
var aStart = 0;
var bStart = 0;
var i = -1;
var j;
var aNode;
var bNode;
var nextNode = null;
var nextPos = 0;
var node;
var aStartNode = a[aStart];
var bStartNode = b[bStart];
var aEndNode = a[aEnd];
var bEndNode = b[bEnd];
var newChildIVs = new Array(bLength);
// Step 1
// tslint:disable-next-line
outer: {
// Sync nodes with the same key at the beginning.
while (aStartNode.k === bStartNode.k) {
patch(aStartNode, bStartNode, parentDOM, lifecycle, isSVG);
newChildIVs[bStart] = aStartNode;
aStart++;
bStart++;
if (aStart > aEnd || bStart > bEnd) {
break outer;
}
aStartNode = a[aStart];
bStartNode = b[bStart];
}
// Sync nodes with the same key at the end.
while (aEndNode.k === bEndNode.k) {
patch(aEndNode, bEndNode, parentDOM, lifecycle, isSVG);
newChildIVs[bEnd] = aEndNode;
aEnd--;
bEnd--;
if (aStart > aEnd || bStart > bEnd) {
break outer;
}
nextNode = aEndNode.d;
nextPos = aEnd;
aEndNode = a[aEnd];
bEndNode = b[bEnd];
}
}
if (aStart > aEnd) {
if (bStart <= bEnd) {
nextPos = bEnd + 1;
nextNode = nextPos < bLength ? newChildIVs[nextPos].d : null;
while (bStart <= bEnd) {
node = b[bStart];
var childIV = createIV(node, bStart, node.k);
insertOrAppend(childIV, parentDOM, mount(childIV, node, parentDOM, lifecycle, isSVG, false), nextNode);
newChildIVs[bStart] = childIV;
bStart++;
}
}
}
else if (bStart > bEnd) {
for (i = aStart; i <= aEnd; i++) {
unmount(a[i], parentDOM);
}
}
else {
var sources = new Array(bEnd - bStart + 1).fill(-1);
var keyIndex = new Map();
// Mark all nodes as inserted.
for (i = bStart; i <= bEnd; i++) {
keyIndex.set(b[i].k, i);
}
var moved = false;
var pos = 0;
var bUpdated = 0;
nextPos = 0;
// Try to patch same keys and remove old
for (i = aStart; i <= aEnd; i++) {
aNode = a[i];
j = keyIndex.get(aNode.k);
if (isUndefined(j)) {
unmount(aNode, parentDOM);
}
else {
bNode = b[j];
sources[j - bStart] = i;
if (pos > j) {
moved = true;
}
else {
pos = j;
}
patch(aNode, bNode, parentDOM, lifecycle, isSVG);
newChildIVs[j] = aNode;
bUpdated++;
}
}
if (moved) {
var seq = LIS(sources);
j = seq.length - 1;
for (i = bEnd - bStart; i >= 0; i--) {
if (sources[i] === -1) {
pos = i + bStart;
node = b[pos];
nextPos = pos + 1;
nextNode = nextPos < bLength ? newChildIVs[nextPos].d : null;
var childIV = createIV(node, bStart, node.k);
insertOrAppend(childIV, parentDOM, mount(childIV, node, parentDOM, lifecycle, isSVG, false), nextNode);
newChildIVs[pos] = childIV;
}
else {
if (j < 0 || i !== seq[j]) {
pos = i + bStart;
nextPos = pos + 1;
nextNode = nextPos < bLength ? newChildIVs[nextPos].d : null;
insertOrAppend(newChildIVs[pos], parentDOM, newChildIVs[pos].d, nextNode);
}
else {
j--;
}
}
}
}
else {
for (i = bEnd; i >= bStart && bUpdated !== bLength; i--) {
bNode = b[i];
if (isUndefined(newChildIVs[i])) {
var iv = createIV(bNode, i, bNode.k);
insertOrAppend(iv, parentDOM, mount(iv, bNode, parentDOM, lifecycle, isSVG, false), nextNode);
newChildIVs[i] = iv;
bUpdated++;
}
nextNode = newChildIVs[i].d;
}
}
}
parentIV.c = newChildIVs;
}
// Longest Increasing Subsequence algorithm
// https://en.wikipedia.org/wiki/Longest_increasing_subsequence
function LIS(arr) {
var p = arr.slice(0);
var result = [0];
var i;
var j;
var u;
var v;
var c;
var len = arr.length;
for (i = 0; i < len; i++) {
var arrI = arr[i];
if (arrI !== -1) {
j = result[result.length - 1];
if (arr[j] < arrI) {
p[i] = j;
result.push(i);
continue;
}
u = 0;
v = result.length - 1;
while (u < v) {
c = ((u + v) / 2) | 0;
if (arr[result[c]] < arrI) {
u = c + 1;
}
else {
v = c;
}
}
if (arrI < arr[result[u]]) {
if (u > 0) {
p[i] = result[u - 1];
}
result[u] = i;
}
}
}
u = result.length;
v = result[u - 1];
while (u-- > 0) {
result[u] = v;
v = p[v];
}
return result;
}
function isAttrAnEvent(attr) {
return attr[0] === "o" && attr[1] === "n";
}
function patchProp(prop, lastValue, nextValue, dom, isSVG) {
if (lastValue !== nextValue && !skipProps.has(prop)) {
if (booleanProps.has(prop)) {
dom[prop] = !!nextValue;
}
else if (isAttrAnEvent(prop)) {
patchEvent(prop, lastValue, nextValue, dom);
}
else if (isNullOrUndef(nextValue)) {
dom.removeAttribute(prop);
}
else if (prop === "style") {
patchStyle(lastValue, nextValue, dom);
}
else {
// We optimize for condition being boolean. Its 99.9% time false
if (isSVG && namespaces.has(prop)) {
// If we end up in this path we can read property again
dom.setAttributeNS(namespaces.get(prop), prop, nextValue);
}
else {
dom.setAttribute(prop, nextValue);
}
}
}
}
function createEventCallback(fn, data) {
if (isFunction(fn)) {
return function (a1, a2) {
queue = true;
if (isNull(data)) {
fn(a1, a2);
}
else {
fn(data, a1, a2);
}
flushSetStates();
queue = false;
};
}
return null;
}
function patchEvent(name, lastValue, nextValue, dom) {
if (lastValue !== nextValue) {
if (syntheticEvents.has(name)) {
handleEvent(name, nextValue, dom);
}
else {
var nameLowerCase = name.toLowerCase();
dom[nameLowerCase] =
!isFunction(nextValue) && !isNullOrUndef(nextValue)
? createEventCallback(nextValue.event, nextValue.data)
: createEventCallback(nextValue, null);
}
}
}
// We are assuming here that we come from patchProp routine
// -nextAttrValue cannot be null or undefined
function patchStyle(lastAttrValue, nextAttrValue, dom) {
var domStyle = dom.style;
var style;
var value;
if (isString(nextAttrValue)) {
domStyle.cssText = nextAttrValue;
}
else if (!isNullOrUndef(lastAttrValue) && !isString(lastAttrValue)) {
for (style in nextAttrValue) {
value = nextAttrValue[style];
if (value !== lastAttrValue[style]) {
domStyle.setProperty(style, value);
}
}
for (style in lastAttrValue) {
if (isNullOrUndef(nextAttrValue[style])) {
domStyle.removeProperty(style);
}
}
}
else {
for (style in nextAttrValue) {
domStyle.setProperty(style, nextAttrValue[style]);
}
}
}
function queueStateChanges(component, newState, callback) {
if (isFunction(newState)) {
newState = newState(component.state, component.props);
}
var pending = component.__PS;
if (isNullOrUndef(pending)) {
component.__PS = pending = newState;
}
else {
for (var stateKey in newState) {
pending[stateKey] = newState[stateKey];
}
}
if (!component.__PSS && !component.__BR) {
queueStateChange(component, callback);
}
else {
var state = component.state;
if (state === null) {
component.state = pending;
}
else {
for (var key in pending) {
state[key] = pending[key];
}
}
component.__PS = null;
if (component.__BR && isFunction(callback)) {
component.__LC.push(callback.bind(component));
}
}
}
var componentFlushQueue = [];
function handleUpdate(component, nextState, nextProps, fromSetState, isSVG, lifecycle, parentDom) {
var hasComponentDidUpdateIsFunction = isFunction(component.componentDidUpdate);
// When component has componentDidUpdate hook, we need to clone lastState or will be modified by reference during update
var prevState = hasComponentDidUpdateIsFunction
? combineFrom(nextState, null)
: component.state;
var prevProps = component.props;
if (prevProps !== nextProps || nextProps === EMPTY_OBJ) {
if (!fromSetState && isFunction(component.componentWillReceiveProps)) {
// keep a copy of state before componentWillReceiveProps
var beforeState = combineFrom(component.state);
component.__BR = true;
component.componentWillReceiveProps(nextProps);
component.__BR = false;
var afterState = component.state;
if (beforeState !== afterState) {
// if state changed in componentWillReceiveProps, reassign the beforeState
component.state = beforeState;
// set the afterState as pending state so the change gets picked up below
component.__PSS = true;
component.__PS = afterState;
}
}
if (component.__PSS) {
nextState = combineFrom(nextState, component.__PS);
component.__PSS = false;
component.__PS = null;
}
}
/* Update if scu is not defined, or it returns truthy value*/
var hasSCU = isFunction(component.shouldComponentUpdate);
if (!hasSCU ||
(hasSCU &&
component.shouldComponentUpdate(nextProps, nextState) !==
false)) {
if (isFunction(component.componentWillUpdate)) {
component.__BS = true;
component.componentWillUpdate(nextProps, nextState);
component.__BS = false;
}
component.props = nextProps;
component.state = nextState;
var iv = component.__IV;
var renderOutput = component.render(nextProps, nextState);
if (renderOutput !== NO_OP) {
patchChildren(iv, renderOutput, parentDom, lifecycle, isSVG);
var dom = iv.c === null ? null : iv.c.d;
iv.d = dom;
if (fromSetState) {
triggerLifecycle(lifecycle);
var parent_1 = iv.b;
while (!isNull(parent_1)) {
parent_1.d = dom;
parent_1 = parent_1.b;
}
}
if (hasComponentDidUpdateIsFunction) {
component.componentDidUpdate(prevProps, prevState);
}
}
}
else {
component.props = nextProps;
component.state = nextState;
}
component.__PN = parentDom;
}
function applyState(component) {
if (component.__UN) {
return;
}
if (!component.__BR) {
var pendingState = component.__PS;
component.__PSS = false;
component.__PS = null;
handleUpdate(component, combineFrom(component.state, pendingState), component.props, true, component.__SVG, component.__LC, component.__PN);
}
else {
component.state = component.__PS;
component.__PS = null;
}
}
function flushSetStates() {
var length = componentFlushQueue.length;
if (length > 0) {
for (var i = 0; i < length; i++) {
var component = componentFlushQueue[i];
applyState(component);
var callbacks = component.__FCB;
if (!isNull(callbacks)) {
for (var j = 0, len = callbacks.length; j < len; j++) {
callbacks[i].call(component);
}
component.__FCB = null;
}
component.__FP = false; // Flush no longer pending for this component
}
componentFlushQueue = [];
}
}
function queueStateChange(component, callback) {
if (queue) {
if (!component.__FP) {
component.__FP = true;
componentFlushQueue.push(component);
}
if (isFunction(callback)) {
var callbacks = component.__FCB;
if (callbacks === null) {
component.__FCB = [callback];
}
else {
callbacks.push(callback);
}
}
}
else {
queue = true;
applyState(component);
flushSetStates();
queue = false;
if (isFunction(callback)) {
callback.call(component);
}
}
}
var Component = (function () {
function Component(props) {
this.state = null;
this.__BR = false;
this.__BS = true;
this.__PSS = false;
this.__PS = null;
this.__UN = false;
this.__SVG = false;
this.__FP = false; // Flush Pending
this.__FCB = null; // Flush callbacks for this component
this.props = props || EMPTY_OBJ;
}
Component.prototype.setState = function (newState, callback) {
if (this.__UN) {
return;
}
if (!this.__BS) {
queueStateChanges(this, newState, callback);
}
else {
if (process.env.NODE_ENV !== "production") {
throwError("cannot update state via setState() in componentWillUpdate() or constructor.");
}
throwError();
}
};
// tslint:disable-next-line:no-empty
Component.prototype.render = function (nextProps, nextState) { };
return Component;
}());
if (process.env.NODE_ENV !== "production") {
/* tslint:disable-next-line:no-empty */
var testFunc = function testFn() { };
if ((testFunc.name || testFunc.toString()).indexOf("testFn") ===
-1) {
warning("It looks like you're using a minified copy of the development build " +
"of Soot. When deploying Soot apps to production, make sure to use " +
"the production build which skips development warnings and is faster. ");
}
}
var version = "1.0.3";
exports.EMPTY_OBJ = EMPTY_OBJ;
exports.Component = Component;
exports.NO_OP = NO_OP;
exports.V = V;
exports.linkEvent = linkEvent;
exports.render = render;
exports.version = version;