You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
 
 
 

6405 line
200 KiB

  1. var DataTable = (function (Sortable) {
  2. 'use strict';
  3. Sortable = Sortable && Sortable.hasOwnProperty('default') ? Sortable['default'] : Sortable;
  4. function $(expr, con) {
  5. return typeof expr === 'string' ?
  6. (con || document).querySelector(expr) :
  7. expr || null;
  8. }
  9. $.each = (expr, con) => {
  10. return typeof expr === 'string' ?
  11. Array.from((con || document).querySelectorAll(expr)) :
  12. expr || null;
  13. };
  14. $.create = (tag, o) => {
  15. let element = document.createElement(tag);
  16. for (let i in o) {
  17. let val = o[i];
  18. if (i === 'inside') {
  19. $(val).appendChild(element);
  20. } else
  21. if (i === 'around') {
  22. let ref = $(val);
  23. ref.parentNode.insertBefore(element, ref);
  24. element.appendChild(ref);
  25. } else
  26. if (i === 'styles') {
  27. if (typeof val === 'object') {
  28. Object.keys(val).map(prop => {
  29. element.style[prop] = val[prop];
  30. });
  31. }
  32. } else
  33. if (i in element) {
  34. element[i] = val;
  35. } else {
  36. element.setAttribute(i, val);
  37. }
  38. }
  39. return element;
  40. };
  41. $.on = (element, event, selector, callback) => {
  42. if (!callback) {
  43. callback = selector;
  44. $.bind(element, event, callback);
  45. } else {
  46. $.delegate(element, event, selector, callback);
  47. }
  48. };
  49. $.off = (element, event, handler) => {
  50. element.removeEventListener(event, handler);
  51. };
  52. $.bind = (element, event, callback) => {
  53. event.split(/\s+/).forEach(function (event) {
  54. element.addEventListener(event, callback);
  55. });
  56. };
  57. $.delegate = (element, event, selector, callback) => {
  58. element.addEventListener(event, function (e) {
  59. const delegatedTarget = e.target.closest(selector);
  60. if (delegatedTarget) {
  61. e.delegatedTarget = delegatedTarget;
  62. callback.call(this, e, delegatedTarget);
  63. }
  64. });
  65. };
  66. $.unbind = (element, o) => {
  67. if (element) {
  68. for (let event in o) {
  69. let callback = o[event];
  70. event.split(/\s+/).forEach(function (event) {
  71. element.removeEventListener(event, callback);
  72. });
  73. }
  74. }
  75. };
  76. $.fire = (target, type, properties) => {
  77. let evt = document.createEvent('HTMLEvents');
  78. evt.initEvent(type, true, true);
  79. for (let j in properties) {
  80. evt[j] = properties[j];
  81. }
  82. return target.dispatchEvent(evt);
  83. };
  84. $.data = (element, attrs) => { // eslint-disable-line
  85. if (!attrs) {
  86. return element.dataset;
  87. }
  88. for (const attr in attrs) {
  89. element.dataset[attr] = attrs[attr];
  90. }
  91. };
  92. $.style = (elements, styleMap) => { // eslint-disable-line
  93. if (typeof styleMap === 'string') {
  94. return $.getStyle(elements, styleMap);
  95. }
  96. if (!Array.isArray(elements)) {
  97. elements = [elements];
  98. }
  99. elements.map(element => {
  100. for (const prop in styleMap) {
  101. element.style[prop] = styleMap[prop];
  102. }
  103. });
  104. };
  105. $.removeStyle = (elements, styleProps) => {
  106. if (!Array.isArray(elements)) {
  107. elements = [elements];
  108. }
  109. if (!Array.isArray(styleProps)) {
  110. styleProps = [styleProps];
  111. }
  112. elements.map(element => {
  113. for (const prop of styleProps) {
  114. element.style[prop] = '';
  115. }
  116. });
  117. };
  118. $.getStyle = (element, prop) => {
  119. if (!prop) {
  120. return getComputedStyle(element);
  121. }
  122. let val = getComputedStyle(element)[prop];
  123. if (['width', 'height'].includes(prop)) {
  124. val = parseFloat(val);
  125. }
  126. return val;
  127. };
  128. $.closest = (selector, element) => {
  129. if (!element) return null;
  130. if (element.matches(selector)) {
  131. return element;
  132. }
  133. return $.closest(selector, element.parentNode);
  134. };
  135. $.inViewport = (el, parentEl) => {
  136. const {
  137. top,
  138. left,
  139. bottom,
  140. right
  141. } = el.getBoundingClientRect();
  142. const {
  143. top: pTop,
  144. left: pLeft,
  145. bottom: pBottom,
  146. right: pRight
  147. } = parentEl.getBoundingClientRect();
  148. return top >= pTop && left >= pLeft && bottom <= pBottom && right <= pRight;
  149. };
  150. $.scrollTop = function scrollTop(element, pixels) {
  151. requestAnimationFrame(() => {
  152. element.scrollTop = pixels;
  153. });
  154. };
  155. $.scrollbarSize = function scrollbarSize() {
  156. if (!$.scrollBarSizeValue) {
  157. $.scrollBarSizeValue = getScrollBarSize();
  158. }
  159. return $.scrollBarSizeValue;
  160. };
  161. function getScrollBarSize() {
  162. // assume scrollbar width and height would be the same
  163. // Create the measurement node
  164. const scrollDiv = document.createElement('div');
  165. $.style(scrollDiv, {
  166. width: '100px',
  167. height: '100px',
  168. overflow: 'scroll',
  169. position: 'absolute',
  170. top: '-9999px'
  171. });
  172. document.body.appendChild(scrollDiv);
  173. // Get the scrollbar width
  174. const scrollbarWidth = scrollDiv.offsetWidth - scrollDiv.clientWidth;
  175. // Delete the DIV
  176. document.body.removeChild(scrollDiv);
  177. return scrollbarWidth;
  178. }
  179. $.hasVerticalOverflow = function (element) {
  180. return element.scrollHeight > element.offsetHeight + 10;
  181. };
  182. $.hasHorizontalOverflow = function (element) {
  183. return element.scrollWidth > element.offsetWidth + 10;
  184. };
  185. $.measureTextWidth = function (text) {
  186. const div = document.createElement('div');
  187. div.style.position = 'absolute';
  188. div.style.visibility = 'hidden';
  189. div.style.height = 'auto';
  190. div.style.width = 'auto';
  191. div.style.whiteSpace = 'nowrap';
  192. div.innerText = text;
  193. document.body.appendChild(div);
  194. return div.clientWidth + 1;
  195. };
  196. /**
  197. * Checks if `value` is the
  198. * [language type](http://www.ecma-international.org/ecma-262/7.0/#sec-ecmascript-language-types)
  199. * of `Object`. (e.g. arrays, functions, objects, regexes, `new Number(0)`, and `new String('')`)
  200. *
  201. * @static
  202. * @memberOf _
  203. * @since 0.1.0
  204. * @category Lang
  205. * @param {*} value The value to check.
  206. * @returns {boolean} Returns `true` if `value` is an object, else `false`.
  207. * @example
  208. *
  209. * _.isObject({});
  210. * // => true
  211. *
  212. * _.isObject([1, 2, 3]);
  213. * // => true
  214. *
  215. * _.isObject(_.noop);
  216. * // => true
  217. *
  218. * _.isObject(null);
  219. * // => false
  220. */
  221. function isObject(value) {
  222. var type = typeof value;
  223. return value != null && (type == 'object' || type == 'function');
  224. }
  225. var isObject_1 = isObject;
  226. var isObject$1 = /*#__PURE__*/Object.freeze({
  227. default: isObject_1,
  228. __moduleExports: isObject_1
  229. });
  230. var commonjsGlobal = typeof window !== 'undefined' ? window : typeof global !== 'undefined' ? global : typeof self !== 'undefined' ? self : {};
  231. function commonjsRequire () {
  232. throw new Error('Dynamic requires are not currently supported by rollup-plugin-commonjs');
  233. }
  234. function unwrapExports (x) {
  235. return x && x.__esModule && Object.prototype.hasOwnProperty.call(x, 'default') ? x['default'] : x;
  236. }
  237. function createCommonjsModule(fn, module) {
  238. return module = { exports: {} }, fn(module, module.exports), module.exports;
  239. }
  240. /** Detect free variable `global` from Node.js. */
  241. var freeGlobal = typeof commonjsGlobal == 'object' && commonjsGlobal && commonjsGlobal.Object === Object && commonjsGlobal;
  242. var _freeGlobal = freeGlobal;
  243. var _freeGlobal$1 = /*#__PURE__*/Object.freeze({
  244. default: _freeGlobal,
  245. __moduleExports: _freeGlobal
  246. });
  247. var freeGlobal$1 = ( _freeGlobal$1 && _freeGlobal ) || _freeGlobal$1;
  248. /** Detect free variable `self`. */
  249. var freeSelf = typeof self == 'object' && self && self.Object === Object && self;
  250. /** Used as a reference to the global object. */
  251. var root = freeGlobal$1 || freeSelf || Function('return this')();
  252. var _root = root;
  253. var _root$1 = /*#__PURE__*/Object.freeze({
  254. default: _root,
  255. __moduleExports: _root
  256. });
  257. var root$1 = ( _root$1 && _root ) || _root$1;
  258. /**
  259. * Gets the timestamp of the number of milliseconds that have elapsed since
  260. * the Unix epoch (1 January 1970 00:00:00 UTC).
  261. *
  262. * @static
  263. * @memberOf _
  264. * @since 2.4.0
  265. * @category Date
  266. * @returns {number} Returns the timestamp.
  267. * @example
  268. *
  269. * _.defer(function(stamp) {
  270. * console.log(_.now() - stamp);
  271. * }, _.now());
  272. * // => Logs the number of milliseconds it took for the deferred invocation.
  273. */
  274. var now = function() {
  275. return root$1.Date.now();
  276. };
  277. var now_1 = now;
  278. var now$1 = /*#__PURE__*/Object.freeze({
  279. default: now_1,
  280. __moduleExports: now_1
  281. });
  282. /** Used to match a single whitespace character. */
  283. var reWhitespace = /\s/;
  284. /**
  285. * Used by `_.trim` and `_.trimEnd` to get the index of the last non-whitespace
  286. * character of `string`.
  287. *
  288. * @private
  289. * @param {string} string The string to inspect.
  290. * @returns {number} Returns the index of the last non-whitespace character.
  291. */
  292. function trimmedEndIndex(string) {
  293. var index = string.length;
  294. while (index-- && reWhitespace.test(string.charAt(index))) {}
  295. return index;
  296. }
  297. var _trimmedEndIndex = trimmedEndIndex;
  298. var _trimmedEndIndex$1 = /*#__PURE__*/Object.freeze({
  299. default: _trimmedEndIndex,
  300. __moduleExports: _trimmedEndIndex
  301. });
  302. var trimmedEndIndex$1 = ( _trimmedEndIndex$1 && _trimmedEndIndex ) || _trimmedEndIndex$1;
  303. /** Used to match leading whitespace. */
  304. var reTrimStart = /^\s+/;
  305. /**
  306. * The base implementation of `_.trim`.
  307. *
  308. * @private
  309. * @param {string} string The string to trim.
  310. * @returns {string} Returns the trimmed string.
  311. */
  312. function baseTrim(string) {
  313. return string
  314. ? string.slice(0, trimmedEndIndex$1(string) + 1).replace(reTrimStart, '')
  315. : string;
  316. }
  317. var _baseTrim = baseTrim;
  318. var _baseTrim$1 = /*#__PURE__*/Object.freeze({
  319. default: _baseTrim,
  320. __moduleExports: _baseTrim
  321. });
  322. /** Built-in value references. */
  323. var Symbol = root$1.Symbol;
  324. var _Symbol = Symbol;
  325. var _Symbol$1 = /*#__PURE__*/Object.freeze({
  326. default: _Symbol,
  327. __moduleExports: _Symbol
  328. });
  329. var Symbol$1 = ( _Symbol$1 && _Symbol ) || _Symbol$1;
  330. /** Used for built-in method references. */
  331. var objectProto = Object.prototype;
  332. /** Used to check objects for own properties. */
  333. var hasOwnProperty = objectProto.hasOwnProperty;
  334. /**
  335. * Used to resolve the
  336. * [`toStringTag`](http://ecma-international.org/ecma-262/7.0/#sec-object.prototype.tostring)
  337. * of values.
  338. */
  339. var nativeObjectToString = objectProto.toString;
  340. /** Built-in value references. */
  341. var symToStringTag = Symbol$1 ? Symbol$1.toStringTag : undefined;
  342. /**
  343. * A specialized version of `baseGetTag` which ignores `Symbol.toStringTag` values.
  344. *
  345. * @private
  346. * @param {*} value The value to query.
  347. * @returns {string} Returns the raw `toStringTag`.
  348. */
  349. function getRawTag(value) {
  350. var isOwn = hasOwnProperty.call(value, symToStringTag),
  351. tag = value[symToStringTag];
  352. try {
  353. value[symToStringTag] = undefined;
  354. } catch (e) {}
  355. var result = nativeObjectToString.call(value);
  356. {
  357. if (isOwn) {
  358. value[symToStringTag] = tag;
  359. } else {
  360. delete value[symToStringTag];
  361. }
  362. }
  363. return result;
  364. }
  365. var _getRawTag = getRawTag;
  366. var _getRawTag$1 = /*#__PURE__*/Object.freeze({
  367. default: _getRawTag,
  368. __moduleExports: _getRawTag
  369. });
  370. /** Used for built-in method references. */
  371. var objectProto$1 = Object.prototype;
  372. /**
  373. * Used to resolve the
  374. * [`toStringTag`](http://ecma-international.org/ecma-262/7.0/#sec-object.prototype.tostring)
  375. * of values.
  376. */
  377. var nativeObjectToString$1 = objectProto$1.toString;
  378. /**
  379. * Converts `value` to a string using `Object.prototype.toString`.
  380. *
  381. * @private
  382. * @param {*} value The value to convert.
  383. * @returns {string} Returns the converted string.
  384. */
  385. function objectToString(value) {
  386. return nativeObjectToString$1.call(value);
  387. }
  388. var _objectToString = objectToString;
  389. var _objectToString$1 = /*#__PURE__*/Object.freeze({
  390. default: _objectToString,
  391. __moduleExports: _objectToString
  392. });
  393. var getRawTag$1 = ( _getRawTag$1 && _getRawTag ) || _getRawTag$1;
  394. var objectToString$1 = ( _objectToString$1 && _objectToString ) || _objectToString$1;
  395. /** `Object#toString` result references. */
  396. var nullTag = '[object Null]',
  397. undefinedTag = '[object Undefined]';
  398. /** Built-in value references. */
  399. var symToStringTag$1 = Symbol$1 ? Symbol$1.toStringTag : undefined;
  400. /**
  401. * The base implementation of `getTag` without fallbacks for buggy environments.
  402. *
  403. * @private
  404. * @param {*} value The value to query.
  405. * @returns {string} Returns the `toStringTag`.
  406. */
  407. function baseGetTag(value) {
  408. if (value == null) {
  409. return value === undefined ? undefinedTag : nullTag;
  410. }
  411. return (symToStringTag$1 && symToStringTag$1 in Object(value))
  412. ? getRawTag$1(value)
  413. : objectToString$1(value);
  414. }
  415. var _baseGetTag = baseGetTag;
  416. var _baseGetTag$1 = /*#__PURE__*/Object.freeze({
  417. default: _baseGetTag,
  418. __moduleExports: _baseGetTag
  419. });
  420. /**
  421. * Checks if `value` is object-like. A value is object-like if it's not `null`
  422. * and has a `typeof` result of "object".
  423. *
  424. * @static
  425. * @memberOf _
  426. * @since 4.0.0
  427. * @category Lang
  428. * @param {*} value The value to check.
  429. * @returns {boolean} Returns `true` if `value` is object-like, else `false`.
  430. * @example
  431. *
  432. * _.isObjectLike({});
  433. * // => true
  434. *
  435. * _.isObjectLike([1, 2, 3]);
  436. * // => true
  437. *
  438. * _.isObjectLike(_.noop);
  439. * // => false
  440. *
  441. * _.isObjectLike(null);
  442. * // => false
  443. */
  444. function isObjectLike(value) {
  445. return value != null && typeof value == 'object';
  446. }
  447. var isObjectLike_1 = isObjectLike;
  448. var isObjectLike$1 = /*#__PURE__*/Object.freeze({
  449. default: isObjectLike_1,
  450. __moduleExports: isObjectLike_1
  451. });
  452. var baseGetTag$1 = ( _baseGetTag$1 && _baseGetTag ) || _baseGetTag$1;
  453. var isObjectLike$2 = ( isObjectLike$1 && isObjectLike_1 ) || isObjectLike$1;
  454. /** `Object#toString` result references. */
  455. var symbolTag = '[object Symbol]';
  456. /**
  457. * Checks if `value` is classified as a `Symbol` primitive or object.
  458. *
  459. * @static
  460. * @memberOf _
  461. * @since 4.0.0
  462. * @category Lang
  463. * @param {*} value The value to check.
  464. * @returns {boolean} Returns `true` if `value` is a symbol, else `false`.
  465. * @example
  466. *
  467. * _.isSymbol(Symbol.iterator);
  468. * // => true
  469. *
  470. * _.isSymbol('abc');
  471. * // => false
  472. */
  473. function isSymbol(value) {
  474. return typeof value == 'symbol' ||
  475. (isObjectLike$2(value) && baseGetTag$1(value) == symbolTag);
  476. }
  477. var isSymbol_1 = isSymbol;
  478. var isSymbol$1 = /*#__PURE__*/Object.freeze({
  479. default: isSymbol_1,
  480. __moduleExports: isSymbol_1
  481. });
  482. var baseTrim$1 = ( _baseTrim$1 && _baseTrim ) || _baseTrim$1;
  483. var isObject$2 = ( isObject$1 && isObject_1 ) || isObject$1;
  484. var isSymbol$2 = ( isSymbol$1 && isSymbol_1 ) || isSymbol$1;
  485. /** Used as references for various `Number` constants. */
  486. var NAN = 0 / 0;
  487. /** Used to detect bad signed hexadecimal string values. */
  488. var reIsBadHex = /^[-+]0x[0-9a-f]+$/i;
  489. /** Used to detect binary string values. */
  490. var reIsBinary = /^0b[01]+$/i;
  491. /** Used to detect octal string values. */
  492. var reIsOctal = /^0o[0-7]+$/i;
  493. /** Built-in method references without a dependency on `root`. */
  494. var freeParseInt = parseInt;
  495. /**
  496. * Converts `value` to a number.
  497. *
  498. * @static
  499. * @memberOf _
  500. * @since 4.0.0
  501. * @category Lang
  502. * @param {*} value The value to process.
  503. * @returns {number} Returns the number.
  504. * @example
  505. *
  506. * _.toNumber(3.2);
  507. * // => 3.2
  508. *
  509. * _.toNumber(Number.MIN_VALUE);
  510. * // => 5e-324
  511. *
  512. * _.toNumber(Infinity);
  513. * // => Infinity
  514. *
  515. * _.toNumber('3.2');
  516. * // => 3.2
  517. */
  518. function toNumber(value) {
  519. if (typeof value == 'number') {
  520. return value;
  521. }
  522. if (isSymbol$2(value)) {
  523. return NAN;
  524. }
  525. if (isObject$2(value)) {
  526. var other = typeof value.valueOf == 'function' ? value.valueOf() : value;
  527. value = isObject$2(other) ? (other + '') : other;
  528. }
  529. if (typeof value != 'string') {
  530. return value === 0 ? value : +value;
  531. }
  532. value = baseTrim$1(value);
  533. var isBinary = reIsBinary.test(value);
  534. return (isBinary || reIsOctal.test(value))
  535. ? freeParseInt(value.slice(2), isBinary ? 2 : 8)
  536. : (reIsBadHex.test(value) ? NAN : +value);
  537. }
  538. var toNumber_1 = toNumber;
  539. var toNumber$1 = /*#__PURE__*/Object.freeze({
  540. default: toNumber_1,
  541. __moduleExports: toNumber_1
  542. });
  543. var now$2 = ( now$1 && now_1 ) || now$1;
  544. var toNumber$2 = ( toNumber$1 && toNumber_1 ) || toNumber$1;
  545. /** Error message constants. */
  546. var FUNC_ERROR_TEXT = 'Expected a function';
  547. /* Built-in method references for those with the same name as other `lodash` methods. */
  548. var nativeMax = Math.max,
  549. nativeMin = Math.min;
  550. /**
  551. * Creates a debounced function that delays invoking `func` until after `wait`
  552. * milliseconds have elapsed since the last time the debounced function was
  553. * invoked. The debounced function comes with a `cancel` method to cancel
  554. * delayed `func` invocations and a `flush` method to immediately invoke them.
  555. * Provide `options` to indicate whether `func` should be invoked on the
  556. * leading and/or trailing edge of the `wait` timeout. The `func` is invoked
  557. * with the last arguments provided to the debounced function. Subsequent
  558. * calls to the debounced function return the result of the last `func`
  559. * invocation.
  560. *
  561. * **Note:** If `leading` and `trailing` options are `true`, `func` is
  562. * invoked on the trailing edge of the timeout only if the debounced function
  563. * is invoked more than once during the `wait` timeout.
  564. *
  565. * If `wait` is `0` and `leading` is `false`, `func` invocation is deferred
  566. * until to the next tick, similar to `setTimeout` with a timeout of `0`.
  567. *
  568. * See [David Corbacho's article](https://css-tricks.com/debouncing-throttling-explained-examples/)
  569. * for details over the differences between `_.debounce` and `_.throttle`.
  570. *
  571. * @static
  572. * @memberOf _
  573. * @since 0.1.0
  574. * @category Function
  575. * @param {Function} func The function to debounce.
  576. * @param {number} [wait=0] The number of milliseconds to delay.
  577. * @param {Object} [options={}] The options object.
  578. * @param {boolean} [options.leading=false]
  579. * Specify invoking on the leading edge of the timeout.
  580. * @param {number} [options.maxWait]
  581. * The maximum time `func` is allowed to be delayed before it's invoked.
  582. * @param {boolean} [options.trailing=true]
  583. * Specify invoking on the trailing edge of the timeout.
  584. * @returns {Function} Returns the new debounced function.
  585. * @example
  586. *
  587. * // Avoid costly calculations while the window size is in flux.
  588. * jQuery(window).on('resize', _.debounce(calculateLayout, 150));
  589. *
  590. * // Invoke `sendMail` when clicked, debouncing subsequent calls.
  591. * jQuery(element).on('click', _.debounce(sendMail, 300, {
  592. * 'leading': true,
  593. * 'trailing': false
  594. * }));
  595. *
  596. * // Ensure `batchLog` is invoked once after 1 second of debounced calls.
  597. * var debounced = _.debounce(batchLog, 250, { 'maxWait': 1000 });
  598. * var source = new EventSource('/stream');
  599. * jQuery(source).on('message', debounced);
  600. *
  601. * // Cancel the trailing debounced invocation.
  602. * jQuery(window).on('popstate', debounced.cancel);
  603. */
  604. function debounce(func, wait, options) {
  605. var lastArgs,
  606. lastThis,
  607. maxWait,
  608. result,
  609. timerId,
  610. lastCallTime,
  611. lastInvokeTime = 0,
  612. leading = false,
  613. maxing = false,
  614. trailing = true;
  615. if (typeof func != 'function') {
  616. throw new TypeError(FUNC_ERROR_TEXT);
  617. }
  618. wait = toNumber$2(wait) || 0;
  619. if (isObject$2(options)) {
  620. leading = !!options.leading;
  621. maxing = 'maxWait' in options;
  622. maxWait = maxing ? nativeMax(toNumber$2(options.maxWait) || 0, wait) : maxWait;
  623. trailing = 'trailing' in options ? !!options.trailing : trailing;
  624. }
  625. function invokeFunc(time) {
  626. var args = lastArgs,
  627. thisArg = lastThis;
  628. lastArgs = lastThis = undefined;
  629. lastInvokeTime = time;
  630. result = func.apply(thisArg, args);
  631. return result;
  632. }
  633. function leadingEdge(time) {
  634. // Reset any `maxWait` timer.
  635. lastInvokeTime = time;
  636. // Start the timer for the trailing edge.
  637. timerId = setTimeout(timerExpired, wait);
  638. // Invoke the leading edge.
  639. return leading ? invokeFunc(time) : result;
  640. }
  641. function remainingWait(time) {
  642. var timeSinceLastCall = time - lastCallTime,
  643. timeSinceLastInvoke = time - lastInvokeTime,
  644. timeWaiting = wait - timeSinceLastCall;
  645. return maxing
  646. ? nativeMin(timeWaiting, maxWait - timeSinceLastInvoke)
  647. : timeWaiting;
  648. }
  649. function shouldInvoke(time) {
  650. var timeSinceLastCall = time - lastCallTime,
  651. timeSinceLastInvoke = time - lastInvokeTime;
  652. // Either this is the first call, activity has stopped and we're at the
  653. // trailing edge, the system time has gone backwards and we're treating
  654. // it as the trailing edge, or we've hit the `maxWait` limit.
  655. return (lastCallTime === undefined || (timeSinceLastCall >= wait) ||
  656. (timeSinceLastCall < 0) || (maxing && timeSinceLastInvoke >= maxWait));
  657. }
  658. function timerExpired() {
  659. var time = now$2();
  660. if (shouldInvoke(time)) {
  661. return trailingEdge(time);
  662. }
  663. // Restart the timer.
  664. timerId = setTimeout(timerExpired, remainingWait(time));
  665. }
  666. function trailingEdge(time) {
  667. timerId = undefined;
  668. // Only invoke if we have `lastArgs` which means `func` has been
  669. // debounced at least once.
  670. if (trailing && lastArgs) {
  671. return invokeFunc(time);
  672. }
  673. lastArgs = lastThis = undefined;
  674. return result;
  675. }
  676. function cancel() {
  677. if (timerId !== undefined) {
  678. clearTimeout(timerId);
  679. }
  680. lastInvokeTime = 0;
  681. lastArgs = lastCallTime = lastThis = timerId = undefined;
  682. }
  683. function flush() {
  684. return timerId === undefined ? result : trailingEdge(now$2());
  685. }
  686. function debounced() {
  687. var time = now$2(),
  688. isInvoking = shouldInvoke(time);
  689. lastArgs = arguments;
  690. lastThis = this;
  691. lastCallTime = time;
  692. if (isInvoking) {
  693. if (timerId === undefined) {
  694. return leadingEdge(lastCallTime);
  695. }
  696. if (maxing) {
  697. // Handle invocations in a tight loop.
  698. clearTimeout(timerId);
  699. timerId = setTimeout(timerExpired, wait);
  700. return invokeFunc(lastCallTime);
  701. }
  702. }
  703. if (timerId === undefined) {
  704. timerId = setTimeout(timerExpired, wait);
  705. }
  706. return result;
  707. }
  708. debounced.cancel = cancel;
  709. debounced.flush = flush;
  710. return debounced;
  711. }
  712. var debounce_1 = debounce;
  713. var debounce$1 = /*#__PURE__*/Object.freeze({
  714. default: debounce_1,
  715. __moduleExports: debounce_1
  716. });
  717. var debounce$2 = ( debounce$1 && debounce_1 ) || debounce$1;
  718. /** Error message constants. */
  719. var FUNC_ERROR_TEXT$1 = 'Expected a function';
  720. /**
  721. * Creates a throttled function that only invokes `func` at most once per
  722. * every `wait` milliseconds. The throttled function comes with a `cancel`
  723. * method to cancel delayed `func` invocations and a `flush` method to
  724. * immediately invoke them. Provide `options` to indicate whether `func`
  725. * should be invoked on the leading and/or trailing edge of the `wait`
  726. * timeout. The `func` is invoked with the last arguments provided to the
  727. * throttled function. Subsequent calls to the throttled function return the
  728. * result of the last `func` invocation.
  729. *
  730. * **Note:** If `leading` and `trailing` options are `true`, `func` is
  731. * invoked on the trailing edge of the timeout only if the throttled function
  732. * is invoked more than once during the `wait` timeout.
  733. *
  734. * If `wait` is `0` and `leading` is `false`, `func` invocation is deferred
  735. * until to the next tick, similar to `setTimeout` with a timeout of `0`.
  736. *
  737. * See [David Corbacho's article](https://css-tricks.com/debouncing-throttling-explained-examples/)
  738. * for details over the differences between `_.throttle` and `_.debounce`.
  739. *
  740. * @static
  741. * @memberOf _
  742. * @since 0.1.0
  743. * @category Function
  744. * @param {Function} func The function to throttle.
  745. * @param {number} [wait=0] The number of milliseconds to throttle invocations to.
  746. * @param {Object} [options={}] The options object.
  747. * @param {boolean} [options.leading=true]
  748. * Specify invoking on the leading edge of the timeout.
  749. * @param {boolean} [options.trailing=true]
  750. * Specify invoking on the trailing edge of the timeout.
  751. * @returns {Function} Returns the new throttled function.
  752. * @example
  753. *
  754. * // Avoid excessively updating the position while scrolling.
  755. * jQuery(window).on('scroll', _.throttle(updatePosition, 100));
  756. *
  757. * // Invoke `renewToken` when the click event is fired, but not more than once every 5 minutes.
  758. * var throttled = _.throttle(renewToken, 300000, { 'trailing': false });
  759. * jQuery(element).on('click', throttled);
  760. *
  761. * // Cancel the trailing throttled invocation.
  762. * jQuery(window).on('popstate', throttled.cancel);
  763. */
  764. function throttle(func, wait, options) {
  765. var leading = true,
  766. trailing = true;
  767. if (typeof func != 'function') {
  768. throw new TypeError(FUNC_ERROR_TEXT$1);
  769. }
  770. if (isObject$2(options)) {
  771. leading = 'leading' in options ? !!options.leading : leading;
  772. trailing = 'trailing' in options ? !!options.trailing : trailing;
  773. }
  774. return debounce$2(func, wait, {
  775. 'leading': leading,
  776. 'maxWait': wait,
  777. 'trailing': trailing
  778. });
  779. }
  780. var throttle_1 = throttle;
  781. /** `Object#toString` result references. */
  782. var asyncTag = '[object AsyncFunction]',
  783. funcTag = '[object Function]',
  784. genTag = '[object GeneratorFunction]',
  785. proxyTag = '[object Proxy]';
  786. /**
  787. * Checks if `value` is classified as a `Function` object.
  788. *
  789. * @static
  790. * @memberOf _
  791. * @since 0.1.0
  792. * @category Lang
  793. * @param {*} value The value to check.
  794. * @returns {boolean} Returns `true` if `value` is a function, else `false`.
  795. * @example
  796. *
  797. * _.isFunction(_);
  798. * // => true
  799. *
  800. * _.isFunction(/abc/);
  801. * // => false
  802. */
  803. function isFunction(value) {
  804. if (!isObject$2(value)) {
  805. return false;
  806. }
  807. // The use of `Object#toString` avoids issues with the `typeof` operator
  808. // in Safari 9 which returns 'object' for typed arrays and other constructors.
  809. var tag = baseGetTag$1(value);
  810. return tag == funcTag || tag == genTag || tag == asyncTag || tag == proxyTag;
  811. }
  812. var isFunction_1 = isFunction;
  813. var isFunction$1 = /*#__PURE__*/Object.freeze({
  814. default: isFunction_1,
  815. __moduleExports: isFunction_1
  816. });
  817. /** Used to detect overreaching core-js shims. */
  818. var coreJsData = root$1['__core-js_shared__'];
  819. var _coreJsData = coreJsData;
  820. var _coreJsData$1 = /*#__PURE__*/Object.freeze({
  821. default: _coreJsData,
  822. __moduleExports: _coreJsData
  823. });
  824. var coreJsData$1 = ( _coreJsData$1 && _coreJsData ) || _coreJsData$1;
  825. /** Used to detect methods masquerading as native. */
  826. var maskSrcKey = (function() {
  827. var uid = /[^.]+$/.exec(coreJsData$1 && coreJsData$1.keys && coreJsData$1.keys.IE_PROTO || '');
  828. return uid ? ('Symbol(src)_1.' + uid) : '';
  829. }());
  830. /**
  831. * Checks if `func` has its source masked.
  832. *
  833. * @private
  834. * @param {Function} func The function to check.
  835. * @returns {boolean} Returns `true` if `func` is masked, else `false`.
  836. */
  837. function isMasked(func) {
  838. return !!maskSrcKey && (maskSrcKey in func);
  839. }
  840. var _isMasked = isMasked;
  841. var _isMasked$1 = /*#__PURE__*/Object.freeze({
  842. default: _isMasked,
  843. __moduleExports: _isMasked
  844. });
  845. /** Used for built-in method references. */
  846. var funcProto = Function.prototype;
  847. /** Used to resolve the decompiled source of functions. */
  848. var funcToString = funcProto.toString;
  849. /**
  850. * Converts `func` to its source code.
  851. *
  852. * @private
  853. * @param {Function} func The function to convert.
  854. * @returns {string} Returns the source code.
  855. */
  856. function toSource(func) {
  857. if (func != null) {
  858. try {
  859. return funcToString.call(func);
  860. } catch (e) {}
  861. try {
  862. return (func + '');
  863. } catch (e) {}
  864. }
  865. return '';
  866. }
  867. var _toSource = toSource;
  868. var _toSource$1 = /*#__PURE__*/Object.freeze({
  869. default: _toSource,
  870. __moduleExports: _toSource
  871. });
  872. var isFunction$2 = ( isFunction$1 && isFunction_1 ) || isFunction$1;
  873. var isMasked$1 = ( _isMasked$1 && _isMasked ) || _isMasked$1;
  874. var toSource$1 = ( _toSource$1 && _toSource ) || _toSource$1;
  875. /**
  876. * Used to match `RegExp`
  877. * [syntax characters](http://ecma-international.org/ecma-262/7.0/#sec-patterns).
  878. */
  879. var reRegExpChar = /[\\^$.*+?()[\]{}|]/g;
  880. /** Used to detect host constructors (Safari). */
  881. var reIsHostCtor = /^\[object .+?Constructor\]$/;
  882. /** Used for built-in method references. */
  883. var funcProto$1 = Function.prototype,
  884. objectProto$2 = Object.prototype;
  885. /** Used to resolve the decompiled source of functions. */
  886. var funcToString$1 = funcProto$1.toString;
  887. /** Used to check objects for own properties. */
  888. var hasOwnProperty$1 = objectProto$2.hasOwnProperty;
  889. /** Used to detect if a method is native. */
  890. var reIsNative = RegExp('^' +
  891. funcToString$1.call(hasOwnProperty$1).replace(reRegExpChar, '\\$&')
  892. .replace(/hasOwnProperty|(function).*?(?=\\\()| for .+?(?=\\\])/g, '$1.*?') + '$'
  893. );
  894. /**
  895. * The base implementation of `_.isNative` without bad shim checks.
  896. *
  897. * @private
  898. * @param {*} value The value to check.
  899. * @returns {boolean} Returns `true` if `value` is a native function,
  900. * else `false`.
  901. */
  902. function baseIsNative(value) {
  903. if (!isObject$2(value) || isMasked$1(value)) {
  904. return false;
  905. }
  906. var pattern = isFunction$2(value) ? reIsNative : reIsHostCtor;
  907. return pattern.test(toSource$1(value));
  908. }
  909. var _baseIsNative = baseIsNative;
  910. var _baseIsNative$1 = /*#__PURE__*/Object.freeze({
  911. default: _baseIsNative,
  912. __moduleExports: _baseIsNative
  913. });
  914. /**
  915. * Gets the value at `key` of `object`.
  916. *
  917. * @private
  918. * @param {Object} [object] The object to query.
  919. * @param {string} key The key of the property to get.
  920. * @returns {*} Returns the property value.
  921. */
  922. function getValue(object, key) {
  923. return object == null ? undefined : object[key];
  924. }
  925. var _getValue = getValue;
  926. var _getValue$1 = /*#__PURE__*/Object.freeze({
  927. default: _getValue,
  928. __moduleExports: _getValue
  929. });
  930. var baseIsNative$1 = ( _baseIsNative$1 && _baseIsNative ) || _baseIsNative$1;
  931. var getValue$1 = ( _getValue$1 && _getValue ) || _getValue$1;
  932. /**
  933. * Gets the native function at `key` of `object`.
  934. *
  935. * @private
  936. * @param {Object} object The object to query.
  937. * @param {string} key The key of the method to get.
  938. * @returns {*} Returns the function if it's native, else `undefined`.
  939. */
  940. function getNative(object, key) {
  941. var value = getValue$1(object, key);
  942. return baseIsNative$1(value) ? value : undefined;
  943. }
  944. var _getNative = getNative;
  945. var _getNative$1 = /*#__PURE__*/Object.freeze({
  946. default: _getNative,
  947. __moduleExports: _getNative
  948. });
  949. var getNative$1 = ( _getNative$1 && _getNative ) || _getNative$1;
  950. /* Built-in method references that are verified to be native. */
  951. var nativeCreate = getNative$1(Object, 'create');
  952. var _nativeCreate = nativeCreate;
  953. var _nativeCreate$1 = /*#__PURE__*/Object.freeze({
  954. default: _nativeCreate,
  955. __moduleExports: _nativeCreate
  956. });
  957. var nativeCreate$1 = ( _nativeCreate$1 && _nativeCreate ) || _nativeCreate$1;
  958. /**
  959. * Removes all key-value entries from the hash.
  960. *
  961. * @private
  962. * @name clear
  963. * @memberOf Hash
  964. */
  965. function hashClear() {
  966. this.__data__ = nativeCreate$1 ? nativeCreate$1(null) : {};
  967. this.size = 0;
  968. }
  969. var _hashClear = hashClear;
  970. var _hashClear$1 = /*#__PURE__*/Object.freeze({
  971. default: _hashClear,
  972. __moduleExports: _hashClear
  973. });
  974. /**
  975. * Removes `key` and its value from the hash.
  976. *
  977. * @private
  978. * @name delete
  979. * @memberOf Hash
  980. * @param {Object} hash The hash to modify.
  981. * @param {string} key The key of the value to remove.
  982. * @returns {boolean} Returns `true` if the entry was removed, else `false`.
  983. */
  984. function hashDelete(key) {
  985. var result = this.has(key) && delete this.__data__[key];
  986. this.size -= result ? 1 : 0;
  987. return result;
  988. }
  989. var _hashDelete = hashDelete;
  990. var _hashDelete$1 = /*#__PURE__*/Object.freeze({
  991. default: _hashDelete,
  992. __moduleExports: _hashDelete
  993. });
  994. /** Used to stand-in for `undefined` hash values. */
  995. var HASH_UNDEFINED = '__lodash_hash_undefined__';
  996. /** Used for built-in method references. */
  997. var objectProto$3 = Object.prototype;
  998. /** Used to check objects for own properties. */
  999. var hasOwnProperty$2 = objectProto$3.hasOwnProperty;
  1000. /**
  1001. * Gets the hash value for `key`.
  1002. *
  1003. * @private
  1004. * @name get
  1005. * @memberOf Hash
  1006. * @param {string} key The key of the value to get.
  1007. * @returns {*} Returns the entry value.
  1008. */
  1009. function hashGet(key) {
  1010. var data = this.__data__;
  1011. if (nativeCreate$1) {
  1012. var result = data[key];
  1013. return result === HASH_UNDEFINED ? undefined : result;
  1014. }
  1015. return hasOwnProperty$2.call(data, key) ? data[key] : undefined;
  1016. }
  1017. var _hashGet = hashGet;
  1018. var _hashGet$1 = /*#__PURE__*/Object.freeze({
  1019. default: _hashGet,
  1020. __moduleExports: _hashGet
  1021. });
  1022. /** Used for built-in method references. */
  1023. var objectProto$4 = Object.prototype;
  1024. /** Used to check objects for own properties. */
  1025. var hasOwnProperty$3 = objectProto$4.hasOwnProperty;
  1026. /**
  1027. * Checks if a hash value for `key` exists.
  1028. *
  1029. * @private
  1030. * @name has
  1031. * @memberOf Hash
  1032. * @param {string} key The key of the entry to check.
  1033. * @returns {boolean} Returns `true` if an entry for `key` exists, else `false`.
  1034. */
  1035. function hashHas(key) {
  1036. var data = this.__data__;
  1037. return nativeCreate$1 ? (data[key] !== undefined) : hasOwnProperty$3.call(data, key);
  1038. }
  1039. var _hashHas = hashHas;
  1040. var _hashHas$1 = /*#__PURE__*/Object.freeze({
  1041. default: _hashHas,
  1042. __moduleExports: _hashHas
  1043. });
  1044. /** Used to stand-in for `undefined` hash values. */
  1045. var HASH_UNDEFINED$1 = '__lodash_hash_undefined__';
  1046. /**
  1047. * Sets the hash `key` to `value`.
  1048. *
  1049. * @private
  1050. * @name set
  1051. * @memberOf Hash
  1052. * @param {string} key The key of the value to set.
  1053. * @param {*} value The value to set.
  1054. * @returns {Object} Returns the hash instance.
  1055. */
  1056. function hashSet(key, value) {
  1057. var data = this.__data__;
  1058. this.size += this.has(key) ? 0 : 1;
  1059. data[key] = (nativeCreate$1 && value === undefined) ? HASH_UNDEFINED$1 : value;
  1060. return this;
  1061. }
  1062. var _hashSet = hashSet;
  1063. var _hashSet$1 = /*#__PURE__*/Object.freeze({
  1064. default: _hashSet,
  1065. __moduleExports: _hashSet
  1066. });
  1067. var hashClear$1 = ( _hashClear$1 && _hashClear ) || _hashClear$1;
  1068. var hashDelete$1 = ( _hashDelete$1 && _hashDelete ) || _hashDelete$1;
  1069. var hashGet$1 = ( _hashGet$1 && _hashGet ) || _hashGet$1;
  1070. var hashHas$1 = ( _hashHas$1 && _hashHas ) || _hashHas$1;
  1071. var hashSet$1 = ( _hashSet$1 && _hashSet ) || _hashSet$1;
  1072. /**
  1073. * Creates a hash object.
  1074. *
  1075. * @private
  1076. * @constructor
  1077. * @param {Array} [entries] The key-value pairs to cache.
  1078. */
  1079. function Hash(entries) {
  1080. var index = -1,
  1081. length = entries == null ? 0 : entries.length;
  1082. this.clear();
  1083. while (++index < length) {
  1084. var entry = entries[index];
  1085. this.set(entry[0], entry[1]);
  1086. }
  1087. }
  1088. // Add methods to `Hash`.
  1089. Hash.prototype.clear = hashClear$1;
  1090. Hash.prototype['delete'] = hashDelete$1;
  1091. Hash.prototype.get = hashGet$1;
  1092. Hash.prototype.has = hashHas$1;
  1093. Hash.prototype.set = hashSet$1;
  1094. var _Hash = Hash;
  1095. var _Hash$1 = /*#__PURE__*/Object.freeze({
  1096. default: _Hash,
  1097. __moduleExports: _Hash
  1098. });
  1099. /**
  1100. * Removes all key-value entries from the list cache.
  1101. *
  1102. * @private
  1103. * @name clear
  1104. * @memberOf ListCache
  1105. */
  1106. function listCacheClear() {
  1107. this.__data__ = [];
  1108. this.size = 0;
  1109. }
  1110. var _listCacheClear = listCacheClear;
  1111. var _listCacheClear$1 = /*#__PURE__*/Object.freeze({
  1112. default: _listCacheClear,
  1113. __moduleExports: _listCacheClear
  1114. });
  1115. /**
  1116. * Performs a
  1117. * [`SameValueZero`](http://ecma-international.org/ecma-262/7.0/#sec-samevaluezero)
  1118. * comparison between two values to determine if they are equivalent.
  1119. *
  1120. * @static
  1121. * @memberOf _
  1122. * @since 4.0.0
  1123. * @category Lang
  1124. * @param {*} value The value to compare.
  1125. * @param {*} other The other value to compare.
  1126. * @returns {boolean} Returns `true` if the values are equivalent, else `false`.
  1127. * @example
  1128. *
  1129. * var object = { 'a': 1 };
  1130. * var other = { 'a': 1 };
  1131. *
  1132. * _.eq(object, object);
  1133. * // => true
  1134. *
  1135. * _.eq(object, other);
  1136. * // => false
  1137. *
  1138. * _.eq('a', 'a');
  1139. * // => true
  1140. *
  1141. * _.eq('a', Object('a'));
  1142. * // => false
  1143. *
  1144. * _.eq(NaN, NaN);
  1145. * // => true
  1146. */
  1147. function eq(value, other) {
  1148. return value === other || (value !== value && other !== other);
  1149. }
  1150. var eq_1 = eq;
  1151. var eq$1 = /*#__PURE__*/Object.freeze({
  1152. default: eq_1,
  1153. __moduleExports: eq_1
  1154. });
  1155. var eq$2 = ( eq$1 && eq_1 ) || eq$1;
  1156. /**
  1157. * Gets the index at which the `key` is found in `array` of key-value pairs.
  1158. *
  1159. * @private
  1160. * @param {Array} array The array to inspect.
  1161. * @param {*} key The key to search for.
  1162. * @returns {number} Returns the index of the matched value, else `-1`.
  1163. */
  1164. function assocIndexOf(array, key) {
  1165. var length = array.length;
  1166. while (length--) {
  1167. if (eq$2(array[length][0], key)) {
  1168. return length;
  1169. }
  1170. }
  1171. return -1;
  1172. }
  1173. var _assocIndexOf = assocIndexOf;
  1174. var _assocIndexOf$1 = /*#__PURE__*/Object.freeze({
  1175. default: _assocIndexOf,
  1176. __moduleExports: _assocIndexOf
  1177. });
  1178. var assocIndexOf$1 = ( _assocIndexOf$1 && _assocIndexOf ) || _assocIndexOf$1;
  1179. /** Used for built-in method references. */
  1180. var arrayProto = Array.prototype;
  1181. /** Built-in value references. */
  1182. var splice = arrayProto.splice;
  1183. /**
  1184. * Removes `key` and its value from the list cache.
  1185. *
  1186. * @private
  1187. * @name delete
  1188. * @memberOf ListCache
  1189. * @param {string} key The key of the value to remove.
  1190. * @returns {boolean} Returns `true` if the entry was removed, else `false`.
  1191. */
  1192. function listCacheDelete(key) {
  1193. var data = this.__data__,
  1194. index = assocIndexOf$1(data, key);
  1195. if (index < 0) {
  1196. return false;
  1197. }
  1198. var lastIndex = data.length - 1;
  1199. if (index == lastIndex) {
  1200. data.pop();
  1201. } else {
  1202. splice.call(data, index, 1);
  1203. }
  1204. --this.size;
  1205. return true;
  1206. }
  1207. var _listCacheDelete = listCacheDelete;
  1208. var _listCacheDelete$1 = /*#__PURE__*/Object.freeze({
  1209. default: _listCacheDelete,
  1210. __moduleExports: _listCacheDelete
  1211. });
  1212. /**
  1213. * Gets the list cache value for `key`.
  1214. *
  1215. * @private
  1216. * @name get
  1217. * @memberOf ListCache
  1218. * @param {string} key The key of the value to get.
  1219. * @returns {*} Returns the entry value.
  1220. */
  1221. function listCacheGet(key) {
  1222. var data = this.__data__,
  1223. index = assocIndexOf$1(data, key);
  1224. return index < 0 ? undefined : data[index][1];
  1225. }
  1226. var _listCacheGet = listCacheGet;
  1227. var _listCacheGet$1 = /*#__PURE__*/Object.freeze({
  1228. default: _listCacheGet,
  1229. __moduleExports: _listCacheGet
  1230. });
  1231. /**
  1232. * Checks if a list cache value for `key` exists.
  1233. *
  1234. * @private
  1235. * @name has
  1236. * @memberOf ListCache
  1237. * @param {string} key The key of the entry to check.
  1238. * @returns {boolean} Returns `true` if an entry for `key` exists, else `false`.
  1239. */
  1240. function listCacheHas(key) {
  1241. return assocIndexOf$1(this.__data__, key) > -1;
  1242. }
  1243. var _listCacheHas = listCacheHas;
  1244. var _listCacheHas$1 = /*#__PURE__*/Object.freeze({
  1245. default: _listCacheHas,
  1246. __moduleExports: _listCacheHas
  1247. });
  1248. /**
  1249. * Sets the list cache `key` to `value`.
  1250. *
  1251. * @private
  1252. * @name set
  1253. * @memberOf ListCache
  1254. * @param {string} key The key of the value to set.
  1255. * @param {*} value The value to set.
  1256. * @returns {Object} Returns the list cache instance.
  1257. */
  1258. function listCacheSet(key, value) {
  1259. var data = this.__data__,
  1260. index = assocIndexOf$1(data, key);
  1261. if (index < 0) {
  1262. ++this.size;
  1263. data.push([key, value]);
  1264. } else {
  1265. data[index][1] = value;
  1266. }
  1267. return this;
  1268. }
  1269. var _listCacheSet = listCacheSet;
  1270. var _listCacheSet$1 = /*#__PURE__*/Object.freeze({
  1271. default: _listCacheSet,
  1272. __moduleExports: _listCacheSet
  1273. });
  1274. var listCacheClear$1 = ( _listCacheClear$1 && _listCacheClear ) || _listCacheClear$1;
  1275. var listCacheDelete$1 = ( _listCacheDelete$1 && _listCacheDelete ) || _listCacheDelete$1;
  1276. var listCacheGet$1 = ( _listCacheGet$1 && _listCacheGet ) || _listCacheGet$1;
  1277. var listCacheHas$1 = ( _listCacheHas$1 && _listCacheHas ) || _listCacheHas$1;
  1278. var listCacheSet$1 = ( _listCacheSet$1 && _listCacheSet ) || _listCacheSet$1;
  1279. /**
  1280. * Creates an list cache object.
  1281. *
  1282. * @private
  1283. * @constructor
  1284. * @param {Array} [entries] The key-value pairs to cache.
  1285. */
  1286. function ListCache(entries) {
  1287. var index = -1,
  1288. length = entries == null ? 0 : entries.length;
  1289. this.clear();
  1290. while (++index < length) {
  1291. var entry = entries[index];
  1292. this.set(entry[0], entry[1]);
  1293. }
  1294. }
  1295. // Add methods to `ListCache`.
  1296. ListCache.prototype.clear = listCacheClear$1;
  1297. ListCache.prototype['delete'] = listCacheDelete$1;
  1298. ListCache.prototype.get = listCacheGet$1;
  1299. ListCache.prototype.has = listCacheHas$1;
  1300. ListCache.prototype.set = listCacheSet$1;
  1301. var _ListCache = ListCache;
  1302. var _ListCache$1 = /*#__PURE__*/Object.freeze({
  1303. default: _ListCache,
  1304. __moduleExports: _ListCache
  1305. });
  1306. /* Built-in method references that are verified to be native. */
  1307. var Map = getNative$1(root$1, 'Map');
  1308. var _Map = Map;
  1309. var _Map$1 = /*#__PURE__*/Object.freeze({
  1310. default: _Map,
  1311. __moduleExports: _Map
  1312. });
  1313. var Hash$1 = ( _Hash$1 && _Hash ) || _Hash$1;
  1314. var ListCache$1 = ( _ListCache$1 && _ListCache ) || _ListCache$1;
  1315. var Map$1 = ( _Map$1 && _Map ) || _Map$1;
  1316. /**
  1317. * Removes all key-value entries from the map.
  1318. *
  1319. * @private
  1320. * @name clear
  1321. * @memberOf MapCache
  1322. */
  1323. function mapCacheClear() {
  1324. this.size = 0;
  1325. this.__data__ = {
  1326. 'hash': new Hash$1,
  1327. 'map': new (Map$1 || ListCache$1),
  1328. 'string': new Hash$1
  1329. };
  1330. }
  1331. var _mapCacheClear = mapCacheClear;
  1332. var _mapCacheClear$1 = /*#__PURE__*/Object.freeze({
  1333. default: _mapCacheClear,
  1334. __moduleExports: _mapCacheClear
  1335. });
  1336. /**
  1337. * Checks if `value` is suitable for use as unique object key.
  1338. *
  1339. * @private
  1340. * @param {*} value The value to check.
  1341. * @returns {boolean} Returns `true` if `value` is suitable, else `false`.
  1342. */
  1343. function isKeyable(value) {
  1344. var type = typeof value;
  1345. return (type == 'string' || type == 'number' || type == 'symbol' || type == 'boolean')
  1346. ? (value !== '__proto__')
  1347. : (value === null);
  1348. }
  1349. var _isKeyable = isKeyable;
  1350. var _isKeyable$1 = /*#__PURE__*/Object.freeze({
  1351. default: _isKeyable,
  1352. __moduleExports: _isKeyable
  1353. });
  1354. var isKeyable$1 = ( _isKeyable$1 && _isKeyable ) || _isKeyable$1;
  1355. /**
  1356. * Gets the data for `map`.
  1357. *
  1358. * @private
  1359. * @param {Object} map The map to query.
  1360. * @param {string} key The reference key.
  1361. * @returns {*} Returns the map data.
  1362. */
  1363. function getMapData(map, key) {
  1364. var data = map.__data__;
  1365. return isKeyable$1(key)
  1366. ? data[typeof key == 'string' ? 'string' : 'hash']
  1367. : data.map;
  1368. }
  1369. var _getMapData = getMapData;
  1370. var _getMapData$1 = /*#__PURE__*/Object.freeze({
  1371. default: _getMapData,
  1372. __moduleExports: _getMapData
  1373. });
  1374. var getMapData$1 = ( _getMapData$1 && _getMapData ) || _getMapData$1;
  1375. /**
  1376. * Removes `key` and its value from the map.
  1377. *
  1378. * @private
  1379. * @name delete
  1380. * @memberOf MapCache
  1381. * @param {string} key The key of the value to remove.
  1382. * @returns {boolean} Returns `true` if the entry was removed, else `false`.
  1383. */
  1384. function mapCacheDelete(key) {
  1385. var result = getMapData$1(this, key)['delete'](key);
  1386. this.size -= result ? 1 : 0;
  1387. return result;
  1388. }
  1389. var _mapCacheDelete = mapCacheDelete;
  1390. var _mapCacheDelete$1 = /*#__PURE__*/Object.freeze({
  1391. default: _mapCacheDelete,
  1392. __moduleExports: _mapCacheDelete
  1393. });
  1394. /**
  1395. * Gets the map value for `key`.
  1396. *
  1397. * @private
  1398. * @name get
  1399. * @memberOf MapCache
  1400. * @param {string} key The key of the value to get.
  1401. * @returns {*} Returns the entry value.
  1402. */
  1403. function mapCacheGet(key) {
  1404. return getMapData$1(this, key).get(key);
  1405. }
  1406. var _mapCacheGet = mapCacheGet;
  1407. var _mapCacheGet$1 = /*#__PURE__*/Object.freeze({
  1408. default: _mapCacheGet,
  1409. __moduleExports: _mapCacheGet
  1410. });
  1411. /**
  1412. * Checks if a map value for `key` exists.
  1413. *
  1414. * @private
  1415. * @name has
  1416. * @memberOf MapCache
  1417. * @param {string} key The key of the entry to check.
  1418. * @returns {boolean} Returns `true` if an entry for `key` exists, else `false`.
  1419. */
  1420. function mapCacheHas(key) {
  1421. return getMapData$1(this, key).has(key);
  1422. }
  1423. var _mapCacheHas = mapCacheHas;
  1424. var _mapCacheHas$1 = /*#__PURE__*/Object.freeze({
  1425. default: _mapCacheHas,
  1426. __moduleExports: _mapCacheHas
  1427. });
  1428. /**
  1429. * Sets the map `key` to `value`.
  1430. *
  1431. * @private
  1432. * @name set
  1433. * @memberOf MapCache
  1434. * @param {string} key The key of the value to set.
  1435. * @param {*} value The value to set.
  1436. * @returns {Object} Returns the map cache instance.
  1437. */
  1438. function mapCacheSet(key, value) {
  1439. var data = getMapData$1(this, key),
  1440. size = data.size;
  1441. data.set(key, value);
  1442. this.size += data.size == size ? 0 : 1;
  1443. return this;
  1444. }
  1445. var _mapCacheSet = mapCacheSet;
  1446. var _mapCacheSet$1 = /*#__PURE__*/Object.freeze({
  1447. default: _mapCacheSet,
  1448. __moduleExports: _mapCacheSet
  1449. });
  1450. var mapCacheClear$1 = ( _mapCacheClear$1 && _mapCacheClear ) || _mapCacheClear$1;
  1451. var mapCacheDelete$1 = ( _mapCacheDelete$1 && _mapCacheDelete ) || _mapCacheDelete$1;
  1452. var mapCacheGet$1 = ( _mapCacheGet$1 && _mapCacheGet ) || _mapCacheGet$1;
  1453. var mapCacheHas$1 = ( _mapCacheHas$1 && _mapCacheHas ) || _mapCacheHas$1;
  1454. var mapCacheSet$1 = ( _mapCacheSet$1 && _mapCacheSet ) || _mapCacheSet$1;
  1455. /**
  1456. * Creates a map cache object to store key-value pairs.
  1457. *
  1458. * @private
  1459. * @constructor
  1460. * @param {Array} [entries] The key-value pairs to cache.
  1461. */
  1462. function MapCache(entries) {
  1463. var index = -1,
  1464. length = entries == null ? 0 : entries.length;
  1465. this.clear();
  1466. while (++index < length) {
  1467. var entry = entries[index];
  1468. this.set(entry[0], entry[1]);
  1469. }
  1470. }
  1471. // Add methods to `MapCache`.
  1472. MapCache.prototype.clear = mapCacheClear$1;
  1473. MapCache.prototype['delete'] = mapCacheDelete$1;
  1474. MapCache.prototype.get = mapCacheGet$1;
  1475. MapCache.prototype.has = mapCacheHas$1;
  1476. MapCache.prototype.set = mapCacheSet$1;
  1477. var _MapCache = MapCache;
  1478. var _MapCache$1 = /*#__PURE__*/Object.freeze({
  1479. default: _MapCache,
  1480. __moduleExports: _MapCache
  1481. });
  1482. /** Used to stand-in for `undefined` hash values. */
  1483. var HASH_UNDEFINED$2 = '__lodash_hash_undefined__';
  1484. /**
  1485. * Adds `value` to the array cache.
  1486. *
  1487. * @private
  1488. * @name add
  1489. * @memberOf SetCache
  1490. * @alias push
  1491. * @param {*} value The value to cache.
  1492. * @returns {Object} Returns the cache instance.
  1493. */
  1494. function setCacheAdd(value) {
  1495. this.__data__.set(value, HASH_UNDEFINED$2);
  1496. return this;
  1497. }
  1498. var _setCacheAdd = setCacheAdd;
  1499. var _setCacheAdd$1 = /*#__PURE__*/Object.freeze({
  1500. default: _setCacheAdd,
  1501. __moduleExports: _setCacheAdd
  1502. });
  1503. /**
  1504. * Checks if `value` is in the array cache.
  1505. *
  1506. * @private
  1507. * @name has
  1508. * @memberOf SetCache
  1509. * @param {*} value The value to search for.
  1510. * @returns {number} Returns `true` if `value` is found, else `false`.
  1511. */
  1512. function setCacheHas(value) {
  1513. return this.__data__.has(value);
  1514. }
  1515. var _setCacheHas = setCacheHas;
  1516. var _setCacheHas$1 = /*#__PURE__*/Object.freeze({
  1517. default: _setCacheHas,
  1518. __moduleExports: _setCacheHas
  1519. });
  1520. var MapCache$1 = ( _MapCache$1 && _MapCache ) || _MapCache$1;
  1521. var setCacheAdd$1 = ( _setCacheAdd$1 && _setCacheAdd ) || _setCacheAdd$1;
  1522. var setCacheHas$1 = ( _setCacheHas$1 && _setCacheHas ) || _setCacheHas$1;
  1523. /**
  1524. *
  1525. * Creates an array cache object to store unique values.
  1526. *
  1527. * @private
  1528. * @constructor
  1529. * @param {Array} [values] The values to cache.
  1530. */
  1531. function SetCache(values) {
  1532. var index = -1,
  1533. length = values == null ? 0 : values.length;
  1534. this.__data__ = new MapCache$1;
  1535. while (++index < length) {
  1536. this.add(values[index]);
  1537. }
  1538. }
  1539. // Add methods to `SetCache`.
  1540. SetCache.prototype.add = SetCache.prototype.push = setCacheAdd$1;
  1541. SetCache.prototype.has = setCacheHas$1;
  1542. var _SetCache = SetCache;
  1543. var _SetCache$1 = /*#__PURE__*/Object.freeze({
  1544. default: _SetCache,
  1545. __moduleExports: _SetCache
  1546. });
  1547. /**
  1548. * The base implementation of `_.findIndex` and `_.findLastIndex` without
  1549. * support for iteratee shorthands.
  1550. *
  1551. * @private
  1552. * @param {Array} array The array to inspect.
  1553. * @param {Function} predicate The function invoked per iteration.
  1554. * @param {number} fromIndex The index to search from.
  1555. * @param {boolean} [fromRight] Specify iterating from right to left.
  1556. * @returns {number} Returns the index of the matched value, else `-1`.
  1557. */
  1558. function baseFindIndex(array, predicate, fromIndex, fromRight) {
  1559. var length = array.length,
  1560. index = fromIndex + (fromRight ? 1 : -1);
  1561. while ((fromRight ? index-- : ++index < length)) {
  1562. if (predicate(array[index], index, array)) {
  1563. return index;
  1564. }
  1565. }
  1566. return -1;
  1567. }
  1568. var _baseFindIndex = baseFindIndex;
  1569. var _baseFindIndex$1 = /*#__PURE__*/Object.freeze({
  1570. default: _baseFindIndex,
  1571. __moduleExports: _baseFindIndex
  1572. });
  1573. /**
  1574. * The base implementation of `_.isNaN` without support for number objects.
  1575. *
  1576. * @private
  1577. * @param {*} value The value to check.
  1578. * @returns {boolean} Returns `true` if `value` is `NaN`, else `false`.
  1579. */
  1580. function baseIsNaN(value) {
  1581. return value !== value;
  1582. }
  1583. var _baseIsNaN = baseIsNaN;
  1584. var _baseIsNaN$1 = /*#__PURE__*/Object.freeze({
  1585. default: _baseIsNaN,
  1586. __moduleExports: _baseIsNaN
  1587. });
  1588. /**
  1589. * A specialized version of `_.indexOf` which performs strict equality
  1590. * comparisons of values, i.e. `===`.
  1591. *
  1592. * @private
  1593. * @param {Array} array The array to inspect.
  1594. * @param {*} value The value to search for.
  1595. * @param {number} fromIndex The index to search from.
  1596. * @returns {number} Returns the index of the matched value, else `-1`.
  1597. */
  1598. function strictIndexOf(array, value, fromIndex) {
  1599. var index = fromIndex - 1,
  1600. length = array.length;
  1601. while (++index < length) {
  1602. if (array[index] === value) {
  1603. return index;
  1604. }
  1605. }
  1606. return -1;
  1607. }
  1608. var _strictIndexOf = strictIndexOf;
  1609. var _strictIndexOf$1 = /*#__PURE__*/Object.freeze({
  1610. default: _strictIndexOf,
  1611. __moduleExports: _strictIndexOf
  1612. });
  1613. var baseFindIndex$1 = ( _baseFindIndex$1 && _baseFindIndex ) || _baseFindIndex$1;
  1614. var baseIsNaN$1 = ( _baseIsNaN$1 && _baseIsNaN ) || _baseIsNaN$1;
  1615. var strictIndexOf$1 = ( _strictIndexOf$1 && _strictIndexOf ) || _strictIndexOf$1;
  1616. /**
  1617. * The base implementation of `_.indexOf` without `fromIndex` bounds checks.
  1618. *
  1619. * @private
  1620. * @param {Array} array The array to inspect.
  1621. * @param {*} value The value to search for.
  1622. * @param {number} fromIndex The index to search from.
  1623. * @returns {number} Returns the index of the matched value, else `-1`.
  1624. */
  1625. function baseIndexOf(array, value, fromIndex) {
  1626. return value === value
  1627. ? strictIndexOf$1(array, value, fromIndex)
  1628. : baseFindIndex$1(array, baseIsNaN$1, fromIndex);
  1629. }
  1630. var _baseIndexOf = baseIndexOf;
  1631. var _baseIndexOf$1 = /*#__PURE__*/Object.freeze({
  1632. default: _baseIndexOf,
  1633. __moduleExports: _baseIndexOf
  1634. });
  1635. var baseIndexOf$1 = ( _baseIndexOf$1 && _baseIndexOf ) || _baseIndexOf$1;
  1636. /**
  1637. * A specialized version of `_.includes` for arrays without support for
  1638. * specifying an index to search from.
  1639. *
  1640. * @private
  1641. * @param {Array} [array] The array to inspect.
  1642. * @param {*} target The value to search for.
  1643. * @returns {boolean} Returns `true` if `target` is found, else `false`.
  1644. */
  1645. function arrayIncludes(array, value) {
  1646. var length = array == null ? 0 : array.length;
  1647. return !!length && baseIndexOf$1(array, value, 0) > -1;
  1648. }
  1649. var _arrayIncludes = arrayIncludes;
  1650. var _arrayIncludes$1 = /*#__PURE__*/Object.freeze({
  1651. default: _arrayIncludes,
  1652. __moduleExports: _arrayIncludes
  1653. });
  1654. /**
  1655. * This function is like `arrayIncludes` except that it accepts a comparator.
  1656. *
  1657. * @private
  1658. * @param {Array} [array] The array to inspect.
  1659. * @param {*} target The value to search for.
  1660. * @param {Function} comparator The comparator invoked per element.
  1661. * @returns {boolean} Returns `true` if `target` is found, else `false`.
  1662. */
  1663. function arrayIncludesWith(array, value, comparator) {
  1664. var index = -1,
  1665. length = array == null ? 0 : array.length;
  1666. while (++index < length) {
  1667. if (comparator(value, array[index])) {
  1668. return true;
  1669. }
  1670. }
  1671. return false;
  1672. }
  1673. var _arrayIncludesWith = arrayIncludesWith;
  1674. var _arrayIncludesWith$1 = /*#__PURE__*/Object.freeze({
  1675. default: _arrayIncludesWith,
  1676. __moduleExports: _arrayIncludesWith
  1677. });
  1678. /**
  1679. * Checks if a `cache` value for `key` exists.
  1680. *
  1681. * @private
  1682. * @param {Object} cache The cache to query.
  1683. * @param {string} key The key of the entry to check.
  1684. * @returns {boolean} Returns `true` if an entry for `key` exists, else `false`.
  1685. */
  1686. function cacheHas(cache, key) {
  1687. return cache.has(key);
  1688. }
  1689. var _cacheHas = cacheHas;
  1690. var _cacheHas$1 = /*#__PURE__*/Object.freeze({
  1691. default: _cacheHas,
  1692. __moduleExports: _cacheHas
  1693. });
  1694. /* Built-in method references that are verified to be native. */
  1695. var Set = getNative$1(root$1, 'Set');
  1696. var _Set = Set;
  1697. var _Set$1 = /*#__PURE__*/Object.freeze({
  1698. default: _Set,
  1699. __moduleExports: _Set
  1700. });
  1701. /**
  1702. * This method returns `undefined`.
  1703. *
  1704. * @static
  1705. * @memberOf _
  1706. * @since 2.3.0
  1707. * @category Util
  1708. * @example
  1709. *
  1710. * _.times(2, _.noop);
  1711. * // => [undefined, undefined]
  1712. */
  1713. function noop() {
  1714. // No operation performed.
  1715. }
  1716. var noop_1 = noop;
  1717. var noop$1 = /*#__PURE__*/Object.freeze({
  1718. default: noop_1,
  1719. __moduleExports: noop_1
  1720. });
  1721. /**
  1722. * Converts `set` to an array of its values.
  1723. *
  1724. * @private
  1725. * @param {Object} set The set to convert.
  1726. * @returns {Array} Returns the values.
  1727. */
  1728. function setToArray(set) {
  1729. var index = -1,
  1730. result = Array(set.size);
  1731. set.forEach(function(value) {
  1732. result[++index] = value;
  1733. });
  1734. return result;
  1735. }
  1736. var _setToArray = setToArray;
  1737. var _setToArray$1 = /*#__PURE__*/Object.freeze({
  1738. default: _setToArray,
  1739. __moduleExports: _setToArray
  1740. });
  1741. var Set$1 = ( _Set$1 && _Set ) || _Set$1;
  1742. var noop$2 = ( noop$1 && noop_1 ) || noop$1;
  1743. var setToArray$1 = ( _setToArray$1 && _setToArray ) || _setToArray$1;
  1744. /** Used as references for various `Number` constants. */
  1745. var INFINITY = 1 / 0;
  1746. /**
  1747. * Creates a set object of `values`.
  1748. *
  1749. * @private
  1750. * @param {Array} values The values to add to the set.
  1751. * @returns {Object} Returns the new set.
  1752. */
  1753. var createSet = !(Set$1 && (1 / setToArray$1(new Set$1([,-0]))[1]) == INFINITY) ? noop$2 : function(values) {
  1754. return new Set$1(values);
  1755. };
  1756. var _createSet = createSet;
  1757. var _createSet$1 = /*#__PURE__*/Object.freeze({
  1758. default: _createSet,
  1759. __moduleExports: _createSet
  1760. });
  1761. var SetCache$1 = ( _SetCache$1 && _SetCache ) || _SetCache$1;
  1762. var arrayIncludes$1 = ( _arrayIncludes$1 && _arrayIncludes ) || _arrayIncludes$1;
  1763. var arrayIncludesWith$1 = ( _arrayIncludesWith$1 && _arrayIncludesWith ) || _arrayIncludesWith$1;
  1764. var cacheHas$1 = ( _cacheHas$1 && _cacheHas ) || _cacheHas$1;
  1765. var createSet$1 = ( _createSet$1 && _createSet ) || _createSet$1;
  1766. /** Used as the size to enable large array optimizations. */
  1767. var LARGE_ARRAY_SIZE = 200;
  1768. /**
  1769. * The base implementation of `_.uniqBy` without support for iteratee shorthands.
  1770. *
  1771. * @private
  1772. * @param {Array} array The array to inspect.
  1773. * @param {Function} [iteratee] The iteratee invoked per element.
  1774. * @param {Function} [comparator] The comparator invoked per element.
  1775. * @returns {Array} Returns the new duplicate free array.
  1776. */
  1777. function baseUniq(array, iteratee, comparator) {
  1778. var index = -1,
  1779. includes = arrayIncludes$1,
  1780. length = array.length,
  1781. isCommon = true,
  1782. result = [],
  1783. seen = result;
  1784. if (comparator) {
  1785. isCommon = false;
  1786. includes = arrayIncludesWith$1;
  1787. }
  1788. else if (length >= LARGE_ARRAY_SIZE) {
  1789. var set = iteratee ? null : createSet$1(array);
  1790. if (set) {
  1791. return setToArray$1(set);
  1792. }
  1793. isCommon = false;
  1794. includes = cacheHas$1;
  1795. seen = new SetCache$1;
  1796. }
  1797. else {
  1798. seen = iteratee ? [] : result;
  1799. }
  1800. outer:
  1801. while (++index < length) {
  1802. var value = array[index],
  1803. computed = iteratee ? iteratee(value) : value;
  1804. value = (comparator || value !== 0) ? value : 0;
  1805. if (isCommon && computed === computed) {
  1806. var seenIndex = seen.length;
  1807. while (seenIndex--) {
  1808. if (seen[seenIndex] === computed) {
  1809. continue outer;
  1810. }
  1811. }
  1812. if (iteratee) {
  1813. seen.push(computed);
  1814. }
  1815. result.push(value);
  1816. }
  1817. else if (!includes(seen, computed, comparator)) {
  1818. if (seen !== result) {
  1819. seen.push(computed);
  1820. }
  1821. result.push(value);
  1822. }
  1823. }
  1824. return result;
  1825. }
  1826. var _baseUniq = baseUniq;
  1827. var _baseUniq$1 = /*#__PURE__*/Object.freeze({
  1828. default: _baseUniq,
  1829. __moduleExports: _baseUniq
  1830. });
  1831. var baseUniq$1 = ( _baseUniq$1 && _baseUniq ) || _baseUniq$1;
  1832. /**
  1833. * Creates a duplicate-free version of an array, using
  1834. * [`SameValueZero`](http://ecma-international.org/ecma-262/7.0/#sec-samevaluezero)
  1835. * for equality comparisons, in which only the first occurrence of each element
  1836. * is kept. The order of result values is determined by the order they occur
  1837. * in the array.
  1838. *
  1839. * @static
  1840. * @memberOf _
  1841. * @since 0.1.0
  1842. * @category Array
  1843. * @param {Array} array The array to inspect.
  1844. * @returns {Array} Returns the new duplicate free array.
  1845. * @example
  1846. *
  1847. * _.uniq([2, 1, 2]);
  1848. * // => [2, 1]
  1849. */
  1850. function uniq(array) {
  1851. return (array && array.length) ? baseUniq$1(array) : [];
  1852. }
  1853. var uniq_1 = uniq;
  1854. function camelCaseToDash(str) {
  1855. return str.replace(/([A-Z])/g, (g) => `-${g[0].toLowerCase()}`);
  1856. }
  1857. function makeDataAttributeString(props) {
  1858. const keys = Object.keys(props);
  1859. return keys
  1860. .map((key) => {
  1861. const _key = camelCaseToDash(key);
  1862. const val = props[key];
  1863. if (val === undefined) return '';
  1864. return `data-${_key}="${val}" `;
  1865. })
  1866. .join('')
  1867. .trim();
  1868. }
  1869. function copyTextToClipboard(text) {
  1870. // https://stackoverflow.com/a/30810322/5353542
  1871. var textArea = document.createElement('textarea');
  1872. //
  1873. // *** This styling is an extra step which is likely not required. ***
  1874. //
  1875. // Why is it here? To ensure:
  1876. // 1. the element is able to have focus and selection.
  1877. // 2. if element was to flash render it has minimal visual impact.
  1878. // 3. less flakyness with selection and copying which **might** occur if
  1879. // the textarea element is not visible.
  1880. //
  1881. // The likelihood is the element won't even render, not even a flash,
  1882. // so some of these are just precautions. However in IE the element
  1883. // is visible whilst the popup box asking the user for permission for
  1884. // the web page to copy to the clipboard.
  1885. //
  1886. // Place in top-left corner of screen regardless of scroll position.
  1887. textArea.style.position = 'fixed';
  1888. textArea.style.top = 0;
  1889. textArea.style.left = 0;
  1890. // Ensure it has a small width and height. Setting to 1px / 1em
  1891. // doesn't work as this gives a negative w/h on some browsers.
  1892. textArea.style.width = '2em';
  1893. textArea.style.height = '2em';
  1894. // We don't need padding, reducing the size if it does flash render.
  1895. textArea.style.padding = 0;
  1896. // Clean up any borders.
  1897. textArea.style.border = 'none';
  1898. textArea.style.outline = 'none';
  1899. textArea.style.boxShadow = 'none';
  1900. // Avoid flash of white box if rendered for any reason.
  1901. textArea.style.background = 'transparent';
  1902. textArea.value = text;
  1903. document.body.appendChild(textArea);
  1904. textArea.select();
  1905. try {
  1906. document.execCommand('copy');
  1907. } catch (err) {
  1908. console.log('Oops, unable to copy');
  1909. }
  1910. document.body.removeChild(textArea);
  1911. }
  1912. function isNumeric(val) {
  1913. return !isNaN(val);
  1914. }
  1915. let throttle$1 = throttle_1;
  1916. let debounce$3 = debounce_1;
  1917. function nextTick(fn, context = null) {
  1918. return (...args) => {
  1919. return new Promise(resolve => {
  1920. const execute = () => {
  1921. const out = fn.apply(context, args);
  1922. resolve(out);
  1923. };
  1924. setTimeout(execute);
  1925. });
  1926. };
  1927. }
  1928. function linkProperties(target, source, properties) {
  1929. const props = properties.reduce((acc, prop) => {
  1930. acc[prop] = {
  1931. get() {
  1932. return source[prop];
  1933. }
  1934. };
  1935. return acc;
  1936. }, {});
  1937. Object.defineProperties(target, props);
  1938. }
  1939. function isSet(val) {
  1940. return val !== undefined || val !== null;
  1941. }
  1942. function notSet(val) {
  1943. return !isSet(val);
  1944. }
  1945. function isNumber(val) {
  1946. return !isNaN(val);
  1947. }
  1948. function ensureArray(val) {
  1949. if (!Array.isArray(val)) {
  1950. return [val];
  1951. }
  1952. return val;
  1953. }
  1954. function uniq$1(arr) {
  1955. return uniq_1(arr);
  1956. }
  1957. function numberSortAsc(a, b) {
  1958. return a - b;
  1959. }
  1960. function stripHTML(html) {
  1961. return html.replace(/<[^>]*>/g, '');
  1962. }
  1963. function format(str, args) {
  1964. if (!str) return str;
  1965. Object.keys(args).forEach(arg => {
  1966. let regex = new RegExp(`{(${arg})}`, 'g');
  1967. str = str.replace(regex, args[arg]);
  1968. });
  1969. return str;
  1970. }
  1971. class DataManager {
  1972. constructor(options) {
  1973. this.options = options;
  1974. this.sortRows = nextTick(this.sortRows, this);
  1975. this.switchColumn = nextTick(this.switchColumn, this);
  1976. this.removeColumn = nextTick(this.removeColumn, this);
  1977. this.options.filterRows = nextTick(this.options.filterRows, this);
  1978. }
  1979. init(data, columns) {
  1980. if (!data) {
  1981. data = this.options.data;
  1982. }
  1983. if (columns) {
  1984. this.options.columns = columns;
  1985. }
  1986. this.data = data;
  1987. this.rowCount = 0;
  1988. this.columns = [];
  1989. this.rows = [];
  1990. this.prepareColumns();
  1991. this.prepareRows();
  1992. this.prepareTreeRows();
  1993. this.prepareRowView();
  1994. this.prepareNumericColumns();
  1995. }
  1996. // computed property
  1997. get currentSort() {
  1998. const col = this.columns.find(col => col.sortOrder !== 'none');
  1999. return col || {
  2000. colIndex: -1,
  2001. sortOrder: 'none'
  2002. };
  2003. }
  2004. prepareColumns() {
  2005. this.columns = [];
  2006. this.validateColumns();
  2007. this.prepareDefaultColumns();
  2008. this.prepareHeader();
  2009. }
  2010. prepareDefaultColumns() {
  2011. if (this.options.checkboxColumn && !this.hasColumnById('_checkbox')) {
  2012. const cell = {
  2013. id: '_checkbox',
  2014. content: this.getCheckboxHTML(),
  2015. editable: false,
  2016. resizable: false,
  2017. sortable: false,
  2018. focusable: false,
  2019. dropdown: false,
  2020. width: 32
  2021. };
  2022. this.columns.push(cell);
  2023. }
  2024. if (this.options.serialNoColumn && !this.hasColumnById('_rowIndex')) {
  2025. let cell = {
  2026. id: '_rowIndex',
  2027. content: '',
  2028. align: 'center',
  2029. editable: false,
  2030. resizable: false,
  2031. focusable: false,
  2032. dropdown: false
  2033. };
  2034. this.columns.push(cell);
  2035. }
  2036. }
  2037. prepareHeader() {
  2038. let columns = this.columns.concat(this.options.columns);
  2039. const baseCell = {
  2040. isHeader: 1,
  2041. editable: true,
  2042. sortable: true,
  2043. resizable: true,
  2044. focusable: true,
  2045. dropdown: true,
  2046. width: null,
  2047. format: (value) => {
  2048. if (value === null || value === undefined) {
  2049. return '';
  2050. }
  2051. return value + '';
  2052. }
  2053. };
  2054. this.columns = columns
  2055. .map((cell, i) => this.prepareCell(cell, i))
  2056. .map(col => Object.assign({}, baseCell, col))
  2057. .map(col => {
  2058. col.content = col.content || col.name || '';
  2059. col.id = col.id || col.content;
  2060. return col;
  2061. });
  2062. }
  2063. prepareCell(content, i) {
  2064. const cell = {
  2065. content: '',
  2066. sortOrder: 'none',
  2067. colIndex: i,
  2068. column: this.columns[i]
  2069. };
  2070. if (content !== null && typeof content === 'object') {
  2071. // passed as column/header
  2072. Object.assign(cell, content);
  2073. } else {
  2074. cell.content = content;
  2075. }
  2076. return cell;
  2077. }
  2078. prepareNumericColumns() {
  2079. const row0 = this.getRow(0);
  2080. if (!row0) return;
  2081. this.columns = this.columns.map((column, i) => {
  2082. const cellValue = row0[i].content;
  2083. if (!column.align && isNumeric(cellValue)) {
  2084. column.align = 'right';
  2085. }
  2086. return column;
  2087. });
  2088. }
  2089. prepareRows() {
  2090. this.validateData(this.data);
  2091. this.rows = this.data.map((d, i) => {
  2092. const index = this._getNextRowCount();
  2093. let row = [];
  2094. let meta = {
  2095. rowIndex: index
  2096. };
  2097. if (Array.isArray(d)) {
  2098. // row is an array
  2099. if (this.options.checkboxColumn) {
  2100. row.push(this.getCheckboxHTML());
  2101. }
  2102. if (this.options.serialNoColumn) {
  2103. row.push((index + 1) + '');
  2104. }
  2105. row = row.concat(d);
  2106. while (row.length < this.columns.length) {
  2107. row.push('');
  2108. }
  2109. } else {
  2110. // row is an object
  2111. for (let col of this.columns) {
  2112. if (col.id === '_checkbox') {
  2113. row.push(this.getCheckboxHTML());
  2114. } else if (col.id === '_rowIndex') {
  2115. row.push((index + 1) + '');
  2116. } else {
  2117. row.push(d[col.id]);
  2118. }
  2119. }
  2120. meta.indent = d.indent || 0;
  2121. }
  2122. return this.prepareRow(row, meta);
  2123. });
  2124. }
  2125. prepareTreeRows() {
  2126. this.rows.forEach((row, i) => {
  2127. if (isNumber(row.meta.indent)) {
  2128. // if (i === 36) debugger;
  2129. const nextRow = this.getRow(i + 1);
  2130. row.meta.isLeaf = !nextRow ||
  2131. notSet(nextRow.meta.indent) ||
  2132. nextRow.meta.indent <= row.meta.indent;
  2133. row.meta.isTreeNodeClose = false;
  2134. }
  2135. });
  2136. }
  2137. prepareRowView() {
  2138. // This is order in which rows will be rendered in the table.
  2139. // When sorting happens, only this.rowViewOrder will change
  2140. // and not the original this.rows
  2141. this.rowViewOrder = this.rows.map(row => row.meta.rowIndex);
  2142. }
  2143. prepareRow(row, meta) {
  2144. const baseRowCell = {
  2145. rowIndex: meta.rowIndex,
  2146. indent: meta.indent
  2147. };
  2148. row = row
  2149. .map((cell, i) => this.prepareCell(cell, i))
  2150. .map(cell => Object.assign({}, baseRowCell, cell));
  2151. // monkey patched in array object
  2152. row.meta = meta;
  2153. return row;
  2154. }
  2155. validateColumns() {
  2156. const columns = this.options.columns;
  2157. if (!Array.isArray(columns)) {
  2158. throw new DataError('`columns` must be an array');
  2159. }
  2160. columns.forEach((column, i) => {
  2161. if (typeof column !== 'string' && typeof column !== 'object') {
  2162. throw new DataError(`column "${i}" must be a string or an object`);
  2163. }
  2164. });
  2165. }
  2166. validateData(data) {
  2167. if (Array.isArray(data) &&
  2168. (data.length === 0 || Array.isArray(data[0]) || typeof data[0] === 'object')) {
  2169. return true;
  2170. }
  2171. throw new DataError('`data` must be an array of arrays or objects');
  2172. }
  2173. appendRows(rows) {
  2174. this.validateData(rows);
  2175. this.rows.push(...this.prepareRows(rows));
  2176. }
  2177. sortRows(colIndex, sortOrder = 'none') {
  2178. colIndex = +colIndex;
  2179. // reset sortOrder and update for colIndex
  2180. this.getColumns()
  2181. .map(col => {
  2182. if (col.colIndex === colIndex) {
  2183. col.sortOrder = sortOrder;
  2184. } else {
  2185. col.sortOrder = 'none';
  2186. }
  2187. });
  2188. this._sortRows(colIndex, sortOrder);
  2189. }
  2190. _sortRows(colIndex, sortOrder) {
  2191. if (this.currentSort.colIndex === colIndex) {
  2192. // reverse the array if only sortOrder changed
  2193. if (
  2194. (this.currentSort.sortOrder === 'asc' && sortOrder === 'desc') ||
  2195. (this.currentSort.sortOrder === 'desc' && sortOrder === 'asc')
  2196. ) {
  2197. this.reverseArray(this.rowViewOrder);
  2198. this.currentSort.sortOrder = sortOrder;
  2199. return;
  2200. }
  2201. }
  2202. this.rowViewOrder.sort((a, b) => {
  2203. const aIndex = a;
  2204. const bIndex = b;
  2205. let aContent = this.getCell(colIndex, a).content;
  2206. let bContent = this.getCell(colIndex, b).content;
  2207. aContent = aContent == null ? '' : aContent;
  2208. bContent = bContent == null ? '' : bContent;
  2209. if (sortOrder === 'none') {
  2210. return aIndex - bIndex;
  2211. } else if (sortOrder === 'asc') {
  2212. if (aContent < bContent) return -1;
  2213. if (aContent > bContent) return 1;
  2214. if (aContent === bContent) return 0;
  2215. } else if (sortOrder === 'desc') {
  2216. if (aContent < bContent) return 1;
  2217. if (aContent > bContent) return -1;
  2218. if (aContent === bContent) return 0;
  2219. }
  2220. return 0;
  2221. });
  2222. if (this.hasColumnById('_rowIndex')) {
  2223. // update row index
  2224. const srNoColIndex = this.getColumnIndexById('_rowIndex');
  2225. this.rows.forEach((row, index) => {
  2226. const viewIndex = this.rowViewOrder.indexOf(index);
  2227. const cell = row[srNoColIndex];
  2228. cell.content = (viewIndex + 1) + '';
  2229. });
  2230. }
  2231. }
  2232. reverseArray(array) {
  2233. let left = null;
  2234. let right = null;
  2235. let length = array.length;
  2236. for (left = 0, right = length - 1; left < right; left += 1, right -= 1) {
  2237. const temporary = array[left];
  2238. array[left] = array[right];
  2239. array[right] = temporary;
  2240. }
  2241. }
  2242. switchColumn(index1, index2) {
  2243. // update columns
  2244. const temp = this.columns[index1];
  2245. this.columns[index1] = this.columns[index2];
  2246. this.columns[index2] = temp;
  2247. this.columns[index1].colIndex = index1;
  2248. this.columns[index2].colIndex = index2;
  2249. // update rows
  2250. this.rows.forEach(row => {
  2251. const newCell1 = Object.assign({}, row[index1], {
  2252. colIndex: index2
  2253. });
  2254. const newCell2 = Object.assign({}, row[index2], {
  2255. colIndex: index1
  2256. });
  2257. row[index2] = newCell1;
  2258. row[index1] = newCell2;
  2259. });
  2260. }
  2261. removeColumn(index) {
  2262. index = +index;
  2263. const filter = cell => cell.colIndex !== index;
  2264. const map = (cell, i) => Object.assign({}, cell, {
  2265. colIndex: i
  2266. });
  2267. // update columns
  2268. this.columns = this.columns
  2269. .filter(filter)
  2270. .map(map);
  2271. // update rows
  2272. this.rows.forEach(row => {
  2273. // remove cell
  2274. row.splice(index, 1);
  2275. // update colIndex
  2276. row.forEach((cell, i) => {
  2277. cell.colIndex = i;
  2278. });
  2279. });
  2280. }
  2281. updateRow(row, rowIndex) {
  2282. if (row.length < this.columns.length) {
  2283. if (this.hasColumnById('_rowIndex')) {
  2284. const val = (rowIndex + 1) + '';
  2285. row = [val].concat(row);
  2286. }
  2287. if (this.hasColumnById('_checkbox')) {
  2288. const val = '<input type="checkbox" />';
  2289. row = [val].concat(row);
  2290. }
  2291. }
  2292. const _row = this.prepareRow(row, {rowIndex});
  2293. const index = this.rows.findIndex(row => row[0].rowIndex === rowIndex);
  2294. this.rows[index] = _row;
  2295. return _row;
  2296. }
  2297. updateCell(colIndex, rowIndex, options) {
  2298. let cell;
  2299. if (typeof colIndex === 'object') {
  2300. // cell object was passed,
  2301. // must have colIndex, rowIndex
  2302. cell = colIndex;
  2303. colIndex = cell.colIndex;
  2304. rowIndex = cell.rowIndex;
  2305. // the object passed must be merged with original cell
  2306. options = cell;
  2307. }
  2308. cell = this.getCell(colIndex, rowIndex);
  2309. // mutate object directly
  2310. for (let key in options) {
  2311. const newVal = options[key];
  2312. if (newVal !== undefined) {
  2313. cell[key] = newVal;
  2314. }
  2315. }
  2316. return cell;
  2317. }
  2318. updateColumn(colIndex, keyValPairs) {
  2319. const column = this.getColumn(colIndex);
  2320. for (let key in keyValPairs) {
  2321. const newVal = keyValPairs[key];
  2322. if (newVal !== undefined) {
  2323. column[key] = newVal;
  2324. }
  2325. }
  2326. return column;
  2327. }
  2328. filterRows(filters) {
  2329. return this.options.filterRows(this.rows, filters)
  2330. .then(result => {
  2331. if (!result) {
  2332. result = this.getAllRowIndices();
  2333. }
  2334. if (!result.then) {
  2335. result = Promise.resolve(result);
  2336. }
  2337. return result.then(rowsToShow => {
  2338. this._filteredRows = rowsToShow;
  2339. const rowsToHide = this.getAllRowIndices()
  2340. .filter(index => !rowsToShow.includes(index));
  2341. return {
  2342. rowsToHide,
  2343. rowsToShow
  2344. };
  2345. });
  2346. });
  2347. }
  2348. getFilteredRowIndices() {
  2349. return this._filteredRows || this.getAllRowIndices();
  2350. }
  2351. getAllRowIndices() {
  2352. return this.rows.map(row => row.meta.rowIndex);
  2353. }
  2354. getRowCount() {
  2355. return this.rowCount;
  2356. }
  2357. _getNextRowCount() {
  2358. const val = this.rowCount;
  2359. this.rowCount++;
  2360. return val;
  2361. }
  2362. getRows(start, end) {
  2363. return this.rows.slice(start, end);
  2364. }
  2365. getRowsForView(start, end) {
  2366. const rows = this.rowViewOrder.map(i => this.rows[i]);
  2367. return rows.slice(start, end);
  2368. }
  2369. getColumns(skipStandardColumns) {
  2370. let columns = this.columns;
  2371. if (skipStandardColumns) {
  2372. columns = columns.slice(this.getStandardColumnCount());
  2373. }
  2374. return columns;
  2375. }
  2376. getStandardColumnCount() {
  2377. if (this.options.checkboxColumn && this.options.serialNoColumn) {
  2378. return 2;
  2379. }
  2380. if (this.options.checkboxColumn || this.options.serialNoColumn) {
  2381. return 1;
  2382. }
  2383. return 0;
  2384. }
  2385. getColumnCount(skipStandardColumns) {
  2386. let val = this.columns.length;
  2387. if (skipStandardColumns) {
  2388. val = val - this.getStandardColumnCount();
  2389. }
  2390. return val;
  2391. }
  2392. getColumn(colIndex) {
  2393. colIndex = +colIndex;
  2394. if (colIndex < 0) {
  2395. // negative indexes
  2396. colIndex = this.columns.length + colIndex;
  2397. }
  2398. return this.columns.find(col => col.colIndex === colIndex);
  2399. }
  2400. getColumnById(id) {
  2401. return this.columns.find(col => col.id === id);
  2402. }
  2403. getRow(rowIndex) {
  2404. rowIndex = +rowIndex;
  2405. return this.rows[rowIndex];
  2406. }
  2407. getCell(colIndex, rowIndex) {
  2408. rowIndex = +rowIndex;
  2409. colIndex = +colIndex;
  2410. return this.getRow(rowIndex)[colIndex];
  2411. }
  2412. getChildren(parentRowIndex) {
  2413. parentRowIndex = +parentRowIndex;
  2414. const parentIndent = this.getRow(parentRowIndex).meta.indent;
  2415. const out = [];
  2416. for (let i = parentRowIndex + 1; i < this.rowCount; i++) {
  2417. const row = this.getRow(i);
  2418. if (isNaN(row.meta.indent)) continue;
  2419. if (row.meta.indent > parentIndent) {
  2420. out.push(i);
  2421. }
  2422. if (row.meta.indent === parentIndent) {
  2423. break;
  2424. }
  2425. }
  2426. return out;
  2427. }
  2428. getImmediateChildren(parentRowIndex) {
  2429. parentRowIndex = +parentRowIndex;
  2430. const parentIndent = this.getRow(parentRowIndex).meta.indent;
  2431. const out = [];
  2432. const childIndent = parentIndent + 1;
  2433. for (let i = parentRowIndex + 1; i < this.rowCount; i++) {
  2434. const row = this.getRow(i);
  2435. if (isNaN(row.meta.indent) || row.meta.indent > childIndent) continue;
  2436. if (row.meta.indent === childIndent) {
  2437. out.push(i);
  2438. }
  2439. if (row.meta.indent === parentIndent) {
  2440. break;
  2441. }
  2442. }
  2443. return out;
  2444. }
  2445. get() {
  2446. return {
  2447. columns: this.columns,
  2448. rows: this.rows
  2449. };
  2450. }
  2451. /**
  2452. * Returns the original data which was passed
  2453. * based on rowIndex
  2454. * @param {Number} rowIndex
  2455. * @returns Array|Object
  2456. * @memberof DataManager
  2457. */
  2458. getData(rowIndex) {
  2459. return this.data[rowIndex];
  2460. }
  2461. hasColumn(name) {
  2462. return Boolean(this.columns.find(col => col.content === name));
  2463. }
  2464. hasColumnById(id) {
  2465. return Boolean(this.columns.find(col => col.id === id));
  2466. }
  2467. getColumnIndex(name) {
  2468. return this.columns.findIndex(col => col.content === name);
  2469. }
  2470. getColumnIndexById(id) {
  2471. return this.columns.findIndex(col => col.id === id);
  2472. }
  2473. getCheckboxHTML() {
  2474. return '<input type="checkbox" />';
  2475. }
  2476. }
  2477. // Custom Errors
  2478. class DataError extends TypeError {}
  2479. /* eslint-disable max-len */
  2480. // Icons from https://feathericons.com/
  2481. let icons = {
  2482. chevronDown: '<svg xmlns="http://www.w3.org/2000/svg" width="16" height="16" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round" class="feather feather-chevron-down"><polyline points="6 9 12 15 18 9"></polyline></svg>',
  2483. chevronRight: '<svg xmlns="http://www.w3.org/2000/svg" width="16" height="16" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round" class="feather feather-chevron-right"><polyline points="9 18 15 12 9 6"></polyline></svg>'
  2484. };
  2485. class CellManager {
  2486. constructor(instance) {
  2487. this.instance = instance;
  2488. linkProperties(this, this.instance, [
  2489. 'wrapper',
  2490. 'options',
  2491. 'style',
  2492. 'header',
  2493. 'bodyScrollable',
  2494. 'columnmanager',
  2495. 'rowmanager',
  2496. 'datamanager',
  2497. 'keyboard'
  2498. ]);
  2499. this.bindEvents();
  2500. }
  2501. bindEvents() {
  2502. this.bindFocusCell();
  2503. this.bindEditCell();
  2504. this.bindKeyboardSelection();
  2505. this.bindCopyCellContents();
  2506. this.bindMouseEvents();
  2507. this.bindTreeEvents();
  2508. }
  2509. bindFocusCell() {
  2510. this.bindKeyboardNav();
  2511. }
  2512. bindEditCell() {
  2513. this.$editingCell = null;
  2514. $.on(this.bodyScrollable, 'dblclick', '.dt-cell', (e, cell) => {
  2515. this.activateEditing(cell);
  2516. });
  2517. this.keyboard.on('enter', () => {
  2518. if (this.$focusedCell && !this.$editingCell) {
  2519. // enter keypress on focused cell
  2520. this.activateEditing(this.$focusedCell);
  2521. } else if (this.$editingCell) {
  2522. // enter keypress on editing cell
  2523. this.deactivateEditing();
  2524. }
  2525. });
  2526. }
  2527. bindKeyboardNav() {
  2528. const focusLastCell = (direction) => {
  2529. if (!this.$focusedCell || this.$editingCell) {
  2530. return false;
  2531. }
  2532. let $cell = this.$focusedCell;
  2533. const {
  2534. rowIndex,
  2535. colIndex
  2536. } = $.data($cell);
  2537. if (direction === 'left') {
  2538. $cell = this.getLeftMostCell$(rowIndex);
  2539. } else if (direction === 'right') {
  2540. $cell = this.getRightMostCell$(rowIndex);
  2541. } else if (direction === 'up') {
  2542. $cell = this.getTopMostCell$(colIndex);
  2543. } else if (direction === 'down') {
  2544. $cell = this.getBottomMostCell$(colIndex);
  2545. }
  2546. this.focusCell($cell);
  2547. return true;
  2548. };
  2549. ['left', 'right', 'up', 'down', 'tab', 'shift+tab']
  2550. .map(direction => this.keyboard.on(direction, () => this.focusCellInDirection(direction)));
  2551. ['left', 'right', 'up', 'down']
  2552. .map(direction => this.keyboard.on(`ctrl+${direction}`, () => focusLastCell(direction)));
  2553. this.keyboard.on('esc', () => {
  2554. this.deactivateEditing(false);
  2555. this.columnmanager.toggleFilter(false);
  2556. });
  2557. if (this.options.inlineFilters) {
  2558. this.keyboard.on('ctrl+f', (e) => {
  2559. const $cell = $.closest('.dt-cell', e.target);
  2560. const { colIndex } = $.data($cell);
  2561. this.activateFilter(colIndex);
  2562. return true;
  2563. });
  2564. $.on(this.header, 'focusin', '.dt-filter', () => {
  2565. this.unfocusCell(this.$focusedCell);
  2566. });
  2567. }
  2568. }
  2569. bindKeyboardSelection() {
  2570. const getNextSelectionCursor = (direction) => {
  2571. let $selectionCursor = this.getSelectionCursor();
  2572. if (direction === 'left') {
  2573. $selectionCursor = this.getLeftCell$($selectionCursor);
  2574. } else if (direction === 'right') {
  2575. $selectionCursor = this.getRightCell$($selectionCursor);
  2576. } else if (direction === 'up') {
  2577. $selectionCursor = this.getAboveCell$($selectionCursor);
  2578. } else if (direction === 'down') {
  2579. $selectionCursor = this.getBelowCell$($selectionCursor);
  2580. }
  2581. return $selectionCursor;
  2582. };
  2583. ['left', 'right', 'up', 'down']
  2584. .map(direction =>
  2585. this.keyboard.on(`shift+${direction}`, () => this.selectArea(getNextSelectionCursor(direction))));
  2586. }
  2587. bindCopyCellContents() {
  2588. this.keyboard.on('ctrl+c', () => {
  2589. const noOfCellsCopied = this.copyCellContents(this.$focusedCell, this.$selectionCursor);
  2590. const message = this.instance.translate('{count} cells copied', {
  2591. count: noOfCellsCopied
  2592. });
  2593. if (noOfCellsCopied) {
  2594. this.instance.showToastMessage(message, 2);
  2595. }
  2596. });
  2597. if (this.options.pasteFromClipboard) {
  2598. this.keyboard.on('ctrl+v', (e) => {
  2599. // hack
  2600. // https://stackoverflow.com/a/2177059/5353542
  2601. this.instance.pasteTarget.focus();
  2602. setTimeout(() => {
  2603. const data = this.instance.pasteTarget.value;
  2604. this.instance.pasteTarget.value = '';
  2605. this.pasteContentInCell(data);
  2606. }, 10);
  2607. return false;
  2608. });
  2609. }
  2610. }
  2611. bindMouseEvents() {
  2612. let mouseDown = null;
  2613. $.on(this.bodyScrollable, 'mousedown', '.dt-cell', (e) => {
  2614. mouseDown = true;
  2615. this.focusCell($(e.delegatedTarget));
  2616. });
  2617. $.on(this.bodyScrollable, 'mouseup', () => {
  2618. mouseDown = false;
  2619. });
  2620. const selectArea = (e) => {
  2621. if (!mouseDown) return;
  2622. this.selectArea($(e.delegatedTarget));
  2623. };
  2624. $.on(this.bodyScrollable, 'mousemove', '.dt-cell', throttle$1(selectArea, 50));
  2625. }
  2626. bindTreeEvents() {
  2627. $.on(this.bodyScrollable, 'click', '.dt-tree-node__toggle', (e, $toggle) => {
  2628. const $cell = $.closest('.dt-cell', $toggle);
  2629. const { rowIndex } = $.data($cell);
  2630. if ($cell.classList.contains('dt-cell--tree-close')) {
  2631. this.rowmanager.openSingleNode(rowIndex);
  2632. } else {
  2633. this.rowmanager.closeSingleNode(rowIndex);
  2634. }
  2635. });
  2636. }
  2637. focusCell($cell, {
  2638. skipClearSelection = 0,
  2639. skipDOMFocus = 0,
  2640. skipScrollToCell = 0
  2641. } = {}) {
  2642. if (!$cell) return;
  2643. // don't focus if already editing cell
  2644. if ($cell === this.$editingCell) return;
  2645. const {
  2646. colIndex,
  2647. isHeader
  2648. } = $.data($cell);
  2649. if (isHeader) {
  2650. return;
  2651. }
  2652. const column = this.columnmanager.getColumn(colIndex);
  2653. if (column.focusable === false) {
  2654. return;
  2655. }
  2656. if (!skipScrollToCell) {
  2657. this.scrollToCell($cell);
  2658. }
  2659. this.deactivateEditing();
  2660. if (!skipClearSelection) {
  2661. this.clearSelection();
  2662. }
  2663. if (this.$focusedCell) {
  2664. this.$focusedCell.classList.remove('dt-cell--focus');
  2665. }
  2666. this.$focusedCell = $cell;
  2667. $cell.classList.add('dt-cell--focus');
  2668. if (!skipDOMFocus) {
  2669. // so that keyboard nav works
  2670. $cell.focus();
  2671. }
  2672. this.highlightRowColumnHeader($cell);
  2673. }
  2674. unfocusCell($cell) {
  2675. if (!$cell) return;
  2676. // remove cell border
  2677. $cell.classList.remove('dt-cell--focus');
  2678. this.$focusedCell = null;
  2679. // reset header background
  2680. if (this.lastHeaders) {
  2681. this.lastHeaders.forEach(header => header && header.classList.remove('dt-cell--highlight'));
  2682. }
  2683. }
  2684. highlightRowColumnHeader($cell) {
  2685. const {
  2686. colIndex,
  2687. rowIndex
  2688. } = $.data($cell);
  2689. const srNoColIndex = this.datamanager.getColumnIndexById('_rowIndex');
  2690. const colHeaderSelector = `.dt-cell--header-${colIndex}`;
  2691. const rowHeaderSelector = `.dt-cell--${srNoColIndex}-${rowIndex}`;
  2692. if (this.lastHeaders) {
  2693. this.lastHeaders.forEach(header => header && header.classList.remove('dt-cell--highlight'));
  2694. }
  2695. const colHeader = $(colHeaderSelector, this.wrapper);
  2696. const rowHeader = $(rowHeaderSelector, this.wrapper);
  2697. this.lastHeaders = [colHeader, rowHeader];
  2698. this.lastHeaders.forEach(header => header && header.classList.add('dt-cell--highlight'));
  2699. }
  2700. selectAreaOnClusterChanged() {
  2701. if (!(this.$focusedCell && this.$selectionCursor)) return;
  2702. const {
  2703. colIndex,
  2704. rowIndex
  2705. } = $.data(this.$selectionCursor);
  2706. const $cell = this.getCell$(colIndex, rowIndex);
  2707. if (!$cell || $cell === this.$selectionCursor) return;
  2708. // selectArea needs $focusedCell
  2709. const fCell = $.data(this.$focusedCell);
  2710. this.$focusedCell = this.getCell$(fCell.colIndex, fCell.rowIndex);
  2711. this.selectArea($cell);
  2712. }
  2713. focusCellOnClusterChanged() {
  2714. if (!this.$focusedCell) return;
  2715. const {
  2716. colIndex,
  2717. rowIndex
  2718. } = $.data(this.$focusedCell);
  2719. const $cell = this.getCell$(colIndex, rowIndex);
  2720. if (!$cell) return;
  2721. // this function is called after hyperlist renders the rows after scroll,
  2722. // focusCell calls clearSelection which resets the area selection
  2723. // so a flag to skip it
  2724. // we also skip DOM focus and scroll to cell
  2725. // because it fights with the user scroll
  2726. this.focusCell($cell, {
  2727. skipClearSelection: 1,
  2728. skipDOMFocus: 1,
  2729. skipScrollToCell: 1
  2730. });
  2731. }
  2732. selectArea($selectionCursor) {
  2733. if (!this.$focusedCell) return;
  2734. if (this._selectArea(this.$focusedCell, $selectionCursor)) {
  2735. // valid selection
  2736. this.$selectionCursor = $selectionCursor;
  2737. }
  2738. }
  2739. _selectArea($cell1, $cell2) {
  2740. if ($cell1 === $cell2) return false;
  2741. const cells = this.getCellsInRange($cell1, $cell2);
  2742. if (!cells) return false;
  2743. this.clearSelection();
  2744. this._selectedCells = cells.map(index => this.getCell$(...index));
  2745. requestAnimationFrame(() => {
  2746. this._selectedCells.map($cell => $cell.classList.add('dt-cell--highlight'));
  2747. });
  2748. return true;
  2749. }
  2750. getCellsInRange($cell1, $cell2) {
  2751. let colIndex1, rowIndex1, colIndex2, rowIndex2;
  2752. if (typeof $cell1 === 'number') {
  2753. [colIndex1, rowIndex1, colIndex2, rowIndex2] = arguments;
  2754. } else
  2755. if (typeof $cell1 === 'object') {
  2756. if (!($cell1 && $cell2)) {
  2757. return false;
  2758. }
  2759. const cell1 = $.data($cell1);
  2760. const cell2 = $.data($cell2);
  2761. colIndex1 = +cell1.colIndex;
  2762. rowIndex1 = +cell1.rowIndex;
  2763. colIndex2 = +cell2.colIndex;
  2764. rowIndex2 = +cell2.rowIndex;
  2765. }
  2766. if (rowIndex1 > rowIndex2) {
  2767. [rowIndex1, rowIndex2] = [rowIndex2, rowIndex1];
  2768. }
  2769. if (colIndex1 > colIndex2) {
  2770. [colIndex1, colIndex2] = [colIndex2, colIndex1];
  2771. }
  2772. if (this.isStandardCell(colIndex1) || this.isStandardCell(colIndex2)) {
  2773. return false;
  2774. }
  2775. const cells = [];
  2776. let colIndex = colIndex1;
  2777. let rowIndex = rowIndex1;
  2778. const rowIndices = [];
  2779. while (rowIndex <= rowIndex2) {
  2780. rowIndices.push(rowIndex);
  2781. rowIndex += 1;
  2782. }
  2783. rowIndices.map((rowIndex) => {
  2784. while (colIndex <= colIndex2) {
  2785. cells.push([colIndex, rowIndex]);
  2786. colIndex++;
  2787. }
  2788. colIndex = colIndex1;
  2789. });
  2790. return cells;
  2791. }
  2792. clearSelection() {
  2793. (this._selectedCells || [])
  2794. .forEach($cell => $cell.classList.remove('dt-cell--highlight'));
  2795. this._selectedCells = [];
  2796. this.$selectionCursor = null;
  2797. }
  2798. getSelectionCursor() {
  2799. return this.$selectionCursor || this.$focusedCell;
  2800. }
  2801. activateEditing($cell) {
  2802. this.focusCell($cell);
  2803. const {
  2804. rowIndex,
  2805. colIndex
  2806. } = $.data($cell);
  2807. const col = this.columnmanager.getColumn(colIndex);
  2808. if (col && (col.editable === false || col.focusable === false)) {
  2809. return;
  2810. }
  2811. const cell = this.getCell(colIndex, rowIndex);
  2812. if (cell && cell.editable === false) {
  2813. return;
  2814. }
  2815. if (this.$editingCell) {
  2816. const {
  2817. _rowIndex,
  2818. _colIndex
  2819. } = $.data(this.$editingCell);
  2820. if (rowIndex === _rowIndex && colIndex === _colIndex) {
  2821. // editing the same cell
  2822. return;
  2823. }
  2824. }
  2825. this.$editingCell = $cell;
  2826. $cell.classList.add('dt-cell--editing');
  2827. const $editCell = $('.dt-cell__edit', $cell);
  2828. $editCell.innerHTML = '';
  2829. const editor = this.getEditor(colIndex, rowIndex, cell.content, $editCell);
  2830. if (editor) {
  2831. this.currentCellEditor = editor;
  2832. // initialize editing input with cell value
  2833. editor.initValue(cell.content, rowIndex, col);
  2834. }
  2835. }
  2836. deactivateEditing(submitValue = true) {
  2837. if (submitValue) {
  2838. this.submitEditing();
  2839. }
  2840. // keep focus on the cell so that keyboard navigation works
  2841. if (this.$focusedCell) this.$focusedCell.focus();
  2842. if (!this.$editingCell) return;
  2843. this.$editingCell.classList.remove('dt-cell--editing');
  2844. this.$editingCell = null;
  2845. }
  2846. getEditor(colIndex, rowIndex, value, parent) {
  2847. const column = this.datamanager.getColumn(colIndex);
  2848. const row = this.datamanager.getRow(rowIndex);
  2849. const data = this.datamanager.getData(rowIndex);
  2850. let editor = this.options.getEditor ?
  2851. this.options.getEditor(colIndex, rowIndex, value, parent, column, row, data) :
  2852. this.getDefaultEditor(parent);
  2853. if (editor === false) {
  2854. // explicitly returned false
  2855. return false;
  2856. }
  2857. if (editor === undefined) {
  2858. // didn't return editor, fallback to default
  2859. editor = this.getDefaultEditor(parent);
  2860. }
  2861. return editor;
  2862. }
  2863. getDefaultEditor(parent) {
  2864. const $input = $.create('input', {
  2865. class: 'dt-input',
  2866. type: 'text',
  2867. inside: parent
  2868. });
  2869. return {
  2870. initValue(value) {
  2871. $input.focus();
  2872. $input.value = value;
  2873. },
  2874. getValue() {
  2875. return $input.value;
  2876. },
  2877. setValue(value) {
  2878. $input.value = value;
  2879. }
  2880. };
  2881. }
  2882. submitEditing() {
  2883. let promise = Promise.resolve();
  2884. if (!this.$editingCell) return promise;
  2885. const $cell = this.$editingCell;
  2886. const {
  2887. rowIndex,
  2888. colIndex
  2889. } = $.data($cell);
  2890. const col = this.datamanager.getColumn(colIndex);
  2891. if ($cell) {
  2892. const editor = this.currentCellEditor;
  2893. if (editor) {
  2894. let valuePromise = editor.getValue();
  2895. // convert to stubbed Promise
  2896. if (!valuePromise.then) {
  2897. valuePromise = Promise.resolve(valuePromise);
  2898. }
  2899. promise = valuePromise.then((value) => {
  2900. const oldValue = this.getCell(colIndex, rowIndex).content;
  2901. if (oldValue === value) return false;
  2902. const done = editor.setValue(value, rowIndex, col);
  2903. // update cell immediately
  2904. this.updateCell(colIndex, rowIndex, value, true);
  2905. $cell.focus();
  2906. if (done && done.then) {
  2907. // revert to oldValue if promise fails
  2908. done.catch((e) => {
  2909. console.log(e);
  2910. this.updateCell(colIndex, rowIndex, oldValue);
  2911. });
  2912. }
  2913. return done;
  2914. });
  2915. }
  2916. }
  2917. this.currentCellEditor = null;
  2918. return promise;
  2919. }
  2920. copyCellContents($cell1, $cell2) {
  2921. if (!$cell2 && $cell1) {
  2922. // copy only focusedCell
  2923. const {
  2924. colIndex,
  2925. rowIndex
  2926. } = $.data($cell1);
  2927. const cell = this.getCell(colIndex, rowIndex);
  2928. copyTextToClipboard(cell.content);
  2929. return 1;
  2930. }
  2931. const cells = this.getCellsInRange($cell1, $cell2);
  2932. if (!cells) return 0;
  2933. const rows = cells
  2934. // get cell objects
  2935. .map(index => this.getCell(...index))
  2936. // convert to array of rows
  2937. .reduce((acc, curr) => {
  2938. const rowIndex = curr.rowIndex;
  2939. acc[rowIndex] = acc[rowIndex] || [];
  2940. acc[rowIndex].push(curr.content);
  2941. return acc;
  2942. }, []);
  2943. const values = rows
  2944. // join values by tab
  2945. .map(row => row.join('\t'))
  2946. // join rows by newline
  2947. .join('\n');
  2948. copyTextToClipboard(values);
  2949. // return no of cells copied
  2950. return rows.reduce((total, row) => total + row.length, 0);
  2951. }
  2952. pasteContentInCell(data) {
  2953. if (!this.$focusedCell) return;
  2954. const matrix = data
  2955. .split('\n')
  2956. .map(row => row.split('\t'))
  2957. .filter(row => row.length && row.every(it => it));
  2958. let { colIndex, rowIndex } = $.data(this.$focusedCell);
  2959. let focusedCell = {
  2960. colIndex: +colIndex,
  2961. rowIndex: +rowIndex
  2962. };
  2963. matrix.forEach((row, i) => {
  2964. let rowIndex = i + focusedCell.rowIndex;
  2965. row.forEach((cell, j) => {
  2966. let colIndex = j + focusedCell.colIndex;
  2967. this.updateCell(colIndex, rowIndex, cell, true);
  2968. });
  2969. });
  2970. }
  2971. activateFilter(colIndex) {
  2972. this.columnmanager.toggleFilter();
  2973. this.columnmanager.focusFilter(colIndex);
  2974. if (!this.columnmanager.isFilterShown) {
  2975. // put focus back on cell
  2976. this.$focusedCell && this.$focusedCell.focus();
  2977. }
  2978. }
  2979. updateCell(colIndex, rowIndex, value, refreshHtml = false) {
  2980. const cell = this.datamanager.updateCell(colIndex, rowIndex, {
  2981. content: value
  2982. });
  2983. this.refreshCell(cell, refreshHtml);
  2984. }
  2985. refreshCell(cell, refreshHtml = false) {
  2986. const $cell = $(this.selector(cell.colIndex, cell.rowIndex), this.bodyScrollable);
  2987. $cell.innerHTML = this.getCellContent(cell, refreshHtml);
  2988. }
  2989. toggleTreeButton(rowIndex, flag) {
  2990. const colIndex = this.columnmanager.getFirstColumnIndex();
  2991. const $cell = this.getCell$(colIndex, rowIndex);
  2992. if ($cell) {
  2993. $cell.classList[flag ? 'remove' : 'add']('dt-cell--tree-close');
  2994. }
  2995. }
  2996. isStandardCell(colIndex) {
  2997. // Standard cells are in Sr. No and Checkbox column
  2998. return colIndex < this.columnmanager.getFirstColumnIndex();
  2999. }
  3000. focusCellInDirection(direction) {
  3001. if (!this.$focusedCell || (this.$editingCell && ['left', 'right', 'up', 'down'].includes(direction))) {
  3002. return false;
  3003. } else if (this.$editingCell && ['tab', 'shift+tab'].includes(direction)) {
  3004. this.deactivateEditing();
  3005. }
  3006. let $cell = this.$focusedCell;
  3007. if (direction === 'left' || direction === 'shift+tab') {
  3008. $cell = this.getLeftCell$($cell);
  3009. } else if (direction === 'right' || direction === 'tab') {
  3010. $cell = this.getRightCell$($cell);
  3011. } else if (direction === 'up') {
  3012. $cell = this.getAboveCell$($cell);
  3013. } else if (direction === 'down') {
  3014. $cell = this.getBelowCell$($cell);
  3015. }
  3016. if (!$cell) {
  3017. return false;
  3018. }
  3019. const {
  3020. colIndex
  3021. } = $.data($cell);
  3022. const column = this.columnmanager.getColumn(colIndex);
  3023. if (!column.focusable) {
  3024. let $prevFocusedCell = this.$focusedCell;
  3025. this.unfocusCell($prevFocusedCell);
  3026. this.$focusedCell = $cell;
  3027. let ret = this.focusCellInDirection(direction);
  3028. if (!ret) {
  3029. this.focusCell($prevFocusedCell);
  3030. }
  3031. return ret;
  3032. }
  3033. this.focusCell($cell);
  3034. return true;
  3035. }
  3036. getCell$(colIndex, rowIndex) {
  3037. return $(this.selector(colIndex, rowIndex), this.bodyScrollable);
  3038. }
  3039. getAboveCell$($cell) {
  3040. const {
  3041. colIndex
  3042. } = $.data($cell);
  3043. let $aboveRow = $cell.parentElement.previousElementSibling;
  3044. while ($aboveRow && $aboveRow.classList.contains('dt-row--hide')) {
  3045. $aboveRow = $aboveRow.previousElementSibling;
  3046. }
  3047. if (!$aboveRow) return $cell;
  3048. return $(`.dt-cell--col-${colIndex}`, $aboveRow);
  3049. }
  3050. getBelowCell$($cell) {
  3051. const {
  3052. colIndex
  3053. } = $.data($cell);
  3054. let $belowRow = $cell.parentElement.nextElementSibling;
  3055. while ($belowRow && $belowRow.classList.contains('dt-row--hide')) {
  3056. $belowRow = $belowRow.nextElementSibling;
  3057. }
  3058. if (!$belowRow) return $cell;
  3059. return $(`.dt-cell--col-${colIndex}`, $belowRow);
  3060. }
  3061. getLeftCell$($cell) {
  3062. return $cell.previousElementSibling;
  3063. }
  3064. getRightCell$($cell) {
  3065. return $cell.nextElementSibling;
  3066. }
  3067. getLeftMostCell$(rowIndex) {
  3068. return this.getCell$(this.columnmanager.getFirstColumnIndex(), rowIndex);
  3069. }
  3070. getRightMostCell$(rowIndex) {
  3071. return this.getCell$(this.columnmanager.getLastColumnIndex(), rowIndex);
  3072. }
  3073. getTopMostCell$(colIndex) {
  3074. return this.getCell$(colIndex, this.rowmanager.getFirstRowIndex());
  3075. }
  3076. getBottomMostCell$(colIndex) {
  3077. return this.getCell$(colIndex, this.rowmanager.getLastRowIndex());
  3078. }
  3079. getCell(colIndex, rowIndex) {
  3080. return this.instance.datamanager.getCell(colIndex, rowIndex);
  3081. }
  3082. getRowHeight() {
  3083. return $.style($('.dt-row', this.bodyScrollable), 'height');
  3084. }
  3085. scrollToCell($cell) {
  3086. if ($.inViewport($cell, this.bodyScrollable)) return false;
  3087. const {
  3088. rowIndex
  3089. } = $.data($cell);
  3090. this.rowmanager.scrollToRow(rowIndex);
  3091. return false;
  3092. }
  3093. getRowCountPerPage() {
  3094. return Math.ceil(this.instance.getViewportHeight() / this.getRowHeight());
  3095. }
  3096. getCellHTML(cell) {
  3097. const {
  3098. rowIndex,
  3099. colIndex,
  3100. isHeader,
  3101. isFilter,
  3102. isTotalRow
  3103. } = cell;
  3104. const dataAttr = makeDataAttributeString({
  3105. rowIndex,
  3106. colIndex,
  3107. isHeader,
  3108. isFilter,
  3109. isTotalRow
  3110. });
  3111. const row = this.datamanager.getRow(rowIndex);
  3112. const isBodyCell = !(isHeader || isFilter || isTotalRow);
  3113. const className = [
  3114. 'dt-cell',
  3115. 'dt-cell--col-' + colIndex,
  3116. isBodyCell ? `dt-cell--${colIndex}-${rowIndex}` : '',
  3117. isBodyCell ? 'dt-cell--row-' + rowIndex : '',
  3118. isHeader ? 'dt-cell--header' : '',
  3119. isHeader ? `dt-cell--header-${colIndex}` : '',
  3120. isFilter ? 'dt-cell--filter' : '',
  3121. isBodyCell && (row && row.meta.isTreeNodeClose) ? 'dt-cell--tree-close' : ''
  3122. ].join(' ');
  3123. return `
  3124. <div class="${className}" ${dataAttr} tabindex="0">
  3125. ${this.getCellContent(cell)}
  3126. </div>
  3127. `;
  3128. }
  3129. getCellContent(cell, refreshHtml = false) {
  3130. const {
  3131. isHeader,
  3132. isFilter,
  3133. colIndex
  3134. } = cell;
  3135. const editable = !isHeader && cell.editable !== false;
  3136. const editCellHTML = editable ? this.getEditCellHTML(colIndex) : '';
  3137. const sortable = isHeader && cell.sortable !== false;
  3138. const sortIndicator = sortable ?
  3139. `<span class="sort-indicator">
  3140. ${this.options.sortIndicator[cell.sortOrder]}
  3141. </span>` :
  3142. '';
  3143. const resizable = isHeader && cell.resizable !== false;
  3144. const resizeColumn = resizable ? '<span class="dt-cell__resize-handle"></span>' : '';
  3145. const hasDropdown = isHeader && cell.dropdown !== false;
  3146. const dropdown = hasDropdown ? this.columnmanager.getDropdownHTML() : '';
  3147. let customFormatter = CellManager.getCustomCellFormatter(cell);
  3148. let contentHTML;
  3149. if (isHeader || isFilter || !customFormatter) {
  3150. contentHTML = cell.content;
  3151. } else {
  3152. if (!cell.html || refreshHtml) {
  3153. const row = this.datamanager.getRow(cell.rowIndex);
  3154. const data = this.datamanager.getData(cell.rowIndex);
  3155. contentHTML = customFormatter(cell.content, row, cell.column, data);
  3156. } else {
  3157. contentHTML = cell.html;
  3158. }
  3159. }
  3160. cell.html = contentHTML;
  3161. if (this.options.treeView && !(isHeader || isFilter) && cell.indent !== undefined) {
  3162. const nextRow = this.datamanager.getRow(cell.rowIndex + 1);
  3163. const addToggle = nextRow && nextRow.meta.indent > cell.indent;
  3164. const leftPadding = 20;
  3165. const unit = 'px';
  3166. // Add toggle and indent in the first column
  3167. const firstColumnIndex = this.datamanager.getColumnIndexById('_rowIndex') + 1;
  3168. if (firstColumnIndex === cell.colIndex) {
  3169. const padding = ((cell.indent || 0)) * leftPadding;
  3170. const toggleHTML = addToggle ?
  3171. `<span class="dt-tree-node__toggle" style="left: ${padding - leftPadding}${unit}">
  3172. <span class="icon-open">${icons.chevronDown}</span>
  3173. <span class="icon-close">${icons.chevronRight}</span>
  3174. </span>` : '';
  3175. contentHTML = `<span class="dt-tree-node" style="padding-left: ${padding}${unit}">
  3176. ${toggleHTML}
  3177. <span>${contentHTML}</span>
  3178. </span>`;
  3179. }
  3180. }
  3181. const className = [
  3182. 'dt-cell__content',
  3183. isHeader ? `dt-cell__content--header-${colIndex}` : `dt-cell__content--col-${colIndex}`
  3184. ].join(' ');
  3185. return `
  3186. <div class="${className}">
  3187. ${contentHTML}
  3188. ${sortIndicator}
  3189. ${resizeColumn}
  3190. ${dropdown}
  3191. </div>
  3192. ${editCellHTML}
  3193. `;
  3194. }
  3195. getEditCellHTML(colIndex) {
  3196. return `<div class="dt-cell__edit dt-cell__edit--col-${colIndex}"></div>`;
  3197. }
  3198. selector(colIndex, rowIndex) {
  3199. return `.dt-cell--${colIndex}-${rowIndex}`;
  3200. }
  3201. static getCustomCellFormatter(cell) {
  3202. return cell.format || (cell.column && cell.column.format) || null;
  3203. }
  3204. }
  3205. class ColumnManager {
  3206. constructor(instance) {
  3207. this.instance = instance;
  3208. linkProperties(this, this.instance, [
  3209. 'options',
  3210. 'fireEvent',
  3211. 'header',
  3212. 'datamanager',
  3213. 'cellmanager',
  3214. 'style',
  3215. 'wrapper',
  3216. 'rowmanager',
  3217. 'bodyScrollable',
  3218. 'bodyRenderer'
  3219. ]);
  3220. this.bindEvents();
  3221. }
  3222. renderHeader() {
  3223. this.header.innerHTML = '<div></div>';
  3224. this.refreshHeader();
  3225. }
  3226. refreshHeader() {
  3227. const columns = this.datamanager.getColumns();
  3228. // refresh html
  3229. $('div', this.header).innerHTML = this.getHeaderHTML(columns);
  3230. this.$filterRow = $('.dt-row-filter', this.header);
  3231. if (this.$filterRow) {
  3232. $.style(this.$filterRow, { display: 'none' });
  3233. }
  3234. // reset columnMap
  3235. this.$columnMap = [];
  3236. this.bindMoveColumn();
  3237. }
  3238. getHeaderHTML(columns) {
  3239. let html = this.rowmanager.getRowHTML(columns, {
  3240. isHeader: 1
  3241. });
  3242. if (this.options.inlineFilters) {
  3243. html += this.rowmanager.getRowHTML(columns, {
  3244. isFilter: 1
  3245. });
  3246. }
  3247. return html;
  3248. }
  3249. bindEvents() {
  3250. this.bindDropdown();
  3251. this.bindResizeColumn();
  3252. this.bindPerfectColumnWidth();
  3253. this.bindFilter();
  3254. }
  3255. bindDropdown() {
  3256. let toggleClass = '.dt-dropdown__toggle';
  3257. let dropdownClass = '.dt-dropdown__list';
  3258. // attach the dropdown list to container
  3259. this.instance.dropdownContainer.innerHTML = this.getDropdownListHTML();
  3260. this.$dropdownList = this.instance.dropdownContainer.firstElementChild;
  3261. $.on(this.header, 'click', toggleClass, e => {
  3262. this.openDropdown(e);
  3263. });
  3264. const deactivateDropdownOnBodyClick = (e) => {
  3265. const selector = [
  3266. toggleClass, toggleClass + ' *',
  3267. dropdownClass, dropdownClass + ' *'
  3268. ].join(',');
  3269. if (e.target.matches(selector)) return;
  3270. deactivateDropdown();
  3271. };
  3272. $.on(document.body, 'click', deactivateDropdownOnBodyClick);
  3273. document.addEventListener('scroll', deactivateDropdown, true);
  3274. this.instance.on('onDestroy', () => {
  3275. $.off(document.body, 'click', deactivateDropdownOnBodyClick);
  3276. $.off(document, 'scroll', deactivateDropdown);
  3277. });
  3278. $.on(this.$dropdownList, 'click', '.dt-dropdown__list-item', (e, $item) => {
  3279. if (!this._dropdownActiveColIndex) return;
  3280. const dropdownItems = this.options.headerDropdown;
  3281. const { index } = $.data($item);
  3282. const colIndex = this._dropdownActiveColIndex;
  3283. let callback = dropdownItems[index].action;
  3284. callback && callback.call(this.instance, this.getColumn(colIndex));
  3285. this.hideDropdown();
  3286. });
  3287. const _this = this;
  3288. function deactivateDropdown(e) {
  3289. _this.hideDropdown();
  3290. }
  3291. this.hideDropdown();
  3292. }
  3293. openDropdown(e) {
  3294. if (!this._dropdownWidth) {
  3295. $.style(this.$dropdownList, { display: '' });
  3296. this._dropdownWidth = $.style(this.$dropdownList, 'width');
  3297. }
  3298. $.style(this.$dropdownList, {
  3299. display: '',
  3300. left: (e.clientX - this._dropdownWidth + 4) + 'px',
  3301. top: (e.clientY + 4) + 'px'
  3302. });
  3303. const $cell = $.closest('.dt-cell', e.target);
  3304. const { colIndex } = $.data($cell);
  3305. this._dropdownActiveColIndex = colIndex;
  3306. }
  3307. hideDropdown() {
  3308. $.style(this.$dropdownList, {
  3309. display: 'none'
  3310. });
  3311. this._dropdownActiveColIndex = null;
  3312. }
  3313. bindResizeColumn() {
  3314. let isDragging = false;
  3315. let $resizingCell, startWidth, startX;
  3316. $.on(this.header, 'mousedown', '.dt-cell .dt-cell__resize-handle', (e, $handle) => {
  3317. document.body.classList.add('dt-resize');
  3318. const $cell = $handle.parentNode.parentNode;
  3319. $resizingCell = $cell;
  3320. const {
  3321. colIndex
  3322. } = $.data($resizingCell);
  3323. const col = this.getColumn(colIndex);
  3324. if (col && col.resizable === false) {
  3325. return;
  3326. }
  3327. isDragging = true;
  3328. startWidth = $.style($('.dt-cell__content', $resizingCell), 'width');
  3329. startX = e.pageX;
  3330. });
  3331. const onMouseup = (e) => {
  3332. document.body.classList.remove('dt-resize');
  3333. if (!$resizingCell) return;
  3334. isDragging = false;
  3335. const {
  3336. colIndex
  3337. } = $.data($resizingCell);
  3338. this.setColumnWidth(colIndex);
  3339. this.style.setBodyStyle();
  3340. $resizingCell = null;
  3341. };
  3342. $.on(document.body, 'mouseup', onMouseup);
  3343. this.instance.on('onDestroy', () => {
  3344. $.off(document.body, 'mouseup', onMouseup);
  3345. });
  3346. const onMouseMove = (e) => {
  3347. if (!isDragging) return;
  3348. let delta = e.pageX - startX;
  3349. if (this.options.direction === 'rtl') {
  3350. delta = -1 * delta;
  3351. }
  3352. const finalWidth = startWidth + delta;
  3353. const {
  3354. colIndex
  3355. } = $.data($resizingCell);
  3356. let columnMinWidth = this.options.minimumColumnWidth;
  3357. if (columnMinWidth > finalWidth) {
  3358. // don't resize past 30 pixels
  3359. return;
  3360. }
  3361. this.datamanager.updateColumn(colIndex, {
  3362. width: finalWidth
  3363. });
  3364. this.setColumnHeaderWidth(colIndex);
  3365. };
  3366. $.on(document.body, 'mousemove', onMouseMove);
  3367. this.instance.on('onDestroy', () => {
  3368. $.off(document.body, 'mousemove', onMouseMove);
  3369. });
  3370. }
  3371. bindPerfectColumnWidth() {
  3372. $.on(this.header, 'dblclick', '.dt-cell .dt-cell__resize-handle', (e, $handle) => {
  3373. const $cell = $handle.parentNode.parentNode;
  3374. const { colIndex } = $.data($cell);
  3375. let longestCell = this.bodyRenderer.visibleRows
  3376. .map(d => d[colIndex])
  3377. .reduce((acc, curr) => acc.content.length > curr.content.length ? acc : curr);
  3378. let $longestCellHTML = this.cellmanager.getCellHTML(longestCell);
  3379. let $div = document.createElement('div');
  3380. $div.innerHTML = $longestCellHTML;
  3381. let cellText = $div.querySelector('.dt-cell__content').textContent;
  3382. let {
  3383. borderLeftWidth,
  3384. borderRightWidth,
  3385. paddingLeft,
  3386. paddingRight
  3387. } = $.getStyle(this.bodyScrollable.querySelector('.dt-cell__content'));
  3388. let padding = [borderLeftWidth, borderRightWidth, paddingLeft, paddingRight]
  3389. .map(parseFloat)
  3390. .reduce((sum, val) => sum + val);
  3391. let width = $.measureTextWidth(cellText) + padding;
  3392. this.datamanager.updateColumn(colIndex, { width });
  3393. this.setColumnHeaderWidth(colIndex);
  3394. this.setColumnWidth(colIndex);
  3395. });
  3396. }
  3397. bindMoveColumn() {
  3398. if (this.options.disableReorderColumn) return;
  3399. const $parent = $('.dt-row', this.header);
  3400. this.sortable = Sortable.create($parent, {
  3401. onEnd: (e) => {
  3402. const {
  3403. oldIndex,
  3404. newIndex
  3405. } = e;
  3406. const $draggedCell = e.item;
  3407. const {
  3408. colIndex
  3409. } = $.data($draggedCell);
  3410. if (+colIndex === newIndex) return;
  3411. this.switchColumn(oldIndex, newIndex);
  3412. },
  3413. preventOnFilter: false,
  3414. filter: '.dt-cell__resize-handle, .dt-dropdown',
  3415. chosenClass: 'dt-cell--dragging',
  3416. animation: 150
  3417. });
  3418. }
  3419. sortColumn(colIndex, nextSortOrder) {
  3420. this.instance.freeze();
  3421. this.sortRows(colIndex, nextSortOrder)
  3422. .then(() => {
  3423. this.refreshHeader();
  3424. return this.rowmanager.refreshRows();
  3425. })
  3426. .then(() => this.instance.unfreeze())
  3427. .then(() => {
  3428. this.fireEvent('onSortColumn', this.getColumn(colIndex));
  3429. });
  3430. }
  3431. removeColumn(colIndex) {
  3432. const removedCol = this.getColumn(colIndex);
  3433. this.instance.freeze();
  3434. this.datamanager.removeColumn(colIndex)
  3435. .then(() => {
  3436. this.refreshHeader();
  3437. return this.rowmanager.refreshRows();
  3438. })
  3439. .then(() => this.instance.unfreeze())
  3440. .then(() => {
  3441. this.fireEvent('onRemoveColumn', removedCol);
  3442. });
  3443. }
  3444. switchColumn(oldIndex, newIndex) {
  3445. this.instance.freeze();
  3446. this.datamanager.switchColumn(oldIndex, newIndex)
  3447. .then(() => {
  3448. this.refreshHeader();
  3449. return this.rowmanager.refreshRows();
  3450. })
  3451. .then(() => {
  3452. this.setColumnWidth(oldIndex);
  3453. this.setColumnWidth(newIndex);
  3454. this.instance.unfreeze();
  3455. })
  3456. .then(() => {
  3457. this.fireEvent('onSwitchColumn',
  3458. this.getColumn(oldIndex), this.getColumn(newIndex)
  3459. );
  3460. });
  3461. }
  3462. toggleFilter(flag) {
  3463. if (!this.options.inlineFilters) return;
  3464. let showFilter;
  3465. if (flag === undefined) {
  3466. showFilter = !this.isFilterShown;
  3467. } else {
  3468. showFilter = flag;
  3469. }
  3470. if (showFilter) {
  3471. $.style(this.$filterRow, { display: '' });
  3472. } else {
  3473. $.style(this.$filterRow, { display: 'none' });
  3474. }
  3475. this.isFilterShown = showFilter;
  3476. this.style.setBodyStyle();
  3477. }
  3478. focusFilter(colIndex) {
  3479. if (!this.isFilterShown) return;
  3480. const $filterInput = $(`.dt-cell--col-${colIndex} .dt-filter`, this.$filterRow);
  3481. $filterInput.focus();
  3482. }
  3483. bindFilter() {
  3484. if (!this.options.inlineFilters) return;
  3485. const handler = e => {
  3486. this.applyFilter(this.getAppliedFilters());
  3487. };
  3488. $.on(this.header, 'keydown', '.dt-filter', debounce$3(handler, 300));
  3489. }
  3490. applyFilter(filters) {
  3491. this.datamanager.filterRows(filters)
  3492. .then(({
  3493. rowsToShow
  3494. }) => {
  3495. this.rowmanager.showRows(rowsToShow);
  3496. });
  3497. }
  3498. getAppliedFilters() {
  3499. const filters = {};
  3500. $.each('.dt-filter', this.header).map((input) => {
  3501. const value = input.value;
  3502. if (value) {
  3503. filters[input.dataset.colIndex] = value;
  3504. }
  3505. });
  3506. return filters;
  3507. }
  3508. applyDefaultSortOrder() {
  3509. // sort rows if any 1 column has a default sortOrder set
  3510. const columnsToSort = this.getColumns().filter(col => col.sortOrder !== 'none');
  3511. if (columnsToSort.length === 1) {
  3512. const column = columnsToSort[0];
  3513. this.sortColumn(column.colIndex, column.sortOrder);
  3514. }
  3515. }
  3516. sortRows(colIndex, sortOrder) {
  3517. return this.datamanager.sortRows(colIndex, sortOrder);
  3518. }
  3519. getColumn(colIndex) {
  3520. return this.datamanager.getColumn(colIndex);
  3521. }
  3522. getColumns() {
  3523. return this.datamanager.getColumns();
  3524. }
  3525. setColumnWidth(colIndex, width) {
  3526. colIndex = +colIndex;
  3527. let columnWidth = width || this.getColumn(colIndex).width;
  3528. const selector = [
  3529. `.dt-cell__content--col-${colIndex}`,
  3530. `.dt-cell__edit--col-${colIndex}`
  3531. ].join(', ');
  3532. const styles = {
  3533. width: columnWidth + 'px'
  3534. };
  3535. this.style.setStyle(selector, styles);
  3536. }
  3537. setColumnHeaderWidth(colIndex) {
  3538. colIndex = +colIndex;
  3539. this.$columnMap = this.$columnMap || [];
  3540. const selector = `.dt-cell__content--header-${colIndex}`;
  3541. const {
  3542. width
  3543. } = this.getColumn(colIndex);
  3544. let $column = this.$columnMap[colIndex];
  3545. if (!$column) {
  3546. $column = this.header.querySelector(selector);
  3547. this.$columnMap[colIndex] = $column;
  3548. }
  3549. $column.style.width = width + 'px';
  3550. }
  3551. getColumnMinWidth(colIndex) {
  3552. colIndex = +colIndex;
  3553. return this.getColumn(colIndex).minWidth || 24;
  3554. }
  3555. getFirstColumnIndex() {
  3556. return this.datamanager.getColumnIndexById('_rowIndex') + 1;
  3557. }
  3558. getHeaderCell$(colIndex) {
  3559. return $(`.dt-cell--header-${colIndex}`, this.header);
  3560. }
  3561. getLastColumnIndex() {
  3562. return this.datamanager.getColumnCount() - 1;
  3563. }
  3564. getDropdownHTML() {
  3565. const { dropdownButton } = this.options;
  3566. return `
  3567. <div class="dt-dropdown">
  3568. <div class="dt-dropdown__toggle">${dropdownButton}</div>
  3569. </div>
  3570. `;
  3571. }
  3572. getDropdownListHTML() {
  3573. const { headerDropdown: dropdownItems } = this.options;
  3574. return `
  3575. <div class="dt-dropdown__list">
  3576. ${dropdownItems.map((d, i) => `
  3577. <div class="dt-dropdown__list-item" data-index="${i}">${d.label}</div>
  3578. `).join('')}
  3579. </div>
  3580. `;
  3581. }
  3582. }
  3583. class RowManager {
  3584. constructor(instance) {
  3585. this.instance = instance;
  3586. linkProperties(this, this.instance, [
  3587. 'options',
  3588. 'fireEvent',
  3589. 'wrapper',
  3590. 'bodyScrollable',
  3591. 'bodyRenderer',
  3592. 'style'
  3593. ]);
  3594. this.bindEvents();
  3595. this.refreshRows = nextTick(this.refreshRows, this);
  3596. }
  3597. get datamanager() {
  3598. return this.instance.datamanager;
  3599. }
  3600. get cellmanager() {
  3601. return this.instance.cellmanager;
  3602. }
  3603. bindEvents() {
  3604. this.bindCheckbox();
  3605. }
  3606. bindCheckbox() {
  3607. if (!this.options.checkboxColumn) return;
  3608. // map of checked rows
  3609. this.checkMap = [];
  3610. $.on(this.wrapper, 'click', '.dt-cell--col-0 [type="checkbox"]', (e, $checkbox) => {
  3611. const $cell = $checkbox.closest('.dt-cell');
  3612. const {
  3613. rowIndex,
  3614. isHeader
  3615. } = $.data($cell);
  3616. const checked = $checkbox.checked;
  3617. if (isHeader) {
  3618. this.checkAll(checked);
  3619. } else {
  3620. this.checkRow(rowIndex, checked);
  3621. }
  3622. });
  3623. }
  3624. refreshRows() {
  3625. this.instance.renderBody();
  3626. this.instance.setDimensions();
  3627. }
  3628. refreshRow(row, rowIndex) {
  3629. const _row = this.datamanager.updateRow(row, rowIndex);
  3630. _row.forEach(cell => {
  3631. this.cellmanager.refreshCell(cell, true);
  3632. });
  3633. }
  3634. getCheckedRows() {
  3635. if (!this.checkMap) {
  3636. return [];
  3637. }
  3638. let out = [];
  3639. for (let rowIndex in this.checkMap) {
  3640. const checked = this.checkMap[rowIndex];
  3641. if (checked === 1) {
  3642. out.push(rowIndex);
  3643. }
  3644. }
  3645. return out;
  3646. }
  3647. highlightCheckedRows() {
  3648. this.getCheckedRows()
  3649. .map(rowIndex => this.checkRow(rowIndex, true));
  3650. }
  3651. checkRow(rowIndex, toggle) {
  3652. const value = toggle ? 1 : 0;
  3653. const selector = rowIndex => `.dt-cell--0-${rowIndex} [type="checkbox"]`;
  3654. // update internal map
  3655. this.checkMap[rowIndex] = value;
  3656. // set checkbox value explicitly
  3657. $.each(selector(rowIndex), this.bodyScrollable)
  3658. .map(input => {
  3659. input.checked = toggle;
  3660. });
  3661. // highlight row
  3662. this.highlightRow(rowIndex, toggle);
  3663. this.showCheckStatus();
  3664. this.fireEvent('onCheckRow', this.datamanager.getRow(rowIndex));
  3665. }
  3666. checkAll(toggle) {
  3667. const value = toggle ? 1 : 0;
  3668. // update internal map
  3669. if (toggle) {
  3670. this.checkMap = Array.from(Array(this.getTotalRows())).map(c => value);
  3671. } else {
  3672. this.checkMap = [];
  3673. }
  3674. // set checkbox value
  3675. $.each('.dt-cell--col-0 [type="checkbox"]', this.bodyScrollable)
  3676. .map(input => {
  3677. input.checked = toggle;
  3678. });
  3679. // highlight all
  3680. this.highlightAll(toggle);
  3681. this.showCheckStatus();
  3682. this.fireEvent('onCheckRow');
  3683. }
  3684. showCheckStatus() {
  3685. if (!this.options.checkedRowStatus) return;
  3686. const checkedRows = this.getCheckedRows();
  3687. const count = checkedRows.length;
  3688. if (count > 0) {
  3689. let message = this.instance.translate('{count} rows selected', {
  3690. count: count
  3691. });
  3692. this.bodyRenderer.showToastMessage(message);
  3693. } else {
  3694. this.bodyRenderer.clearToastMessage();
  3695. }
  3696. }
  3697. highlightRow(rowIndex, toggle = true) {
  3698. const $row = this.getRow$(rowIndex);
  3699. if (!$row) return;
  3700. if (!toggle && this.bodyScrollable.classList.contains('dt-scrollable--highlight-all')) {
  3701. $row.classList.add('dt-row--unhighlight');
  3702. return;
  3703. }
  3704. if (toggle && $row.classList.contains('dt-row--unhighlight')) {
  3705. $row.classList.remove('dt-row--unhighlight');
  3706. }
  3707. this._highlightedRows = this._highlightedRows || {};
  3708. if (toggle) {
  3709. $row.classList.add('dt-row--highlight');
  3710. this._highlightedRows[rowIndex] = $row;
  3711. } else {
  3712. $row.classList.remove('dt-row--highlight');
  3713. delete this._highlightedRows[rowIndex];
  3714. }
  3715. }
  3716. highlightAll(toggle = true) {
  3717. if (toggle) {
  3718. this.bodyScrollable.classList.add('dt-scrollable--highlight-all');
  3719. } else {
  3720. this.bodyScrollable.classList.remove('dt-scrollable--highlight-all');
  3721. for (const rowIndex in this._highlightedRows) {
  3722. const $row = this._highlightedRows[rowIndex];
  3723. $row.classList.remove('dt-row--highlight');
  3724. }
  3725. this._highlightedRows = {};
  3726. }
  3727. }
  3728. showRows(rowIndices) {
  3729. rowIndices = ensureArray(rowIndices);
  3730. const rows = rowIndices.map(rowIndex => this.datamanager.getRow(rowIndex));
  3731. this.bodyRenderer.renderRows(rows);
  3732. }
  3733. showAllRows() {
  3734. const rowIndices = this.datamanager.getAllRowIndices();
  3735. this.showRows(rowIndices);
  3736. }
  3737. getChildrenToShowForNode(rowIndex) {
  3738. const row = this.datamanager.getRow(rowIndex);
  3739. row.meta.isTreeNodeClose = false;
  3740. return this.datamanager.getImmediateChildren(rowIndex);
  3741. }
  3742. openSingleNode(rowIndex) {
  3743. const childrenToShow = this.getChildrenToShowForNode(rowIndex);
  3744. const visibleRowIndices = this.bodyRenderer.visibleRowIndices;
  3745. const rowsToShow = uniq$1([...childrenToShow, ...visibleRowIndices]).sort(numberSortAsc);
  3746. this.showRows(rowsToShow);
  3747. }
  3748. getChildrenToHideForNode(rowIndex) {
  3749. const row = this.datamanager.getRow(rowIndex);
  3750. row.meta.isTreeNodeClose = true;
  3751. const rowsToHide = this.datamanager.getChildren(rowIndex);
  3752. rowsToHide.forEach(rowIndex => {
  3753. const row = this.datamanager.getRow(rowIndex);
  3754. if (!row.meta.isLeaf) {
  3755. row.meta.isTreeNodeClose = true;
  3756. }
  3757. });
  3758. return rowsToHide;
  3759. }
  3760. closeSingleNode(rowIndex) {
  3761. const rowsToHide = this.getChildrenToHideForNode(rowIndex);
  3762. const visibleRows = this.bodyRenderer.visibleRowIndices;
  3763. const rowsToShow = visibleRows
  3764. .filter(rowIndex => !rowsToHide.includes(rowIndex))
  3765. .sort(numberSortAsc);
  3766. this.showRows(rowsToShow);
  3767. }
  3768. expandAllNodes() {
  3769. let rows = this.datamanager.getRows();
  3770. let rootNodes = rows.filter(row => !row.meta.isLeaf);
  3771. const childrenToShow = rootNodes.map(row => this.getChildrenToShowForNode(row.meta.rowIndex)).flat();
  3772. const visibleRowIndices = this.bodyRenderer.visibleRowIndices;
  3773. const rowsToShow = uniq$1([...childrenToShow, ...visibleRowIndices]).sort(numberSortAsc);
  3774. this.showRows(rowsToShow);
  3775. }
  3776. collapseAllNodes() {
  3777. let rows = this.datamanager.getRows();
  3778. let rootNodes = rows.filter(row => row.meta.indent === 0);
  3779. const rowsToHide = rootNodes.map(row => this.getChildrenToHideForNode(row.meta.rowIndex)).flat();
  3780. const visibleRows = this.bodyRenderer.visibleRowIndices;
  3781. const rowsToShow = visibleRows
  3782. .filter(rowIndex => !rowsToHide.includes(rowIndex))
  3783. .sort(numberSortAsc);
  3784. this.showRows(rowsToShow);
  3785. }
  3786. setTreeDepth(depth) {
  3787. let rows = this.datamanager.getRows();
  3788. const rowsToOpen = rows.filter(row => row.meta.indent < depth);
  3789. const rowsToClose = rows.filter(row => row.meta.indent >= depth);
  3790. const rowsToHide = rowsToClose.filter(row => row.meta.indent > depth);
  3791. rowsToClose.forEach(row => {
  3792. if (!row.meta.isLeaf) {
  3793. row.meta.isTreeNodeClose = true;
  3794. }
  3795. });
  3796. rowsToOpen.forEach(row => {
  3797. if (!row.meta.isLeaf) {
  3798. row.meta.isTreeNodeClose = false;
  3799. }
  3800. });
  3801. const rowsToShow = rows
  3802. .filter(row => !rowsToHide.includes(row))
  3803. .map(row => row.meta.rowIndex)
  3804. .sort(numberSortAsc);
  3805. this.showRows(rowsToShow);
  3806. }
  3807. getRow$(rowIndex) {
  3808. return $(this.selector(rowIndex), this.bodyScrollable);
  3809. }
  3810. getTotalRows() {
  3811. return this.datamanager.getRowCount();
  3812. }
  3813. getFirstRowIndex() {
  3814. return 0;
  3815. }
  3816. getLastRowIndex() {
  3817. return this.datamanager.getRowCount() - 1;
  3818. }
  3819. scrollToRow(rowIndex) {
  3820. rowIndex = +rowIndex;
  3821. this._lastScrollTo = this._lastScrollTo || 0;
  3822. const $row = this.getRow$(rowIndex);
  3823. if ($.inViewport($row, this.bodyScrollable)) return;
  3824. const {
  3825. height
  3826. } = $row.getBoundingClientRect();
  3827. const {
  3828. top,
  3829. bottom
  3830. } = this.bodyScrollable.getBoundingClientRect();
  3831. const rowsInView = Math.floor((bottom - top) / height);
  3832. let offset = 0;
  3833. if (rowIndex > this._lastScrollTo) {
  3834. offset = height * ((rowIndex + 1) - rowsInView);
  3835. } else {
  3836. offset = height * ((rowIndex + 1) - 1);
  3837. }
  3838. this._lastScrollTo = rowIndex;
  3839. $.scrollTop(this.bodyScrollable, offset);
  3840. }
  3841. getRowHTML(row, props) {
  3842. const dataAttr = makeDataAttributeString(props);
  3843. let rowIdentifier = props.rowIndex;
  3844. if (props.isFilter) {
  3845. row = row.map(cell => (Object.assign({}, cell, {
  3846. content: this.getFilterInput({
  3847. colIndex: cell.colIndex,
  3848. name: cell.name
  3849. }),
  3850. isFilter: 1,
  3851. isHeader: undefined,
  3852. editable: false
  3853. })));
  3854. rowIdentifier = 'filter';
  3855. }
  3856. if (props.isHeader) {
  3857. rowIdentifier = 'header';
  3858. }
  3859. return `
  3860. <div class="dt-row dt-row-${rowIdentifier}" ${dataAttr}>
  3861. ${row.map(cell => this.cellmanager.getCellHTML(cell)).join('')}
  3862. </div>
  3863. `;
  3864. }
  3865. getFilterInput(props) {
  3866. let title = `title="Filter based on ${props.name || 'Index'}"`;
  3867. const dataAttr = makeDataAttributeString(props);
  3868. return `<input class="dt-filter dt-input" type="text" ${dataAttr} tabindex="1"
  3869. ${props.colIndex === 0 ? 'disabled' : title} />`;
  3870. }
  3871. selector(rowIndex) {
  3872. return `.dt-row-${rowIndex}`;
  3873. }
  3874. }
  3875. var hyperlist = createCommonjsModule(function (module, exports) {
  3876. (function(f){{module.exports=f();}})(function(){return (function(){function r(e,n,t){function o(i,f){if(!n[i]){if(!e[i]){var c="function"==typeof commonjsRequire&&commonjsRequire;if(!f&&c)return c(i,!0);if(u)return u(i,!0);var a=new Error("Cannot find module '"+i+"'");throw a.code="MODULE_NOT_FOUND",a}var p=n[i]={exports:{}};e[i][0].call(p.exports,function(r){var n=e[i][1][r];return o(n||r)},p,p.exports,r,e,n,t);}return n[i].exports}for(var u="function"==typeof commonjsRequire&&commonjsRequire,i=0;i<t.length;i++)o(t[i]);return o}return r})()({1:[function(_dereq_,module,exports){
  3877. // Default configuration.
  3878. Object.defineProperty(exports, "__esModule", {
  3879. value: true
  3880. });
  3881. var _createClass = function () { function defineProperties(target, props) { for (var i = 0; i < props.length; i++) { var descriptor = props[i]; descriptor.enumerable = descriptor.enumerable || false; descriptor.configurable = true; if ("value" in descriptor) descriptor.writable = true; Object.defineProperty(target, descriptor.key, descriptor); } } return function (Constructor, protoProps, staticProps) { if (protoProps) defineProperties(Constructor.prototype, protoProps); if (staticProps) defineProperties(Constructor, staticProps); return Constructor; }; }();
  3882. function _defineProperty(obj, key, value) { if (key in obj) { Object.defineProperty(obj, key, { value: value, enumerable: true, configurable: true, writable: true }); } else { obj[key] = value; } return obj; }
  3883. function _classCallCheck(instance, Constructor) { if (!(instance instanceof Constructor)) { throw new TypeError("Cannot call a class as a function"); } }
  3884. var defaultConfig = {
  3885. width: '100%',
  3886. height: '100%'
  3887. // Check for valid number.
  3888. };var isNumber = function isNumber(input) {
  3889. return Number(input) === Number(input);
  3890. };
  3891. // Add a class to an element.
  3892. var addClass = 'classList' in document.documentElement ? function (element, className) {
  3893. element.classList.add(className);
  3894. } : function (element, className) {
  3895. var oldClass = element.getAttribute('class') || '';
  3896. element.setAttribute('class', oldClass + ' ' + className);
  3897. };
  3898. /**
  3899. * Creates a HyperList instance that virtually scrolls very large amounts of
  3900. * data effortlessly.
  3901. */
  3902. var HyperList = function () {
  3903. _createClass(HyperList, null, [{
  3904. key: 'create',
  3905. value: function create(element, userProvidedConfig) {
  3906. return new HyperList(element, userProvidedConfig);
  3907. }
  3908. /**
  3909. * Merge given css style on an element
  3910. * @param {DOMElement} element
  3911. * @param {Object} style
  3912. */
  3913. }, {
  3914. key: 'mergeStyle',
  3915. value: function mergeStyle(element, style) {
  3916. for (var i in style) {
  3917. if (element.style[i] !== style[i]) {
  3918. element.style[i] = style[i];
  3919. }
  3920. }
  3921. }
  3922. }, {
  3923. key: 'getMaxBrowserHeight',
  3924. value: function getMaxBrowserHeight() {
  3925. // Create two elements, the wrapper is `1px` tall and is transparent and
  3926. // positioned at the top of the page. Inside that is an element that gets
  3927. // set to 1 billion pixels. Then reads the max height the browser can
  3928. // calculate.
  3929. var wrapper = document.createElement('div');
  3930. var fixture = document.createElement('div');
  3931. // As said above, these values get set to put the fixture elements into the
  3932. // right visual state.
  3933. HyperList.mergeStyle(wrapper, { position: 'absolute', height: '1px', opacity: 0 });
  3934. HyperList.mergeStyle(fixture, { height: '1e7px' });
  3935. // Add the fixture into the wrapper element.
  3936. wrapper.appendChild(fixture);
  3937. // Apply to the page, the values won't kick in unless this is attached.
  3938. document.body.appendChild(wrapper);
  3939. // Get the maximum element height in pixels.
  3940. var maxElementHeight = fixture.offsetHeight;
  3941. // Remove the element immediately after reading the value.
  3942. document.body.removeChild(wrapper);
  3943. return maxElementHeight;
  3944. }
  3945. }]);
  3946. function HyperList(element, userProvidedConfig) {
  3947. var _this = this;
  3948. _classCallCheck(this, HyperList);
  3949. this._config = {};
  3950. this._lastRepaint = null;
  3951. this._maxElementHeight = HyperList.getMaxBrowserHeight();
  3952. this.refresh(element, userProvidedConfig);
  3953. var config = this._config;
  3954. // Create internal render loop.
  3955. var render = function render() {
  3956. var scrollTop = _this._getScrollPosition();
  3957. var lastRepaint = _this._lastRepaint;
  3958. _this._renderAnimationFrame = window.requestAnimationFrame(render);
  3959. if (scrollTop === lastRepaint) {
  3960. return;
  3961. }
  3962. var diff = lastRepaint ? scrollTop - lastRepaint : 0;
  3963. if (!lastRepaint || diff < 0 || diff > _this._averageHeight) {
  3964. var rendered = _this._renderChunk();
  3965. _this._lastRepaint = scrollTop;
  3966. if (rendered !== false && typeof config.afterRender === 'function') {
  3967. config.afterRender();
  3968. }
  3969. }
  3970. };
  3971. render();
  3972. }
  3973. _createClass(HyperList, [{
  3974. key: 'destroy',
  3975. value: function destroy() {
  3976. window.cancelAnimationFrame(this._renderAnimationFrame);
  3977. }
  3978. }, {
  3979. key: 'refresh',
  3980. value: function refresh(element, userProvidedConfig) {
  3981. var _scrollerStyle;
  3982. Object.assign(this._config, defaultConfig, userProvidedConfig);
  3983. if (!element || element.nodeType !== 1) {
  3984. throw new Error('HyperList requires a valid DOM Node container');
  3985. }
  3986. this._element = element;
  3987. var config = this._config;
  3988. var scroller = this._scroller || config.scroller || document.createElement(config.scrollerTagName || 'tr');
  3989. // Default configuration option `useFragment` to `true`.
  3990. if (typeof config.useFragment !== 'boolean') {
  3991. this._config.useFragment = true;
  3992. }
  3993. if (!config.generate) {
  3994. throw new Error('Missing required `generate` function');
  3995. }
  3996. if (!isNumber(config.total)) {
  3997. throw new Error('Invalid required `total` value, expected number');
  3998. }
  3999. if (!Array.isArray(config.itemHeight) && !isNumber(config.itemHeight)) {
  4000. throw new Error('\n Invalid required `itemHeight` value, expected number or array\n '.trim());
  4001. } else if (isNumber(config.itemHeight)) {
  4002. this._itemHeights = Array(config.total).fill(config.itemHeight);
  4003. } else {
  4004. this._itemHeights = config.itemHeight;
  4005. }
  4006. // Width and height should be coerced to string representations. Either in
  4007. // `%` or `px`.
  4008. Object.keys(defaultConfig).filter(function (prop) {
  4009. return prop in config;
  4010. }).forEach(function (prop) {
  4011. var value = config[prop];
  4012. var isValueNumber = isNumber(value);
  4013. if (value && typeof value !== 'string' && typeof value !== 'number') {
  4014. var msg = 'Invalid optional `' + prop + '`, expected string or number';
  4015. throw new Error(msg);
  4016. } else if (isValueNumber) {
  4017. config[prop] = value + 'px';
  4018. }
  4019. });
  4020. var isHoriz = Boolean(config.horizontal);
  4021. var value = config[isHoriz ? 'width' : 'height'];
  4022. if (value) {
  4023. var isValueNumber = isNumber(value);
  4024. var isValuePercent = isValueNumber ? false : value.slice(-1) === '%';
  4025. // Compute the containerHeight as number
  4026. var numberValue = isValueNumber ? value : parseInt(value.replace(/px|%/, ''), 10);
  4027. var innerSize = window[isHoriz ? 'innerWidth' : 'innerHeight'];
  4028. if (isValuePercent) {
  4029. this._containerSize = innerSize * numberValue / 100;
  4030. } else {
  4031. this._containerSize = isNumber(value) ? value : numberValue;
  4032. }
  4033. }
  4034. var scrollContainer = config.scrollContainer;
  4035. var scrollerHeight = config.itemHeight * config.total;
  4036. var maxElementHeight = this._maxElementHeight;
  4037. if (scrollerHeight > maxElementHeight) {
  4038. console.warn(['HyperList: The maximum element height', maxElementHeight + 'px has', 'been exceeded; please reduce your item height.'].join(' '));
  4039. }
  4040. // Decorate the container element with styles that will match
  4041. // the user supplied configuration.
  4042. var elementStyle = {
  4043. width: '' + config.width,
  4044. height: scrollContainer ? scrollerHeight + 'px' : '' + config.height,
  4045. overflow: scrollContainer ? 'none' : 'auto',
  4046. position: 'relative'
  4047. };
  4048. HyperList.mergeStyle(element, elementStyle);
  4049. if (scrollContainer) {
  4050. HyperList.mergeStyle(config.scrollContainer, { overflow: 'auto' });
  4051. }
  4052. var scrollerStyle = (_scrollerStyle = {
  4053. opacity: '0',
  4054. position: 'absolute'
  4055. }, _defineProperty(_scrollerStyle, isHoriz ? 'height' : 'width', '1px'), _defineProperty(_scrollerStyle, isHoriz ? 'width' : 'height', scrollerHeight + 'px'), _scrollerStyle);
  4056. HyperList.mergeStyle(scroller, scrollerStyle);
  4057. // Only append the scroller element once.
  4058. if (!this._scroller) {
  4059. element.appendChild(scroller);
  4060. }
  4061. var padding = this._computeScrollPadding();
  4062. this._scrollPaddingBottom = padding.bottom;
  4063. this._scrollPaddingTop = padding.top;
  4064. // Set the scroller instance.
  4065. this._scroller = scroller;
  4066. this._scrollHeight = this._computeScrollHeight();
  4067. // Reuse the item positions if refreshed, otherwise set to empty array.
  4068. this._itemPositions = this._itemPositions || Array(config.total).fill(0);
  4069. // Each index in the array should represent the position in the DOM.
  4070. this._computePositions(0);
  4071. // Render after refreshing. Force render if we're calling refresh manually.
  4072. this._renderChunk(this._lastRepaint !== null);
  4073. if (typeof config.afterRender === 'function') {
  4074. config.afterRender();
  4075. }
  4076. }
  4077. }, {
  4078. key: '_getRow',
  4079. value: function _getRow(i) {
  4080. var config = this._config;
  4081. var item = config.generate(i);
  4082. var height = item.height;
  4083. if (height !== undefined && isNumber(height)) {
  4084. item = item.element;
  4085. // The height isn't the same as predicted, compute positions again
  4086. if (height !== this._itemHeights[i]) {
  4087. this._itemHeights[i] = height;
  4088. this._computePositions(i);
  4089. this._scrollHeight = this._computeScrollHeight(i);
  4090. }
  4091. } else {
  4092. height = this._itemHeights[i];
  4093. }
  4094. if (!item || item.nodeType !== 1) {
  4095. throw new Error('Generator did not return a DOM Node for index: ' + i);
  4096. }
  4097. addClass(item, config.rowClassName || 'vrow');
  4098. var top = this._itemPositions[i] + this._scrollPaddingTop;
  4099. HyperList.mergeStyle(item, _defineProperty({
  4100. position: 'absolute'
  4101. }, config.horizontal ? 'left' : 'top', top + 'px'));
  4102. return item;
  4103. }
  4104. }, {
  4105. key: '_getScrollPosition',
  4106. value: function _getScrollPosition() {
  4107. var config = this._config;
  4108. if (typeof config.overrideScrollPosition === 'function') {
  4109. return config.overrideScrollPosition();
  4110. }
  4111. return this._element[config.horizontal ? 'scrollLeft' : 'scrollTop'];
  4112. }
  4113. }, {
  4114. key: '_renderChunk',
  4115. value: function _renderChunk(force) {
  4116. var config = this._config;
  4117. var element = this._element;
  4118. var scrollTop = this._getScrollPosition();
  4119. var total = config.total;
  4120. var from = config.reverse ? this._getReverseFrom(scrollTop) : this._getFrom(scrollTop) - 1;
  4121. if (from < 0 || from - this._screenItemsLen < 0) {
  4122. from = 0;
  4123. }
  4124. if (!force && this._lastFrom === from) {
  4125. return false;
  4126. }
  4127. this._lastFrom = from;
  4128. var to = from + this._cachedItemsLen;
  4129. if (to > total || to + this._cachedItemsLen > total) {
  4130. to = total;
  4131. }
  4132. // Append all the new rows in a document fragment that we will later append
  4133. // to the parent node
  4134. var fragment = config.useFragment ? document.createDocumentFragment() : []
  4135. // Sometimes you'll pass fake elements to this tool and Fragments require
  4136. // real elements.
  4137. // The element that forces the container to scroll.
  4138. ;var scroller = this._scroller;
  4139. // Keep the scroller in the list of children.
  4140. fragment[config.useFragment ? 'appendChild' : 'push'](scroller);
  4141. for (var i = from; i < to; i++) {
  4142. var row = this._getRow(i);
  4143. fragment[config.useFragment ? 'appendChild' : 'push'](row);
  4144. }
  4145. if (config.applyPatch) {
  4146. return config.applyPatch(element, fragment);
  4147. }
  4148. element.innerHTML = '';
  4149. element.appendChild(fragment);
  4150. }
  4151. }, {
  4152. key: '_computePositions',
  4153. value: function _computePositions() {
  4154. var from = arguments.length > 0 && arguments[0] !== undefined ? arguments[0] : 1;
  4155. var config = this._config;
  4156. var total = config.total;
  4157. var reverse = config.reverse;
  4158. if (from < 1 && !reverse) {
  4159. from = 1;
  4160. }
  4161. for (var i = from; i < total; i++) {
  4162. if (reverse) {
  4163. if (i === 0) {
  4164. this._itemPositions[0] = this._scrollHeight - this._itemHeights[0];
  4165. } else {
  4166. this._itemPositions[i] = this._itemPositions[i - 1] - this._itemHeights[i];
  4167. }
  4168. } else {
  4169. this._itemPositions[i] = this._itemHeights[i - 1] + this._itemPositions[i - 1];
  4170. }
  4171. }
  4172. }
  4173. }, {
  4174. key: '_computeScrollHeight',
  4175. value: function _computeScrollHeight() {
  4176. var _HyperList$mergeStyle2,
  4177. _this2 = this;
  4178. var config = this._config;
  4179. var isHoriz = Boolean(config.horizontal);
  4180. var total = config.total;
  4181. var scrollHeight = this._itemHeights.reduce(function (a, b) {
  4182. return a + b;
  4183. }, 0) + this._scrollPaddingBottom + this._scrollPaddingTop;
  4184. HyperList.mergeStyle(this._scroller, (_HyperList$mergeStyle2 = {
  4185. opacity: 0,
  4186. position: 'absolute',
  4187. top: '0px'
  4188. }, _defineProperty(_HyperList$mergeStyle2, isHoriz ? 'height' : 'width', '1px'), _defineProperty(_HyperList$mergeStyle2, isHoriz ? 'width' : 'height', scrollHeight + 'px'), _HyperList$mergeStyle2));
  4189. // Calculate the height median
  4190. var sortedItemHeights = this._itemHeights.slice(0).sort(function (a, b) {
  4191. return a - b;
  4192. });
  4193. var middle = Math.floor(total / 2);
  4194. var averageHeight = total % 2 === 0 ? (sortedItemHeights[middle] + sortedItemHeights[middle - 1]) / 2 : sortedItemHeights[middle];
  4195. var clientProp = isHoriz ? 'clientWidth' : 'clientHeight';
  4196. var element = config.scrollContainer ? config.scrollContainer : this._element;
  4197. var containerHeight = element[clientProp] ? element[clientProp] : this._containerSize;
  4198. this._screenItemsLen = Math.ceil(containerHeight / averageHeight);
  4199. this._containerSize = containerHeight;
  4200. // Cache 3 times the number of items that fit in the container viewport.
  4201. this._cachedItemsLen = Math.max(this._cachedItemsLen || 0, this._screenItemsLen * 3);
  4202. this._averageHeight = averageHeight;
  4203. if (config.reverse) {
  4204. window.requestAnimationFrame(function () {
  4205. if (isHoriz) {
  4206. _this2._element.scrollLeft = scrollHeight;
  4207. } else {
  4208. _this2._element.scrollTop = scrollHeight;
  4209. }
  4210. });
  4211. }
  4212. return scrollHeight;
  4213. }
  4214. }, {
  4215. key: '_computeScrollPadding',
  4216. value: function _computeScrollPadding() {
  4217. var config = this._config;
  4218. var isHoriz = Boolean(config.horizontal);
  4219. var isReverse = config.reverse;
  4220. var styles = window.getComputedStyle(this._element);
  4221. var padding = function padding(location) {
  4222. var cssValue = styles.getPropertyValue('padding-' + location);
  4223. return parseInt(cssValue, 10) || 0;
  4224. };
  4225. if (isHoriz && isReverse) {
  4226. return {
  4227. bottom: padding('left'),
  4228. top: padding('right')
  4229. };
  4230. } else if (isHoriz) {
  4231. return {
  4232. bottom: padding('right'),
  4233. top: padding('left')
  4234. };
  4235. } else if (isReverse) {
  4236. return {
  4237. bottom: padding('top'),
  4238. top: padding('bottom')
  4239. };
  4240. } else {
  4241. return {
  4242. bottom: padding('bottom'),
  4243. top: padding('top')
  4244. };
  4245. }
  4246. }
  4247. }, {
  4248. key: '_getFrom',
  4249. value: function _getFrom(scrollTop) {
  4250. var i = 0;
  4251. while (this._itemPositions[i] < scrollTop) {
  4252. i++;
  4253. }
  4254. return i;
  4255. }
  4256. }, {
  4257. key: '_getReverseFrom',
  4258. value: function _getReverseFrom(scrollTop) {
  4259. var i = this._config.total - 1;
  4260. while (i > 0 && this._itemPositions[i] < scrollTop + this._containerSize) {
  4261. i--;
  4262. }
  4263. return i;
  4264. }
  4265. }]);
  4266. return HyperList;
  4267. }();
  4268. exports.default = HyperList;
  4269. module.exports = exports['default'];
  4270. },{}]},{},[1])(1)
  4271. });
  4272. });
  4273. var HyperList = unwrapExports(hyperlist);
  4274. class BodyRenderer {
  4275. constructor(instance) {
  4276. this.instance = instance;
  4277. this.options = instance.options;
  4278. this.datamanager = instance.datamanager;
  4279. this.rowmanager = instance.rowmanager;
  4280. this.cellmanager = instance.cellmanager;
  4281. this.bodyScrollable = instance.bodyScrollable;
  4282. this.footer = this.instance.footer;
  4283. this.log = instance.log;
  4284. }
  4285. renderRows(rows) {
  4286. this.visibleRows = rows;
  4287. this.visibleRowIndices = rows.map(row => row.meta.rowIndex);
  4288. if (rows.length === 0) {
  4289. this.bodyScrollable.innerHTML = this.getNoDataHTML();
  4290. return;
  4291. }
  4292. const rowViewOrder = this.datamanager.rowViewOrder.map(index => {
  4293. if (this.visibleRowIndices.includes(index)) {
  4294. return index;
  4295. }
  4296. return null;
  4297. }).filter(index => index !== null);
  4298. const computedStyle = getComputedStyle(this.bodyScrollable);
  4299. let config = {
  4300. width: computedStyle.width,
  4301. height: computedStyle.height,
  4302. itemHeight: this.options.cellHeight,
  4303. total: rows.length,
  4304. generate: (index) => {
  4305. const el = document.createElement('div');
  4306. const rowIndex = rowViewOrder[index];
  4307. const row = this.datamanager.getRow(rowIndex);
  4308. const rowHTML = this.rowmanager.getRowHTML(row, row.meta);
  4309. el.innerHTML = rowHTML;
  4310. return el.children[0];
  4311. },
  4312. afterRender: () => {
  4313. this.restoreState();
  4314. }
  4315. };
  4316. if (!this.hyperlist) {
  4317. this.hyperlist = new HyperList(this.bodyScrollable, config);
  4318. } else {
  4319. this.hyperlist.refresh(this.bodyScrollable, config);
  4320. }
  4321. this.renderFooter();
  4322. }
  4323. render() {
  4324. const rows = this.datamanager.getRowsForView();
  4325. this.renderRows(rows);
  4326. // setDimensions requires atleast 1 row to exist in dom
  4327. this.instance.setDimensions();
  4328. }
  4329. renderFooter() {
  4330. if (!this.options.showTotalRow) return;
  4331. const totalRow = this.getTotalRow();
  4332. let html = this.rowmanager.getRowHTML(totalRow, { isTotalRow: 1, rowIndex: 'totalRow' });
  4333. this.footer.innerHTML = html;
  4334. }
  4335. getTotalRow() {
  4336. const columns = this.datamanager.getColumns();
  4337. const totalRowTemplate = columns.map(col => {
  4338. let content = null;
  4339. if (['_rowIndex', '_checkbox'].includes(col.id)) {
  4340. content = '';
  4341. }
  4342. return {
  4343. content,
  4344. isTotalRow: 1,
  4345. colIndex: col.colIndex,
  4346. column: col
  4347. };
  4348. });
  4349. const totalRow = totalRowTemplate.map((cell, i) => {
  4350. if (cell.content === '') return cell;
  4351. if (this.options.hooks.columnTotal) {
  4352. const columnValues = this.visibleRows.map(row => row[i].content);
  4353. const result = this.options.hooks.columnTotal.call(this.instance, columnValues, cell);
  4354. if (result != null) {
  4355. cell.content = result;
  4356. return cell;
  4357. }
  4358. }
  4359. cell.content = this.visibleRows.reduce((acc, prevRow) => {
  4360. const prevCell = prevRow[i];
  4361. if (typeof prevCell.content === 'number') {
  4362. if (acc == null) acc = 0;
  4363. return acc + prevCell.content;
  4364. }
  4365. return acc;
  4366. }, cell.content);
  4367. return cell;
  4368. });
  4369. return totalRow;
  4370. }
  4371. restoreState() {
  4372. this.rowmanager.highlightCheckedRows();
  4373. this.cellmanager.selectAreaOnClusterChanged();
  4374. this.cellmanager.focusCellOnClusterChanged();
  4375. }
  4376. showToastMessage(message, hideAfter) {
  4377. this.instance.toastMessage.innerHTML = this.getToastMessageHTML(message);
  4378. if (hideAfter) {
  4379. setTimeout(() => {
  4380. this.clearToastMessage();
  4381. }, hideAfter * 1000);
  4382. }
  4383. }
  4384. clearToastMessage() {
  4385. this.instance.toastMessage.innerHTML = '';
  4386. }
  4387. getNoDataHTML() {
  4388. return `<div class="dt-scrollable__no-data">${this.options.noDataMessage}</div>`;
  4389. }
  4390. getToastMessageHTML(message) {
  4391. return `<span class="dt-toast__message">${message}</span>`;
  4392. }
  4393. }
  4394. class Style {
  4395. constructor(instance) {
  4396. this.instance = instance;
  4397. linkProperties(this, this.instance, [
  4398. 'options', 'datamanager', 'columnmanager',
  4399. 'header', 'footer', 'bodyScrollable', 'datatableWrapper',
  4400. 'getColumn', 'bodyRenderer'
  4401. ]);
  4402. this.scopeClass = 'dt-instance-' + instance.constructor.instances;
  4403. instance.datatableWrapper.classList.add(this.scopeClass);
  4404. const styleEl = document.createElement('style');
  4405. instance.wrapper.insertBefore(styleEl, instance.datatableWrapper);
  4406. this.styleEl = styleEl;
  4407. this.bindResizeWindow();
  4408. this.bindScrollHeader();
  4409. }
  4410. get stylesheet() {
  4411. return this.styleEl.sheet;
  4412. }
  4413. bindResizeWindow() {
  4414. this.onWindowResize = this.onWindowResize.bind(this);
  4415. this.onWindowResize = throttle$1(this.onWindowResize, 300);
  4416. if (this.options.layout === 'fluid') {
  4417. $.on(window, 'resize', this.onWindowResize);
  4418. }
  4419. }
  4420. bindScrollHeader() {
  4421. this._settingHeaderPosition = false;
  4422. $.on(this.bodyScrollable, 'scroll', (e) => {
  4423. if (this._settingHeaderPosition) return;
  4424. this._settingHeaderPosition = true;
  4425. requestAnimationFrame(() => {
  4426. const left = -e.target.scrollLeft;
  4427. $.style(this.header, {
  4428. transform: `translateX(${left}px)`
  4429. });
  4430. $.style(this.footer, {
  4431. transform: `translateX(${left}px)`
  4432. });
  4433. this._settingHeaderPosition = false;
  4434. });
  4435. });
  4436. }
  4437. onWindowResize() {
  4438. this.distributeRemainingWidth();
  4439. this.refreshColumnWidth();
  4440. this.setBodyStyle();
  4441. }
  4442. destroy() {
  4443. this.styleEl.remove();
  4444. $.off(window, 'resize', this.onWindowResize);
  4445. }
  4446. setStyle(selector, styleObject) {
  4447. if (selector.includes(',')) {
  4448. selector.split(',')
  4449. .map(s => s.trim())
  4450. .forEach(selector => {
  4451. this.setStyle(selector, styleObject);
  4452. });
  4453. return;
  4454. }
  4455. selector = selector.trim();
  4456. if (!selector) return;
  4457. this._styleRulesMap = this._styleRulesMap || {};
  4458. const prefixedSelector = this._getPrefixedSelector(selector);
  4459. if (this._styleRulesMap[prefixedSelector]) {
  4460. this.removeStyle(selector);
  4461. // merge with old styleobject
  4462. styleObject = Object.assign({}, this._styleRulesMap[prefixedSelector], styleObject);
  4463. }
  4464. const styleString = this._getRuleString(styleObject);
  4465. const ruleString = `${prefixedSelector} { ${styleString} }`;
  4466. this._styleRulesMap[prefixedSelector] = styleObject;
  4467. this.stylesheet.insertRule(ruleString);
  4468. }
  4469. removeStyle(selector) {
  4470. if (selector.includes(',')) {
  4471. selector.split(',')
  4472. .map(s => s.trim())
  4473. .forEach(selector => {
  4474. this.removeStyle(selector);
  4475. });
  4476. return;
  4477. }
  4478. selector = selector.trim();
  4479. if (!selector) return;
  4480. // find and remove
  4481. const prefixedSelector = this._getPrefixedSelector(selector);
  4482. const index = Array.from(this.stylesheet.cssRules)
  4483. .findIndex(rule => rule.selectorText === prefixedSelector);
  4484. if (index === -1) return;
  4485. this.stylesheet.deleteRule(index);
  4486. }
  4487. _getPrefixedSelector(selector) {
  4488. return `.${this.scopeClass} ${selector}`;
  4489. }
  4490. _getRuleString(styleObject) {
  4491. return Object.keys(styleObject)
  4492. .map(prop => {
  4493. let dashed = prop;
  4494. if (!prop.includes('-')) {
  4495. dashed = camelCaseToDash(prop);
  4496. }
  4497. return `${dashed}:${styleObject[prop]};`;
  4498. })
  4499. .join('');
  4500. }
  4501. setDimensions() {
  4502. this.setCellHeight();
  4503. this.setupMinWidth();
  4504. this.setupNaturalColumnWidth();
  4505. this.setupColumnWidth();
  4506. this.distributeRemainingWidth();
  4507. this.setColumnStyle();
  4508. this.setBodyStyle();
  4509. }
  4510. setCellHeight() {
  4511. this.setStyle('.dt-cell', {
  4512. height: this.options.cellHeight + 'px'
  4513. });
  4514. }
  4515. setupMinWidth() {
  4516. $.each('.dt-cell--header', this.header).map(col => {
  4517. const { colIndex } = $.data(col);
  4518. const column = this.getColumn(colIndex);
  4519. if (!column.minWidth) {
  4520. const width = $.style($('.dt-cell__content', col), 'width');
  4521. // only set this once
  4522. column.minWidth = width;
  4523. }
  4524. });
  4525. }
  4526. setupNaturalColumnWidth() {
  4527. if (!$('.dt-row')) return;
  4528. $.each('.dt-row-header .dt-cell', this.header).map($headerCell => {
  4529. const { colIndex } = $.data($headerCell);
  4530. const column = this.datamanager.getColumn(colIndex);
  4531. let width = $.style($('.dt-cell__content', $headerCell), 'width');
  4532. if (typeof width === 'number' && width >= this.options.minimumColumnWidth) {
  4533. column.naturalWidth = width;
  4534. } else {
  4535. column.naturalWidth = this.options.minimumColumnWidth;
  4536. }
  4537. });
  4538. // set initial width as naturally calculated by table's first row
  4539. $.each('.dt-row-0 .dt-cell', this.bodyScrollable).map($cell => {
  4540. const {
  4541. colIndex
  4542. } = $.data($cell);
  4543. const column = this.datamanager.getColumn(colIndex);
  4544. let naturalWidth = $.style($('.dt-cell__content', $cell), 'width');
  4545. if (typeof naturalWidth === 'number' && naturalWidth >= column.naturalWidth) {
  4546. column.naturalWidth = naturalWidth;
  4547. } else {
  4548. column.naturalWidth = column.naturalWidth;
  4549. }
  4550. });
  4551. }
  4552. setupColumnWidth() {
  4553. if (this.options.layout === 'ratio') {
  4554. let totalWidth = $.style(this.datatableWrapper, 'width');
  4555. if (this.options.serialNoColumn) {
  4556. const rowIndexColumn = this.datamanager.getColumnById('_rowIndex');
  4557. totalWidth = totalWidth - rowIndexColumn.width - 1;
  4558. }
  4559. if (this.options.checkboxColumn) {
  4560. const rowIndexColumn = this.datamanager.getColumnById('_checkbox');
  4561. totalWidth = totalWidth - rowIndexColumn.width - 1;
  4562. }
  4563. const totalParts = this.datamanager.getColumns()
  4564. .map(column => {
  4565. if (column.id === '_rowIndex' || column.id === '_checkbox') {
  4566. return 0;
  4567. }
  4568. if (!column.width) {
  4569. column.width = 1;
  4570. }
  4571. column.ratioWidth = parseInt(column.width, 10);
  4572. return column.ratioWidth;
  4573. })
  4574. .reduce((a, c) => a + c);
  4575. const onePart = totalWidth / totalParts;
  4576. this.datamanager.getColumns()
  4577. .map(column => {
  4578. if (column.id === '_rowIndex' || column.id === '_checkbox') return;
  4579. column.width = Math.floor(onePart * column.ratioWidth) - 1;
  4580. });
  4581. } else {
  4582. this.datamanager.getColumns()
  4583. .map(column => {
  4584. if (!column.width) {
  4585. column.width = column.naturalWidth;
  4586. }
  4587. if (column.id === '_rowIndex') {
  4588. column.width = this.getRowIndexColumnWidth();
  4589. }
  4590. if (column.width < this.options.minimumColumnWidth) {
  4591. column.width = this.options.minimumColumnWidth;
  4592. }
  4593. });
  4594. }
  4595. }
  4596. distributeRemainingWidth() {
  4597. if (this.options.layout !== 'fluid') return;
  4598. const wrapperWidth = $.style(this.instance.datatableWrapper, 'width');
  4599. let firstRow = $('.dt-row', this.bodyScrollable);
  4600. let firstRowWidth = wrapperWidth;
  4601. if (!firstRow) {
  4602. let headerRow = $('.dt-row', this.instance.header);
  4603. let cellWidths = Array.from(headerRow.children)
  4604. .map(cell => cell.offsetWidth);
  4605. firstRowWidth = cellWidths.reduce((sum, a) => sum + a, 0);
  4606. } else {
  4607. firstRowWidth = $.style(firstRow, 'width');
  4608. }
  4609. const resizableColumns = this.datamanager.getColumns().filter(col => col.resizable);
  4610. const deltaWidth = (wrapperWidth - firstRowWidth) / resizableColumns.length;
  4611. resizableColumns.map(col => {
  4612. const width = $.style(this.getColumnHeaderElement(col.colIndex), 'width');
  4613. let finalWidth = Math.floor(width + deltaWidth) - 2;
  4614. this.datamanager.updateColumn(col.colIndex, {
  4615. width: finalWidth
  4616. });
  4617. });
  4618. }
  4619. setColumnStyle() {
  4620. // align columns
  4621. this.datamanager.getColumns()
  4622. .map(column => {
  4623. // alignment
  4624. if (!column.align) {
  4625. column.align = 'left';
  4626. }
  4627. if (!['left', 'center', 'right'].includes(column.align)) {
  4628. column.align = 'left';
  4629. }
  4630. this.setStyle(`.dt-cell--col-${column.colIndex}`, {
  4631. 'text-align': column.align
  4632. });
  4633. // width
  4634. this.columnmanager.setColumnHeaderWidth(column.colIndex);
  4635. this.columnmanager.setColumnWidth(column.colIndex);
  4636. });
  4637. }
  4638. refreshColumnWidth() {
  4639. this.datamanager.getColumns()
  4640. .map(column => {
  4641. this.columnmanager.setColumnHeaderWidth(column.colIndex);
  4642. this.columnmanager.setColumnWidth(column.colIndex);
  4643. });
  4644. }
  4645. setBodyStyle() {
  4646. const bodyWidth = $.style(this.datatableWrapper, 'width');
  4647. const firstRow = $('.dt-row', this.bodyScrollable);
  4648. if (!firstRow) return;
  4649. const rowWidth = $.style(firstRow, 'width');
  4650. let width = bodyWidth > rowWidth ? rowWidth : bodyWidth;
  4651. $.style(this.bodyScrollable, {
  4652. width: width + 'px'
  4653. });
  4654. // remove the body height, so that it resets to it's original
  4655. $.removeStyle(this.bodyScrollable, 'height');
  4656. // when there are less rows than the container
  4657. // adapt the container height
  4658. let bodyHeight = $.getStyle(this.bodyScrollable, 'height');
  4659. const scrollHeight = (this.bodyRenderer.hyperlist || {})._scrollHeight || Infinity;
  4660. const hasHorizontalOverflow = $.hasHorizontalOverflow(this.bodyScrollable);
  4661. let height;
  4662. if (scrollHeight < bodyHeight) {
  4663. height = scrollHeight;
  4664. // account for scrollbar size when
  4665. // there is horizontal overflow
  4666. if (hasHorizontalOverflow) {
  4667. height += $.scrollbarSize();
  4668. }
  4669. $.style(this.bodyScrollable, {
  4670. height: height + 'px'
  4671. });
  4672. }
  4673. const verticalOverflow = this.bodyScrollable.scrollHeight - this.bodyScrollable.offsetHeight;
  4674. if (verticalOverflow < $.scrollbarSize()) {
  4675. // if verticalOverflow is less than scrollbar size
  4676. // then most likely scrollbar is causing the scroll
  4677. // which is not needed
  4678. $.style(this.bodyScrollable, {
  4679. overflowY: 'hidden'
  4680. });
  4681. }
  4682. if (this.options.layout === 'fluid') {
  4683. $.style(this.bodyScrollable, {
  4684. overflowX: 'hidden'
  4685. });
  4686. }
  4687. }
  4688. getColumnHeaderElement(colIndex) {
  4689. colIndex = +colIndex;
  4690. if (colIndex < 0) return null;
  4691. return $(`.dt-cell--col-${colIndex}`, this.header);
  4692. }
  4693. getRowIndexColumnWidth() {
  4694. const rowCount = this.datamanager.getRowCount();
  4695. const padding = 22;
  4696. return $.measureTextWidth(rowCount + '') + padding;
  4697. }
  4698. }
  4699. const KEYCODES = {
  4700. 13: 'enter',
  4701. 91: 'meta',
  4702. 16: 'shift',
  4703. 17: 'ctrl',
  4704. 18: 'alt',
  4705. 37: 'left',
  4706. 38: 'up',
  4707. 39: 'right',
  4708. 40: 'down',
  4709. 9: 'tab',
  4710. 27: 'esc',
  4711. 67: 'c',
  4712. 70: 'f',
  4713. 86: 'v'
  4714. };
  4715. class Keyboard {
  4716. constructor(element) {
  4717. this.listeners = {};
  4718. $.on(element, 'keydown', this.handler.bind(this));
  4719. }
  4720. handler(e) {
  4721. let key = KEYCODES[e.keyCode];
  4722. if (e.shiftKey && key !== 'shift') {
  4723. key = 'shift+' + key;
  4724. }
  4725. if ((e.ctrlKey && key !== 'ctrl') || (e.metaKey && key !== 'meta')) {
  4726. key = 'ctrl+' + key;
  4727. }
  4728. const listeners = this.listeners[key];
  4729. if (listeners && listeners.length > 0) {
  4730. for (let listener of listeners) {
  4731. const preventBubbling = listener(e);
  4732. if (preventBubbling === undefined || preventBubbling === true) {
  4733. e.preventDefault();
  4734. }
  4735. }
  4736. }
  4737. }
  4738. on(key, listener) {
  4739. const keys = key.split(',').map(k => k.trim());
  4740. keys.map(key => {
  4741. this.listeners[key] = this.listeners[key] || [];
  4742. this.listeners[key].push(listener);
  4743. });
  4744. }
  4745. }
  4746. var en = {
  4747. "Sort Ascending": "Sort Ascending",
  4748. "Sort Descending": "Sort Descending",
  4749. "Reset sorting": "Reset sorting",
  4750. "Remove column": "Remove column",
  4751. "No Data": "No Data",
  4752. "{count} cells copied": {"1":"{count} cell copied","default":"{count} cells copied"},
  4753. "{count} rows selected": {"1":"{count} row selected","default":"{count} rows selected"}
  4754. };
  4755. var de = {
  4756. "Sort Ascending": "Aufsteigend sortieren",
  4757. "Sort Descending": "Absteigend sortieren",
  4758. "Reset sorting": "Sortierung zurücksetzen",
  4759. "Remove column": "Spalte entfernen",
  4760. "No Data": "Keine Daten",
  4761. "{count} cells copied": {"1":"{count} Zelle kopiert","default":"{count} Zellen kopiert"},
  4762. "{count} rows selected": {"1":"{count} Zeile ausgewählt","default":"{count} Zeilen ausgewählt"}
  4763. };
  4764. var fr = {
  4765. "Sort Ascending": "Trier par ordre croissant",
  4766. "Sort Descending": "Trier par ordre décroissant",
  4767. "Reset sorting": "Réinitialiser le tri",
  4768. "Remove column": "Supprimer colonne",
  4769. "No Data": "Pas de données",
  4770. "{count} cells copied": {"1":"{count} cellule copiée","default":"{count} cellules copiées"},
  4771. "{count} rows selected": {"1":"{count} ligne sélectionnée","default":"{count} lignes sélectionnées"}
  4772. };
  4773. var it = {
  4774. "Sort Ascending": "Ordinamento ascendente",
  4775. "Sort Descending": "Ordinamento decrescente",
  4776. "Reset sorting": "Azzeramento ordinamento",
  4777. "Remove column": "Rimuovi colonna",
  4778. "No Data": "Nessun dato",
  4779. "{count} cells copied": {"1":"Copiato {count} cella","default":"{count} celle copiate"},
  4780. "{count} rows selected": {"1":"{count} linea selezionata","default":"{count} linee selezionate"}
  4781. };
  4782. function getTranslations() {
  4783. return {
  4784. en,
  4785. de,
  4786. fr,
  4787. it,
  4788. };
  4789. }
  4790. class TranslationManager {
  4791. constructor(language) {
  4792. this.language = language;
  4793. this.translations = getTranslations();
  4794. }
  4795. addTranslations(translations) {
  4796. this.translations = Object.assign(this.translations, translations);
  4797. }
  4798. translate(sourceText, args) {
  4799. let translation = (this.translations[this.language] &&
  4800. this.translations[this.language][sourceText]) || sourceText;
  4801. if (typeof translation === 'object') {
  4802. translation = args && args.count ?
  4803. this.getPluralizedTranslation(translation, args.count) :
  4804. sourceText;
  4805. }
  4806. return format(translation, args || {});
  4807. }
  4808. getPluralizedTranslation(translations, count) {
  4809. return translations[count] || translations['default'];
  4810. }
  4811. }
  4812. function filterRows(rows, filters) {
  4813. let filteredRowIndices = [];
  4814. if (Object.keys(filters).length === 0) {
  4815. return rows.map(row => row.meta.rowIndex);
  4816. }
  4817. for (let colIndex in filters) {
  4818. const keyword = filters[colIndex];
  4819. const filteredRows = filteredRowIndices.length ?
  4820. filteredRowIndices.map(i => rows[i]) :
  4821. rows;
  4822. const cells = filteredRows.map(row => row[colIndex]);
  4823. let filter = guessFilter(keyword);
  4824. let filterMethod = getFilterMethod(rows, filter);
  4825. if (filterMethod) {
  4826. filteredRowIndices = filterMethod(filter.text, cells);
  4827. } else {
  4828. filteredRowIndices = cells.map(cell => cell.rowIndex);
  4829. }
  4830. }
  4831. return filteredRowIndices;
  4832. }
  4833. function getFilterMethod(rows, filter) {
  4834. const getFormattedValue = cell => {
  4835. let formatter = CellManager.getCustomCellFormatter(cell);
  4836. if (formatter && cell.content) {
  4837. cell.html = formatter(cell.content, rows[cell.rowIndex], cell.column, rows[cell.rowIndex]);
  4838. return stripHTML(cell.html);
  4839. }
  4840. return cell.content || '';
  4841. };
  4842. const stringCompareValue = cell =>
  4843. String(stripHTML(cell.html || '') || getFormattedValue(cell)).toLowerCase();
  4844. const numberCompareValue = cell => parseFloat(cell.content);
  4845. const getCompareValues = (cell, keyword) => {
  4846. if (cell.column.compareValue) {
  4847. const compareValues = cell.column.compareValue(cell, keyword);
  4848. if (compareValues && Array.isArray(compareValues)) return compareValues;
  4849. }
  4850. // check if it can be converted to number
  4851. const float = numberCompareValue(cell);
  4852. if (!isNaN(float)) {
  4853. return [float, keyword];
  4854. }
  4855. return [stringCompareValue(cell), keyword];
  4856. };
  4857. let filterMethodMap = {
  4858. contains(keyword, cells) {
  4859. return cells
  4860. .filter(cell => {
  4861. const hay = stringCompareValue(cell);
  4862. const needle = (keyword || '').toLowerCase();
  4863. return !needle || hay.includes(needle);
  4864. })
  4865. .map(cell => cell.rowIndex);
  4866. },
  4867. greaterThan(keyword, cells) {
  4868. return cells
  4869. .filter(cell => {
  4870. const [compareValue, keywordValue] = getCompareValues(cell, keyword);
  4871. return compareValue > keywordValue;
  4872. })
  4873. .map(cell => cell.rowIndex);
  4874. },
  4875. lessThan(keyword, cells) {
  4876. return cells
  4877. .filter(cell => {
  4878. const [compareValue, keywordValue] = getCompareValues(cell, keyword);
  4879. return compareValue < keywordValue;
  4880. })
  4881. .map(cell => cell.rowIndex);
  4882. },
  4883. equals(keyword, cells) {
  4884. return cells
  4885. .filter(cell => {
  4886. const value = parseFloat(cell.content);
  4887. return value === keyword;
  4888. })
  4889. .map(cell => cell.rowIndex);
  4890. },
  4891. notEquals(keyword, cells) {
  4892. return cells
  4893. .filter(cell => {
  4894. const value = parseFloat(cell.content);
  4895. return value !== keyword;
  4896. })
  4897. .map(cell => cell.rowIndex);
  4898. },
  4899. range(rangeValues, cells) {
  4900. return cells
  4901. .filter(cell => {
  4902. const values1 = getCompareValues(cell, rangeValues[0]);
  4903. const values2 = getCompareValues(cell, rangeValues[1]);
  4904. const value = values1[0];
  4905. return value >= values1[1] && value <= values2[1];
  4906. })
  4907. .map(cell => cell.rowIndex);
  4908. },
  4909. containsNumber(keyword, cells) {
  4910. return cells
  4911. .filter(cell => {
  4912. let number = parseFloat(keyword, 10);
  4913. let string = keyword;
  4914. let hayNumber = numberCompareValue(cell);
  4915. let hayString = stringCompareValue(cell);
  4916. return number === hayNumber || hayString.includes(string);
  4917. })
  4918. .map(cell => cell.rowIndex);
  4919. }
  4920. };
  4921. return filterMethodMap[filter.type];
  4922. }
  4923. function guessFilter(keyword = '') {
  4924. if (keyword.length === 0) return {};
  4925. let compareString = keyword;
  4926. if (['>', '<', '='].includes(compareString[0])) {
  4927. compareString = keyword.slice(1);
  4928. } else if (compareString.startsWith('!=')) {
  4929. compareString = keyword.slice(2);
  4930. }
  4931. if (keyword.startsWith('>')) {
  4932. if (compareString) {
  4933. return {
  4934. type: 'greaterThan',
  4935. text: compareString.trim()
  4936. };
  4937. }
  4938. }
  4939. if (keyword.startsWith('<')) {
  4940. if (compareString) {
  4941. return {
  4942. type: 'lessThan',
  4943. text: compareString.trim()
  4944. };
  4945. }
  4946. }
  4947. if (keyword.startsWith('=')) {
  4948. if (isNumber(compareString)) {
  4949. return {
  4950. type: 'equals',
  4951. text: Number(keyword.slice(1).trim())
  4952. };
  4953. }
  4954. }
  4955. if (isNumber(compareString)) {
  4956. return {
  4957. type: 'containsNumber',
  4958. text: compareString
  4959. };
  4960. }
  4961. if (keyword.startsWith('!=')) {
  4962. if (isNumber(compareString)) {
  4963. return {
  4964. type: 'notEquals',
  4965. text: Number(keyword.slice(2).trim())
  4966. };
  4967. }
  4968. }
  4969. if (keyword.split(':').length === 2) {
  4970. compareString = keyword.split(':');
  4971. return {
  4972. type: 'range',
  4973. text: compareString.map(v => v.trim())
  4974. };
  4975. }
  4976. return {
  4977. type: 'contains',
  4978. text: compareString.toLowerCase()
  4979. };
  4980. }
  4981. function getDefaultOptions(instance) {
  4982. return {
  4983. columns: [],
  4984. data: [],
  4985. dropdownButton: icons.chevronDown,
  4986. headerDropdown: [
  4987. {
  4988. label: instance.translate('Sort Ascending'),
  4989. action: function (column) {
  4990. this.sortColumn(column.colIndex, 'asc');
  4991. }
  4992. },
  4993. {
  4994. label: instance.translate('Sort Descending'),
  4995. action: function (column) {
  4996. this.sortColumn(column.colIndex, 'desc');
  4997. }
  4998. },
  4999. {
  5000. label: instance.translate('Reset sorting'),
  5001. action: function (column) {
  5002. this.sortColumn(column.colIndex, 'none');
  5003. }
  5004. },
  5005. {
  5006. label: instance.translate('Remove column'),
  5007. action: function (column) {
  5008. this.removeColumn(column.colIndex);
  5009. }
  5010. }
  5011. ],
  5012. events: {
  5013. onRemoveColumn(column) {},
  5014. onSwitchColumn(column1, column2) {},
  5015. onSortColumn(column) {},
  5016. onCheckRow(row) {},
  5017. onDestroy() {}
  5018. },
  5019. hooks: {
  5020. columnTotal: null
  5021. },
  5022. sortIndicator: {
  5023. asc: '↑',
  5024. desc: '↓',
  5025. none: ''
  5026. },
  5027. overrideComponents: {
  5028. // ColumnManager: CustomColumnManager
  5029. },
  5030. filterRows: filterRows,
  5031. freezeMessage: '',
  5032. getEditor: null,
  5033. serialNoColumn: true,
  5034. checkboxColumn: false,
  5035. clusterize: true,
  5036. logs: false,
  5037. layout: 'fixed', // fixed, fluid, ratio
  5038. noDataMessage: instance.translate('No Data'),
  5039. cellHeight: 40,
  5040. minimumColumnWidth: 30,
  5041. inlineFilters: false,
  5042. treeView: false,
  5043. checkedRowStatus: true,
  5044. dynamicRowHeight: false,
  5045. pasteFromClipboard: false,
  5046. showTotalRow: false,
  5047. direction: 'ltr',
  5048. disableReorderColumn: false
  5049. };
  5050. }
  5051. let defaultComponents = {
  5052. DataManager,
  5053. CellManager,
  5054. ColumnManager,
  5055. RowManager,
  5056. BodyRenderer,
  5057. Style,
  5058. Keyboard
  5059. };
  5060. class DataTable {
  5061. constructor(wrapper, options) {
  5062. DataTable.instances++;
  5063. if (typeof wrapper === 'string') {
  5064. // css selector
  5065. wrapper = document.querySelector(wrapper);
  5066. }
  5067. this.wrapper = wrapper;
  5068. if (!(this.wrapper instanceof HTMLElement)) {
  5069. throw new Error('Invalid argument given for `wrapper`');
  5070. }
  5071. this.initializeTranslations(options);
  5072. this.setDefaultOptions();
  5073. this.buildOptions(options);
  5074. this.prepare();
  5075. this.initializeComponents();
  5076. if (this.options.data) {
  5077. this.refresh();
  5078. this.columnmanager.applyDefaultSortOrder();
  5079. }
  5080. }
  5081. initializeTranslations(options) {
  5082. this.language = options.language || 'en';
  5083. this.translationManager = new TranslationManager(this.language);
  5084. if (options.translations) {
  5085. this.translationManager.addTranslations(options.translations);
  5086. }
  5087. }
  5088. setDefaultOptions() {
  5089. this.DEFAULT_OPTIONS = getDefaultOptions(this);
  5090. }
  5091. buildOptions(options) {
  5092. this.options = this.options || {};
  5093. this.options = Object.assign(
  5094. {}, this.DEFAULT_OPTIONS,
  5095. this.options || {}, options
  5096. );
  5097. options.headerDropdown = options.headerDropdown || [];
  5098. this.options.headerDropdown = [
  5099. ...this.DEFAULT_OPTIONS.headerDropdown,
  5100. ...options.headerDropdown
  5101. ];
  5102. // custom user events
  5103. this.events = Object.assign(
  5104. {}, this.DEFAULT_OPTIONS.events,
  5105. this.options.events || {},
  5106. options.events || {}
  5107. );
  5108. this.fireEvent = this.fireEvent.bind(this);
  5109. }
  5110. prepare() {
  5111. this.prepareDom();
  5112. this.unfreeze();
  5113. }
  5114. initializeComponents() {
  5115. let components = Object.assign({}, defaultComponents, this.options.overrideComponents);
  5116. let {
  5117. Style: Style$$1,
  5118. Keyboard: Keyboard$$1,
  5119. DataManager: DataManager$$1,
  5120. RowManager: RowManager$$1,
  5121. ColumnManager: ColumnManager$$1,
  5122. CellManager: CellManager$$1,
  5123. BodyRenderer: BodyRenderer$$1
  5124. } = components;
  5125. this.style = new Style$$1(this);
  5126. this.keyboard = new Keyboard$$1(this.wrapper);
  5127. this.datamanager = new DataManager$$1(this.options);
  5128. this.rowmanager = new RowManager$$1(this);
  5129. this.columnmanager = new ColumnManager$$1(this);
  5130. this.cellmanager = new CellManager$$1(this);
  5131. this.bodyRenderer = new BodyRenderer$$1(this);
  5132. }
  5133. prepareDom() {
  5134. this.wrapper.innerHTML = `
  5135. <div class="datatable" dir="${this.options.direction}">
  5136. <div class="dt-header"></div>
  5137. <div class="dt-scrollable"></div>
  5138. <div class="dt-footer"></div>
  5139. <div class="dt-freeze">
  5140. <span class="dt-freeze__message">
  5141. ${this.options.freezeMessage}
  5142. </span>
  5143. </div>
  5144. <div class="dt-toast"></div>
  5145. <div class="dt-dropdown-container"></div>
  5146. <textarea class="dt-paste-target"></textarea>
  5147. </div>
  5148. `;
  5149. this.datatableWrapper = $('.datatable', this.wrapper);
  5150. this.header = $('.dt-header', this.wrapper);
  5151. this.footer = $('.dt-footer', this.wrapper);
  5152. this.bodyScrollable = $('.dt-scrollable', this.wrapper);
  5153. this.freezeContainer = $('.dt-freeze', this.wrapper);
  5154. this.toastMessage = $('.dt-toast', this.wrapper);
  5155. this.pasteTarget = $('.dt-paste-target', this.wrapper);
  5156. this.dropdownContainer = $('.dt-dropdown-container', this.wrapper);
  5157. }
  5158. refresh(data, columns) {
  5159. this.datamanager.init(data, columns);
  5160. this.render();
  5161. this.setDimensions();
  5162. }
  5163. destroy() {
  5164. this.wrapper.innerHTML = '';
  5165. this.style.destroy();
  5166. this.fireEvent('onDestroy');
  5167. }
  5168. appendRows(rows) {
  5169. this.datamanager.appendRows(rows);
  5170. this.rowmanager.refreshRows();
  5171. }
  5172. refreshRow(row, rowIndex) {
  5173. this.rowmanager.refreshRow(row, rowIndex);
  5174. }
  5175. render() {
  5176. this.renderHeader();
  5177. this.renderBody();
  5178. }
  5179. renderHeader() {
  5180. this.columnmanager.renderHeader();
  5181. }
  5182. renderBody() {
  5183. this.bodyRenderer.render();
  5184. }
  5185. setDimensions() {
  5186. this.style.setDimensions();
  5187. }
  5188. showToastMessage(message, hideAfter) {
  5189. this.bodyRenderer.showToastMessage(message, hideAfter);
  5190. }
  5191. clearToastMessage() {
  5192. this.bodyRenderer.clearToastMessage();
  5193. }
  5194. getColumn(colIndex) {
  5195. return this.datamanager.getColumn(colIndex);
  5196. }
  5197. getColumns() {
  5198. return this.datamanager.getColumns();
  5199. }
  5200. getRows() {
  5201. return this.datamanager.getRows();
  5202. }
  5203. getCell(colIndex, rowIndex) {
  5204. return this.datamanager.getCell(colIndex, rowIndex);
  5205. }
  5206. getColumnHeaderElement(colIndex) {
  5207. return this.columnmanager.getColumnHeaderElement(colIndex);
  5208. }
  5209. getViewportHeight() {
  5210. if (!this.viewportHeight) {
  5211. this.viewportHeight = $.style(this.bodyScrollable, 'height');
  5212. }
  5213. return this.viewportHeight;
  5214. }
  5215. sortColumn(colIndex, sortOrder) {
  5216. this.columnmanager.sortColumn(colIndex, sortOrder);
  5217. }
  5218. removeColumn(colIndex) {
  5219. this.columnmanager.removeColumn(colIndex);
  5220. }
  5221. scrollToLastColumn() {
  5222. this.datatableWrapper.scrollLeft = 9999;
  5223. }
  5224. freeze() {
  5225. $.style(this.freezeContainer, {
  5226. display: ''
  5227. });
  5228. }
  5229. unfreeze() {
  5230. $.style(this.freezeContainer, {
  5231. display: 'none'
  5232. });
  5233. }
  5234. updateOptions(options) {
  5235. this.buildOptions(options);
  5236. }
  5237. fireEvent(eventName, ...args) {
  5238. // fire internalEventHandlers if any
  5239. // and then user events
  5240. const handlers = [
  5241. ...(this._internalEventHandlers[eventName] || []),
  5242. this.events[eventName]
  5243. ].filter(Boolean);
  5244. for (let handler of handlers) {
  5245. handler.apply(this, args);
  5246. }
  5247. }
  5248. on(event, handler) {
  5249. this._internalEventHandlers = this._internalEventHandlers || {};
  5250. this._internalEventHandlers[event] = this._internalEventHandlers[event] || [];
  5251. this._internalEventHandlers[event].push(handler);
  5252. }
  5253. log() {
  5254. if (this.options.logs) {
  5255. console.log.apply(console, arguments);
  5256. }
  5257. }
  5258. translate(str, args) {
  5259. return this.translationManager.translate(str, args);
  5260. }
  5261. }
  5262. DataTable.instances = 0;
  5263. var name = "influxframework-datatable";
  5264. var version = "0.0.0-development";
  5265. var description = "A modern datatable library for the web";
  5266. var main = "dist/influxframework-datatable.cjs.js";
  5267. var unpkg = "dist/influxframework-datatable.min.js";
  5268. var jsdelivr = "dist/influxframework-datatable.min.js";
  5269. var scripts = {"start":"yarn run dev","build":"rollup -c && NODE_ENV=production rollup -c","dev":"rollup -c -w","cy:server":"http-server -p 8989","cy:open":"cypress open","cy:run":"cypress run","test":"start-server-and-test cy:server http://localhost:8989 cy:run","test-local":"start-server-and-test cy:server http://localhost:8989 cy:open","travis-deploy-once":"travis-deploy-once","semantic-release":"semantic-release","lint":"eslint src","lint-and-build":"yarn lint && yarn build","commit":"npx git-cz"};
  5270. var files = ["dist","src"];
  5271. var devDependencies = {"autoprefixer":"^9.0.0","chai":"3.5.0","cypress":"^9.2.0","cz-conventional-changelog":"^2.1.0","deepmerge":"^2.0.1","eslint":"^5.0.1","eslint-config-airbnb":"^16.1.0","eslint-config-airbnb-base":"^12.1.0","eslint-plugin-import":"^2.11.0","http-server":"^0.11.1","mocha":"3.3.0","postcss-custom-properties":"^7.0.0","postcss-nested":"^3.0.0","rollup":"^0.59.4","rollup-plugin-commonjs":"^8.3.0","rollup-plugin-eslint":"^4.0.0","rollup-plugin-json":"^2.3.0","rollup-plugin-node-resolve":"^3.0.3","rollup-plugin-postcss":"^1.2.8","rollup-plugin-uglify-es":"^0.0.1","semantic-release":"^17.1.1","start-server-and-test":"^1.4.1","travis-deploy-once":"^5.0.1"};
  5272. var repository = {"type":"git","url":"https://github.com/influxframework/datatable.git"};
  5273. var keywords = ["datatable","data","grid","table"];
  5274. var author = "Faris Ansari";
  5275. var license = "MIT";
  5276. var bugs = {"url":"https://github.com/influxframework/datatable/issues"};
  5277. var homepage = "https://influxframework.com/datatable";
  5278. var dependencies = {"hyperlist":"^1.0.0-beta","lodash":"^4.17.5","sortablejs":"^1.7.0"};
  5279. var config = {"commitizen":{"path":"cz-conventional-changelog"}};
  5280. var packageJson = {
  5281. name: name,
  5282. version: version,
  5283. description: description,
  5284. main: main,
  5285. unpkg: unpkg,
  5286. jsdelivr: jsdelivr,
  5287. scripts: scripts,
  5288. files: files,
  5289. devDependencies: devDependencies,
  5290. repository: repository,
  5291. keywords: keywords,
  5292. author: author,
  5293. license: license,
  5294. bugs: bugs,
  5295. homepage: homepage,
  5296. dependencies: dependencies,
  5297. config: config
  5298. };
  5299. DataTable.__version__ = packageJson.version;
  5300. return DataTable;
  5301. }(Sortable));