diff --git a/bindModel.js b/bindModel.js index c2759fb..76029da 100644 --- a/bindModel.js +++ b/bindModel.js @@ -1,13 +1,13 @@ -var listener = require('./listener'); +var listener = require('./listener') var binding = require('./binding') var RefreshHook = require('./render').RefreshHook -module.exports = function(tag, attributes, children) { +module.exports = function (tag, attributes, children) { var type = inputType(tag, attributes) - var bind = inputTypeBindings[type] || bindTextInput; + var bind = inputTypeBindings[type] || bindTextInput - var bindingAttr = binding(attributes.binding); - bind(attributes, children, bindingAttr.get, bindingAttr.set); + var bindingAttr = binding(attributes.binding) + bind(attributes, children, bindingAttr.get, bindingAttr.set) } var inputTypeBindings = { @@ -16,145 +16,145 @@ var inputTypeBindings = { textarea: bindTextInput, checkbox: function (attributes, children, get, set) { - attributes.checked = get(); + attributes.checked = get() attachEventHandler(attributes, 'onclick', function (ev) { - attributes.checked = ev.target.checked; - set(ev.target.checked); - }); + attributes.checked = ev.target.checked + set(ev.target.checked) + }) }, radio: function (attributes, children, get, set) { - var value = attributes.value; - attributes.checked = get() == attributes.value; + var value = attributes.value + attributes.checked = get() == attributes.value attributes.on_hyperdomsyncchecked = listener(function (event) { - attributes.checked = event.target.checked; - }); + attributes.checked = event.target.checked + }) attachEventHandler(attributes, 'onclick', function (event) { - var name = event.target.name; + var name = event.target.name if (name) { - var inputs = document.getElementsByName(name); + var inputs = document.getElementsByName(name) for (var i = 0, l = inputs.length; i < l; i++) { - inputs[i].dispatchEvent(customEvent('_hyperdomsyncchecked')); + inputs[i].dispatchEvent(customEvent('_hyperdomsyncchecked')) } } - set(value); - }); + set(value) + }) }, select: function (attributes, children, get, set) { - var currentValue = get(); + var currentValue = get() var options = children.filter(function (child) { - return child.tagName.toLowerCase() == 'option'; - }); + return child.tagName.toLowerCase() == 'option' + }) - var values = []; - var selectedIndex; + var values = [] + var selectedIndex - for(var n = 0; n < options.length; n++) { - var option = options[n]; - var hasValue = option.properties.hasOwnProperty('value'); - var value = option.properties.value; - var text = option.children.map(function (x) { return x.text; }).join(''); + for (var n = 0; n < options.length; n++) { + var option = options[n] + var hasValue = option.properties.hasOwnProperty('value') + var value = option.properties.value + var text = option.children.map(function (x) { return x.text }).join('') - values.push(hasValue? value: text); + values.push(hasValue ? value : text) - var selected = value == currentValue || text == currentValue; + var selected = value == currentValue || text == currentValue if (selected) { - selectedIndex = n; + selectedIndex = n } - option.properties.selected = selected; - option.properties.value = n; + option.properties.selected = selected + option.properties.value = n } if (selectedIndex !== undefined) { - attributes.selectedIndex = selectedIndex; + attributes.selectedIndex = selectedIndex } attachEventHandler(attributes, 'onchange', function (ev) { - attributes.selectedIndex = ev.target.selectedIndex; - set(values[ev.target.value]); - }); + attributes.selectedIndex = ev.target.selectedIndex + set(values[ev.target.value]) + }) }, file: function (attributes, children, get, set) { - var multiple = attributes.multiple; + var multiple = attributes.multiple attachEventHandler(attributes, 'onchange', function (ev) { if (multiple) { - set(ev.target.files); + set(ev.target.files) } else { - set(ev.target.files[0]); + set(ev.target.files[0]) } - }); + }) } -}; +} -function inputType(selector, attributes) { +function inputType (selector, attributes) { if (/^textarea\b/i.test(selector)) { - return 'textarea'; + return 'textarea' } else if (/^select\b/i.test(selector)) { - return 'select'; + return 'select' } else { - return attributes.type || 'text'; + return attributes.type || 'text' } } -function bindTextInput(attributes, children, get, set) { - var textEventNames = ['onkeyup', 'oninput', 'onpaste', 'textInput']; +function bindTextInput (attributes, children, get, set) { + var textEventNames = ['onkeyup', 'oninput', 'onpaste', 'textInput'] - var bindingValue = get(); + var bindingValue = get() if (!(bindingValue instanceof Error)) { - attributes.value = bindingValue != undefined? bindingValue: ''; + attributes.value = bindingValue != undefined ? bindingValue : '' } attachEventHandler(attributes, textEventNames, function (ev) { if (get() != ev.target.value) { - set(ev.target.value); + set(ev.target.value) } - }); + }) } -function attachEventHandler(attributes, eventNames, handler) { +function attachEventHandler (attributes, eventNames, handler) { if (eventNames instanceof Array) { for (var n = 0; n < eventNames.length; n++) { - insertEventHandler(attributes, eventNames[n], handler); + insertEventHandler(attributes, eventNames[n], handler) } } else { - insertEventHandler(attributes, eventNames, handler); + insertEventHandler(attributes, eventNames, handler) } } -function insertEventHandler(attributes, eventName, handler) { - var previousHandler = attributes[eventName]; +function insertEventHandler (attributes, eventName, handler) { + var previousHandler = attributes[eventName] if (previousHandler) { - attributes[eventName] = sequenceFunctions(handler, previousHandler); + attributes[eventName] = sequenceFunctions(handler, previousHandler) } else { - attributes[eventName] = handler; + attributes[eventName] = handler } } -function sequenceFunctions(handler1, handler2) { +function sequenceFunctions (handler1, handler2) { return function (ev) { - handler1(ev); + handler1(ev) if (handler2 instanceof RefreshHook) { - return handler2.handler(ev); + return handler2.handler(ev) } else { - return handler2(ev); + return handler2(ev) } - }; + } } -function customEvent(name) { - if (typeof Event == 'function') { - return new Event(name); +function customEvent (name) { + if (typeof Event === 'function') { + return new Event(name) } else { - var event = document.createEvent('Event'); - event.initEvent(name, false, false); - return event; + var event = document.createEvent('Event') + event.initEvent(name, false, false) + return event } } diff --git a/binding.js b/binding.js index 8650fad..3cb229a 100644 --- a/binding.js +++ b/binding.js @@ -1,7 +1,7 @@ -var refreshify = require('./render').refreshify; -var meta = require('./meta'); +var refreshify = require('./render').refreshify +var meta = require('./meta') -module.exports = function(b, options) { +module.exports = function (b, options) { var binding = b if (b instanceof Array) { @@ -12,28 +12,28 @@ module.exports = function(b, options) { throw Error('hyperdom bindings must be either an array [object, property, setter] or an object { get(), set(value) }, instead binding was: ' + JSON.stringify(b)) } - binding.set = refreshify(binding.set, options); + binding.set = refreshify(binding.set, options) - return binding; + return binding } -function bindingObject(model, property, setter) { - var _meta; +function bindingObject (model, property, setter) { + var _meta return { get: function () { - return model[property]; + return model[property] }, set: function (value) { - model[property] = value; + model[property] = value if (setter) { return setter(value) } }, - meta: function() { - return _meta || (_meta = meta(model, property)); + meta: function () { + return _meta || (_meta = meta(model, property)) } - }; + } } diff --git a/browser.js b/browser.js index c1cde24..6a1b019 100644 --- a/browser.js +++ b/browser.js @@ -1 +1 @@ -window.hyperdom = require('.'); +window.hyperdom = require('.') diff --git a/component.js b/component.js index 23a8d71..757e230 100644 --- a/component.js +++ b/component.js @@ -1,26 +1,26 @@ -var hyperdomMeta = require('./meta'); -var render = require('./render'); +var hyperdomMeta = require('./meta') +var render = require('./render') -function Component(model, options) { +function Component (model, options) { this.isComponent = options && options.hasOwnProperty('component') && options.component - this.model = model; - this.key = model.renderKey; - this.component = undefined; + this.model = model + this.key = model.renderKey + this.component = undefined } -Component.prototype.type = 'Widget'; +Component.prototype.type = 'Widget' Component.prototype.init = function () { - var self = this; + var self = this - var vdom = this.render(); + var vdom = this.render() - var meta = hyperdomMeta(this.model); - meta.components.add(this); + var meta = hyperdomMeta(this.model) + meta.components.add(this) - var currentRender = render.currentRender(); + var currentRender = render.currentRender() this.component = currentRender.mount.createDomComponent() - var element = this.component.create(vdom); + var element = this.component.create(vdom) if (self.model.onbeforeadd) { self.model.onbeforeadd() @@ -33,22 +33,22 @@ Component.prototype.init = function () { if (self.model.onadd || self.model.onrender) { currentRender.finished.then(function () { if (self.model.onadd) { - self.model.onadd(self.component.element); + self.model.onadd(self.component.element) } if (self.model.onrender) { - self.model.onrender(self.component.element); + self.model.onrender(self.component.element) } - }); + }) } if (self.model.detached) { - return document.createTextNode(''); + return document.createTextNode('') } else { - return element; + return element } -}; +} -function beforeUpdate(model, element) { +function beforeUpdate (model, element) { if (model.onbeforeupdate) { model.onbeforeupdate(element) } @@ -58,81 +58,80 @@ function beforeUpdate(model, element) { } } -function afterUpdate(model, element, oldElement) { +function afterUpdate (model, element, oldElement) { if (model.onupdate) { - model.onupdate(element, oldElement); + model.onupdate(element, oldElement) } if (model.onrender) { - model.onrender(element, oldElement); + model.onrender(element, oldElement) } } Component.prototype.update = function (previous) { - var self = this; + var self = this if (this.isComponent) { - var keys = Object.keys(this.model); - for(var n = 0; n < keys.length; n++) { - var key = keys[n]; - previous.model[key] = self.model[key]; + var keys = Object.keys(this.model) + for (var n = 0; n < keys.length; n++) { + var key = keys[n] + previous.model[key] = self.model[key] } - this.model = previous.model; + this.model = previous.model } - if (self.model.onupdate || self.model.onrender) { - var currentRender = render.currentRender(); + var currentRender = render.currentRender() currentRender.finished.then(function () { afterUpdate(self.model, self.component.element, oldElement) - }); + }) } - this.component = previous.component; + this.component = previous.component var oldElement = this.component.element beforeUpdate(this.model, oldElement) - var element = this.component.update(this.render()); + var element = this.component.update(this.render()) if (self.model.detached) { - return document.createTextNode(''); + return document.createTextNode('') } else { - return element; + return element } -}; +} Component.prototype.render = function () { - var currentRender = render.currentRender(); - return currentRender.mount.renderComponent(this.model); -}; + var currentRender = render.currentRender() + return currentRender.mount.renderComponent(this.model) +} Component.prototype.refresh = function () { var oldElement = this.component.element beforeUpdate(this.model, oldElement) - this.component.update(this.render()); + this.component.update(this.render()) afterUpdate(this.model, this.component.element, oldElement) -}; +} Component.prototype.destroy = function (element) { - var self = this; + var self = this - var meta = hyperdomMeta(this.model); - meta.components.delete(this); + var meta = hyperdomMeta(this.model) + meta.components.delete(this) if (self.model.onbeforeremove) { self.model.onbeforeremove(element) } if (self.model.onremove) { - var currentRender = render.currentRender(); + var currentRender = render.currentRender() currentRender.finished.then(function () { - self.model.onremove(element); - }); + self.model.onremove(element) + }) } - this.component.destroy(); -}; + this.component.destroy() +} -module.exports = Component; +module.exports = Component diff --git a/componentWidget.js b/componentWidget.js index 5aaf662..7d6865d 100644 --- a/componentWidget.js +++ b/componentWidget.js @@ -1,140 +1,140 @@ -var VText = require("virtual-dom/vnode/vtext.js") -var domComponent = require('./domComponent'); -var render = require('./render'); -var deprecations = require('./deprecations'); +var VText = require('virtual-dom/vnode/vtext.js') +var domComponent = require('./domComponent') +var render = require('./render') +var deprecations = require('./deprecations') -function ComponentWidget(state, vdom) { +function ComponentWidget (state, vdom) { if (!vdom) { - throw new Error('hyperdom.html.component([options], vdom) expects a vdom argument'); + throw new Error('hyperdom.html.component([options], vdom) expects a vdom argument') } - this.state = state; - this.key = state.key; - var currentRender = render.currentRender(); + this.state = state + this.key = state.key + var currentRender = render.currentRender() if (typeof vdom === 'function') { this.render = function () { if (currentRender && state.on) { - currentRender.transformFunctionAttribute = function(key, value) { + currentRender.transformFunctionAttribute = function (key, value) { return state.on(key.replace(/^on/, ''), value) } } - return vdom.apply(this.state, arguments); - }; - this.canRefresh = true; + return vdom.apply(this.state, arguments) + } + this.canRefresh = true } else { - vdom = vdom || new VText(''); + vdom = vdom || new VText('') this.render = function () { - return vdom; + return vdom } } - this.cacheKey = state.cacheKey; - this.component = domComponent.create(); + this.cacheKey = state.cacheKey + this.component = domComponent.create() - var renderFinished = currentRender && currentRender.finished; + var renderFinished = currentRender && currentRender.finished if (renderFinished) { this.afterRender = function (fn) { - renderFinished.then(fn); - }; + renderFinished.then(fn) + } } else { - this.afterRender = function () {}; + this.afterRender = function () {} } } -ComponentWidget.prototype.type = 'Widget'; +ComponentWidget.prototype.type = 'Widget' ComponentWidget.prototype.init = function () { - var self = this; + var self = this if (self.state.onbeforeadd) { - self.state.onbeforeadd(); + self.state.onbeforeadd() } - var vdom = this.render(this); + var vdom = this.render(this) if (vdom instanceof Array) { - throw new Error('vdom returned from component cannot be an array'); + throw new Error('vdom returned from component cannot be an array') } - var element = this.component.create(vdom); + var element = this.component.create(vdom) if (self.state.onadd) { this.afterRender(function () { - self.state.onadd(element); - }); + self.state.onadd(element) + }) } if (self.state.detached) { - return document.createTextNode(''); + return document.createTextNode('') } else { - return element; + return element } -}; +} ComponentWidget.prototype.update = function (previous) { - var self = this; + var self = this - var refresh = !this.cacheKey || this.cacheKey !== previous.cacheKey; + var refresh = !this.cacheKey || this.cacheKey !== previous.cacheKey if (refresh) { if (self.state.onupdate) { this.afterRender(function () { - self.state.onupdate(self.component.element); - }); + self.state.onupdate(self.component.element) + }) } } - this.component = previous.component; + this.component = previous.component if (previous.state && this.state) { - var keys = Object.keys(this.state); - for(var n = 0; n < keys.length; n++) { - var key = keys[n]; - previous.state[key] = self.state[key]; + var keys = Object.keys(this.state) + for (var n = 0; n < keys.length; n++) { + var key = keys[n] + previous.state[key] = self.state[key] } - this.state = previous.state; + this.state = previous.state } if (refresh) { - var element = this.component.update(this.render(this)); + var element = this.component.update(this.render(this)) if (self.state.detached) { - return document.createTextNode(''); + return document.createTextNode('') } else { - return element; + return element } } -}; +} ComponentWidget.prototype.refresh = function () { - this.component.update(this.render(this)); + this.component.update(this.render(this)) if (this.state.onupdate) { - this.state.onupdate(this.component.element); + this.state.onupdate(this.component.element) } -}; +} -ComponentWidget.prototype.refresh = ComponentWidget.prototype.refresh; +ComponentWidget.prototype.refresh = ComponentWidget.prototype.refresh ComponentWidget.prototype.destroy = function (element) { - var self = this; + var self = this if (self.state.onremove) { this.afterRender(function () { - self.state.onremove(element); - }); + self.state.onremove(element) + }) } - this.component.destroy(); -}; + this.component.destroy() +} module.exports = function (state, vdom) { - deprecations.component('hyperdom.html.component is deprecated, please use hyperdom.component'); + deprecations.component('hyperdom.html.component is deprecated, please use hyperdom.component') if (typeof state === 'function') { - return new ComponentWidget({}, state); + return new ComponentWidget({}, state) } else if (state.constructor === Object) { - return new ComponentWidget(state, vdom); + return new ComponentWidget(state, vdom) } else { - return new ComponentWidget({}, state); + return new ComponentWidget({}, state) } -}; +} -module.exports.ComponentWidget = ComponentWidget; +module.exports.ComponentWidget = ComponentWidget diff --git a/deprecations.js b/deprecations.js index 82ffd9f..2aa2dcc 100644 --- a/deprecations.js +++ b/deprecations.js @@ -1,12 +1,12 @@ -function deprecationWarning() { - var warningIssued = false; +function deprecationWarning () { + var warningIssued = false return function (arg) { if (!warningIssued) { - console.warn(arg); - warningIssued = true; + console.warn(arg) + warningIssued = true } - }; + } } module.exports = { @@ -17,4 +17,4 @@ module.exports = { refreshAfter: deprecationWarning(), norefresh: deprecationWarning(), mapBinding: deprecationWarning() -}; +} diff --git a/domComponent.js b/domComponent.js index 55f10f9..8d0f57a 100644 --- a/domComponent.js +++ b/domComponent.js @@ -1,57 +1,57 @@ -var createElement = require('virtual-dom/create-element'); -var diff = require('virtual-dom/diff'); -var patch = require('virtual-dom/patch'); -var toVdom = require('./toVdom'); -var isVdom = require('./isVdom'); - -function DomComponent(options) { - this.document = options && options.document; +var createElement = require('virtual-dom/create-element') +var diff = require('virtual-dom/diff') +var patch = require('virtual-dom/patch') +var toVdom = require('./toVdom') +var isVdom = require('./isVdom') + +function DomComponent (options) { + this.document = options && options.document } -function prepareVdom(object) { - var vdom = toVdom(object); +function prepareVdom (object) { + var vdom = toVdom(object) if (!isVdom(vdom)) { - throw new Error('expected render to return vdom'); + throw new Error('expected render to return vdom') } else { - return vdom; + return vdom } } DomComponent.prototype.create = function (vdom) { - this.vdom = prepareVdom(vdom); - return this.element = createElement(this.vdom, {document: this.document}); -}; + this.vdom = prepareVdom(vdom) + return this.element = createElement(this.vdom, {document: this.document}) +} DomComponent.prototype.merge = function (vdom, element) { - this.vdom = prepareVdom(vdom); - return this.element = element; -}; + this.vdom = prepareVdom(vdom) + return this.element = element +} DomComponent.prototype.update = function (vdom) { - var oldVdom = this.vdom; - this.vdom = prepareVdom(vdom); - var patches = diff(oldVdom, this.vdom); - return this.element = patch(this.element, patches); -}; + var oldVdom = this.vdom + this.vdom = prepareVdom(vdom) + var patches = diff(oldVdom, this.vdom) + return this.element = patch(this.element, patches) +} DomComponent.prototype.destroy = function (options) { - function destroyWidgets(vdom) { + function destroyWidgets (vdom) { if (vdom.type === 'Widget') { - vdom.destroy(); + vdom.destroy() } else if (vdom.children) { - vdom.children.forEach(destroyWidgets); + vdom.children.forEach(destroyWidgets) } } - destroyWidgets(this.vdom); + destroyWidgets(this.vdom) if (options && options.removeElement && this.element.parentNode) { - this.element.parentNode.removeChild(this.element); + this.element.parentNode.removeChild(this.element) } -}; +} -function domComponent(options) { - return new DomComponent(options); +function domComponent (options) { + return new DomComponent(options) } -exports.create = domComponent; +exports.create = domComponent diff --git a/hyperx.js b/hyperx.js index 69e3743..e6f57cf 100644 --- a/hyperx.js +++ b/hyperx.js @@ -1,6 +1,6 @@ try { var hyperx = require('hyperx') -} catch(e) { +} catch (e) { if (e.code == 'MODULE_NOT_FOUND') { throw new Error('to use hyperx with hyperdom you need to install the hyperx package') } diff --git a/index.js b/index.js index 67e81aa..6dda0bf 100644 --- a/index.js +++ b/index.js @@ -1,23 +1,23 @@ var rendering = require('./rendering') var binding = require('./binding') -var meta = require('./meta'); +var meta = require('./meta') var render = require('./render') var refreshEventResult = require('./refreshEventResult') var Component = require('./component') -exports.html = rendering.html; +exports.html = rendering.html exports.html.refreshify = render.refreshify exports.rawHtml = rendering.rawHtml -exports.jsx = rendering.jsx; -exports.attach = rendering.attach; -exports.replace = rendering.replace; -exports.append = rendering.append; -exports.appendVDom = rendering.appendVDom; -exports.binding = binding; -exports.meta = meta; -exports.refreshify = render.refreshify; -exports.norefresh = refreshEventResult.norefresh; -exports.component = function(model) { +exports.jsx = rendering.jsx +exports.attach = rendering.attach +exports.replace = rendering.replace +exports.append = rendering.append +exports.appendVDom = rendering.appendVDom +exports.binding = binding +exports.meta = meta +exports.refreshify = render.refreshify +exports.norefresh = refreshEventResult.norefresh +exports.component = function (model) { return new Component(model, {component: true}) } diff --git a/isVdom.js b/isVdom.js index acea6e9..239a8f7 100644 --- a/isVdom.js +++ b/isVdom.js @@ -1,10 +1,10 @@ -var virtualDomVersion = require("virtual-dom/vnode/version") +var virtualDomVersion = require('virtual-dom/vnode/version') -module.exports = function(x) { - var type = x.type; +module.exports = function (x) { + var type = x.type if (type == 'VirtualNode' || type == 'VirtualText') { - return x.version == virtualDomVersion; + return x.version == virtualDomVersion } else { - return type == 'Widget' || type == 'Thunk'; + return type == 'Widget' || type == 'Thunk' } -}; +} diff --git a/karma.conf.js b/karma.conf.js index b43dce7..acccf95 100644 --- a/karma.conf.js +++ b/karma.conf.js @@ -1,31 +1,27 @@ // Karma configuration // Generated on Sat Dec 27 2014 08:06:04 GMT+0100 (CET) -module.exports = function(config) { +module.exports = function (config) { config.set({ // base path that will be used to resolve all patterns (eg. files, exclude) basePath: '', - // frameworks to use // available frameworks: https://npmjs.org/browse/keyword/karma-adapter frameworks: ['browserify', 'mocha'], - // list of files / patterns to load in the browser files: [ 'test/browser/promisePolyfill.js', 'test/browser/**/*Spec.js' ], - // list of files to exclude exclude: [ '**/.*.sw?' ], - // preprocess matching files before serving them to the browser // available preprocessors: https://npmjs.org/browse/keyword/karma-preprocessor preprocessors: { @@ -39,7 +35,7 @@ module.exports = function(config) { // test results reporter to use // possible values: 'dots', 'progress' // available reporters: https://npmjs.org/browse/keyword/karma-reporter - reporters: process.env.BROWSERS? ['dots']: ['mocha'], + reporters: process.env.BROWSERS ? ['dots'] : ['mocha'], electronOpts: { show: false @@ -58,24 +54,20 @@ module.exports = function(config) { // web server port port: 9876, - // enable / disable colors in the output (reporters and logs) colors: true, - // level of logging // possible values: config.LOG_DISABLE || config.LOG_ERROR || config.LOG_WARN || config.LOG_INFO || config.LOG_DEBUG logLevel: config.LOG_WARN, - concurrency: process.env.BROWSERS == 'all'? 2: Infinity, - + concurrency: process.env.BROWSERS == 'all' ? 2 : Infinity, // enable / disable watching file and executing tests whenever any file changes autoWatch: true, - // start these browsers // available browser launchers: https://npmjs.org/browse/keyword/karma-launcher - browsers: process.env.BROWSERS == 'all'? Object.keys(browsers): ['Chrome'], + browsers: process.env.BROWSERS == 'all' ? Object.keys(browsers) : ['Chrome'], browserStack: { username: process.env.BROWSERSTACK_USER, @@ -89,70 +81,70 @@ module.exports = function(config) { customLaunchers: browsers, browserNoActivityTimeout: 60000 - }); -}; + }) +} var browsers = { 'browserstack-ie9': { base: 'BrowserStack', - browser : 'IE', - browser_version : '9.0', - os : 'Windows', - os_version : '7', - resolution : '1024x768' + browser: 'IE', + browser_version: '9.0', + os: 'Windows', + os_version: '7', + resolution: '1024x768' }, 'browserstack-ie10': { base: 'BrowserStack', - browser : 'IE', - browser_version : '10.0', - os : 'Windows', - os_version : '8', - resolution : '1024x768' + browser: 'IE', + browser_version: '10.0', + os: 'Windows', + os_version: '8', + resolution: '1024x768' }, 'browserstack-ie11': { base: 'BrowserStack', - browser : 'IE', - browser_version : '11.0', - os : 'Windows', - os_version : '10', - resolution : '1024x768' + browser: 'IE', + browser_version: '11.0', + os: 'Windows', + os_version: '10', + resolution: '1024x768' }, 'browserstack-edge': { base: 'BrowserStack', - browser : 'Edge', - browser_version : '13.0', - os : 'Windows', - os_version : '10', - resolution : '1024x768' + browser: 'Edge', + browser_version: '13.0', + os: 'Windows', + os_version: '10', + resolution: '1024x768' }, 'browserstack-firefox': { base: 'BrowserStack', - browser : 'Firefox', - browser_version : '47.0', - os : 'Windows', - os_version : '10', - resolution : '1024x768' + browser: 'Firefox', + browser_version: '47.0', + os: 'Windows', + os_version: '10', + resolution: '1024x768' }, 'browserstack-safari': { base: 'BrowserStack', - browser : 'Safari', - browser_version : '9.1', - os : 'OS X', - os_version : 'El Capitan', - resolution : '1024x768' + browser: 'Safari', + browser_version: '9.1', + os: 'OS X', + os_version: 'El Capitan', + resolution: '1024x768' }, 'browserstack-safari-ios': { base: 'BrowserStack', - device : 'iPhone 6S', - os : 'ios', - os_version : '9.1', + device: 'iPhone 6S', + os: 'ios', + os_version: '9.1' }, 'browserstack-chrome': { base: 'BrowserStack', - browser : 'Chrome', - browser_version : '52.0', - os : 'Windows', - os_version : '10', - resolution : '1024x768' + browser: 'Chrome', + browser_version: '52.0', + os: 'Windows', + os_version: '10', + resolution: '1024x768' } -}; +} diff --git a/listener.js b/listener.js index 732378f..01f5a79 100644 --- a/listener.js +++ b/listener.js @@ -1,17 +1,17 @@ -var refreshify = require('./render').refreshify; +var refreshify = require('./render').refreshify -function ListenerHook(listener) { - this.listener = refreshify(listener); +function ListenerHook (listener) { + this.listener = refreshify(listener) } ListenerHook.prototype.hook = function (element, propertyName) { - element.addEventListener(propertyName.substring(2), this.listener, false); -}; + element.addEventListener(propertyName.substring(2), this.listener, false) +} ListenerHook.prototype.unhook = function (element, propertyName) { - element.removeEventListener(propertyName.substring(2), this.listener); -}; + element.removeEventListener(propertyName.substring(2), this.listener) +} module.exports = function (listener) { - return new ListenerHook(listener); -}; + return new ListenerHook(listener) +} diff --git a/mapBinding.js b/mapBinding.js index f641eff..075adaf 100644 --- a/mapBinding.js +++ b/mapBinding.js @@ -1,111 +1,111 @@ var bindingMeta = require('./meta') -function makeConverter(converter) { - if (typeof converter == 'function') { +function makeConverter (converter) { + if (typeof converter === 'function') { return { view: function (model) { - return model; + return model }, model: function (view) { - return converter(view); + return converter(view) } - }; + } } else { - return converter; + return converter } } -function chainConverters(startIndex, converters) { - function makeConverters() { +function chainConverters (startIndex, converters) { + function makeConverters () { if (!_converters) { - _converters = new Array(converters.length - startIndex); + _converters = new Array(converters.length - startIndex) - for(var n = startIndex; n < converters.length; n++) { - _converters[n - startIndex] = makeConverter(converters[n]); + for (var n = startIndex; n < converters.length; n++) { + _converters[n - startIndex] = makeConverter(converters[n]) } } } if ((converters.length - startIndex) == 1) { - return makeConverter(converters[startIndex]); + return makeConverter(converters[startIndex]) } else { - var _converters; + var _converters return { view: function (model) { - makeConverters(); - var intermediateValue = model; - for(var n = 0; n < _converters.length; n++) { - intermediateValue = _converters[n].view(intermediateValue); + makeConverters() + var intermediateValue = model + for (var n = 0; n < _converters.length; n++) { + intermediateValue = _converters[n].view(intermediateValue) } - return intermediateValue; + return intermediateValue }, model: function (view) { - makeConverters(); - var intermediateValue = view; - for(var n = _converters.length - 1; n >= 0; n--) { - intermediateValue = _converters[n].model(intermediateValue); + makeConverters() + var intermediateValue = view + for (var n = _converters.length - 1; n >= 0; n--) { + intermediateValue = _converters[n].model(intermediateValue) } - return intermediateValue; + return intermediateValue } - }; + } } } -module.exports = function(model, property) { - var _meta; - function hyperdomMeta() { - return _meta || (_meta = bindingMeta(model, property)); +module.exports = function (model, property) { + var _meta + function hyperdomMeta () { + return _meta || (_meta = bindingMeta(model, property)) } - var converter = chainConverters(2, arguments); + var converter = chainConverters(2, arguments) return { - get: function() { - var meta = hyperdomMeta(); - var modelValue = model[property]; - var modelText; + get: function () { + var meta = hyperdomMeta() + var modelValue = model[property] + var modelText if (meta.error) { - return meta.view; + return meta.view } else if (meta.view === undefined) { - modelText = converter.view(modelValue); - meta.view = modelText; - return modelText; + modelText = converter.view(modelValue) + meta.view = modelText + return modelText } else { - var previousValue; + var previousValue try { - previousValue = converter.model(meta.view); + previousValue = converter.model(meta.view) } catch (e) { - meta.error = e; - return meta.view; + meta.error = e + return meta.view } - modelText = converter.view(modelValue); - var normalisedPreviousText = converter.view(previousValue); + modelText = converter.view(modelValue) + var normalisedPreviousText = converter.view(previousValue) if (modelText === normalisedPreviousText) { - return meta.view; + return meta.view } else { - meta.view = modelText; - return modelText; + meta.view = modelText + return modelText } } }, - set: function(view) { - var meta = hyperdomMeta(); - meta.view = view; + set: function (view) { + var meta = hyperdomMeta() + meta.view = view try { - model[property] = converter.model(view, model[property]); - delete meta.error; + model[property] = converter.model(view, model[property]) + delete meta.error } catch (e) { - meta.error = e; + meta.error = e } }, - meta: function() { - return hyperdomMeta(); + meta: function () { + return hyperdomMeta() } - }; + } } diff --git a/merge.js b/merge.js index f12b2c0..d35ef8f 100644 --- a/merge.js +++ b/merge.js @@ -1,24 +1,24 @@ -var domComponent = require('./domComponent'); +var domComponent = require('./domComponent') var Mount = require('./mount') var vdomParser = require('vdom-parser') -var render = require('./render'); +var render = require('./render') -module.exports = function(element, app, options) { +module.exports = function (element, app, options) { if (!element) { throw new Error('merge: element must not be null') } - var mount = new Mount(app, options); + var mount = new Mount(app, options) - mount.component = domComponent.create(options); + mount.component = domComponent.create(options) var serverVdom = vdomParser(element) - mount.component.merge(serverVdom, element); + mount.component.merge(serverVdom, element) mount.serverRenderCache = new LoadCache(options && options.loadCache) render(mount, function () { - var vdom = mount.render(); - mount.component.update(vdom); + var vdom = mount.render() + mount.component.update(vdom) }) delete mount.serverRenderCache @@ -26,11 +26,11 @@ module.exports = function(element, app, options) { return mount } -function LoadCache(data) { +function LoadCache (data) { this.data = data } -LoadCache.prototype.cache = function(key) { +LoadCache.prototype.cache = function (key) { var data = this.data[key] return Promise.resolve(data) diff --git a/meta.js b/meta.js index 3bfde00..b1a71dc 100644 --- a/meta.js +++ b/meta.js @@ -1,20 +1,20 @@ module.exports = function (model, property) { - var hyperdomMeta = model._hyperdomMeta; + var hyperdomMeta = model._hyperdomMeta if (!hyperdomMeta) { - hyperdomMeta = {}; - Object.defineProperty(model, '_hyperdomMeta', {value: hyperdomMeta}); + hyperdomMeta = {} + Object.defineProperty(model, '_hyperdomMeta', {value: hyperdomMeta}) } if (property) { - var meta = hyperdomMeta[property]; + var meta = hyperdomMeta[property] if (!meta) { - meta = hyperdomMeta[property] = {}; + meta = hyperdomMeta[property] = {} } - return meta; + return meta } else { - return hyperdomMeta; + return hyperdomMeta } -}; +} diff --git a/mount.js b/mount.js index 5a62053..ef56136 100644 --- a/mount.js +++ b/mount.js @@ -1,59 +1,59 @@ -var hyperdomMeta = require('./meta'); -var runRender = require('./render'); -var domComponent = require('./domComponent'); -var Set = require('./set'); +var hyperdomMeta = require('./meta') +var runRender = require('./render') +var domComponent = require('./domComponent') +var Set = require('./set') var refreshEventResult = require('./refreshEventResult') -var vtext = require("virtual-dom/vnode/vtext.js") -var PropertyHook = require('./propertyHook'); +var vtext = require('virtual-dom/vnode/vtext.js') +var PropertyHook = require('./propertyHook') -var lastId = 0; +var lastId = 0 -function Mount(model, options) { - var win = (options && options.window) || window; - var router = typeof options == 'object' && options.hasOwnProperty('router')? options.router: undefined; - this.requestRender = (options && options.requestRender) || win.requestAnimationFrame || win.setTimeout; +function Mount (model, options) { + var win = (options && options.window) || window + var router = typeof options === 'object' && options.hasOwnProperty('router') ? options.router : undefined + this.requestRender = (options && options.requestRender) || win.requestAnimationFrame || win.setTimeout this.document = (options && options.document) || document - this.model = model; + this.model = model - this.renderQueued = false; - this.mountRenderRequested = false; - this.componentRendersRequested = undefined; - this.id = ++lastId; - this.mounted = true; + this.renderQueued = false + this.mountRenderRequested = false + this.componentRendersRequested = undefined + this.id = ++lastId + this.mounted = true this.router = router } -Mount.prototype.refreshify = function(fn, options) { +Mount.prototype.refreshify = function (fn, options) { if (!fn) { - return fn; + return fn } if (options && (options.norefresh == true || options.refresh == false)) { - return fn; + return fn } var self = this return function () { - var result = fn.apply(this, arguments); - return refreshEventResult(result, self, options); - }; + var result = fn.apply(this, arguments) + return refreshEventResult(result, self, options) + } } -Mount.prototype.transformFunctionAttribute = function(key, value) { +Mount.prototype.transformFunctionAttribute = function (key, value) { return this.refreshify(value) -}; +} Mount.prototype.queueRender = function () { if (!this.renderQueued) { - var self = this; + var self = this - var requestRender = this.requestRender; - this.renderQueued = true; + var requestRender = this.requestRender + this.renderQueued = true requestRender(function () { - self.renderQueued = false; + self.renderQueued = false if (self.mounted) { if (self.mountRenderRequested) { @@ -62,132 +62,132 @@ Mount.prototype.queueRender = function () { self.refreshComponentsImmediately() } } - }); + }) } -}; +} -Mount.prototype.createDomComponent = function() { +Mount.prototype.createDomComponent = function () { return domComponent.create({ document: this.document }) -}; +} -Mount.prototype.render = function() { +Mount.prototype.render = function () { return (this.router && this.router.render(this.model)) || this.model -}; +} Mount.prototype.refresh = function () { - this.mountRenderRequested = true; - this.queueRender(); -}; + this.mountRenderRequested = true + this.queueRender() +} -Mount.prototype.refreshImmediately = function() { +Mount.prototype.refreshImmediately = function () { var self = this runRender(self, function () { - var vdom = self.render(); - self.component.update(vdom); - self.mountRenderRequested = false; + var vdom = self.render() + self.component.update(vdom) + self.mountRenderRequested = false }) } -Mount.prototype.refreshComponentsImmediately = function() { +Mount.prototype.refreshComponentsImmediately = function () { var self = this runRender(self, function () { for (var i = 0, l = self.componentRendersRequested.length; i < l; i++) { - var w = self.componentRendersRequested[i]; - w.refresh(); + var w = self.componentRendersRequested[i] + w.refresh() } - self.componentRendersRequested = undefined; + self.componentRendersRequested = undefined }) } Mount.prototype.refreshComponent = function (component) { if (!this.componentRendersRequested) { - this.componentRendersRequested = []; + this.componentRendersRequested = [] } - this.componentRendersRequested.push(component); - this.queueRender(); -}; + this.componentRendersRequested.push(component) + this.queueRender() +} -Mount.prototype.setupModelComponent = function(model) { - var self = this; +Mount.prototype.setupModelComponent = function (model) { + var self = this - var meta = hyperdomMeta(model); + var meta = hyperdomMeta(model) if (!meta.mount) { - meta.mount = this; - meta.components = new Set(); + meta.mount = this + meta.components = new Set() model.refresh = function () { - self.refresh(); - }; + self.refresh() + } model.refreshImmediately = function () { - self.refreshImmediately(); - }; + self.refreshImmediately() + } - model.refreshComponent = function() { - var meta = hyperdomMeta(this); + model.refreshComponent = function () { + var meta = hyperdomMeta(this) meta.components.forEach(function (w) { - self.refreshComponent(w); - }); - }; + self.refreshComponent(w) + }) + } - if (typeof model.onload == 'function') { - this.refreshify(function () { return model.onload(); }, {refresh: 'promise'})(); + if (typeof model.onload === 'function') { + this.refreshify(function () { return model.onload() }, {refresh: 'promise'})() } } } -Mount.prototype._renderComponent = function(model) { +Mount.prototype._renderComponent = function (model) { this.setupModelComponent(model) - var vdom = typeof model.render == 'function'? model.render(): new vtext(JSON.stringify(model)) + var vdom = typeof model.render === 'function' ? model.render() : new vtext(JSON.stringify(model)) if (vdom instanceof Array) { console.error('vdom returned from component cannot be an array, component: ', model) - throw new Error('vdom returned from component cannot be an array'); + throw new Error('vdom returned from component cannot be an array') } if (vdom) { if (!vdom.properties) { - vdom.properties = {}; + vdom.properties = {} } vdom.properties._hyperdomMeta = new PropertyHook({ component: model, render: runRender.currentRender() - }); + }) } - return vdom; + return vdom } -Mount.prototype.renderComponent = function(model) { +Mount.prototype.renderComponent = function (model) { if (typeof model.renderCacheKey === 'function') { - var meta = hyperdomMeta(model); - var key = model.renderCacheKey(); + var meta = hyperdomMeta(model) + var key = model.renderCacheKey() if (key !== undefined && meta.cacheKey === key && meta.cachedVdom) { - return meta.cachedVdom; + return meta.cachedVdom } else { - meta.cacheKey = key; - return meta.cachedVdom = this._renderComponent(model); + meta.cacheKey = key + return meta.cachedVdom = this._renderComponent(model) } } else { - return this._renderComponent(model); + return this._renderComponent(model) } -}; +} Mount.prototype.detach = function () { - this.mounted = false; -}; + this.mounted = false +} Mount.prototype.remove = function () { if (this.router) { this.router.reset() } - this.component.destroy({removeElement: true}); - this.mounted = false; -}; + this.component.destroy({removeElement: true}) + this.mounted = false +} -module.exports = Mount; +module.exports = Mount diff --git a/prepareAttributes.js b/prepareAttributes.js index 5db0fd9..84970b5 100644 --- a/prepareAttributes.js +++ b/prepareAttributes.js @@ -1,65 +1,65 @@ -var render = require('./render'); +var render = require('./render') var bindModel = require('./bindModel') -module.exports = function(tag, attributes, childElements) { - var keys = Object.keys(attributes); - var dataset; - var currentRender = render.currentRender(); +module.exports = function (tag, attributes, childElements) { + var keys = Object.keys(attributes) + var dataset + var currentRender = render.currentRender() for (var k = 0; k < keys.length; k++) { - var key = keys[k]; - var attribute = attributes[key]; + var key = keys[k] + var attribute = attributes[key] - if (typeof(attribute) == 'function' && currentRender) { + if (typeof (attribute) === 'function' && currentRender) { attributes[key] = currentRender.transformFunctionAttribute(key, attribute) } - var rename = renames[key]; + var rename = renames[key] if (rename) { - attributes[rename] = attribute; - delete attributes[key]; - continue; + attributes[rename] = attribute + delete attributes[key] + continue } if (dataAttributeRegex.test(key)) { if (!dataset) { - dataset = attributes.dataset; + dataset = attributes.dataset if (!dataset) { - dataset = attributes.dataset = {}; + dataset = attributes.dataset = {} } } var datakey = key .replace(dataAttributeRegex, '') - .replace(/-([a-z])/ig, function(_, x) { return x.toUpperCase(); }); + .replace(/-([a-z])/ig, function (_, x) { return x.toUpperCase() }) - dataset[datakey] = attribute; - delete attributes[key]; - continue; + dataset[datakey] = attribute + delete attributes[key] + continue } } if (attributes.__source) { if (!dataset) { - dataset = attributes.dataset; + dataset = attributes.dataset if (!dataset) { - dataset = attributes.dataset = {}; + dataset = attributes.dataset = {} } } - dataset.fileName = attributes.__source.fileName; - dataset.lineNumber = attributes.__source.lineNumber; + dataset.fileName = attributes.__source.fileName + dataset.lineNumber = attributes.__source.lineNumber } if (attributes.className) { - attributes.className = generateClassName(attributes.className); + attributes.className = generateClassName(attributes.className) } if (attributes.binding) { - bindModel(tag, attributes, childElements); - delete attributes.binding; + bindModel(tag, attributes, childElements) + delete attributes.binding } return attributes @@ -71,27 +71,27 @@ var renames = { contenteditable: 'contentEditable', tabindex: 'tabIndex', colspan: 'colSpan' -}; +} -var dataAttributeRegex = /^data-/; +var dataAttributeRegex = /^data-/ -function generateClassName(obj) { - if (typeof(obj) == 'object') { +function generateClassName (obj) { + if (typeof (obj) === 'object') { if (obj instanceof Array) { - var names = obj.map(function(item) { - return generateClassName(item); - }); - return names.join(' ') || undefined; + var names = obj.map(function (item) { + return generateClassName(item) + }) + return names.join(' ') || undefined } else { - return generateConditionalClassNames(obj); + return generateConditionalClassNames(obj) } } else { - return obj; + return obj } } -function generateConditionalClassNames(obj) { +function generateConditionalClassNames (obj) { return Object.keys(obj).filter(function (key) { - return obj[key]; - }).join(' ') || undefined; + return obj[key] + }).join(' ') || undefined } diff --git a/propertyHook.js b/propertyHook.js index bb77eb0..759b9f2 100644 --- a/propertyHook.js +++ b/propertyHook.js @@ -1,13 +1,13 @@ -function PropertyHook(value) { - this.value = value; +function PropertyHook (value) { + this.value = value } PropertyHook.prototype.hook = function (element, property) { - element[property] = this.value; -}; + element[property] = this.value +} PropertyHook.prototype.unhook = function (element, property) { - delete element[property]; -}; + delete element[property] +} -module.exports = PropertyHook; +module.exports = PropertyHook diff --git a/refreshAfter.js b/refreshAfter.js index 064bc70..ff489ba 100644 --- a/refreshAfter.js +++ b/refreshAfter.js @@ -1,7 +1,7 @@ -var deprecations = require('./deprecations'); -var refreshify = require('./render').refreshify; +var deprecations = require('./deprecations') +var refreshify = require('./render').refreshify -module.exports = function(promise) { - deprecations.refreshAfter('hyperdom.html.refreshAfter is deprecated'); - refreshify(function() { return promise }, {refresh: 'promise'})() +module.exports = function (promise) { + deprecations.refreshAfter('hyperdom.html.refreshAfter is deprecated') + refreshify(function () { return promise }, {refresh: 'promise'})() } diff --git a/refreshEventResult.js b/refreshEventResult.js index 0818dad..d9052d5 100644 --- a/refreshEventResult.js +++ b/refreshEventResult.js @@ -1,67 +1,67 @@ -var deprecations = require('./deprecations'); +var deprecations = require('./deprecations') module.exports = refreshAfterEvent -var norefresh = {}; +var norefresh = {} -function norefreshFunction() { - return norefresh; +function norefreshFunction () { + return norefresh } module.exports.norefresh = norefreshFunction -function refreshAfterEvent(result, mount, options) { - var onlyRefreshAfterPromise = options && options.refresh == 'promise'; - var componentToRefresh = options && options.component; +function refreshAfterEvent (result, mount, options) { + var onlyRefreshAfterPromise = options && options.refresh == 'promise' + var componentToRefresh = options && options.component - if (result && typeof(result.then) == 'function') { + if (result && typeof (result.then) === 'function') { result.then(function (result) { var opts = cloneOptions(options) opts.refresh = undefined - refreshAfterEvent(result, mount, opts); - }); + refreshAfterEvent(result, mount, opts) + }) } if (onlyRefreshAfterPromise) { - return; + return } if (isComponent(result)) { - mount.refreshComponent(result); + mount.refreshComponent(result) } else if (result instanceof Array) { for (var i = 0; i < result.length; i++) { - refreshAfterEvent(result[i], mount, options); + refreshAfterEvent(result[i], mount, options) } } else if (componentToRefresh) { if (componentToRefresh.refreshComponent) { componentToRefresh.refreshComponent() } else { - componentToRefresh.refresh(); + componentToRefresh.refresh() } } else if (result === norefresh) { // don't refresh; } else if (result === norefreshFunction) { - deprecations.norefresh('hyperdom.norefresh is deprecated, please use hyperdom.norefresh()'); + deprecations.norefresh('hyperdom.norefresh is deprecated, please use hyperdom.norefresh()') // don't refresh; } else { - mount.refresh(); - return result; + mount.refresh() + return result } } -function isComponent(component) { - return component - && ((typeof component.init === 'function' - && typeof component.update === 'function' - && typeof component.destroy === 'function') || (typeof component.refreshComponent === 'function')); +function isComponent (component) { + return component && + ((typeof component.init === 'function' && + typeof component.update === 'function' && + typeof component.destroy === 'function') || (typeof component.refreshComponent === 'function')) } -function cloneOptions(options) { +function cloneOptions (options) { if (options) { return { norefresh: options.norefresh, refresh: options.refresh, - component: options.component, + component: options.component } } else { return {} diff --git a/render.js b/render.js index 51e40a6..b8f06d2 100644 --- a/render.js +++ b/render.js @@ -1,25 +1,25 @@ -var simplePromise = require('./simplePromise'); +var simplePromise = require('./simplePromise') -function runRender(mount, fn) { - var render = new Render(mount); +function runRender (mount, fn) { + var render = new Render(mount) try { - runRender._currentRender = render; + runRender._currentRender = render - return fn(); + return fn() } finally { - render.finished.fulfill(); - runRender._currentRender = undefined; + render.finished.fulfill() + runRender._currentRender = undefined } } -function Render(mount) { - this.finished = simplePromise(); - this.mount = mount; - this.attachment = mount; +function Render (mount) { + this.finished = simplePromise() + this.mount = mount + this.attachment = mount } -Render.prototype.transformFunctionAttribute = function() { +Render.prototype.transformFunctionAttribute = function () { return this.mount.transformFunctionAttribute.apply(this.mount, arguments) } @@ -29,13 +29,13 @@ module.exports.refreshify = refreshify module.exports.RefreshHook = RefreshHook function currentRender () { - return runRender._currentRender || defaultRender; + return runRender._currentRender || defaultRender } var defaultRender = { mount: { - renderComponent: function(model) { return model.render() }, - refreshify: function(fn) { return fn } + renderComponent: function (model) { return model.render() }, + refreshify: function (fn) { return fn } }, transformFunctionAttribute: function (key, value) { @@ -43,11 +43,11 @@ var defaultRender = { } } -function refreshify(fn, options) { +function refreshify (fn, options) { return runRender.currentRender().mount.refreshify(fn, options) } -function RefreshHook(handler) { +function RefreshHook (handler) { this.handler = handler } diff --git a/rendering.js b/rendering.js index f765c29..b12a585 100644 --- a/rendering.js +++ b/rendering.js @@ -1,73 +1,73 @@ -var vhtml = require('./vhtml'); -var domComponent = require('./domComponent'); -var bindingMeta = require('./meta'); -var toVdom = require('./toVdom'); -var parseTag = require('virtual-dom/virtual-hyperscript/parse-tag'); -var Mount = require('./mount'); -var render = require('./render'); -var deprecations = require('./deprecations'); +var vhtml = require('./vhtml') +var domComponent = require('./domComponent') +var bindingMeta = require('./meta') +var toVdom = require('./toVdom') +var parseTag = require('virtual-dom/virtual-hyperscript/parse-tag') +var Mount = require('./mount') +var render = require('./render') +var deprecations = require('./deprecations') var prepareAttributes = require('./prepareAttributes') var binding = require('./binding') var refreshAfter = require('./refreshAfter') var refreshEventResult = require('./refreshEventResult') exports.append = function (element, render, model, options) { - return startAttachment(render, model, options, function(mount, domComponentOptions) { - var component = domComponent.create(domComponentOptions); - var vdom = mount.render(); - element.appendChild(component.create(vdom)); - return component; - }); -}; + return startAttachment(render, model, options, function (mount, domComponentOptions) { + var component = domComponent.create(domComponentOptions) + var vdom = mount.render() + element.appendChild(component.create(vdom)) + return component + }) +} exports.replace = function (element, render, model, options) { - return startAttachment(render, model, options, function(mount, domComponentOptions) { - var component = domComponent.create(domComponentOptions); - var vdom = mount.render(); - element.parentNode.replaceChild(component.create(vdom), element); - return component; - }); -}; + return startAttachment(render, model, options, function (mount, domComponentOptions) { + var component = domComponent.create(domComponentOptions) + var vdom = mount.render() + element.parentNode.replaceChild(component.create(vdom), element) + return component + }) +} exports.appendVDom = function (vdom, render, model, options) { - return startAttachment(render, model, options, function(mount) { + return startAttachment(render, model, options, function (mount) { var component = { - create: function(newVDom) { - vdom.children = []; + create: function (newVDom) { + vdom.children = [] if (newVDom) { - vdom.children.push(toVdom(newVDom)); + vdom.children.push(toVdom(newVDom)) } }, - update: function(newVDom) { - vdom.children = []; + update: function (newVDom) { + vdom.children = [] if (newVDom) { - vdom.children.push(toVdom(newVDom)); + vdom.children.push(toVdom(newVDom)) } } - }; - component.create(mount.render()); - return component; - }); -}; - -function startAttachment(render, model, options, attachToDom) { - if (typeof render == 'object') { - return start(render, attachToDom, model); + } + component.create(mount.render()) + return component + }) +} + +function startAttachment (render, model, options, attachToDom) { + if (typeof render === 'object') { + return start(render, attachToDom, model) } else { - deprecations.renderFunction('hyperdom.append and hyperdom.replace with render functions are deprecated, please pass a component'); - return start({render: function () { return render(model); }}, attachToDom, options); + deprecations.renderFunction('hyperdom.append and hyperdom.replace with render functions are deprecated, please pass a component') + return start({render: function () { return render(model) }}, attachToDom, options) } } -function start(model, attachToDom, options) { - var mount = new Mount(model, options); +function start (model, attachToDom, options) { + var mount = new Mount(model, options) render(mount, function () { if (options) { - var domComponentOptions = {document: options.document}; + var domComponentOptions = {document: options.document} } - mount.component = attachToDom(mount, domComponentOptions); - }); - return mount; + mount.component = attachToDom(mount, domComponentOptions) + }) + return mount } /** @@ -77,101 +77,101 @@ function start(model, attachToDom, options) { * so think of that before refactoring! :) */ exports.html = function (hierarchySelector) { - var hasHierarchy = hierarchySelector.indexOf(' ') >= 0; - var selector, selectorElements; + var hasHierarchy = hierarchySelector.indexOf(' ') >= 0 + var selector, selectorElements if (hasHierarchy) { - selectorElements = hierarchySelector.match(/\S+/g); - selector = selectorElements[selectorElements.length - 1]; + selectorElements = hierarchySelector.match(/\S+/g) + selector = selectorElements[selectorElements.length - 1] } else { - selector = hierarchySelector; + selector = hierarchySelector } - var childElements; - var vdom; - var tag; - var attributes = arguments[1]; + var childElements + var vdom + var tag + var attributes = arguments[1] if (attributes && attributes.constructor == Object && typeof attributes.render !== 'function') { - childElements = toVdom.recursive(Array.prototype.slice.call(arguments, 2)); - prepareAttributes(selector, attributes, childElements); - tag = parseTag(selector, attributes); - vdom = vhtml(tag, attributes, childElements); + childElements = toVdom.recursive(Array.prototype.slice.call(arguments, 2)) + prepareAttributes(selector, attributes, childElements) + tag = parseTag(selector, attributes) + vdom = vhtml(tag, attributes, childElements) } else { - attributes = {}; - childElements = toVdom.recursive(Array.prototype.slice.call(arguments, 1)); - tag = parseTag(selector, attributes); - vdom = vhtml(tag, attributes, childElements); + attributes = {} + childElements = toVdom.recursive(Array.prototype.slice.call(arguments, 1)) + tag = parseTag(selector, attributes) + vdom = vhtml(tag, attributes, childElements) } if (hasHierarchy) { - for(var n = selectorElements.length - 2; n >= 0; n--) { - vdom = vhtml(selectorElements[n], {}, [vdom]); + for (var n = selectorElements.length - 2; n >= 0; n--) { + vdom = vhtml(selectorElements[n], {}, [vdom]) } } - return vdom; -}; + return vdom +} exports.jsx = function (tag, attributes) { - var childElements = toVdom.recursive(Array.prototype.slice.call(arguments, 2)); + var childElements = toVdom.recursive(Array.prototype.slice.call(arguments, 2)) if (attributes) { - prepareAttributes(tag, attributes, childElements); + prepareAttributes(tag, attributes, childElements) } - return vhtml(tag, attributes || {}, childElements); -}; + return vhtml(tag, attributes || {}, childElements) +} Object.defineProperty(exports.html, 'currentRender', {get: function () { - deprecations.currentRender('hyperdom.html.currentRender is deprecated, please use hyperdom.currentRender() instead'); - return render._currentRender; -}}); + deprecations.currentRender('hyperdom.html.currentRender is deprecated, please use hyperdom.currentRender() instead') + return render._currentRender +}}) Object.defineProperty(exports.html, 'refresh', {get: function () { - deprecations.refresh('hyperdom.html.refresh is deprecated, please use component.refresh() instead'); + deprecations.refresh('hyperdom.html.refresh is deprecated, please use component.refresh() instead') if (render._currentRender) { var currentRender = render._currentRender - return function(result) { + return function (result) { refreshEventResult(result, currentRender.mount) } } else { - throw new Error('Please assign hyperdom.html.refresh during a render cycle if you want to use it in event handlers. See https://github.com/featurist/hyperdom#refresh-outside-render-cycle'); + throw new Error('Please assign hyperdom.html.refresh during a render cycle if you want to use it in event handlers. See https://github.com/featurist/hyperdom#refresh-outside-render-cycle') } -}}); +}}) Object.defineProperty(exports.html, 'norefresh', {get: function () { - deprecations.refresh('hyperdom.html.norefresh is deprecated, please use hyperdom.norefresh() instead'); + deprecations.refresh('hyperdom.html.norefresh is deprecated, please use hyperdom.norefresh() instead') return refreshEventResult.norefresh -}}); +}}) Object.defineProperty(exports.html, 'binding', {get: function () { - deprecations.refresh('hyperdom.html.binding() is deprecated, please use hyperdom.binding() instead'); + deprecations.refresh('hyperdom.html.binding() is deprecated, please use hyperdom.binding() instead') return binding -}}); +}}) Object.defineProperty(exports.html, 'refreshAfter', {get: function () { - deprecations.refresh("hyperdom.html.refreshAfter() is deprecated, please use require('hyperdom/refreshAfter')() instead"); + deprecations.refresh("hyperdom.html.refreshAfter() is deprecated, please use require('hyperdom/refreshAfter')() instead") return refreshAfter -}}); +}}) -exports.html.meta = bindingMeta; +exports.html.meta = bindingMeta -function rawHtml() { - var selector; - var html; - var options; +function rawHtml () { + var selector + var html + var options if (arguments.length == 2) { - selector = arguments[0]; - html = arguments[1]; - options = {innerHTML: html}; - return exports.html(selector, options); + selector = arguments[0] + html = arguments[1] + options = {innerHTML: html} + return exports.html(selector, options) } else { - selector = arguments[0]; - options = arguments[1]; - html = arguments[2]; - options.innerHTML = html; - return exports.html(selector, options); + selector = arguments[0] + options = arguments[1] + html = arguments[2] + options.innerHTML = html + return exports.html(selector, options) } } -exports.html.rawHtml = rawHtml; +exports.html.rawHtml = rawHtml diff --git a/router.js b/router.js index 09e1dbd..afbbe1a 100644 --- a/router.js +++ b/router.js @@ -1,19 +1,19 @@ var makeBinding = require('./binding') -var refreshify = require('./render').refreshify; +var refreshify = require('./render').refreshify var runRender = require('./render') var h = require('./rendering').html -function Router(options) { - this._querystring = typeof options == 'object' && options.hasOwnProperty('querystring')? options.querystring: new QueryString(); - this.history = typeof options == 'object' && options.hasOwnProperty('history')? options.history: new PushState(); +function Router (options) { + this._querystring = typeof options === 'object' && options.hasOwnProperty('querystring') ? options.querystring : new QueryString() + this.history = typeof options === 'object' && options.hasOwnProperty('history') ? options.history : new PushState() } -Router.prototype.reset = function() { +Router.prototype.reset = function () { this.lastUrl = undefined this.history.stop() } -function modelRoutes(model, isModel) { +function modelRoutes (model, isModel) { if (isModel) { runRender.currentRender().mount.setupModelComponent(model) } @@ -30,15 +30,15 @@ function modelRoutes(model, isModel) { } } -Router.prototype.url = function() { +Router.prototype.url = function () { return this.history.url() } -Router.prototype.render = function(model) { +Router.prototype.render = function (model) { var self = this this.history.start(model) - function renderUrl(redirects) { + function renderUrl (redirects) { var url = self.history.url() var routes = modelRoutes(model, true) @@ -81,60 +81,60 @@ Router.prototype.render = function(model) { return renderUrl([]) } -Router.prototype.push = function(url) { +Router.prototype.push = function (url) { this.history.push(url) -}; +} -Router.prototype.replace = function(url) { +Router.prototype.replace = function (url) { this.history.replace(url) -}; +} -function renderNotFound(url, routes) { - return h('pre', h('code', 'no route for: ' + url + '\n\navailable routes:\n\n' + routes.map(function (r) { return ' ' + r.pattern; }).join('\n'))) +function renderNotFound (url, routes) { + return h('pre', h('code', 'no route for: ' + url + '\n\navailable routes:\n\n' + routes.map(function (r) { return ' ' + r.pattern }).join('\n'))) } var notFoundPatternVariables = preparePattern('*') -Router.prototype.notFound = function(options) { +Router.prototype.notFound = function (options) { options.notFound = true return new Route(notFoundPatternVariables, options, this) } -Router.prototype.route = function(pattern) { +Router.prototype.route = function (pattern) { var self = this var patternVariables = preparePattern(pattern) - function route(options) { + function route (options) { return new Route(patternVariables, options, self) } - route.params = function() { + route.params = function () { return route().urlParams(self.url()) } - route.push = function(params, options) { + route.push = function (params, options) { self.history.push(self.expandUrl(patternVariables.pattern, params)) if (!(options && options.resetScroll == false)) { window.scrollTo(0, 0) } } - route.replace = function(params) { + route.replace = function (params) { self.history.replace(self.expandUrl(patternVariables.pattern, params)) } - route.href = function(params, options) { + route.href = function (params, options) { return new HrefAttribute(route, params, options) } - route.url = function(params) { + route.url = function (params) { return self.expandUrl(patternVariables.pattern, params) } return route } -function Route(patternVariables, options, router) { +function Route (patternVariables, options, router) { this.pattern = patternVariables.pattern this.router = router @@ -142,14 +142,14 @@ function Route(patternVariables, options, router) { this.regex = patternVariables.regex this.mountRegex = patternVariables.mountRegex - this.routes = typeof options == 'object' && options.hasOwnProperty('routes')? options.routes: undefined; - var bindings = typeof options == 'object' && options.hasOwnProperty('bindings')? options.bindings: undefined - this.bindings = bindings? bindParams(bindings): undefined - this.onload = typeof options == 'object' && options.hasOwnProperty('onload')? options.onload: undefined - this.render = typeof options == 'object' && options.hasOwnProperty('render')? options.render: (this.routes? function(inner) { return inner }: function () {}) - this.redirect = typeof options == 'object' && options.hasOwnProperty('redirect')? options.redirect: undefined + this.routes = typeof options === 'object' && options.hasOwnProperty('routes') ? options.routes : undefined + var bindings = typeof options === 'object' && options.hasOwnProperty('bindings') ? options.bindings : undefined + this.bindings = bindings ? bindParams(bindings) : undefined + this.onload = typeof options === 'object' && options.hasOwnProperty('onload') ? options.onload : undefined + this.render = typeof options === 'object' && options.hasOwnProperty('render') ? options.render : (this.routes ? function (inner) { return inner } : function () {}) + this.redirect = typeof options === 'object' && options.hasOwnProperty('redirect') ? options.redirect : undefined - var push = typeof options == 'object' && options.hasOwnProperty('push')? options.push: undefined + var push = typeof options === 'object' && options.hasOwnProperty('push') ? options.push : undefined if (typeof push === 'function') { this.push = push @@ -164,7 +164,7 @@ function Route(patternVariables, options, router) { } } -function bindParams(params) { +function bindParams (params) { var bindings = {} Object.keys(params).forEach(function (key) { @@ -174,13 +174,13 @@ function bindParams(params) { return bindings } -Route.prototype.hasRoute = function(model, url) { +Route.prototype.hasRoute = function (model, url) { var routes = modelRoutes(model, true) var match = findMatch(url, routes) return !!match && !match.route.notFound } -Route.prototype.match = function(url) { +Route.prototype.match = function (url) { if (this.routes) { return this.mountRegex.exec(url.split('?')[0]) } else { @@ -188,7 +188,7 @@ Route.prototype.match = function(url) { } } -Route.prototype.urlParams = function(url, _match) { +Route.prototype.urlParams = function (url, _match) { var query = url.split('?')[1] var match = _match || this.match(url) var params = this.router._querystring.parse(query) @@ -202,7 +202,7 @@ Route.prototype.urlParams = function(url, _match) { return params } -Route.prototype.set = function(url, match) { +Route.prototype.set = function (url, match) { var self = this var params = this.urlParams(url, match) @@ -241,19 +241,19 @@ Route.prototype.set = function(url, match) { } } -Route.prototype.wrapAction = function(action) { +Route.prototype.wrapAction = function (action) { var innerRender = action.render var outerRender = this.render - action.render = function() { + action.render = function () { return outerRender(innerRender()) } return action } -Route.prototype.get = function(url) { +Route.prototype.get = function (url) { var self = this var routes - + if (this.bindings) { var params = {} Object.keys(this.bindings).forEach(function (key) { @@ -282,12 +282,12 @@ Route.prototype.get = function(url) { } } -function extend(a, b) { +function extend (a, b) { if (b) { var keys = Object.keys(b) for (var k = 0, l = keys.length; k < l; k++) { - var key = keys[k]; + var key = keys[k] a[key] = b[key] } @@ -295,11 +295,11 @@ function extend(a, b) { } } -function clone(thing) { +function clone (thing) { return JSON.parse(JSON.stringify(thing)) } -function paramToString(p) { +function paramToString (p) { if (p === undefined || p === null) { return '' } else { @@ -307,7 +307,7 @@ function paramToString(p) { } } -Router.prototype.expandUrl = function(pattern, _params) { +Router.prototype.expandUrl = function (pattern, _params) { var params = _params || {} var onlyQueryParams = clone(params) @@ -332,22 +332,22 @@ Router.prototype.expandUrl = function(pattern, _params) { } } -function escapeRegex(pattern) { +function escapeRegex (pattern) { return pattern.replace(/[-\/\\^$*+?.()|[\]{}]/g, '\\$&') } -function compilePattern(pattern) { +function compilePattern (pattern) { var anyRegex = /\\\*/ig var splatVariableRegex = /:[a-z\-_]+\\\*/ig var variableRegex = /:[-a-z_]+/ig return escapeRegex(pattern) - .replace(splatVariableRegex, "(.+)") - .replace(anyRegex, ".*") - .replace(variableRegex, "([^\/]+)") + .replace(splatVariableRegex, '(.+)') + .replace(anyRegex, '.*') + .replace(variableRegex, '([^\/]+)') } -function preparePattern(pattern) { +function preparePattern (pattern) { var match var variableRegex = new RegExp(':([-a-z_]+)', 'ig') var variables = [] @@ -361,21 +361,21 @@ function preparePattern(pattern) { return { pattern: pattern, regex: new RegExp('^' + compiledPattern + '($)'), - mountRegex: new RegExp('^' + compiledPattern + (pattern[pattern.length - 1] == '/'? '': '(/|$)')), + mountRegex: new RegExp('^' + compiledPattern + (pattern[pattern.length - 1] == '/' ? '' : '(/|$)')), variables: variables } } -function setUrl(url, routes) { +function setUrl (url, routes) { var match = findMatch(url, routes) if (match) { return match.route.set(url, match.match) } } -function findMatch(url, routes) { +function findMatch (url, routes) { for (var r = 0, l = routes.length; r < l; r++) { - var route = routes[r]; + var route = routes[r] var match if (typeof route.match === 'function') { @@ -388,7 +388,7 @@ function findMatch(url, routes) { } else if (typeof route.routes === 'function') { var subRoutes = modelRoutes(route) var subMatch = findMatch(url, subRoutes) - + if (subMatch) { return subMatch } @@ -396,18 +396,18 @@ function findMatch(url, routes) { } } -function getUrl(url, routes) { +function getUrl (url, routes) { var match = findMatch(url, routes) if (match) { return match.route.get(url, match.match) } } -function QueryString() { +function QueryString () { } -QueryString.prototype.parse = function(search) { - var params = {}; +QueryString.prototype.parse = function (search) { + var params = {} if (search) { search.split('&').map(function (param) { @@ -433,7 +433,7 @@ QueryString.prototype.stringify = function (paramsObject) { return query } -var PushState = function() { +var PushState = function () { } PushState.prototype.start = function (model) { @@ -442,7 +442,7 @@ PushState.prototype.start = function (model) { } this.started = true - window.addEventListener('popstate', this.listener = function() { + window.addEventListener('popstate', this.listener = function () { if (model) { model.refreshImmediately() @@ -486,56 +486,56 @@ function Hash () { } Hash.prototype.start = function (model) { - var self = this; + var self = this if (this.started) { return } this.started = true - this.hashchangeListener = function() { + this.hashchangeListener = function () { if (self.started) { if (!self.pushed) { if (model) { model.refreshImmediately() } } else { - self.pushed = false; + self.pushed = false } } } - window.addEventListener('hashchange', this.hashchangeListener); + window.addEventListener('hashchange', this.hashchangeListener) } Hash.prototype.stop = function () { this.started = false - window.removeEventListener('hashchange', this.hashchangeListener); + window.removeEventListener('hashchange', this.hashchangeListener) } -Hash.prototype.url = function() { - var path = window.location.hash || '#'; +Hash.prototype.url = function () { + var path = window.location.hash || '#' - var m = /^#(.*?)(\?.*)?$/.exec(path); + var m = /^#(.*?)(\?.*)?$/.exec(path) var pathname = m[1] var search = m[2] - return '/' + pathname + (search? search: '') -}; + return '/' + pathname + (search || '') +} -Hash.prototype.push = function(url) { - this.pushed = true; - window.location.hash = url.replace(/^\//, ''); -}; +Hash.prototype.push = function (url) { + this.pushed = true + window.location.hash = url.replace(/^\//, '') +} -Hash.prototype.state = function() { -}; +Hash.prototype.state = function () { +} -Hash.prototype.replace = function(url) { - return this.push(url); -}; +Hash.prototype.replace = function (url) { + return this.push(url) +} -function HrefAttribute(route, params, options) { +function HrefAttribute (route, params, options) { this.href = route.url(params) - this.onclick = refreshify(function(event) { + this.onclick = refreshify(function (event) { if (!event.metaKey) { route.push(params, options) event.preventDefault() diff --git a/serverRender.js b/serverRender.js index 28b2373..86d0903 100644 --- a/serverRender.js +++ b/serverRender.js @@ -5,22 +5,24 @@ var router = require('./router') var StoreCache = require('./storeCache') var toVdom = require('./toVdom') -module.exports.hasRoute = function(app, url) { +module.exports.hasRoute = function (app, url) { return router.hasRoute(app, url) } -module.exports.render = function(app, url) { +module.exports.render = function (app, url) { var renderRequested = false var cache = new StoreCache() - var mount = new Mount(app, {window: {}, router: router.create({history: new ServerHistory(url)}), requestRender: () => { - renderRequested = true - }}) + var mount = new Mount(app, {window: {}, + router: router.create({history: new ServerHistory(url)}), + requestRender: () => { + renderRequested = true + }}) mount.serverRenderCache = cache mount.refreshify = cache.refreshify - function renderUntilAllLoaded(mount, cache, {maxRenders, renders = 0} = {}) { + function renderUntilAllLoaded (mount, cache, {maxRenders, renders = 0} = {}) { if (renders >= maxRenders) { throw new Error('page could not load all resources') } @@ -53,12 +55,12 @@ module.exports.render = function(app, url) { return renderUntilAllLoaded(mount, cache, {maxRenders: 10}) } -function ServerHistory(url) { +function ServerHistory (url) { this._url = url } -ServerHistory.prototype.url = function() { +ServerHistory.prototype.url = function () { return this._url } -ServerHistory.prototype.start = function() {} +ServerHistory.prototype.start = function () {} diff --git a/serverRenderCache.js b/serverRenderCache.js index 0ce2645..ec85500 100644 --- a/serverRenderCache.js +++ b/serverRenderCache.js @@ -1,13 +1,13 @@ -var render = require('./render'); +var render = require('./render') -module.exports = function(key, loadFn) { +module.exports = function (key, loadFn) { var cache = render.currentRender().mount.serverRenderCache || new NoCache() return cache.cache(key, loadFn) } -function NoCache() { +function NoCache () { } -NoCache.prototype.cache = function(key, loadFn) { +NoCache.prototype.cache = function (key, loadFn) { return loadFn() } diff --git a/set.js b/set.js index f7e56de..7422713 100644 --- a/set.js +++ b/set.js @@ -1,26 +1,26 @@ if (typeof Set === 'function') { - module.exports = Set; + module.exports = Set } else { - module.exports = function() { - this.items = []; - }; + module.exports = function () { + this.items = [] + } - module.exports.prototype.add = function(widget) { + module.exports.prototype.add = function (widget) { if (this.items.indexOf(widget) == -1) { - this.items.push(widget); + this.items.push(widget) } - }; + } - module.exports.prototype.delete = function(widget) { - var i = this.items.indexOf(widget); + module.exports.prototype.delete = function (widget) { + var i = this.items.indexOf(widget) if (i !== -1) { - this.items.splice(i, 1); + this.items.splice(i, 1) } - }; + } - module.exports.prototype.forEach = function(fn) { - for(var n = 0; n < this.items.length; n++) { - fn(this.items[n]); + module.exports.prototype.forEach = function (fn) { + for (var n = 0; n < this.items.length; n++) { + fn(this.items[n]) } - }; + } } diff --git a/simplePromise.js b/simplePromise.js index 135345c..3957ad9 100644 --- a/simplePromise.js +++ b/simplePromise.js @@ -1,25 +1,25 @@ function SimplePromise () { - this.listeners = []; + this.listeners = [] } SimplePromise.prototype.fulfill = function (value) { if (!this.isFulfilled) { - this.isFulfilled = true; - this.value = value; + this.isFulfilled = true + this.value = value this.listeners.forEach(function (listener) { - listener(); - }); + listener() + }) } -}; +} SimplePromise.prototype.then = function (success) { if (this.isFulfilled) { - success(this.value); + success(this.value) } else { - this.listeners.push(success); + this.listeners.push(success) } -}; +} module.exports = function () { - return new SimplePromise(); -}; + return new SimplePromise() +} diff --git a/storeCache.js b/storeCache.js index 9a428b8..4bb444f 100644 --- a/storeCache.js +++ b/storeCache.js @@ -1,12 +1,12 @@ module.exports = StoreCache -function StoreCache() { +function StoreCache () { this.data = {} this.loadPromises = [] var self = this - this.refreshify = function(fn) { - return function() { + this.refreshify = function (fn) { + return function () { var result = fn.apply(this, arguments) if (result && typeof result.then === 'function') { self.loadPromises.push(result) @@ -15,7 +15,7 @@ function StoreCache() { } } -StoreCache.prototype.cache = function(key, loadFn) { +StoreCache.prototype.cache = function (key, loadFn) { var self = this var loadPromise = loadFn().then(function (data) { @@ -29,28 +29,28 @@ StoreCache.prototype.cache = function(key, loadFn) { }) } -function modifyPromiseChain(promise, modify) { +function modifyPromiseChain (promise, modify) { modify(promise) - var then = promise.then; - var _catch = promise.catch; + var then = promise.then + var _catch = promise.catch promise.then = function () { - var p = then.apply(this, arguments); - modifyPromiseChain(p, modify); - return p; - }; + var p = then.apply(this, arguments) + modifyPromiseChain(p, modify) + return p + } promise.catch = function () { - var p = _catch.apply(this, arguments); - modifyPromiseChain(p, modify); - return p; - }; + var p = _catch.apply(this, arguments) + modifyPromiseChain(p, modify) + return p + } return promise } -StoreCache.prototype.loaded = function() { +StoreCache.prototype.loaded = function () { this.waitingForLoad = true return Promise.all(this.loadPromises).then(() => { this.waitingForLoad = false diff --git a/sync.js b/sync.js index 2ddc63d..f2c2956 100644 --- a/sync.js +++ b/sync.js @@ -1,80 +1,79 @@ -var hyperdom = require('.'); -var h = hyperdom.html; +var hyperdom = require('.') +var h = hyperdom.html module.exports = function () { - var refresh; - var throttle; + var refresh + var throttle - var promise, awaitingPromise, lastTime, lastValue, timeout; + var promise, awaitingPromise, lastTime, lastValue, timeout - var currentValue; - var currentFn; + var currentValue + var currentFn - function callFn() { + function callFn () { if (promise) { if (!awaitingPromise) { promise.then(function () { - promise = undefined; - awaitingPromise = undefined; - sync(); - }); + promise = undefined + awaitingPromise = undefined + sync() + }) - awaitingPromise = true; + awaitingPromise = true } } else { - var result = currentFn(currentValue); + var result = currentFn(currentValue) if (result && typeof result.then === 'function') { - promise = result; - promise.then(refresh); + promise = result + promise.then(refresh) } - valueChanged(); - lastTime = Date.now(); + valueChanged() + lastTime = Date.now() } } - - function valueHasChanged() { - return lastValue !== normalisedValue(currentValue); + function valueHasChanged () { + return lastValue !== normalisedValue(currentValue) } - function valueChanged() { - lastValue = normalisedValue(currentValue); + function valueChanged () { + lastValue = normalisedValue(currentValue) } - function sync() { - var now = Date.now(); + function sync () { + var now = Date.now() if (valueHasChanged()) { if (!lastTime || (lastTime + throttle < now)) { - callFn(); + callFn() } else if (!timeout) { - var timeoutDuration = lastTime - now + throttle; + var timeoutDuration = lastTime - now + throttle timeout = setTimeout(function () { - timeout = undefined; - callFn(); - }, timeoutDuration); + timeout = undefined + callFn() + }, timeoutDuration) } } } return function (value, options, fn) { if (typeof options === 'function') { - fn = options; - options = undefined; + fn = options + options = undefined } - refresh = h.refresh; - throttle = options && options.hasOwnProperty('throttle') && options.throttle !== undefined? options.throttle: 0; + refresh = h.refresh + throttle = options && options.hasOwnProperty('throttle') && options.throttle !== undefined ? options.throttle : 0 - currentValue = value; - currentFn = fn; + currentValue = value + currentFn = fn - sync(); + sync() } -}; +} -function normalisedValue(value) { +function normalisedValue (value) { return value.constructor === Object || value instanceof Array ? JSON.stringify(value) - : value; + : value } diff --git a/test/browser/hyperdomSpec.js b/test/browser/hyperdomSpec.js index 065066e..ddbc558 100644 --- a/test/browser/hyperdomSpec.js +++ b/test/browser/hyperdomSpec.js @@ -1,137 +1,137 @@ -var $ = require('jquery'); -var hyperdom = require('../..'); -var mapBinding = require('../../mapBinding'); -var h = hyperdom.html; -var jsx = hyperdom.jsx; -var expect = require('chai').expect; -var retry = require('trytryagain'); -require('jquery-sendkeys'); -var browser = require('browser-monkey').find('.test'); -var vdomToHtml = require('vdom-to-html'); -var times = require('lowscore/times'); -var vdomComponent = require('../../componentWidget'); -var windowEvents = require('../../windowEvents'); +var $ = require('jquery') +var hyperdom = require('../..') +var mapBinding = require('../../mapBinding') +var h = hyperdom.html +var jsx = hyperdom.jsx +var expect = require('chai').expect +var retry = require('trytryagain') +require('jquery-sendkeys') +var browser = require('browser-monkey').find('.test') +var vdomToHtml = require('vdom-to-html') +var times = require('lowscore/times') +var vdomComponent = require('../../componentWidget') +var windowEvents = require('../../windowEvents') var merge = require('../../merge') var runRender = require('../../render') var Mount = require('../../mount') var detect = { - dataset: typeof document.body.dataset == 'object' + dataset: typeof document.body.dataset === 'object' } describe('hyperdom', function () { - var div; + var div beforeEach(function () { - $('.test').remove(); + $('.test').remove() div = $('
').appendTo(document.body)[0] - }); + }) - function attach() { - var args = Array.prototype.slice.call(arguments); - args.unshift(div); + function attach () { + var args = Array.prototype.slice.call(arguments) + args.unshift(div) args.push({ requestRender: setTimeout - }); - hyperdom.append.apply(hyperdom, args); + }) + hyperdom.append.apply(hyperdom, args) } - function find(selector) { - return $(div).find(selector); + function find (selector) { + return $(div).find(selector) } - function click(selector) { + function click (selector) { return retry(function () { - expect(find(selector).length).to.equal(1, "could not find button '" + selector + "'"); + expect(find(selector).length).to.equal(1, "could not find button '" + selector + "'") }).then(function () { - find(selector).click(); - }); + find(selector).click() + }) } - function check(selector) { + function check (selector) { return retry(function () { - expect(find(selector).length).to.equal(1, "could not find button '" + selector + "'"); + expect(find(selector).length).to.equal(1, "could not find button '" + selector + "'") }).then(function () { - find(selector).prop('checked', true); - find(selector).click(); - }); + find(selector).prop('checked', true) + find(selector).click() + }) } - function renderMonitor() { + function renderMonitor () { return { renderCount: 0, rendering: function () { - this.renderCount++; + this.renderCount++ }, waitForRender: function () { - var self = this; + var self = this - var oldRefreshCount = self.renderCount; + var oldRefreshCount = self.renderCount - return this.wait(oldRefreshCount); + return this.wait(oldRefreshCount) }, waitForRenderAfter: function (action) { - var self = this; + var self = this - var oldRefreshCount = self.renderCount; + var oldRefreshCount = self.renderCount return action.then(function () { - return self.wait(oldRefreshCount); - }); + return self.wait(oldRefreshCount) + }) }, - wait: function(oldRefreshCount) { - var self = this; + wait: function (oldRefreshCount) { + var self = this return retry(function () { - expect(self.renderCount).to.equal(oldRefreshCount + 1); - }); + expect(self.renderCount).to.equal(oldRefreshCount + 1) + }) } - }; + } } describe('attaching', function () { - var targetDiv; + var targetDiv beforeEach(function () { - targetDiv = $('
').appendTo(div)[0]; - }); + targetDiv = $('
').appendTo(div)[0] + }) it('can append an element as a child of another', function () { - function render() { - return h('div.rendered'); + function render () { + return h('div.rendered') } - hyperdom.append(targetDiv, render); + hyperdom.append(targetDiv, render) - expect(div.innerHTML).to.equal('
'); - }); + expect(div.innerHTML).to.equal('
') + }) it('can pass a model with a render method', function () { var model = { stuff: 'stuff', render: function () { - return h('div.rendered', {onclick: function () {}}, this.stuff); + return h('div.rendered', {onclick: function () {}}, this.stuff) } - }; + } - var renderRequested = false; + var renderRequested = false hyperdom.append(targetDiv, model, { requestRender: function (render) { - renderRequested = true; - setTimeout(render); + renderRequested = true + setTimeout(render) } - }); + }) - expect(div.innerHTML).to.equal('
stuff
'); + expect(div.innerHTML).to.equal('
stuff
') return click('div.rendered').then(function () { - expect(renderRequested).to.be.true; - }); - }); + expect(renderRequested).to.be.true + }) + }) it('can pass a synchronous reqeustRender function', function () { var model = { @@ -144,15 +144,15 @@ describe('hyperdom', function () { h('button.add', {onclick: function () { self.count++ }}, '++') ) } - }; + } - var renderRequested = false; + var renderRequested = false hyperdom.append(targetDiv, model, { requestRender: function (render) { render() } - }); + }) expect(find('.count').text()).to.equal('count: 0') find('.add').click() @@ -161,29 +161,29 @@ describe('hyperdom', function () { expect(find('.count').text()).to.equal('count: 2') find('.add').click() expect(find('.count').text()).to.equal('count: 3') - }); + }) it('can replace an element', function () { - function render() { - return h('div.rendered'); + function render () { + return h('div.rendered') } - hyperdom.replace(targetDiv, render); + hyperdom.replace(targetDiv, render) - expect(div.innerHTML).to.equal('
'); - }); + expect(div.innerHTML).to.equal('
') + }) it('can append to a vdom node', function () { - function render() { - return h('div.rendered'); + function render () { + return h('div.rendered') } - var targetVDom = h('body'); + var targetVDom = h('body') - hyperdom.appendVDom(targetVDom, render); + hyperdom.appendVDom(targetVDom, render) - expect(vdomToHtml(targetVDom)).to.contain('
'); - }); + expect(vdomToHtml(targetVDom)).to.contain('
') + }) describe('server-side rendering', function () { var app @@ -195,392 +195,391 @@ describe('hyperdom', function () { app = { name: 'server render', - render: function() { - var self = this; + render: function () { + var self = this return h('div.static', h('h1', self.name), h('button.update', { onclick: function () { events.push('click') - self.name = 'client render'; + self.name = 'client render' } }, 'update' ) - ); + ) } } - }); + }) it('can merge onto an existing DOM', function () { - $(targetDiv).replaceWith(vdomToHtml(app.render())); + $(targetDiv).replaceWith(vdomToHtml(app.render())) - var mergeDiv = div.children[0]; + var mergeDiv = div.children[0] - merge(mergeDiv, app); + merge(mergeDiv, app) return retry(function () { - expect(find('button.update')[0].onclick).to.exist; + expect(find('button.update')[0].onclick).to.exist }).then(function () { return click('button.update').then(function () { }).then(function () { return retry(function () { - expect(find('h1').text()).to.equal('client render'); - }); - }); - }); - }); + expect(find('h1').text()).to.equal('client render') + }) + }) + }) + }) it('updates client side with client-side changes', function () { - $(targetDiv).replaceWith(vdomToHtml(app.render())); + $(targetDiv).replaceWith(vdomToHtml(app.render())) - var mergeDiv = div.children[0]; + var mergeDiv = div.children[0] app.name = 'client render' merge(mergeDiv, app) - expect(find('h1').text()).to.equal('client render'); - }); - }); - }); + expect(find('h1').text()).to.equal('client render') + }) + }) + }) describe('rendering', function () { it('can render a div', function () { - function render() { - return h('div.haha'); + function render () { + return h('div.haha') } - attach(render, {}); + attach(render, {}) - expect(find('.haha').length).to.eql(1); - }); + expect(find('.haha').length).to.eql(1) + }) it('can render pound sign', function () { - function render() { - return h('div','£'); + function render () { + return h('div', '£') } - attach(render, {}); + attach(render, {}) - expect(find('div').text()).to.eql('£'); - }); + expect(find('div').text()).to.eql('£') + }) - function itCanRenderA(type, value, expectedValue) { + function itCanRenderA (type, value, expectedValue) { it('can render a ' + type, function () { - function render() { - return h('div.haha', value); + function render () { + return h('div.haha', value) } - attach(render, {}); + attach(render, {}) - expect(find('.haha').text()).to.eql(expectedValue != undefined? expectedValue: String(value)); - }); + expect(find('.haha').text()).to.eql(expectedValue != undefined ? expectedValue : String(value)) + }) } - itCanRenderA('number', 4); - itCanRenderA('boolean', true); - itCanRenderA('date', new Date()); - itCanRenderA('undefined', undefined, ''); + itCanRenderA('number', 4) + itCanRenderA('boolean', true) + itCanRenderA('date', new Date()) + itCanRenderA('undefined', undefined, '') it('can render an object', function () { - function render() { - return h('div.haha', 'object ', { name: 'asdf' }); + function render () { + return h('div.haha', 'object ', { name: 'asdf' }) } - attach(render, {}); + attach(render, {}) - expect(find('.haha').text()).to.equal('object {"name":"asdf"}'); - }); + expect(find('.haha').text()).to.equal('object {"name":"asdf"}') + }) describe('class', function () { it('accepts a string', function () { - function render() { - return h('div.one', {class: 'two three'}); + function render () { + return h('div.one', {class: 'two three'}) } - attach(render, {}); + attach(render, {}) - expect(find('div').attr('class')).to.eql('one two three'); - }); + expect(find('div').attr('class')).to.eql('one two three') + }) it('accepts an array of strings', function () { - function render() { - return h('div.one', {class: ['two', 'three']}); + function render () { + return h('div.one', {class: ['two', 'three']}) } - attach(render, {}); + attach(render, {}) - expect(find('div').attr('class')).to.eql('one two three'); - }); + expect(find('div').attr('class')).to.eql('one two three') + }) it('accepts an object', function () { - function render() { - return h('div.one', {class: {two: true, three: true, four: false}}); + function render () { + return h('div.one', {class: {two: true, three: true, four: false}}) } - attach(render, {}); + attach(render, {}) - expect(find('div').attr('class')).to.eql('one two three'); - }); + expect(find('div').attr('class')).to.eql('one two three') + }) it('accepts an array with a mix of strings and objects', function () { - function render() { - return h('div.one', {class: ['two', ['three', {four: true, five: false}], {six: true, seven: false, eight: true}]}); + function render () { + return h('div.one', {class: ['two', ['three', {four: true, five: false}], {six: true, seven: false, eight: true}]}) } - attach(render, {}); + attach(render, {}) - expect(find('div').attr('class')).to.eql('one two three four six eight'); - }); - }); + expect(find('div').attr('class')).to.eql('one two three four six eight') + }) + }) describe('selectors', function () { - function selectorProduces(selector, expectedSelector) { + function selectorProduces (selector, expectedSelector) { it("h('" + selector + "') produces '" + expectedSelector + "'", function () { - function render() { - return h(selector); + function render () { + return h(selector) } - attach(render); + attach(render) - expect(find(expectedSelector).length).to.equal(1); - }); + expect(find(expectedSelector).length).to.equal(1) + }) } - selectorProduces('div.class', 'div.class'); - selectorProduces('div#id', 'div#id'); - selectorProduces('div.class#id', 'div.class#id'); - selectorProduces('h1 a', 'h1 a'); - }); + selectorProduces('div.class', 'div.class') + selectorProduces('div#id', 'div#id') + selectorProduces('div.class#id', 'div.class#id') + selectorProduces('h1 a', 'h1 a') + }) describe('attribute naming exceptions', function () { it('can render a for attribute', function () { - function render() { - return h('div', + function render () { + return h('div', h('label', {for: 'blah'}) - ); - } + ) + } - attach(render, {text: 'one'}); + attach(render, {text: 'one'}) - expect(find('label').attr('for')).to.eql('blah'); - }); + expect(find('label').attr('for')).to.eql('blah') + }) it('can render a contenteditable attribute', function () { - function render() { - return h('div', {contenteditable: true}); - } + function render () { + return h('div', {contenteditable: true}) + } - attach(render); + attach(render) - expect(find('div').attr('contenteditable')).to.eql('true'); - }); + expect(find('div').attr('contenteditable')).to.eql('true') + }) it('can render a tabindex attribute', function () { - function render() { - return h('div', {tabindex: 3}); - } + function render () { + return h('div', {tabindex: 3}) + } - attach(render); + attach(render) - expect(find('div').attr('tabindex')).to.eql('3'); - }); + expect(find('div').attr('tabindex')).to.eql('3') + }) it('can render a colspan attribute', function () { - function render() { - return h('table tbody tr td', {colspan: 3}); - } + function render () { + return h('table tbody tr td', {colspan: 3}) + } - attach(render); + attach(render) - expect(find('table tbody tr td').attr('colspan')).to.eql('3'); - }); + expect(find('table tbody tr td').attr('colspan')).to.eql('3') + }) if (detect.dataset) { describe('data- attributes', function () { it('can render data- attributes', function () { - function render() { - return h('div', {'id': 'bals', 'data-one': 'one', 'data-two-two': 'two'}); + function render () { + return h('div', {'id': 'bals', 'data-one': 'one', 'data-two-two': 'two'}) } - attach(render); + attach(render) - expect(find('div').data('one')).to.eql('one'); - expect(find('div').data('two-two')).to.eql('two'); - }); + expect(find('div').data('one')).to.eql('one') + expect(find('div').data('two-two')).to.eql('two') + }) it('can render data- and dataset attributes', function () { - function render() { - return h('div', {'data-one': 'one', 'data-two': 'two', dataset: {three: 'three'}}); + function render () { + return h('div', {'data-one': 'one', 'data-two': 'two', dataset: {three: 'three'}}) } - attach(render); + attach(render) - expect(find('div').data('one')).to.eql('one'); - expect(find('div').data('two')).to.eql('two'); - expect(find('div').data('three')).to.eql('three'); - }); - }); + expect(find('div').data('one')).to.eql('one') + expect(find('div').data('two')).to.eql('two') + expect(find('div').data('three')).to.eql('three') + }) + }) } - }); + }) describe('non-standard HTML attributes', function () { it('can be rendered by passing an attributes object', function () { - function render() { - return h('div', + function render () { + return h('div', h('input', { type: 'text', attributes: { autocapitalize: 'none', autofocus: true } }) - ); - } + ) + } - attach(render, {}); + attach(render, {}) - expect(find('input').attr('autocapitalize')).to.equal('none'); - expect(find('input').attr('autofocus')).to.equal('autofocus'); - }); - }); + expect(find('input').attr('autocapitalize')).to.equal('none') + expect(find('input').attr('autofocus')).to.equal('autofocus') + }) + }) describe('raw unescaped HTML', function () { it('can render raw HTML', function () { - function render(model) { + function render (model) { return h('div', model.text ? h.rawHtml('p', 'some dangerous HTML (' + model.text + ')') : undefined, - h('button.two', {onclick: function () { model.text = 'two'; }}), - h('button.three', {onclick: function () { model.text = ''; }}) - ); + h('button.two', {onclick: function () { model.text = 'two' }}), + h('button.three', {onclick: function () { model.text = '' }}) + ) } - attach(render, {text: 'one'}); + attach(render, {text: 'one'}) - expect(find('p').html()).to.eql('some dangerous HTML (one)'); + expect(find('p').html()).to.eql('some dangerous HTML (one)') return click('button.two').then(function () { - return retry(function () { - expect(find('p').html()).to.eql('some dangerous HTML (two)'); + expect(find('p').html()).to.eql('some dangerous HTML (two)') }).then(function () { return click('button.three').then(function () { return retry(function () { - expect(find('p').length).to.eql(0); - }); - }); - }); - }); - }); + expect(find('p').length).to.eql(0) + }) + }) + }) + }) + }) it('renders undefined as empty string', function () { - function render() { - return h.rawHtml('.raw', undefined); + function render () { + return h.rawHtml('.raw', undefined) } - attach(render, {text: 'one'}); + attach(render, {text: 'one'}) - expect(find('.raw').text()).to.eql(''); - }); + expect(find('.raw').text()).to.eql('') + }) it('can render raw HTML with attributes', function () { - function render() { + function render () { return h('div', h.rawHtml('p.raw', {style: {color: 'red'}}, 'some dangerous HTML') - ); + ) } - attach(render, {text: 'one'}); + attach(render, {text: 'one'}) - var p = find('p'); - expect(p.html()).to.eql('some dangerous HTML'); - expect(p.attr('class')).to.eql('raw'); - expect(p.attr('style')).to.eql('color: red;'); - }); + var p = find('p') + expect(p.html()).to.eql('some dangerous HTML') + expect(p.attr('class')).to.eql('raw') + expect(p.attr('style')).to.eql('color: red;') + }) - it('updates the dom when the HTML changes', function() { - function render(model) { + it('updates the dom when the HTML changes', function () { + function render (model) { return h('div', h.rawHtml('p.raw', model.html), h('p.x', model.x), - h('button.one', {onclick: function () { model.x = 'zzz'; }}), - h('button.two', {onclick: function () { model.html = 'Nice HTML'; }}) - ); + h('button.one', {onclick: function () { model.x = 'zzz' }}), + h('button.two', {onclick: function () { model.html = 'Nice HTML' }}) + ) } - attach(render, {html: 'Naughty HTML', x: 'yyy'}); + attach(render, {html: 'Naughty HTML', x: 'yyy'}) - expect(find('p.raw').html()).to.equal('Naughty HTML'); + expect(find('p.raw').html()).to.equal('Naughty HTML') - var b = find('p.raw b')[0]; + var b = find('p.raw b')[0] return click('button.one').then(function () { - return retry(function() { - expect(find('p.x').html()).to.equal('zzz'); - }).then(function() { - expect(find('p.raw b')[0]).to.equal(b); + return retry(function () { + expect(find('p.x').html()).to.equal('zzz') + }).then(function () { + expect(find('p.raw b')[0]).to.equal(b) return click('button.two').then(function () { - return retry(function() { - expect(find('p.raw b')[0]).not.to.equal(b); - }); - }); + return retry(function () { + expect(find('p.raw b')[0]).not.to.equal(b) + }) + }) }) - }); - }); - }); + }) + }) + }) if (detect.dataset) { it('generates filename and line number from __source attribute', function () { - function render() { - return h('div', {__source: {fileName: '/full/path/to/file.jsx', lineNumber: 80}}); + function render () { + return h('div', {__source: {fileName: '/full/path/to/file.jsx', lineNumber: 80}}) } - attach(render, {}); + attach(render, {}) - expect(find('div').data('file-name')).to.eql('/full/path/to/file.jsx'); - expect(find('div').data('line-number')).to.eql(80); - }); + expect(find('div').data('file-name')).to.eql('/full/path/to/file.jsx') + expect(find('div').data('line-number')).to.eql(80) + }) } - }); + }) describe('jsx', function () { it('renders', function () { - function render() { + function render () { return jsx('div', {class: 'one'}, [ jsx('div', {class: 'two'}, ['text']) - ]); + ]) } - attach(render, {}); + attach(render, {}) - expect(find('div.one').attr('class')).to.eql('one'); - expect(find('div.one > div.two').text()).to.eql('text'); - }); - }); + expect(find('div.one').attr('class')).to.eql('one') + expect(find('div.one > div.two').text()).to.eql('text') + }) + }) describe('xml', function () { it('renders xml element all children with namespace specified with xmlns', function () { - function render() { - return jsx('svg', {xmlns: 'http://www.w3.org/2000/svg', width: "300", height: "300"}, [ + function render () { + return jsx('svg', {xmlns: 'http://www.w3.org/2000/svg', width: '300', height: '300'}, [ jsx('circle', {cx: '50', cy: '50', r: '40', stroke: 'red', 'stroke-width': '4', fill: 'yellow'}) - ]); + ]) } - attach(render, {}); + attach(render, {}) - expect(find('svg')[0].namespaceURI).to.eql('http://www.w3.org/2000/svg'); - expect(find('svg>circle')[0].namespaceURI).to.eql('http://www.w3.org/2000/svg'); - }); + expect(find('svg')[0].namespaceURI).to.eql('http://www.w3.org/2000/svg') + expect(find('svg>circle')[0].namespaceURI).to.eql('http://www.w3.org/2000/svg') + }) it('renders tags with namespaces', function () { - function render() { + function render () { return jsx('data', {xmlns: 'urn:data', 'xmlns--addr': 'urn:address'}, [ jsx('addr--address', {name: 'bob', 'addr--street': 'ny st'}) ]) } - attach(render, {}); + attach(render, {}) - expect(find('data')[0].namespaceURI).to.eql('urn:data'); + expect(find('data')[0].namespaceURI).to.eql('urn:data') var address = find('data>address')[0] expect(address.namespaceURI).to.eql('urn:address') expect(address.prefix).to.eql('addr') @@ -591,18 +590,18 @@ describe('hyperdom', function () { expect(addressAttribute.localName).to.eql('street') expect(addressAttribute.value).to.eql('ny st') expect(address.getAttribute('name')).to.eql('bob') - }); + }) it('inner element can declare new default namespace', function () { - function render() { + function render () { return jsx('data', {xmlns: 'urn:data'}, [ jsx('address', {name: 'bob', xmlns: 'urn:address', 'xmlns--addr': 'urn:address', 'addr--street': 'ny st'}) ]) } - attach(render, {}); + attach(render, {}) - expect(find('data')[0].namespaceURI).to.eql('urn:data'); + expect(find('data')[0].namespaceURI).to.eql('urn:data') var address = find('data>address')[0] expect(address.namespaceURI).to.eql('urn:address') expect(address.prefix).to.eql(null) @@ -614,85 +613,85 @@ describe('hyperdom', function () { expect(addressAttribute.localName).to.eql('street') expect(addressAttribute.value).to.eql('ny st') expect(address.getAttribute('name')).to.eql('bob') - }); - }); + }) + }) describe('event handlers', function () { it('can respond to button clicks', function () { - function render(model) { + function render (model) { return h('div', h('button', { onclick: function () { - model.on = true; + model.on = true } }), - model.on? h('span', 'on'): undefined - ); + model.on ? h('span', 'on') : undefined + ) } - attach(render, {}); + attach(render, {}) return click('button').then(function () { return retry(function () { - expect(find('span').text()).to.eql('on'); - }); - }); - }); + expect(find('span').text()).to.eql('on') + }) + }) + }) it('can respond to button clicks after promise resolves', function () { - function render(model) { + function render (model) { return h('div', h('button', { onclick: function () { - model.text = 'loading'; + model.text = 'loading' return new Promise(function (result) { setTimeout(function () { - model.text = 'loaded'; - result(); - }, 100); - }); + model.text = 'loaded' + result() + }, 100) + }) } }), h('span', model.text) - ); + ) } - attach(render, {}); + attach(render, {}) return click('button').then(function () { return retry(function () { - expect(find('span').text()).to.eql('loading'); - }); + expect(find('span').text()).to.eql('loading') + }) }).then(function () { return retry(function () { - expect(find('span').text()).to.eql('loaded'); - }); - }); - }); + expect(find('span').text()).to.eql('loaded') + }) + }) + }) it('can define event handlers outside of the render loop', function () { var model = { button: h('button', { onclick: function () { - model.on = true; + model.on = true } }), render: function () { return h('div', this.button, - model.on? h('span', 'on'): undefined - ); + model.on ? h('span', 'on') : undefined + ) } } - attach(model); + attach(model) return click('button').then(function () { return retry(function () { - expect(find('span').text()).to.eql('on'); - }); - }); + expect(find('span').text()).to.eql('on') + }) + }) }) it('can render components outside of the render loop', function () { @@ -702,7 +701,7 @@ describe('hyperdom', function () { render: function () { return h('button', { onclick: function () { - model.on = true; + model.on = true } }) } @@ -712,26 +711,26 @@ describe('hyperdom', function () { render: function () { return h('div', this.button, - model.on? h('span', 'on'): undefined - ); + model.on ? h('span', 'on') : undefined + ) } } - attach(model); + attach(model) return click('button').then(function () { return retry(function () { - expect(find('span').text()).to.eql('on'); - }); - }); + expect(find('span').text()).to.eql('on') + }) + }) }) }) describe('norefresh', function () { it("when returned the view doesn't refresh after the handler has run", function () { - var refreshes = 0; - function render() { - refreshes++; + var refreshes = 0 + function render () { + refreshes++ return h('div', h('button.refresh', { @@ -740,59 +739,59 @@ describe('hyperdom', function () { }), h('button.norefresh', { onclick: function () { - return hyperdom.norefresh(); + return hyperdom.norefresh() } }), h('span', refreshes) - ); + ) } - attach(render, {}); + attach(render, {}) return click('button.refresh').then(function () { return retry(function () { - expect(refreshes).to.eql(2); + expect(refreshes).to.eql(2) }).then(function () { return click('button.norefresh').then(function () { return wait(10).then(function () { return retry(function () { - expect(refreshes, 'expected not to refresh').to.eql(2); + expect(refreshes, 'expected not to refresh').to.eql(2) }).then(function () { return click('button.refresh').then(function () { return retry(function () { - expect(refreshes, 'expected to refresh').to.eql(3); - }); - }); - }); - }); - }); - }); - }); - }); - }); + expect(refreshes, 'expected to refresh').to.eql(3) + }) + }) + }) + }) + }) + }) + }) + }) + }) describe('model binding', function () { it('can bind to a text input', function () { - function render(model) { + function render (model) { return h('div', h('input', {type: 'text', binding: [model, 'text']}), h('span', model.text) - ); + ) } - attach(render, {text: ''}); + attach(render, {text: ''}) - find('input').sendkeys('haha'); + find('input').sendkeys('haha') - return retry(function() { - expect(find('span').text()).to.equal('haha'); - expect(find('input').val()).to.equal('haha'); - }); - }); + return retry(function () { + expect(find('span').text()).to.equal('haha') + expect(find('input').val()).to.equal('haha') + }) + }) describe('setting input values on reused DOM elements', function () { it('checkbox', function () { - function render(model) { + function render (model) { return h('div', !model.hide1 ? h('label', h('input.one', {type: 'checkbox', binding: [model, 'hide1']}), 'hide one') @@ -800,203 +799,203 @@ describe('hyperdom', function () { !model.hide2 ? h('label', h('input.two', {type: 'checkbox', binding: [model, 'hide2']}), 'hide two') : undefined - ); + ) } - attach(render, {}); + attach(render, {}) return click('.one').then(function () { return retry(function () { - expect(find('input.one').length).to.equal(0); - expect(find('input.two').prop('checked')).to.equal(false); - }); - }); - }); + expect(find('input.one').length).to.equal(0) + expect(find('input.two').prop('checked')).to.equal(false) + }) + }) + }) it('radio', function () { - function render(model) { + function render (model) { return h('div', - model.value == 1? h('h1', 'selected one'): undefined, + model.value == 1 ? h('h1', 'selected one') : undefined, h('label', h('input.one', {type: 'radio', name: 'thingy', binding: [model, 'value'], value: 1, id: 'one'}), 'one'), h('label', h('input.two', {type: 'radio', name: 'thingy', binding: [model, 'value'], value: 2, id: 'two'}), 'two') - ); + ) } - attach(render, {value: 1}); + attach(render, {value: 1}) return check('.two').then(function () { return retry(function () { - expect(find('h1').length).to.equal(0); - expect(find('input.one')[0].checked).to.equal(false); - expect(find('input.two')[0].checked).to.equal(true); - }); - }); - }); - }); + expect(find('h1').length).to.equal(0) + expect(find('input.one')[0].checked).to.equal(false) + expect(find('input.two')[0].checked).to.equal(true) + }) + }) + }) + }) describe('binding options', function () { it('can bind with set conversion', function () { var numberConversion = { model: function (view) { - return Number(view); + return Number(view) }, view: function (model) { - return String(model); + return String(model) } - }; + } - function render(model) { + function render (model) { return h('div', h('input', {type: 'text', binding: mapBinding(model, 'number', numberConversion)}), h('span', model.number) - ); + ) } - var model = {number: 0}; - attach(render, model); + var model = {number: 0} + attach(render, model) - find('input').sendkeys('{selectall}{backspace}123'); + find('input').sendkeys('{selectall}{backspace}123') - return retry(function() { - expect(find('span').text()).to.equal('123'); - expect(find('input').val()).to.equal('123'); - expect(model.number).to.equal(123); - }); - }); + return retry(function () { + expect(find('span').text()).to.equal('123') + expect(find('input').val()).to.equal('123') + expect(model.number).to.equal(123) + }) + }) it("doesn't set the input text if the value is an Error", function () { - function number(value) { - var n = Number(value); + function number (value) { + var n = Number(value) if (isNaN(n)) { - return new Error('expected a number'); + return new Error('expected a number') } else { - return n; + return n } } - function render(model) { + function render (model) { return h('div', h('input', {type: 'text', binding: mapBinding(model, 'number', number)}), h('span', model.number) - ); + ) } - var model = {number: 0}; - attach(render, model); + var model = {number: 0} + attach(render, model) - find('input').sendkeys('{selectall}{backspace}abc'); + find('input').sendkeys('{selectall}{backspace}abc') - return retry(function() { - expect(find('span').text()).to.equal('Error: expected a number'); - expect(find('input').val()).to.equal('abc'); - expect(model.number).to.be.instanceof(Error); + return retry(function () { + expect(find('span').text()).to.equal('Error: expected a number') + expect(find('input').val()).to.equal('abc') + expect(model.number).to.be.instanceof(Error) }).then(function () { - find('input').sendkeys('{selectall}{backspace}123'); + find('input').sendkeys('{selectall}{backspace}123') }).then(function () { - return retry(function() { - expect(find('span').text()).to.equal('123'); - expect(find('input').val()).to.equal('123'); - expect(model.number).to.equal(123); - }); - }); - }); - }); + return retry(function () { + expect(find('span').text()).to.equal('123') + expect(find('input').val()).to.equal('123') + expect(model.number).to.equal(123) + }) + }) + }) + }) it('when model returns undefined, it clears the input', function () { - function render(model) { + function render (model) { return h('div', h('input', {type: 'text', binding: [model, 'text']}), - h('button.clear', {onclick: function () { delete model.text; }}, 'clear'), + h('button.clear', {onclick: function () { delete model.text }}, 'clear'), h('span', model.text) - ); + ) } - attach(render, {text: ''}); + attach(render, {text: ''}) - find('input').sendkeys('haha'); + find('input').sendkeys('haha') - return retry(function() { - expect(find('span').text()).to.equal('haha'); - expect(find('input').val()).to.equal('haha'); + return retry(function () { + expect(find('span').text()).to.equal('haha') + expect(find('input').val()).to.equal('haha') return click('button.clear').then(function () { return retry(function () { - expect(find('span').text()).to.equal(''); - expect(find('input').val()).to.equal(''); - }); - }); - }); - }); + expect(find('span').text()).to.equal('') + expect(find('input').val()).to.equal('') + }) + }) + }) + }) it('can bind to a text input and oninput', function () { - function render(model) { + function render (model) { return h('div', h('input', { type: 'text', binding: [model, 'tempText'], oninput: function () { - model.text = model.tempText; + model.text = model.tempText } }), h('span', model.text) - ); + ) } - attach(render, {text: ''}); + attach(render, {text: ''}) - find('input').sendkeys('haha{newline}'); + find('input').sendkeys('haha{newline}') - return retry(function() { - expect(find('span').text()).to.contain('haha'); - expect(find('input').val()).to.contain('haha'); - }); - }); + return retry(function () { + expect(find('span').text()).to.contain('haha') + expect(find('input').val()).to.contain('haha') + }) + }) it('can bind to a textarea', function () { - function render(model) { + function render (model) { return h('div', h('textarea', {binding: [model, 'text']}), h('span', model.text) - ); + ) } - attach(render, {text: ''}); + attach(render, {text: ''}) - find('textarea').sendkeys('haha'); + find('textarea').sendkeys('haha') - return retry(function() { - expect(find('span').text()).to.equal('haha'); - expect(find('textarea').val()).to.equal('haha'); - }); - }); + return retry(function () { + expect(find('span').text()).to.equal('haha') + expect(find('textarea').val()).to.equal('haha') + }) + }) it('can bind to a checkbox', function () { - function render(model) { + function render (model) { return h('div', h('input', {type: 'checkbox', binding: [model, 'check']}), - h('span', model.check? 'on': 'off') - ); + h('span', model.check ? 'on' : 'off') + ) } - attach(render, {check: false}); + attach(render, {check: false}) - return retry(function() { - expect(find('span').text()).to.equal('off'); - expect(find('input').prop('checked')).to.equal(false); + return retry(function () { + expect(find('span').text()).to.equal('off') + expect(find('input').prop('checked')).to.equal(false) }).then(function () { - find('input').click(); + find('input').click() - return retry(function() { - expect(find('span').text()).to.equal('on'); - expect(find('input').prop('checked')).to.equal(true); - }); - }); - }); + return retry(function () { + expect(find('span').text()).to.equal('on') + expect(find('input').prop('checked')).to.equal(true) + }) + }) + }) it('can bind to radio buttons', function () { - var blue = { name: 'blue' }; + var blue = { name: 'blue' } - function render(model) { + function render (model) { return h('div', h('input.red', { type: 'radio', @@ -1011,36 +1010,36 @@ describe('hyperdom', function () { value: blue }), h('span', JSON.stringify(model.colour)) - ); + ) } - attach(render, { colour: blue }); + attach(render, { colour: blue }) - return retry(function() { - expect(find('span').text()).to.equal('{"name":"blue"}'); - expect(find('input.blue').prop('checked')).to.equal(true); - expect(find('input.red').prop('checked')).to.equal(false); + return retry(function () { + expect(find('span').text()).to.equal('{"name":"blue"}') + expect(find('input.blue').prop('checked')).to.equal(true) + expect(find('input.red').prop('checked')).to.equal(false) }).then(function () { - find('input.red').click(); + find('input.red').click() - return retry(function() { - expect(find('span').text()).to.equal('"red"'); - expect(find('input.red').prop('checked')).to.equal(true); + return retry(function () { + expect(find('span').text()).to.equal('"red"') + expect(find('input.red').prop('checked')).to.equal(true) }).then(function () { - find('input.blue').click(); + find('input.blue').click() - return retry(function() { - expect(find('span').text()).to.equal('{"name":"blue"}'); - expect(find('input.blue').prop('checked')).to.equal(true); - }); - }); - }); - }); + return retry(function () { + expect(find('span').text()).to.equal('{"name":"blue"}') + expect(find('input.blue').prop('checked')).to.equal(true) + }) + }) + }) + }) it('can bind to select', function () { - var blue = { name: 'blue' }; + var blue = { name: 'blue' } - function render(model) { + function render (model) { return h('div', h('select', {binding: [model, 'colour']}, @@ -1048,36 +1047,36 @@ describe('hyperdom', function () { h('option.blue', {value: blue}, 'blue') ), h('span', JSON.stringify(model.colour)) - ); + ) } - attach(render, { colour: blue }); + attach(render, { colour: blue }) - return retry(function() { - expect(find('span').text()).to.equal('{"name":"blue"}'); - expect(find('option.red').prop('selected')).to.equal(false); - expect(find('option.blue').prop('selected')).to.equal(true); + return retry(function () { + expect(find('span').text()).to.equal('{"name":"blue"}') + expect(find('option.red').prop('selected')).to.equal(false) + expect(find('option.blue').prop('selected')).to.equal(true) }).then(function () { - find('select')[0].selectedIndex = 0; - find('select').change(); + find('select')[0].selectedIndex = 0 + find('select').change() - return retry(function() { - expect(find('span').text()).to.equal('"red"'); - expect(find('option.red').prop('selected')).to.equal(true); + return retry(function () { + expect(find('span').text()).to.equal('"red"') + expect(find('option.red').prop('selected')).to.equal(true) }).then(function () { - find('select')[0].selectedIndex = 1; - find('select').change(); + find('select')[0].selectedIndex = 1 + find('select').change() - return retry(function() { - expect(find('span').text()).to.equal('{"name":"blue"}'); - expect(find('option.blue').prop('selected')).to.equal(true); - }); - }); - }); - }); + return retry(function () { + expect(find('span').text()).to.equal('{"name":"blue"}') + expect(find('option.blue').prop('selected')).to.equal(true) + }) + }) + }) + }) it('can bind to select with no values on its options', function () { - function render(model) { + function render (model) { return h('div', h('select', {binding: [model, 'colour']}, @@ -1087,34 +1086,34 @@ describe('hyperdom', function () { h('option.blue', 'bl', 'ue') ), h('span', JSON.stringify(model.colour)) - ); + ) } - attach(render, { colour: 'blue' }); + attach(render, { colour: 'blue' }) - return retry(function() { - expect(find('span').text()).to.equal('"blue"'); - expect(find('option.red').prop('selected')).to.equal(false); - expect(find('option.blue').prop('selected')).to.equal(true); + return retry(function () { + expect(find('span').text()).to.equal('"blue"') + expect(find('option.red').prop('selected')).to.equal(false) + expect(find('option.blue').prop('selected')).to.equal(true) }).then(function () { - find('select')[0].selectedIndex = 0; - find('select').change(); + find('select')[0].selectedIndex = 0 + find('select').change() - return retry(function() { - expect(find('span').text()).to.equal('"red"'); - expect(find('option.red').prop('selected')).to.equal(true); + return retry(function () { + expect(find('span').text()).to.equal('"red"') + expect(find('option.red').prop('selected')).to.equal(true) }).then(function () { - find('select')[0].selectedIndex = 3; - find('select').change(); - - return retry(function() { - expect(find('span').text()).to.equal('"blue"'); - expect(find('option.blue').prop('selected')).to.equal(true); - }); - }); - }); - }); - }); + find('select')[0].selectedIndex = 3 + find('select').change() + + return retry(function () { + expect(find('span').text()).to.equal('"blue"') + expect(find('option.blue').prop('selected')).to.equal(true) + }) + }) + }) + }) + }) describe('components', function () { it('calls onload once when HTML appears on page', function () { @@ -1123,36 +1122,36 @@ describe('hyperdom', function () { refreshed: 0, onload: function () { - var self = this; + var self = this return wait(20).then(function () { - self.loaded++; - }); + self.loaded++ + }) }, - render: function() { - this.refreshed++; + render: function () { + this.refreshed++ return h('div', h('h1.loaded', 'loaded ' + this.loaded + ' times'), h('h1.refreshed', 'refreshed ' + this.refreshed + ' times'), h('button.refresh', {onclick: function () {}}, 'refresh') - ); + ) } - }; + } - attach(model); + attach(model) return retry(function () { - expect(find('h1.loaded').text()).to.equal('loaded 1 times'); - expect(find('h1.refreshed').text()).to.equal('refreshed 2 times'); + expect(find('h1.loaded').text()).to.equal('loaded 1 times') + expect(find('h1.refreshed').text()).to.equal('refreshed 2 times') }).then(function () { - return click('button.refresh'); + return click('button.refresh') }).then(function () { return retry(function () { - expect(find('h1.loaded').text()).to.equal('loaded 1 times'); - expect(find('h1.refreshed').text()).to.equal('refreshed 3 times'); - }); - }); - }); + expect(find('h1.loaded').text()).to.equal('loaded 1 times') + expect(find('h1.refreshed').text()).to.equal('refreshed 3 times') + }) + }) + }) describe('inner components', function () { it('calls onload once when HTML appears on page', function () { @@ -1162,46 +1161,46 @@ describe('hyperdom', function () { refreshed: 0, onload: function () { - var self = this; + var self = this return wait(20).then(function () { - self.loaded++; - }); + self.loaded++ + }) }, - render: function() { - this.refreshed++; + render: function () { + this.refreshed++ return h('div', h('h1.loaded', 'loaded ' + this.loaded + ' times'), h('h1.refreshed', 'refreshed ' + this.refreshed + ' times'), h('button.refresh', {onclick: function () {}}, 'refresh') - ); + ) } }, render: function () { - return h('div.outer', this.innerModel); + return h('div.outer', this.innerModel) } - }; + } - attach(model); + attach(model) return retry(function () { - expect(find('h1.loaded').text()).to.equal('loaded 1 times'); - expect(find('h1.refreshed').text()).to.equal('refreshed 2 times'); + expect(find('h1.loaded').text()).to.equal('loaded 1 times') + expect(find('h1.refreshed').text()).to.equal('refreshed 2 times') }).then(function () { - return click('button.refresh'); + return click('button.refresh') }).then(function () { return retry(function () { - expect(find('h1.loaded').text()).to.equal('loaded 1 times'); - expect(find('h1.refreshed').text()).to.equal('refreshed 3 times'); - }); - }); - }); - }); + expect(find('h1.loaded').text()).to.equal('loaded 1 times') + expect(find('h1.refreshed').text()).to.equal('refreshed 3 times') + }) + }) + }) + }) it('receives onadd, onupdate and onremove events after the DOM changes have been made', function () { - var events = []; - var monitor = renderMonitor(); + var events = [] + var monitor = renderMonitor() var model = { showComponent: true, @@ -1212,48 +1211,48 @@ describe('hyperdom', function () { type: 'onadd', parent: element.parentNode, element: element - }); + }) }, onupdate: function (element) { events.push({ type: 'onupdate', - element: element, - }); + element: element + }) }, onremove: function (element) { events.push({ type: 'onremove', - element: element, - }); + element: element + }) }, render: function () { - return h('h1', 'component'); + return h('h1', 'component') } }, - render: function() { - monitor.rendering(); + render: function () { + monitor.rendering() return h('div', - this.showComponent? this.innerModel: undefined, - h('button.refresh', {onclick: function () {}}, 'refresh'), - h('button.remove', {onclick: function () { model.showComponent = false; }}, 'remove') - ); + this.showComponent ? this.innerModel : undefined, + h('button.refresh', {onclick: function () {}}, 'refresh'), + h('button.remove', {onclick: function () { model.showComponent = false }}, 'remove') + ) } - }; + } - attach(model); + attach(model) - var expectedParent = div.firstChild; - var expectedElement = div.firstChild.firstChild; + var expectedParent = div.firstChild + var expectedElement = div.firstChild.firstChild return monitor.waitForRenderAfter(click('button.refresh')).then(function () { - return monitor.waitForRenderAfter(click('button.refresh')); + return monitor.waitForRenderAfter(click('button.refresh')) }).then(function () { - return monitor.waitForRenderAfter(click('button.remove')); + return monitor.waitForRenderAfter(click('button.remove')) }).then(function () { expect(events).to.eql([ { @@ -1273,13 +1272,13 @@ describe('hyperdom', function () { type: 'onremove', element: expectedElement } - ]); - }); - }); + ]) + }) + }) it('top level receives onadd, onupdate and onremove events after the DOM changes have been made', function () { - var events = []; - var monitor = renderMonitor(); + var events = [] + var monitor = renderMonitor() var model = { onadd: function (element) { @@ -1287,18 +1286,18 @@ describe('hyperdom', function () { type: 'onadd', parent: element.parentNode, element: element - }); + }) }, onupdate: function (element) { events.push({ type: 'onupdate', - element: element, - }); + element: element + }) }, render: function () { - monitor.rendering(); + monitor.rendering() return h('div', h('h1', 'component'), @@ -1307,13 +1306,13 @@ describe('hyperdom', function () { } } - attach(model); + attach(model) - var expectedParent = div; - var expectedElement = div.firstChild; + var expectedParent = div + var expectedElement = div.firstChild return monitor.waitForRenderAfter(click('button.refresh')).then(function () { - return monitor.waitForRenderAfter(click('button.refresh')); + return monitor.waitForRenderAfter(click('button.refresh')) }).then(function () { expect(events).to.eql([ { @@ -1329,117 +1328,117 @@ describe('hyperdom', function () { type: 'onupdate', element: expectedElement } - ]); - }); - }); + ]) + }) + }) describe('caching', function () { it('can update the component only when the renderKey changes', function () { - var innerRenders = 0; - var renders = 0; + var innerRenders = 0 + var renders = 0 var model = { innerModel: { cacheKey: 1, renderCacheKey: function () { - return this.cacheKey; + return this.cacheKey }, render: function () { - innerRenders++; - return h('button', {onclick: function () {}}, 'refresh'); + innerRenders++ + return h('button', {onclick: function () {}}, 'refresh') } }, - render: function() { - renders++; - return this.innerModel; + render: function () { + renders++ + return this.innerModel } - }; + } - attach(model); + attach(model) - expect(renders).to.equal(1); - expect(innerRenders).to.equal(1); + expect(renders).to.equal(1) + expect(innerRenders).to.equal(1) return click('button').then(function () { return retry(function () { - expect(renders, 'renders').to.equal(2); - expect(innerRenders, 'innerRenders').to.equal(1); - }); + expect(renders, 'renders').to.equal(2) + expect(innerRenders, 'innerRenders').to.equal(1) + }) }).then(function () { - model.innerModel.cacheKey++; - return click('button'); + model.innerModel.cacheKey++ + return click('button') }).then(function () { return retry(function () { - expect(renders, 'renders').to.equal(3); - expect(innerRenders, 'innerRenders').to.equal(2); - }); - }); - }); + expect(renders, 'renders').to.equal(3) + expect(innerRenders, 'innerRenders').to.equal(2) + }) + }) + }) it("doesn't cache when renderCacheKey returns undefined", function () { - var innerRenders = 0; - var renders = 0; + var innerRenders = 0 + var renders = 0 var model = { innerModel: { renderCacheKey: function () {}, render: function () { - innerRenders++; - return h('button', {onclick: function () {}}, 'refresh'); + innerRenders++ + return h('button', {onclick: function () {}}, 'refresh') } }, - render: function() { - renders++; - return this.innerModel; + render: function () { + renders++ + return this.innerModel } - }; + } - attach(model); + attach(model) - expect(renders).to.equal(1); - expect(innerRenders).to.equal(1); + expect(renders).to.equal(1) + expect(innerRenders).to.equal(1) return click('button').then(function () { return retry(function () { - expect(renders, 'renders').to.equal(2); - expect(innerRenders, 'innerRenders').to.equal(2); - }); + expect(renders, 'renders').to.equal(2) + expect(innerRenders, 'innerRenders').to.equal(2) + }) }).then(function () { - return click('button'); + return click('button') }).then(function () { return retry(function () { - expect(renders, 'renders').to.equal(3); - expect(innerRenders, 'innerRenders').to.equal(3); - }); - }); - }); - }); + expect(renders, 'renders').to.equal(3) + expect(innerRenders, 'innerRenders').to.equal(3) + }) + }) + }) + }) it('the component can refresh the view', function () { var model = { name: 'Njord', render: function () { - return h('h1', 'hi ' + this.name); + return h('h1', 'hi ' + this.name) } - }; + } - attach(model); + attach(model) - expect(find('h1').text()).to.equal('hi Njord'); + expect(find('h1').text()).to.equal('hi Njord') - model.name = 'Hayfa'; - model.refresh(); + model.name = 'Hayfa' + model.refresh() return retry(function () { - expect(find('h1').text()).to.equal('hi Hayfa'); - }); - }); + expect(find('h1').text()).to.equal('hi Hayfa') + }) + }) it('can refresh several components without refreshing the whole page', function () { var model = { @@ -1447,52 +1446,52 @@ describe('hyperdom', function () { model2: innerModel('model2', 'xxx'), render: function () { - return h('div', this.model1, this.model2); + return h('div', this.model1, this.model2) } - }; + } - function innerModel(class_, name) { + function innerModel (class_, name) { return { name: name, render: function () { - return h('h1' + '.' + class_, 'hi ' + this.name); + return h('h1' + '.' + class_, 'hi ' + this.name) } - }; + } } - attach(model); + attach(model) - expect(find('h1.model1').text()).to.equal('hi one'); - expect(find('h1.model2').text()).to.equal('hi xxx'); + expect(find('h1.model1').text()).to.equal('hi one') + expect(find('h1.model2').text()).to.equal('hi xxx') - model.model1.name = 'two'; - model.model2.name = 'yyy'; - model.model1.refreshComponent(); + model.model1.name = 'two' + model.model2.name = 'yyy' + model.model1.refreshComponent() return retry(function () { - expect(find('h1.model1').text()).to.equal('hi two'); - expect(find('h1.model2').text()).to.equal('hi xxx'); + expect(find('h1.model1').text()).to.equal('hi two') + expect(find('h1.model2').text()).to.equal('hi xxx') }).then(function () { - model.model2.refreshComponent(); + model.model2.refreshComponent() }).then(function () { return retry(function () { - expect(find('h1.model1').text()).to.equal('hi two'); - expect(find('h1.model2').text()).to.equal('hi yyy'); - }); + expect(find('h1.model1').text()).to.equal('hi two') + expect(find('h1.model2').text()).to.equal('hi yyy') + }) }).then(function () { - model.model1.name = 'three'; - model.model2.name = 'zzz'; + model.model1.name = 'three' + model.model2.name = 'zzz' - model.model1.refreshComponent(); - model.model2.refreshComponent(); + model.model1.refreshComponent() + model.model2.refreshComponent() return retry(function () { - expect(find('h1.model1').text()).to.equal('hi three'); - expect(find('h1.model2').text()).to.equal('hi zzz'); - }); - }); - }); + expect(find('h1.model1').text()).to.equal('hi three') + expect(find('h1.model2').text()).to.equal('hi zzz') + }) + }) + }) it('a component can be represented several times and be refreshed', function () { var model = { @@ -1502,93 +1501,93 @@ describe('hyperdom', function () { name: 'Jack', render: function () { - return h('li', this.name); + return h('li', this.name) } }, render: function () { - var self = this; + var self = this return h('ul', times(this.models, function () { - return self.innerModel; - })); + return self.innerModel + })) } - }; + } - attach(model); + attach(model) - expect(find('ul').text()).to.equal('Jack'); + expect(find('ul').text()).to.equal('Jack') - model.innerModel.name = 'Jill'; - model.innerModel.refreshComponent(); + model.innerModel.name = 'Jill' + model.innerModel.refreshComponent() return retry(function () { - expect(find('ul').text()).to.equal('Jill'); + expect(find('ul').text()).to.equal('Jill') }).then(function () { - model.models = 3; - model.refresh(); + model.models = 3 + model.refresh() }).then(function () { return retry(function () { - expect(find('ul').text()).to.equal('JillJillJill'); - }); + expect(find('ul').text()).to.equal('JillJillJill') + }) }).then(function () { - model.innerModel.name = 'Jacky'; - model.innerModel.refreshComponent(); + model.innerModel.name = 'Jacky' + model.innerModel.refreshComponent() return retry(function () { - expect(find('ul').text()).to.equal('JackyJackyJacky'); - }); + expect(find('ul').text()).to.equal('JackyJackyJacky') + }) }).then(function () { - model.models = 2; - model.refresh(); + model.models = 2 + model.refresh() }).then(function () { return retry(function () { - expect(find('ul').text()).to.equal('JackyJacky'); - }); + expect(find('ul').text()).to.equal('JackyJacky') + }) }).then(function () { - model.innerModel.name = 'Joel'; - model.innerModel.refreshComponent(); + model.innerModel.name = 'Joel' + model.innerModel.refreshComponent() return retry(function () { - expect(find('ul').text()).to.equal('JoelJoel'); - }); - }); - }); - }); + expect(find('ul').text()).to.equal('JoelJoel') + }) + }) + }) + }) describe('hyperdom.binding', function () { this.timeout(2000) var refreshCalled beforeEach(function () { - refreshCalled = false; + refreshCalled = false var mount = new Mount() runRender._currentRender = { mount: { refresh: function () { - refreshCalled = true; + refreshCalled = true }, requestRender: function (fn) { - fn(); + fn() }, - refreshify: function(fn, options) { + refreshify: function (fn, options) { return mount.refreshify.call(this, fn, options) } } - }; - }); + } + }) - function expectToRefresh(options, v) { - var model = {}; + function expectToRefresh (options, v) { + var model = {} - hyperdom.binding([model, 'field'], options).set('value'); - expect(refreshCalled).to.equal(v); + hyperdom.binding([model, 'field'], options).set('value') + expect(refreshCalled).to.equal(v) } - function expectPromiseToRefreshWithOptions(options, expectations) { + function expectPromiseToRefreshWithOptions (options, expectations) { var binding = hyperdom.binding({ set: function () { return wait(10) @@ -1598,15 +1597,15 @@ describe('hyperdom', function () { return expectPromiseToRefreshWithBinding(binding, expectations) } - function expectPromiseToRefreshWithBinding(binding, expectations) { - binding.set('value'); + function expectPromiseToRefreshWithBinding (binding, expectations) { + binding.set('value') - expect(refreshCalled).to.equal(expectations.immediately); - refreshCalled = false; + expect(refreshCalled).to.equal(expectations.immediately) + refreshCalled = false return wait(20).then(function () { - expect(refreshCalled).to.equal(expectations.afterPromise); - }); + expect(refreshCalled).to.equal(expectations.afterPromise) + }) } describe('setters', function () { @@ -1640,109 +1639,109 @@ describe('hyperdom', function () { context('normal', function () { it('normally calls refresh', function () { - expectToRefresh(undefined, true); - }); + expectToRefresh(undefined, true) + }) it('normally calls refresh, even after a promise', function () { - return expectPromiseToRefreshWithOptions(undefined, {immediately: true, afterPromise: true}); - }); - }); + return expectPromiseToRefreshWithOptions(undefined, {immediately: true, afterPromise: true}) + }) + }) context('component: old component', function () { it('calls refresh with the component', function () { var component = { canRefresh: true, refresh: function () { - this.wasRefreshed = true; + this.wasRefreshed = true } } - var model = {}; - hyperdom.binding([model, 'field'], {component: component}).set('value'); + var model = {} + hyperdom.binding([model, 'field'], {component: component}).set('value') - expect(component.wasRefreshed).to.be.true; - }); - }); + expect(component.wasRefreshed).to.be.true + }) + }) context('component: component', function () { it('calls refresh with the component', function () { var component = { refreshComponent: function () { - this.wasRefreshed = true; + this.wasRefreshed = true } } - var model = {}; - hyperdom.binding([model, 'field'], {component: component}).set('value'); + var model = {} + hyperdom.binding([model, 'field'], {component: component}).set('value') - expect(component.wasRefreshed).to.be.true; - }); - }); + expect(component.wasRefreshed).to.be.true + }) + }) context('norefresh: true', function () { it('never calls refresh', function () { - expectToRefresh({norefresh: true}, false); - }); + expectToRefresh({norefresh: true}, false) + }) it('never calls refresh, even after promise', function () { - return expectPromiseToRefreshWithOptions({norefresh: true}, {immediately: false, afterPromise: false}); - }); - }); + return expectPromiseToRefreshWithOptions({norefresh: true}, {immediately: false, afterPromise: false}) + }) + }) context('refresh: false', function () { it('never calls refresh', function () { - expectToRefresh({refresh: false}, false); - }); + expectToRefresh({refresh: false}, false) + }) it('never calls refresh, even after promise', function () { - return expectPromiseToRefreshWithOptions({refresh: false}, {immediately: false, afterPromise: false}); - }); - }); + return expectPromiseToRefreshWithOptions({refresh: false}, {immediately: false, afterPromise: false}) + }) + }) context("refresh: 'promise'", function () { it('never calls refresh', function () { - expectToRefresh({refresh: 'promise'}, false); - }); + expectToRefresh({refresh: 'promise'}, false) + }) it("doesn't call refresh, but does after a promise", function () { - return expectPromiseToRefreshWithOptions({refresh: 'promise'}, {immediately: false, afterPromise: true}); - }); - }); - }); + return expectPromiseToRefreshWithOptions({refresh: 'promise'}, {immediately: false, afterPromise: true}) + }) + }) + }) - describe('html.meta()', function() { - it('stores temporary state without updating the model', function() { + describe('html.meta()', function () { + it('stores temporary state without updating the model', function () { var integer = { - view: function(model) { - return (model || '').toString(); + view: function (model) { + return (model || '').toString() }, - model: function(view) { - if (!/^\d+$/.test(view)) { throw new Error('Must be an integer'); } - return Number(view); + model: function (view) { + if (!/^\d+$/.test(view)) { throw new Error('Must be an integer') } + return Number(view) } } - function render(model) { + function render (model) { return h('div', h('input.x', {binding: mapBinding(model, 'x', integer)}) - ); + ) } - var model = {}; - attach(render, model); + var model = {} + attach(render, model) return browser.find('input.x').typeIn('1').then(function () { return retry(function () { - expect(model.x).to.equal(1); - }); + expect(model.x).to.equal(1) + }) }).then(function () { - return browser.find('input.x').typeIn('x'); + return browser.find('input.x').typeIn('x') }).then(function () { - return retry(function() { - expect(hyperdom.html.meta(model, 'x').error.message).to.equal('Must be an integer'); - expect(model.x).to.equal(1); - }); - }); - }); - }); + return retry(function () { + expect(hyperdom.html.meta(model, 'x').error.message).to.equal('Must be an integer') + expect(model.x).to.equal(1) + }) + }) + }) + }) describe('components', function () { var events @@ -1758,12 +1757,12 @@ describe('hyperdom', function () { renderCacheKey = 'one' }) - function trimH1(innerHTML) { + function trimH1 (innerHTML) { return /

.*?<\/h1>/.exec(innerHTML)[0] } - function component(options) { - var render = typeof options == 'object' && options.hasOwnProperty('render')? options.render: undefined; + function component (options) { + var render = typeof options === 'object' && options.hasOwnProperty('render') ? options.render : undefined return { onbeforeadd: function () { @@ -1777,11 +1776,11 @@ describe('hyperdom', function () { }, onbeforerender: function (element) { - events.push(['onbeforerender', element? trimH1(element.innerHTML): null, this.lastState]) + events.push(['onbeforerender', element ? trimH1(element.innerHTML) : null, this.lastState]) }, onrender: function (element, oldElement) { - events.push(['onrender', trimH1(element.innerHTML), oldElement? trimH1(oldElement.innerHTML): null, this.lastState]) + events.push(['onrender', trimH1(element.innerHTML), oldElement ? trimH1(oldElement.innerHTML) : null, this.lastState]) }, onbeforeupdate: function (element) { @@ -1805,32 +1804,32 @@ describe('hyperdom', function () { }, render: function () { - return h('div', h('h1', 'element: ' + monitor.renderCount), render? render(): '') + return h('div', h('h1', 'element: ' + monitor.renderCount), render ? render() : '') } } } - function cachingComponent(render) { + function cachingComponent (render) { return { renderCacheKey: function () { - monitor.rendering(); + monitor.rendering() return renderCacheKey }, render: function () { return h('div', h('h1', 'element: ' + renderData), - render? render(): '' + render ? render() : '' ) } } } - function respondsToEvents(options) { - function elementHtml() { + function respondsToEvents (options) { + function elementHtml () { return '

element: ' + (monitor.renderCount - renderOffset) + '

' } - function oldElementHtml() { + function oldElementHtml () { return '

element: ' + (monitor.renderCount - renderOffset - 1) + '

' } @@ -1874,8 +1873,8 @@ describe('hyperdom', function () { } }) } - - function canCache() { + + function canCache () { expect(find('h1').text()).to.equal('element: one') renderData = 'two' @@ -1896,21 +1895,21 @@ describe('hyperdom', function () { innerModel: component(), - render: function() { - monitor.rendering(); + render: function () { + monitor.rendering() this.innerModel.data = monitor.renderCount return h('div', - this.show? this.innerModel: undefined, - h('button.add', {onclick: function () { model.show = true; }}, 'add'), - h('button.update', {onclick: function () {}}, 'update'), - h('button.remove', {onclick: function () { model.show = false; }}, 'remove') - ); + this.show ? this.innerModel : undefined, + h('button.add', {onclick: function () { model.show = true }}, 'add'), + h('button.update', {onclick: function () {}}, 'update'), + h('button.remove', {onclick: function () { model.show = false }}, 'remove') + ) } - }; + } - attach(model); + attach(model) return respondsToEvents() }) @@ -1919,7 +1918,7 @@ describe('hyperdom', function () { var app = { innerModel: cachingComponent(), - render: function() { + render: function () { return h('div', this.innerModel, h('button.update', {onclick: function () {}}, 'update') @@ -1937,15 +1936,15 @@ describe('hyperdom', function () { it('captures lifetime events', function () { var model = component({ render: function () { - monitor.rendering(); + monitor.rendering() return h('div', - h('button.add', {onclick: function () { model.show = true; }}, 'add'), - h('button.update', {onclick: function () {}}, 'update') - ); + h('button.add', {onclick: function () { model.show = true }}, 'add'), + h('button.update', {onclick: function () {}}, 'update') + ) } }) - attach(model); + attach(model) return respondsToEvents({remove: false}) }) @@ -1964,14 +1963,14 @@ describe('hyperdom', function () { context('view components', function () { it('captures lifetime events', function () { var app = { - render: function() { - monitor.rendering(); + render: function () { + monitor.rendering() return h('div', - this.show? - hyperdom.component(component()) + this.show + ? hyperdom.component(component()) : undefined, - h('button.add', {onclick: function () { app.show = true; }}, 'add'), - h('button.remove', {onclick: function () { app.show = false; }}, 'remove'), + h('button.add', {onclick: function () { app.show = true }}, 'add'), + h('button.remove', {onclick: function () { app.show = false }}, 'remove'), h('button.update', {onclick: function () {}}, 'update') ) } @@ -1984,7 +1983,7 @@ describe('hyperdom', function () { it('can cache', function () { var app = { - render: function() { + render: function () { return h('div', hyperdom.component(cachingComponent()), h('button.update', {onclick: function () {}}, 'update') @@ -2013,7 +2012,7 @@ describe('hyperdom', function () { } } - attach(outer); + attach(outer) expect(find('.outer')[0]._hyperdomMeta.component).to.eql(outer) expect(find('.inner')[0]._hyperdomMeta.component).to.eql(inner) @@ -2023,42 +2022,42 @@ describe('hyperdom', function () { describe('v1 compatibility', function () { describe('hyperdom.html.refresh', function () { it('refreshes the UI when called', function () { - function render(model) { - var refresh = h.refresh; + function render (model) { + var refresh = h.refresh return h('div', h('h1', model.text), h('button.refresh', { onclick: function () { setTimeout(function () { - model.text = 'after timeout'; - refresh(); - }, 50); + model.text = 'after timeout' + refresh() + }, 50) } }, 'refresh') - ); + ) } - attach(render, {text: 'before timeout'}); + attach(render, {text: 'before timeout'}) return click('button.refresh').then(function () { return wait(20).then(function () { return retry(function () { - expect(find('h1').text()).to.equal('before timeout'); + expect(find('h1').text()).to.equal('before timeout') }).then(function () { return retry(function () { - expect(find('h1').text()).to.equal('after timeout'); - }); - }); - }); - }); - }); + expect(find('h1').text()).to.equal('after timeout') + }) + }) + }) + }) + }) it('refreshes a component when called with that component', function () { - function render(model) { - var refresh = h.refresh; - var component = vdomComponent(function () { return h('h2', model.text); }); + function render (model) { + var refresh = h.refresh + var component = vdomComponent(function () { return h('h2', model.text) }) return h('div', h('h1', model.text), @@ -2066,115 +2065,115 @@ describe('hyperdom', function () { h('button.refresh', { onclick: function () { setTimeout(function () { - model.text = 'after timeout'; - refresh(component); - }, 50); + model.text = 'after timeout' + refresh(component) + }, 50) } }, 'refresh') - ); + ) } - attach(render, {text: 'before timeout'}); + attach(render, {text: 'before timeout'}) return click('button.refresh').then(function () { return wait(20).then(function () { return retry(function () { - expect(find('h1').text()).to.equal('before timeout'); - expect(find('h2').text()).to.equal('before timeout'); + expect(find('h1').text()).to.equal('before timeout') + expect(find('h2').text()).to.equal('before timeout') }).then(function () { return retry(function () { - expect(find('h1').text()).to.equal('before timeout'); - expect(find('h2').text()).to.equal('after timeout'); - }); - }); - }); - }); - }); + expect(find('h1').text()).to.equal('before timeout') + expect(find('h2').text()).to.equal('after timeout') + }) + }) + }) + }) + }) it('updates the component when refreshed', function () { - var monitor = renderMonitor(); - var updated = 0, rendered = 0; + var monitor = renderMonitor() + var updated = 0, rendered = 0 - function render(model) { - var refresh = h.refresh; - monitor.rendering(); + function render (model) { + var refresh = h.refresh + monitor.rendering() var component = vdomComponent( { cacheKey: true, onupdate: function () { - updated++; + updated++ } }, function () { - rendered++; - return h('h2', model.text); + rendered++ + return h('h2', model.text) } - ); + ) return h('div', component, h('button.refresh', { onclick: function () { monitor.waitForRender().then(function () { - refresh(component); - }); + refresh(component) + }) } }, 'refresh') - ); + ) } - attach(render, {text: 'before timeout'}); + attach(render, {text: 'before timeout'}) - expect(updated).to.equal(0); - expect(rendered).to.equal(1); + expect(updated).to.equal(0) + expect(rendered).to.equal(1) return click('button.refresh').then(function () { return retry(function () { - expect(updated).to.equal(1); - expect(rendered).to.equal(2); - }); - }); - }); + expect(updated).to.equal(1) + expect(rendered).to.equal(2) + }) + }) + }) it('refreshes whole page if passed a non-component', function () { - function render(model) { - var refresh = h.refresh; + function render (model) { + var refresh = h.refresh return h('div', h('h1', model.text), h('button.refresh', { onclick: function () { setTimeout(function () { - model.text = 'after timeout'; - refresh({}); - }, 50); + model.text = 'after timeout' + refresh({}) + }, 50) } }, 'refresh') - ); + ) } - attach(render, {text: 'before timeout'}); + attach(render, {text: 'before timeout'}) return click('button.refresh').then(function () { return wait(20).then(function () { return retry(function () { - expect(find('h1').text()).to.equal('before timeout'); + expect(find('h1').text()).to.equal('before timeout') }).then(function () { return retry(function () { - expect(find('h1').text()).to.equal('after timeout'); - }); - }); - }); - }); - }); + expect(find('h1').text()).to.equal('after timeout') + }) + }) + }) + }) + }) it('must be taken during render cycle, or exception is thrown', function () { - function render(model) { - var refresh = h.refresh; + function render (model) { + var refresh = h.refresh return h('div', h('h1', model.text), @@ -2182,136 +2181,136 @@ describe('hyperdom', function () { onclick: function () { setTimeout(function () { try { - model.text = 'after timeout'; - h.refresh(); + model.text = 'after timeout' + h.refresh() } catch (e) { - model.text = e.message; - refresh(); + model.text = e.message + refresh() } - }, 50); + }, 50) } }, 'refresh') - ); + ) } - attach(render, {text: 'before timeout'}); + attach(render, {text: 'before timeout'}) return click('button.refresh').then(function () { return wait(20).then(function () { return retry(function () { - expect(find('h1').text()).to.equal('before timeout'); + expect(find('h1').text()).to.equal('before timeout') }).then(function () { return retry(function () { - expect(find('h1').text()).to.include("hyperdom.html.refresh"); - }); - }); - }); - }); - }); - }); + expect(find('h1').text()).to.include('hyperdom.html.refresh') + }) + }) + }) + }) + }) + }) describe('hyperdom.html.window', function () { it('can add and remove event handlers on window', function () { - function render(model) { + function render (model) { return h('div', model.active ? windowEvents( - { - onclick: function () { - model.clicks++; - } + { + onclick: function () { + model.clicks++ } + } ) : undefined, model.active - ? h('button.disactivate', {onclick: function () { model.active = false; return false; }}, 'disactivate') - : h('button.activate', {onclick: function () { model.active = true; return false; }}, 'activate'), + ? h('button.disactivate', {onclick: function () { model.active = false; return false }}, 'disactivate') + : h('button.activate', {onclick: function () { model.active = true; return false }}, 'activate'), h('div.click', 'click here'), h('div.clicks', model.clicks) - ); + ) } - attach(render, {clicks: 0, active: false}); + attach(render, {clicks: 0, active: false}) return click('button.activate').then(function () { return retry(function () { - return expect(find('button.disactivate').length).to.equal(1); + return expect(find('button.disactivate').length).to.equal(1) }).then(function () { return click('div.click').then(function () { - return retry(function() { - expect(find('div.clicks').text()).to.equal('1'); + return retry(function () { + expect(find('div.clicks').text()).to.equal('1') }).then(function () { return click('button.disactivate').then(function () { return retry(function () { - expect(find('button.activate').length).to.equal(1); + expect(find('button.activate').length).to.equal(1) }).then(function () { return click('div.click').then(function () { wait(30).then(function () { - return retry(function() { - expect(find('div.clicks').text()).to.equal('1'); - }); - }); - }); - }); - }); - }); - }); - }); - }); - }); - }); + return retry(function () { + expect(find('div.clicks').text()).to.equal('1') + }) + }) + }) + }) + }) + }) + }) + }) + }) + }) + }) describe('hyperdom.html.component', function () { it('receives onadd, onupdate and onremove events after the DOM changes have been made', function () { - var events = []; - var componentState; - var monitor = renderMonitor(); + var events = [] + var componentState + var monitor = renderMonitor() - function render(model) { - monitor.rendering(); + function render (model) { + monitor.rendering() return h('div', model.showComponent ? vdomComponent({ - onadd: function (element) { - events.push({ - type: 'onadd', - parent: element.parentNode, - element: element - }); - componentState = this; - }, - onupdate: function (element) { - events.push({ - type: 'onupdate', - element: element, - state: this - }); - }, - onremove: function (element) { - events.push({ - type: 'onremove', - element: element, - state: this - }); - } - }, h('h1', 'component')) + onadd: function (element) { + events.push({ + type: 'onadd', + parent: element.parentNode, + element: element + }) + componentState = this + }, + onupdate: function (element) { + events.push({ + type: 'onupdate', + element: element, + state: this + }) + }, + onremove: function (element) { + events.push({ + type: 'onremove', + element: element, + state: this + }) + } + }, h('h1', 'component')) : undefined, - h('button.refresh', {onclick: function () {}}, 'refresh'), - h('button.remove', {onclick: function () { model.showComponent = false; }}, 'remove') - ); + h('button.refresh', {onclick: function () {}}, 'refresh'), + h('button.remove', {onclick: function () { model.showComponent = false }}, 'remove') + ) } - attach(render, {showComponent: true}); + attach(render, {showComponent: true}) - var expectedParent = div.firstChild; - var expectedElement = div.firstChild.firstChild; + var expectedParent = div.firstChild + var expectedElement = div.firstChild.firstChild return monitor.waitForRenderAfter(click('button.refresh')).then(function () { - return monitor.waitForRenderAfter(click('button.refresh')); + return monitor.waitForRenderAfter(click('button.refresh')) }).then(function () { - return monitor.waitForRenderAfter(click('button.remove')); + return monitor.waitForRenderAfter(click('button.remove')) }).then(function () { expect(events).to.eql([ { @@ -2334,12 +2333,12 @@ describe('hyperdom', function () { element: expectedElement, state: componentState } - ]); - }); - }); + ]) + }) + }) it('throws error if not given vdom', function () { - function render() { + function render () { return vdomComponent( { onadd: function () { @@ -2349,206 +2348,205 @@ describe('hyperdom', function () { ) } - expect(function () {attach(render);}).to.throw('expects a vdom argument'); - }); + expect(function () { attach(render) }).to.throw('expects a vdom argument') + }) it('can expose long-running state for components', function () { - function render() { + function render () { return vdomComponent( { onbeforeadd: function () { - this.counter = 2; + this.counter = 2 } }, function () { - var self = this; + var self = this return h('div', h('span.counter', this.counter), - h('button.add', {onclick: function () { self.counter++; }}, 'add') - ); + h('button.add', {onclick: function () { self.counter++ }}, 'add') + ) } - ); + ) } - attach(render, {counter: 0}); + attach(render, {counter: 0}) return retry(function () { - expect(find('span.counter').text()).to.equal('2'); + expect(find('span.counter').text()).to.equal('2') }).then(function () { - return click('button.add'); + return click('button.add') }).then(function () { return retry(function () { - expect(find('span.counter').text()).to.equal('3'); - }); + expect(find('span.counter').text()).to.equal('3') + }) }).then(function () { - return click('button.add'); + return click('button.add') }).then(function () { return retry(function () { - expect(find('span.counter').text()).to.equal('4'); - }); - }); - }); + expect(find('span.counter').text()).to.equal('4') + }) + }) + }) it('renders and updates the vdom inside the component', function () { - function render(model) { + function render (model) { return h('div', vdomComponent({ - }, + }, h('span.counter', model.counter) ), - h('button.add', {onclick: function () { model.counter++; }}, 'add') - ); + h('button.add', {onclick: function () { model.counter++ }}, 'add') + ) } - attach(render, {counter: 0}); + attach(render, {counter: 0}) return click('button.add').then(function () { return wait(30).then(function () { return retry(function () { - expect(find('span.counter').text()).to.equal('1'); + expect(find('span.counter').text()).to.equal('1') }).then(function () { return click('button.add').then(function () { return retry(function () { - expect(find('span.counter').text()).to.equal('2'); - }); - }); - }); - }); - }); - }); + expect(find('span.counter').text()).to.equal('2') + }) + }) + }) + }) + }) + }) it('only refreshes the component when returned from an event', function () { - function render(model) { - + function render (model) { return h('div', vdomComponent(function (component) { return h('div', h('span.inner-counter', model.counter), - h('button.add-inner', {onclick: function () { model.counter++; return component; }}, 'add inner') - ); + h('button.add-inner', {onclick: function () { model.counter++; return component }}, 'add inner') + ) }), h('span.outer-counter', model.counter), - h('button.add-outer', {onclick: function () { model.counter++; }}, 'add outer') - ); + h('button.add-outer', {onclick: function () { model.counter++ }}, 'add outer') + ) } - attach(render, {counter: 0}); + attach(render, {counter: 0}) - expect(find('span.inner-counter').text()).to.equal('0'); - expect(find('span.outer-counter').text()).to.equal('0'); + expect(find('span.inner-counter').text()).to.equal('0') + expect(find('span.outer-counter').text()).to.equal('0') return click('button.add-inner').then(function () { return retry(function () { - expect(find('span.inner-counter').text()).to.equal('1'); - expect(find('span.outer-counter').text()).to.equal('0'); - }); + expect(find('span.inner-counter').text()).to.equal('1') + expect(find('span.outer-counter').text()).to.equal('0') + }) }).then(function () { - return click('button.add-inner'); + return click('button.add-inner') }).then(function () { return retry(function () { - expect(find('span.inner-counter').text()).to.equal('2'); - expect(find('span.outer-counter').text()).to.equal('0'); - }); + expect(find('span.inner-counter').text()).to.equal('2') + expect(find('span.outer-counter').text()).to.equal('0') + }) }).then(function () { return click('button.add-outer').then(function () { return retry(function () { - expect(find('span.inner-counter').text()).to.equal('3'); - expect(find('span.outer-counter').text()).to.equal('3'); - }); - }); - }); - }); + expect(find('span.inner-counter').text()).to.equal('3') + expect(find('span.outer-counter').text()).to.equal('3') + }) + }) + }) + }) it('only refreshes array of the components when returned from an event', function () { - function render(model) { + function render (model) { var component1 = vdomComponent(function (component) { - return h('div', + return h('div', h('span.inner-counter', model.counter), - h('button.add-inner', {onclick: function () { model.counter++; return component; }}, 'add inner') - ); - }); + h('button.add-inner', {onclick: function () { model.counter++; return component }}, 'add inner') + ) + }) return h('div', component1, vdomComponent(function (component) { return h('div', h('span.inner-counter2', model.counter), - h('button.add-inner2', {onclick: function () { model.counter++; return [component, component1]; }}, 'add inner 2') - ); + h('button.add-inner2', {onclick: function () { model.counter++; return [component, component1] }}, 'add inner 2') + ) }), h('span.outer-counter', model.counter), - h('button.add-outer', {onclick: function () { model.counter++; }}, 'add outer') - ); + h('button.add-outer', {onclick: function () { model.counter++ }}, 'add outer') + ) } - attach(render, {counter: 0}); + attach(render, {counter: 0}) - expect(find('span.inner-counter').text()).to.equal('0'); - expect(find('span.inner-counter2').text()).to.equal('0'); - expect(find('span.outer-counter').text()).to.equal('0'); + expect(find('span.inner-counter').text()).to.equal('0') + expect(find('span.inner-counter2').text()).to.equal('0') + expect(find('span.outer-counter').text()).to.equal('0') return click('button.add-inner').then(function () { return retry(function () { - expect(find('span.inner-counter').text()).to.equal('1'); - expect(find('span.inner-counter2').text()).to.equal('0'); - expect(find('span.outer-counter').text()).to.equal('0'); - }); + expect(find('span.inner-counter').text()).to.equal('1') + expect(find('span.inner-counter2').text()).to.equal('0') + expect(find('span.outer-counter').text()).to.equal('0') + }) }).then(function () { - return click('button.add-inner2'); + return click('button.add-inner2') }).then(function () { return retry(function () { - expect(find('span.inner-counter').text()).to.equal('2'); - expect(find('span.inner-counter2').text()).to.equal('2'); - expect(find('span.outer-counter').text()).to.equal('0'); - }); + expect(find('span.inner-counter').text()).to.equal('2') + expect(find('span.inner-counter2').text()).to.equal('2') + expect(find('span.outer-counter').text()).to.equal('0') + }) }).then(function () { return click('button.add-outer').then(function () { return retry(function () { - expect(find('span.inner-counter').text()).to.equal('3'); - expect(find('span.inner-counter2').text()).to.equal('3'); - expect(find('span.outer-counter').text()).to.equal('3'); - }); - }); - }); - }); + expect(find('span.inner-counter').text()).to.equal('3') + expect(find('span.inner-counter2').text()).to.equal('3') + expect(find('span.outer-counter').text()).to.equal('3') + }) + }) + }) + }) it('throws exception when component is returned from event but does not have a render function', function () { - function render(model) { - var component = vdomComponent(h('span.inner-counter', model.counter)); + function render (model) { + var component = vdomComponent(h('span.inner-counter', model.counter)) return h('div', component, - h('button', { onclick: function () { return component; } }, 'refresh component') - ); + h('button', { onclick: function () { return component } }, 'refresh component') + ) } - attach(render, {}); + attach(render, {}) - return click('button').then(undefined, function(error) { - expect(error.message).to.contain('refresh'); - }); - }); + return click('button').then(undefined, function (error) { + expect(error.message).to.contain('refresh') + }) + }) it('can refresh the component when returned from an event, and handle lifetime events', function () { - var events = []; - var refreshCount = 0; + var events = [] + var refreshCount = 0 - function render(model) { - refreshCount++; + function render (model) { + refreshCount++ return h('div', model.show ? vdomComponent( vdomComponent( { onadd: function () { - events.push('add'); + events.push('add') }, onupdate: function () { - events.push('update'); + events.push('update') }, onremove: function () { - events.push('remove'); + events.push('remove') } }, function () { @@ -2559,21 +2557,21 @@ describe('hyperdom', function () { : undefined, h('button.refresh', {onclick: function () {}}, 'refresh'), h('label', 'show', h('input.show', {type: 'checkbox', binding: [model, 'show']})) - ); + ) } var waitForRefresh = (function () { - var oldRefreshCount = 1; + var oldRefreshCount = 1 return function () { return retry(function () { - expect(refreshCount).to.equal(oldRefreshCount + 1); + expect(refreshCount).to.equal(oldRefreshCount + 1) }).then(function () { - oldRefreshCount = refreshCount; - }); - }; - })(); + oldRefreshCount = refreshCount + }) + } + })() - attach(render, {}); + attach(render, {}) return click('input.show').then(function () { return waitForRefresh().then(function () { @@ -2588,23 +2586,23 @@ describe('hyperdom', function () { 'update', 'update', 'remove' - ]); - }); - }); - }); - }); - }); - }); - }); - }); - }); + ]) + }) + }) + }) + }) + }) + }) + }) + }) + }) it('can capture fields from each refresh', function () { - var events = []; + var events = [] - function render(model) { - model.value++; - var refresh = h.refresh; + function render (model) { + model.value++ + var refresh = h.refresh return h('div', vdomComponent( @@ -2612,88 +2610,88 @@ describe('hyperdom', function () { value: model.value, onadd: function (element) { - var self = this; + var self = this element.addEventListener('click', function () { - events.push(self.value); - refresh(); - }); + events.push(self.value) + refresh() + }) } }, h('.button-' + model.value, 'click me') ) - ); + ) } - attach(render, {value: 0}); + attach(render, {value: 0}) return click('.button-1').then(function () { - expect(events).to.eql([1]); + expect(events).to.eql([1]) }).then(function () { return click('.button-2').then(function () { - expect(events).to.eql([1, 2]); - }); - }); - }); + expect(events).to.eql([1, 2]) + }) + }) + }) it('can update the component only when the cacheKey changes', function () { - var updates = 0; - var componentRenders = 0; - var renders = 0; + var updates = 0 + var componentRenders = 0 + var renders = 0 - function render() { - renders++; + function render () { + renders++ return vdomComponent( { cacheKey: model.cacheKey, onupdate: function () { - updates++; + updates++ } }, function () { - componentRenders++; - return h('button', {onclick: function () {}}, 'refresh'); + componentRenders++ + return h('button', {onclick: function () {}}, 'refresh') } - ); + ) } var model = { cacheKey: 1 - }; + } - attach(render, model); + attach(render, model) - expect(renders).to.equal(1); - expect(componentRenders).to.equal(1); - expect(updates).to.equal(0); + expect(renders).to.equal(1) + expect(componentRenders).to.equal(1) + expect(updates).to.equal(0) return click('button').then(function () { return retry(function () { - expect(renders).to.equal(2); - expect(componentRenders).to.equal(1); - expect(updates).to.equal(0); - }); + expect(renders).to.equal(2) + expect(componentRenders).to.equal(1) + expect(updates).to.equal(0) + }) }).then(function () { - model.cacheKey++; - return click('button'); + model.cacheKey++ + return click('button') }).then(function () { return retry(function () { - expect(renders).to.equal(3); - expect(componentRenders).to.equal(2); - expect(updates).to.equal(1); - }); - }); - }); + expect(renders).to.equal(3) + expect(componentRenders).to.equal(2) + expect(updates).to.equal(1) + }) + }) + }) it('can wrap event handlers inside the component', function () { - var events = []; + var events = [] - function render() { + function render () { return h('div', vdomComponent( { on: function (type, handler) { - return function() { - events.push('component ' + type); - return handler.apply(this, arguments); + return function () { + events.push('component ' + type) + return handler.apply(this, arguments) } } }, @@ -2702,70 +2700,70 @@ describe('hyperdom', function () { vdomComponent( { on: function (type, handler) { - return function() { - events.push('inner component ' + type); - return handler.apply(this, arguments); + return function () { + events.push('inner component ' + type) + return handler.apply(this, arguments) } } }, function () { - return h('button.inner-inner-component', {onclick: function () { events.push('inner inner click'); }}, 'click me'); + return h('button.inner-inner-component', {onclick: function () { events.push('inner inner click') }}, 'click me') } ), - h('button.inner-component', {onclick: function () { events.push('inner click'); }}, 'click me') - ); + h('button.inner-component', {onclick: function () { events.push('inner click') }}, 'click me') + ) } ), - h('button.outer-component', {onclick: function () { events.push('outer click'); }}, 'click me') - ); + h('button.outer-component', {onclick: function () { events.push('outer click') }}, 'click me') + ) } - attach(render); + attach(render) return click('button.inner-component').then(function () { - expect(events).to.eql(['component click', 'inner click']); + expect(events).to.eql(['component click', 'inner click']) }).then(function () { return click('button.inner-inner-component').then(function () { - expect(events).to.eql(['component click', 'inner click', 'inner component click', 'inner inner click']); - }); + expect(events).to.eql(['component click', 'inner click', 'inner component click', 'inner inner click']) + }) }).then(function () { return click('button.outer-component').then(function () { - expect(events).to.eql(['component click', 'inner click', 'inner component click', 'inner inner click', 'outer click']); - }); - }); - }); - }); + expect(events).to.eql(['component click', 'inner click', 'inner component click', 'inner inner click', 'outer click']) + }) + }) + }) + }) describe('hyperdom.html.refreshAfter', function () { it('refreshes after the promise is complete', function () { var waiting - function load(model) { + function load (model) { return waiting ? undefined : waiting = wait(20).then(function () { - model.text = 'loaded'; + model.text = 'loaded' }) } - function render(model) { - hyperdom.html.refreshAfter(load(model)); + function render (model) { + hyperdom.html.refreshAfter(load(model)) - return h('div', model.text); + return h('div', model.text) } - attach(render, {text: 'loading'}); + attach(render, {text: 'loading'}) return retry(function () { - expect(find('div').text()).to.equal('loaded'); - }); - }); - }); - }); -}); - -function wait(n) { + expect(find('div').text()).to.equal('loaded') + }) + }) + }) + }) +}) + +function wait (n) { return new Promise(function (result) { - setTimeout(result, n); - }); + setTimeout(result, n) + }) } diff --git a/test/browser/mountHyperdom.js b/test/browser/mountHyperdom.js index 9b09623..971b9eb 100644 --- a/test/browser/mountHyperdom.js +++ b/test/browser/mountHyperdom.js @@ -3,15 +3,15 @@ var browserMonkey = require('browser-monkey') var extend = require('lowscore/extend') var div -function createTestDiv() { +function createTestDiv () { if (div && div.parentNode) { - div.parentNode.removeChild(div); + div.parentNode.removeChild(div) } div = window.document.createElement('div') window.document.body.appendChild(div) - return div; + return div } module.exports = function (app, options) { @@ -19,6 +19,6 @@ module.exports = function (app, options) { if (options && (options.hash || options.url) && options.router) { options.router.push(options.url || options.hash) } - hyperdom.append(testDiv, app, extend({ requestRender: setTimeout }, options)); - return browserMonkey.scope(testDiv); + hyperdom.append(testDiv, app, extend({ requestRender: setTimeout }, options)) + return browserMonkey.scope(testDiv) } diff --git a/test/browser/promisePolyfill.js b/test/browser/promisePolyfill.js index b944315..fdba81e 100644 --- a/test/browser/promisePolyfill.js +++ b/test/browser/promisePolyfill.js @@ -1,11 +1,10 @@ -(function(global){ - +(function (global) { // // Check for native Promise and it has correct interface // -var NativePromise = global['Promise']; -var nativePromiseSupported = + var NativePromise = global['Promise'] + var nativePromiseSupported = NativePromise && // Some of these methods are missing from // Firefox/Chrome experimental implementations @@ -15,312 +14,268 @@ var nativePromiseSupported = 'race' in NativePromise && // Older version of the spec had a resolver object // as the arg rather than a function - (function(){ - var resolve; - new NativePromise(function(r){ resolve = r; }); - return typeof resolve === 'function'; - })(); - + (function () { + var resolve + new NativePromise(function (r) { resolve = r }) + return typeof resolve === 'function' + })() // // export if necessary // -if (typeof exports !== 'undefined' && exports) -{ + if (typeof exports !== 'undefined' && exports) { // node.js - exports.Promise = Promise || NativePromise; -} -else -{ + exports.Promise = Promise || NativePromise + } else { // in browser add to global - if (!nativePromiseSupported) - global['Promise'] = Promise; -} - + if (!nativePromiseSupported) { global['Promise'] = Promise } + } // // Polyfill // -var PENDING = 'pending'; -var SEALED = 'sealed'; -var FULFILLED = 'fulfilled'; -var REJECTED = 'rejected'; -var NOOP = function(){}; + var PENDING = 'pending' + var SEALED = 'sealed' + var FULFILLED = 'fulfilled' + var REJECTED = 'rejected' + var NOOP = function () {} // async calls -var asyncSetTimer = typeof setImmediate !== 'undefined' ? setImmediate : setTimeout; -var asyncQueue = []; -var asyncTimer; + var asyncSetTimer = typeof setImmediate !== 'undefined' ? setImmediate : setTimeout + var asyncQueue = [] + var asyncTimer -function asyncFlush(){ + function asyncFlush () { // run promise callbacks - for (var i = 0; i < asyncQueue.length; i++) - asyncQueue[i][0](asyncQueue[i][1]); + for (var i = 0; i < asyncQueue.length; i++) { asyncQueue[i][0](asyncQueue[i][1]) } // reset async asyncQueue - asyncQueue = []; - asyncTimer = false; -} - -function asyncCall(callback, arg){ - asyncQueue.push([callback, arg]); - - if (!asyncTimer) - { - asyncTimer = true; - asyncSetTimer(asyncFlush, 0); + asyncQueue = [] + asyncTimer = false } -} + function asyncCall (callback, arg) { + asyncQueue.push([callback, arg]) -function invokeResolver(resolver, promise) { - function resolvePromise(value) { - resolve(promise, value); + if (!asyncTimer) { + asyncTimer = true + asyncSetTimer(asyncFlush, 0) + } } - function rejectPromise(reason) { - reject(promise, reason); - } + function invokeResolver (resolver, promise) { + function resolvePromise (value) { + resolve(promise, value) + } + + function rejectPromise (reason) { + reject(promise, reason) + } - try { - resolver(resolvePromise, rejectPromise); - } catch(e) { - rejectPromise(e); - } -} - -function invokeCallback(subscriber){ - var owner = subscriber.owner; - var settled = owner.state_; - var value = owner.data_; - var callback = subscriber[settled]; - var promise = subscriber.then; - - if (typeof callback === 'function') - { - settled = FULFILLED; try { - value = callback(value); - } catch(e) { - reject(promise, e); + resolver(resolvePromise, rejectPromise) + } catch (e) { + rejectPromise(e) } } - if (!handleThenable(promise, value)) - { - if (settled === FULFILLED) - resolve(promise, value); + function invokeCallback (subscriber) { + var owner = subscriber.owner + var settled = owner.state_ + var value = owner.data_ + var callback = subscriber[settled] + var promise = subscriber.then + + if (typeof callback === 'function') { + settled = FULFILLED + try { + value = callback(value) + } catch (e) { + reject(promise, e) + } + } + + if (!handleThenable(promise, value)) { + if (settled === FULFILLED) { resolve(promise, value) } - if (settled === REJECTED) - reject(promise, value); + if (settled === REJECTED) { reject(promise, value) } + } } -} - -function handleThenable(promise, value) { - var resolved; - - try { - if (promise === value) - throw new TypeError('A promises callback cannot return that same promise.'); - - if (value && (typeof value === 'function' || typeof value === 'object')) - { - var then = value.then; // then should be retrived only once - - if (typeof then === 'function') - { - then.call(value, function(val){ - if (!resolved) - { - resolved = true; - - if (value !== val) - resolve(promise, val); - else - fulfill(promise, val); - } - }, function(reason){ - if (!resolved) - { - resolved = true; - - reject(promise, reason); - } - }); - - return true; + + function handleThenable (promise, value) { + var resolved + + try { + if (promise === value) { throw new TypeError('A promises callback cannot return that same promise.') } + + if (value && (typeof value === 'function' || typeof value === 'object')) { + var then = value.then // then should be retrived only once + + if (typeof then === 'function') { + then.call(value, function (val) { + if (!resolved) { + resolved = true + + if (value !== val) { resolve(promise, val) } else { fulfill(promise, val) } + } + }, function (reason) { + if (!resolved) { + resolved = true + + reject(promise, reason) + } + }) + + return true + } } + } catch (e) { + if (!resolved) { reject(promise, e) } + + return true } - } catch (e) { - if (!resolved) - reject(promise, e); - return true; + return false } - return false; -} - -function resolve(promise, value){ - if (promise === value || !handleThenable(promise, value)) - fulfill(promise, value); -} + function resolve (promise, value) { + if (promise === value || !handleThenable(promise, value)) { fulfill(promise, value) } + } -function fulfill(promise, value){ - if (promise.state_ === PENDING) - { - promise.state_ = SEALED; - promise.data_ = value; + function fulfill (promise, value) { + if (promise.state_ === PENDING) { + promise.state_ = SEALED + promise.data_ = value - asyncCall(publishFulfillment, promise); + asyncCall(publishFulfillment, promise) + } } -} -function reject(promise, reason){ - if (promise.state_ === PENDING) - { - promise.state_ = SEALED; - promise.data_ = reason; + function reject (promise, reason) { + if (promise.state_ === PENDING) { + promise.state_ = SEALED + promise.data_ = reason - asyncCall(publishRejection, promise); + asyncCall(publishRejection, promise) + } } -} -function publish(promise) { - promise.then_ = promise.then_.forEach(invokeCallback); -} + function publish (promise) { + promise.then_ = promise.then_.forEach(invokeCallback) + } -function publishFulfillment(promise){ - promise.state_ = FULFILLED; - publish(promise); -} + function publishFulfillment (promise) { + promise.state_ = FULFILLED + publish(promise) + } -function publishRejection(promise){ - promise.state_ = REJECTED; - publish(promise); -} + function publishRejection (promise) { + promise.state_ = REJECTED + publish(promise) + } /** * @class */ -function Promise(resolver){ - if (typeof resolver !== 'function') - throw new TypeError('Promise constructor takes a function argument'); + function Promise (resolver) { + if (typeof resolver !== 'function') { throw new TypeError('Promise constructor takes a function argument') } - if (this instanceof Promise === false) - throw new TypeError('Failed to construct \'Promise\': Please use the \'new\' operator, this object constructor cannot be called as a function.'); + if (this instanceof Promise === false) { throw new TypeError('Failed to construct \'Promise\': Please use the \'new\' operator, this object constructor cannot be called as a function.') } - this.then_ = []; + this.then_ = [] - invokeResolver(resolver, this); -} + invokeResolver(resolver, this) + } -Promise.prototype = { - constructor: Promise, + Promise.prototype = { + constructor: Promise, - state_: PENDING, - then_: null, - data_: undefined, + state_: PENDING, + then_: null, + data_: undefined, - then: function(onFulfillment, onRejection){ - var subscriber = { - owner: this, - then: new this.constructor(NOOP), - fulfilled: onFulfillment, - rejected: onRejection - }; + then: function (onFulfillment, onRejection) { + var subscriber = { + owner: this, + then: new this.constructor(NOOP), + fulfilled: onFulfillment, + rejected: onRejection + } - if (this.state_ === FULFILLED || this.state_ === REJECTED) - { + if (this.state_ === FULFILLED || this.state_ === REJECTED) { // already resolved, call callback async - asyncCall(invokeCallback, subscriber); - } - else - { + asyncCall(invokeCallback, subscriber) + } else { // subscribe - this.then_.push(subscriber); - } + this.then_.push(subscriber) + } - return subscriber.then; - }, + return subscriber.then + }, - 'catch': function(onRejection) { - return this.then(null, onRejection); + 'catch': function (onRejection) { + return this.then(null, onRejection) + } } -}; - -Promise.all = function(promises){ - var Class = this; - if (!Array.isArray(promises)) - throw new TypeError('You must pass an array to Promise.all().'); + Promise.all = function (promises) { + var Class = this - return new Class(function(resolve, reject){ - var results = []; - var remaining = 0; + if (!Array.isArray(promises)) { throw new TypeError('You must pass an array to Promise.all().') } - function resolver(index){ - remaining++; - return function(value){ - results[index] = value; - if (!--remaining) - resolve(results); - }; - } + return new Class(function (resolve, reject) { + var results = [] + var remaining = 0 - for (var i = 0, promise; i < promises.length; i++) - { - promise = promises[i]; + function resolver (index) { + remaining++ + return function (value) { + results[index] = value + if (!--remaining) { resolve(results) } + } + } - if (promise && typeof promise.then === 'function') - promise.then(resolver(i), reject); - else - results[i] = promise; - } + for (var i = 0, promise; i < promises.length; i++) { + promise = promises[i] - if (!remaining) - resolve(results); - }); -}; + if (promise && typeof promise.then === 'function') { promise.then(resolver(i), reject) } else { results[i] = promise } + } -Promise.race = function(promises){ - var Class = this; + if (!remaining) { resolve(results) } + }) + } - if (!Array.isArray(promises)) - throw new TypeError('You must pass an array to Promise.race().'); + Promise.race = function (promises) { + var Class = this - return new Class(function(resolve, reject) { - for (var i = 0, promise; i < promises.length; i++) - { - promise = promises[i]; + if (!Array.isArray(promises)) { throw new TypeError('You must pass an array to Promise.race().') } - if (promise && typeof promise.then === 'function') - promise.then(resolve, reject); - else - resolve(promise); - } - }); -}; + return new Class(function (resolve, reject) { + for (var i = 0, promise; i < promises.length; i++) { + promise = promises[i] -Promise.resolve = function(value){ - var Class = this; + if (promise && typeof promise.then === 'function') { promise.then(resolve, reject) } else { resolve(promise) } + } + }) + } - if (value && typeof value === 'object' && value.constructor === Class) - return value; + Promise.resolve = function (value) { + var Class = this - return new Class(function(resolve){ - resolve(value); - }); -}; + if (value && typeof value === 'object' && value.constructor === Class) { return value } -Promise.reject = function(reason){ - var Class = this; + return new Class(function (resolve) { + resolve(value) + }) + } - return new Class(function(resolve, reject){ - reject(reason); - }); -}; + Promise.reject = function (reason) { + var Class = this -})(new Function('return this')()); + return new Class(function (resolve, reject) { + reject(reason) + }) + } +})(new Function('return this')()) diff --git a/test/browser/routerSpec.js b/test/browser/routerSpec.js index 3ce8748..b6bbd94 100644 --- a/test/browser/routerSpec.js +++ b/test/browser/routerSpec.js @@ -11,11 +11,11 @@ if (detect.pushState) { describeRouter('pushState') } -function describeRouter(historyApi) { +function describeRouter (historyApi) { describe('router (' + historyApi + ')', function () { var router - function mount(app, url) { + function mount (app, url) { var options = {router: router} if (historyApi == 'hash') { @@ -27,7 +27,7 @@ function describeRouter(historyApi) { return mountHyperdom(app, options) } - function resetRouter() { + function resetRouter () { if (router) { router.reset() } @@ -38,7 +38,7 @@ function describeRouter(historyApi) { } } - function push(route, params) { + function push (route, params) { if (history == 'hash') { return new Promise(function (resolve) { var oldURL = window.location.href @@ -125,9 +125,9 @@ function describeRouter(historyApi) { } }) - function articleComponent() { + function articleComponent () { return { - load: function(id) { + load: function (id) { var self = this this.id = id @@ -139,7 +139,7 @@ function describeRouter(historyApi) { }) }, - render: function() { + render: function () { if (this.article) { return h('article', this.article) } else { @@ -149,7 +149,7 @@ function describeRouter(historyApi) { } } - function loadsArticle(monkey, article, id) { + function loadsArticle (monkey, article, id) { return monkey.find('div.loading').shouldHave({text: 'loading article ' + id}).then(function () { article.resolve() return monkey.find('article').shouldHave({text: 'this is article ' + id}) @@ -236,7 +236,7 @@ function describeRouter(historyApi) { }), route({ bindings: { - a: [this, 'a'], + a: [this, 'a'] }, push: push, @@ -303,7 +303,7 @@ function describeRouter(historyApi) { beforeEach(function () { pushResult = false - push = function(_oldParams, _newParams) { + push = function (_oldParams, _newParams) { oldParams = _oldParams newParams = _newParams return pushResult @@ -361,7 +361,7 @@ function describeRouter(historyApi) { return [ route({ - onload: function(params) { + onload: function (params) { return self.article.load(params.id) }, @@ -487,7 +487,7 @@ function describeRouter(historyApi) { events = [] - function aComponent(a) { + function aComponent (a) { return { a: a, diff --git a/test/server/detachedRenderingSpec.js b/test/server/detachedRenderingSpec.js index 79d89cc..e3d66d7 100644 --- a/test/server/detachedRenderingSpec.js +++ b/test/server/detachedRenderingSpec.js @@ -1,35 +1,31 @@ -var hyperdom = require('../..'); -var h = hyperdom.html; +var hyperdom = require('../..') +var h = hyperdom.html -var vdomToHtml = require('vdom-to-html'); -var expect = require('chai').expect; -var hyperdomComponent = require('../../componentWidget'); +var vdomToHtml = require('vdom-to-html') +var expect = require('chai').expect +var hyperdomComponent = require('../../componentWidget') -describe('hyperdom', function() { - - describe('.html(), detached from a real DOM', function() { - - it('creates a virtual dom with event handlers', function() { - var model = { counter: 0 }; +describe('hyperdom', function () { + describe('.html(), detached from a real DOM', function () { + it('creates a virtual dom with event handlers', function () { + var model = { counter: 0 } var vdom = h('.outer', h('.inner', { - onclick: function() { - model.counter++; + onclick: function () { + model.counter++ } }), hyperdomComponent(function () { - return h('.component'); + return h('.component') }), h.rawHtml('div', 'some raw HTML') - ); - var html = vdomToHtml(vdom); - expect(html).to.equal('
some raw HTML
'); - vdom.children[0].properties.onclick.handler(); - expect(model.counter).to.equal(1); - vdom.children[0].properties.onclick.handler(); - expect(model.counter).to.equal(2); - }); - - }); - -}); + ) + var html = vdomToHtml(vdom) + expect(html).to.equal('
some raw HTML
') + vdom.children[0].properties.onclick.handler() + expect(model.counter).to.equal(1) + vdom.children[0].properties.onclick.handler() + expect(model.counter).to.equal(2) + }) + }) +}) diff --git a/test/server/jsdomSpec.js b/test/server/jsdomSpec.js index 115d42a..7cb820c 100644 --- a/test/server/jsdomSpec.js +++ b/test/server/jsdomSpec.js @@ -1,34 +1,30 @@ -var hyperdom = require('../..'); -var jsdom = require('jsdom'); -var expect = require('chai').expect; +var hyperdom = require('../..') +var jsdom = require('jsdom') +var expect = require('chai').expect -describe('hyperdom', function() { - - describe('.append()', function() { - - it('renders elements in jsdom', function(done) { +describe('hyperdom', function () { + describe('.append()', function () { + it('renders elements in jsdom', function (done) { jsdom.env( '', [], function (errors, window) { - var render = function(model) { - return hyperdom.html('p', 'hello'); + var render = function (model) { + return hyperdom.html('p', 'hello') } - function requestRender(render) { - render(); + function requestRender (render) { + render() } hyperdom.append(window.document.body, render, {}, { window: window, document: window.document, requestRender: requestRender - }); - expect(window.document.body.childNodes[0].tagName).to.equal('P'); - done(); + }) + expect(window.document.body.childNodes[0].tagName).to.equal('P') + done() } - ); - }); - - }); - -}); + ) + }) + }) +}) diff --git a/test/server/storeCacheSpec.js b/test/server/storeCacheSpec.js index 135dd60..3c89138 100644 --- a/test/server/storeCacheSpec.js +++ b/test/server/storeCacheSpec.js @@ -2,7 +2,7 @@ var serverRenderCache = require('../../serverRenderCache') var StoreCache = require('../../storeCache') var render = require('../../render') var expect = require('chai').expect -var refreshify = require('../../render').refreshify; +var refreshify = require('../../render').refreshify describe('store cache', function () { var storeCache @@ -24,14 +24,14 @@ describe('store cache', function () { render._currentRender = oldCurrentRender }) - function load(data) { + function load (data) { return wait(10).then(() => data) } - function wait(n) { + function wait (n) { return new Promise((resolve) => { setTimeout(resolve, 10) - }); + }) } it('can store data loaded', function () { @@ -54,7 +54,7 @@ describe('store cache', function () { expect(setData1).to.equal('some data') expect(setData2).to.equal('some data') }) - }); + }) it("can store data even if promise isn't returned", function () { var setData @@ -70,5 +70,5 @@ describe('store cache', function () { expect(storeCache.data).to.eql({key: 'some data'}) expect(setData).to.equal('some data') }) - }); -}); + }) +}) diff --git a/toHtml.js b/toHtml.js index 086273b..697eaf9 100644 --- a/toHtml.js +++ b/toHtml.js @@ -1,7 +1,7 @@ var vdomToHtml = require('vdom-to-html') var toVdom = require('./toVdom') -module.exports = function(_vdom) { +module.exports = function (_vdom) { var vdom = toVdom(_vdom) return vdomToHtml(vdom) } diff --git a/toVdom.js b/toVdom.js index 7ac0c84..d41f468 100644 --- a/toVdom.js +++ b/toVdom.js @@ -1,39 +1,39 @@ -var vtext = require("virtual-dom/vnode/vtext.js") -var isVdom = require('./isVdom'); +var vtext = require('virtual-dom/vnode/vtext.js') +var isVdom = require('./isVdom') var Component = require('./component') -function toVdom(object) { +function toVdom (object) { if (object === undefined || object === null) { - return new vtext(''); - } else if (typeof(object) != 'object') { - return new vtext(String(object)); + return new vtext('') + } else if (typeof (object) !== 'object') { + return new vtext(String(object)) } else if (object instanceof Date) { - return new vtext(String(object)); + return new vtext(String(object)) } else if (object instanceof Error) { - return new vtext(object.toString()); + return new vtext(object.toString()) } else if (isVdom(object)) { - return object; + return object } else if (typeof object.render === 'function') { - return new Component(object); + return new Component(object) } else { - return new vtext(JSON.stringify(object)); + return new vtext(JSON.stringify(object)) } } -module.exports = toVdom; +module.exports = toVdom -function addChild(children, child) { +function addChild (children, child) { if (child instanceof Array) { for (var n = 0; n < child.length; n++) { - addChild(children, child[n]); + addChild(children, child[n]) } } else { - children.push(toVdom(child)); + children.push(toVdom(child)) } } module.exports.recursive = function (child) { - var children = []; - addChild(children, child); - return children; -}; + var children = [] + addChild(children, child) + return children +} diff --git a/vhtml.js b/vhtml.js index 4d0cf56..17a50b7 100644 --- a/vhtml.js +++ b/vhtml.js @@ -1,26 +1,26 @@ -'use strict'; +'use strict' -var VNode = require('virtual-dom/vnode/vnode.js'); -var isHook = require('virtual-dom/vnode/is-vhook'); +var VNode = require('virtual-dom/vnode/vnode.js') +var isHook = require('virtual-dom/vnode/is-vhook') var xml = require('./xml') -var softSetHook = require('virtual-dom/virtual-hyperscript/hooks/soft-set-hook.js'); +var softSetHook = require('virtual-dom/virtual-hyperscript/hooks/soft-set-hook.js') -module.exports = h; +module.exports = h -function h(tagName, props, children) { - var tag = tagName; +function h (tagName, props, children) { + var tag = tagName // support keys if (props.hasOwnProperty('key')) { - var key = props.key; - props.key = undefined; + var key = props.key + props.key = undefined } // support namespace if (props.hasOwnProperty('namespace')) { - var namespace = props.namespace; - props.namespace = undefined; + var namespace = props.namespace + props.namespace = undefined } // fix cursor bug @@ -30,10 +30,10 @@ function h(tagName, props, children) { props.value !== undefined && !isHook(props.value) ) { - props.value = softSetHook(props.value); + props.value = softSetHook(props.value) } - var vnode = new VNode(tag, props, children, key, namespace); + var vnode = new VNode(tag, props, children, key, namespace) if (props.xmlns) { xml.transform(vnode) diff --git a/windowEvents.js b/windowEvents.js index 242ab5e..b33c5a7 100644 --- a/windowEvents.js +++ b/windowEvents.js @@ -1,78 +1,78 @@ -var domComponent = require('./domComponent'); -var rendering = require('./rendering'); -var VText = require("virtual-dom/vnode/vtext.js") +var domComponent = require('./domComponent') +var rendering = require('./rendering') +var VText = require('virtual-dom/vnode/vtext.js') -function WindowWidget(attributes) { - this.attributes = attributes; - this.vdom = new VText(''); - this.component = domComponent.create(); +function WindowWidget (attributes) { + this.attributes = attributes + this.vdom = new VText('') + this.component = domComponent.create() - var self = this; - this.cache = {}; + var self = this + this.cache = {} Object.keys(this.attributes).forEach(function (key) { - self.cache[key] = rendering.html.refreshify(self.attributes[key]); - }); + self.cache[key] = rendering.html.refreshify(self.attributes[key]) + }) } -WindowWidget.prototype.type = 'Widget'; +WindowWidget.prototype.type = 'Widget' WindowWidget.prototype.init = function () { - applyPropertyDiffs(window, {}, this.attributes, {}, this.cache); - return this.element = document.createTextNode(''); -}; + applyPropertyDiffs(window, {}, this.attributes, {}, this.cache) + return this.element = document.createTextNode('') +} -function uniq(array) { - var sortedArray = array.slice(); - sortedArray.sort(); +function uniq (array) { + var sortedArray = array.slice() + sortedArray.sort() - var last; + var last - for(var n = 0; n < sortedArray.length;) { - var current = sortedArray[n]; + for (var n = 0; n < sortedArray.length;) { + var current = sortedArray[n] if (last === current) { - sortedArray.splice(n, 1); + sortedArray.splice(n, 1) } else { - n++; + n++ } - last = current; + last = current } - return sortedArray; + return sortedArray } -function applyPropertyDiffs(element, previous, current, previousCache, currentCache) { +function applyPropertyDiffs (element, previous, current, previousCache, currentCache) { uniq(Object.keys(previous).concat(Object.keys(current))).forEach(function (key) { if (/^on/.test(key)) { - var event = key.slice(2); + var event = key.slice(2) - var prev = previous[key]; - var curr = current[key]; - var refreshPrev = previousCache[key]; - var refreshCurr = currentCache[key]; + var prev = previous[key] + var curr = current[key] + var refreshPrev = previousCache[key] + var refreshCurr = currentCache[key] if (prev !== undefined && curr === undefined) { - element.removeEventListener(event, refreshPrev); + element.removeEventListener(event, refreshPrev) } else if (prev !== undefined && curr !== undefined && prev !== curr) { - element.removeEventListener(event, refreshPrev); - element.addEventListener(event, refreshCurr); + element.removeEventListener(event, refreshPrev) + element.addEventListener(event, refreshCurr) } else if (prev === undefined && curr !== undefined) { - element.addEventListener(event, refreshCurr); + element.addEventListener(event, refreshCurr) } } - }); + }) } WindowWidget.prototype.update = function (previous) { - applyPropertyDiffs(window, previous.attributes, this.attributes, previous.cache, this.cache); - this.component = previous.component; - return this.element; -}; + applyPropertyDiffs(window, previous.attributes, this.attributes, previous.cache, this.cache) + this.component = previous.component + return this.element +} WindowWidget.prototype.destroy = function () { - applyPropertyDiffs(window, this.attributes, {}, this.cache, {}); -}; + applyPropertyDiffs(window, this.attributes, {}, this.cache, {}) +} module.exports = function (attributes) { - return new WindowWidget(attributes); -}; + return new WindowWidget(attributes) +} diff --git a/xml.js b/xml.js index ac90b26..a1afb70 100644 --- a/xml.js +++ b/xml.js @@ -3,7 +3,7 @@ var AttributeHook = require('virtual-dom/virtual-hyperscript/hooks/attribute-hoo var namespaceRegex = /^([a-z0-9_-]+)(--|:)([a-z0-9_-]+)$/i var xmlnsRegex = /^xmlns(--|:)([a-z0-9_-]+)$/i -function transformTanName(vnode, namespaces) { +function transformTanName (vnode, namespaces) { var tagNamespace = namespaceRegex.exec(vnode.tagName) if (tagNamespace) { var namespaceKey = tagNamespace[1] @@ -17,25 +17,25 @@ function transformTanName(vnode, namespaces) { } } -function transformProperties(vnode, namespaces) { +function transformProperties (vnode, namespaces) { var properties = vnode.properties if (properties) { var attributes = properties.attributes || (properties.attributes = {}) - var keys = Object.keys(properties); + var keys = Object.keys(properties) for (var k = 0, l = keys.length; k < l; k++) { - var key = keys[k]; + var key = keys[k] if (key != 'style' && key != 'attributes') { var match = namespaceRegex.exec(key) if (match) { properties[match[1] + ':' + match[3]] = new AttributeHook(namespaces[match[1]], properties[key]) delete properties[key] } else { - var property = properties[key]; - var type = typeof property; + var property = properties[key] + var type = typeof property if (type === 'string' || type === 'number' || type === 'boolean') { - attributes[key] = property; + attributes[key] = property } } } @@ -43,7 +43,7 @@ function transformProperties(vnode, namespaces) { } } -function declaredNamespaces(vnode) { +function declaredNamespaces (vnode) { var namespaces = { '': vnode.properties.xmlns, xmlns: 'http://www.w3.org/2000/xmlns/' @@ -52,7 +52,7 @@ function declaredNamespaces(vnode) { var keys = Object.keys(vnode.properties) for (var k = 0, l = keys.length; k < l; k++) { - var key = keys[k]; + var key = keys[k] var value = vnode.properties[key] if (key == 'xmlns') { @@ -69,16 +69,16 @@ function declaredNamespaces(vnode) { return namespaces } -function transform(vnode) { +function transform (vnode) { var namespaces = declaredNamespaces(vnode) - function transformChildren(vnode, namespaces) { + function transformChildren (vnode, namespaces) { transformTanName(vnode, namespaces) transformProperties(vnode, namespaces) if (vnode.children) { for (var c = 0, l = vnode.children.length; c < l; c++) { - var child = vnode.children[c]; + var child = vnode.children[c] if (!(child.properties && child.properties.xmlns)) { transformChildren(child, namespaces) }