Skip to content
This repository has been archived by the owner on Jun 21, 2023. It is now read-only.

Commit

Permalink
fixes for internet explorer and windows
Browse files Browse the repository at this point in the history
  • Loading branch information
gr0uch committed Feb 25, 2017
1 parent ad627a5 commit bbb3724
Show file tree
Hide file tree
Showing 14 changed files with 115 additions and 90 deletions.
5 changes: 5 additions & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
@@ -1,6 +1,11 @@
# Changelog


### 2.0.2 (2017-02-25)
- Fix: IE11 compatibility problems.
- Fix: Windows scripting compatibility.


### 2.0.1 (2017-01-09)
- Polish: include `dist/*.js` in package.

Expand Down
1 change: 0 additions & 1 deletion README.md
Original file line number Diff line number Diff line change
Expand Up @@ -187,7 +187,6 @@ When a bound key is assigned, it gets internally casted into an array if it is n
This library makes use of these JavaScript features:

- **Object.defineProperty** (ES5): used for binding keys on objects.
- **Object.freeze** (ES5.1): used to prevent internal state from being mutated.
- **WeakMap** (ES6): memory efficient mapping of DOM nodes.

It also makes use of these DOM API features:
Expand Down
21 changes: 11 additions & 10 deletions lib/bind_keys.js
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,7 @@
var processNodes = require('./process_nodes')
var keyMap = require('./key_map')

var markerMap = processNodes.markerMap
var markerKey = keyMap.marker
var hasDefinitionKey = keyMap.hasDefinition
var isBoundToParentKey = keyMap.isBoundToParent
var replaceAttributeKey = keyMap.replaceAttribute
Expand Down Expand Up @@ -69,7 +69,8 @@ function bindKeys (scope, obj, def, parentNode, path) {
}


