diff --git a/.github/FUNDING.yml b/.github/FUNDING.yml new file mode 100644 index 00000000..943f5e9f --- /dev/null +++ b/.github/FUNDING.yml @@ -0,0 +1,8 @@ +# These are supported funding model platforms + +github: # Replace with up to 4 GitHub Sponsors-enabled usernames e.g., [user1, user2] +patreon: # not working due missing www. +open_collective: hyperHTML +ko_fi: # Replace with a single Ko-fi username +tidelift: # Replace with a single Tidelift platform-name/package-name e.g., npm/babel +custom: https://www.patreon.com/webreflection diff --git a/.github/workflows/node.js.yml b/.github/workflows/node.js.yml new file mode 100644 index 00000000..73cf8d65 --- /dev/null +++ b/.github/workflows/node.js.yml @@ -0,0 +1,31 @@ +# This workflow will do a clean install of node dependencies, cache/restore them, build the source code and run tests across different versions of node +# For more information see: https://help.github.com/actions/language-and-framework-guides/using-nodejs-with-github-actions + +name: build + +on: [push, pull_request] + +jobs: + build: + + runs-on: ubuntu-latest + + strategy: + matrix: + node-version: [16] + + steps: + - uses: actions/checkout@v2 + - name: Use Node.js ${{ matrix.node-version }} + uses: actions/setup-node@v2 + with: + node-version: ${{ matrix.node-version }} + cache: 'npm' + - run: npm ci + - run: npm run build --if-present + - run: npm test + - run: npm run coverage --if-present + - name: Coveralls + uses: coverallsapp/github-action@master + with: + github-token: ${{ secrets.GITHUB_TOKEN }} diff --git a/.gitignore b/.gitignore index 475f26d7..3cb01d4d 100644 --- a/.gitignore +++ b/.gitignore @@ -1,4 +1,4 @@ .DS_Store node_modules/ coverage/ -package-lock.json + diff --git a/CHANGELOG.md b/CHANGELOG.md index 6d0a406d..60ac2164 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,5 +1,25 @@ # hyper(html) Changelog +### v.2.23 + * monkey patched rollup generated code to export once the same module shared within sub-modules + +### v2.22 + * using latest domtagger + +### v2.21 + * refactored out all dependencies + +### v2.20 + * re-tested every single supported browser nd fixed few outstanding issues with the 2.19 release + +### v2.19 + * refactored out most of the code + * finally managed to have coveralls show coverage stats + * attributes can have spaces around as per DOM standard - [#244](https://github.com/WebReflection/hyperHTML/issues/224) + * fixed SVG (non-critical) errors when interpolations are used for numerically expected values + * fixed minor issues with Edge attributes + * changed the unique id so if any of your logic was trusting `_hyper: ....;` comments you need to update your logic - [#300](https://github.com/WebReflection/hyperHTML/issues/300) + ### v2.16.8 * improved MutationObserver and fallback so that double `dis/connected` events won't happen again * exposed `observe` utility for 3rd parts so that it is possible to observe any node, not only those defined via template literals. Once observed, a node can have `connected` and `disconnected` listeners that will be triggered automatically. diff --git a/HELPERS.md b/HELPERS.md new file mode 100644 index 00000000..d0f8aefb --- /dev/null +++ b/HELPERS.md @@ -0,0 +1,57 @@ +## [babel-plugin-remove-ungap] + +Remove the [@ungap ponyfill modules] from your bundle. This will decrease the size of +your bundle if you are targeting modern browsers only or if your build already includes +other polyfills. This has been tested with [hyperHTML] and [lighterhtml] bundles. + + +## [babel-plugin-template-html-minifier] + +Run [html-minifier] on hyperHTML templates. + + +## [babel-plugin-bare-import-rewrite] + +This can be used as an alternative to [rollup-plugin-node-resolve], or can be used with certain node.js +web servers to allow browsing live from source. + +Known web server integrations: +* [fastify-babel] plugin for [fastify] enables running any babel plugins, generally expects `payload.filename` as set by [fastify-static] +* [express-transform-bare-module-specifiers] for [express] servers + + +## [vinyl-rollup] + +This module copies the output of rollup builds to a stream of vinyl-fs objects for [gulp]. +In addition it optionally adds files from modules that were bundled into the stream. This +makes it easy to ensure that LICENSE and package.json files associated with bundled modules +are published on the web server without publishing node.js server-side dependencies to the web. +This can also be used to copy complete modules if required for licensing or if bundled code +requires additional assets that are not part of the bundled JS (images for example). + + +## [babel-plugin-bundled-import-meta] + +If `node_modules/some-web-component/index.js` uses `import.meta.url` to calculate the actual +path to `node_modules/some-web-components/image.png`, rollup does not compensate. This babel +plugin rewrites references to `import.meta.url` so it points to the original location where +it is expected that the additional assets (images and such) can be found. This plugin works +well with `vinyl-rollup` with `copyModules: true`. + + +[babel-plugin-remove-ungap]: https://github.com/cfware/babel-plugin-remove-ungap#readme +[@ungap ponyfill modules]: https://github.com/ungap/ungap.github.io#readme +[hyperHTML]: https://github.com/WebReflection/hyperHTML#readme +[lighterhtml]: https://github.com/WebReflection/lighterhtml#readme +[babel-plugin-template-html-minifier]: https://github.com/cfware/babel-plugin-template-html-minifier#readme +[html-minifier]: https://github.com/kangax/html-minifier#readme +[babel-plugin-bare-import-rewrite]: https://github.com/cfware/babel-plugin-bare-import-rewrite#readme +[rollup-plugin-node-resolve]: https://github.com/rollup/rollup-plugin-node-resolve#readme +[fastify]: https://github.com/fastify/fastify#readme +[fastify-babel]: https://github.com/cfware/fastify-babel#readme +[fastify-static]: https://github.com/fastify/fastify-static#readme +[express-transform-bare-module-specifiers]: https://github.com/nodecg/express-transform-bare-module-specifiers#readme +[express]: https://github.com/expressjs/express#readme +[vinyl-rollup]: https://github.com/cfware/vinyl-rollup#readme +[gulp]: https://github.com/gulpjs/gulp#readme +[babel-plugin-bundled-import-meta]: https://github.com/cfware/babel-plugin-bundled-import-meta#readme diff --git a/README.md b/README.md index 00231d81..72f7e51a 100644 --- a/README.md +++ b/README.md @@ -1,8 +1,22 @@ # hyper(HTML) +### Maintainance Only + +This module is great, works great, and served me greatly, but there's a pletora of modern, faster, more capable alternatives me, among many other OSS developers, offer so that if obvious bugs are proven to exist, these will be fixed, but there won't be a major release and I won't remove legacy support for stuff that, as previously mentioned, works just fine and it's battle-tested from IE to the latest Chrome. + +Removing that legacy support brings pretty much nothing in terms of size too: this module is already smaller than 90% of alternatives out there, dropping 0.xK so that there's less code that, behind feature detection, is not even used in modern browsers, won't benefit anyone. + +Thansk for your understanding and for not opening PRs which goal is to drop a check for legacy browsers ... these won't likely be merged ever as that'd be a major release update and I don't think anyone is interested in that. + +### ๐Ÿ“ฃ Community Announcement + +Please ask questions in the [dedicated discussions repository](https://github.com/WebReflection/discussions), to help the community around this project grow โ™ฅ + +- - - + hyperHTML logo -A **Fast & Light Virtual DOM Alternative** available for [Node.js](https://viperhtml.js.org/viper.html) and [NativeScript](https://viperhtml.js.org/native.html) too. +A **Fast & Light Virtual DOM Alternative**. - - - @@ -15,9 +29,29 @@ A **Fast & Light Virtual DOM Alternative** available for [Node.js](https://viper - - - +Following an overview of projects related, or inspired by, _hyperHTML_. For a deep comparison of current libraries, feel free to [check this gist out](https://gist.github.com/WebReflection/761052d6dae7c8207d2fcba7cdede295). + + +## ยตhtml + +The latest, smallest, iteration of all best concept from this library since 2017, have been packaged in _~2.5K_. If it's extreme minimalism and great _DX_ that you are after, check [uhtml](https://github.com/WebReflection/uhtml#readme) out. + + +## hypersimple + +If you've just started with template literals based projects and you like components, or you'd like to understand what's _hyperHTML_ capable of, give [hypersimple](https://github.com/WebReflection/hypersimple#readme) a try ๐ŸŽ‰ + + +## lighterhtml ๐Ÿ’ก + +This little brother is "_showing off_" these days, claiming better performance and unprecedented ease of use. + +[GitHub Repository](https://github.com/WebReflection/lighterhtml) + + ## Neverland ๐ŸŒˆ๐Ÿฆ„ -If you like React hooks concept, don't miss this little wrap tha adds 0._something_ overhead to the already lightweight hyperHTML, bringing in very similar concepts. +If you like React hooks concept, don't miss this little wrap that adds 0._something_ overhead to the already lightweight hyperHTML, bringing in very similar concepts. [Blog Post](https://medium.com/@WebReflection/neverland-the-hyperhtmls-hook-a0c3e11324bb) @@ -34,6 +68,8 @@ You can require or import _hyperHTML_ with any bundler and in different ways. If requiring or importing from `"hyperhtml"` doesn't work, try requiring from `"hyperhtml/cjs"` for CommonJS friendly bundlers (WebPack), or `"hyperhtml/esm"` for ESM compatible bundlers (Rollup). +See [HELPERS.md](./HELPERS.md) for a list of additional tools which can be helpful for building hyperHTML based web applications. + - - - ## Sponsors @@ -55,21 +91,12 @@ This project exists thanks to all the people who contribute. [[Contribute](CONTR - - - -### Seamlessly Isomorphic -No matter if you use ESM or CommonJS, you can use [hypermorphic](https://github.com/WebReflection/hypermorphic#hypermorphic-) -to load same features on both client and server. +### 2.34 Highlights -```js -// ESM example (assuming bundlers/ESM loaders in place) -import {bind, wire} from 'hypermorphic'; - -// CommonJS example -const {bind, wire} = require('hypermorphic'); -``` - -- - - + * the new `?boolean=${value}` syntax from [ยตhtml](https://github.com/WebReflection/uhtml#readme) has landed in *hyperHTML* too. Feel free to [read this long discussion](https://github.com/WebReflection/discussions/discussions/13) to better understand *why* this syntax is necessary. ### V2.5 Highlights + * `` tags for both custom elements and any other as well ๐ŸŽ‰ ### V2 Highlights @@ -89,6 +116,7 @@ Following most important changes in version 2: A proper documentation full of examples can be found in [viperhtml.js.org](https://viperhtml.js.org/). + ## Basic Example The easiest way to describe `hyperHTML` is through [an example](https://webreflection.github.io/hyperHTML/test/tick.html). ```js @@ -121,6 +149,12 @@ You can verify directly through the following links: * [100% code coverage](https://webreflection.github.io/hyperHTML/test/) for browsers natively compatible with string literals * [100% code coverage](https://webreflection.github.io/hyperHTML/test/ie/) for IE9+ and browsers that need transpiled code + +#### Weakmap error on ie < 11 + +'@ungap/weakmap': object is not extensible + +Babel freezes the template literals by spec but that causes problems with the weakmap polyfill. To fix this error add the fix explained on [ungap/weakmap](https://github.com/ungap/weakmap#transpiled-code-and-frozen-objects-in-legacy-browsers) ## HTML Syntax Highlight @@ -138,7 +172,7 @@ Please ask anything you'd like to know in [StackOverflow](https://stackoverflow. #### hyper or lit ? -You can read more on this [hyperHTML vs lit-html](https://gist.github.com/WebReflection/fadcc419f5ccaae92bc167d8ff5c611b) comparison. +You can read more on this [hyperHTML vs lit-html](https://medium.com/@WebReflection/lit-html-vs-hyperhtml-vs-lighterhtml-c084abfe1285) comparison. #### installation? diff --git a/cjs/3rd/disconnected.js b/cjs/3rd/disconnected.js deleted file mode 100644 index 611103de..00000000 --- a/cjs/3rd/disconnected.js +++ /dev/null @@ -1,110 +0,0 @@ -'use strict'; -/* AUTOMATICALLY IMPORTED, DO NOT MODIFY */ -/*! (c) Andrea Giammarchi */ -function disconnected(poly) {'use strict'; - var CONNECTED = 'connected'; - var DISCONNECTED = 'dis' + CONNECTED; - var Event = poly.Event; - var WeakSet = poly.WeakSet; - var notObserving = true; - var observer = new WeakSet; - return function observe(node) { - if (notObserving) { - notObserving = !notObserving; - startObserving(node.ownerDocument); - } - observer.add(node); - return node; - }; - function startObserving(document) { - var dispatched = null; - try { - (new MutationObserver(changes)).observe( - document, - {subtree: true, childList: true} - ); - } - catch(o_O) { - var timer = 0; - var records = []; - var reschedule = function (record) { - records.push(record); - clearTimeout(timer); - timer = setTimeout( - function () { - changes(records.splice(timer = 0, records.length)); - }, - 0 - ); - }; - document.addEventListener( - 'DOMNodeRemoved', - function (event) { - reschedule({addedNodes: [], removedNodes: [event.target]}); - }, - true - ); - document.addEventListener( - 'DOMNodeInserted', - function (event) { - reschedule({addedNodes: [event.target], removedNodes: []}); - }, - true - ); - } - function changes(records) { - dispatched = new Tracker; - for (var - record, - length = records.length, - i = 0; i < length; i++ - ) { - record = records[i]; - dispatchAll(record.removedNodes, DISCONNECTED, CONNECTED); - dispatchAll(record.addedNodes, CONNECTED, DISCONNECTED); - } - dispatched = null; - } - function dispatchAll(nodes, type, counter) { - for (var - node, - event = new Event(type), - length = nodes.length, - i = 0; i < length; - (node = nodes[i++]).nodeType === 1 && - dispatchTarget(node, event, type, counter) - ); - } - function dispatchTarget(node, event, type, counter) { - if (observer.has(node) && !dispatched[type].has(node)) { - dispatched[counter].delete(node); - dispatched[type].add(node); - node.dispatchEvent(event); - /* - // The event is not bubbling (perf reason: should it?), - // hence there's no way to know if - // stop/Immediate/Propagation() was called. - // Should DOM Level 0 work at all? - // I say it's a YAGNI case for the time being, - // and easy to implement in user-land. - if (!event.cancelBubble) { - var fn = node['on' + type]; - if (fn) - fn.call(node, event); - } - */ - } - for (var - children = node.children, - length = children.length, - i = 0; i < length; - dispatchTarget(children[i++], event, type, counter) - ); - } - function Tracker() { - this[CONNECTED] = new WeakSet; - this[DISCONNECTED] = new WeakSet; - } - } -} -Object.defineProperty(exports, '__esModule', {value: true}).default = disconnected; diff --git a/cjs/3rd/domdiff.js b/cjs/3rd/domdiff.js deleted file mode 100644 index 67b3b079..00000000 --- a/cjs/3rd/domdiff.js +++ /dev/null @@ -1,223 +0,0 @@ -'use strict'; -/* AUTOMATICALLY IMPORTED, DO NOT MODIFY */ -/*! (c) 2018 Andrea Giammarchi (ISC) */ - -const { - eqeq, identity, indexOf, isReversed, next, append, remove, smartDiff -} = require('./utils.js'); - -const domdiff = ( - parentNode, // where changes happen - currentNodes, // Array of current items/nodes - futureNodes, // Array of future items/nodes - options // optional object with one of the following properties - // before: domNode - // compare(generic, generic) => true if same generic - // node(generic) => Node -) => { - if (!options) - options = {}; - - const compare = options.compare || eqeq; - const get = options.node || identity; - const before = options.before == null ? null : get(options.before, 0); - - const currentLength = currentNodes.length; - let currentEnd = currentLength; - let currentStart = 0; - - let futureEnd = futureNodes.length; - let futureStart = 0; - - // common prefix - while ( - currentStart < currentEnd && - futureStart < futureEnd && - compare(currentNodes[currentStart], futureNodes[futureStart]) - ) { - currentStart++; - futureStart++; - } - - // common suffix - while ( - currentStart < currentEnd && - futureStart < futureEnd && - compare(currentNodes[currentEnd - 1], futureNodes[futureEnd - 1]) - ) { - currentEnd--; - futureEnd--; - } - - const currentSame = currentStart === currentEnd; - const futureSame = futureStart === futureEnd; - - // same list - if (currentSame && futureSame) - return futureNodes; - - // only stuff to add - if (currentSame && futureStart < futureEnd) { - append( - get, - parentNode, - futureNodes, - futureStart, - futureEnd, - next(get, currentNodes, currentStart, currentLength, before) - ); - return futureNodes; - } - - // only stuff to remove - if (futureSame && currentStart < currentEnd) { - remove( - get, - parentNode, - currentNodes, - currentStart, - currentEnd - ); - return futureNodes; - } - - const currentChanges = currentEnd - currentStart; - const futureChanges = futureEnd - futureStart; - let i = -1; - - // 2 simple indels: the shortest sequence is a subsequence of the longest - if (currentChanges < futureChanges) { - i = indexOf( - futureNodes, - futureStart, - futureEnd, - currentNodes, - currentStart, - currentEnd, - compare - ); - // inner diff - if (-1 < i) { - append( - get, - parentNode, - futureNodes, - futureStart, - i, - get(currentNodes[currentStart], 0) - ); - append( - get, - parentNode, - futureNodes, - i + currentChanges, - futureEnd, - next(get, currentNodes, currentEnd, currentLength, before) - ); - return futureNodes; - } - } - /* istanbul ignore else */ - else if (futureChanges < currentChanges) { - i = indexOf( - currentNodes, - currentStart, - currentEnd, - futureNodes, - futureStart, - futureEnd, - compare - ); - // outer diff - if (-1 < i) { - remove( - get, - parentNode, - currentNodes, - currentStart, - i - ); - remove( - get, - parentNode, - currentNodes, - i + futureChanges, - currentEnd - ); - return futureNodes; - } - } - - // common case with one replacement for many nodes - // or many nodes replaced for a single one - /* istanbul ignore else */ - if ((currentChanges < 2 || futureChanges < 2)) { - append( - get, - parentNode, - futureNodes, - futureStart, - futureEnd, - get(currentNodes[currentStart], 0) - ); - remove( - get, - parentNode, - currentNodes, - currentStart, - currentEnd - ); - return futureNodes; - } - - // the half match diff part has been skipped in petit-dom - // https://github.com/yelouafi/petit-dom/blob/bd6f5c919b5ae5297be01612c524c40be45f14a7/src/vdom.js#L391-L397 - // accordingly, I think it's safe to skip in here too - // if one day it'll come out like the speediest thing ever to do - // then I might add it in here too - - // Extra: before going too fancy, what about reversed lists ? - // This should bail out pretty quickly if that's not the case. - if ( - currentChanges === futureChanges && - isReversed( - futureNodes, - futureEnd, - currentNodes, - currentStart, - currentEnd, - compare - ) - ) { - append( - get, - parentNode, - futureNodes, - futureStart, - futureEnd, - next(get, currentNodes, currentEnd, currentLength, before) - ); - return futureNodes; - } - - // last resort through a smart diff - smartDiff( - get, - parentNode, - futureNodes, - futureStart, - futureEnd, - futureChanges, - currentNodes, - currentStart, - currentEnd, - currentChanges, - currentLength, - compare, - before - ); - - return futureNodes; -}; - -Object.defineProperty(exports, '__esModule', {value: true}).default = domdiff; diff --git a/cjs/3rd/utils.js b/cjs/3rd/utils.js deleted file mode 100644 index 483aea85..00000000 --- a/cjs/3rd/utils.js +++ /dev/null @@ -1,396 +0,0 @@ -'use strict'; -/* AUTOMATICALLY IMPORTED, DO NOT MODIFY */ -const append = (get, parent, children, start, end, before) => { - if ((end - start) < 2) - parent.insertBefore(get(children[start], 1), before); - else { - const fragment = parent.ownerDocument.createDocumentFragment(); - while (start < end) - fragment.appendChild(get(children[start++], 1)); - parent.insertBefore(fragment, before); - } -}; -exports.append = append; - -const eqeq = (a, b) => a == b; -exports.eqeq = eqeq; - -const identity = O => O; -exports.identity = identity; - -const indexOf = ( - moreNodes, - moreStart, - moreEnd, - lessNodes, - lessStart, - lessEnd, - compare -) => { - const length = lessEnd - lessStart; - /* istanbul ignore if */ - if (length < 1) - return -1; - while ((moreEnd - moreStart) >= length) { - let m = moreStart; - let l = lessStart; - while ( - m < moreEnd && - l < lessEnd && - compare(moreNodes[m], lessNodes[l]) - ) { - m++; - l++; - } - if (l === lessEnd) - return moreStart; - moreStart = m + 1; - } - return -1; -}; -exports.indexOf = indexOf; - -const isReversed = ( - futureNodes, - futureEnd, - currentNodes, - currentStart, - currentEnd, - compare -) => { - while ( - currentStart < currentEnd && - compare( - currentNodes[currentStart], - futureNodes[futureEnd - 1] - )) { - currentStart++; - futureEnd--; - }; - return futureEnd === 0; -}; -exports.isReversed = isReversed; - -const next = (get, list, i, length, before) => i < length ? - get(list[i], 0) : - (0 < i ? - get(list[i - 1], -0).nextSibling : - before); -exports.next = next; - -const remove = (get, parent, children, start, end) => { - if ((end - start) < 2) - parent.removeChild(get(children[start], -1)); - else { - const range = parent.ownerDocument.createRange(); - range.setStartBefore(get(children[start], -1)); - range.setEndAfter(get(children[end - 1], -1)); - range.deleteContents(); - } -}; -exports.remove = remove; - -// - - - - - - - - - - - - - - - - - - - -// diff related constants and utilities -// - - - - - - - - - - - - - - - - - - - - -const DELETION = -1; -const INSERTION = 1; -const SKIP = 0; -const SKIP_OND = 50; - -/* istanbul ignore next */ -const Rel = typeof Map === 'undefined' ? - function () { - const k = [], v = []; - return { - has: value => -1 < k.indexOf(value), - get: value => v[k.indexOf(value)], - set: value => { - const i = k.indexOf(value); - v[i < 0 ? (k.push(value) - 1) : i] = value; - } - }; - } : - Map -; - -const HS = ( - futureNodes, - futureStart, - futureEnd, - futureChanges, - currentNodes, - currentStart, - currentEnd, - currentChanges -) => { - - let k = 0; - /* istanbul ignore next */ - let minLen = futureChanges < currentChanges ? futureChanges : currentChanges; - const link = Array(minLen++); - const tresh = Array(minLen); - tresh[0] = -1; - - for (let i = 1; i < minLen; i++) - tresh[i] = currentEnd; - - const keymap = new Rel; - for (let i = currentStart; i < currentEnd; i++) - keymap.set(currentNodes[i], i); - - for (let i = futureStart; i < futureEnd; i++) { - const idxInOld = keymap.get(futureNodes[i]); - if (idxInOld != null) { - k = findK(tresh, minLen, idxInOld); - /* istanbul ignore else */ - if (-1 < k) { - tresh[k] = idxInOld; - link[k] = { - newi: i, - oldi: idxInOld, - prev: link[k - 1] - }; - } - } - } - - k = --minLen; - --currentEnd; - while (tresh[k] > currentEnd) --k; - - minLen = currentChanges + futureChanges - k; - const diff = Array(minLen); - let ptr = link[k]; - --futureEnd; - while (ptr) { - const {newi, oldi} = ptr; - while (futureEnd > newi) { - diff[--minLen] = INSERTION; - --futureEnd; - } - while (currentEnd > oldi) { - diff[--minLen] = DELETION; - --currentEnd; - } - diff[--minLen] = SKIP; - --futureEnd; - --currentEnd; - ptr = ptr.prev; - } - while (futureEnd >= futureStart) { - diff[--minLen] = INSERTION; - --futureEnd; - } - while (currentEnd >= currentStart) { - diff[--minLen] = DELETION; - --currentEnd; - } - return diff; -}; - -// this is pretty much the same petit-dom code without the delete map part -// https://github.com/yelouafi/petit-dom/blob/bd6f5c919b5ae5297be01612c524c40be45f14a7/src/vdom.js#L556-L561 -const OND = ( - futureNodes, - futureStart, - rows, - currentNodes, - currentStart, - cols, - compare -) => { - const length = rows + cols; - const v = []; - let d, k, r, c, pv, cv, pd; - outer: for (d = 0; d <= length; d++) { - /* istanbul ignore if */ - if (d > SKIP_OND) - return null; - pd = d - 1; - /* istanbul ignore next */ - pv = d ? v[d - 1] : [0, 0]; - cv = v[d] = []; - for (k = -d; k <= d; k += 2) { - if (k === -d || (k !== d && pv[pd + k - 1] < pv[pd + k + 1])) { - c = pv[pd + k + 1]; - } else { - c = pv[pd + k - 1] + 1; - } - r = c - k; - while ( - c < cols && - r < rows && - compare( - currentNodes[currentStart + c], - futureNodes[futureStart + r] - ) - ) { - c++; - r++; - } - if (c === cols && r === rows) { - break outer; - } - cv[d + k] = c; - } - } - - const diff = Array(d / 2 + length / 2); - let diffIdx = diff.length - 1; - for (d = v.length - 1; d >= 0; d--) { - while ( - c > 0 && - r > 0 && - compare( - currentNodes[currentStart + c - 1], - futureNodes[futureStart + r - 1] - ) - ) { - // diagonal edge = equality - diff[diffIdx--] = SKIP; - c--; - r--; - } - if (!d) - break; - pd = d - 1; - /* istanbul ignore next */ - pv = d ? v[d - 1] : [0, 0]; - k = c - r; - if (k === -d || (k !== d && pv[pd + k - 1] < pv[pd + k + 1])) { - // vertical edge = insertion - r--; - diff[diffIdx--] = INSERTION; - } else { - // horizontal edge = deletion - c--; - diff[diffIdx--] = DELETION; - } - } - return diff; -}; - -const applyDiff = ( - diff, - get, - parentNode, - futureNodes, - futureStart, - currentNodes, - currentStart, - currentLength, - before -) => { - const live = new Rel; - const length = diff.length; - let currentIndex = currentStart; - let i = 0; - while (i < length) { - switch (diff[i++]) { - case SKIP: - futureStart++; - currentIndex++; - break; - case INSERTION: - // TODO: bulk appends for sequential nodes - live.set(futureNodes[futureStart], 1); - append( - get, - parentNode, - futureNodes, - futureStart++, - futureStart, - currentIndex < currentLength ? - get(currentNodes[currentIndex], 1) : - before - ); - break; - case DELETION: - currentIndex++; - break; - } - } - i = 0; - while (i < length) { - switch (diff[i++]) { - case SKIP: - currentStart++; - break; - case DELETION: - // TODO: bulk removes for sequential nodes - if (live.has(currentNodes[currentStart])) - currentStart++; - else - remove( - get, - parentNode, - currentNodes, - currentStart++, - currentStart - ); - break; - } - } -}; - -const findK = (ktr, length, j) => { - let lo = 1; - let hi = length; - while (lo < hi) { - var mid = ((lo + hi) / 2) >>> 0; - if (j < ktr[mid]) - hi = mid; - else - lo = mid + 1; - } - return lo; -} - -const smartDiff = ( - get, - parentNode, - futureNodes, - futureStart, - futureEnd, - futureChanges, - currentNodes, - currentStart, - currentEnd, - currentChanges, - currentLength, - compare, - before -) => { - applyDiff( - OND( - futureNodes, - futureStart, - futureChanges, - currentNodes, - currentStart, - currentChanges, - compare - ) || - HS( - futureNodes, - futureStart, - futureEnd, - futureChanges, - currentNodes, - currentStart, - currentEnd, - currentChanges - ), - get, - parentNode, - futureNodes, - futureStart, - currentNodes, - currentStart, - currentLength, - before - ); -}; -exports.smartDiff = smartDiff; diff --git a/cjs/classes/Component.js b/cjs/classes/Component.js index 1667e96d..632986bf 100644 --- a/cjs/classes/Component.js +++ b/cjs/classes/Component.js @@ -1,5 +1,7 @@ 'use strict'; -const { Map, WeakMap } = require('../shared/poorlyfills.js'); +const CustomEvent = (m => m.__esModule ? /* istanbul ignore next */ m.default : /* istanbul ignore next */ m)(require('@ungap/custom-event')); +const Map = (m => m.__esModule ? /* istanbul ignore next */ m.default : /* istanbul ignore next */ m)(require('@ungap/essential-map')); +const WeakMap = (m => m.__esModule ? /* istanbul ignore next */ m.default : /* istanbul ignore next */ m)(require('@ungap/weakmap')); // hyperHTML.Component is a very basic class // able to create Custom Elements like components @@ -105,7 +107,7 @@ function setup(content) { event.component = this; return (_wire$.dispatchEvent ? _wire$ : - _wire$.childNodes[0] + _wire$.firstChild ).dispatchEvent(event); } return false; @@ -153,3 +155,12 @@ const setValue = (self, secret, value) => value })[secret] ; + +Object.defineProperties( + Component.prototype, + { + // used to distinguish better than instanceof + ELEMENT_NODE: {value: 1}, + nodeType: {value: -1} + } +); diff --git a/cjs/classes/Wire.js b/cjs/classes/Wire.js deleted file mode 100644 index da8d4e34..00000000 --- a/cjs/classes/Wire.js +++ /dev/null @@ -1,39 +0,0 @@ -'use strict'; -const { append } = require('../shared/utils.js'); -const { doc, fragment } = require('../shared/easy-dom.js'); - -function Wire(childNodes) { - this.childNodes = childNodes; - this.length = childNodes.length; - this.first = childNodes[0]; - this.last = childNodes[this.length - 1]; - this._ = null; -} -Object.defineProperty(exports, '__esModule', {value: true}).default = Wire - -// when a wire is inserted, all its nodes will follow -Wire.prototype.valueOf = function valueOf(different) { - const noFragment = this._ == null; - if (noFragment) - this._ = fragment(this.first); - /* istanbul ignore else */ - if (noFragment || different) - append(this._, this.childNodes); - return this._; -}; - -// when a wire is removed, all its nodes must be removed as well -Wire.prototype.remove = function remove() { - this._ = null; - const first = this.first; - const last = this.last; - if (this.length === 2) { - last.parentNode.removeChild(last); - } else { - const range = doc(first).createRange(); - range.setStartBefore(this.childNodes[1]); - range.setEndAfter(last); - range.deleteContents(); - } - return first; -}; diff --git a/cjs/hyper/render.js b/cjs/hyper/render.js index 9b8a4faf..a401a66b 100644 --- a/cjs/hyper/render.js +++ b/cjs/hyper/render.js @@ -1,33 +1,25 @@ 'use strict'; -const {WeakMap} = require('../shared/poorlyfills.js'); -const {UIDC, VOID_ELEMENTS} = require('../shared/constants.js'); -const Updates = (m => m.__esModule ? m.default : m)(require('../objects/Updates.js')); -const { - createFragment, - importNode, - unique, - TemplateMap -} = require('../shared/utils.js'); +const WeakMap = (m => m.__esModule ? /* istanbul ignore next */ m.default : /* istanbul ignore next */ m)(require('@ungap/weakmap')); +const tta = (m => m.__esModule ? /* istanbul ignore next */ m.default : /* istanbul ignore next */ m)(require('@ungap/template-tag-arguments')); -const {selfClosing} = require('../shared/re.js'); +const {OWNER_SVG_ELEMENT} = require('../shared/constants.js'); +const {Tagger} = require('../objects/Updates.js'); // a weak collection of contexts that // are already known to hyperHTML const bewitched = new WeakMap; -// all unique template literals -const templates = TemplateMap(); - // better known as hyper.bind(node), the render is // the main tag function in charge of fully upgrading // or simply updating, contexts used as hyperHTML targets. // The `this` context is either a regular DOM node or a fragment. -function render(template) { +function render() { const wicked = bewitched.get(this); - if (wicked && wicked.template === unique(template)) { - update.apply(wicked.updates, arguments); + const args = tta.apply(null, arguments); + if (wicked && wicked.template === args[0]) { + wicked.tagger.apply(null, args); } else { - upgrade.apply(this, arguments); + upgrade.apply(this, args); } return this; } @@ -37,44 +29,11 @@ function render(template) { // as single DOM callbacks, relate such template // to the current context, and render it after cleaning the context up function upgrade(template) { - template = unique(template); - const info = templates.get(template) || - createTemplate.call(this, template); - const fragment = importNode(this.ownerDocument, info.fragment); - const updates = Updates.create(fragment, info.paths); - bewitched.set(this, {template, updates}); - update.apply(updates, arguments); + const type = OWNER_SVG_ELEMENT in this ? 'svg' : 'html'; + const tagger = new Tagger(type); + bewitched.set(this, {tagger, template: template}); this.textContent = ''; - this.appendChild(fragment); -} - -// an update simply loops over all mapped DOM operations -function update() { - const length = arguments.length; - for (let i = 1; i < length; i++) { - this[i - 1](arguments[i]); - } + this.appendChild(tagger.apply(null, arguments)); } -// a template can be used to create a document fragment -// aware of all interpolations and with a list -// of paths used to find once those nodes that need updates, -// no matter if these are attributes, text nodes, or regular one -function createTemplate(template) { - const paths = []; - const html = template.join(UIDC).replace(SC_RE, SC_PLACE); - const fragment = createFragment(this, html); - Updates.find(fragment, paths, template.slice()); - const info = {fragment, paths}; - templates.set(template, info); - return info; -} - -// some node could be special though, like a custom element -// with a self closing tag, which should work through these changes. -const SC_RE = selfClosing; -const SC_PLACE = ($0, $1, $2) => { - return VOID_ELEMENTS.test($1) ? $0 : ('<' + $1 + $2 + '>'); -}; - Object.defineProperty(exports, '__esModule', {value: true}).default = render; diff --git a/cjs/hyper/wire.js b/cjs/hyper/wire.js index be8eefa5..139eaaba 100644 --- a/cjs/hyper/wire.js +++ b/cjs/hyper/wire.js @@ -1,10 +1,10 @@ 'use strict'; -const {ELEMENT_NODE, SVG_NAMESPACE} = require('../shared/constants.js'); -const {WeakMap, trim} = require('../shared/poorlyfills.js'); -const {fragment} = require('../shared/easy-dom.js'); -const {append, slice, unique} = require('../shared/utils.js'); -const Wire = (m => m.__esModule ? m.default : m)(require('../classes/Wire.js')); -const render = (m => m.__esModule ? m.default : m)(require('./render.js')); +const WeakMap = (m => m.__esModule ? /* istanbul ignore next */ m.default : /* istanbul ignore next */ m)(require('@ungap/weakmap')); +const tta = (m => m.__esModule ? /* istanbul ignore next */ m.default : /* istanbul ignore next */ m)(require('@ungap/template-tag-arguments')); + +const Wire = (m => m.__esModule ? /* istanbul ignore next */ m.default : /* istanbul ignore next */ m)(require('hyperhtml-wire')); + +const {Tagger} = require('../objects/Updates.js'); // all wires used per each context const wires = new WeakMap; @@ -29,24 +29,15 @@ const wire = (obj, type) => obj == null ? // In few words, a wire content is like an invisible parent node // in charge of updating its content like a bound element would do. const content = type => { - let wire, container, content, template, updates; - return function (statics) { - statics = unique(statics); - let setup = template !== statics; - if (setup) { - template = statics; - content = fragment(document); - container = type === 'svg' ? - document.createElementNS(SVG_NAMESPACE, 'svg') : - content; - updates = render.bind(container); - } - updates.apply(null, arguments); - if (setup) { - if (type === 'svg') { - append(content, slice.call(container.childNodes)); - } - wire = wireContent(content); + let wire, tagger, template; + return function () { + const args = tta.apply(null, arguments); + if (template !== args[0]) { + template = args[0]; + tagger = new Tagger(type); + wire = wireContent(tagger.apply(tagger, args)); + } else { + tagger.apply(tagger, args); } return wire; }; @@ -63,34 +54,29 @@ const weakly = (obj, type) => { id = type.slice(i + 1); type = type.slice(0, i) || 'html'; } - if (!wire) wires.set(obj, wire = {}); + if (!wire) + wires.set(obj, wire = {}); return wire[id] || (wire[id] = content(type)); }; -// a document fragment loses its nodes as soon -// as it's appended into another node. -// This would easily lose wired content -// so that on a second render call, the parent -// node wouldn't know which node was there -// associated to the interpolation. -// To prevent hyperHTML to forget about wired nodes, -// these are either returned as Array or, if there's ony one entry, -// as single referenced node that won't disappear from the fragment. -// The initial fragment, at this point, would be used as unique reference. +// A document fragment loses its nodes +// as soon as it is appended into another node. +// This has the undesired effect of losing wired content +// on a second render call, because (by then) the fragment would be empty: +// no longer providing access to those sub-nodes that ultimately need to +// stay associated with the original interpolation. +// To prevent hyperHTML from forgetting about a fragment's sub-nodes, +// fragments are instead returned as an Array of nodes or, if there's only one entry, +// as a single referenced node which, unlike fragments, will indeed persist +// wire content throughout multiple renderings. +// The initial fragment, at this point, would be used as unique reference to this +// array of nodes or to this single referenced node. const wireContent = node => { const childNodes = node.childNodes; - const length = childNodes.length; - const wireNodes = []; - for (let i = 0; i < length; i++) { - let child = childNodes[i]; - if ( - child.nodeType === ELEMENT_NODE || - trim.call(child.textContent).length !== 0 - ) { - wireNodes.push(child); - } - } - return wireNodes.length === 1 ? wireNodes[0] : new Wire(wireNodes); + const {length} = childNodes; + return length === 1 ? + childNodes[0] : + (length ? new Wire(childNodes) : node); }; exports.content = content; diff --git a/cjs/index.d.ts b/cjs/index.d.ts deleted file mode 100644 index 02ce463a..00000000 --- a/cjs/index.d.ts +++ /dev/null @@ -1,3 +0,0 @@ -import hyper from ".."; -export * from '..'; -export default hyper; diff --git a/cjs/index.js b/cjs/index.js index e742253d..04ed734a 100644 --- a/cjs/index.js +++ b/cjs/index.js @@ -1,16 +1,16 @@ 'use strict'; /*! (c) Andrea Giammarchi (ISC) */ +const WeakMap = (m => m.__esModule ? /* istanbul ignore next */ m.default : /* istanbul ignore next */ m)(require('@ungap/weakmap')); +const WeakSet = (m => m.__esModule ? /* istanbul ignore next */ m.default : /* istanbul ignore next */ m)(require('@ungap/essential-weakset')); -const Component = (m => m.__esModule ? m.default : m)(require('./classes/Component.js')); +const diff = (m => m.__esModule ? /* istanbul ignore next */ m.default : /* istanbul ignore next */ m)(require('domdiff')); +const Component = (m => m.__esModule ? /* istanbul ignore next */ m.default : /* istanbul ignore next */ m)(require('./classes/Component.js')); const {setup} = require('./classes/Component.js'); -const Intent = (m => m.__esModule ? m.default : m)(require('./objects/Intent.js')); -const {observe} = require('./objects/Updates.js'); -const wire = (m => m.__esModule ? m.default : m)(require('./hyper/wire.js')); +const Intent = (m => m.__esModule ? /* istanbul ignore next */ m.default : /* istanbul ignore next */ m)(require('./objects/Intent.js')); +const {observe, Tagger} = require('./objects/Updates.js'); +const wire = (m => m.__esModule ? /* istanbul ignore next */ m.default : /* istanbul ignore next */ m)(require('./hyper/wire.js')); const {content, weakly} = require('./hyper/wire.js'); -const render = (m => m.__esModule ? m.default : m)(require('./hyper/render.js')); -const diff = (m => m.__esModule ? m.default : m)(require('./3rd/domdiff.js')); -const { WeakMap, WeakSet } = require('./shared/poorlyfills.js'); -const { G } = require('./shared/constants.js'); +const render = (m => m.__esModule ? /* istanbul ignore next */ m.default : /* istanbul ignore next */ m)(require('./hyper/render.js')); // all functions are self bound to the right context // you can do the following @@ -18,6 +18,7 @@ const { G } = require('./shared/constants.js'); // and use them right away: bind(node)`hello!`; const bind = context => render.bind(context); const define = Intent.define; +const tagger = Tagger.prototype; hyper.Component = Component; hyper.bind = bind; @@ -25,6 +26,7 @@ hyper.define = define; hyper.diff = diff; hyper.hyper = hyper; hyper.observe = observe; +hyper.tagger = tagger; hyper.wire = wire; // exported as shared utils @@ -32,7 +34,6 @@ hyper.wire = wire; // that don't necessarily need upfront polyfills // i.e. those still targeting IE hyper._ = { - global: G, WeakMap, WeakSet }; @@ -49,6 +50,7 @@ exports.define = define; exports.diff = diff; exports.hyper = hyper; exports.observe = observe; +exports.tagger = tagger; exports.wire = wire; // by default, hyperHTML is a smart function diff --git a/cjs/objects/Engine.js b/cjs/objects/Engine.js deleted file mode 100644 index b5195357..00000000 --- a/cjs/objects/Engine.js +++ /dev/null @@ -1,46 +0,0 @@ -'use strict'; -Object.defineProperty(exports, '__esModule', {value: true}).default = { - update: ( - utils, - liveNodes, liveStart, liveEnd, liveLength, - virtualNodes, virtualStart, virtualEnd /*, virtualLength */ - ) => { - const { splicer } = utils; - while (liveStart < liveEnd && virtualStart < virtualEnd) { - const liveValue = liveNodes[liveStart]; - const virtualValue = virtualNodes[virtualStart]; - const status = liveValue === virtualValue ? - 0 : (liveNodes.indexOf(virtualValue) < 0 ? 1 : -1); - // nodes can be either removed ... - if (status < 0) { - splicer.splice(liveStart, 1); - liveEnd--; - liveLength--; - } - // ... appended ... - else if (0 < status) { - splicer.splice(liveStart, 0, virtualValue); - liveStart++; - liveEnd++; - liveLength++; - virtualStart++; - } - // ... or ignored, since it's the same ... - else { - liveStart++; - virtualStart++; - } - } - if (liveStart < liveEnd) { - splicer.splice(liveStart, liveEnd - liveStart); - } - if (virtualStart < virtualEnd) { - splicer.splice.apply( - splicer, - [liveEnd, 0].concat( - virtualNodes.slice(virtualStart, virtualEnd) - ) - ); - } - } -}; \ No newline at end of file diff --git a/cjs/objects/Path.js b/cjs/objects/Path.js deleted file mode 100644 index aef883cf..00000000 --- a/cjs/objects/Path.js +++ /dev/null @@ -1,58 +0,0 @@ -'use strict'; -const { - COMMENT_NODE, - DOCUMENT_FRAGMENT_NODE, - ELEMENT_NODE -} = require('../shared/constants.js'); - -// every template literal interpolation indicates -// a precise target in the DOM the template is representing. -// `

