├── .gitignore ├── .npmignore ├── .travis.yml ├── LICENSE ├── README.md ├── cjs └── index.js ├── esm └── index.js ├── index.js ├── min.js ├── package.json └── test └── index.html /.gitignore: -------------------------------------------------------------------------------- 1 | .DS_Store 2 | node_modules/ 3 | coverage/ 4 | package-lock.json 5 | -------------------------------------------------------------------------------- /.npmignore: -------------------------------------------------------------------------------- 1 | coverage/* 2 | node_modules/* 3 | test/* 4 | _config.yml 5 | .DS_Store 6 | .gitignore 7 | .travis.yml 8 | package-lock.json 9 | -------------------------------------------------------------------------------- /.travis.yml: -------------------------------------------------------------------------------- 1 | language: node_js 2 | node_js: 3 | - stable 4 | git: 5 | depth: 1 6 | branches: 7 | only: 8 | - master 9 | - /^greenkeeper/.*$/ 10 | 11 | -------------------------------------------------------------------------------- /LICENSE: -------------------------------------------------------------------------------- 1 | ISC License 2 | 3 | Copyright (c) 2018, Andrea Giammarchi, @WebReflection 4 | 5 | Permission to use, copy, modify, and/or distribute this software for any 6 | purpose with or without fee is hereby granted, provided that the above 7 | copyright notice and this permission notice appear in all copies. 8 | 9 | THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES WITH 10 | REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY 11 | AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY SPECIAL, DIRECT, 12 | INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM 13 | LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE 14 | OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR 15 | PERFORMANCE OF THIS SOFTWARE. 16 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # attributechanged 2 | 3 | [![Build Status](https://travis-ci.com/WebReflection/attributechanged.svg?branch=master)](https://travis-ci.com/WebReflection/attributechanged) [![Greenkeeper badge](https://badges.greenkeeper.io/WebReflection/attributechanged.svg)](https://greenkeeper.io/) ![WebReflection status](https://offline.report/status/webreflection.svg) 4 | 5 | 6 | In less than 0.3K, it enables `attributechanged` element's listener, an ideal companion for [disconnected](https://github.com/WebReflection/disconnected). 7 | 8 | The only optional dependencies it has is a constructable `Event` which must be passed along as configuration object, and a polyfill might be needed only for legacy browsers. 9 | 10 | ```js 11 | // requires both modern Event and WeakSet 12 | import attributechanged from 'attributechanged'; 13 | const observe = attributechanged({Event}); 14 | 15 | observe(mainElement); 16 | mainElement.addEventListener('attributechanged', (e) => { 17 | console.log( 18 | e.target === mainElement, // true 19 | e.attributeName, // any name 20 | e.oldValue, // previous value or null 21 | e.newValue // new value or null if removed 22 | ); 23 | }); 24 | 25 | observe(subElement); 26 | observe(topElement); 27 | 28 | // optionally listen to a list of filters only 29 | observe(anyElement, ['only', 'some', 'attribute']); 30 | ``` 31 | 32 | 33 | ### Compatibility 34 | 35 | [Even IE9](https://webreflection.github.io/attributechanged/test/), as long as a usable `Event` is provided. 36 | 37 | 38 | ### DOM Level 0 Like events ? 39 | 40 | Using [with-level-0](https://github.com/WebReflection/with-level-0) would make it possible to have `el.onattributechanged = ...` simplification too. 41 | ```js 42 | withLevel0('attributechanged'); 43 | 44 | // remember to observe the node 45 | var div = observe(document.createElement('div')); 46 | 47 | // add your Level 0 listener 48 | div.onattributechanged = function () { 49 | div.textContent = 'Level 0'; 50 | }; 51 | 52 | // that's it! 53 | document.body.appendChild(div).setAttribute('test', 'ok'); 54 | 55 | // feel free to clean it up via 56 | div.onattributechanged = null; 57 | ``` 58 | -------------------------------------------------------------------------------- /cjs/index.js: -------------------------------------------------------------------------------- 1 | /*! (c) Andrea Giammarchi */ 2 | function attributechanged(poly) {'use strict'; 3 | var Event = poly.Event; 4 | return function observe(node, attributeFilter) { 5 | var options = {attributes: true, attributeOldValue: true}; 6 | var filtered = attributeFilter instanceof Array && attributeFilter.length; 7 | if (filtered) 8 | options.attributeFilter = attributeFilter.slice(0); 9 | try { 10 | (new MutationObserver(changes)).observe(node, options); 11 | } catch(o_O) { 12 | options.handleEvent = filtered ? handleEvent : attrModified; 13 | node.addEventListener('DOMAttrModified', options, true); 14 | } 15 | return node; 16 | }; 17 | function attrModified(event) { 18 | dispatchEvent(event.target, event.attrName, event.prevValue); 19 | } 20 | function dispatchEvent(node, attributeName, oldValue) { 21 | var event = new Event('attributechanged'); 22 | event.attributeName = attributeName; 23 | event.oldValue = oldValue; 24 | event.newValue = node.getAttribute(attributeName); 25 | node.dispatchEvent(event); 26 | } 27 | function changes(records) { 28 | for (var record, i = 0, length = records.length; i < length; i++) { 29 | record = records[i]; 30 | dispatchEvent(record.target, record.attributeName, record.oldValue); 31 | } 32 | } 33 | function handleEvent(event) { 34 | if (-1 < this.attributeFilter.indexOf(event.attrName)) 35 | attrModified(event); 36 | } 37 | } 38 | module.exports = attributechanged; 39 | -------------------------------------------------------------------------------- /esm/index.js: -------------------------------------------------------------------------------- 1 | /*! (c) Andrea Giammarchi */ 2 | function attributechanged(poly) {'use strict'; 3 | var Event = poly.Event; 4 | return function observe(node, attributeFilter) { 5 | var options = {attributes: true, attributeOldValue: true}; 6 | var filtered = attributeFilter instanceof Array && attributeFilter.length; 7 | if (filtered) 8 | options.attributeFilter = attributeFilter.slice(0); 9 | try { 10 | (new MutationObserver(changes)).observe(node, options); 11 | } catch(o_O) { 12 | options.handleEvent = filtered ? handleEvent : attrModified; 13 | node.addEventListener('DOMAttrModified', options, true); 14 | } 15 | return node; 16 | }; 17 | function attrModified(event) { 18 | dispatchEvent(event.target, event.attrName, event.prevValue); 19 | } 20 | function dispatchEvent(node, attributeName, oldValue) { 21 | var event = new Event('attributechanged'); 22 | event.attributeName = attributeName; 23 | event.oldValue = oldValue; 24 | event.newValue = node.getAttribute(attributeName); 25 | node.dispatchEvent(event); 26 | } 27 | function changes(records) { 28 | for (var record, i = 0, length = records.length; i < length; i++) { 29 | record = records[i]; 30 | dispatchEvent(record.target, record.attributeName, record.oldValue); 31 | } 32 | } 33 | function handleEvent(event) { 34 | if (-1 < this.attributeFilter.indexOf(event.attrName)) 35 | attrModified(event); 36 | } 37 | } 38 | export default attributechanged; 39 | -------------------------------------------------------------------------------- /index.js: -------------------------------------------------------------------------------- 1 | /*! (c) Andrea Giammarchi */ 2 | function attributechanged(poly) {'use strict'; 3 | var Event = poly.Event; 4 | return function observe(node, attributeFilter) { 5 | var options = {attributes: true, attributeOldValue: true}; 6 | var filtered = attributeFilter instanceof Array && attributeFilter.length; 7 | if (filtered) 8 | options.attributeFilter = attributeFilter.slice(0); 9 | try { 10 | (new MutationObserver(changes)).observe(node, options); 11 | } catch(o_O) { 12 | options.handleEvent = filtered ? handleEvent : attrModified; 13 | node.addEventListener('DOMAttrModified', options, true); 14 | } 15 | return node; 16 | }; 17 | function attrModified(event) { 18 | dispatchEvent(event.target, event.attrName, event.prevValue); 19 | } 20 | function dispatchEvent(node, attributeName, oldValue) { 21 | var event = new Event('attributechanged'); 22 | event.attributeName = attributeName; 23 | event.oldValue = oldValue; 24 | event.newValue = node.getAttribute(attributeName); 25 | node.dispatchEvent(event); 26 | } 27 | function changes(records) { 28 | for (var record, i = 0, length = records.length; i < length; i++) { 29 | record = records[i]; 30 | dispatchEvent(record.target, record.attributeName, record.oldValue); 31 | } 32 | } 33 | function handleEvent(event) { 34 | if (-1 < this.attributeFilter.indexOf(event.attrName)) 35 | attrModified(event); 36 | } 37 | } 38 | -------------------------------------------------------------------------------- /min.js: -------------------------------------------------------------------------------- 1 | /*! (c) Andrea Giammarchi */ 2 | function attributechanged(t){"use strict";function e(t){a(t.target,t.attrName,t.prevValue)}function a(t,e,a){var r=new i("attributechanged");r.attributeName=e,r.oldValue=a,r.newValue=t.getAttribute(e),t.dispatchEvent(r)}function r(t){for(var e,r=0,n=t.length;r> cjs/index.js", 11 | "esm": "cp index.js esm/ && echo 'export default attributechanged;' >> esm/index.js", 12 | "min": "uglifyjs index.js --support-ie8 --comments=/^!/ -c -m -o min.js", 13 | "size": "cat index.js | wc -c && cat min.js | wc -c && gzip -c9 min.js | wc -c && cat min.js | brotli | wc -c" 14 | }, 15 | "author": "Andrea Giammarchi", 16 | "license": "ISC", 17 | "devDependencies": { 18 | "uglify-js": "^3.4.9" 19 | }, 20 | "repository": { 21 | "type": "git", 22 | "url": "git+https://github.com/WebReflection/attributechanged.git" 23 | }, 24 | "keywords": [ 25 | "attributechanged", 26 | "dom", 27 | "events" 28 | ], 29 | "bugs": { 30 | "url": "https://github.com/WebReflection/attributechanged/issues" 31 | }, 32 | "homepage": "https://github.com/WebReflection/attributechanged#readme" 33 | } 34 | -------------------------------------------------------------------------------- /test/index.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | disconnected 8 | 23 | 24 | 25 | 26 | 74 | 75 | 76 | 77 |
78 |
first
79 |
80 | 82 | 83 | --------------------------------------------------------------------------------