// This is an internal function, the arguments aren't pretty.
// This is an internal function that's used for defining the getters and
// setters.
function bindKey (scope, obj, def, key, parentNode) {
var memo = storeMemo.get(obj)
var meta = storeMeta.get(obj)[key]
Expand Down Expand Up @@ -123,7 +124,7 @@ function bindKey (scope, obj, def, key, parentNode) {
}

function setter (x) {
var marker = markerMap.get(branch)
var marker = branch[markerKey]
var value, currentNode
var a, b, i, j

Expand All @@ -146,7 +147,7 @@ function bindKey (scope, obj, def, key, parentNode) {
if (value.length !== previousValues.length)
previousValues.length = activeNodes.length = value.length

// Assign array mutator methods.
// Assign array mutator methods if we get an array.
if (valueIsArray) {
// Some mutators such as `sort`, `reverse`, `fill`, `copyWithin` are
// not present here. That is because they trigger the array index
Expand Down Expand Up @@ -176,7 +177,7 @@ function bindKey (scope, obj, def, key, parentNode) {
Object.defineProperty(array, i, {
get: function () { return value },
set: function (x) {
var marker = markerMap.get(branch)
var marker = branch[markerKey]
var a, b, currentNode

value = x
Expand All @@ -195,7 +196,7 @@ function bindKey (scope, obj, def, key, parentNode) {
}

function removeNode (value, previousValue, i) {
var marker = markerMap.get(branch)
var marker = branch[markerKey]
var activeNode = activeNodes[i]
var returnValue

Expand Down Expand Up @@ -231,7 +232,7 @@ function bindKey (scope, obj, def, key, parentNode) {
if (value === void 0) value = null
if (previousValue === void 0) previousValue = null

// If value is null, just remove it.
// If value is null, just remove the Node.
if (value === null) {
removeNode(null, previousValue, i)
return null
Expand Down Expand Up @@ -299,7 +300,7 @@ function bindKey (scope, obj, def, key, parentNode) {
}

function push () {
var marker = markerMap.get(branch)
var marker = branch[markerKey]
var i = this.length
var j = i + arguments.length
var currentNode
Expand Down Expand Up @@ -327,7 +328,7 @@ function bindKey (scope, obj, def, key, parentNode) {
}

function unshift () {
var marker = markerMap.get(branch)
var marker = branch[markerKey]
var i = this.length
var j, k, currentNode

Expand All @@ -350,7 +351,7 @@ function bindKey (scope, obj, def, key, parentNode) {
}

function splice (start, count) {
var marker = markerMap.get(branch)
var marker = branch[markerKey]
var insert = []
var i, j, k, value, currentNode

Expand Down
18 changes: 1 addition & 17 deletions lib/feature_check.js
Original file line number Diff line number Diff line change
@@ -1,29 +1,13 @@
'use strict'


module.exports = featureCheck


/**
* Check if capabilities are available, or throw an error.
*
* @param {*} globalScope
*/
function featureCheck (globalScope) {
var features = [
// ECMAScript features.
[ Object, 'defineProperty' ],
[ Object, 'freeze' ],
[ Object, 'isFrozen' ],
[ WeakMap ],

// DOM features.
[ 'document', 'createTreeWalker' ],
[ 'Node', 'prototype', 'contains' ],
[ 'Node', 'prototype', 'insertBefore' ],
[ 'Node', 'prototype', 'isEqualNode' ],
[ 'Node', 'prototype', 'removeChild' ]
]
function featureCheck (globalScope, features) {
var i, j, k, l, feature, path

for (i = 0, j = features.length; i < j; i++) {
Expand Down
8 changes: 4 additions & 4 deletions lib/helpers.js
Original file line number Diff line number Diff line change
Expand Up @@ -20,13 +20,13 @@ function bindEvents (events, useCapture) {
return function (node, value, previousValue, path) {
var key

if (value == null)
if (value === null)
for (key in events)
// The point of removing event listeners here is not manual memory
// management, but to ensure that after the value has been unset, it
// no longer triggers events.
node.removeEventListener(key, listeners[key], useCapture)
else if (previousValue == null)
else if (previousValue === null)
for (key in events) {
listeners[key] = makeEventListener(events[key], path)
node.addEventListener(key, listeners[key], useCapture)
Expand All @@ -47,7 +47,7 @@ function animate (insertClass, mutateClass, removeClass, retainTime) {

if (!('classList' in node)) return void 0

if (value == null) {
if (value === null) {
if (insertClass) node.classList.remove(insertClass)
if (removeClass) node.classList.add(removeClass)
if (retainTime) {
Expand All @@ -68,7 +68,7 @@ function animate (insertClass, mutateClass, removeClass, retainTime) {

node.classList.add(mutateClass)
}
else if (previousValue == null && insertClass)
else if (previousValue === null && insertClass)
// Trigger class addition after the element is inserted.
if (hasMutationObserver && hasDocument &&
!document.documentElement.contains(node)) {
Expand Down
31 changes: 22 additions & 9 deletions lib/index.js
Original file line number Diff line number Diff line change
Expand Up @@ -13,6 +13,7 @@ var hasDefinitionKey = keyMap.hasDefinition
var replaceAttributeKey = keyMap.replaceAttribute
var isBoundToParentKey = keyMap.isBoundToParent
var isProcessedKey = keyMap.isProcessed
var markerKey = keyMap.marker

// Element tag names which should have value replaced.
var replaceValue = [ 'INPUT', 'TEXTAREA', 'PROGRESS' ]
Expand Down Expand Up @@ -53,7 +54,20 @@ function simulacra (obj, def, matchNode) {
var Node = this ? this.Node : window.Node
var node, query

featureCheck(this || window)
// Before continuing, check if required features are present.
featureCheck(this || window, [
// ECMAScript features.
[ Object, 'defineProperty' ],
[ WeakMap ],

// DOM features. Missing `contains` since apparently it is not on
// the Node.prototype in Internet Explorer.
[ 'document', 'createTreeWalker' ],
[ 'Node', 'prototype', 'cloneNode' ],
[ 'Node', 'prototype', 'insertBefore' ],
[ 'Node', 'prototype', 'isEqualNode' ],
[ 'Node', 'prototype', 'removeChild' ]
])

if (obj === null || typeof obj !== 'object' || isArray(obj))
throw new TypeError('First argument must be a singular object.')
Expand All @@ -76,7 +90,7 @@ function simulacra (obj, def, matchNode) {
if ('content' in def[0]) def[0] = def[0].content

ensureNodes(this, def[0], def[1])
setFrozen(def)
setProperties(def)
}

node = processNodes(this, def[0], def[1])
Expand Down Expand Up @@ -168,7 +182,7 @@ function ensureNodes (scope, parentNode, def) {
setReplaceAttribute(branch, boundNode)
else console.warn( // eslint-disable-line
'A change function was not defined on the key "' + key + '".')
setFrozen(branch)
setProperties(branch)
continue
}

Expand All @@ -180,12 +194,12 @@ function ensureNodes (scope, parentNode, def) {

if (branch[hasDefinitionKey]) {
ensureNodes(scope, boundNode, branch[1])
setFrozen(branch)
setProperties(branch)
continue
}

setReplaceAttribute(branch, boundNode)
setFrozen(branch)
setProperties(branch)
}

// Need to loop again to invalidate containment in adjacent nodes, after the
Expand All @@ -200,8 +214,7 @@ function ensureNodes (scope, parentNode, def) {
'element for the adjacent key "' + adjacentNodes[i][0] + '".')
}

// Freeze the definition.
setFrozen(def)
setProperties(def)
}


Expand All @@ -214,7 +227,7 @@ function setReplaceAttribute (branch, boundNode) {
}


function setFrozen (obj) {
function setProperties (obj) {
Object.defineProperty(obj, isProcessedKey, { value: true })
Object.freeze(obj)
Object.defineProperty(obj, markerKey, { value: null, writable: true })
}
1 change: 1 addition & 0 deletions lib/key_map.js
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,7 @@ var keys = [
'hasDefinition',
'isBoundToParent',
'isProcessed',
'marker',
'replaceAttribute',
'retainElement'
]
Expand Down
28 changes: 19 additions & 9 deletions lib/process_nodes.js
Original file line number Diff line number Diff line change
Expand Up @@ -4,17 +4,19 @@
var keyMap = require('./key_map')

var isBoundToParentKey = keyMap.isBoundToParent

// Map from definition branches to marker nodes. This is necessary because the
// definitions are frozen and cannot be written to.
var markerMap = processNodes.markerMap = new WeakMap()
var markerKey = keyMap.marker

// Internal map from already processed definitions to ready-to-use nodes.
var templateMap = new WeakMap()

// A fixed constant for `NodeFilter.SHOW_ALL`.
var whatToShow = 0xFFFFFFFF

// Option to use comment nodes as markers.
processNodes.useCommentNode = false

// Avoiding duplication of compatibility hack.
processNodes.acceptNode = acceptNode

module.exports = processNodes

Expand Down Expand Up @@ -57,7 +59,7 @@ function processNodes (scope, node, def) {
else marker = parent.insertBefore(
document.createTextNode(''), mirrorNode)

markerMap.set(branch, marker)
branch[markerKey] = marker

parent.removeChild(mirrorNode)
}
Expand All @@ -73,15 +75,16 @@ function processNodes (scope, node, def) {
i = 0
j = 0

treeWalker = document.createTreeWalker(node)
treeWalker = document.createTreeWalker(
node, whatToShow, acceptNode, false)

for (key in def) {
branch = def[key]
if (branch[isBoundToParentKey]) continue

while (treeWalker.nextNode()) {
if (i === indices[j]) {
markerMap.set(branch, treeWalker.currentNode)
branch[markerKey] = treeWalker.currentNode
i++
break
}
Expand All @@ -106,7 +109,8 @@ function processNodes (scope, node, def) {
*/
function matchNodes (scope, node, def) {
var document = scope ? scope.document : window.document
var treeWalker = document.createTreeWalker(node)
var treeWalker = document.createTreeWalker(
node, whatToShow, acceptNode, false)
var map = new WeakMap()
var nodes = []
var i, j, key, currentNode, childWalker
Expand All @@ -128,7 +132,8 @@ function matchNodes (scope, node, def) {
node: treeWalker.currentNode
})
if (processNodes.useCommentNode) offset++
childWalker = document.createTreeWalker(currentNode)
childWalker = document.createTreeWalker(
currentNode, whatToShow, acceptNode, false)
while (childWalker.nextNode()) offset--
nodes.splice(i, 1)
break
Expand All @@ -140,3 +145,8 @@ function matchNodes (scope, node, def) {

return map
}


// A crazy Internet Explorer workaround.
function acceptNode () { return 1 }
acceptNode.acceptNode = acceptNode

0 comments on commit bbb3724

Please sign in to comment.