index.esm.js 10 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514
  1. /**
  2. * Set attribute `name` to `val`, or get attr `name`.
  3. *
  4. * @param {Element} el
  5. * @param {String} name
  6. * @param {String} [val]
  7. * @api public
  8. */
  9. function attr(el, name, val) {
  10. // get
  11. if (arguments.length == 2) {
  12. return el.getAttribute(name);
  13. }
  14. // remove
  15. if (val === null) {
  16. return el.removeAttribute(name);
  17. }
  18. // set
  19. el.setAttribute(name, val);
  20. return el;
  21. }
  22. var indexOf = [].indexOf;
  23. var indexof = function(arr, obj){
  24. if (indexOf) return arr.indexOf(obj);
  25. for (var i = 0; i < arr.length; ++i) {
  26. if (arr[i] === obj) return i;
  27. }
  28. return -1;
  29. };
  30. /**
  31. * Taken from https://github.com/component/classes
  32. *
  33. * Without the component bits.
  34. */
  35. /**
  36. * Whitespace regexp.
  37. */
  38. var re = /\s+/;
  39. /**
  40. * toString reference.
  41. */
  42. var toString = Object.prototype.toString;
  43. /**
  44. * Wrap `el` in a `ClassList`.
  45. *
  46. * @param {Element} el
  47. * @return {ClassList}
  48. * @api public
  49. */
  50. function classes(el) {
  51. return new ClassList(el);
  52. }
  53. /**
  54. * Initialize a new ClassList for `el`.
  55. *
  56. * @param {Element} el
  57. * @api private
  58. */
  59. function ClassList(el) {
  60. if (!el || !el.nodeType) {
  61. throw new Error('A DOM element reference is required');
  62. }
  63. this.el = el;
  64. this.list = el.classList;
  65. }
  66. /**
  67. * Add class `name` if not already present.
  68. *
  69. * @param {String} name
  70. * @return {ClassList}
  71. * @api public
  72. */
  73. ClassList.prototype.add = function (name) {
  74. // classList
  75. if (this.list) {
  76. this.list.add(name);
  77. return this;
  78. }
  79. // fallback
  80. var arr = this.array();
  81. var i = indexof(arr, name);
  82. if (!~i) arr.push(name);
  83. this.el.className = arr.join(' ');
  84. return this;
  85. };
  86. /**
  87. * Remove class `name` when present, or
  88. * pass a regular expression to remove
  89. * any which match.
  90. *
  91. * @param {String|RegExp} name
  92. * @return {ClassList}
  93. * @api public
  94. */
  95. ClassList.prototype.remove = function (name) {
  96. if ('[object RegExp]' == toString.call(name)) {
  97. return this.removeMatching(name);
  98. }
  99. // classList
  100. if (this.list) {
  101. this.list.remove(name);
  102. return this;
  103. }
  104. // fallback
  105. var arr = this.array();
  106. var i = indexof(arr, name);
  107. if (~i) arr.splice(i, 1);
  108. this.el.className = arr.join(' ');
  109. return this;
  110. };
  111. /**
  112. * Remove all classes matching `re`.
  113. *
  114. * @param {RegExp} re
  115. * @return {ClassList}
  116. * @api private
  117. */
  118. ClassList.prototype.removeMatching = function (re) {
  119. var arr = this.array();
  120. for (var i = 0; i < arr.length; i++) {
  121. if (re.test(arr[i])) {
  122. this.remove(arr[i]);
  123. }
  124. }
  125. return this;
  126. };
  127. /**
  128. * Toggle class `name`, can force state via `force`.
  129. *
  130. * For browsers that support classList, but do not support `force` yet,
  131. * the mistake will be detected and corrected.
  132. *
  133. * @param {String} name
  134. * @param {Boolean} force
  135. * @return {ClassList}
  136. * @api public
  137. */
  138. ClassList.prototype.toggle = function (name, force) {
  139. // classList
  140. if (this.list) {
  141. if ('undefined' !== typeof force) {
  142. if (force !== this.list.toggle(name, force)) {
  143. this.list.toggle(name); // toggle again to correct
  144. }
  145. } else {
  146. this.list.toggle(name);
  147. }
  148. return this;
  149. }
  150. // fallback
  151. if ('undefined' !== typeof force) {
  152. if (!force) {
  153. this.remove(name);
  154. } else {
  155. this.add(name);
  156. }
  157. } else {
  158. if (this.has(name)) {
  159. this.remove(name);
  160. } else {
  161. this.add(name);
  162. }
  163. }
  164. return this;
  165. };
  166. /**
  167. * Return an array of classes.
  168. *
  169. * @return {Array}
  170. * @api public
  171. */
  172. ClassList.prototype.array = function () {
  173. var className = this.el.getAttribute('class') || '';
  174. var str = className.replace(/^\s+|\s+$/g, '');
  175. var arr = str.split(re);
  176. if ('' === arr[0]) arr.shift();
  177. return arr;
  178. };
  179. /**
  180. * Check if class `name` is present.
  181. *
  182. * @param {String} name
  183. * @return {ClassList}
  184. * @api public
  185. */
  186. ClassList.prototype.has = ClassList.prototype.contains = function (name) {
  187. return this.list ? this.list.contains(name) : !!~indexof(this.array(), name);
  188. };
  189. /**
  190. * Remove all children from the given element.
  191. */
  192. function clear(el) {
  193. var c;
  194. while (el.childNodes.length) {
  195. c = el.childNodes[0];
  196. el.removeChild(c);
  197. }
  198. return el;
  199. }
  200. var proto = typeof Element !== 'undefined' ? Element.prototype : {};
  201. var vendor = proto.matches
  202. || proto.matchesSelector
  203. || proto.webkitMatchesSelector
  204. || proto.mozMatchesSelector
  205. || proto.msMatchesSelector
  206. || proto.oMatchesSelector;
  207. var matchesSelector = match;
  208. /**
  209. * Match `el` to `selector`.
  210. *
  211. * @param {Element} el
  212. * @param {String} selector
  213. * @return {Boolean}
  214. * @api public
  215. */
  216. function match(el, selector) {
  217. if (!el || el.nodeType !== 1) return false;
  218. if (vendor) return vendor.call(el, selector);
  219. var nodes = el.parentNode.querySelectorAll(selector);
  220. for (var i = 0; i < nodes.length; i++) {
  221. if (nodes[i] == el) return true;
  222. }
  223. return false;
  224. }
  225. /**
  226. * Closest
  227. *
  228. * @param {Element} el
  229. * @param {String} selector
  230. * @param {Boolean} checkYourSelf (optional)
  231. */
  232. function closest (element, selector, checkYourSelf) {
  233. var currentElem = checkYourSelf ? element : element.parentNode;
  234. while (currentElem && currentElem.nodeType !== document.DOCUMENT_NODE && currentElem.nodeType !== document.DOCUMENT_FRAGMENT_NODE) {
  235. if (matchesSelector(currentElem, selector)) {
  236. return currentElem;
  237. }
  238. currentElem = currentElem.parentNode;
  239. }
  240. return matchesSelector(currentElem, selector) ? currentElem : null;
  241. }
  242. var bind = window.addEventListener ? 'addEventListener' : 'attachEvent',
  243. unbind = window.removeEventListener ? 'removeEventListener' : 'detachEvent',
  244. prefix = bind !== 'addEventListener' ? 'on' : '';
  245. /**
  246. * Bind `el` event `type` to `fn`.
  247. *
  248. * @param {Element} el
  249. * @param {String} type
  250. * @param {Function} fn
  251. * @param {Boolean} capture
  252. * @return {Function}
  253. * @api public
  254. */
  255. var bind_1 = function(el, type, fn, capture){
  256. el[bind](prefix + type, fn, capture || false);
  257. return fn;
  258. };
  259. /**
  260. * Unbind `el` event `type`'s callback `fn`.
  261. *
  262. * @param {Element} el
  263. * @param {String} type
  264. * @param {Function} fn
  265. * @param {Boolean} capture
  266. * @return {Function}
  267. * @api public
  268. */
  269. var unbind_1 = function(el, type, fn, capture){
  270. el[unbind](prefix + type, fn, capture || false);
  271. return fn;
  272. };
  273. var componentEvent = {
  274. bind: bind_1,
  275. unbind: unbind_1
  276. };
  277. /**
  278. * Module dependencies.
  279. */
  280. /**
  281. * Delegate event `type` to `selector`
  282. * and invoke `fn(e)`. A callback function
  283. * is returned which may be passed to `.unbind()`.
  284. *
  285. * @param {Element} el
  286. * @param {String} selector
  287. * @param {String} type
  288. * @param {Function} fn
  289. * @param {Boolean} capture
  290. * @return {Function}
  291. * @api public
  292. */
  293. // Some events don't bubble, so we want to bind to the capture phase instead
  294. // when delegating.
  295. var forceCaptureEvents = ['focus', 'blur'];
  296. function bind$1(el, selector, type, fn, capture) {
  297. if (forceCaptureEvents.indexOf(type) !== -1) {
  298. capture = true;
  299. }
  300. return componentEvent.bind(el, type, function (e) {
  301. var target = e.target || e.srcElement;
  302. e.delegateTarget = closest(target, selector, true, el);
  303. if (e.delegateTarget) {
  304. fn.call(el, e);
  305. }
  306. }, capture);
  307. }
  308. /**
  309. * Unbind event `type`'s callback `fn`.
  310. *
  311. * @param {Element} el
  312. * @param {String} type
  313. * @param {Function} fn
  314. * @param {Boolean} capture
  315. * @api public
  316. */
  317. function unbind$1(el, type, fn, capture) {
  318. if (forceCaptureEvents.indexOf(type) !== -1) {
  319. capture = true;
  320. }
  321. return componentEvent.unbind(el, type, fn, capture);
  322. }
  323. var delegate = {
  324. bind: bind$1,
  325. unbind: unbind$1
  326. };
  327. /**
  328. * Expose `parse`.
  329. */
  330. var domify = parse;
  331. /**
  332. * Tests for browser support.
  333. */
  334. var innerHTMLBug = false;
  335. var bugTestDiv;
  336. if (typeof document !== 'undefined') {
  337. bugTestDiv = document.createElement('div');
  338. // Setup
  339. bugTestDiv.innerHTML = ' <link/><table></table><a href="/a">a</a><input type="checkbox"/>';
  340. // Make sure that link elements get serialized correctly by innerHTML
  341. // This requires a wrapper element in IE
  342. innerHTMLBug = !bugTestDiv.getElementsByTagName('link').length;
  343. bugTestDiv = undefined;
  344. }
  345. /**
  346. * Wrap map from jquery.
  347. */
  348. var map = {
  349. legend: [1, '<fieldset>', '</fieldset>'],
  350. tr: [2, '<table><tbody>', '</tbody></table>'],
  351. col: [2, '<table><tbody></tbody><colgroup>', '</colgroup></table>'],
  352. // for script/link/style tags to work in IE6-8, you have to wrap
  353. // in a div with a non-whitespace character in front, ha!
  354. _default: innerHTMLBug ? [1, 'X<div>', '</div>'] : [0, '', '']
  355. };
  356. map.td =
  357. map.th = [3, '<table><tbody><tr>', '</tr></tbody></table>'];
  358. map.option =
  359. map.optgroup = [1, '<select multiple="multiple">', '</select>'];
  360. map.thead =
  361. map.tbody =
  362. map.colgroup =
  363. map.caption =
  364. map.tfoot = [1, '<table>', '</table>'];
  365. map.polyline =
  366. map.ellipse =
  367. map.polygon =
  368. map.circle =
  369. map.text =
  370. map.line =
  371. map.path =
  372. map.rect =
  373. map.g = [1, '<svg xmlns="http://www.w3.org/2000/svg" version="1.1">','</svg>'];
  374. /**
  375. * Parse `html` and return a DOM Node instance, which could be a TextNode,
  376. * HTML DOM Node of some kind (<div> for example), or a DocumentFragment
  377. * instance, depending on the contents of the `html` string.
  378. *
  379. * @param {String} html - HTML string to "domify"
  380. * @param {Document} doc - The `document` instance to create the Node for
  381. * @return {DOMNode} the TextNode, DOM Node, or DocumentFragment instance
  382. * @api private
  383. */
  384. function parse(html, doc) {
  385. if ('string' != typeof html) throw new TypeError('String expected');
  386. // default to the global `document` object
  387. if (!doc) doc = document;
  388. // tag name
  389. var m = /<([\w:]+)/.exec(html);
  390. if (!m) return doc.createTextNode(html);
  391. html = html.replace(/^\s+|\s+$/g, ''); // Remove leading/trailing whitespace
  392. var tag = m[1];
  393. // body support
  394. if (tag == 'body') {
  395. var el = doc.createElement('html');
  396. el.innerHTML = html;
  397. return el.removeChild(el.lastChild);
  398. }
  399. // wrap map
  400. var wrap = map[tag] || map._default;
  401. var depth = wrap[0];
  402. var prefix = wrap[1];
  403. var suffix = wrap[2];
  404. var el = doc.createElement('div');
  405. el.innerHTML = prefix + html + suffix;
  406. while (depth--) el = el.lastChild;
  407. // one element
  408. if (el.firstChild == el.lastChild) {
  409. return el.removeChild(el.firstChild);
  410. }
  411. // several elements
  412. var fragment = doc.createDocumentFragment();
  413. while (el.firstChild) {
  414. fragment.appendChild(el.removeChild(el.firstChild));
  415. }
  416. return fragment;
  417. }
  418. function query(selector, el) {
  419. el = el || document;
  420. return el.querySelector(selector);
  421. }
  422. function all(selector, el) {
  423. el = el || document;
  424. return el.querySelectorAll(selector);
  425. }
  426. function remove(el) {
  427. el.parentNode && el.parentNode.removeChild(el);
  428. }
  429. export { attr, classes, clear, closest, delegate, domify, componentEvent as event, matchesSelector as matches, query, all as queryAll, remove };