diff --git a/selector-listeners.js b/selector-listeners.js index bcc6a63..dc0148f 100644 --- a/selector-listeners.js +++ b/selector-listeners.js @@ -2,24 +2,31 @@ var events = {}, selectors = {}, + docProto = typeof HTMLDocument !== 'undefined' ? HTMLDocument.prototype : Document.prototype, + elemProto = typeof HTMLElement !== 'undefined' ? HTMLElement.prototype : Element.prototype, styles = document.createElement('style'), keyframes = document.createElement('style'), head = document.getElementsByTagName('head')[0], startNames = ['animationstart', 'oAnimationStart', 'MSAnimationStart', 'webkitAnimationStart'], startEvent = function(event){ event.selector = (events[event.animationName] || {}).selector; + var removeList = []; ((this.selectorListeners || {})[event.animationName] || []).forEach(function(fn){ - fn.call(this, event); + if (fn.call(this, event) === false) removeList.push(fn); + }, this); + removeList.forEach(function(fn) { + this.removeSelectorListener(event.selector, fn); }, this); }, prefix = (function() { var duration = 'animation-duration: 0.001s;', name = 'animation-name: SelectorListener !important;', + visibility = 'visibility:hidden;', computed = window.getComputedStyle(document.documentElement, ''), pre = (Array.prototype.slice.call(computed).join('').match(/moz|webkit|ms/)||(computed.OLink===''&&['o']))[0]; return { css: '-' + pre + '-', - properties: '{' + duration + name + '-' + pre + '-' + duration + '-' + pre + '-' + name + '}', + properties: '{' + visibility + duration + name + '-' + pre + '-' + duration + '-' + pre + '-' + name + '}', keyframes: !!(window.CSSKeyframesRule || window[('WebKit|Moz|MS|O').match(new RegExp('(' + pre + ')', 'i'))[1] + 'CSSKeyframesRule']) }; })(); @@ -28,19 +35,20 @@ head.appendChild(styles); head.appendChild(keyframes); - HTMLDocument.prototype.addSelectorListener = HTMLElement.prototype.addSelectorListener = function(selector, fn){ + docProto.addSelectorListener = elemProto.addSelectorListener = function(selector, fn){ var key = selectors[selector], listeners = this.selectorListeners = this.selectorListeners || {}; if (key) events[key].count++; else { - key = selectors[selector] = 'SelectorListener-' + new Date().getTime(); + key = selectors[selector] = 'SelectorListener-' + Math.random().toString(16).substr(2, 9); var node = document.createTextNode('@' + (prefix.keyframes ? prefix.css : '') + 'keyframes ' + key + ' {' +'from { outline-color: #fff; } to { outline-color: #000; }' + '}'); keyframes.appendChild(node); - styles.sheet.insertRule(selector + prefix.properties.replace(/SelectorListener/g, key), 0); - events[key] = { count: 1, selector: selector, keyframe: node, rule: styles.sheet.cssRules[0] }; + var rule = document.createTextNode(selector + prefix.properties.replace(/SelectorListener/g, key)); + styles.appendChild(rule); + events[key] = { count: 1, selector: selector, keyframe: node, rule: rule }; } if (listeners.count) listeners.count++; @@ -54,7 +62,7 @@ (listeners[key] = listeners[key] || []).push(fn); }; - HTMLDocument.prototype.removeSelectorListener = HTMLElement.prototype.removeSelectorListener = function(selector, fn){ + docProto.removeSelectorListener = elemProto.removeSelectorListener = function(selector, fn){ var listeners = this.selectorListeners || {}, key = selectors[selector], listener = listeners[key] || [], @@ -64,7 +72,7 @@ var event = events[selectors[selector]]; event.count--; if (!event.count){ - styles.sheet.deleteRule(styles.sheet.cssRules.item(event.rule)); + styles.removeChild(event.rule); keyframes.removeChild(event.keyframe); delete events[key]; delete selectors[selector]; @@ -77,5 +85,10 @@ }, this); } }; - + + // Single invocation version + HTMLDocument.prototype.onSelector = HTMLElement.prototype.onSelector = function(selector,fn) { + this.addSelectorListener(selector, function(event) { fn(event); return false; }); + }; + })();