Skip to content

Commit

Permalink
Merge pull request #8 from matthewp/build
Browse files Browse the repository at this point in the history
Add a build that allows for ES module use
  • Loading branch information
matthewp authored Feb 1, 2017
2 parents 27ee875 + 054dae2 commit 6ac53b2
Show file tree
Hide file tree
Showing 7 changed files with 178 additions and 5 deletions.
6 changes: 6 additions & 0 deletions Makefile
Original file line number Diff line number Diff line change
@@ -0,0 +1,6 @@
.PHONY: build all

all: build

build:
node_modules/.bin/rollup -o attr.js -f iife global.js
16 changes: 16 additions & 0 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -11,10 +11,26 @@ Define custom attributes in the same way you can define custom elements, which a
npm install custom-attributes --save
```

Add as a script tag:

```html
<script src="node_modules/custom-attributes/attr.js" defer></script>
```

Or import as an ES module:

```js
import customAttributes from 'custom-attributes';
```

Or you can just import the CustomAttributeRegistry and create your own instance:

```js
import CustomAttributeRegistry from 'custom-attributes/registry';

const customAttributes = new CustomAttributeRegistry(document);
```

## Example

```html
Expand Down
13 changes: 9 additions & 4 deletions attr.js
Original file line number Diff line number Diff line change
@@ -1,4 +1,6 @@
(function(){
(function () {
'use strict';

var forEach = Array.prototype.forEach;

class CustomAttributeRegistry {
Expand Down Expand Up @@ -75,7 +77,7 @@ class CustomAttributeRegistry {
this._found(attr.name, element);
}
}

for(var attr of this._attrMap.keys()) {
this._upgradeAttr(attr, element);
}
Expand Down Expand Up @@ -134,6 +136,9 @@ class CustomAttributeRegistry {
}
}

var customAttributes = new CustomAttributeRegistry(document);

window.customAttributes = customAttributes;
window.CustomAttributeRegistry = CustomAttributeRegistry;
window.customAttributes = new CustomAttributeRegistry(document);
})();

}());
4 changes: 4 additions & 0 deletions global.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,4 @@
import customAttributes, { CustomAttributeRegistry } from './index.js';

window.customAttributes = customAttributes;
window.CustomAttributeRegistry = CustomAttributeRegistry;
5 changes: 5 additions & 0 deletions index.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
import CustomAttributeRegistry from './registry.js';

var customAttributes = new CustomAttributeRegistry(document);

export { customAttributes as default, CustomAttributeRegistry }
3 changes: 2 additions & 1 deletion package.json
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,7 @@
"name": "custom-attributes",
"version": "1.0.1",
"description": "Custom attributes, like custom elements, but for attributes",
"main": "attr.js",
"main": "index.js",
"directories": {
"test": "test"
},
Expand All @@ -29,6 +29,7 @@
"homepage": "https://github.com/matthewp/custom-attributes#readme",
"devDependencies": {
"mocha-test": "^1.0.3",
"rollup": "^0.41.4",
"testee": "^0.3.0",
"webcomponents.js": "^0.7.22"
}
Expand Down
136 changes: 136 additions & 0 deletions registry.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,136 @@
var forEach = Array.prototype.forEach;

class CustomAttributeRegistry {
constructor(ownerDocument){
if(!ownerDocument) {
throw new Error("Must be given a document");
}

this.ownerDocument = ownerDocument;
this._attrMap = new Map();
this._elementMap = new WeakMap();
this._observe();
}

define(attrName, Constructor) {
this._attrMap.set(attrName, Constructor);
this._upgradeAttr(attrName);
}

get(element, attrName) {
var map = this._elementMap.get(element);
if(!map) return;
return map.get(attrName);
}

_getConstructor(attrName){
return this._attrMap.get(attrName);
}

_observe(){
var customAttributes = this;
var root = this.ownerDocument;
var downgrade = this._downgrade.bind(this);
var upgrade = this._upgradeElement.bind(this);

this.observer = new MutationObserver(function(mutations){
forEach.call(mutations, function(m){
if(m.type === 'attributes') {
var attr = customAttributes._getConstructor(m.attributeName);
if(attr) {
customAttributes._found(m.attributeName, m.target, m.oldValue);
}
}
// chlidList
else {
forEach.call(m.removedNodes, downgrade);
forEach.call(m.addedNodes, upgrade);
}
});
});

this.observer.observe(root, {
childList: true,
subtree: true,
attributes: true,
attributeOldValue: true
});
}

_upgradeAttr(attrName, document) {
document = document || this.ownerDocument;

var matches = document.querySelectorAll("[" + attrName + "]");
for(var match of matches) {
this._found(attrName, match);
}
}

_upgradeElement(element) {
if(element.nodeType !== 1) return;

for(var attr of element.attributes) {
if(this._getConstructor(attr.name)) {
this._found(attr.name, element);
}
}

for(var attr of this._attrMap.keys()) {
this._upgradeAttr(attr, element);
}
}

_downgrade(element) {
var map = this._elementMap.get(element);
if(!map) return;

for(var inst of map.values()) {
if(inst.disconnectedCallback) {
inst.disconnectedCallback();
}
}

this._elementMap.delete(element);
}

_found(attrName, el, oldVal) {
var map = this._elementMap.get(el);
if(!map) {
map = new Map();
this._elementMap.set(el, map);
}

var inst = map.get(attrName);
var newVal = el.getAttribute(attrName);
if(!inst) {
var Constructor = this._getConstructor(attrName);
inst = new Constructor();
map.set(attrName, inst);
inst.ownerElement = el;
inst.name = attrName;
inst.value = newVal;
if(inst.connectedCallback) {
inst.connectedCallback();
}
}
// Attribute was removed
else if(newVal == null && !!inst.value) {
inst.value = newVal;
if(inst.disconnectedCallback) {
inst.disconnectedCallback();
}

map.delete(attrName);
}
// Attribute changed
else if(newVal !== inst.value) {
inst.value = newVal;
if(inst.changedCallback) {
inst.changedCallback(oldVal, newVal);
}
}

}
}

export default CustomAttributeRegistry;

0 comments on commit 6ac53b2

Please sign in to comment.