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.

795 lines
36 KiB

5 years ago
  1. (function (global, factory) {
  2. typeof exports === 'object' && typeof module !== 'undefined' ? module.exports = factory() :
  3. typeof define === 'function' && define.amd ? define(factory) :
  4. (global = global || self, global.Selection = factory());
  5. }(this, (function () { 'use strict';
  6. /**
  7. * @license
  8. * Copyright (c) 2017 The Polymer Project Authors. All rights reserved.
  9. * This code may only be used under the BSD style license found at
  10. * http://polymer.github.io/LICENSE.txt
  11. * The complete set of authors may be found at
  12. * http://polymer.github.io/AUTHORS.txt
  13. * The complete set of contributors may be found at
  14. * http://polymer.github.io/CONTRIBUTORS.txt
  15. * Code distributed by Google as part of the polymer project is also
  16. * subject to an additional IP rights grant found at
  17. * http://polymer.github.io/PATENTS.txt
  18. */
  19. /**
  20. * @license
  21. * Copyright (c) 2017 The Polymer Project Authors. All rights reserved.
  22. * This code may only be used under the BSD style license found at
  23. * http://polymer.github.io/LICENSE.txt
  24. * The complete set of authors may be found at
  25. * http://polymer.github.io/AUTHORS.txt
  26. * The complete set of contributors may be found at
  27. * http://polymer.github.io/CONTRIBUTORS.txt
  28. * Code distributed by Google as part of the polymer project is also
  29. * subject to an additional IP rights grant found at
  30. * http://polymer.github.io/PATENTS.txt
  31. */
  32. /**
  33. * An expression marker with embedded unique key to avoid collision with
  34. * possible text in templates.
  35. */
  36. const marker = `{{lit-${String(Math.random()).slice(2)}}}`;
  37. /**
  38. * Used to clone existing node instead of each time creating new one which is
  39. * slower
  40. */
  41. const markerNode = document.createComment('');
  42. /**
  43. * Used to clone existing node instead of each time creating new one which is
  44. * slower
  45. */
  46. const emptyTemplateNode = document.createElement('template');
  47. /**
  48. * Used to clone text node instead of each time creating new one which is slower
  49. */
  50. const emptyTextNode = document.createTextNode('');
  51. // Detect event listener options support. If the `capture` property is read
  52. // from the options object, then options are supported. If not, then the third
  53. // argument to add/removeEventListener is interpreted as the boolean capture
  54. // value so we should only pass the `capture` property.
  55. let eventOptionsSupported = false;
  56. // Wrap into an IIFE because MS Edge <= v41 does not support having try/catch
  57. // blocks right into the body of a module
  58. (() => {
  59. try {
  60. const options = {
  61. get capture() {
  62. eventOptionsSupported = true;
  63. return false;
  64. }
  65. };
  66. // eslint-disable-next-line @typescript-eslint/no-explicit-any
  67. window.addEventListener('test', options, options);
  68. // eslint-disable-next-line @typescript-eslint/no-explicit-any
  69. window.removeEventListener('test', options, options);
  70. }
  71. catch (_e) {
  72. // noop
  73. }
  74. })();
  75. /**
  76. * @license
  77. * Copyright (c) 2017 The Polymer Project Authors. All rights reserved.
  78. * This code may only be used under the BSD style license found at
  79. * http://polymer.github.io/LICENSE.txt
  80. * The complete set of authors may be found at
  81. * http://polymer.github.io/AUTHORS.txt
  82. * The complete set of contributors may be found at
  83. * http://polymer.github.io/CONTRIBUTORS.txt
  84. * Code distributed by Google as part of the polymer project is also
  85. * subject to an additional IP rights grant found at
  86. * http://polymer.github.io/PATENTS.txt
  87. */
  88. // IMPORTANT: do not change the property name or the assignment expression.
  89. // This line will be used in regexes to search for lit-html usage.
  90. // TODO(justinfagnani): inject version number at build time
  91. const isBrowser = typeof window !== 'undefined';
  92. if (isBrowser) {
  93. // If we run in the browser set version
  94. (window['litHtmlVersions'] || (window['litHtmlVersions'] = [])).push('1.1.7');
  95. }
  96. /**
  97. * Used to clone existing node instead of each time creating new one which is
  98. * slower
  99. */
  100. const emptyTemplateNode$1 = document.createElement('template');
  101. class Action {
  102. constructor() {
  103. this.isAction = true;
  104. }
  105. }
  106. Action.prototype.isAction = true;
  107. const defaultOptions = {
  108. element: document.createTextNode(''),
  109. axis: 'xy',
  110. threshold: 10,
  111. onDown(data) { },
  112. onMove(data) { },
  113. onUp(data) { },
  114. onWheel(data) { }
  115. };
  116. /**
  117. * Selection plugin
  118. *
  119. * @copyright Rafal Pospiech <https://neuronet.io>
  120. * @author Rafal Pospiech <neuronet.io@gmail.com>
  121. * @package gantt-schedule-timeline-calendar
  122. * @license AGPL-3.0 (https://github.com/neuronetio/gantt-schedule-timeline-calendar/blob/master/LICENSE)
  123. * @link https://github.com/neuronetio/gantt-schedule-timeline-calendar
  124. */
  125. function Selection(options = {}) {
  126. let vido, state, api, schedule;
  127. const pluginPath = 'config.plugin.selection';
  128. const rectClassName = 'gantt-schedule-timeline-caledar__plugin-selection-rect';
  129. const rect = document.createElement('div');
  130. rect.classList.add(rectClassName);
  131. rect.style.visibility = 'hidden';
  132. rect.style.left = '0px';
  133. rect.style.top = '0px';
  134. rect.style.width = '0px';
  135. rect.style.height = '0px';
  136. rect.style.background = 'rgba(0, 119, 192, 0.2)';
  137. rect.style.border = '2px dashed rgba(0, 119, 192, 0.75)';
  138. rect.style.position = 'absolute';
  139. rect.style['user-select'] = 'none';
  140. rect.style['pointer-events'] = 'none';
  141. const defaultOptions = {
  142. grid: false,
  143. items: true,
  144. rows: false,
  145. horizontal: true,
  146. vertical: true,
  147. rectStyle: {},
  148. selecting() { },
  149. deselecting() { },
  150. selected() { },
  151. deselected() { },
  152. canSelect(type, currently, all) {
  153. return currently;
  154. },
  155. canDeselect(type, currently, all) {
  156. return [];
  157. },
  158. getApi() { }
  159. };
  160. options = Object.assign(Object.assign({}, defaultOptions), options);
  161. for (const styleProp in options.rectStyle) {
  162. rect.style[styleProp] = options.rectStyle[styleProp];
  163. }
  164. const selecting = {
  165. fromX: -1,
  166. fromY: -1,
  167. toX: -1,
  168. toY: -1,
  169. startX: -1,
  170. startY: -1,
  171. startCell: false,
  172. selecting: false
  173. };
  174. const selectionTypesIdGetters = {
  175. 'chart-timeline-grid-row': props => props.row.id,
  176. 'chart-timeline-grid-row-block': props => props.id,
  177. 'chart-timeline-items-row': props => props.row.id,
  178. 'chart-timeline-items-row-item': props => props.item.id
  179. };
  180. function getEmptyContainer() {
  181. return {
  182. 'chart-timeline-grid-rows': [],
  183. 'chart-timeline-grid-row-blocks': [],
  184. 'chart-timeline-items-rows': [],
  185. 'chart-timeline-items-row-items': []
  186. };
  187. }
  188. function markSelecting(nowSelecting, addToPrevious = false) {
  189. if (addToPrevious) {
  190. state.update(`${pluginPath}.selecting`, selecting => {
  191. for (const name in selecting) {
  192. nowSelecting[name].forEach(id => {
  193. if (!selecting[name].includes()) {
  194. selecting[name].push(id);
  195. }
  196. });
  197. }
  198. return selecting;
  199. });
  200. }
  201. else {
  202. state.update(`${pluginPath}.selecting`, nowSelecting);
  203. }
  204. state.update('config.chart.items', function updateItems(items) {
  205. const now = nowSelecting['chart-timeline-items-row-items'];
  206. for (const itemId in items) {
  207. const item = items[itemId];
  208. if (now.includes(item.id)) {
  209. item.selecting = true;
  210. }
  211. else {
  212. item.selecting = false;
  213. }
  214. }
  215. return items;
  216. }, { only: ['selecting'] });
  217. state.update('_internal.chart.grid.rowsWithBlocks', function updateRowsWithBlocks(rowsWithBlocks) {
  218. const nowBlocks = nowSelecting['chart-timeline-grid-row-blocks'];
  219. const nowRows = nowSelecting['chart-timeline-grid-rows'];
  220. if (rowsWithBlocks)
  221. for (const row of rowsWithBlocks) {
  222. if (nowRows.includes(row.id)) {
  223. row.selecting = true;
  224. }
  225. else {
  226. row.selecting = false;
  227. }
  228. for (const block of row.blocks) {
  229. if (nowBlocks.includes(block.id)) {
  230. block.selecting = true;
  231. }
  232. else {
  233. block.selecting = false;
  234. }
  235. }
  236. }
  237. return rowsWithBlocks;
  238. });
  239. }
  240. /**
  241. * Clear selection
  242. * @param {boolean} clear
  243. */
  244. function clearSelection(clear = false, onlySelecting = false) {
  245. let selectingState;
  246. if (onlySelecting) {
  247. state.update(pluginPath, currently => {
  248. selectingState = {
  249. selecting: {
  250. 'chart-timeline-grid-rows': [],
  251. 'chart-timeline-grid-row-blocks': [],
  252. 'chart-timeline-items-rows': [],
  253. 'chart-timeline-items-row-items': []
  254. },
  255. selected: currently.selected
  256. };
  257. return selectingState;
  258. });
  259. }
  260. else {
  261. state.update(pluginPath, currently => {
  262. selectingState = {
  263. selecting: {
  264. 'chart-timeline-grid-rows': [],
  265. 'chart-timeline-grid-row-blocks': [],
  266. 'chart-timeline-items-rows': [],
  267. 'chart-timeline-items-row-items': []
  268. },
  269. selected: {
  270. 'chart-timeline-grid-rows': clear
  271. ? []
  272. : options.canDeselect('chart-timeline-grid-rows', currently.selected['chart-timeline-grid-rows'], currently),
  273. 'chart-timeline-grid-row-blocks': clear
  274. ? []
  275. : options.canDeselect('chart-timeline-grid-row-blocks', currently.selected['chart-timeline-grid-row-blocks'], currently),
  276. 'chart-timeline-items-rows': clear
  277. ? []
  278. : options.canDeselect('chart-timeline-items-rows', currently.selected['chart-timeline-items-rows'], currently),
  279. 'chart-timeline-items-row-items': clear
  280. ? []
  281. : options.canDeselect('chart-timeline-items-row-items', currently.selected['chart-timeline-items-row-items'], currently)
  282. }
  283. };
  284. return selectingState;
  285. });
  286. state.update('_internal.chart.grid.rowsWithBlocks', function clearRowsWithBlocks(rowsWithBlocks) {
  287. if (rowsWithBlocks)
  288. for (const row of rowsWithBlocks) {
  289. for (const block of row.blocks) {
  290. block.selected = selectingState.selected['chart-timeline-grid-row-blocks'].includes(block.id);
  291. block.selecting = false;
  292. }
  293. }
  294. return rowsWithBlocks;
  295. });
  296. state.update('config.chart.items', items => {
  297. if (items) {
  298. for (const itemId in items) {
  299. const item = items[itemId];
  300. item.selected = selectingState.selected['chart-timeline-items-row-items'].includes(itemId);
  301. item.selecting = false;
  302. }
  303. }
  304. return items;
  305. });
  306. }
  307. }
  308. let previousSelect;
  309. function markSelected(addToPrevious = false) {
  310. selecting.selecting = false;
  311. rect.style.visibility = 'hidden';
  312. const currentSelect = cloneSelection(state.get(pluginPath));
  313. const select = {};
  314. if (addToPrevious) {
  315. state.update(pluginPath, value => {
  316. const selected = Object.assign({}, value.selecting);
  317. for (const name in value.selected) {
  318. for (const id of selected[name]) {
  319. if (!value.selected[name].includes(id)) {
  320. value.selected[name].push(id);
  321. }
  322. }
  323. }
  324. select.selected = Object.assign({}, value.selected);
  325. select.selecting = getEmptyContainer();
  326. return select;
  327. });
  328. }
  329. else {
  330. state.update(pluginPath, value => {
  331. select.selected = Object.assign({}, value.selecting);
  332. select.selecting = getEmptyContainer();
  333. return select;
  334. });
  335. }
  336. const elements = state.get('_internal.elements');
  337. for (const type in selectionTypesIdGetters) {
  338. if (elements[type + 's'])
  339. for (const element of elements[type + 's']) {
  340. if (currentSelect.selecting[type + 's'].includes(element.vido.id)) {
  341. options.deselecting(element.vido, type);
  342. }
  343. }
  344. }
  345. state.update('config.chart.items', function updateItems(items) {
  346. for (const itemId in items) {
  347. const item = items[itemId];
  348. if (currentSelect.selecting['chart-timeline-items-row-items'].includes(item.id)) {
  349. item.selected = true;
  350. if (typeof item.selected === 'undefined' || !item.selected) {
  351. options.selected(item, 'chart-timeline-items-row-item');
  352. }
  353. }
  354. else if (addToPrevious && previousSelect.selected['chart-timeline-items-row-items'].includes(item.id)) {
  355. item.selected = true;
  356. }
  357. else {
  358. item.selected = false;
  359. if (currentSelect.selected['chart-timeline-items-row-items'].includes(item.id)) {
  360. options.deselected(item, 'chart-timeline-items-row-item');
  361. }
  362. }
  363. }
  364. return items;
  365. });
  366. state.update('_internal.chart.grid.rowsWithBlocks', function updateRowsWithBlocks(rowsWithBlocks) {
  367. if (rowsWithBlocks)
  368. for (const row of rowsWithBlocks) {
  369. for (const block of row.blocks) {
  370. if (currentSelect.selecting['chart-timeline-grid-row-blocks'].includes(block.id)) {
  371. if (typeof block.selected === 'undefined' || !block.selected) {
  372. options.selected(block, 'chart-timeline-grid-row-block');
  373. }
  374. block.selected = true;
  375. }
  376. else if (addToPrevious && previousSelect.selected['chart-timeline-grid-row-blocks'].includes(block.id)) {
  377. block.selected = true;
  378. }
  379. else {
  380. if (currentSelect.selected['chart-timeline-grid-row-blocks'].includes(block.id)) {
  381. options.deselected(block, 'chart-timeline-grid-row-block');
  382. }
  383. block.selected = false;
  384. }
  385. }
  386. }
  387. return rowsWithBlocks;
  388. });
  389. }
  390. /**
  391. * Clone current selection state
  392. * @param {object} currentSelect
  393. * @returns {object} currentSelect cloned
  394. */
  395. function cloneSelection(currentSelect) {
  396. const result = {};
  397. result.selecting = Object.assign({}, currentSelect.selecting);
  398. result.selecting['chart-timeline-grid-rows'] = currentSelect.selecting['chart-timeline-grid-rows'].slice();
  399. result.selecting['chart-timeline-grid-row-blocks'] = currentSelect.selecting['chart-timeline-grid-row-blocks'].slice();
  400. result.selecting['chart-timeline-items-rows'] = currentSelect.selecting['chart-timeline-items-rows'].slice();
  401. result.selecting['chart-timeline-items-row-items'] = currentSelect.selecting['chart-timeline-items-row-items'].slice();
  402. result.selected = Object.assign({}, currentSelect.selected);
  403. result.selected['chart-timeline-grid-rows'] = currentSelect.selected['chart-timeline-grid-rows'].slice();
  404. result.selected['chart-timeline-grid-row-blocks'] = currentSelect.selected['chart-timeline-grid-row-blocks'].slice();
  405. result.selected['chart-timeline-items-rows'] = currentSelect.selected['chart-timeline-items-rows'].slice();
  406. result.selected['chart-timeline-items-row-items'] = currentSelect.selected['chart-timeline-items-row-items'].slice();
  407. return result;
  408. }
  409. /**
  410. * Selection action class
  411. */
  412. class SelectionAction extends Action {
  413. /**
  414. * Selection action constructor
  415. * @param {Element} element
  416. * @param {object|any} data
  417. */
  418. constructor(element, data) {
  419. super();
  420. const api = {};
  421. api.clearSelection = clearSelection;
  422. this.unsub = data.state.subscribeAll(['_internal.elements.chart-timeline', '_internal.chart.dimensions.width'], bulk => {
  423. const chartTimeline = state.get('_internal.elements.chart-timeline');
  424. if (chartTimeline === undefined)
  425. return;
  426. this.chartTimeline = chartTimeline;
  427. if (!this.chartTimeline.querySelector('.' + rectClassName)) {
  428. this.chartTimeline.insertAdjacentElement('beforeend', rect);
  429. }
  430. const bounding = this.chartTimeline.getBoundingClientRect();
  431. this.left = bounding.left;
  432. this.top = bounding.top;
  433. });
  434. /**
  435. * Save and swap coordinates if needed
  436. * @param {MouseEvent} ev
  437. */
  438. const saveAndSwapIfNeeded = (ev) => {
  439. const normalized = vido.api.normalizePointerEvent(ev);
  440. const currentX = normalized.x - this.left;
  441. const currentY = normalized.y - this.top;
  442. if (currentX <= selecting.startX) {
  443. selecting.fromX = currentX;
  444. selecting.toX = selecting.startX;
  445. }
  446. else {
  447. selecting.fromX = selecting.startX;
  448. selecting.toX = currentX;
  449. }
  450. if (currentY <= selecting.startY) {
  451. selecting.fromY = currentY;
  452. selecting.toY = selecting.startY;
  453. }
  454. else {
  455. selecting.fromY = selecting.startY;
  456. selecting.toY = currentY;
  457. }
  458. };
  459. /**
  460. * Is rectangle inside other rectangle ?
  461. * @param {DOMRect} boundingRect
  462. * @param {DOMRect} rectBoundingRect
  463. * @returns {boolean}
  464. */
  465. const isInside = (boundingRect, rectBoundingRect) => {
  466. let horizontal = false;
  467. let vertical = false;
  468. if ((boundingRect.left > rectBoundingRect.left && boundingRect.left < rectBoundingRect.right) ||
  469. (boundingRect.right > rectBoundingRect.left && boundingRect.right < rectBoundingRect.right) ||
  470. (boundingRect.left <= rectBoundingRect.left && boundingRect.right >= rectBoundingRect.right)) {
  471. horizontal = true;
  472. }
  473. if ((boundingRect.top > rectBoundingRect.top && boundingRect.top < rectBoundingRect.bottom) ||
  474. (boundingRect.bottom > rectBoundingRect.top && boundingRect.bottom < rectBoundingRect.bottom) ||
  475. (boundingRect.top <= rectBoundingRect.top && boundingRect.bottom >= rectBoundingRect.bottom)) {
  476. vertical = true;
  477. }
  478. return horizontal && vertical;
  479. };
  480. /**
  481. * Get selecting elements
  482. * @param {DOMRect} rectBoundingRect
  483. * @param {Element[]} elements
  484. * @param {string} type
  485. * @returns {string[]}
  486. */
  487. function getSelecting(rectBoundingRect, elements, type, getId) {
  488. const selectingResult = [];
  489. const currentlySelectingData = [];
  490. const all = elements[type + 's'];
  491. if (!all)
  492. return [];
  493. const currentAll = state.get(pluginPath);
  494. const currentSelecting = currentAll.selecting[type + 's'];
  495. for (const element of all) {
  496. const boundingRect = element.getBoundingClientRect();
  497. if (isInside(boundingRect, rectBoundingRect)) {
  498. currentlySelectingData.push(element.vido);
  499. const canSelect = options.canSelect(type, currentlySelectingData, currentAll);
  500. if (canSelect.includes(element.vido)) {
  501. if (!currentSelecting.includes(getId(element.vido))) {
  502. options.selecting(element.vido, type);
  503. }
  504. selectingResult.push(getId(element.vido));
  505. }
  506. else {
  507. currentlySelectingData.unshift();
  508. }
  509. }
  510. else {
  511. if (currentSelecting.includes(getId(element.vido))) {
  512. options.deselecting(element.vido, type);
  513. }
  514. }
  515. }
  516. return selectingResult;
  517. }
  518. function trackSelection(ev, virtually = false) {
  519. const movement = state.get('config.plugin.ItemMovement.movement');
  520. const moving = movement && (movement.moving || movement.waiting);
  521. if (!selecting.selecting || moving) {
  522. if (moving) {
  523. selecting.selecting = false;
  524. }
  525. return;
  526. }
  527. clearSelection(false, true);
  528. saveAndSwapIfNeeded(ev);
  529. rect.style.left = selecting.fromX + 'px';
  530. rect.style.top = selecting.fromY + 'px';
  531. rect.style.width = selecting.toX - selecting.fromX + 'px';
  532. rect.style.height = selecting.toY - selecting.fromY + 'px';
  533. if (!virtually) {
  534. rect.style.visibility = 'visible';
  535. }
  536. const rectBoundingRect = rect.getBoundingClientRect();
  537. const elements = state.get('_internal.elements');
  538. const nowSelecting = {};
  539. for (const type in selectionTypesIdGetters) {
  540. nowSelecting[type + 's'] = getSelecting(rectBoundingRect, elements, type, selectionTypesIdGetters[type]);
  541. }
  542. markSelecting(nowSelecting, ev.ctrlKey);
  543. }
  544. /**
  545. * End select
  546. * @param {Event} ev
  547. */
  548. const endSelect = ev => {
  549. if (selecting.selecting) {
  550. ev.stopPropagation();
  551. ev.preventDefault();
  552. const normalized = vido.api.normalizePointerEvent(ev);
  553. if (selecting.startX === normalized.x - this.left && selecting.startY === normalized.y - this.top) {
  554. selecting.selecting = false;
  555. rect.style.visibility = 'hidden';
  556. return;
  557. }
  558. }
  559. else {
  560. const itemClass = '.gantt-schedule-timeline-calendar__chart-timeline-items-row-item';
  561. const isItem = !!ev.target.closest(itemClass);
  562. if (!isItem) {
  563. if (!ev.ctrlKey)
  564. clearSelection();
  565. }
  566. else {
  567. markSelected(ev.ctrlKey);
  568. }
  569. return;
  570. }
  571. markSelected(ev.ctrlKey);
  572. };
  573. /**
  574. * Mouse down event handler
  575. * @param {MouseEvent} ev
  576. */
  577. this.mouseDown = ev => {
  578. const movement = state.get('config.plugin.ItemMovement.movement');
  579. const moving = movement && movement.moving;
  580. if ((ev.type === 'mousedown' && ev.button !== 0) || moving) {
  581. return;
  582. }
  583. const normalized = vido.api.normalizePointerEvent(ev);
  584. selecting.selecting = true;
  585. selecting.fromX = normalized.x - this.left;
  586. selecting.fromY = normalized.y - this.top;
  587. selecting.startX = selecting.fromX;
  588. selecting.startY = selecting.fromY;
  589. previousSelect = cloneSelection(state.get(pluginPath));
  590. const itemClass = '.gantt-schedule-timeline-calendar__chart-timeline-items-row-item';
  591. const isItem = !!ev.target.closest(itemClass);
  592. if (!isItem) {
  593. if (!ev.ctrlKey)
  594. clearSelection();
  595. }
  596. };
  597. /**
  598. * Mouse move event handler
  599. * @param {MouseEvent} ev
  600. */
  601. this.mouseMove = ev => {
  602. trackSelection(ev);
  603. };
  604. /**
  605. * Mouse up event handler
  606. * @param {MouseEvent} ev
  607. */
  608. this.mouseUp = ev => {
  609. if (selecting.selecting) {
  610. endSelect(ev);
  611. }
  612. };
  613. element.addEventListener('mousedown', this.mouseDown);
  614. element.addEventListener('touchstart', this.mouseDown);
  615. document.addEventListener('mousemove', this.mouseMove);
  616. document.addEventListener('touchmove', this.mouseMove);
  617. document.addEventListener('mouseup', this.mouseUp);
  618. document.addEventListener('touchend', this.mouseUp);
  619. options.getApi(api);
  620. }
  621. destroy(element) {
  622. document.removeEventListener('mouseup', this.mouseUp);
  623. document.removeEventListener('touchend', this.mouseUp);
  624. document.removeEventListener('mousemove', this.mouseMove);
  625. document.removeEventListener('touchmove', this.mouseMove);
  626. element.removeEventListener('mousedown', this.mouseDown);
  627. element.removeEventListener('touchstart', this.mouseDown);
  628. this.unsub();
  629. }
  630. }
  631. /**
  632. * Update selection
  633. * @param {any} data
  634. * @param {HTMLElement} element
  635. * @param {boolean} selecting
  636. * @param {boolean} selected
  637. * @param {string} classNameSelecting
  638. * @param {string} classNameSelected
  639. */
  640. function updateSelection(element, selecting, selected, classNameSelecting, classNameSelected) {
  641. if (selecting && !element.classList.contains(classNameSelecting)) {
  642. element.classList.add(classNameSelecting);
  643. }
  644. else if (!selecting && element.classList.contains(classNameSelecting)) {
  645. element.classList.remove(classNameSelecting);
  646. }
  647. if (selected && !element.classList.contains(classNameSelected)) {
  648. element.classList.add(classNameSelected);
  649. }
  650. else if (!selected && element.classList.contains(classNameSelected)) {
  651. element.classList.remove(classNameSelected);
  652. }
  653. }
  654. /**
  655. * Grid row block action
  656. * @param {HTMLElement} element
  657. * @param {object} data
  658. * @returns {object} with update and destroy functions
  659. */
  660. class GridBlockAction extends Action {
  661. constructor(element, data) {
  662. super();
  663. this.classNameSelecting = api.getClass('chart-timeline-grid-row-block') + '--selecting';
  664. this.classNameSelected = api.getClass('chart-timeline-grid-row-block') + '--selected';
  665. updateSelection(element, data.selecting, data.selected, this.classNameSelecting, this.classNameSelected);
  666. }
  667. update(element, data) {
  668. updateSelection(element, data.selecting, data.selected, this.classNameSelecting, this.classNameSelected);
  669. }
  670. destroy(element, changedData) {
  671. element.classList.remove(this.classNameSelecting);
  672. element.classList.remove(this.classNameSelected);
  673. }
  674. }
  675. /**
  676. * Item action
  677. * @param {Element} element
  678. * @param {object} data
  679. * @returns {object} with update and destroy functions
  680. */
  681. class ItemAction extends Action {
  682. constructor(element, data) {
  683. super();
  684. this.data = data;
  685. this.element = element;
  686. this.classNameSelecting = api.getClass('chart-timeline-items-row-item') + '--selecting';
  687. this.classNameSelected = api.getClass('chart-timeline-items-row-item') + '--selected';
  688. this.data = data;
  689. this.element = element;
  690. this.onPointerDown = this.onPointerDown.bind(this);
  691. element.addEventListener('mousedown', this.onPointerDown);
  692. element.addEventListener('touchstart', this.onPointerDown);
  693. updateSelection(element, data.item.selecting, data.item.selected, this.classNameSelecting, this.classNameSelected);
  694. }
  695. onPointerDown(ev) {
  696. previousSelect = cloneSelection(state.get(pluginPath));
  697. selecting.selecting = true;
  698. this.data.item.selected = true;
  699. const container = getEmptyContainer();
  700. container['chart-timeline-items-row-items'].push(this.data.item.id);
  701. markSelecting(container);
  702. markSelected(ev.ctrlKey);
  703. updateSelection(this.element, this.data.item.selecting, this.data.item.selected, this.classNameSelecting, this.classNameSelected);
  704. }
  705. update(element, data) {
  706. updateSelection(element, data.item.selecting, data.item.selected, this.classNameSelecting, this.classNameSelected);
  707. this.data = data;
  708. }
  709. destroy(element, data) {
  710. element.classList.remove(this.classNameSelecting);
  711. element.classList.remove(this.classNameSelected);
  712. element.removeEventListener('mousedown', this.onPointerDown);
  713. element.removeEventListener('touchstart', this.onPointerDown);
  714. }
  715. }
  716. /**
  717. * On block create handler
  718. * @param {object} block
  719. * @returns {object} block
  720. */
  721. function onBlockCreate(block) {
  722. const selectedBlocks = state.get('config.plugin.selection.selected.chart-timeline-grid-row-blocks');
  723. for (const selectedBlock of selectedBlocks) {
  724. if (selectedBlock === block.id) {
  725. block.selected = true;
  726. return block;
  727. }
  728. }
  729. block.selected = false;
  730. block.selecting = false;
  731. return block;
  732. }
  733. return function initialize(mainVido) {
  734. vido = mainVido;
  735. state = vido.state;
  736. api = vido.api;
  737. schedule = vido.schedule;
  738. if (typeof state.get(pluginPath) === 'undefined') {
  739. state.update(pluginPath, {
  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: {
  747. 'chart-timeline-grid-rows': [],
  748. 'chart-timeline-grid-row-blocks': [],
  749. 'chart-timeline-items-rows': [],
  750. 'chart-timeline-items-row-items': []
  751. }
  752. });
  753. }
  754. state.update('config.chart.items', items => {
  755. if (items)
  756. for (const itemId in items) {
  757. const item = items[itemId];
  758. if (typeof item.selecting === 'undefined') {
  759. item.selecting = false;
  760. }
  761. if (typeof item.selected === 'undefined') {
  762. item.selected = false;
  763. }
  764. }
  765. return items;
  766. });
  767. state.update('config.actions.chart-timeline', actions => {
  768. actions.push(SelectionAction);
  769. return actions;
  770. });
  771. state.update('config.actions.chart-timeline-grid-row-block', actions => {
  772. actions.push(GridBlockAction);
  773. return actions;
  774. });
  775. state.update('config.actions.chart-timeline-items-row-item', actions => {
  776. actions.push(ItemAction);
  777. return actions;
  778. });
  779. state.update('config.chart.grid.block.onCreate', onCreate => {
  780. onCreate.push(onBlockCreate);
  781. return onCreate;
  782. });
  783. };
  784. }
  785. return Selection;
  786. })));
  787. //# sourceMappingURL=Selection.plugin.js.map