123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514 |
- /**
- * Set attribute `name` to `val`, or get attr `name`.
- *
- * @param {Element} el
- * @param {String} name
- * @param {String} [val]
- * @api public
- */
- function attr(el, name, val) {
- // get
- if (arguments.length == 2) {
- return el.getAttribute(name);
- }
- // remove
- if (val === null) {
- return el.removeAttribute(name);
- }
- // set
- el.setAttribute(name, val);
- return el;
- }
- var indexOf = [].indexOf;
- var indexof = function(arr, obj){
- if (indexOf) return arr.indexOf(obj);
- for (var i = 0; i < arr.length; ++i) {
- if (arr[i] === obj) return i;
- }
- return -1;
- };
- /**
- * Taken from https://github.com/component/classes
- *
- * Without the component bits.
- */
- /**
- * Whitespace regexp.
- */
- var re = /\s+/;
- /**
- * toString reference.
- */
- var toString = Object.prototype.toString;
- /**
- * Wrap `el` in a `ClassList`.
- *
- * @param {Element} el
- * @return {ClassList}
- * @api public
- */
- function classes(el) {
- return new ClassList(el);
- }
- /**
- * Initialize a new ClassList for `el`.
- *
- * @param {Element} el
- * @api private
- */
- function ClassList(el) {
- if (!el || !el.nodeType) {
- throw new Error('A DOM element reference is required');
- }
- this.el = el;
- this.list = el.classList;
- }
- /**
- * Add class `name` if not already present.
- *
- * @param {String} name
- * @return {ClassList}
- * @api public
- */
- ClassList.prototype.add = function (name) {
- // classList
- if (this.list) {
- this.list.add(name);
- return this;
- }
- // fallback
- var arr = this.array();
- var i = indexof(arr, name);
- if (!~i) arr.push(name);
- this.el.className = arr.join(' ');
- return this;
- };
- /**
- * Remove class `name` when present, or
- * pass a regular expression to remove
- * any which match.
- *
- * @param {String|RegExp} name
- * @return {ClassList}
- * @api public
- */
- ClassList.prototype.remove = function (name) {
- if ('[object RegExp]' == toString.call(name)) {
- return this.removeMatching(name);
- }
- // classList
- if (this.list) {
- this.list.remove(name);
- return this;
- }
- // fallback
- var arr = this.array();
- var i = indexof(arr, name);
- if (~i) arr.splice(i, 1);
- this.el.className = arr.join(' ');
- return this;
- };
- /**
- * Remove all classes matching `re`.
- *
- * @param {RegExp} re
- * @return {ClassList}
- * @api private
- */
- ClassList.prototype.removeMatching = function (re) {
- var arr = this.array();
- for (var i = 0; i < arr.length; i++) {
- if (re.test(arr[i])) {
- this.remove(arr[i]);
- }
- }
- return this;
- };
- /**
- * Toggle class `name`, can force state via `force`.
- *
- * For browsers that support classList, but do not support `force` yet,
- * the mistake will be detected and corrected.
- *
- * @param {String} name
- * @param {Boolean} force
- * @return {ClassList}
- * @api public
- */
- ClassList.prototype.toggle = function (name, force) {
- // classList
- if (this.list) {
- if ('undefined' !== typeof force) {
- if (force !== this.list.toggle(name, force)) {
- this.list.toggle(name); // toggle again to correct
- }
- } else {
- this.list.toggle(name);
- }
- return this;
- }
- // fallback
- if ('undefined' !== typeof force) {
- if (!force) {
- this.remove(name);
- } else {
- this.add(name);
- }
- } else {
- if (this.has(name)) {
- this.remove(name);
- } else {
- this.add(name);
- }
- }
- return this;
- };
- /**
- * Return an array of classes.
- *
- * @return {Array}
- * @api public
- */
- ClassList.prototype.array = function () {
- var className = this.el.getAttribute('class') || '';
- var str = className.replace(/^\s+|\s+$/g, '');
- var arr = str.split(re);
- if ('' === arr[0]) arr.shift();
- return arr;
- };
- /**
- * Check if class `name` is present.
- *
- * @param {String} name
- * @return {ClassList}
- * @api public
- */
- ClassList.prototype.has = ClassList.prototype.contains = function (name) {
- return this.list ? this.list.contains(name) : !!~indexof(this.array(), name);
- };
- /**
- * Remove all children from the given element.
- */
- function clear(el) {
- var c;
- while (el.childNodes.length) {
- c = el.childNodes[0];
- el.removeChild(c);
- }
- return el;
- }
- var proto = typeof Element !== 'undefined' ? Element.prototype : {};
- var vendor = proto.matches
- || proto.matchesSelector
- || proto.webkitMatchesSelector
- || proto.mozMatchesSelector
- || proto.msMatchesSelector
- || proto.oMatchesSelector;
- var matchesSelector = match;
- /**
- * Match `el` to `selector`.
- *
- * @param {Element} el
- * @param {String} selector
- * @return {Boolean}
- * @api public
- */
- function match(el, selector) {
- if (!el || el.nodeType !== 1) return false;
- if (vendor) return vendor.call(el, selector);
- var nodes = el.parentNode.querySelectorAll(selector);
- for (var i = 0; i < nodes.length; i++) {
- if (nodes[i] == el) return true;
- }
- return false;
- }
- /**
- * Closest
- *
- * @param {Element} el
- * @param {String} selector
- * @param {Boolean} checkYourSelf (optional)
- */
- function closest (element, selector, checkYourSelf) {
- var currentElem = checkYourSelf ? element : element.parentNode;
- while (currentElem && currentElem.nodeType !== document.DOCUMENT_NODE && currentElem.nodeType !== document.DOCUMENT_FRAGMENT_NODE) {
- if (matchesSelector(currentElem, selector)) {
- return currentElem;
- }
- currentElem = currentElem.parentNode;
- }
- return matchesSelector(currentElem, selector) ? currentElem : null;
- }
- var bind = window.addEventListener ? 'addEventListener' : 'attachEvent',
- unbind = window.removeEventListener ? 'removeEventListener' : 'detachEvent',
- prefix = bind !== 'addEventListener' ? 'on' : '';
- /**
- * Bind `el` event `type` to `fn`.
- *
- * @param {Element} el
- * @param {String} type
- * @param {Function} fn
- * @param {Boolean} capture
- * @return {Function}
- * @api public
- */
- var bind_1 = function(el, type, fn, capture){
- el[bind](prefix + type, fn, capture || false);
- return fn;
- };
- /**
- * Unbind `el` event `type`'s callback `fn`.
- *
- * @param {Element} el
- * @param {String} type
- * @param {Function} fn
- * @param {Boolean} capture
- * @return {Function}
- * @api public
- */
- var unbind_1 = function(el, type, fn, capture){
- el[unbind](prefix + type, fn, capture || false);
- return fn;
- };
- var componentEvent = {
- bind: bind_1,
- unbind: unbind_1
- };
- /**
- * Module dependencies.
- */
- /**
- * Delegate event `type` to `selector`
- * and invoke `fn(e)`. A callback function
- * is returned which may be passed to `.unbind()`.
- *
- * @param {Element} el
- * @param {String} selector
- * @param {String} type
- * @param {Function} fn
- * @param {Boolean} capture
- * @return {Function}
- * @api public
- */
- // Some events don't bubble, so we want to bind to the capture phase instead
- // when delegating.
- var forceCaptureEvents = ['focus', 'blur'];
- function bind$1(el, selector, type, fn, capture) {
- if (forceCaptureEvents.indexOf(type) !== -1) {
- capture = true;
- }
- return componentEvent.bind(el, type, function (e) {
- var target = e.target || e.srcElement;
- e.delegateTarget = closest(target, selector, true, el);
- if (e.delegateTarget) {
- fn.call(el, e);
- }
- }, capture);
- }
- /**
- * Unbind event `type`'s callback `fn`.
- *
- * @param {Element} el
- * @param {String} type
- * @param {Function} fn
- * @param {Boolean} capture
- * @api public
- */
- function unbind$1(el, type, fn, capture) {
- if (forceCaptureEvents.indexOf(type) !== -1) {
- capture = true;
- }
- return componentEvent.unbind(el, type, fn, capture);
- }
- var delegate = {
- bind: bind$1,
- unbind: unbind$1
- };
- /**
- * Expose `parse`.
- */
- var domify = parse;
- /**
- * Tests for browser support.
- */
- var innerHTMLBug = false;
- var bugTestDiv;
- if (typeof document !== 'undefined') {
- bugTestDiv = document.createElement('div');
- // Setup
- bugTestDiv.innerHTML = ' <link/><table></table><a href="/a">a</a><input type="checkbox"/>';
- // Make sure that link elements get serialized correctly by innerHTML
- // This requires a wrapper element in IE
- innerHTMLBug = !bugTestDiv.getElementsByTagName('link').length;
- bugTestDiv = undefined;
- }
- /**
- * Wrap map from jquery.
- */
- var map = {
- legend: [1, '<fieldset>', '</fieldset>'],
- tr: [2, '<table><tbody>', '</tbody></table>'],
- col: [2, '<table><tbody></tbody><colgroup>', '</colgroup></table>'],
- // for script/link/style tags to work in IE6-8, you have to wrap
- // in a div with a non-whitespace character in front, ha!
- _default: innerHTMLBug ? [1, 'X<div>', '</div>'] : [0, '', '']
- };
- map.td =
- map.th = [3, '<table><tbody><tr>', '</tr></tbody></table>'];
- map.option =
- map.optgroup = [1, '<select multiple="multiple">', '</select>'];
- map.thead =
- map.tbody =
- map.colgroup =
- map.caption =
- map.tfoot = [1, '<table>', '</table>'];
- map.polyline =
- map.ellipse =
- map.polygon =
- map.circle =
- map.text =
- map.line =
- map.path =
- map.rect =
- map.g = [1, '<svg xmlns="http://www.w3.org/2000/svg" version="1.1">','</svg>'];
- /**
- * Parse `html` and return a DOM Node instance, which could be a TextNode,
- * HTML DOM Node of some kind (<div> for example), or a DocumentFragment
- * instance, depending on the contents of the `html` string.
- *
- * @param {String} html - HTML string to "domify"
- * @param {Document} doc - The `document` instance to create the Node for
- * @return {DOMNode} the TextNode, DOM Node, or DocumentFragment instance
- * @api private
- */
- function parse(html, doc) {
- if ('string' != typeof html) throw new TypeError('String expected');
- // default to the global `document` object
- if (!doc) doc = document;
- // tag name
- var m = /<([\w:]+)/.exec(html);
- if (!m) return doc.createTextNode(html);
- html = html.replace(/^\s+|\s+$/g, ''); // Remove leading/trailing whitespace
- var tag = m[1];
- // body support
- if (tag == 'body') {
- var el = doc.createElement('html');
- el.innerHTML = html;
- return el.removeChild(el.lastChild);
- }
- // wrap map
- var wrap = map[tag] || map._default;
- var depth = wrap[0];
- var prefix = wrap[1];
- var suffix = wrap[2];
- var el = doc.createElement('div');
- el.innerHTML = prefix + html + suffix;
- while (depth--) el = el.lastChild;
- // one element
- if (el.firstChild == el.lastChild) {
- return el.removeChild(el.firstChild);
- }
- // several elements
- var fragment = doc.createDocumentFragment();
- while (el.firstChild) {
- fragment.appendChild(el.removeChild(el.firstChild));
- }
- return fragment;
- }
- function query(selector, el) {
- el = el || document;
- return el.querySelector(selector);
- }
- function all(selector, el) {
- el = el || document;
- return el.querySelectorAll(selector);
- }
- function remove(el) {
- el.parentNode && el.parentNode.removeChild(el);
- }
- export { attr, classes, clear, closest, delegate, domify, componentEvent as event, matchesSelector as matches, query, all as queryAll, remove };
|