min-dom.js 13 KB

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