Created
February 18, 2019 18:59
-
-
Save mrozbarry/b1861b4f937726154b5273eaf4222cd1 to your computer and use it in GitHub Desktop.
Hyperapp with dev middleware
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
(function (global, factory) { | |
typeof exports === 'object' && typeof module !== 'undefined' ? factory(exports) : | |
typeof define === 'function' && define.amd ? define(['exports'], factory) : | |
(factory((global.hyperapp = {}))); | |
}(this, (function (exports) { 'use strict'; | |
var merge = function(a, b) { | |
var target = {}; | |
for (var i in a) target[i] = a[i]; | |
for (var i in b) target[i] = b[i]; | |
return target | |
}; | |
function timeTravelDebugger(app, h, setState, dispatch) { | |
var debuggerId = Math.random().toString(36).slice(2); | |
var windowId = "hyperappDebugger." + debuggerId; | |
var debugWindow = window.open( | |
"", | |
windowId, | |
"dependent=yes,alwaysRaised=yes,dialog=yes,width=350,height=500,left=0,bottom=0" | |
); | |
var title = debugWindow.document.createElement('title'); | |
title.innerText = 'Hyperapp Debugger'; | |
debugWindow.document.head.appendChild(title); | |
var debuggerCss = [ | |
"@import url('https://fonts.googleapis.com/css?family=Open+Sans');", | |
"html, body { padding: 0; margin: 0; font-size: 16px; font-family: 'Open Sans', sans-serif; height: 100vh }", | |
"* { box-sizing: border-box; }", | |
].join('\n'); | |
var styleSheet = debugWindow.document.createElement('style'); | |
styleSheet.type = 'text/css'; | |
styleSheet.innerText = debuggerCss; | |
debugWindow.document.head.appendChild(styleSheet); | |
var makeStream = function() { | |
var actionState = { actionName: '<init>' }; | |
var listener = null; | |
var pending = []; | |
var setCurrentAction = function(action, data) { | |
if (typeof action === 'function' && typeof actionState.actionName === 'undefined') { | |
actionState.actionName = action.name; | |
actionState.actionData = data; | |
} | |
}; | |
var setCurrentState = function(state) { | |
if (actionState.actionName && typeof actionState.state === 'undefined') { | |
actionState.state = state; | |
pending.push(actionState); | |
if (listener) { | |
listener(actionState); | |
} | |
actionState = {}; | |
} | |
}; | |
return { | |
setAction: setCurrentAction, | |
setState: setCurrentState, | |
listen: function(cb) { | |
listener = cb; | |
pending.forEach(function(p) { listener(p); }); | |
pending = []; | |
return function() { | |
if (listener === cb) { | |
listener = null; | |
} | |
} | |
} | |
} | |
}; | |
var stream = makeStream(); | |
var wrappedSetState = function(nextState) { | |
stream.setState(nextState); | |
return setState(nextState) | |
}; | |
var wrappedDispatch = function(obj, data) { | |
stream.setAction(obj); | |
return dispatch(obj, data) | |
}; | |
var streamSubFx = function(args, dispatch) { | |
var fire = function(actionState) { | |
dispatch(args.action, actionState); | |
}; | |
var cancel = stream.listen(fire); | |
return function() { | |
cancel(); | |
} | |
}; | |
var dragAndDropSubFx = function(args, dispatch) { | |
var updateHistory = function (file) { | |
var reader = new FileReader(); | |
reader.onload = function(event) { | |
var history = JSON.parse(event.target.result); | |
dispatch(args.action, history); | |
}; | |
reader.readAsText(file); | |
}; | |
var onDragOver = function(event) { | |
var dataTransfer = event.dataTransfer; | |
var hasFiles = ( | |
(dataTransfer.files && dataTransfer.files.length > 0) | |
|| (dataTransfer.types && Array.from(dataTransfer.types).indexOf('Files') >= 0) | |
); | |
if (hasFiles) { | |
event.preventDefault(); | |
} | |
}; | |
var onDrop = function(event) { | |
event.preventDefault(); | |
for(var i = 0; i < event.dataTransfer.files.length; i++) { | |
var file = event.dataTransfer.files[i]; | |
if (file.type === 'application/json') { | |
updateHistory(file); | |
break | |
} | |
} | |
}; | |
debugWindow.document.body.addEventListener('dragover', onDragOver); | |
debugWindow.document.body.addEventListener('drop', onDrop); | |
return function() { | |
debugWindow.document.body.removeEventListener('dragover', onDragOver); | |
debugWindow.document.body.removeEventListener('drop', onDrop); | |
} | |
}; | |
var setHistoryAction = function(state, history) { | |
var currentTime = history.length - 1; | |
dispatch(function() { return history[currentTime].state }, {}); | |
return merge(state, { | |
history: history, | |
currentTime: currentTime, | |
}) | |
}; | |
var addHistoryAction = function(state, actionState) { | |
var nextHistory = state.history.concat(actionState); | |
return merge(state, { | |
history: nextHistory, | |
currentTime: nextHistory.length - 1, | |
}) | |
}; | |
var setCurrentTimeAction = function(state, event) { | |
var currentTime = parseInt(event.target.value, 10); | |
dispatch(function() { return state.history[currentTime].state }, {}); | |
return merge(state, { | |
currentTime: currentTime, | |
}) | |
}; | |
var setViewModeAction = function(state, event) { | |
return merge(state, { | |
view: event.target.value, | |
}) | |
}; | |
var styles = { | |
container: { | |
display: 'flex', | |
flexDirection: 'column', | |
alignItems: 'center', | |
justifyContent: 'flex-start', | |
height: '100%', | |
width: '100%', | |
overflow: 'hidden', | |
}, | |
section: { | |
width: '100%', | |
padding: '1rem', | |
paddingBottom: '0', | |
}, | |
actionContainer: { | |
width: '100%', | |
display: 'flex', | |
flexDirection: 'row', | |
alignItems: 'center', | |
justifyContent: 'space-evenly' | |
}, | |
timeLabel: { | |
display: 'block', | |
width: '100%', | |
}, | |
inputRange: { | |
display: 'block', | |
width: '100%', | |
}, | |
actionSelect: { | |
display: 'block', | |
width: '100%', | |
}, | |
stateContainer: { | |
display: 'block', | |
width: '100%', | |
flexGrow: 1, | |
}, | |
controlsContainer: { | |
display: 'flex', | |
flexDirection: 'row', | |
alignItems: 'flex-start', | |
justifyContent: 'space-between', | |
width: '100%', | |
}, | |
jsonString: { | |
color: 'red', | |
}, | |
jsonNumber: { | |
color: 'blue', | |
}, | |
}; | |
var viewControlsView = function(history, view) { | |
var dataUrl = "data:text/json;charset=utf-8," + encodeURIComponent(JSON.stringify(history)); | |
return h('section', { style: merge(styles.section, styles.controlsContainer) }, [ | |
h('select', { onChange: setViewModeAction }, [ | |
h('option', { value: 'by-time', selected: view === 'by-time' }, 'History By Time'), | |
h('option', { value: 'by-action', selected: view === 'by-action' }, 'History By Action'), | |
]), | |
h('div', null, [ | |
h('a', { href: dataUrl, download: 'history.json' }, 'Save History'), | |
]) | |
]) | |
}; | |
var indentView = function(children) { | |
return h('div', { style: { paddingLeft: '0.5rem' } }, children); | |
}; | |
var showVariableView = function(variable, key) { | |
var showKey = function() { | |
return key ? h('strong', null, key + ': ') : '' | |
}; | |
if (Array.isArray(variable)) { | |
return h( | |
'div', | |
null, | |
[ | |
showKey, | |
'[', | |
indentView(variable.map(function (value, index) { return showVariableView(value, index) })), | |
']' | |
] | |
) | |
} else if (variable === null || typeof variable !== 'object') { | |
var isString = typeof variable === 'string'; | |
var wrap = isString ? '"' : ''; | |
return h( | |
'div', | |
null, | |
[ | |
showKey(), | |
h( | |
'span', | |
{ | |
style: isString ? styles.jsonString : styles.jsonNumber, | |
}, | |
[ | |
wrap, | |
variable.toString(), | |
wrap, | |
], | |
) | |
] | |
) | |
} else if (typeof variable === 'undefined') { | |
return null; | |
} else { | |
return h( | |
'div', | |
null, | |
[ | |
showKey(), | |
'{', | |
indentView(Object.keys(variable).map(function (key) { return showVariableView(variable[key], key) })), | |
'}' | |
] | |
) | |
} | |
}; | |
var showStateView = function(time) { | |
return h('section', { style: merge(styles.section, styles.stateContainer) }, [ | |
h('div', null, time ? time.actionName : [h('i', null, 'No Action')]), | |
showVariableView(time.state, 'state'), | |
]) | |
}; | |
var timeView = function(history, index, time, view) { | |
var value = index; | |
var max = history.length - 1; | |
return h( | |
'div', | |
{ style: styles.container }, | |
[ | |
h('section', { style: styles.section }, [ | |
h('label', { style: styles.timeLabel }, [ | |
h('div', null, 'Time'), | |
h('input', { | |
key: max, | |
type: 'range', | |
value: value, | |
min: 0, | |
max: max, | |
oninput: setCurrentTimeAction, | |
style: styles.inputRange | |
}) | |
]), | |
]), | |
showStateView(time), | |
viewControlsView(history, view), | |
] | |
) | |
}; | |
var actionView = function(history, index, time, view) { | |
var grouped = history.reduce(function (memo, currentHistory, index) { | |
var last = memo.slice(-1)[0]; | |
var shouldAppend = last && last.actionName === currentHistory.actionName; | |
var current = merge(currentHistory, { index: index }); | |
return shouldAppend | |
? memo.slice(0, -1).concat(merge(last, { children: last.children.concat(current) })) | |
: memo.concat({ actionName: current.actionName, children: [current] }) | |
}, []); | |
var currentGroupIndex = grouped.findIndex(function(group) { | |
return group.children.find(function(child) { return child.index === index }) | |
}); | |
var currentGroup = grouped[currentGroupIndex]; | |
return h( | |
'div', | |
{ style: styles.container }, | |
[ | |
h('section', { style: merge(styles.section, styles.actionContainer) }, [ | |
h('select', { size: 10, onchange: setCurrentTimeAction, style: styles.actionSelect }, grouped.map(function(group, groupIndex) { | |
return h('option', { value: group.children.slice(-1)[0].index, selected: currentGroupIndex === groupIndex }, group.actionName + ' (' + group.children.length + ')') | |
})), | |
h('select', { size: 10, onchange: setCurrentTimeAction, style: styles.actionSelect }, currentGroup.children.map(function(child, childIndex) { | |
return h('option', { value: child.index, selected: child.index === index }, 'Diff ' + child.index.toString()) | |
})), | |
]), | |
showStateView(time), | |
viewControlsView(history, view), | |
] | |
) | |
}; | |
app({ | |
init: { history: [], currentTime: -1, view: 'by-time' }, | |
container: debugWindow.document.body, | |
view: function(state) { | |
var time = state.history[state.currentTime] || { state: {} }; | |
return state.view === 'by-time' | |
? timeView(state.history, state.currentTime, time) | |
: actionView(state.history, state.currentTime, time) | |
}, | |
subscriptions: function(state) { | |
return [ | |
{ effect: streamSubFx, action: addHistoryAction }, | |
{ effect: dragAndDropSubFx, action: setHistoryAction } | |
] | |
}, | |
timeTravelDebugger: false, | |
}); | |
return { | |
setState: wrappedSetState, | |
dispatch: wrappedDispatch | |
} | |
} | |
var DEFAULT = 0; | |
var RECYCLED_NODE = 1; | |
var TEXT_NODE = 3; // Node.TEXT_NODE | |
var XLINK_NS = "http://www.w3.org/1999/xlink"; | |
var SVG_NS = "http://www.w3.org/2000/svg"; | |
var EMPTY_OBJECT = {}; | |
var EMPTY_ARRAY = []; | |
var map = EMPTY_ARRAY.map; | |
var isArray = Array.isArray; | |
var merge$1 = function(a, b) { | |
var target = {}; | |
for (var i in a) target[i] = a[i]; | |
for (var i in b) target[i] = b[i]; | |
return target | |
}; | |
var resolved = typeof Promise === "function" && Promise.resolve(); | |
var defer = !resolved | |
? setTimeout | |
: function(cb) { | |
return resolved.then(cb) | |
}; | |
var updateProperty = function( | |
element, | |
name, | |
lastValue, | |
nextValue, | |
eventProxy, | |
isSvg | |
) { | |
if (name === "key") ; else if (name === "style") { | |
for (var i in merge$1(lastValue, nextValue)) { | |
var style = nextValue == null || nextValue[i] == null ? "" : nextValue[i]; | |
if (i[0] === "-") { | |
element[name].setProperty(i, style); | |
} else { | |
element[name][i] = style; | |
} | |
} | |
} else { | |
if (name[0] === "o" && name[1] === "n") { | |
name = name.slice(2).toLowerCase(); | |
if (!element.events) element.events = {}; | |
element.events[name] = nextValue; | |
if (nextValue == null) { | |
element.removeEventListener(name, eventProxy); | |
} else if (lastValue == null) { | |
element.addEventListener(name, eventProxy); | |
} | |
} else { | |
var nullOrFalse = nextValue == null || nextValue === false; | |
if ( | |
name in element && | |
name !== "list" && | |
name !== "draggable" && | |
name !== "spellcheck" && | |
name !== "translate" && | |
!isSvg | |
) { | |
element[name] = nextValue == null ? "" : nextValue; | |
if (nullOrFalse) { | |
element.removeAttribute(name); | |
} | |
} else { | |
var ns = isSvg && name !== (name = name.replace(/^xlink:?/, "")); | |
if (ns) { | |
if (nullOrFalse) { | |
element.removeAttributeNS(XLINK_NS, name); | |
} else { | |
element.setAttributeNS(XLINK_NS, name, nextValue); | |
} | |
} else { | |
if (nullOrFalse) { | |
element.removeAttribute(name); | |
} else { | |
element.setAttribute(name, nextValue); | |
} | |
} | |
} | |
} | |
} | |
}; | |
var createElement = function(node, lifecycle, eventProxy, isSvg) { | |
var element = | |
node.type === TEXT_NODE | |
? document.createTextNode(node.name) | |
: (isSvg = isSvg || node.name === "svg") | |
? document.createElementNS(SVG_NS, node.name) | |
: document.createElement(node.name); | |
var props = node.props; | |
if (props.onCreate) { | |
lifecycle.push(function() { | |
props.onCreate(element); | |
}); | |
} | |
for (var i = 0, length = node.children.length; i < length; i++) { | |
element.appendChild( | |
createElement(node.children[i], lifecycle, eventProxy, isSvg) | |
); | |
} | |
for (var name in props) { | |
updateProperty(element, name, null, props[name], eventProxy, isSvg); | |
} | |
return (node.element = element) | |
}; | |
var updateElement = function( | |
element, | |
lastProps, | |
nextProps, | |
lifecycle, | |
eventProxy, | |
isSvg, | |
isRecycled | |
) { | |
for (var name in merge$1(lastProps, nextProps)) { | |
if ( | |
(name === "value" || name === "checked" | |
? element[name] | |
: lastProps[name]) !== nextProps[name] | |
) { | |
updateProperty( | |
element, | |
name, | |
lastProps[name], | |
nextProps[name], | |
eventProxy, | |
isSvg | |
); | |
} | |
} | |
var cb = isRecycled ? nextProps.onCreate : nextProps.onUpdate; | |
if (cb != null) { | |
lifecycle.push(function() { | |
cb(element, lastProps); | |
}); | |
} | |
}; | |
var removeChildren = function(node) { | |
for (var i = 0, length = node.children.length; i < length; i++) { | |
removeChildren(node.children[i]); | |
} | |
var cb = node.props.onDestroy; | |
if (cb != null) { | |
cb(node.element); | |
} | |
return node.element | |
}; | |
var removeElement = function(parent, node) { | |
var remove = function() { | |
parent.removeChild(removeChildren(node)); | |
}; | |
var cb = node.props && node.props.onRemove; | |
if (cb != null) { | |
cb(node.element, remove); | |
} else { | |
remove(); | |
} | |
}; | |
var getKey = function(node) { | |
return node == null ? null : node.key | |
}; | |
var createKeyMap = function(children, start, end) { | |
var out = {}; | |
var key; | |
var node; | |
for (; start <= end; start++) { | |
if ((key = (node = children[start]).key) != null) { | |
out[key] = node; | |
} | |
} | |
return out | |
}; | |
var patchElement = function( | |
parent, | |
element, | |
lastNode, | |
nextNode, | |
lifecycle, | |
eventProxy, | |
isSvg | |
) { | |
if (nextNode === lastNode) ; else if ( | |
lastNode != null && | |
lastNode.type === TEXT_NODE && | |
nextNode.type === TEXT_NODE | |
) { | |
if (lastNode.name !== nextNode.name) { | |
element.nodeValue = nextNode.name; | |
} | |
} else if (lastNode == null || lastNode.name !== nextNode.name) { | |
var newElement = parent.insertBefore( | |
createElement(nextNode, lifecycle, eventProxy, isSvg), | |
element | |
); | |
if (lastNode != null) removeElement(parent, lastNode); | |
element = newElement; | |
} else { | |
updateElement( | |
element, | |
lastNode.props, | |
nextNode.props, | |
lifecycle, | |
eventProxy, | |
(isSvg = isSvg || nextNode.name === "svg"), | |
lastNode.type === RECYCLED_NODE | |
); | |
var savedNode; | |
var childNode; | |
var lastKey; | |
var lastChildren = lastNode.children; | |
var lastChStart = 0; | |
var lastChEnd = lastChildren.length - 1; | |
var nextKey; | |
var nextChildren = nextNode.children; | |
var nextChStart = 0; | |
var nextChEnd = nextChildren.length - 1; | |
while (nextChStart <= nextChEnd && lastChStart <= lastChEnd) { | |
lastKey = getKey(lastChildren[lastChStart]); | |
nextKey = getKey(nextChildren[nextChStart]); | |
if (lastKey == null || lastKey !== nextKey) break | |
patchElement( | |
element, | |
lastChildren[lastChStart].element, | |
lastChildren[lastChStart], | |
nextChildren[nextChStart], | |
lifecycle, | |
eventProxy, | |
isSvg | |
); | |
lastChStart++; | |
nextChStart++; | |
} | |
while (nextChStart <= nextChEnd && lastChStart <= lastChEnd) { | |
lastKey = getKey(lastChildren[lastChEnd]); | |
nextKey = getKey(nextChildren[nextChEnd]); | |
if (lastKey == null || lastKey !== nextKey) break | |
patchElement( | |
element, | |
lastChildren[lastChEnd].element, | |
lastChildren[lastChEnd], | |
nextChildren[nextChEnd], | |
lifecycle, | |
eventProxy, | |
isSvg); | |
lastChEnd--; | |
nextChEnd--; | |
} | |
if (lastChStart > lastChEnd) { | |
while (nextChStart <= nextChEnd) { | |
element.insertBefore( | |
createElement( | |
nextChildren[nextChStart++], | |
lifecycle, | |
eventProxy, | |
isSvg | |
), | |
(childNode = lastChildren[lastChStart]) && childNode.element | |
); | |
} | |
} else if (nextChStart > nextChEnd) { | |
while (lastChStart <= lastChEnd) { | |
removeElement(element, lastChildren[lastChStart++]); | |
} | |
} else { | |
var lastKeyed = createKeyMap(lastChildren, lastChStart, lastChEnd); | |
var nextKeyed = {}; | |
while (nextChStart <= nextChEnd) { | |
lastKey = getKey((childNode = lastChildren[lastChStart])); | |
nextKey = getKey(nextChildren[nextChStart]); | |
if ( | |
nextKeyed[lastKey] || | |
(nextKey != null && nextKey === getKey(lastChildren[lastChStart + 1])) | |
) { | |
if (lastKey == null) { | |
removeElement(element, childNode); | |
} | |
lastChStart++; | |
continue | |
} | |
if (nextKey == null || lastNode.type === RECYCLED_NODE) { | |
if (lastKey == null) { | |
patchElement( | |
element, | |
childNode && childNode.element, | |
childNode, | |
nextChildren[nextChStart], | |
lifecycle, | |
eventProxy, | |
isSvg | |
); | |
nextChStart++; | |
} | |
lastChStart++; | |
} else { | |
if (lastKey === nextKey) { | |
patchElement( | |
element, | |
childNode.element, | |
childNode, | |
nextChildren[nextChStart], | |
lifecycle, | |
eventProxy, | |
isSvg | |
); | |
nextKeyed[nextKey] = true; | |
lastChStart++; | |
} else { | |
if ((savedNode = lastKeyed[nextKey]) != null) { | |
patchElement( | |
element, | |
element.insertBefore( | |
savedNode.element, | |
childNode && childNode.element | |
), | |
savedNode, | |
nextChildren[nextChStart], | |
lifecycle, | |
eventProxy, | |
isSvg | |
); | |
nextKeyed[nextKey] = true; | |
} else { | |
patchElement( | |
element, | |
childNode && childNode.element, | |
null, | |
nextChildren[nextChStart], | |
lifecycle, | |
eventProxy, | |
isSvg | |
); | |
} | |
} | |
nextChStart++; | |
} | |
} | |
while (lastChStart <= lastChEnd) { | |
if (getKey((childNode = lastChildren[lastChStart++])) == null) { | |
removeElement(element, childNode); | |
} | |
} | |
for (var key in lastKeyed) { | |
if (nextKeyed[key] == null) { | |
removeElement(element, lastKeyed[key]); | |
} | |
} | |
} | |
} | |
return (nextNode.element = element) | |
}; | |
var createVNode = function(name, props, children, element, key, type) { | |
return { | |
name: name, | |
props: props, | |
children: children, | |
element: element, | |
key: key, | |
type: type | |
} | |
}; | |
var createTextVNode = function(text, element) { | |
return createVNode(text, EMPTY_OBJECT, EMPTY_ARRAY, element, null, TEXT_NODE) | |
}; | |
var recycleChild = function(element) { | |
return element.nodeType === TEXT_NODE | |
? createTextVNode(element.nodeValue, element) | |
: recycleElement(element) | |
}; | |
var recycleElement = function(element) { | |
return createVNode( | |
element.nodeName.toLowerCase(), | |
EMPTY_OBJECT, | |
map.call(element.childNodes, recycleChild), | |
element, | |
null, | |
RECYCLED_NODE | |
) | |
}; | |
var patch = function(container, element, lastNode, nextNode, eventProxy) { | |
var lifecycle = []; | |
element = patchElement( | |
container, | |
element, | |
lastNode, | |
nextNode, | |
lifecycle, | |
eventProxy | |
); | |
while (lifecycle.length > 0) lifecycle.pop()(); | |
return element | |
}; | |
var h = function(name, props) { | |
var node; | |
var rest = []; | |
var children = []; | |
var length = arguments.length; | |
while (length-- > 2) rest.push(arguments[length]); | |
if ((props = props == null ? {} : props).children != null) { | |
if (rest.length <= 0) { | |
rest.push(props.children); | |
} | |
delete props.children; | |
} | |
while (rest.length > 0) { | |
if (isArray((node = rest.pop()))) { | |
for (length = node.length; length-- > 0; ) { | |
rest.push(node[length]); | |
} | |
} else if (node === false || node === true || node == null) ; else { | |
children.push(typeof node === "object" ? node : createTextVNode(node)); | |
} | |
} | |
return typeof name === "function" | |
? name(props, (props.children = children)) | |
: createVNode(name, props, children, null, props.key, DEFAULT) | |
}; | |
var cancel = function(sub) { | |
sub.cancel(); | |
}; | |
var isSameValue = function(a, b) { | |
if (a !== b) { | |
for (var k in merge$1(a, b)) { | |
if (a[k] !== b[k]) return false | |
} | |
} | |
return true | |
}; | |
var isSameAction = function(a, b) { | |
return ( | |
typeof a === typeof b && | |
(isArray(a) && a[0] === b[0] && isSameValue(a[1], b[1])) | |
) | |
}; | |
var restart = function(sub, oldSub, dispatch) { | |
for (var k in merge$1(sub, oldSub)) { | |
if (k === "cancel") ; else if (sub[k] === oldSub[k] || isSameAction(sub[k], oldSub[k])) ; else { | |
cancel(oldSub); | |
return start(sub, dispatch) | |
} | |
} | |
return oldSub | |
}; | |
var start = function(sub, dispatch) { | |
return merge$1(sub, { | |
cancel: sub.effect(sub, dispatch) | |
}) | |
}; | |
var refresh = function(sub, oldSub, dispatch) { | |
if (isArray(sub) || isArray(oldSub)) { | |
var out = []; | |
var subs = isArray(sub) ? sub : [sub]; | |
var oldSubs = isArray(oldSub) ? oldSub : [oldSub]; | |
for (var i = 0; i < subs.length || i < oldSubs.length; i++) { | |
out.push(refresh(subs[i], oldSubs[i], dispatch)); | |
} | |
return out | |
} | |
return sub | |
? oldSub | |
? restart(sub, oldSub, dispatch) | |
: start(sub, dispatch) | |
: oldSub | |
? cancel(oldSub) | |
: oldSub | |
}; | |
function app(props) { | |
var state; | |
var view = props.view; | |
var subs = props.subscriptions; | |
var container = props.container; | |
var element = container && container.children && container.children[0]; | |
var lastNode = element && recycleElement(element); | |
var lastSub = []; | |
var updateInProgress = false; | |
var setState = function(newState) { | |
if (state !== newState) { | |
state = newState; | |
if (!updateInProgress) { | |
updateInProgress = true; | |
defer(render); | |
} | |
} | |
}; | |
var dispatch = function(obj, data) { | |
if (obj == null) ; else if (typeof obj === "function") { | |
dispatch(obj(state, data)); | |
} else if (isArray(obj)) { | |
if (typeof obj[0] === "function") { | |
dispatch(obj[0](state, obj[1], data)); | |
} else { | |
obj[1].effect(obj[1], dispatch, setState(obj[0])); | |
} | |
} else { | |
setState(obj); | |
} | |
}; | |
var eventProxy = function(event) { | |
dispatch(event.currentTarget.events[event.type], event); | |
}; | |
{ | |
if (props.timeTravelDebugger !== false) { | |
var overrides = timeTravelDebugger(app, h, setState, dispatch); | |
dispatch = overrides.dispatch; | |
setState = overrides.setState; | |
} | |
} | |
var render = function() { | |
updateInProgress = false; | |
if (subs) { | |
lastSub = refresh(subs(state), lastSub, dispatch); | |
} | |
if (view) { | |
element = patch( | |
container, | |
element, | |
lastNode, | |
(lastNode = view(state)), | |
eventProxy | |
); | |
} | |
}; | |
dispatch(props.init); | |
} | |
exports.h = h; | |
exports.app = app; | |
Object.defineProperty(exports, '__esModule', { value: true }); | |
}))); | |
//# sourceMappingURL=hyperapp.js.map |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment