bdom-keep-order
Advanced tools
Comparing version 0.1.4 to 0.1.6
254
index.js
@@ -10,5 +10,6 @@ 'use strict'; | ||
exports.keepOnParentStart = keepOnParentStart; | ||
exports.keepOnParentEnd = keepOnParentEnd; | ||
exports.keepBeforeSibling = keepBeforeSibling; | ||
exports.keepAfterSibling = keepAfterSibling; | ||
exports.mapElementsIterator = mapElementsIterator; | ||
var _marked = /*#__PURE__*/regeneratorRuntime.mark(mapElementsIterator); | ||
var doc = window.document; | ||
@@ -20,6 +21,7 @@ var ELEMENT_NODE = doc.ELEMENT_NODE; | ||
var domNodeError = 'Each map should be a appendable dom node or an array with a condition as the first item ' + ' and appendable dom nodes as subsequent items'; | ||
// This tool uses a single document fragment which makes it strictly | ||
// synchronous. If you need to use this tool asynchronously, you are | ||
// either doing something wrong or you have the wrong tool | ||
var fragment = doc.createDocumentFragment(); | ||
@@ -29,98 +31,80 @@ | ||
validateParams(parent, maps); | ||
// reverse the map so we can run an optimized loop | ||
maps = maps.reverse(); | ||
return function parentStartKeeper(input) { | ||
var lastInDom = void 0; | ||
var addAfterSibling = void 0; | ||
var i = maps.length; | ||
while (i--) { | ||
lastInDom = removeAndPopulateFragment(parent, input, maps[i]); | ||
if (addAfterSibling) { | ||
parent.insertBefore(fragment, addAfterSibling.nextSibling); | ||
} else { | ||
parent.insertBefore(fragment, parent.firstChild); | ||
validateParent(parent); | ||
validateMaps(maps); | ||
var keeper = { | ||
parent: parent, | ||
maps: maps, | ||
keep: function keep(input) { | ||
var lastInDom = void 0; | ||
var addAfterSibling = void 0; | ||
var i = keeper.maps.length; | ||
for (var _i = 0; _i < keeper.maps.length; _i++) { | ||
lastInDom = removeAndPopulateFragment(parent, input, keeper.maps[_i]); | ||
if (lastInDom) { | ||
if (addAfterSibling) { | ||
parent.insertBefore(fragment, addAfterSibling.nextSibling); | ||
} else { | ||
parent.insertBefore(fragment, parent.firstChild); | ||
} | ||
addAfterSibling = lastInDom || addAfterSibling; | ||
} | ||
} | ||
addAfterSibling = lastInDom || addAfterSibling; | ||
} | ||
}; | ||
} | ||
}, | ||
reset: function reset(newMaps) { | ||
validateMaps(newMaps); | ||
function keepOnParentEnd(parent, maps) { | ||
var oldEls = mapElementsIterator(keeper.maps); | ||
var newEls = mapElementsIterator(newMaps); | ||
validateParams(parent, maps); | ||
// reverse the map so we can run an optimized loop | ||
maps = maps.reverse(); | ||
return function parentEndKeeper(input) { | ||
var lastInDom = void 0; | ||
var addAfterSibling = void 0; | ||
var i = maps.length; | ||
while (i--) { | ||
lastInDom = removeAndPopulateFragment(parent, input, maps[i]); | ||
if (addAfterSibling) { | ||
parent.insertBefore(fragment, addAfterSibling.nextSibling); | ||
} else { | ||
parent.appendChild(fragment); | ||
var oldRes = void 0; | ||
var newRes = void 0; | ||
for (newRes = newEls.next(); !newRes.done; newRes = newEls.next()) { | ||
if (!doc.contains(newRes.value)) { | ||
continue; | ||
} | ||
for (oldRes = oldEls.next(); !oldRes.done && !oldRes.value.isEqualNode(newRes.value); oldRes = oldEls.next()) { | ||
if (doc.contains(oldRes.value)) { | ||
parent.removeChild(oldRes.value); | ||
} | ||
} | ||
if (oldRes.done) { | ||
break; | ||
} | ||
} | ||
addAfterSibling = lastInDom || addAfterSibling; | ||
keeper.maps = newMaps; | ||
} | ||
}; | ||
} | ||
function keepBeforeSibling(sibling, maps) { | ||
if (!sibling || !(sibling instanceof Element) && sibling.nodeType !== ELEMENT_NODE) { | ||
throw new Error('The sibling node needs to be an element'); | ||
} | ||
var parent = sibling.parentNode; | ||
validateParams(parent, maps); | ||
// reverse the map so we can run an optimized loop | ||
maps = maps.reverse(); | ||
return function beforeSiblingKeeper(input) { | ||
var i = maps.length; | ||
while (i--) { | ||
removeAndPopulateFragment(parent, input, maps[i]); | ||
parent.insertBefore(fragment, sibling); | ||
} | ||
}; | ||
return keeper; | ||
} | ||
function keepAfterSibling(sibling, maps) { | ||
if (!sibling || !(sibling instanceof Element) && sibling.nodeType !== ELEMENT_NODE) { | ||
throw new Error('The sibling node needs to be an element'); | ||
} | ||
var parent = sibling.parentNode; | ||
validateParams(parent, maps); | ||
// no need to reverse the map here, because we can add in reverse order | ||
return function afterSiblingKeeper(input) { | ||
var i = maps.length; | ||
while (i--) { | ||
removeAndPopulateFragment(parent, input, maps[i]); | ||
parent.insertBefore(fragment, sibling.nextSibling); | ||
} | ||
}; | ||
} | ||
function removeAndPopulateFragment(parent, input, _ref) { | ||
var condition = _ref.condition, | ||
elements = _ref.elements; | ||
var removableElement = void 0; | ||
function removeAndPopulateFragment(parent, input, map) { | ||
var lastElementInDom = void 0; | ||
var i = elements.length; | ||
if (match(condition, input)) { | ||
while (i--) { | ||
lastElementInDom = elements[i]; | ||
if (!doc.contains(lastElementInDom)) { | ||
fragment.appendChild(lastElementInDom); | ||
} | ||
if (map instanceof Node || typeof map.nodeType === 'number') { | ||
lastElementInDom = map; | ||
// this element should always be connected | ||
if (!doc.contains(map)) { | ||
fragment.appendChild(map); | ||
} | ||
} else if (!map || (typeof map === 'undefined' ? 'undefined' : _typeof(map)) !== 'object' || typeof map.length !== 'number') { | ||
throw new Error(domNodeError); | ||
} else { | ||
while (i--) { | ||
removableElement = elements[i]; | ||
if (doc.contains(removableElement)) { | ||
parent.removeChild(removableElement); | ||
var removableElement = void 0; | ||
var i = 1; | ||
if (match(map[0], input)) { | ||
for (; i < map.length; i++) { | ||
lastElementInDom = map[i]; | ||
if (!doc.contains(lastElementInDom)) { | ||
fragment.appendChild(lastElementInDom); | ||
} | ||
} | ||
} else { | ||
for (; i < map.length; i++) { | ||
removableElement = map[i]; | ||
if (doc.contains(removableElement)) { | ||
parent.removeChild(removableElement); | ||
} | ||
} | ||
} | ||
@@ -132,35 +116,12 @@ } | ||
function validateParams(parent, maps) { | ||
// validate parameters | ||
function validateParent(parent) { | ||
if (!parent || !(parent instanceof Element) && parent.nodeType !== ELEMENT_NODE) { | ||
throw new Error('The parent node needs to be an element'); | ||
} | ||
} | ||
function validateMaps(maps) { | ||
if (!maps || (typeof maps === 'undefined' ? 'undefined' : _typeof(maps)) !== 'object' || typeof maps.length !== 'number') { | ||
throw new Error('maps needs to be an array of mapping arrays'); | ||
} | ||
var map = void 0; | ||
var elements = void 0; | ||
var condition = void 0; | ||
var i = maps.length; | ||
while (i--) { | ||
map = maps[i]; | ||
if (map instanceof Node || typeof map.nodeType === 'number') { | ||
maps[i] = { | ||
// this element should always be connected | ||
condition: true, | ||
elements: [map] | ||
}; | ||
} else if (!map || (typeof map === 'undefined' ? 'undefined' : _typeof(map)) !== 'object' || typeof map.length !== 'number') { | ||
throw new Error('Each map should be an array with a condition as the first item ' + ' and appendable dom nodes as subsequent items'); | ||
} else { | ||
maps[i] = { | ||
// remove the first item and place it as the condition | ||
condition: map.splice(0, 1)[0], | ||
// reverse the elements list for optimal looping | ||
elements: map.reverse() | ||
}; | ||
} | ||
} | ||
} | ||
@@ -177,1 +138,68 @@ | ||
} | ||
function mapElementsIterator(maps) { | ||
var map, mi, ei; | ||
return regeneratorRuntime.wrap(function mapElementsIterator$(_context) { | ||
while (1) { | ||
switch (_context.prev = _context.next) { | ||
case 0: | ||
map = void 0; | ||
mi = 0; | ||
case 2: | ||
if (!(mi < maps.length)) { | ||
_context.next = 23; | ||
break; | ||
} | ||
map = maps[mi]; | ||
if (!(map instanceof Node || typeof map.nodeType === 'number')) { | ||
_context.next = 9; | ||
break; | ||
} | ||
_context.next = 7; | ||
return map; | ||
case 7: | ||
_context.next = 20; | ||
break; | ||
case 9: | ||
if (!(!map || (typeof map === 'undefined' ? 'undefined' : _typeof(map)) !== 'object' || typeof map.length !== 'number')) { | ||
_context.next = 13; | ||
break; | ||
} | ||
throw new Error(domNodeError); | ||
case 13: | ||
ei = 1; | ||
case 14: | ||
if (!(ei < map.length)) { | ||
_context.next = 20; | ||
break; | ||
} | ||
_context.next = 17; | ||
return map[ei]; | ||
case 17: | ||
ei++; | ||
_context.next = 14; | ||
break; | ||
case 20: | ||
mi++; | ||
_context.next = 2; | ||
break; | ||
case 23: | ||
case 'end': | ||
return _context.stop(); | ||
} | ||
} | ||
}, _marked, this); | ||
} |
{ | ||
"name": "bdom-keep-order", | ||
"version": "0.1.4", | ||
"version": "0.1.6", | ||
"description": "add/remove child/sibling elements on conditions and keep them in original order ", | ||
@@ -5,0 +5,0 @@ "main": "index.js", |
@@ -13,5 +13,12 @@ # bdom-keep-order - a tool to add/remove sibling elements whilst keeping them in order | ||
... and if you need to support browsers that don't support generator functions you need to install babel polyfill | ||
```bash | ||
npm install --save babel-polyfill | ||
``` | ||
## Usage | ||
```js | ||
import { keepOnParentStart } from 'bdom-keep-order' | ||
// uncomment the line below if you need to polyfill generator function support | ||
// import 'babel-polyfill' | ||
@@ -21,3 +28,3 @@ const parent = document.createElement('ul') | ||
this.keeper = keepOnParentStart(parent, [ | ||
const children = [ | ||
[ show => show === 'show a', document.createTextNode('SHOWING A') ], | ||
@@ -27,6 +34,6 @@ [ show => show === 'show b', document.createTextNode('SHOWING B') ], | ||
document.createTextNode('SHOW ON A AND B') ], | ||
document.createTextNode('Always show this'), | ||
]) | ||
] | ||
this.keeper = keepOnParentStart(parent, children) | ||
this.keeper('show a') | ||
this.keeper.keep('show a') | ||
// SHOWING A | ||
@@ -36,3 +43,3 @@ // SHOW ON A AND B | ||
this.keeper('show b') | ||
this.keeper.keep('show b') | ||
// SHOWING B | ||
@@ -42,5 +49,26 @@ // SHOW ON A AND B | ||
this.keeper('show z') | ||
this.keeper.keep('show z') | ||
// Always show this | ||
children.pop() | ||
this.keeper.keep('show a') | ||
// SHOWING A | ||
// SHOW ON A AND B | ||
const reorderedChildren = [ | ||
children[2], | ||
children[1], | ||
children[0], | ||
document.createTextNode("I'm new!"), | ||
] | ||
// reset will try and perform the reordering of the nodes with minimal dom edits | ||
this.keeper.reset(reorderedChildren) | ||
// you will need to call keep after reset to see the expected result | ||
this.keeper.keep('show a') | ||
// SHOW ON A AND B | ||
// SHOWING A | ||
// I'm new! | ||
``` | ||
@@ -47,0 +75,0 @@ |
8601
167
79