Licitator 1.0
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.

1545 lines
76 KiB

5 years ago
  1. /**
  2. * ItemHold plugin
  3. *
  4. * @copyright Rafal Pospiech <https://neuronet.io>
  5. * @author Rafal Pospiech <neuronet.io@gmail.com>
  6. * @package gantt-schedule-timeline-calendar
  7. * @license AGPL-3.0 (https://github.com/neuronetio/gantt-schedule-timeline-calendar/blob/master/LICENSE)
  8. * @link https://github.com/neuronetio/gantt-schedule-timeline-calendar
  9. */
  10. function ItemHold(options = {}) {
  11. let api;
  12. const defaultOptions = {
  13. time: 1000,
  14. movementThreshold: 2,
  15. action(element, data) { }
  16. };
  17. options = Object.assign(Object.assign({}, defaultOptions), options);
  18. const holding = {};
  19. const pointer = { x: 0, y: 0 };
  20. function onPointerDown(item, element, event) {
  21. if (typeof holding[item.id] === 'undefined') {
  22. const normalized = api.normalizePointerEvent(event);
  23. holding[item.id] = { x: normalized.x, y: normalized.y };
  24. event.stopPropagation();
  25. event.preventDefault();
  26. setTimeout(() => {
  27. if (typeof holding[item.id] !== 'undefined') {
  28. let exec = true;
  29. const xMovement = Math.abs(holding[item.id].x - pointer.x);
  30. const yMovement = Math.abs(holding[item.id].y - pointer.y);
  31. if (xMovement > options.movementThreshold) {
  32. exec = false;
  33. }
  34. if (yMovement > options.movementThreshold) {
  35. exec = false;
  36. }
  37. delete holding[item.id];
  38. if (exec) {
  39. options.action(element, item);
  40. }
  41. }
  42. }, options.time);
  43. }
  44. }
  45. function onPointerUp(itemId) {
  46. if (typeof holding[itemId] !== 'undefined') {
  47. delete holding[itemId];
  48. }
  49. }
  50. function action(element, data) {
  51. function elementPointerDown(event) {
  52. onPointerDown(data.item, element, event);
  53. }
  54. element.addEventListener('mousedown', elementPointerDown);
  55. element.addEventListener('touchstart', elementPointerDown);
  56. function pointerUp() {
  57. onPointerUp(data.item.id);
  58. }
  59. document.addEventListener('mouseup', pointerUp);
  60. document.addEventListener('touchend', pointerUp);
  61. function onPointerMove(event) {
  62. const normalized = api.normalizePointerEvent(event);
  63. pointer.x = normalized.x;
  64. pointer.y = normalized.y;
  65. }
  66. document.addEventListener('mousemove', onPointerMove);
  67. document.addEventListener('touchmove', onPointerMove);
  68. return {
  69. update(element, changedData) {
  70. data = changedData;
  71. },
  72. destroy(element, data) {
  73. document.removeEventListener('mouseup', onPointerUp);
  74. document.removeEventListener('mousemove', onPointerMove);
  75. element.removeEventListener('mousedown', elementPointerDown);
  76. document.removeEventListener('touchend', onPointerUp);
  77. document.removeEventListener('touchmove', onPointerMove);
  78. element.removeEventListener('touchstart', elementPointerDown);
  79. }
  80. };
  81. }
  82. return function initialize(vido) {
  83. api = vido.api;
  84. vido.state.update('config.actions.chart-timeline-items-row-item', actions => {
  85. actions.push(action);
  86. return actions;
  87. });
  88. };
  89. }
  90. /**
  91. * ItemMovement plugin
  92. *
  93. * @copyright Rafal Pospiech <https://neuronet.io>
  94. * @author Rafal Pospiech <neuronet.io@gmail.com>
  95. * @package gantt-schedule-timeline-calendar
  96. * @license AGPL-3.0 (https://github.com/neuronetio/gantt-schedule-timeline-calendar/blob/master/LICENSE)
  97. * @link https://github.com/neuronetio/gantt-schedule-timeline-calendar
  98. */
  99. const pointerEventsExists = typeof PointerEvent !== 'undefined';
  100. function ItemMovement(options = {}) {
  101. const defaultOptions = {
  102. moveable: true,
  103. resizable: true,
  104. resizerContent: '',
  105. collisionDetection: true,
  106. outOfBorders: false,
  107. snapStart(timeStart, startDiff) {
  108. return timeStart + startDiff;
  109. },
  110. snapEnd(timeEnd, endDiff) {
  111. return timeEnd + endDiff;
  112. },
  113. ghostNode: true,
  114. wait: 0
  115. };
  116. options = Object.assign(Object.assign({}, defaultOptions), options);
  117. const movementState = {};
  118. /**
  119. * Add moving functionality to items as action
  120. *
  121. * @param {HTMLElement} element DOM Node
  122. * @param {Object} data
  123. */
  124. function ItemAction(element, data) {
  125. if (!options.moveable && !options.resizable) {
  126. return;
  127. }
  128. const state = data.state;
  129. const api = data.api;
  130. function isMoveable(data) {
  131. let moveable = options.moveable;
  132. if (data.item.hasOwnProperty('moveable') && moveable) {
  133. moveable = data.item.moveable;
  134. }
  135. if (data.row.hasOwnProperty('moveable') && moveable) {
  136. moveable = data.row.moveable;
  137. }
  138. return moveable;
  139. }
  140. function isResizable(data) {
  141. let resizable = options.resizable && (!data.item.hasOwnProperty('resizable') || data.item.resizable === true);
  142. if (data.row.hasOwnProperty('resizable') && resizable) {
  143. resizable = data.row.resizable;
  144. }
  145. return resizable;
  146. }
  147. function getMovement(data) {
  148. const itemId = data.item.id;
  149. if (typeof movementState[itemId] === 'undefined') {
  150. movementState[itemId] = { moving: false, resizing: false, waiting: false };
  151. }
  152. return movementState[itemId];
  153. }
  154. function saveMovement(itemId, movement) {
  155. state.update(`config.plugin.ItemMovement.item`, Object.assign({ id: itemId }, movement));
  156. state.update('config.plugin.ItemMovement.movement', (current) => {
  157. if (!current) {
  158. current = { moving: false, waiting: false, resizing: false };
  159. }
  160. current.moving = movement.moving;
  161. current.waiting = movement.waiting;
  162. current.resizing = movement.resizing;
  163. return current;
  164. });
  165. }
  166. function createGhost(data, normalized, ganttLeft, ganttTop) {
  167. const movement = getMovement(data);
  168. if (!options.ghostNode || typeof movement.ghost !== 'undefined') {
  169. return;
  170. }
  171. const ghost = element.cloneNode(true);
  172. const style = getComputedStyle(element);
  173. const compensationY = state.get('config.scroll.compensation.y');
  174. ghost.style.position = 'absolute';
  175. ghost.style.left = normalized.clientX - ganttLeft - movement.itemLeftCompensation + 'px';
  176. const itemTop = normalized.clientY - ganttTop - element.offsetTop - compensationY + parseInt(style['margin-top']);
  177. movement.itemTop = itemTop;
  178. ghost.style.top = normalized.clientY - ganttTop - itemTop + 'px';
  179. ghost.style.width = style.width;
  180. ghost.style['box-shadow'] = '10px 10px 6px #00000020';
  181. const height = element.clientHeight + 'px';
  182. ghost.style.height = height;
  183. ghost.style['line-height'] = element.clientHeight - 18 + 'px';
  184. ghost.style.opacity = '0.6';
  185. ghost.style.transform = 'scale(1.05, 1.05)';
  186. state.get('_internal.elements.chart-timeline').appendChild(ghost);
  187. movement.ghost = ghost;
  188. saveMovement(data.item.id, movement);
  189. return ghost;
  190. }
  191. function moveGhost(data, normalized) {
  192. if (options.ghostNode) {
  193. const movement = getMovement(data);
  194. const left = normalized.clientX - movement.ganttLeft - movement.itemLeftCompensation;
  195. movement.ghost.style.left = left + 'px';
  196. movement.ghost.style.top =
  197. normalized.clientY -
  198. movement.ganttTop -
  199. movement.itemTop +
  200. parseInt(getComputedStyle(element)['margin-top']) +
  201. 'px';
  202. saveMovement(data.item.id, movement);
  203. }
  204. }
  205. function destroyGhost(itemId) {
  206. if (!options.ghostNode) {
  207. return;
  208. }
  209. if (typeof movementState[itemId] !== 'undefined' && typeof movementState[itemId].ghost !== 'undefined') {
  210. state.get('_internal.elements.chart-timeline').removeChild(movementState[itemId].ghost);
  211. delete movementState[itemId].ghost;
  212. saveMovement(data.item.id, movementState[itemId]);
  213. }
  214. }
  215. function getSnapStart(data) {
  216. let snapStart = options.snapStart;
  217. if (typeof data.item.snapStart === 'function') {
  218. snapStart = data.item.snapStart;
  219. }
  220. return snapStart;
  221. }
  222. function getSnapEnd(data) {
  223. let snapEnd = options.snapEnd;
  224. if (typeof data.item.snapEnd === 'function') {
  225. snapEnd = data.item.snapEnd;
  226. }
  227. return snapEnd;
  228. }
  229. const resizerHTML = `<div class="${api.getClass('chart-timeline-items-row-item-resizer')}">${options.resizerContent}</div>`;
  230. // @ts-ignore
  231. element.insertAdjacentHTML('beforeend', resizerHTML);
  232. const resizerEl = element.querySelector('.gantt-schedule-timeline-calendar__chart-timeline-items-row-item-resizer');
  233. if (!isResizable(data)) {
  234. resizerEl.style.visibility = 'hidden';
  235. }
  236. else {
  237. resizerEl.style.visibility = 'visible';
  238. }
  239. function labelDown(ev) {
  240. const normalized = api.normalizePointerEvent(ev);
  241. if ((ev.type === 'pointerdown' || ev.type === 'mousedown') && ev.button !== 0) {
  242. return;
  243. }
  244. const movement = getMovement(data);
  245. movement.waiting = true;
  246. saveMovement(data.item.id, movement);
  247. setTimeout(() => {
  248. ev.stopPropagation();
  249. ev.preventDefault();
  250. if (!movement.waiting)
  251. return;
  252. movement.moving = true;
  253. const item = state.get(`config.chart.items.${data.item.id}`);
  254. const chartLeftTime = state.get('_internal.chart.time.leftGlobal');
  255. const timePerPixel = state.get('_internal.chart.time.timePerPixel');
  256. const ganttRect = state.get('_internal.elements.chart-timeline').getBoundingClientRect();
  257. movement.ganttTop = ganttRect.top;
  258. movement.ganttLeft = ganttRect.left;
  259. movement.itemX = Math.round((item.time.start - chartLeftTime) / timePerPixel);
  260. movement.itemLeftCompensation = normalized.clientX - movement.ganttLeft - movement.itemX;
  261. saveMovement(data.item.id, movement);
  262. createGhost(data, normalized, ganttRect.left, ganttRect.top);
  263. }, options.wait);
  264. }
  265. function resizerDown(ev) {
  266. ev.stopPropagation();
  267. ev.preventDefault();
  268. if ((ev.type === 'pointerdown' || ev.type === 'mousedown') && ev.button !== 0) {
  269. return;
  270. }
  271. const normalized = api.normalizePointerEvent(ev);
  272. const movement = getMovement(data);
  273. movement.resizing = true;
  274. const item = state.get(`config.chart.items.${data.item.id}`);
  275. const chartLeftTime = state.get('_internal.chart.time.leftGlobal');
  276. const timePerPixel = state.get('_internal.chart.time.timePerPixel');
  277. const ganttRect = state.get('_internal.elements.chart-timeline').getBoundingClientRect();
  278. movement.ganttTop = ganttRect.top;
  279. movement.ganttLeft = ganttRect.left;
  280. movement.itemX = (item.time.end - chartLeftTime) / timePerPixel;
  281. movement.itemLeftCompensation = normalized.clientX - movement.ganttLeft - movement.itemX;
  282. saveMovement(data.item.id, movement);
  283. }
  284. function isCollision(rowId, itemId, start, end) {
  285. if (!options.collisionDetection) {
  286. return false;
  287. }
  288. const time = state.get('_internal.chart.time');
  289. if (options.outOfBorders && (start < time.from || end > time.to)) {
  290. return true;
  291. }
  292. let diff = api.time.date(end).diff(start, 'milliseconds');
  293. if (Math.sign(diff) === -1) {
  294. diff = -diff;
  295. }
  296. if (diff <= 1) {
  297. return true;
  298. }
  299. const row = state.get('config.list.rows.' + rowId);
  300. for (const rowItem of row._internal.items) {
  301. if (rowItem.id !== itemId) {
  302. if (start >= rowItem.time.start && start <= rowItem.time.end) {
  303. return true;
  304. }
  305. if (end >= rowItem.time.start && end <= rowItem.time.end) {
  306. return true;
  307. }
  308. if (start <= rowItem.time.start && end >= rowItem.time.end) {
  309. return true;
  310. }
  311. }
  312. }
  313. return false;
  314. }
  315. function movementX(normalized, row, item, zoom, timePerPixel) {
  316. const movement = getMovement(data);
  317. const left = normalized.clientX - movement.ganttLeft - movement.itemLeftCompensation;
  318. moveGhost(data, normalized);
  319. const leftMs = state.get('_internal.chart.time.leftGlobal') + left * timePerPixel;
  320. const add = leftMs - item.time.start;
  321. const originalStart = item.time.start;
  322. const finalStartTime = getSnapStart(data)(item.time.start, add, item);
  323. const finalAdd = finalStartTime - originalStart;
  324. const collision = isCollision(row.id, item.id, item.time.start + finalAdd, item.time.end + finalAdd);
  325. if (finalAdd && !collision) {
  326. state.update(`config.chart.items.${data.item.id}.time`, function moveItem(time) {
  327. time.start += finalAdd;
  328. time.end = getSnapEnd(data)(time.end, finalAdd, item) - 1;
  329. return time;
  330. });
  331. }
  332. }
  333. function resizeX(normalized, row, item, zoom, timePerPixel) {
  334. if (!isResizable(data)) {
  335. return;
  336. }
  337. const time = state.get('_internal.chart.time');
  338. const movement = getMovement(data);
  339. const left = normalized.clientX - movement.ganttLeft - movement.itemLeftCompensation;
  340. const leftMs = time.leftGlobal + left * timePerPixel;
  341. const add = leftMs - item.time.end;
  342. if (item.time.end + add < item.time.start) {
  343. return;
  344. }
  345. const originalEnd = item.time.end;
  346. const finalEndTime = getSnapEnd(data)(item.time.end, add, item) - 1;
  347. const finalAdd = finalEndTime - originalEnd;
  348. const collision = isCollision(row.id, item.id, item.time.start, item.time.end + finalAdd);
  349. if (finalAdd && !collision) {
  350. state.update(`config.chart.items.${data.item.id}.time`, time => {
  351. time.start = getSnapStart(data)(time.start, 0, item);
  352. time.end = getSnapEnd(data)(time.end, finalAdd, item) - 1;
  353. return time;
  354. });
  355. }
  356. }
  357. function movementY(normalized, row, item, zoom, timePerPixel) {
  358. moveGhost(data, normalized);
  359. const movement = getMovement(data);
  360. const top = normalized.clientY - movement.ganttTop;
  361. const visibleRows = state.get('_internal.list.visibleRows');
  362. const compensationY = state.get('config.scroll.compensation.y');
  363. let index = 0;
  364. for (const currentRow of visibleRows) {
  365. if (currentRow.top + compensationY > top) {
  366. if (index > 0) {
  367. return index - 1;
  368. }
  369. return 0;
  370. }
  371. index++;
  372. }
  373. return index;
  374. }
  375. function documentMove(ev) {
  376. const movement = getMovement(data);
  377. const normalized = api.normalizePointerEvent(ev);
  378. let item, rowId, row, zoom, timePerPixel;
  379. if (movement.moving || movement.resizing) {
  380. ev.stopPropagation();
  381. ev.preventDefault();
  382. item = state.get(`config.chart.items.${data.item.id}`);
  383. rowId = state.get(`config.chart.items.${data.item.id}.rowId`);
  384. row = state.get(`config.list.rows.${rowId}`);
  385. zoom = state.get('_internal.chart.time.zoom');
  386. timePerPixel = state.get('_internal.chart.time.timePerPixel');
  387. }
  388. const moveable = isMoveable(data);
  389. if (movement.moving) {
  390. if (moveable === true || moveable === 'x' || (Array.isArray(moveable) && moveable.includes(rowId))) {
  391. movementX(normalized, row, item, zoom, timePerPixel);
  392. }
  393. if (!moveable || moveable === 'x') {
  394. return;
  395. }
  396. let visibleRowsIndex = movementY(normalized);
  397. const visibleRows = state.get('_internal.list.visibleRows');
  398. if (typeof visibleRows[visibleRowsIndex] === 'undefined') {
  399. if (visibleRowsIndex > 0) {
  400. visibleRowsIndex = visibleRows.length - 1;
  401. }
  402. else if (visibleRowsIndex < 0) {
  403. visibleRowsIndex = 0;
  404. }
  405. }
  406. const newRow = visibleRows[visibleRowsIndex];
  407. const newRowId = newRow.id;
  408. const collision = isCollision(newRowId, item.id, item.time.start, item.time.end);
  409. if (newRowId !== item.rowId && !collision) {
  410. if (!Array.isArray(moveable) || moveable.includes(newRowId)) {
  411. if (!newRow.hasOwnProperty('moveable') || newRow.moveable) {
  412. state.update(`config.chart.items.${item.id}.rowId`, newRowId);
  413. }
  414. }
  415. }
  416. }
  417. else if (movement.resizing && (typeof item.resizable === 'undefined' || item.resizable === true)) {
  418. resizeX(normalized, row, item, zoom, timePerPixel);
  419. }
  420. }
  421. function documentUp(ev) {
  422. const movement = getMovement(data);
  423. if (movement.moving || movement.resizing || movement.waiting) {
  424. ev.stopPropagation();
  425. ev.preventDefault();
  426. }
  427. else {
  428. return;
  429. }
  430. movement.moving = false;
  431. movement.waiting = false;
  432. movement.resizing = false;
  433. saveMovement(data.item.id, movement);
  434. for (const itemId in movementState) {
  435. movementState[itemId].moving = false;
  436. movementState[itemId].resizing = false;
  437. movementState[itemId].waiting = false;
  438. destroyGhost(itemId);
  439. }
  440. }
  441. if (pointerEventsExists) {
  442. element.addEventListener('pointerdown', labelDown);
  443. resizerEl.addEventListener('pointerdown', resizerDown);
  444. document.addEventListener('pointermove', documentMove);
  445. document.addEventListener('pointerup', documentUp);
  446. }
  447. else {
  448. element.addEventListener('touchstart', labelDown);
  449. resizerEl.addEventListener('touchstart', resizerDown);
  450. document.addEventListener('touchmove', documentMove);
  451. document.addEventListener('touchend', documentUp);
  452. document.addEventListener('touchcancel', documentUp);
  453. element.addEventListener('mousedown', labelDown);
  454. resizerEl.addEventListener('mousedown', resizerDown);
  455. document.addEventListener('mousemove', documentMove);
  456. document.addEventListener('mouseup', documentUp);
  457. }
  458. return {
  459. update(node, changedData) {
  460. if (!isResizable(changedData) && resizerEl.style.visibility === 'visible') {
  461. resizerEl.style.visibility = 'hidden';
  462. }
  463. else if (isResizable(changedData) && resizerEl.style.visibility === 'hidden') {
  464. resizerEl.style.visibility = 'visible';
  465. }
  466. data = changedData;
  467. },
  468. destroy(node, data) {
  469. if (pointerEventsExists) {
  470. element.removeEventListener('pointerdown', labelDown);
  471. resizerEl.removeEventListener('pointerdown', resizerDown);
  472. document.removeEventListener('pointermove', documentMove);
  473. document.removeEventListener('pointerup', documentUp);
  474. }
  475. else {
  476. element.removeEventListener('mousedown', labelDown);
  477. resizerEl.removeEventListener('mousedown', resizerDown);
  478. document.removeEventListener('mousemove', documentMove);
  479. document.removeEventListener('mouseup', documentUp);
  480. element.removeEventListener('touchstart', labelDown);
  481. resizerEl.removeEventListener('touchstart', resizerDown);
  482. document.removeEventListener('touchmove', documentMove);
  483. document.removeEventListener('touchend', documentUp);
  484. document.removeEventListener('touchcancel', documentUp);
  485. }
  486. resizerEl.remove();
  487. }
  488. };
  489. }
  490. return function initialize(vido) {
  491. vido.state.update('config.actions.chart-timeline-items-row-item', actions => {
  492. actions.push(ItemAction);
  493. return actions;
  494. });
  495. };
  496. }
  497. /**
  498. * @license
  499. * Copyright (c) 2017 The Polymer Project Authors. All rights reserved.
  500. * This code may only be used under the BSD style license found at
  501. * http://polymer.github.io/LICENSE.txt
  502. * The complete set of authors may be found at
  503. * http://polymer.github.io/AUTHORS.txt
  504. * The complete set of contributors may be found at
  505. * http://polymer.github.io/CONTRIBUTORS.txt
  506. * Code distributed by Google as part of the polymer project is also
  507. * subject to an additional IP rights grant found at
  508. * http://polymer.github.io/PATENTS.txt
  509. */
  510. /**
  511. * @license
  512. * Copyright (c) 2017 The Polymer Project Authors. All rights reserved.
  513. * This code may only be used under the BSD style license found at
  514. * http://polymer.github.io/LICENSE.txt
  515. * The complete set of authors may be found at
  516. * http://polymer.github.io/AUTHORS.txt
  517. * The complete set of contributors may be found at
  518. * http://polymer.github.io/CONTRIBUTORS.txt
  519. * Code distributed by Google as part of the polymer project is also
  520. * subject to an additional IP rights grant found at
  521. * http://polymer.github.io/PATENTS.txt
  522. */
  523. /**
  524. * An expression marker with embedded unique key to avoid collision with
  525. * possible text in templates.
  526. */
  527. const marker = `{{lit-${String(Math.random()).slice(2)}}}`;
  528. /**
  529. * Used to clone existing node instead of each time creating new one which is
  530. * slower
  531. */
  532. const markerNode = document.createComment('');
  533. /**
  534. * Used to clone existing node instead of each time creating new one which is
  535. * slower
  536. */
  537. const emptyTemplateNode = document.createElement('template');
  538. /**
  539. * Used to clone text node instead of each time creating new one which is slower
  540. */
  541. const emptyTextNode = document.createTextNode('');
  542. // Detect event listener options support. If the `capture` property is read
  543. // from the options object, then options are supported. If not, then the third
  544. // argument to add/removeEventListener is interpreted as the boolean capture
  545. // value so we should only pass the `capture` property.
  546. let eventOptionsSupported = false;
  547. // Wrap into an IIFE because MS Edge <= v41 does not support having try/catch
  548. // blocks right into the body of a module
  549. (() => {
  550. try {
  551. const options = {
  552. get capture() {
  553. eventOptionsSupported = true;
  554. return false;
  555. }
  556. };
  557. // eslint-disable-next-line @typescript-eslint/no-explicit-any
  558. window.addEventListener('test', options, options);
  559. // eslint-disable-next-line @typescript-eslint/no-explicit-any
  560. window.removeEventListener('test', options, options);
  561. }
  562. catch (_e) {
  563. // noop
  564. }
  565. })();
  566. /**
  567. * @license
  568. * Copyright (c) 2017 The Polymer Project Authors. All rights reserved.
  569. * This code may only be used under the BSD style license found at
  570. * http://polymer.github.io/LICENSE.txt
  571. * The complete set of authors may be found at
  572. * http://polymer.github.io/AUTHORS.txt
  573. * The complete set of contributors may be found at
  574. * http://polymer.github.io/CONTRIBUTORS.txt
  575. * Code distributed by Google as part of the polymer project is also
  576. * subject to an additional IP rights grant found at
  577. * http://polymer.github.io/PATENTS.txt
  578. */
  579. // IMPORTANT: do not change the property name or the assignment expression.
  580. // This line will be used in regexes to search for lit-html usage.
  581. // TODO(justinfagnani): inject version number at build time
  582. const isBrowser = typeof window !== 'undefined';
  583. if (isBrowser) {
  584. // If we run in the browser set version
  585. (window['litHtmlVersions'] || (window['litHtmlVersions'] = [])).push('1.1.7');
  586. }
  587. /**
  588. * Used to clone existing node instead of each time creating new one which is
  589. * slower
  590. */
  591. const emptyTemplateNode$1 = document.createElement('template');
  592. class Action {
  593. constructor() {
  594. this.isAction = true;
  595. }
  596. }
  597. Action.prototype.isAction = true;
  598. const defaultOptions = {
  599. element: document.createTextNode(''),
  600. axis: 'xy',
  601. threshold: 10,
  602. onDown(data) { },
  603. onMove(data) { },
  604. onUp(data) { },
  605. onWheel(data) { }
  606. };
  607. /**
  608. * Selection plugin
  609. *
  610. * @copyright Rafal Pospiech <https://neuronet.io>
  611. * @author Rafal Pospiech <neuronet.io@gmail.com>
  612. * @package gantt-schedule-timeline-calendar
  613. * @license AGPL-3.0 (https://github.com/neuronetio/gantt-schedule-timeline-calendar/blob/master/LICENSE)
  614. * @link https://github.com/neuronetio/gantt-schedule-timeline-calendar
  615. */
  616. function Selection(options = {}) {
  617. let vido, state, api, schedule;
  618. const pluginPath = 'config.plugin.selection';
  619. const rectClassName = 'gantt-schedule-timeline-caledar__plugin-selection-rect';
  620. const rect = document.createElement('div');
  621. rect.classList.add(rectClassName);
  622. rect.style.visibility = 'hidden';
  623. rect.style.left = '0px';
  624. rect.style.top = '0px';
  625. rect.style.width = '0px';
  626. rect.style.height = '0px';
  627. rect.style.background = 'rgba(0, 119, 192, 0.2)';
  628. rect.style.border = '2px dashed rgba(0, 119, 192, 0.75)';
  629. rect.style.position = 'absolute';
  630. rect.style['user-select'] = 'none';
  631. rect.style['pointer-events'] = 'none';
  632. const defaultOptions = {
  633. grid: false,
  634. items: true,
  635. rows: false,
  636. horizontal: true,
  637. vertical: true,
  638. rectStyle: {},
  639. selecting() { },
  640. deselecting() { },
  641. selected() { },
  642. deselected() { },
  643. canSelect(type, currently, all) {
  644. return currently;
  645. },
  646. canDeselect(type, currently, all) {
  647. return [];
  648. },
  649. getApi() { }
  650. };
  651. options = Object.assign(Object.assign({}, defaultOptions), options);
  652. for (const styleProp in options.rectStyle) {
  653. rect.style[styleProp] = options.rectStyle[styleProp];
  654. }
  655. const selecting = {
  656. fromX: -1,
  657. fromY: -1,
  658. toX: -1,
  659. toY: -1,
  660. startX: -1,
  661. startY: -1,
  662. startCell: false,
  663. selecting: false
  664. };
  665. const selectionTypesIdGetters = {
  666. 'chart-timeline-grid-row': props => props.row.id,
  667. 'chart-timeline-grid-row-block': props => props.id,
  668. 'chart-timeline-items-row': props => props.row.id,
  669. 'chart-timeline-items-row-item': props => props.item.id
  670. };
  671. function getEmptyContainer() {
  672. return {
  673. 'chart-timeline-grid-rows': [],
  674. 'chart-timeline-grid-row-blocks': [],
  675. 'chart-timeline-items-rows': [],
  676. 'chart-timeline-items-row-items': []
  677. };
  678. }
  679. function markSelecting(nowSelecting, addToPrevious = false) {
  680. if (addToPrevious) {
  681. state.update(`${pluginPath}.selecting`, selecting => {
  682. for (const name in selecting) {
  683. nowSelecting[name].forEach(id => {
  684. if (!selecting[name].includes()) {
  685. selecting[name].push(id);
  686. }
  687. });
  688. }
  689. return selecting;
  690. });
  691. }
  692. else {
  693. state.update(`${pluginPath}.selecting`, nowSelecting);
  694. }
  695. state.update('config.chart.items', function updateItems(items) {
  696. const now = nowSelecting['chart-timeline-items-row-items'];
  697. for (const itemId in items) {
  698. const item = items[itemId];
  699. if (now.includes(item.id)) {
  700. item.selecting = true;
  701. }
  702. else {
  703. item.selecting = false;
  704. }
  705. }
  706. return items;
  707. }, { only: ['selecting'] });
  708. state.update('_internal.chart.grid.rowsWithBlocks', function updateRowsWithBlocks(rowsWithBlocks) {
  709. const nowBlocks = nowSelecting['chart-timeline-grid-row-blocks'];
  710. const nowRows = nowSelecting['chart-timeline-grid-rows'];
  711. if (rowsWithBlocks)
  712. for (const row of rowsWithBlocks) {
  713. if (nowRows.includes(row.id)) {
  714. row.selecting = true;
  715. }
  716. else {
  717. row.selecting = false;
  718. }
  719. for (const block of row.blocks) {
  720. if (nowBlocks.includes(block.id)) {
  721. block.selecting = true;
  722. }
  723. else {
  724. block.selecting = false;
  725. }
  726. }
  727. }
  728. return rowsWithBlocks;
  729. });
  730. }
  731. /**
  732. * Clear selection
  733. * @param {boolean} clear
  734. */
  735. function clearSelection(clear = false, onlySelecting = false) {
  736. let selectingState;
  737. if (onlySelecting) {
  738. state.update(pluginPath, currently => {
  739. selectingState = {
  740. selecting: {
  741. 'chart-timeline-grid-rows': [],
  742. 'chart-timeline-grid-row-blocks': [],
  743. 'chart-timeline-items-rows': [],
  744. 'chart-timeline-items-row-items': []
  745. },
  746. selected: currently.selected
  747. };
  748. return selectingState;
  749. });
  750. }
  751. else {
  752. state.update(pluginPath, currently => {
  753. selectingState = {
  754. selecting: {
  755. 'chart-timeline-grid-rows': [],
  756. 'chart-timeline-grid-row-blocks': [],
  757. 'chart-timeline-items-rows': [],
  758. 'chart-timeline-items-row-items': []
  759. },
  760. selected: {
  761. 'chart-timeline-grid-rows': clear
  762. ? []
  763. : options.canDeselect('chart-timeline-grid-rows', currently.selected['chart-timeline-grid-rows'], currently),
  764. 'chart-timeline-grid-row-blocks': clear
  765. ? []
  766. : options.canDeselect('chart-timeline-grid-row-blocks', currently.selected['chart-timeline-grid-row-blocks'], currently),
  767. 'chart-timeline-items-rows': clear
  768. ? []
  769. : options.canDeselect('chart-timeline-items-rows', currently.selected['chart-timeline-items-rows'], currently),
  770. 'chart-timeline-items-row-items': clear
  771. ? []
  772. : options.canDeselect('chart-timeline-items-row-items', currently.selected['chart-timeline-items-row-items'], currently)
  773. }
  774. };
  775. return selectingState;
  776. });
  777. state.update('_internal.chart.grid.rowsWithBlocks', function clearRowsWithBlocks(rowsWithBlocks) {
  778. if (rowsWithBlocks)
  779. for (const row of rowsWithBlocks) {
  780. for (const block of row.blocks) {
  781. block.selected = selectingState.selected['chart-timeline-grid-row-blocks'].includes(block.id);
  782. block.selecting = false;
  783. }
  784. }
  785. return rowsWithBlocks;
  786. });
  787. state.update('config.chart.items', items => {
  788. if (items) {
  789. for (const itemId in items) {
  790. const item = items[itemId];
  791. item.selected = selectingState.selected['chart-timeline-items-row-items'].includes(itemId);
  792. item.selecting = false;
  793. }
  794. }
  795. return items;
  796. });
  797. }
  798. }
  799. let previousSelect;
  800. function markSelected(addToPrevious = false) {
  801. selecting.selecting = false;
  802. rect.style.visibility = 'hidden';
  803. const currentSelect = cloneSelection(state.get(pluginPath));
  804. const select = {};
  805. if (addToPrevious) {
  806. state.update(pluginPath, value => {
  807. const selected = Object.assign({}, value.selecting);
  808. for (const name in value.selected) {
  809. for (const id of selected[name]) {
  810. if (!value.selected[name].includes(id)) {
  811. value.selected[name].push(id);
  812. }
  813. }
  814. }
  815. select.selected = Object.assign({}, value.selected);
  816. select.selecting = getEmptyContainer();
  817. return select;
  818. });
  819. }
  820. else {
  821. state.update(pluginPath, value => {
  822. select.selected = Object.assign({}, value.selecting);
  823. select.selecting = getEmptyContainer();
  824. return select;
  825. });
  826. }
  827. const elements = state.get('_internal.elements');
  828. for (const type in selectionTypesIdGetters) {
  829. if (elements[type + 's'])
  830. for (const element of elements[type + 's']) {
  831. if (currentSelect.selecting[type + 's'].includes(element.vido.id)) {
  832. options.deselecting(element.vido, type);
  833. }
  834. }
  835. }
  836. state.update('config.chart.items', function updateItems(items) {
  837. for (const itemId in items) {
  838. const item = items[itemId];
  839. if (currentSelect.selecting['chart-timeline-items-row-items'].includes(item.id)) {
  840. item.selected = true;
  841. if (typeof item.selected === 'undefined' || !item.selected) {
  842. options.selected(item, 'chart-timeline-items-row-item');
  843. }
  844. }
  845. else if (addToPrevious && previousSelect.selected['chart-timeline-items-row-items'].includes(item.id)) {
  846. item.selected = true;
  847. }
  848. else {
  849. item.selected = false;
  850. if (currentSelect.selected['chart-timeline-items-row-items'].includes(item.id)) {
  851. options.deselected(item, 'chart-timeline-items-row-item');
  852. }
  853. }
  854. }
  855. return items;
  856. });
  857. state.update('_internal.chart.grid.rowsWithBlocks', function updateRowsWithBlocks(rowsWithBlocks) {
  858. if (rowsWithBlocks)
  859. for (const row of rowsWithBlocks) {
  860. for (const block of row.blocks) {
  861. if (currentSelect.selecting['chart-timeline-grid-row-blocks'].includes(block.id)) {
  862. if (typeof block.selected === 'undefined' || !block.selected) {
  863. options.selected(block, 'chart-timeline-grid-row-block');
  864. }
  865. block.selected = true;
  866. }
  867. else if (addToPrevious && previousSelect.selected['chart-timeline-grid-row-blocks'].includes(block.id)) {
  868. block.selected = true;
  869. }
  870. else {
  871. if (currentSelect.selected['chart-timeline-grid-row-blocks'].includes(block.id)) {
  872. options.deselected(block, 'chart-timeline-grid-row-block');
  873. }
  874. block.selected = false;
  875. }
  876. }
  877. }
  878. return rowsWithBlocks;
  879. });
  880. }
  881. /**
  882. * Clone current selection state
  883. * @param {object} currentSelect
  884. * @returns {object} currentSelect cloned
  885. */
  886. function cloneSelection(currentSelect) {
  887. const result = {};
  888. result.selecting = Object.assign({}, currentSelect.selecting);
  889. result.selecting['chart-timeline-grid-rows'] = currentSelect.selecting['chart-timeline-grid-rows'].slice();
  890. result.selecting['chart-timeline-grid-row-blocks'] = currentSelect.selecting['chart-timeline-grid-row-blocks'].slice();
  891. result.selecting['chart-timeline-items-rows'] = currentSelect.selecting['chart-timeline-items-rows'].slice();
  892. result.selecting['chart-timeline-items-row-items'] = currentSelect.selecting['chart-timeline-items-row-items'].slice();
  893. result.selected = Object.assign({}, currentSelect.selected);
  894. result.selected['chart-timeline-grid-rows'] = currentSelect.selected['chart-timeline-grid-rows'].slice();
  895. result.selected['chart-timeline-grid-row-blocks'] = currentSelect.selected['chart-timeline-grid-row-blocks'].slice();
  896. result.selected['chart-timeline-items-rows'] = currentSelect.selected['chart-timeline-items-rows'].slice();
  897. result.selected['chart-timeline-items-row-items'] = currentSelect.selected['chart-timeline-items-row-items'].slice();
  898. return result;
  899. }
  900. /**
  901. * Selection action class
  902. */
  903. class SelectionAction extends Action {
  904. /**
  905. * Selection action constructor
  906. * @param {Element} element
  907. * @param {object|any} data
  908. */
  909. constructor(element, data) {
  910. super();
  911. const api = {};
  912. api.clearSelection = clearSelection;
  913. this.unsub = data.state.subscribeAll(['_internal.elements.chart-timeline', '_internal.chart.dimensions.width'], bulk => {
  914. const chartTimeline = state.get('_internal.elements.chart-timeline');
  915. if (chartTimeline === undefined)
  916. return;
  917. this.chartTimeline = chartTimeline;
  918. if (!this.chartTimeline.querySelector('.' + rectClassName)) {
  919. this.chartTimeline.insertAdjacentElement('beforeend', rect);
  920. }
  921. const bounding = this.chartTimeline.getBoundingClientRect();
  922. this.left = bounding.left;
  923. this.top = bounding.top;
  924. });
  925. /**
  926. * Save and swap coordinates if needed
  927. * @param {MouseEvent} ev
  928. */
  929. const saveAndSwapIfNeeded = (ev) => {
  930. const normalized = vido.api.normalizePointerEvent(ev);
  931. const currentX = normalized.x - this.left;
  932. const currentY = normalized.y - this.top;
  933. if (currentX <= selecting.startX) {
  934. selecting.fromX = currentX;
  935. selecting.toX = selecting.startX;
  936. }
  937. else {
  938. selecting.fromX = selecting.startX;
  939. selecting.toX = currentX;
  940. }
  941. if (currentY <= selecting.startY) {
  942. selecting.fromY = currentY;
  943. selecting.toY = selecting.startY;
  944. }
  945. else {
  946. selecting.fromY = selecting.startY;
  947. selecting.toY = currentY;
  948. }
  949. };
  950. /**
  951. * Is rectangle inside other rectangle ?
  952. * @param {DOMRect} boundingRect
  953. * @param {DOMRect} rectBoundingRect
  954. * @returns {boolean}
  955. */
  956. const isInside = (boundingRect, rectBoundingRect) => {
  957. let horizontal = false;
  958. let vertical = false;
  959. if ((boundingRect.left > rectBoundingRect.left && boundingRect.left < rectBoundingRect.right) ||
  960. (boundingRect.right > rectBoundingRect.left && boundingRect.right < rectBoundingRect.right) ||
  961. (boundingRect.left <= rectBoundingRect.left && boundingRect.right >= rectBoundingRect.right)) {
  962. horizontal = true;
  963. }
  964. if ((boundingRect.top > rectBoundingRect.top && boundingRect.top < rectBoundingRect.bottom) ||
  965. (boundingRect.bottom > rectBoundingRect.top && boundingRect.bottom < rectBoundingRect.bottom) ||
  966. (boundingRect.top <= rectBoundingRect.top && boundingRect.bottom >= rectBoundingRect.bottom)) {
  967. vertical = true;
  968. }
  969. return horizontal && vertical;
  970. };
  971. /**
  972. * Get selecting elements
  973. * @param {DOMRect} rectBoundingRect
  974. * @param {Element[]} elements
  975. * @param {string} type
  976. * @returns {string[]}
  977. */
  978. function getSelecting(rectBoundingRect, elements, type, getId) {
  979. const selectingResult = [];
  980. const currentlySelectingData = [];
  981. const all = elements[type + 's'];
  982. if (!all)
  983. return [];
  984. const currentAll = state.get(pluginPath);
  985. const currentSelecting = currentAll.selecting[type + 's'];
  986. for (const element of all) {
  987. const boundingRect = element.getBoundingClientRect();
  988. if (isInside(boundingRect, rectBoundingRect)) {
  989. currentlySelectingData.push(element.vido);
  990. const canSelect = options.canSelect(type, currentlySelectingData, currentAll);
  991. if (canSelect.includes(element.vido)) {
  992. if (!currentSelecting.includes(getId(element.vido))) {
  993. options.selecting(element.vido, type);
  994. }
  995. selectingResult.push(getId(element.vido));
  996. }
  997. else {
  998. currentlySelectingData.unshift();
  999. }
  1000. }
  1001. else {
  1002. if (currentSelecting.includes(getId(element.vido))) {
  1003. options.deselecting(element.vido, type);
  1004. }
  1005. }
  1006. }
  1007. return selectingResult;
  1008. }
  1009. function trackSelection(ev, virtually = false) {
  1010. const movement = state.get('config.plugin.ItemMovement.movement');
  1011. const moving = movement && (movement.moving || movement.waiting);
  1012. if (!selecting.selecting || moving) {
  1013. if (moving) {
  1014. selecting.selecting = false;
  1015. }
  1016. return;
  1017. }
  1018. clearSelection(false, true);
  1019. saveAndSwapIfNeeded(ev);
  1020. rect.style.left = selecting.fromX + 'px';
  1021. rect.style.top = selecting.fromY + 'px';
  1022. rect.style.width = selecting.toX - selecting.fromX + 'px';
  1023. rect.style.height = selecting.toY - selecting.fromY + 'px';
  1024. if (!virtually) {
  1025. rect.style.visibility = 'visible';
  1026. }
  1027. const rectBoundingRect = rect.getBoundingClientRect();
  1028. const elements = state.get('_internal.elements');
  1029. const nowSelecting = {};
  1030. for (const type in selectionTypesIdGetters) {
  1031. nowSelecting[type + 's'] = getSelecting(rectBoundingRect, elements, type, selectionTypesIdGetters[type]);
  1032. }
  1033. markSelecting(nowSelecting, ev.ctrlKey);
  1034. }
  1035. /**
  1036. * End select
  1037. * @param {Event} ev
  1038. */
  1039. const endSelect = ev => {
  1040. if (selecting.selecting) {
  1041. ev.stopPropagation();
  1042. ev.preventDefault();
  1043. const normalized = vido.api.normalizePointerEvent(ev);
  1044. if (selecting.startX === normalized.x - this.left && selecting.startY === normalized.y - this.top) {
  1045. selecting.selecting = false;
  1046. rect.style.visibility = 'hidden';
  1047. return;
  1048. }
  1049. }
  1050. else {
  1051. const itemClass = '.gantt-schedule-timeline-calendar__chart-timeline-items-row-item';
  1052. const isItem = !!ev.target.closest(itemClass);
  1053. if (!isItem) {
  1054. if (!ev.ctrlKey)
  1055. clearSelection();
  1056. }
  1057. else {
  1058. markSelected(ev.ctrlKey);
  1059. }
  1060. return;
  1061. }
  1062. markSelected(ev.ctrlKey);
  1063. };
  1064. /**
  1065. * Mouse down event handler
  1066. * @param {MouseEvent} ev
  1067. */
  1068. this.mouseDown = ev => {
  1069. const movement = state.get('config.plugin.ItemMovement.movement');
  1070. const moving = movement && movement.moving;
  1071. if ((ev.type === 'mousedown' && ev.button !== 0) || moving) {
  1072. return;
  1073. }
  1074. const normalized = vido.api.normalizePointerEvent(ev);
  1075. selecting.selecting = true;
  1076. selecting.fromX = normalized.x - this.left;
  1077. selecting.fromY = normalized.y - this.top;
  1078. selecting.startX = selecting.fromX;
  1079. selecting.startY = selecting.fromY;
  1080. previousSelect = cloneSelection(state.get(pluginPath));
  1081. const itemClass = '.gantt-schedule-timeline-calendar__chart-timeline-items-row-item';
  1082. const isItem = !!ev.target.closest(itemClass);
  1083. if (!isItem) {
  1084. if (!ev.ctrlKey)
  1085. clearSelection();
  1086. }
  1087. };
  1088. /**
  1089. * Mouse move event handler
  1090. * @param {MouseEvent} ev
  1091. */
  1092. this.mouseMove = ev => {
  1093. trackSelection(ev);
  1094. };
  1095. /**
  1096. * Mouse up event handler
  1097. * @param {MouseEvent} ev
  1098. */
  1099. this.mouseUp = ev => {
  1100. if (selecting.selecting) {
  1101. endSelect(ev);
  1102. }
  1103. };
  1104. element.addEventListener('mousedown', this.mouseDown);
  1105. element.addEventListener('touchstart', this.mouseDown);
  1106. document.addEventListener('mousemove', this.mouseMove);
  1107. document.addEventListener('touchmove', this.mouseMove);
  1108. document.addEventListener('mouseup', this.mouseUp);
  1109. document.addEventListener('touchend', this.mouseUp);
  1110. options.getApi(api);
  1111. }
  1112. destroy(element) {
  1113. document.removeEventListener('mouseup', this.mouseUp);
  1114. document.removeEventListener('touchend', this.mouseUp);
  1115. document.removeEventListener('mousemove', this.mouseMove);
  1116. document.removeEventListener('touchmove', this.mouseMove);
  1117. element.removeEventListener('mousedown', this.mouseDown);
  1118. element.removeEventListener('touchstart', this.mouseDown);
  1119. this.unsub();
  1120. }
  1121. }
  1122. /**
  1123. * Update selection
  1124. * @param {any} data
  1125. * @param {HTMLElement} element
  1126. * @param {boolean} selecting
  1127. * @param {boolean} selected
  1128. * @param {string} classNameSelecting
  1129. * @param {string} classNameSelected
  1130. */
  1131. function updateSelection(element, selecting, selected, classNameSelecting, classNameSelected) {
  1132. if (selecting && !element.classList.contains(classNameSelecting)) {
  1133. element.classList.add(classNameSelecting);
  1134. }
  1135. else if (!selecting && element.classList.contains(classNameSelecting)) {
  1136. element.classList.remove(classNameSelecting);
  1137. }
  1138. if (selected && !element.classList.contains(classNameSelected)) {
  1139. element.classList.add(classNameSelected);
  1140. }
  1141. else if (!selected && element.classList.contains(classNameSelected)) {
  1142. element.classList.remove(classNameSelected);
  1143. }
  1144. }
  1145. /**
  1146. * Grid row block action
  1147. * @param {HTMLElement} element
  1148. * @param {object} data
  1149. * @returns {object} with update and destroy functions
  1150. */
  1151. class GridBlockAction extends Action {
  1152. constructor(element, data) {
  1153. super();
  1154. this.classNameSelecting = api.getClass('chart-timeline-grid-row-block') + '--selecting';
  1155. this.classNameSelected = api.getClass('chart-timeline-grid-row-block') + '--selected';
  1156. updateSelection(element, data.selecting, data.selected, this.classNameSelecting, this.classNameSelected);
  1157. }
  1158. update(element, data) {
  1159. updateSelection(element, data.selecting, data.selected, this.classNameSelecting, this.classNameSelected);
  1160. }
  1161. destroy(element, changedData) {
  1162. element.classList.remove(this.classNameSelecting);
  1163. element.classList.remove(this.classNameSelected);
  1164. }
  1165. }
  1166. /**
  1167. * Item action
  1168. * @param {Element} element
  1169. * @param {object} data
  1170. * @returns {object} with update and destroy functions
  1171. */
  1172. class ItemAction extends Action {
  1173. constructor(element, data) {
  1174. super();
  1175. this.data = data;
  1176. this.element = element;
  1177. this.classNameSelecting = api.getClass('chart-timeline-items-row-item') + '--selecting';
  1178. this.classNameSelected = api.getClass('chart-timeline-items-row-item') + '--selected';
  1179. this.data = data;
  1180. this.element = element;
  1181. this.onPointerDown = this.onPointerDown.bind(this);
  1182. element.addEventListener('mousedown', this.onPointerDown);
  1183. element.addEventListener('touchstart', this.onPointerDown);
  1184. updateSelection(element, data.item.selecting, data.item.selected, this.classNameSelecting, this.classNameSelected);
  1185. }
  1186. onPointerDown(ev) {
  1187. previousSelect = cloneSelection(state.get(pluginPath));
  1188. selecting.selecting = true;
  1189. this.data.item.selected = true;
  1190. const container = getEmptyContainer();
  1191. container['chart-timeline-items-row-items'].push(this.data.item.id);
  1192. markSelecting(container);
  1193. markSelected(ev.ctrlKey);
  1194. updateSelection(this.element, this.data.item.selecting, this.data.item.selected, this.classNameSelecting, this.classNameSelected);
  1195. }
  1196. update(element, data) {
  1197. updateSelection(element, data.item.selecting, data.item.selected, this.classNameSelecting, this.classNameSelected);
  1198. this.data = data;
  1199. }
  1200. destroy(element, data) {
  1201. element.classList.remove(this.classNameSelecting);
  1202. element.classList.remove(this.classNameSelected);
  1203. element.removeEventListener('mousedown', this.onPointerDown);
  1204. element.removeEventListener('touchstart', this.onPointerDown);
  1205. }
  1206. }
  1207. /**
  1208. * On block create handler
  1209. * @param {object} block
  1210. * @returns {object} block
  1211. */
  1212. function onBlockCreate(block) {
  1213. const selectedBlocks = state.get('config.plugin.selection.selected.chart-timeline-grid-row-blocks');
  1214. for (const selectedBlock of selectedBlocks) {
  1215. if (selectedBlock === block.id) {
  1216. block.selected = true;
  1217. return block;
  1218. }
  1219. }
  1220. block.selected = false;
  1221. block.selecting = false;
  1222. return block;
  1223. }
  1224. return function initialize(mainVido) {
  1225. vido = mainVido;
  1226. state = vido.state;
  1227. api = vido.api;
  1228. schedule = vido.schedule;
  1229. if (typeof state.get(pluginPath) === 'undefined') {
  1230. state.update(pluginPath, {
  1231. selecting: {
  1232. 'chart-timeline-grid-rows': [],
  1233. 'chart-timeline-grid-row-blocks': [],
  1234. 'chart-timeline-items-rows': [],
  1235. 'chart-timeline-items-row-items': []
  1236. },
  1237. selected: {
  1238. 'chart-timeline-grid-rows': [],
  1239. 'chart-timeline-grid-row-blocks': [],
  1240. 'chart-timeline-items-rows': [],
  1241. 'chart-timeline-items-row-items': []
  1242. }
  1243. });
  1244. }
  1245. state.update('config.chart.items', items => {
  1246. if (items)
  1247. for (const itemId in items) {
  1248. const item = items[itemId];
  1249. if (typeof item.selecting === 'undefined') {
  1250. item.selecting = false;
  1251. }
  1252. if (typeof item.selected === 'undefined') {
  1253. item.selected = false;
  1254. }
  1255. }
  1256. return items;
  1257. });
  1258. state.update('config.actions.chart-timeline', actions => {
  1259. actions.push(SelectionAction);
  1260. return actions;
  1261. });
  1262. state.update('config.actions.chart-timeline-grid-row-block', actions => {
  1263. actions.push(GridBlockAction);
  1264. return actions;
  1265. });
  1266. state.update('config.actions.chart-timeline-items-row-item', actions => {
  1267. actions.push(ItemAction);
  1268. return actions;
  1269. });
  1270. state.update('config.chart.grid.block.onCreate', onCreate => {
  1271. onCreate.push(onBlockCreate);
  1272. return onCreate;
  1273. });
  1274. };
  1275. }
  1276. /**
  1277. * @license
  1278. * Copyright (c) 2017 The Polymer Project Authors. All rights reserved.
  1279. * This code may only be used under the BSD style license found at
  1280. * http://polymer.github.io/LICENSE.txt
  1281. * The complete set of authors may be found at
  1282. * http://polymer.github.io/AUTHORS.txt
  1283. * The complete set of contributors may be found at
  1284. * http://polymer.github.io/CONTRIBUTORS.txt
  1285. * Code distributed by Google as part of the polymer project is also
  1286. * subject to an additional IP rights grant found at
  1287. * http://polymer.github.io/PATENTS.txt
  1288. */
  1289. const t=t=>(...e)=>{const n=t(...e);return n.isDirective=!0,n};class e{constructor(){this.isDirective=!0,this.isClass=!0;}body(t){}}const n=t=>null!=t&&"boolean"==typeof t.isDirective,s="undefined"!=typeof window&&(null!=window.customElements&&void 0!==window.customElements.polyfillWrapFlushCallback),o=(t,e,n=null,s=null)=>{for(;e!==n;){const n=e.nextSibling;t.insertBefore(e,s),e=n;}},i=(t,e,n=null)=>{for(;e!==n;){const n=e.nextSibling;t.removeChild(e),e=n;}},r={},a={},l=`{{lit-${String(Math.random()).slice(2)}}}`,c=`\x3c!--${l}--\x3e`,h=new RegExp(`${l}|${c}`),d="$lit$";
  1290. /**
  1291. * @license
  1292. * Copyright (c) 2017 The Polymer Project Authors. All rights reserved.
  1293. * This code may only be used under the BSD style license found at
  1294. * http://polymer.github.io/LICENSE.txt
  1295. * The complete set of authors may be found at
  1296. * http://polymer.github.io/AUTHORS.txt
  1297. * The complete set of contributors may be found at
  1298. * http://polymer.github.io/CONTRIBUTORS.txt
  1299. * Code distributed by Google as part of the polymer project is also
  1300. * subject to an additional IP rights grant found at
  1301. * http://polymer.github.io/PATENTS.txt
  1302. */class p{constructor(t,e){this.parts=[],this.element=e;const n=[],s=[],o=document.createTreeWalker(e.content,133,null,!1);let i=0,r=-1,a=0;const{strings:c,values:{length:p}}=t;for(;a<p;){const t=o.nextNode();if(null!==t){if(r++,1===t.nodeType){if(t.hasAttributes()){const e=t.attributes,{length:n}=e;let s=0;for(let t=0;t<n;t++)u(e[t].name,d)&&s++;for(;s-- >0;){const e=c[a],n=g.exec(e)[2],s=n.toLowerCase()+d,o=t.getAttribute(s);t.removeAttribute(s);const i=o.split(h);this.parts.push({type:"attribute",index:r,name:n,strings:i,sanitizer:void 0}),a+=i.length-1;}}"TEMPLATE"===t.tagName&&(s.push(t),o.currentNode=t.content);}else if(3===t.nodeType){const e=t.data;if(e.indexOf(l)>=0){const s=t.parentNode,o=e.split(h),i=o.length-1;for(let e=0;e<i;e++){let n,i=o[e];if(""===i)n=f();else{const t=g.exec(i);null!==t&&u(t[2],d)&&(i=i.slice(0,t.index)+t[1]+t[2].slice(0,-d.length)+t[3]),n=document.createTextNode(i);}s.insertBefore(n,t),this.parts.push({type:"node",index:++r});}""===o[i]?(s.insertBefore(f(),t),n.push(t)):t.data=o[i],a+=i;}}else if(8===t.nodeType)if(t.data===l){const e=t.parentNode;null!==t.previousSibling&&r!==i||(r++,e.insertBefore(f(),t)),i=r,this.parts.push({type:"node",index:r}),null===t.nextSibling?t.data="":(n.push(t),r--),a++;}else{let e=-1;for(;-1!==(e=t.data.indexOf(l,e+1));)this.parts.push({type:"node",index:-1}),a++;}}else o.currentNode=s.pop();}for(const t of n)t.parentNode.removeChild(t);}}const u=(t,e)=>{const n=t.length-e.length;return n>=0&&t.slice(n)===e},m=t=>-1!==t.index,v=document.createComment(""),f=()=>v.cloneNode(),g=/([ \x09\x0a\x0c\x0d])([^\0-\x1F\x7F-\x9F "'>=/]+)([ \x09\x0a\x0c\x0d]*=[ \x09\x0a\x0c\x0d]*(?:[^ \x09\x0a\x0c\x0d"'`<>=]*|"[^"]*|'[^']*))$/;
  1303. /**
  1304. * @license
  1305. * Copyright (c) 2017 The Polymer Project Authors. All rights reserved.
  1306. * This code may only be used under the BSD style license found at
  1307. * http://polymer.github.io/LICENSE.txt
  1308. * The complete set of authors may be found at
  1309. * http://polymer.github.io/AUTHORS.txt
  1310. * The complete set of contributors may be found at
  1311. * http://polymer.github.io/CONTRIBUTORS.txt
  1312. * Code distributed by Google as part of the polymer project is also
  1313. * subject to an additional IP rights grant found at
  1314. * http://polymer.github.io/PATENTS.txt
  1315. */
  1316. class y{constructor(t,e,n){this.__parts=[],this.template=t,this.processor=e,this.options=n;}update(t){let e=0;for(const n of this.__parts)void 0!==n&&n.setValue(t[e]),e++;for(const t of this.__parts)void 0!==t&&t.commit();}_clone(){const t=s?this.template.element.content.cloneNode(!0):document.importNode(this.template.element.content,!0),e=[],n=this.template.parts,o=document.createTreeWalker(t,133,null,!1);let i,r=0,a=0,l=o.nextNode();for(;r<n.length;)if(i=n[r],m(i)){for(;a<i.index;)a++,"TEMPLATE"===l.nodeName&&(e.push(l),o.currentNode=l.content),null===(l=o.nextNode())&&(o.currentNode=e.pop(),l=o.nextNode());if("node"===i.type){const t=this.processor.handleTextExpression(this.options,i);t.insertAfterNode(l.previousSibling),this.__parts.push(t);}else this.__parts.push(...this.processor.handleAttributeExpressions(l,i.name,i.strings,this.options,i));r++;}else this.__parts.push(void 0),r++;return s&&(document.adoptNode(t),customElements.upgrade(t)),t}}
  1317. /**
  1318. * @license
  1319. * Copyright (c) 2017 The Polymer Project Authors. All rights reserved.
  1320. * This code may only be used under the BSD style license found at
  1321. * http://polymer.github.io/LICENSE.txt
  1322. * The complete set of authors may be found at
  1323. * http://polymer.github.io/AUTHORS.txt
  1324. * The complete set of contributors may be found at
  1325. * http://polymer.github.io/CONTRIBUTORS.txt
  1326. * Code distributed by Google as part of the polymer project is also
  1327. * subject to an additional IP rights grant found at
  1328. * http://polymer.github.io/PATENTS.txt
  1329. */let x;const b=` ${l} `,_=document.createElement("template");class w{constructor(t,e,n,s){this.strings=t,this.values=e,this.type=n,this.processor=s;}getHTML(){const t=this.strings.length-1;let e="",n=!1;for(let s=0;s<t;s++){const t=this.strings[s],o=t.lastIndexOf("\x3c!--");n=(o>-1||n)&&-1===t.indexOf("--\x3e",o+1);const i=g.exec(t);e+=null===i?t+(n?b:c):t.substr(0,i.index)+i[1]+i[2]+d+i[3]+l;}return e+=this.strings[t],e}getTemplateElement(){const t=_.cloneNode();return t.innerHTML=function(t){const e=window,n=e.trustedTypes||e.TrustedTypes;return n&&!x&&(x=n.createPolicy("lit-html",{createHTML:t=>t})),x?x.createHTML(t):t}(this.getHTML()),t}}class N extends w{getHTML(){return `<svg>${super.getHTML()}</svg>`}getTemplateElement(){const t=super.getTemplateElement(),e=t.content,n=e.firstChild;return e.removeChild(n),o(e,n.firstChild),t}}
  1330. /**
  1331. * @license
  1332. * Copyright (c) 2017 The Polymer Project Authors. All rights reserved.
  1333. * This code may only be used under the BSD style license found at
  1334. * http://polymer.github.io/LICENSE.txt
  1335. * The complete set of authors may be found at
  1336. * http://polymer.github.io/AUTHORS.txt
  1337. * The complete set of contributors may be found at
  1338. * http://polymer.github.io/CONTRIBUTORS.txt
  1339. * Code distributed by Google as part of the polymer project is also
  1340. * subject to an additional IP rights grant found at
  1341. * http://polymer.github.io/PATENTS.txt
  1342. */const E=t=>null===t||!("object"==typeof t||"function"==typeof t),P=t=>Array.isArray(t)||!(!t||!t[Symbol.iterator]),A=t=>t,T=(t,e,n)=>A;let M=T;const Y=document.createTextNode("");class X{constructor(t,e,n,s,o="attribute"){this.dirty=!0,this.element=t,this.name=e,this.strings=n,this.parts=[];let i=s&&s.sanitizer;void 0===i&&(i=M(t,e,o),void 0!==s&&(s.sanitizer=i)),this.sanitizer=i;for(let t=0;t<n.length-1;t++)this.parts[t]=this._createPart();}_createPart(){return new I(this)}_getValue(){const t=this.strings,e=this.parts,n=t.length-1;if(1===n&&""===t[0]&&""===t[1]&&void 0!==e[0]){const t=e[0].value;if(!P(t))return t}let s="";for(let o=0;o<n;o++){s+=t[o];const n=e[o];if(void 0!==n){const t=n.value;if(E(t)||!P(t))s+="string"==typeof t?t:String(t);else for(const e of t)s+="string"==typeof e?e:String(e);}}return s+=t[n],s}commit(){if(this.dirty){this.dirty=!1;let t=this._getValue();t=this.sanitizer(t),"symbol"==typeof t&&(t=String(t)),this.element.setAttribute(this.name,t);}}}class I{constructor(t){this.value=void 0,this.committer=t;}setValue(t){t===r||E(t)&&t===this.value||(this.value=t,n(t)||(this.committer.dirty=!0));}commit(){for(;n(this.value);){const t=this.value;this.value=r,t.isClass?t.body(this):t(this);}this.value!==r&&this.committer.commit();}}class S{constructor(t,e){this.value=void 0,this.__pendingValue=void 0,this.textSanitizer=void 0,this.options=t,this.templatePart=e;}appendInto(t){this.startNode=t.appendChild(f()),this.endNode=t.appendChild(f());}insertAfterNode(t){this.startNode=t,this.endNode=t.nextSibling;}appendIntoPart(t){t.__insert(this.startNode=f()),t.__insert(this.endNode=f());}insertAfterPart(t){t.__insert(this.startNode=f()),this.endNode=t.endNode,t.endNode=this.startNode;}setValue(t){this.__pendingValue=t;}commit(){for(;n(this.__pendingValue);){const t=this.__pendingValue;this.__pendingValue=r,t.isClass?t.body(this):t(this);}const t=this.__pendingValue;t!==r&&(E(t)?t!==this.value&&this.__commitText(t):t instanceof w?this.__commitTemplateResult(t):t instanceof Node?this.__commitNode(t):P(t)?this.__commitIterable(t):t===a?(this.value=a,this.clear()):this.__commitText(t));}__insert(t){this.endNode.parentNode.insertBefore(t,this.endNode);}__commitNode(t){this.value!==t&&(this.clear(),this.__insert(t),this.value=t);}__commitText(t){const e=this.startNode.nextSibling;if(t=null==t?"":t,e===this.endNode.previousSibling&&3===e.nodeType){void 0===this.textSanitizer&&(this.textSanitizer=M(e,"data","property"));const n=this.textSanitizer(t);e.data="string"==typeof n?n:String(n);}else{const e=Y.cloneNode();this.__commitNode(e),void 0===this.textSanitizer&&(this.textSanitizer=M(e,"data","property"));const n=this.textSanitizer(t);e.data="string"==typeof n?n:String(n);}this.value=t;}__commitTemplateResult(t){const e=this.options.templateFactory(t);if(this.value instanceof y&&this.value.template===e)this.value.update(t.values);else{const n=this.endNode.parentNode;if(M!==T&&"STYLE"===n.nodeName||"SCRIPT"===n.nodeName)return void this.__commitText("/* lit-html will not write TemplateResults to scripts and styles */");const s=new y(e,t.processor,this.options),o=s._clone();s.update(t.values),this.__commitNode(o),this.value=s;}}__commitIterable(t){Array.isArray(this.value)||(this.value=[],this.clear());const e=this.value;let n,s=0;for(const o of t)n=e[s],void 0===n&&(n=new S(this.options,this.templatePart),e.push(n),0===s?n.appendIntoPart(this):n.insertAfterPart(e[s-1])),n.setValue(o),n.commit(),s++;s<e.length&&(e.length=s,this.clear(n&&n.endNode));}clear(t=this.startNode){i(this.startNode.parentNode,t.nextSibling,this.endNode);}}class C{constructor(t,e,n){if(this.value=void 0,this.__pendingValue=void 0,2!==n.length||""!==n[0]||""!==n[1])throw new Error("Boolean attributes can only contain a single expression");this.element=t,this.name=e,this.strings=n;}setValue(t){this.__pendingValue=t;}commit(){for(;n(this.__pendingValue);){const t=this.__pendingValue;this.__pendingValue=r,t.isClass?t.body(this):t(this);}if(this.__pendingValue===r)return;const t=!!this.__pendingValue;this.value!==t&&(t?this.element.setAttribute(th
  1343. /**
  1344. * @license
  1345. * Copyright (c) 2017 The Polymer Project Authors. All rights reserved.
  1346. * This code may only be used under the BSD style license found at
  1347. * http://polymer.github.io/LICENSE.txt
  1348. * The complete set of authors may be found at
  1349. * http://polymer.github.io/AUTHORS.txt
  1350. * The complete set of contributors may be found at
  1351. * http://polymer.github.io/CONTRIBUTORS.txt
  1352. * Code distributed by Google as part of the polymer project is also
  1353. * subject to an additional IP rights grant found at
  1354. * http://polymer.github.io/PATENTS.txt
  1355. */class F{handleAttributeExpressions(t,e,n,s,o){const i=e[0];if("."===i){return new V(t,e.slice(1),n,o).parts}return "@"===i?[new D(t,e.slice(1),s.eventContext)]:"?"===i?[new C(t,e.slice(1),n)]:new X(t,e,n,o).parts}handleTextExpression(t,e){return new S(t,e)}}const B=new F;
  1356. /**
  1357. * @license
  1358. * Copyright (c) 2017 The Polymer Project Authors. All rights reserved.
  1359. * This code may only be used under the BSD style license found at
  1360. * http://polymer.github.io/LICENSE.txt
  1361. * The complete set of authors may be found at
  1362. * http://polymer.github.io/AUTHORS.txt
  1363. * The complete set of contributors may be found at
  1364. * http://polymer.github.io/CONTRIBUTORS.txt
  1365. * Code distributed by Google as part of the polymer project is also
  1366. * subject to an additional IP rights grant found at
  1367. * http://polymer.github.io/PATENTS.txt
  1368. */function W(t){let e=$.get(t.type);void 0===e&&(e={stringsArray:new WeakMap,keyString:new Map},$.set(t.type,e));let n=e.stringsArray.get(t.strings);if(void 0!==n)return n;const s=t.strings.join(l);return n=e.keyString.get(s),void 0===n&&(n=new p(t,t.getTemplateElement()),e.keyString.set(s,n)),e.stringsArray.set(t.strings,n),n}const $=new Map,H=new WeakMap,R=(t,e,n)=>{let s=H.get(e);void 0===s&&(i(e,e.firstChild),H.set(e,s=new S(Object.assign({templateFactory:W},n),void 0)),s.appendInto(e)),s.setValue(t),s.commit();};
  1369. /**
  1370. * @license
  1371. * Copyright (c) 2017 The Polymer Project Authors. All rights reserved.
  1372. * This code may only be used under the BSD style license found at
  1373. * http://polymer.github.io/LICENSE.txt
  1374. * The complete set of authors may be found at
  1375. * http://polymer.github.io/AUTHORS.txt
  1376. * The complete set of contributors may be found at
  1377. * http://polymer.github.io/CONTRIBUTORS.txt
  1378. * Code distributed by Google as part of the polymer project is also
  1379. * subject to an additional IP rights grant found at
  1380. * http://polymer.github.io/PATENTS.txt
  1381. */"undefined"!=typeof window&&(window.litHtmlVersions||(window.litHtmlVersions=[])).push("1.1.7");const O=(t,...e)=>new w(t,e,"html",B),U=(t,...e)=>new N(t,e,"svg",B);var j=Object.freeze({__proto__:null,html:O,svg:U,DefaultTemplateProcessor:F,defaultTemplateProcessor:B,directive:t,Directive:e,isDirective:n,removeNodes:i,reparentNodes:o,noChange:r,nothing:a,AttributeCommitter:X,AttributePart:I,BooleanAttributePart:C,EventPart:D,isIterable:P,isPrimitive:E,NodePart:S,PropertyCommitter:V,PropertyPart:L,get sanitizerFactory(){return M},setSanitizerFactory:t=>{if(M!==T)throw new Error("Attempted to overwrite existing lit-html security policy. setSanitizeDOMValueFactory should be called at most once.");M=t;},parts:H,render:R,templateCaches:$,templateFactory:W,TemplateInstance:y,SVGTemplateResult:N,TemplateResult:w,createMarker:f,isTemplatePartActive:m,Template:p});
  1382. const mt=document.createElement("template");
  1383. class Nt{constructor(){this.isAction=!0;}}Nt.prototype.isAction=!0;const Et={element:document.createTextNode(""),axis:"xy",threshold:10,onDown(t){},onMove(t){},onUp(t){},onWheel(t){}};
  1384. /**
  1385. * CalendarScroll plugin
  1386. *
  1387. * @copyright Rafal Pospiech <https://neuronet.io>
  1388. * @author Rafal Pospiech <neuronet.io@gmail.com>
  1389. * @package gantt-schedule-timeline-calendar
  1390. * @license AGPL-3.0 (https://github.com/neuronetio/gantt-schedule-timeline-calendar/blob/master/LICENSE)
  1391. * @link https://github.com/neuronetio/gantt-schedule-timeline-calendar
  1392. */
  1393. function CalendarScroll(options = {}) {
  1394. let state, api, update;
  1395. const defaultOptions = {
  1396. speed: 0.25,
  1397. hideScroll: false,
  1398. onChange(time) { }
  1399. };
  1400. options = Object.assign(Object.assign({}, defaultOptions), options);
  1401. class CalendarScrollAction extends Nt {
  1402. constructor(element) {
  1403. super();
  1404. this.isMoving = false;
  1405. this.lastX = 0;
  1406. this.collectLowerThanZero = 0;
  1407. this.onPointerStart = this.onPointerStart.bind(this);
  1408. this.onPointerMove = this.onPointerMove.bind(this);
  1409. this.onPointerEnd = this.onPointerEnd.bind(this);
  1410. element.addEventListener('touchstart', this.onPointerStart);
  1411. document.addEventListener('touchmove', this.onPointerMove);
  1412. document.addEventListener('touchend', this.onPointerEnd);
  1413. element.addEventListener('mousedown', this.onPointerStart);
  1414. document.addEventListener('mousemove', this.onPointerMove);
  1415. document.addEventListener('mouseup', this.onPointerEnd);
  1416. element.style.cursor = 'move';
  1417. const horizontalScroll = state.get('_internal.elements.horizontal-scroll');
  1418. // @ts-ignore
  1419. if (options.hideScroll && horizontalScroll) {
  1420. horizontalScroll.style.visibility = 'hidden';
  1421. }
  1422. }
  1423. onPointerStart(ev) {
  1424. if (ev.type === 'mousedown' && ev.button !== 0)
  1425. return;
  1426. ev.stopPropagation();
  1427. this.isMoving = true;
  1428. const normalized = api.normalizePointerEvent(ev);
  1429. this.lastX = normalized.x;
  1430. }
  1431. onPointerMove(ev) {
  1432. if (!this.isMoving)
  1433. return;
  1434. const normalized = api.normalizePointerEvent(ev);
  1435. const movedX = normalized.x - this.lastX;
  1436. let finalMovement = movedX * options.speed;
  1437. if (Math.abs(finalMovement) >= 1) {
  1438. finalMovement = Math.round(finalMovement);
  1439. state.update('config.chart.time', time => {
  1440. let centerTime = api.time
  1441. .date(time.centerGlobal)
  1442. .add(finalMovement * -1, time.period)
  1443. .valueOf();
  1444. const movedTime = centerTime - time.centerGlobal;
  1445. time.leftGlobal += movedTime;
  1446. time.centerGlobal = centerTime;
  1447. time.rightGlobal += movedTime;
  1448. time.from += movedTime;
  1449. time.to += movedTime;
  1450. options.onChange(time);
  1451. return time;
  1452. });
  1453. this.lastX = normalized.x;
  1454. }
  1455. }
  1456. onPointerEnd() {
  1457. this.isMoving = false;
  1458. this.lastX = 0;
  1459. }
  1460. destroy(element, data) {
  1461. element.removeEventListener('touchstart', this.onPointerStart);
  1462. document.removeEventListener('touchmove', this.onPointerMove);
  1463. document.removeEventListener('touchend', this.onPointerEnd);
  1464. element.removeEventListener('mousedown', this.onPointerStart);
  1465. document.removeEventListener('mousemove', this.onPointerMove);
  1466. document.removeEventListener('mouseup', this.onPointerEnd);
  1467. }
  1468. }
  1469. return function initialize(vido) {
  1470. api = vido.api;
  1471. state = vido.state;
  1472. update = vido.update;
  1473. state.update('config.actions.chart-calendar', actions => {
  1474. actions.push(CalendarScrollAction);
  1475. return actions;
  1476. });
  1477. };
  1478. }
  1479. /**
  1480. * Weekend highlight plugin
  1481. *
  1482. * @copyright Rafal Pospiech <https://neuronet.io>
  1483. * @author Rafal Pospiech <neuronet.io@gmail.com>
  1484. * @package gantt-schedule-timeline-calendar
  1485. * @license AGPL-3.0 (https://github.com/neuronetio/gantt-schedule-timeline-calendar/blob/master/LICENSE)
  1486. * @link https://github.com/neuronetio/gantt-schedule-timeline-calendar
  1487. */
  1488. function WeekendHiglight(options = {}) {
  1489. const weekdays = options.weekdays || [6, 0];
  1490. let className;
  1491. let api;
  1492. let enabled = true;
  1493. class WeekendHighlightAction extends Action {
  1494. constructor(element, data) {
  1495. super();
  1496. this.highlight(element, data.time.leftGlobal);
  1497. }
  1498. update(element, data) {
  1499. this.highlight(element, data.time.leftGlobal);
  1500. }
  1501. highlight(element, time) {
  1502. const hasClass = element.classList.contains(className);
  1503. if (!enabled) {
  1504. if (hasClass) {
  1505. element.classList.remove(className);
  1506. }
  1507. return;
  1508. }
  1509. const isWeekend = weekdays.includes(api.time.date(time).day());
  1510. if (!hasClass && isWeekend) {
  1511. element.classList.add(className);
  1512. }
  1513. else if (hasClass && !isWeekend) {
  1514. element.classList.remove(className);
  1515. }
  1516. }
  1517. }
  1518. return function initialize(vido) {
  1519. api = vido.api;
  1520. className = options.className || api.getClass('chart-timeline-grid-row-block') + '--weekend';
  1521. const destroy = vido.state.subscribe('_internal.chart.time.format.period', period => (enabled = period === 'day'));
  1522. vido.state.update('config.actions.chart-timeline-grid-row-block', actions => {
  1523. actions.push(WeekendHighlightAction);
  1524. return actions;
  1525. });
  1526. return function onDestroy() {
  1527. destroy();
  1528. };
  1529. };
  1530. }
  1531. var plugins = { ItemHold, ItemMovement, Selection, CalendarScroll, WeekendHighlight: WeekendHiglight };
  1532. export default plugins;
  1533. //# sourceMappingURL=plugins.js.map