some ${'content'}

` -// hyperHTML finds only once per template literal, -// hence once per entire application life-cycle, -// all nodes that are related to interpolations. -// These nodes are stored as indexes used to retrieve, -// once per upgrade, nodes that will change on each future update. -// A path example is [2, 0, 1] representing the operation: -// node.childNodes[2].childNodes[0].childNodes[1] -// Attributes are addressed via their owner node and their name. -const createPath = node => { - const path = []; - let parentNode; - switch (node.nodeType) { - case ELEMENT_NODE: - case DOCUMENT_FRAGMENT_NODE: - parentNode = node; - break; - case COMMENT_NODE: - parentNode = node.parentNode; - prepend(path, parentNode, node); - break; - default: - parentNode = node.ownerElement; - break; - } - for ( - node = parentNode; - (parentNode = parentNode.parentNode); - node = parentNode - ) { - prepend(path, parentNode, node); - } - return path; -}; - -const prepend = (path, parent, node) => { - path.unshift(path.indexOf.call(parent.childNodes, node)); -}; - -Object.defineProperty(exports, '__esModule', {value: true}).default = { - create: (type, node, name) => ({type, name, node, path: createPath(node)}), - find: (node, path) => { - const length = path.length; - for (let i = 0; i < length; i++) { - node = node.childNodes[path[i]]; - } - return node; - } -} diff --git a/cjs/objects/Style.js b/cjs/objects/Style.js deleted file mode 100644 index a11a1d64..00000000 --- a/cjs/objects/Style.js +++ /dev/null @@ -1,82 +0,0 @@ -'use strict'; -// from https://github.com/developit/preact/blob/33fc697ac11762a1cb6e71e9847670d047af7ce5/src/constants.js -const IS_NON_DIMENSIONAL = /acit|ex(?:s|g|n|p|$)|rph|ows|mnc|ntw|ine[ch]|zoo|^ord/i; - -// style is handled as both string and object -// even if the target is an SVG element (consistency) -Object.defineProperty(exports, '__esModule', {value: true}).default = (node, original, isSVG) => { - if (isSVG) { - const style = original.cloneNode(true); - style.value = ''; - node.setAttributeNode(style); - return update(style, isSVG); - } - return update(node.style, isSVG); -}; - -// the update takes care or changing/replacing -// only properties that are different or -// in case of string, the whole node -const update = (style, isSVG) => { - let oldType, oldValue; - return newValue => { - switch (typeof newValue) { - case 'object': - if (newValue) { - if (oldType === 'object') { - if (!isSVG) { - if (oldValue !== newValue) { - for (const key in oldValue) { - if (!(key in newValue)) { - style[key] = ''; - } - } - } - } - } else { - if (isSVG) - style.value = ''; - else - style.cssText = ''; - } - const info = isSVG ? {} : style; - for (const key in newValue) { - const value = newValue[key]; - const styleValue = typeof value === 'number' && - !IS_NON_DIMENSIONAL.test(key) ? - (value + 'px') : value; - if (/^--/.test(key)) - info.setProperty(key, styleValue); - else - info[key] = styleValue; - } - oldType = 'object'; - if (isSVG) - style.value = toStyle((oldValue = info)); - else - oldValue = newValue; - break; - } - default: - if (oldValue != newValue) { - oldType = 'string'; - oldValue = newValue; - if (isSVG) - style.value = newValue || ''; - else - style.cssText = newValue || ''; - } - break; - } - }; -}; - -const hyphen = /([^A-Z])([A-Z]+)/g; -const ized = ($0, $1, $2) => $1 + '-' + $2.toLowerCase(); -const toStyle = object => { - const css = []; - for (const key in object) { - css.push(key.replace(hyphen, ized), ':', object[key], ';'); - } - return css.join(''); -}; \ No newline at end of file diff --git a/cjs/objects/Updates.js b/cjs/objects/Updates.js index f4a55cea..0df2e324 100644 --- a/cjs/objects/Updates.js +++ b/cjs/objects/Updates.js @@ -1,196 +1,77 @@ 'use strict'; +const CustomEvent = (m => m.__esModule ? /* istanbul ignore next */ m.default : /* istanbul ignore next */ m)(require('@ungap/custom-event')); +const WeakSet = (m => m.__esModule ? /* istanbul ignore next */ m.default : /* istanbul ignore next */ m)(require('@ungap/essential-weakset')); +const isArray = (m => m.__esModule ? /* istanbul ignore next */ m.default : /* istanbul ignore next */ m)(require('@ungap/is-array')); +const createContent = (m => m.__esModule ? /* istanbul ignore next */ m.default : /* istanbul ignore next */ m)(require('@ungap/create-content')); + +const disconnected = (m => m.__esModule ? /* istanbul ignore next */ m.default : /* istanbul ignore next */ m)(require('disconnected')); +const domdiff = (m => m.__esModule ? /* istanbul ignore next */ m.default : /* istanbul ignore next */ m)(require('domdiff')); +const domtagger = (m => m.__esModule ? /* istanbul ignore next */ m.default : /* istanbul ignore next */ m)(require('domtagger')); +const hyperStyle = (m => m.__esModule ? /* istanbul ignore next */ m.default : /* istanbul ignore next */ m)(require('hyperhtml-style')); +const Wire = (m => m.__esModule ? /* istanbul ignore next */ m.default : /* istanbul ignore next */ m)(require('hyperhtml-wire')); + const { - CONNECTED, DISCONNECTED, COMMENT_NODE, DOCUMENT_FRAGMENT_NODE, ELEMENT_NODE, TEXT_NODE, OWNER_SVG_ELEMENT, SHOULD_USE_TEXT_CONTENT, G, UID, UIDC + CONNECTED, DISCONNECTED, DOCUMENT_FRAGMENT_NODE, OWNER_SVG_ELEMENT } = require('../shared/constants.js'); -const Component = (m => m.__esModule ? m.default : m)(require('../classes/Component.js')); -const Wire = (m => m.__esModule ? m.default : m)(require('../classes/Wire.js')); -const Path = (m => m.__esModule ? m.default : m)(require('./Path.js')); -const Style = (m => m.__esModule ? m.default : m)(require('./Style.js')); -const Intent = (m => m.__esModule ? m.default : m)(require('./Intent.js')); -const domdiff = (m => m.__esModule ? m.default : m)(require('../3rd/domdiff.js')); -// see /^script$/i.test(nodeName) bit down here -// import { create as createElement, text } from '../shared/easy-dom.js'; -const { text } = require('../shared/easy-dom.js'); -const { Event, WeakSet, isArray, trim } = require('../shared/poorlyfills.js'); -const { createFragment, slice } = require('../shared/utils.js'); -const disconnected = (m => m.__esModule ? m.default : m)(require('../3rd/disconnected.js')); +const Component = (m => m.__esModule ? /* istanbul ignore next */ m.default : /* istanbul ignore next */ m)(require('../classes/Component.js')); +const Intent = (m => m.__esModule ? /* istanbul ignore next */ m.default : /* istanbul ignore next */ m)(require('./Intent.js')); + +const componentType = Component.prototype.nodeType; +const wireType = Wire.prototype.nodeType; -const { document } = G; -const observe = disconnected({Event, WeakSet}); +const observe = disconnected({Event: CustomEvent, WeakSet}); -// a basic dictionary used to filter already cached attributes -// while looking for special hyperHTML values. -function Cache() {} -Cache.prototype = Object.create(null); +exports.Tagger = Tagger; +exports.observe = observe; // returns an intent to explicitly inject content as html const asHTML = html => ({html}); // returns nodes from wires and components const asNode = (item, i) => { - return 'ELEMENT_NODE' in item ? - item : - (item.constructor === Wire ? + switch (item.nodeType) { + case wireType: // in the Wire case, the content can be // removed, post-pended, inserted, or pre-pended and // all these cases are handled by domdiff already /* istanbul ignore next */ - ((1 / i) < 0 ? - (i ? item.remove() : item.last) : - (i ? item.valueOf(true) : item.first)) : - asNode(item.render(), i)); + return (1 / i) < 0 ? + (i ? item.remove(true) : item.lastChild) : + (i ? item.valueOf(true) : item.firstChild); + case componentType: + return asNode(item.render(), i); + default: + return item; + } } // returns true if domdiff can handle the value -const canDiff = value => 'ELEMENT_NODE' in value || -value instanceof Wire || -value instanceof Component; - -// updates are created once per context upgrade -// within the main render function (../hyper/render.js) -// These are an Array of callbacks to invoke passing -// each interpolation value. -// Updates can be related to any kind of content, -// attributes, or special text-only cases such + - +

results in console

diff --git a/test/ie/test/test.js b/test/ie/test/test.js index deb5108b..0b3662a0 100644 --- a/test/ie/test/test.js +++ b/test/ie/test/test.js @@ -1,1457 +1,3051 @@ -var _createClass = function () { function defineProperties(target, props) { for (var i = 0; i < props.length; i++) { var descriptor = props[i]; descriptor.enumerable = descriptor.enumerable || false; descriptor.configurable = true; if ("value" in descriptor) descriptor.writable = true; Object.defineProperty(target, descriptor.key, descriptor); } } return function (Constructor, protoProps, staticProps) { if (protoProps) defineProperties(Constructor.prototype, protoProps); if (staticProps) defineProperties(Constructor, staticProps); return Constructor; }; }(); - -var _templateObject = _taggedTemplateLiteral(['\n

\n Time: ', '\n

\n '], ['\n

\n Time: ', '\n

\n ']), - _templateObject2 = _taggedTemplateLiteral(['

', ' world

'], ['

', ' world

']), - _templateObject3 = _taggedTemplateLiteral(['

', '

'], ['

', '

']), - _templateObject4 = _taggedTemplateLiteral(['click'], ['click']), - _templateObject5 = _taggedTemplateLiteral(['how cool'], ['how cool']), - _templateObject6 = _taggedTemplateLiteral(['\n

1

\n

2

\n '], ['\n

1

\n

2

\n ']), - _templateObject7 = _taggedTemplateLiteral(['\n

1

\n

2

\n

3

\n '], ['\n

1

\n

2

\n

3

\n ']), - _templateObject8 = _taggedTemplateLiteral(['

OK

'], ['

OK

']), - _templateObject9 = _taggedTemplateLiteral(['\n

1

\n '], ['\n

1

\n ']), - _templateObject10 = _taggedTemplateLiteral(['\n 0\n

1

\n '], ['\n 0\n

1

\n ']), - _templateObject11 = _taggedTemplateLiteral(['', ''], ['', '']), - _templateObject12 = _taggedTemplateLiteral(['a'], ['a']), - _templateObject13 = _taggedTemplateLiteral(['\n O'], ['\n O']), - _templateObject14 = _taggedTemplateLiteral(['\n
\n \n
'], ['\n
\n \n
']), - _templateObject15 = _taggedTemplateLiteral(['\n
  • ', '
  • \n '], ['\n
  • ', '
  • \n ']), - _templateObject16 = _taggedTemplateLiteral(['
    ', '
    '], ['
    ', '
    ']), - _templateObject17 = _taggedTemplateLiteral([''], ['']), - _templateObject18 = _taggedTemplateLiteral(['

    '], ['

    ']), - _templateObject19 = _taggedTemplateLiteral(['

    ', '

    ', '
    ', '
    ', ''], ['

    ', '

    ', '
    ', '
    ', '']), - _templateObject20 = _taggedTemplateLiteral([''], ['']), - _templateObject21 = _taggedTemplateLiteral(['
    ', ''], ['
    ', '']), - _templateObject22 = _taggedTemplateLiteral(['', '
    '], ['', '
    ']), - _templateObject23 = _taggedTemplateLiteral([''], ['']), - _templateObject24 = _taggedTemplateLiteral(['a=', ''], ['a=', '']), - _templateObject25 = _taggedTemplateLiteral(['[', ']'], ['[', ']']), - _templateObject26 = _taggedTemplateLiteral(['

    '], ['

    ']), - _templateObject27 = _taggedTemplateLiteral(['
    ', '
    '], ['
    ', '
    ']), - _templateObject28 = _taggedTemplateLiteral([''], ['']), - _templateObject29 = _taggedTemplateLiteral([''], ['']), - _templateObject30 = _taggedTemplateLiteral([''], ['']), - _templateObject31 = _taggedTemplateLiteral(['ok'], ['ok']), - _templateObject32 = _taggedTemplateLiteral(['
    ', '
    '], ['
    ', '
    ']), - _templateObject33 = _taggedTemplateLiteral([''], ['']), - _templateObject34 = _taggedTemplateLiteral(['

    '], ['

    ']), - _templateObject35 = _taggedTemplateLiteral(['

    ', '

    '], ['

    ', '

    ']), - _templateObject36 = _taggedTemplateLiteral([''], ['']), - _templateObject37 = _taggedTemplateLiteral(['

    '], ['

    ']), - _templateObject38 = _taggedTemplateLiteral([''], ['']), - _templateObject39 = _taggedTemplateLiteral([''], ['']), - _templateObject40 = _taggedTemplateLiteral(['\n '], ['\n ']), - _templateObject41 = _taggedTemplateLiteral(['\n
    First name: ', '
    \n

    '], ['\n
    First name: ', '
    \n

    ']), - _templateObject42 = _taggedTemplateLiteral(['\n

    ', ''], ['\n

    ', '']), - _templateObject43 = _taggedTemplateLiteral(['\n

    ', ''], ['\n

    ', '']), - _templateObject44 = _taggedTemplateLiteral([''], ['']), - _templateObject45 = _taggedTemplateLiteral(['

    '], ['

    ']), - _templateObject46 = _taggedTemplateLiteral(['

    '], ['

    ']), - _templateObject47 = _taggedTemplateLiteral(['a ', ''], ['a ', '']), - _templateObject48 = _taggedTemplateLiteral(['

    any content

    '], ['

    any content

    ']), - _templateObject49 = _taggedTemplateLiteral([''], ['']), - _templateObject50 = _taggedTemplateLiteral(['abc'], ['abc']), - _templateObject51 = _taggedTemplateLiteral(['

    a', 'c

    '], ['

    a', 'c

    ']), - _templateObject52 = _taggedTemplateLiteral(['a', 'c'], ['a', 'c']), - _templateObject53 = _taggedTemplateLiteral([''], ['']), - _templateObject54 = _taggedTemplateLiteral(['
    abc
    '], ['
    abc
    ']), - _templateObject55 = _taggedTemplateLiteral(['\n '], ['\n ']), - _templateObject56 = _taggedTemplateLiteral(['\n '], ['\n ']), - _templateObject57 = _taggedTemplateLiteral(['\n

    hello

    '], ['\n

    hello

    ']), - _templateObject58 = _taggedTemplateLiteral(['\n

    hello

    '], ['\n

    hello

    ']), - _templateObject59 = _taggedTemplateLiteral(['
    \n \n
    '], ['
    \n \n
    ']), - _templateObject60 = _taggedTemplateLiteral(['
      \n ', '\n
    '], ['
      \n ', '\n
    ']), - _templateObject61 = _taggedTemplateLiteral(['
  • ', '
  • '], ['
  • ', '
  • ']), - _templateObject62 = _taggedTemplateLiteral(['\n

    hello

    '], ['\n

    hello

    ']), - _templateObject63 = _taggedTemplateLiteral(['

    '], ['

    ']), - _templateObject64 = _taggedTemplateLiteral(['
    '], ['
    ']), - _templateObject65 = _taggedTemplateLiteral(['
    \n \n
    '], ['
    \n \n
    ']), - _templateObject66 = _taggedTemplateLiteral(['\n
    \n \n \n \n \n
    \n '], ['\n
    \n \n \n \n \n
    \n ']), - _templateObject67 = _taggedTemplateLiteral(['\n
    \n