@progress/kendo-angular-gantt 0.3.0-dev.202201111723 → 0.3.0-dev.202201131518

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (98) hide show
  1. package/dist/cdn/js/kendo-angular-gantt.js +2 -2
  2. package/dist/cdn/main.js +4 -10
  3. package/dist/es/common/touch-enabled.js +9 -0
  4. package/dist/es/dependencies/utils.js +34 -0
  5. package/dist/es/dragging/dependency-drag-create.directive.js +347 -0
  6. package/dist/es/dragging/drag-validation-tooltip.component.js +27 -0
  7. package/dist/es/editing/{util.js → utils.js} +0 -0
  8. package/dist/es/gantt.component.js +125 -7
  9. package/dist/es/gantt.module.js +23 -6
  10. package/dist/es/index.js +4 -0
  11. package/dist/es/main.js +1 -0
  12. package/dist/es/models/events/dependency-add-event.interface.js +4 -0
  13. package/dist/es/models/view-item.interface.js +4 -0
  14. package/dist/es/package-metadata.js +1 -1
  15. package/dist/es/rendering/gantt-milestone-task.component.js +7 -4
  16. package/dist/es/rendering/gantt-summary-task.component.js +7 -4
  17. package/dist/es/rendering/gantt-task-base.js +30 -19
  18. package/dist/es/rendering/gantt-task.component.js +8 -6
  19. package/dist/es/rendering/gantt-tasks-table-body.component.js +5 -1
  20. package/dist/es/scrolling/drag-scroll-settings.js +20 -0
  21. package/dist/es/scrolling/timeline-scroll.directive.js +89 -0
  22. package/dist/es/scrolling/timeline-scroll.service.js +39 -0
  23. package/dist/es/scrolling/utils.js +80 -0
  24. package/dist/es/timeline/gantt-timeline.component.js +45 -3
  25. package/dist/es/utils.js +143 -12
  26. package/dist/es2015/common/touch-enabled.d.ts +9 -0
  27. package/dist/es2015/common/touch-enabled.js +9 -0
  28. package/dist/es2015/dependencies/utils.d.ts +15 -0
  29. package/dist/es2015/dependencies/utils.js +34 -0
  30. package/dist/es2015/dragging/dependency-drag-create.directive.d.ts +72 -0
  31. package/dist/es2015/dragging/dependency-drag-create.directive.js +324 -0
  32. package/dist/es2015/dragging/drag-validation-tooltip.component.d.ts +29 -0
  33. package/dist/es2015/dragging/drag-validation-tooltip.component.js +76 -0
  34. package/dist/es2015/editing/{util.d.ts → utils.d.ts} +0 -0
  35. package/dist/es2015/editing/{util.js → utils.js} +0 -0
  36. package/dist/es2015/gantt.component.d.ts +39 -3
  37. package/dist/es2015/gantt.component.js +117 -6
  38. package/dist/es2015/gantt.module.js +23 -6
  39. package/dist/es2015/index.d.ts +4 -0
  40. package/dist/es2015/index.js +4 -0
  41. package/dist/es2015/index.metadata.json +1 -1
  42. package/dist/es2015/main.d.ts +1 -0
  43. package/dist/es2015/main.js +1 -0
  44. package/dist/es2015/models/events/dependency-add-event.interface.d.ts +26 -0
  45. package/dist/es2015/models/events/dependency-add-event.interface.js +4 -0
  46. package/dist/es2015/models/models.d.ts +2 -0
  47. package/dist/es2015/models/view-item.interface.d.ts +35 -0
  48. package/dist/es2015/models/view-item.interface.js +4 -0
  49. package/dist/es2015/package-metadata.js +1 -1
  50. package/dist/es2015/rendering/gantt-milestone-task.component.d.ts +2 -1
  51. package/dist/es2015/rendering/gantt-milestone-task.component.js +18 -5
  52. package/dist/es2015/rendering/gantt-summary-task.component.d.ts +2 -1
  53. package/dist/es2015/rendering/gantt-summary-task.component.js +18 -5
  54. package/dist/es2015/rendering/gantt-task-base.d.ts +11 -5
  55. package/dist/es2015/rendering/gantt-task-base.js +30 -19
  56. package/dist/es2015/rendering/gantt-task.component.d.ts +2 -1
  57. package/dist/es2015/rendering/gantt-task.component.js +19 -7
  58. package/dist/es2015/rendering/gantt-tasks-table-body.component.d.ts +1 -0
  59. package/dist/es2015/rendering/gantt-tasks-table-body.component.js +10 -3
  60. package/dist/es2015/scrolling/drag-scroll-settings.d.ts +47 -0
  61. package/dist/es2015/scrolling/drag-scroll-settings.js +20 -0
  62. package/dist/es2015/scrolling/timeline-scroll.directive.d.ts +24 -0
  63. package/dist/es2015/scrolling/timeline-scroll.directive.js +78 -0
  64. package/dist/es2015/scrolling/timeline-scroll.service.d.ts +20 -0
  65. package/dist/es2015/scrolling/timeline-scroll.service.js +44 -0
  66. package/dist/es2015/scrolling/utils.d.ts +29 -0
  67. package/dist/es2015/scrolling/utils.js +80 -0
  68. package/dist/es2015/timeline/gantt-timeline.component.d.ts +25 -2
  69. package/dist/es2015/timeline/gantt-timeline.component.js +56 -3
  70. package/dist/es2015/utils.d.ts +70 -8
  71. package/dist/es2015/utils.js +143 -12
  72. package/dist/fesm2015/index.js +1337 -372
  73. package/dist/fesm5/index.js +1206 -298
  74. package/dist/npm/common/touch-enabled.js +11 -0
  75. package/dist/npm/dependencies/utils.js +34 -0
  76. package/dist/npm/dragging/dependency-drag-create.directive.js +349 -0
  77. package/dist/npm/dragging/drag-validation-tooltip.component.js +29 -0
  78. package/dist/npm/editing/{util.js → utils.js} +0 -0
  79. package/dist/npm/gantt.component.js +127 -9
  80. package/dist/npm/gantt.module.js +22 -5
  81. package/dist/npm/index.js +8 -0
  82. package/dist/npm/main.js +2 -0
  83. package/dist/npm/models/events/dependency-add-event.interface.js +6 -0
  84. package/dist/npm/models/view-item.interface.js +6 -0
  85. package/dist/npm/package-metadata.js +1 -1
  86. package/dist/npm/rendering/gantt-milestone-task.component.js +6 -3
  87. package/dist/npm/rendering/gantt-summary-task.component.js +6 -3
  88. package/dist/npm/rendering/gantt-task-base.js +30 -19
  89. package/dist/npm/rendering/gantt-task.component.js +7 -5
  90. package/dist/npm/rendering/gantt-tasks-table-body.component.js +5 -1
  91. package/dist/npm/scrolling/drag-scroll-settings.js +22 -0
  92. package/dist/npm/scrolling/timeline-scroll.directive.js +91 -0
  93. package/dist/npm/scrolling/timeline-scroll.service.js +41 -0
  94. package/dist/npm/scrolling/utils.js +83 -0
  95. package/dist/npm/timeline/gantt-timeline.component.js +44 -2
  96. package/dist/npm/utils.js +143 -12
  97. package/dist/systemjs/kendo-angular-gantt.js +1 -1
  98. package/package.json +5 -4
@@ -3,25 +3,26 @@
3
3
  * Licensed under commercial license. See LICENSE.md in the project root for more information
4
4
  *-------------------------------------------------------------------------------------------*/
5
5
  import { __decorate, __metadata, __param } from 'tslib';
6
- import { Input, EventEmitter, Injectable, Directive, Optional, TemplateRef, QueryList, ContentChildren, ContentChild, Component, forwardRef, SkipSelf, Host, Injector, NgZone, isDevMode, ViewChild, HostBinding, Output, Renderer2, ElementRef, ChangeDetectorRef, NgModule } from '@angular/core';
6
+ import { Input, EventEmitter, Injectable, Directive, Optional, TemplateRef, QueryList, ContentChildren, ContentChild, Component, forwardRef, SkipSelf, Host, Injector, NgZone, ViewChild, ElementRef, ViewContainerRef, HostBinding, Output, Renderer2, isDevMode, InjectionToken, Inject, ChangeDetectorRef, NgModule } from '@angular/core';
7
7
  import { ColumnBase, ColumnComponent, ColumnGroupComponent, SpanColumnComponent, TreeListComponent, DataBoundTreeComponent, ExpandableTreeComponent, FlatBindingDirective, HierarchyBindingDirective, ExpandableDirective, TreeListModule } from '@progress/kendo-angular-treelist';
8
8
  import { cloneDate, addWeeks, firstDayInWeek, addDays, getDate, lastDayOfMonth, firstDayOfMonth, addMonths, isEqual, MS_PER_HOUR, MS_PER_DAY } from '@progress/kendo-date-math';
9
9
  import { of, Subject, Subscription, fromEvent, forkJoin, EMPTY, isObservable } from 'rxjs';
10
10
  import { validatePackage } from '@progress/kendo-licensing';
11
- import { isDocumentAvailable, closestInScope, matchesClasses, anyChanged, hasObservers, EventsModule } from '@progress/kendo-angular-common';
11
+ import { closestInScope, matchesClasses, isDocumentAvailable, anyChanged, hasObservers, EventsModule, DraggableModule } from '@progress/kendo-angular-common';
12
+ import { LocalizationService, ComponentMessages, L10N_PREFIX } from '@progress/kendo-angular-l10n';
12
13
  import { IntlService } from '@progress/kendo-angular-intl';
13
14
  import { orderBy } from '@progress/kendo-data-query';
14
- import { getter } from '@progress/kendo-common';
15
+ import { getter, touchEnabled } from '@progress/kendo-common';
15
16
  import { map, distinctUntilChanged, take, expand, reduce, filter, switchMap } from 'rxjs/operators';
16
- import { LocalizationService, ComponentMessages, L10N_PREFIX } from '@progress/kendo-angular-l10n';
17
17
  import { CommonModule } from '@angular/common';
18
+ import { FormArray, FormGroup, FormControl, Validators, ReactiveFormsModule } from '@angular/forms';
18
19
  import { SplitterModule, TabStripModule } from '@progress/kendo-angular-layout';
19
20
  import { ButtonsModule } from '@progress/kendo-angular-buttons';
20
21
  import { DialogModule } from '@progress/kendo-angular-dialog';
21
- import { FormArray, FormGroup, FormControl, Validators, ReactiveFormsModule } from '@angular/forms';
22
22
  import { LabelModule } from '@progress/kendo-angular-label';
23
23
  import { InputsModule } from '@progress/kendo-angular-inputs';
24
24
  import { DateInputsModule } from '@progress/kendo-angular-dateinputs';
25
+ import { PopupService, PopupModule } from '@progress/kendo-angular-popup';
25
26
  import { GridModule } from '@progress/kendo-angular-grid';
26
27
  import { DropDownsModule } from '@progress/kendo-angular-dropdowns';
27
28
 
@@ -32,7 +33,7 @@ const packageMetadata = {
32
33
  name: '@progress/kendo-angular-gantt',
33
34
  productName: 'Kendo UI for Angular',
34
35
  productCodes: ['KENDOUIANGULAR', 'KENDOUICOMPLETE'],
35
- publishDate: 1641921322,
36
+ publishDate: 1642086647,
36
37
  version: '',
37
38
  licensingDocsUrl: 'https://www.telerik.com/kendo-angular-ui/my-license/?utm_medium=product&utm_source=kendoangular&utm_campaign=kendo-ui-angular-purchase-license-keys-warning'
38
39
  };
@@ -634,6 +635,60 @@ const taskClassCallback = () => null;
634
635
  */
635
636
  const isSelected = () => false;
636
637
 
638
+ /**
639
+ * The dependency type when two tasks are connected.
640
+ *
641
+ * The supported values are:
642
+ * * `FF`—from 'finish' to 'finish'
643
+ * * `FS`—from 'finish' to 'start'
644
+ * * `SS`—from 'start' to 'start'
645
+ * * `SF`—from 'start' to 'finish'
646
+ */
647
+ var DependencyType;
648
+ (function (DependencyType) {
649
+ DependencyType[DependencyType["FF"] = 0] = "FF";
650
+ DependencyType[DependencyType["FS"] = 1] = "FS";
651
+ DependencyType[DependencyType["SF"] = 2] = "SF";
652
+ DependencyType[DependencyType["SS"] = 3] = "SS"; // task B can't start before task A starts
653
+ })(DependencyType || (DependencyType = {}));
654
+
655
+ /**
656
+ * @hidden
657
+ */
658
+ class PreventableEvent {
659
+ constructor() {
660
+ this.prevented = false;
661
+ }
662
+ /**
663
+ * Prevents the default action for a specified event.
664
+ * In this way, the source component suppresses
665
+ * the built-in behavior that follows the event.
666
+ */
667
+ preventDefault() {
668
+ this.prevented = true;
669
+ }
670
+ /**
671
+ * Returns `true` if the event was prevented
672
+ * by any of its subscribers.
673
+ *
674
+ * @returns `true` if the default action was prevented.
675
+ * Otherwise, returns `false`.
676
+ */
677
+ isDefaultPrevented() {
678
+ return this.prevented;
679
+ }
680
+ }
681
+
682
+ /**
683
+ * Called every time a user leaves an edited cell.
684
+ */
685
+ class CellCloseEvent extends PreventableEvent {
686
+ constructor(options) {
687
+ super();
688
+ Object.assign(this, options);
689
+ }
690
+ }
691
+
637
692
  /**
638
693
  * @hidden
639
694
  */
@@ -733,15 +788,34 @@ const isNumber = (contender) => typeof contender === 'number' && !isNaN(contende
733
788
  * @hidden
734
789
  */
735
790
  const isString = (contender) => typeof contender === 'string';
791
+ /**
792
+ * @hidden
793
+ *
794
+ * Gets the closest timeline task wrapper element from an event target.
795
+ * Restricts the search up to the provided parent element from the second param.
796
+ */
797
+ const getClosestTaskWrapper = (element, parentScope) => {
798
+ return closestInScope(element, matchesClasses('k-task-wrap'), parentScope);
799
+ };
800
+ /**
801
+ * @hidden
802
+ *
803
+ * Checks whether the queried item or its parent items has a `k-task-wrap` selector.
804
+ * Restricts the search up to the provided parent element from the second param.
805
+ */
806
+ const isTaskWrapper = (contender, parentScope) => {
807
+ const taskWrapper = closestInScope(contender, matchesClasses('k-task-wrap'), parentScope);
808
+ return isPresent(taskWrapper);
809
+ };
736
810
  /**
737
811
  * @hidden
738
812
  *
739
813
  * Gets the closest timeline task element index from an event target.
740
814
  * Uses the `data-task-index` attribute assigned to each task.
741
- * Restricts the search up to the provided gantt element from the second param.
815
+ * Restricts the search up to the provided parent element from the second param.
742
816
  */
743
- const getClosestTaskIndex = (element, gantt) => {
744
- const task = closestInScope(element, matchesClasses('k-task'), gantt);
817
+ const getClosestTaskIndex = (element, parentScope) => {
818
+ const task = closestInScope(element, matchesClasses('k-task-wrap'), parentScope);
745
819
  if (!isPresent(task)) {
746
820
  return null;
747
821
  }
@@ -751,22 +825,133 @@ const getClosestTaskIndex = (element, gantt) => {
751
825
  * @hidden
752
826
  *
753
827
  * Checks whether the queried item or its parent items has a `k-task` selector.
754
- * Restricts the search up to the provided gantt element from the second param.
828
+ * Restricts the search up to the provided parent element from the second param.
755
829
  */
756
- const isTask = (contender, gantt) => {
757
- const task = closestInScope(contender, matchesClasses('k-task'), gantt);
830
+ const isTask = (contender, parentScope) => {
831
+ const task = closestInScope(contender, matchesClasses('k-task'), parentScope);
758
832
  return isPresent(task);
759
833
  };
760
834
  /**
761
835
  * @hidden
762
836
  *
763
837
  * Checks whether the queried item or its parent items has a `k-task-actions` selector - used for the clear button.
764
- * Restricts the search up to the provided gantt element from the second param.
838
+ * Restricts the search up to the provided parent element from the second param.
765
839
  */
766
- const isClearButton = (contender, gantt) => {
767
- const clearButtonContainer = closestInScope(contender, matchesClasses('k-task-actions'), gantt);
840
+ const isClearButton = (contender, parentScope) => {
841
+ const clearButtonContainer = closestInScope(contender, matchesClasses('k-task-actions'), parentScope);
768
842
  return isPresent(clearButtonContainer);
769
843
  };
844
+ /**
845
+ * @hidden
846
+ *
847
+ * Checks whether the queried item has a `k-task-dot` selector - used for the dependency drag clues.
848
+ */
849
+ const isDependencyDragClue = (element) => {
850
+ if (!isPresent(element)) {
851
+ return false;
852
+ }
853
+ return element.classList.contains('k-task-dot');
854
+ };
855
+ /**
856
+ * @hidden
857
+ *
858
+ * Checks whether the queried item has a `k-task-dot` & `k-task-start` selector - used for the dependency drag start clues.
859
+ */
860
+ const isDependencyDragStartClue = (element) => {
861
+ if (!isPresent(element)) {
862
+ return false;
863
+ }
864
+ return element.classList.contains('k-task-dot') && element.classList.contains('k-task-start');
865
+ };
866
+ /**
867
+ * @hidden
868
+ *
869
+ * Gets the `DependencyType` for an attempted dependency create from the provided two elements.
870
+ * The two linked drag clue HTML elements are used to extract this data (via their CSS classes).
871
+ */
872
+ const getDependencyTypeFromTargetTasks = (fromTaskClue, toTaskClue) => {
873
+ if (!isDependencyDragClue(fromTaskClue) || !isDependencyDragClue(toTaskClue)) {
874
+ return null;
875
+ }
876
+ const fromTaskType = isDependencyDragStartClue(fromTaskClue) ? 'S' : 'F';
877
+ const toTaskType = isDependencyDragStartClue(toTaskClue) ? 'S' : 'F';
878
+ const dependencyTypeName = `${fromTaskType}${toTaskType}`;
879
+ switch (dependencyTypeName) {
880
+ case 'FF': return DependencyType.FF;
881
+ case 'FS': return DependencyType.FS;
882
+ case 'SF': return DependencyType.SF;
883
+ case 'SS': return DependencyType.SS;
884
+ default: return null;
885
+ }
886
+ };
887
+ /**
888
+ * @hidden
889
+ *
890
+ * Checks whether the two provided drag clues belong to the same task element.
891
+ */
892
+ const sameTaskClues = (fromTaskClue, toTaskClue, parentScope) => {
893
+ if (!isPresent(fromTaskClue) || !isPresent(toTaskClue)) {
894
+ return false;
895
+ }
896
+ const fromTaskWrapper = getClosestTaskWrapper(fromTaskClue, parentScope);
897
+ const toTaskWrapper = getClosestTaskWrapper(toTaskClue, parentScope);
898
+ return fromTaskWrapper === toTaskWrapper;
899
+ };
900
+ /**
901
+ * @hidden
902
+ *
903
+ * Fits a contender number between a min and max range.
904
+ * If the contender is below the min value, the min value is returned.
905
+ * If the contender is above the max value, the max value is returned.
906
+ */
907
+ const fitToRange = (contender, min, max) => {
908
+ if (contender > max) {
909
+ return max;
910
+ }
911
+ else if (contender < min) {
912
+ return min;
913
+ }
914
+ else {
915
+ return contender;
916
+ }
917
+ };
918
+ /**
919
+ * @hidden
920
+ *
921
+ * Checks whether either of the two provided tasks is a parent of the other.
922
+ */
923
+ const areParentChild = (taskA, taskB) => {
924
+ let parentChildRelationship = false;
925
+ let taskAParent = taskA;
926
+ while (isPresent(taskAParent) && isPresent(taskAParent.data)) {
927
+ if (taskAParent.data === taskB.data) {
928
+ parentChildRelationship = true;
929
+ break;
930
+ }
931
+ taskAParent = taskAParent.parent;
932
+ }
933
+ let taskBParent = taskB;
934
+ while (!parentChildRelationship && isPresent(taskBParent) && isPresent(taskBParent.data)) {
935
+ if (taskBParent.data === taskA.data) {
936
+ parentChildRelationship = true;
937
+ break;
938
+ }
939
+ taskBParent = taskBParent.parent;
940
+ }
941
+ return parentChildRelationship;
942
+ };
943
+ /**
944
+ * @hidden
945
+ *
946
+ * Extracts an element from the provided client coords.
947
+ * Using the `event.target` is not reliable under mobile devices with the current implementation of the draggable, so use this instead.
948
+ */
949
+ const elementFromPoint = (clientX, clientY) => {
950
+ if (!isDocumentAvailable()) {
951
+ return null;
952
+ }
953
+ return document.elementFromPoint(clientX, clientY);
954
+ };
770
955
 
771
956
  /**
772
957
  * @hidden
@@ -1419,6 +1604,61 @@ EditService = __decorate([
1419
1604
  __metadata("design:paramtypes", [MappingService])
1420
1605
  ], EditService);
1421
1606
 
1607
+ /**
1608
+ * @hidden
1609
+ *
1610
+ * Notifies the timeline-scroll.directive to scroll into view to requested coordinates.
1611
+ * The scrolling is performed based on client (viewport) coordinates.
1612
+ */
1613
+ let TimelineScrollService = class TimelineScrollService {
1614
+ /**
1615
+ * @hidden
1616
+ *
1617
+ * Notifies the timeline-scroll.directive to scroll into view to requested coordinates.
1618
+ * The scrolling is performed based on client (viewport) coordinates.
1619
+ */
1620
+ constructor() {
1621
+ this.horizontalScroll = new Subject();
1622
+ this.verticalScroll = new Subject();
1623
+ this.scrollCancel = new Subject();
1624
+ }
1625
+ ngOnDestroy() {
1626
+ this.horizontalScroll.complete();
1627
+ this.verticalScroll.complete();
1628
+ this.scrollCancel.complete();
1629
+ }
1630
+ requestHorizontalScroll(clientTop) {
1631
+ this.horizontalScroll.next(clientTop);
1632
+ }
1633
+ requestVerticalScroll(clientLeft) {
1634
+ this.verticalScroll.next(clientLeft);
1635
+ }
1636
+ requestScrollCancel() {
1637
+ this.scrollCancel.next();
1638
+ }
1639
+ };
1640
+ TimelineScrollService = __decorate([
1641
+ Injectable()
1642
+ ], TimelineScrollService);
1643
+
1644
+ /**
1645
+ * @hidden
1646
+ *
1647
+ * Needed to keep the Gantt's LocalizationService reference and be able to use it component's inside the TabStrip
1648
+ */
1649
+ let GanttLocalizationService = class GanttLocalizationService {
1650
+ constructor(localizationService) {
1651
+ this.localizationService = localizationService;
1652
+ }
1653
+ get(token) {
1654
+ return this.localizationService.get(token);
1655
+ }
1656
+ };
1657
+ GanttLocalizationService = __decorate([
1658
+ Injectable(),
1659
+ __metadata("design:paramtypes", [LocalizationService])
1660
+ ], GanttLocalizationService);
1661
+
1422
1662
  /**
1423
1663
  * @hidden
1424
1664
  */
@@ -1677,84 +1917,322 @@ ToolbarTemplateDirective = __decorate([
1677
1917
  ], ToolbarTemplateDirective);
1678
1918
 
1679
1919
  /**
1680
- * The base class for the column components of the Gantt.
1920
+ * @hidden
1681
1921
  */
1682
- class ViewBase {
1922
+ let GanttTimelineComponent = class GanttTimelineComponent {
1923
+ constructor(scrollSyncService, dependencyDomService, renderer, zone) {
1924
+ this.scrollSyncService = scrollSyncService;
1925
+ this.dependencyDomService = dependencyDomService;
1926
+ this.renderer = renderer;
1927
+ this.zone = zone;
1928
+ this.hostClass = true;
1929
+ this.dependencies = [];
1930
+ // as all drag-and-drop operations are on the timeline container, use a single draggable instance
1931
+ this.timelineContainerPress = new EventEmitter();
1932
+ this.timelineContainerDrag = new EventEmitter();
1933
+ this.timelineContainerRelease = new EventEmitter();
1934
+ this.subscriptions = new Subscription();
1935
+ this.subscriptions.add(
1936
+ // task changes indicates change in row content, number, height, etc.
1937
+ this.dependencyDomService.taskChanges
1938
+ .pipe(filter(args => isPresent(args.timelineRow)), switchMap(args => this.zone.onStable.pipe(take(1), map(() => args))) // ensure the content is rendered
1939
+ )
1940
+ .subscribe(({ timelineRow }) => {
1941
+ const timelineRowHeight = isDocumentAvailable() ? timelineRow.getBoundingClientRect().height : 0;
1942
+ this.renderer.setStyle(this.timelineColumns.nativeElement, 'height', `${(this.rows || []).length * timelineRowHeight}px`);
1943
+ }));
1944
+ }
1683
1945
  /**
1684
- *
1685
- * @hidden
1946
+ * Specifies whether the draggable will attach or detach its pointer event listeners.
1686
1947
  */
1687
- constructor(optionChangesService, dependencyDomService) {
1688
- this.optionChangesService = optionChangesService;
1689
- this.dependencyDomService = dependencyDomService;
1690
- /**
1691
- * The width of the time slot headers. Values are treated as pixels.
1692
- *
1693
- * @default 100
1694
- */
1695
- this.slotWidth = 100;
1948
+ get draggableEnabled() {
1949
+ return this.renderDependencyDragClues;
1696
1950
  }
1697
- ngOnChanges(changes) {
1698
- if (anyChanged(['slotWidth'], changes)) {
1699
- this.optionChangesService.notifyColumnChanges();
1700
- this.dependencyDomService.notifyChanges();
1701
- }
1951
+ ngAfterViewInit() {
1952
+ const timelineHeader = this.timelineHeaderWrap.nativeElement;
1953
+ const rightContainer = this.timelineContent.nativeElement;
1954
+ this.scrollSyncService.registerElement(rightContainer, 'timeline');
1955
+ this.scrollSyncService.registerElement(timelineHeader, 'header');
1956
+ this.dependencyDomService.registerContentContainer(this.tasksContainer.nativeElement);
1702
1957
  }
1703
- }
1704
- __decorate([
1705
- Input(),
1706
- __metadata("design:type", Number)
1707
- ], ViewBase.prototype, "slotWidth", void 0);
1708
-
1709
- /**
1710
- * @hidden
1711
- */
1712
- const getEditItem = (dataItem, data, mapper) => {
1713
- const treeListDataItem = data.find(item => mapper.extractFromTask(item.data, 'id') === mapper.extractFromTask(dataItem, 'id'));
1714
- return mapPath(treeListDataItem);
1715
- };
1716
- const mapPath = (item) => ({
1717
- dataItem: item.data,
1718
- parent: item.parent.data ? mapPath(item.parent) : null
1719
- });
1720
-
1721
- /**
1722
- * @hidden
1723
- *
1724
- * Needed to keep the Gantt's LocalizationService reference and be able to use it component's inside the TabStrip
1725
- */
1726
- let GanttLocalizationService = class GanttLocalizationService {
1727
- constructor(localizationService) {
1728
- this.localizationService = localizationService;
1958
+ ngOnDestroy() {
1959
+ this.subscriptions.unsubscribe();
1729
1960
  }
1730
- get(token) {
1731
- return this.localizationService.get(token);
1961
+ isNonWorking(item) {
1962
+ return item.hasOwnProperty('isWorking') && !item.isWorking;
1732
1963
  }
1733
1964
  };
1734
- GanttLocalizationService = __decorate([
1735
- Injectable(),
1736
- __metadata("design:paramtypes", [LocalizationService])
1737
- ], GanttLocalizationService);
1738
-
1739
- var GanttComponent_1;
1740
- const TREELIST_GROUP_COLUMNS_CLASS = 'k-gantt-treelist-nested-columns';
1741
- const DEFAULT_VIEW = 'week';
1742
- /**
1743
- * Represents the Kendo UI Gantt component for Angular.
1744
- *
1745
- * @example
1746
- * ```ts-preview
1747
- * _@Component({
1748
- * selector: 'my-app',
1749
- * template: `
1750
- * <kendo-gantt
1751
- * [style.height.px]="500"
1752
- * [kendoGanttHierarchyBinding]="data"
1753
- * childrenField="subtasks"
1754
- * [dependencies]="dependencies">
1755
- * <kendo-gantt-column
1756
- * field="title"
1757
- * title="Task"
1965
+ __decorate([
1966
+ ViewChild('timelineContent', { static: true }),
1967
+ __metadata("design:type", ElementRef)
1968
+ ], GanttTimelineComponent.prototype, "timelineContent", void 0);
1969
+ __decorate([
1970
+ ViewChild('timelineColumns', { static: true }),
1971
+ __metadata("design:type", ElementRef)
1972
+ ], GanttTimelineComponent.prototype, "timelineColumns", void 0);
1973
+ __decorate([
1974
+ ViewChild('timelineHeaderWrap', { static: true }),
1975
+ __metadata("design:type", ElementRef)
1976
+ ], GanttTimelineComponent.prototype, "timelineHeaderWrap", void 0);
1977
+ __decorate([
1978
+ ViewChild('tasksContainer', { static: true }),
1979
+ __metadata("design:type", ElementRef)
1980
+ ], GanttTimelineComponent.prototype, "tasksContainer", void 0);
1981
+ __decorate([
1982
+ ViewChild('dragPopupContainer', { static: false, read: ViewContainerRef }),
1983
+ __metadata("design:type", ViewContainerRef)
1984
+ ], GanttTimelineComponent.prototype, "dragPopupContainer", void 0);
1985
+ __decorate([
1986
+ ViewChild('dependencyDragCreatePolyline', { static: false }),
1987
+ __metadata("design:type", ElementRef)
1988
+ ], GanttTimelineComponent.prototype, "dependencyDragCreatePolyline", void 0);
1989
+ __decorate([
1990
+ HostBinding('class.k-gantt-timeline'),
1991
+ __metadata("design:type", Boolean)
1992
+ ], GanttTimelineComponent.prototype, "hostClass", void 0);
1993
+ __decorate([
1994
+ Input(),
1995
+ __metadata("design:type", Array)
1996
+ ], GanttTimelineComponent.prototype, "rows", void 0);
1997
+ __decorate([
1998
+ Input(),
1999
+ __metadata("design:type", Array)
2000
+ ], GanttTimelineComponent.prototype, "slots", void 0);
2001
+ __decorate([
2002
+ Input(),
2003
+ __metadata("design:type", Array)
2004
+ ], GanttTimelineComponent.prototype, "groupSlots", void 0);
2005
+ __decorate([
2006
+ Input(),
2007
+ __metadata("design:type", Number)
2008
+ ], GanttTimelineComponent.prototype, "tableWidth", void 0);
2009
+ __decorate([
2010
+ Input(),
2011
+ __metadata("design:type", String)
2012
+ ], GanttTimelineComponent.prototype, "activeView", void 0);
2013
+ __decorate([
2014
+ Input(),
2015
+ __metadata("design:type", TemplateRef)
2016
+ ], GanttTimelineComponent.prototype, "taskContentTemplate", void 0);
2017
+ __decorate([
2018
+ Input(),
2019
+ __metadata("design:type", TemplateRef)
2020
+ ], GanttTimelineComponent.prototype, "taskTemplate", void 0);
2021
+ __decorate([
2022
+ Input(),
2023
+ __metadata("design:type", TemplateRef)
2024
+ ], GanttTimelineComponent.prototype, "summaryTaskTemplate", void 0);
2025
+ __decorate([
2026
+ Input(),
2027
+ __metadata("design:type", Function)
2028
+ ], GanttTimelineComponent.prototype, "taskClass", void 0);
2029
+ __decorate([
2030
+ Input(),
2031
+ __metadata("design:type", Function)
2032
+ ], GanttTimelineComponent.prototype, "isTaskSelected", void 0);
2033
+ __decorate([
2034
+ Input(),
2035
+ __metadata("design:type", Boolean)
2036
+ ], GanttTimelineComponent.prototype, "renderDependencyDragClues", void 0);
2037
+ __decorate([
2038
+ Input(),
2039
+ __metadata("design:type", Object)
2040
+ ], GanttTimelineComponent.prototype, "dragScrollSettings", void 0);
2041
+ __decorate([
2042
+ Input(),
2043
+ __metadata("design:type", Function)
2044
+ ], GanttTimelineComponent.prototype, "hasChildren", void 0);
2045
+ __decorate([
2046
+ Input(),
2047
+ __metadata("design:type", Array)
2048
+ ], GanttTimelineComponent.prototype, "dependencies", void 0);
2049
+ __decorate([
2050
+ Output(),
2051
+ __metadata("design:type", EventEmitter)
2052
+ ], GanttTimelineComponent.prototype, "timelineContainerPress", void 0);
2053
+ __decorate([
2054
+ Output(),
2055
+ __metadata("design:type", EventEmitter)
2056
+ ], GanttTimelineComponent.prototype, "timelineContainerDrag", void 0);
2057
+ __decorate([
2058
+ Output(),
2059
+ __metadata("design:type", EventEmitter)
2060
+ ], GanttTimelineComponent.prototype, "timelineContainerRelease", void 0);
2061
+ GanttTimelineComponent = __decorate([
2062
+ Component({
2063
+ selector: 'kendo-gantt-timeline',
2064
+ template: `
2065
+ <div class="k-timeline k-grid k-widget">
2066
+ <div class="k-grid-header">
2067
+ <div #timelineHeaderWrap class="k-grid-header-wrap">
2068
+ <table
2069
+ role="presentation"
2070
+ [style.width.px]="tableWidth"
2071
+ >
2072
+ <tbody
2073
+ kendoGanttHeaderTableBody
2074
+ [groupSlots]="groupSlots"
2075
+ [slots]="slots">
2076
+ </tbody>
2077
+ </table>
2078
+ </div>
2079
+ </div>
2080
+ <div
2081
+ #timelineContent
2082
+ class="k-grid-content"
2083
+ kendoGanttTimelineScrollable
2084
+ [scrollSettings]="dragScrollSettings"
2085
+ kendoDraggable
2086
+ [enableDrag]="draggableEnabled"
2087
+ (kendoPress)="timelineContainerPress.emit($event)"
2088
+ (kendoDrag)="timelineContainerDrag.emit($event)"
2089
+ (kendoRelease)="timelineContainerRelease.emit($event)"
2090
+ >
2091
+ <div class="k-gantt-tables">
2092
+ <table
2093
+ class="k-gantt-rows"
2094
+ [style.width.px]="tableWidth"
2095
+ role="presentation"
2096
+ >
2097
+ <tbody>
2098
+ <tr *ngFor="let item of rows; let i = index;"
2099
+ [class.k-alt]="i % 2"
2100
+ >
2101
+ <td></td>
2102
+ </tr>
2103
+ </tbody>
2104
+ </table>
2105
+
2106
+ <table
2107
+ #timelineColumns
2108
+ class="k-gantt-columns"
2109
+ role="presentation"
2110
+ [style.width.px]="tableWidth"
2111
+ >
2112
+ <colgroup>
2113
+ <col *ngFor="let item of slots">
2114
+ </colgroup>
2115
+
2116
+ <tbody>
2117
+ <tr>
2118
+ <td *ngFor="let item of slots"
2119
+ [class.k-nonwork-hour]="isNonWorking(item)"
2120
+ >
2121
+ </td>
2122
+ </tr>
2123
+ </tbody>
2124
+ </table>
2125
+
2126
+ <table
2127
+ #tasksContainer
2128
+ class="k-gantt-tasks"
2129
+ role="presentation"
2130
+ style="border-collapse: collapse;"
2131
+ [style.width.px]="tableWidth"
2132
+ >
2133
+ <tbody
2134
+ kendoGanttTasksTableBody
2135
+ [rows]="rows"
2136
+ [activeView]="activeView"
2137
+ [taskContentTemplate]="taskContentTemplate"
2138
+ [taskTemplate]="taskTemplate"
2139
+ [summaryTaskTemplate]="summaryTaskTemplate"
2140
+ [taskClass]="taskClass"
2141
+ [hasChildren]="hasChildren"
2142
+ [isTaskSelected]="isTaskSelected"
2143
+ [renderDependencyDragClues]="renderDependencyDragClues"
2144
+ >
2145
+ </tbody>
2146
+ </table>
2147
+ </div>
2148
+ <svg class="k-gantt-dependencies-svg">
2149
+ <polyline
2150
+ *ngFor="let dependency of dependencies"
2151
+ kendoGanttDependency
2152
+ [dependency]="dependency"
2153
+ />
2154
+ <polyline #dependencyDragCreatePolyline />
2155
+ </svg>
2156
+
2157
+ <!-- placeholder for the dependency drag popup; its position is not arbitrary - the popup is intended to be absolutely positioned inside the .k-grid-content element -->
2158
+ <ng-container #dragPopupContainer></ng-container>
2159
+ </div>
2160
+ </div>
2161
+ `
2162
+ }),
2163
+ __metadata("design:paramtypes", [ScrollSyncService,
2164
+ DependencyDomService,
2165
+ Renderer2,
2166
+ NgZone])
2167
+ ], GanttTimelineComponent);
2168
+
2169
+ /**
2170
+ * The base class for the column components of the Gantt.
2171
+ */
2172
+ class ViewBase {
2173
+ /**
2174
+ *
2175
+ * @hidden
2176
+ */
2177
+ constructor(optionChangesService, dependencyDomService) {
2178
+ this.optionChangesService = optionChangesService;
2179
+ this.dependencyDomService = dependencyDomService;
2180
+ /**
2181
+ * The width of the time slot headers. Values are treated as pixels.
2182
+ *
2183
+ * @default 100
2184
+ */
2185
+ this.slotWidth = 100;
2186
+ }
2187
+ ngOnChanges(changes) {
2188
+ if (anyChanged(['slotWidth'], changes)) {
2189
+ this.optionChangesService.notifyColumnChanges();
2190
+ this.dependencyDomService.notifyChanges();
2191
+ }
2192
+ }
2193
+ }
2194
+ __decorate([
2195
+ Input(),
2196
+ __metadata("design:type", Number)
2197
+ ], ViewBase.prototype, "slotWidth", void 0);
2198
+
2199
+ /**
2200
+ * @hidden
2201
+ */
2202
+ const getEditItem = (dataItem, data, mapper) => {
2203
+ const treeListDataItem = data.find(item => mapper.extractFromTask(item.data, 'id') === mapper.extractFromTask(dataItem, 'id'));
2204
+ return mapPath(treeListDataItem);
2205
+ };
2206
+ const mapPath = (item) => ({
2207
+ dataItem: item.data,
2208
+ parent: item.parent.data ? mapPath(item.parent) : null
2209
+ });
2210
+
2211
+ var GanttComponent_1;
2212
+ const TREELIST_GROUP_COLUMNS_CLASS = 'k-gantt-treelist-nested-columns';
2213
+ const DEFAULT_VIEW = 'week';
2214
+ const DEFAULT_DRAG_SCROLL_SETTINGS = {
2215
+ enabled: true,
2216
+ step: 3,
2217
+ interval: 1,
2218
+ threshold: 10
2219
+ };
2220
+ /**
2221
+ * Represents the Kendo UI Gantt component for Angular.
2222
+ *
2223
+ * @example
2224
+ * ```ts-preview
2225
+ * _@Component({
2226
+ * selector: 'my-app',
2227
+ * template: `
2228
+ * <kendo-gantt
2229
+ * [style.height.px]="500"
2230
+ * [kendoGanttHierarchyBinding]="data"
2231
+ * childrenField="subtasks"
2232
+ * [dependencies]="dependencies">
2233
+ * <kendo-gantt-column
2234
+ * field="title"
2235
+ * title="Task"
1758
2236
  * [width]="200"
1759
2237
  * [expandable]="true"></kendo-gantt-column>
1760
2238
  * <kendo-gantt-column
@@ -1824,11 +2302,22 @@ let GanttComponent = GanttComponent_1 = class GanttComponent {
1824
2302
  this.zone = zone;
1825
2303
  this.hostClasses = true;
1826
2304
  /**
1827
- * Provides a callback that determines if the given task is selected ([see example]({% slug selection_gantt %}#toc-custom-selection))
2305
+ * Specifies a callback that determines if the given task is selected ([see example]({% slug selection_gantt %}#toc-custom-selection)).
1828
2306
  *
1829
2307
  * > The [`selectable`]({% slug api_gantt_ganttcomponent %}#toc-selectable) prop has to be set to `true` in order for this callback to be executed.
1830
2308
  */
1831
2309
  this.isSelected = isSelected;
2310
+ /**
2311
+ * Specifies a callback that determines if a new dependency is valid.
2312
+ * Used when evaluating if an attempt to create a new dependency will result in a valid link between the two tasks
2313
+ * [see example]({% slug editing_drag_create_dependencies_gantt %}#toc-validation).
2314
+ *
2315
+ * By defalut, dependencies are deemed invalid when:
2316
+ * - The two tasks are in a parent-child relationship.
2317
+ * - The two tasks are already dependent on one another. Only one dependency is allowed per pair.
2318
+ * - The start or end times of the two tasks are incompatible with the attempted dependency type.
2319
+ */
2320
+ this.validateNewDependency = this.defaultValidateNewDependencyCallback.bind(this);
1832
2321
  /**
1833
2322
  * Fires when the Gantt selection is changed through user interaction.
1834
2323
  *
@@ -1949,6 +2438,11 @@ let GanttComponent = GanttComponent_1 = class GanttComponent {
1949
2438
  * Fires when the user adds a task.
1950
2439
  */
1951
2440
  this.taskAdd = new EventEmitter();
2441
+ /**
2442
+ * Fires when the user adds a dependency via dragging
2443
+ * [see example]({% slug editing_drag_create_dependencies_gantt %}#toc-basic-concepts).
2444
+ */
2445
+ this.dependencyAdd = new EventEmitter();
1952
2446
  /**
1953
2447
  * Fires when the sorting of the Gantt is changed.
1954
2448
  * You have to handle the event yourself and sort the data.
@@ -2005,6 +2499,15 @@ let GanttComponent = GanttComponent_1 = class GanttComponent {
2005
2499
  * Fires when a task is clicked.
2006
2500
  */
2007
2501
  this.taskClick = new EventEmitter();
2502
+ /**
2503
+ * @hidden
2504
+ *
2505
+ * Specifies whether the dependency drag clues will be rendered.
2506
+ * Set internally by the dependency-drag-create directive.
2507
+ *
2508
+ * @default false
2509
+ */
2510
+ this.renderDependencyDragClues = false;
2008
2511
  /**
2009
2512
  * @hidden
2010
2513
  *
@@ -2021,6 +2524,7 @@ let GanttComponent = GanttComponent_1 = class GanttComponent {
2021
2524
  this.showConfirmationDialog = false;
2022
2525
  this._columns = new QueryList();
2023
2526
  this._data = [];
2527
+ this._dragScrollSettings = Object.assign({}, DEFAULT_DRAG_SCROLL_SETTINGS);
2024
2528
  this._timelinePaneOptions = Object.assign({}, DEFAULT_TIMELINE_PANE_SETTINGS);
2025
2529
  this._treeListPaneOptions = Object.assign({}, DEFAULT_TREELIST_PANE_SETTINGS);
2026
2530
  this._rowClass = rowClassCallback;
@@ -2236,6 +2740,17 @@ let GanttComponent = GanttComponent_1 = class GanttComponent {
2236
2740
  get taskIdField() {
2237
2741
  return this.mapper.taskFields.id;
2238
2742
  }
2743
+ /**
2744
+ * Specifies the settings for auto-scrolling during dragging
2745
+ * when the pointer moves outside of the container bounderies
2746
+ * [see example]({% slug editing_drag_create_dependencies_gantt %}#toc-auto-scrolling).
2747
+ */
2748
+ set dragScrollSettings(settings) {
2749
+ this._dragScrollSettings = Object.assign({}, DEFAULT_DRAG_SCROLL_SETTINGS, settings);
2750
+ }
2751
+ get dragScrollSettings() {
2752
+ return this._dragScrollSettings;
2753
+ }
2239
2754
  /**
2240
2755
  * @hidden
2241
2756
  */
@@ -2656,11 +3171,60 @@ let GanttComponent = GanttComponent_1 = class GanttComponent {
2656
3171
  const loadedItems = this.renderedTreeListItems || [];
2657
3172
  return loadedItems.find(isSelectedCallback);
2658
3173
  }
3174
+ defaultValidateNewDependencyCallback(dependency) {
3175
+ const fromTaskId = this.mapper.extractFromDependency(dependency, 'fromId');
3176
+ const toTaskId = this.mapper.extractFromDependency(dependency, 'toId');
3177
+ const fromTask = this.treeList.view.data.find(task => this.mapper.extractFromTask(task.data, 'id') === fromTaskId);
3178
+ const toTask = this.treeList.view.data.find(task => this.mapper.extractFromTask(task.data, 'id') === toTaskId);
3179
+ // mark as invalid if the attempted dependency is lacking valid from- and to-tasks
3180
+ // or when the from- and to-tasks are actually the same task
3181
+ if (!isPresent(fromTask) || !isPresent(fromTask.data) ||
3182
+ !isPresent(toTask) || !isPresent(toTask.data) ||
3183
+ fromTask.data === toTask.data) {
3184
+ return false;
3185
+ }
3186
+ const tasksDependentOnOneAnother = this.dependencies.some(current => {
3187
+ const currentFromId = this.mapper.extractFromDependency(current, 'fromId');
3188
+ const currentToId = this.mapper.extractFromDependency(current, 'toId');
3189
+ return (fromTaskId === currentFromId && toTaskId === currentToId) ||
3190
+ (toTaskId === currentFromId && fromTaskId === currentToId);
3191
+ });
3192
+ // mark as invalid if the attempted dependency is trying to connect already dependent tasks
3193
+ // mark as invalid if the two tasks are in parent-child relationship
3194
+ if (tasksDependentOnOneAnother || areParentChild(fromTask, toTask)) {
3195
+ return false;
3196
+ }
3197
+ const fromTaskStart = this.mapper.extractFromTask(fromTask.data, 'start');
3198
+ const fromTaskEnd = this.mapper.extractFromTask(fromTask.data, 'end');
3199
+ const toTaskStart = this.mapper.extractFromTask(toTask.data, 'start');
3200
+ const toTaskEnd = this.mapper.extractFromTask(toTask.data, 'end');
3201
+ // if the two tasks are available to be connected via a dependency,
3202
+ // check if their start and end time allow for the attempted dependency type
3203
+ switch (this.mapper.extractFromDependency(dependency, 'type')) {
3204
+ // finish to finish (FF) — the from-task ends before the to-task can end
3205
+ case DependencyType.FF:
3206
+ return fromTaskEnd <= toTaskEnd;
3207
+ // finish to start (FS) — the from-task ends before the to-task can begin
3208
+ case DependencyType.FS:
3209
+ return fromTaskEnd <= toTaskStart;
3210
+ // start to finish (SF) — the from-task begins before the to-task can end
3211
+ case DependencyType.SF:
3212
+ return fromTaskStart <= toTaskEnd;
3213
+ // start to start (SS) — the from-task begins before the to-task can begin
3214
+ case DependencyType.SS:
3215
+ return fromTaskStart <= toTaskStart;
3216
+ default: return false;
3217
+ }
3218
+ }
2659
3219
  };
2660
3220
  __decorate([
2661
3221
  ViewChild(TreeListComponent, { static: true }),
2662
3222
  __metadata("design:type", TreeListComponent)
2663
3223
  ], GanttComponent.prototype, "treeList", void 0);
3224
+ __decorate([
3225
+ ViewChild(GanttTimelineComponent, { static: false }),
3226
+ __metadata("design:type", GanttTimelineComponent)
3227
+ ], GanttComponent.prototype, "timeline", void 0);
2664
3228
  __decorate([
2665
3229
  ContentChild(GanttTaskContentTemplateDirective, { static: true }),
2666
3230
  __metadata("design:type", GanttTaskContentTemplateDirective)
@@ -2719,6 +3283,10 @@ __decorate([
2719
3283
  Input(),
2720
3284
  __metadata("design:type", Function)
2721
3285
  ], GanttComponent.prototype, "isSelected", void 0);
3286
+ __decorate([
3287
+ Input(),
3288
+ __metadata("design:type", Function)
3289
+ ], GanttComponent.prototype, "validateNewDependency", void 0);
2722
3290
  __decorate([
2723
3291
  Output(),
2724
3292
  __metadata("design:type", EventEmitter)
@@ -2818,6 +3386,11 @@ __decorate([
2818
3386
  Input(),
2819
3387
  __metadata("design:type", Boolean)
2820
3388
  ], GanttComponent.prototype, "columnsResizable", void 0);
3389
+ __decorate([
3390
+ Input(),
3391
+ __metadata("design:type", Object),
3392
+ __metadata("design:paramtypes", [Object])
3393
+ ], GanttComponent.prototype, "dragScrollSettings", null);
2821
3394
  __decorate([
2822
3395
  Output(),
2823
3396
  __metadata("design:type", EventEmitter)
@@ -2857,7 +3430,11 @@ __decorate([
2857
3430
  __decorate([
2858
3431
  Output(),
2859
3432
  __metadata("design:type", EventEmitter)
2860
- ], GanttComponent.prototype, "taskAdd", void 0);
3433
+ ], GanttComponent.prototype, "taskAdd", void 0);
3434
+ __decorate([
3435
+ Output(),
3436
+ __metadata("design:type", EventEmitter)
3437
+ ], GanttComponent.prototype, "dependencyAdd", void 0);
2861
3438
  __decorate([
2862
3439
  Output(),
2863
3440
  __metadata("design:type", EventEmitter)
@@ -2933,7 +3510,8 @@ GanttComponent = GanttComponent_1 = __decorate([
2933
3510
  DependencyDomService,
2934
3511
  MappingService,
2935
3512
  OptionChangesService,
2936
- EditService
3513
+ EditService,
3514
+ TimelineScrollService
2937
3515
  ],
2938
3516
  template: `
2939
3517
  <ng-container kendoGanttLocalizedMessages
@@ -3248,6 +3826,8 @@ GanttComponent = GanttComponent_1 = __decorate([
3248
3826
  [scrollable]="false">
3249
3827
  <kendo-gantt-timeline
3250
3828
  *ngIf="views && views.length"
3829
+ [renderDependencyDragClues]="renderDependencyDragClues"
3830
+ [dragScrollSettings]="dragScrollSettings"
3251
3831
  [rows]="renderedTreeListItems"
3252
3832
  [slots]="timelineSlots"
3253
3833
  [groupSlots]="timelineGroupSlots"
@@ -3311,199 +3891,7 @@ GanttComponent = GanttComponent_1 = __decorate([
3311
3891
  /**
3312
3892
  * @hidden
3313
3893
  */
3314
- let GanttTimelineComponent = class GanttTimelineComponent {
3315
- constructor(scrollSyncService, dependencyDomService, renderer, zone) {
3316
- this.scrollSyncService = scrollSyncService;
3317
- this.dependencyDomService = dependencyDomService;
3318
- this.renderer = renderer;
3319
- this.zone = zone;
3320
- this.hostClass = true;
3321
- this.dependencies = [];
3322
- this.subscriptions = new Subscription();
3323
- this.subscriptions.add(
3324
- // task changes indicates change in row content, number, height, etc.
3325
- this.dependencyDomService.taskChanges
3326
- .pipe(filter(args => isPresent(args.timelineRow)), switchMap(args => this.zone.onStable.pipe(take(1), map(() => args))) // ensure the content is rendered
3327
- )
3328
- .subscribe(({ timelineRow }) => {
3329
- const timelineRowHeight = isDocumentAvailable() ? timelineRow.getBoundingClientRect().height : 0;
3330
- this.renderer.setStyle(this.timelineColumns.nativeElement, 'height', `${(this.rows || []).length * timelineRowHeight}px`);
3331
- }));
3332
- }
3333
- ngAfterViewInit() {
3334
- const timelineHeader = this.timelineHeaderWrap.nativeElement;
3335
- const rightContainer = this.timelineContent.nativeElement;
3336
- this.scrollSyncService.registerElement(rightContainer, 'timeline');
3337
- this.scrollSyncService.registerElement(timelineHeader, 'header');
3338
- this.dependencyDomService.registerContentContainer(this.tasksContainer.nativeElement);
3339
- }
3340
- ngOnDestroy() {
3341
- this.subscriptions.unsubscribe();
3342
- }
3343
- isNonWorking(item) {
3344
- return item.hasOwnProperty('isWorking') && !item.isWorking;
3345
- }
3346
- };
3347
- __decorate([
3348
- ViewChild('timelineContent', { static: true }),
3349
- __metadata("design:type", ElementRef)
3350
- ], GanttTimelineComponent.prototype, "timelineContent", void 0);
3351
- __decorate([
3352
- ViewChild('timelineColumns', { static: true }),
3353
- __metadata("design:type", ElementRef)
3354
- ], GanttTimelineComponent.prototype, "timelineColumns", void 0);
3355
- __decorate([
3356
- ViewChild('timelineHeaderWrap', { static: true }),
3357
- __metadata("design:type", ElementRef)
3358
- ], GanttTimelineComponent.prototype, "timelineHeaderWrap", void 0);
3359
- __decorate([
3360
- ViewChild('tasksContainer', { static: true }),
3361
- __metadata("design:type", ElementRef)
3362
- ], GanttTimelineComponent.prototype, "tasksContainer", void 0);
3363
- __decorate([
3364
- HostBinding('class.k-gantt-timeline'),
3365
- __metadata("design:type", Boolean)
3366
- ], GanttTimelineComponent.prototype, "hostClass", void 0);
3367
- __decorate([
3368
- Input(),
3369
- __metadata("design:type", Array)
3370
- ], GanttTimelineComponent.prototype, "rows", void 0);
3371
- __decorate([
3372
- Input(),
3373
- __metadata("design:type", Array)
3374
- ], GanttTimelineComponent.prototype, "slots", void 0);
3375
- __decorate([
3376
- Input(),
3377
- __metadata("design:type", Array)
3378
- ], GanttTimelineComponent.prototype, "groupSlots", void 0);
3379
- __decorate([
3380
- Input(),
3381
- __metadata("design:type", Number)
3382
- ], GanttTimelineComponent.prototype, "tableWidth", void 0);
3383
- __decorate([
3384
- Input(),
3385
- __metadata("design:type", String)
3386
- ], GanttTimelineComponent.prototype, "activeView", void 0);
3387
- __decorate([
3388
- Input(),
3389
- __metadata("design:type", TemplateRef)
3390
- ], GanttTimelineComponent.prototype, "taskContentTemplate", void 0);
3391
- __decorate([
3392
- Input(),
3393
- __metadata("design:type", TemplateRef)
3394
- ], GanttTimelineComponent.prototype, "taskTemplate", void 0);
3395
- __decorate([
3396
- Input(),
3397
- __metadata("design:type", TemplateRef)
3398
- ], GanttTimelineComponent.prototype, "summaryTaskTemplate", void 0);
3399
- __decorate([
3400
- Input(),
3401
- __metadata("design:type", Function)
3402
- ], GanttTimelineComponent.prototype, "taskClass", void 0);
3403
- __decorate([
3404
- Input(),
3405
- __metadata("design:type", Function)
3406
- ], GanttTimelineComponent.prototype, "isTaskSelected", void 0);
3407
- __decorate([
3408
- Input(),
3409
- __metadata("design:type", Function)
3410
- ], GanttTimelineComponent.prototype, "hasChildren", void 0);
3411
- __decorate([
3412
- Input(),
3413
- __metadata("design:type", Array)
3414
- ], GanttTimelineComponent.prototype, "dependencies", void 0);
3415
- GanttTimelineComponent = __decorate([
3416
- Component({
3417
- selector: 'kendo-gantt-timeline',
3418
- template: `
3419
- <div class="k-timeline k-grid k-widget">
3420
- <div class="k-grid-header">
3421
- <div #timelineHeaderWrap class="k-grid-header-wrap">
3422
- <table
3423
- role="presentation"
3424
- [style.width.px]="tableWidth"
3425
- >
3426
- <tbody
3427
- kendoGanttHeaderTableBody
3428
- [groupSlots]="groupSlots"
3429
- [slots]="slots">
3430
- </tbody>
3431
- </table>
3432
- </div>
3433
- </div>
3434
- <div #timelineContent class="k-grid-content">
3435
- <div class="k-gantt-tables">
3436
- <table
3437
- class="k-gantt-rows"
3438
- [style.width.px]="tableWidth"
3439
- role="presentation"
3440
- >
3441
- <tbody>
3442
- <tr *ngFor="let item of rows; let i = index;"
3443
- [class.k-alt]="i % 2"
3444
- >
3445
- <td></td>
3446
- </tr>
3447
- </tbody>
3448
- </table>
3449
-
3450
- <table
3451
- #timelineColumns
3452
- class="k-gantt-columns"
3453
- role="presentation"
3454
- [style.width.px]="tableWidth"
3455
- >
3456
- <colgroup>
3457
- <col *ngFor="let item of slots">
3458
- </colgroup>
3459
-
3460
- <tbody>
3461
- <tr>
3462
- <td *ngFor="let item of slots"
3463
- [class.k-nonwork-hour]="isNonWorking(item)"
3464
- >
3465
- </td>
3466
- </tr>
3467
- </tbody>
3468
- </table>
3469
-
3470
- <table
3471
- #tasksContainer
3472
- class="k-gantt-tasks"
3473
- role="presentation"
3474
- style="border-collapse: collapse;"
3475
- [style.width.px]="tableWidth"
3476
- >
3477
- <tbody
3478
- kendoGanttTasksTableBody
3479
- [rows]="rows"
3480
- [activeView]="activeView"
3481
- [taskContentTemplate]="taskContentTemplate"
3482
- [taskTemplate]="taskTemplate"
3483
- [summaryTaskTemplate]="summaryTaskTemplate"
3484
- [taskClass]="taskClass"
3485
- [hasChildren]="hasChildren"
3486
- [isTaskSelected]="isTaskSelected"
3487
- >
3488
- </tbody>
3489
- </table>
3490
- </div>
3491
- <svg class="k-gantt-dependencies-svg">
3492
- <polyline
3493
- *ngFor="let dependency of dependencies"
3494
- kendoGanttDependency
3495
- [dependency]="dependency"
3496
- />
3497
- </svg>
3498
- </div>
3499
- </div>
3500
- `
3501
- }),
3502
- __metadata("design:paramtypes", [ScrollSyncService,
3503
- DependencyDomService,
3504
- Renderer2,
3505
- NgZone])
3506
- ], GanttTimelineComponent);
3894
+ const TOUCH_ENABLED = new InjectionToken('gantt-touch-enabled');
3507
3895
 
3508
3896
  /**
3509
3897
  * @hidden
@@ -3561,6 +3949,10 @@ __decorate([
3561
3949
  Input(),
3562
3950
  __metadata("design:type", Function)
3563
3951
  ], GanttTasksTableBodyComponent.prototype, "isTaskSelected", void 0);
3952
+ __decorate([
3953
+ Input(),
3954
+ __metadata("design:type", Boolean)
3955
+ ], GanttTasksTableBodyComponent.prototype, "renderDependencyDragClues", void 0);
3564
3956
  GanttTasksTableBodyComponent = __decorate([
3565
3957
  Component({
3566
3958
  selector: '[kendoGanttTasksTableBody]',
@@ -3573,7 +3965,8 @@ GanttTasksTableBodyComponent = __decorate([
3573
3965
  [activeView]="activeView"
3574
3966
  [taskClass]="taskClass"
3575
3967
  [isSelected]="isTaskSelected"
3576
- [index]="index"
3968
+ [attr.data-task-index]="index"
3969
+ [renderDependencyDragClues]="renderDependencyDragClues"
3577
3970
  >
3578
3971
  </kendo-gantt-milestone-task>
3579
3972
  <ng-template #task>
@@ -3584,7 +3977,8 @@ GanttTasksTableBodyComponent = __decorate([
3584
3977
  [activeView]="activeView"
3585
3978
  [taskClass]="taskClass"
3586
3979
  [isSelected]="isTaskSelected"
3587
- [index]="index"
3980
+ [attr.data-task-index]="index"
3981
+ [renderDependencyDragClues]="renderDependencyDragClues"
3588
3982
  >
3589
3983
  </kendo-gantt-summary-task>
3590
3984
  <kendo-gantt-task
@@ -3595,7 +3989,8 @@ GanttTasksTableBodyComponent = __decorate([
3595
3989
  [activeView]="activeView"
3596
3990
  [taskClass]="taskClass"
3597
3991
  [isSelected]="isTaskSelected"
3598
- [index]="index"
3992
+ [attr.data-task-index]="index"
3993
+ [renderDependencyDragClues]="renderDependencyDragClues"
3599
3994
  >
3600
3995
  </kendo-gantt-task>
3601
3996
  </ng-template>
@@ -3666,29 +4061,18 @@ class GanttTaskBase {
3666
4061
  get slotWidth() {
3667
4062
  return this.viewService.options.slotWidth;
3668
4063
  }
3669
- ngOnChanges(changes) {
3670
- if (isPresent(changes.dataItem)) {
3671
- if (isPresent(changes.dataItem.previousValue)) {
3672
- this.dependencyDomService.unregisterTask(changes.dataItem.previousValue);
3673
- }
3674
- this.dependencyDomService.registerTask(this.dataItem, this.taskElement.nativeElement);
3675
- }
3676
- else if (isPresent(changes.activeView)) {
3677
- this.dependencyDomService.notifyChanges();
3678
- }
3679
- }
3680
- ngOnDestroy() {
3681
- if (isPresent(this.dataItem)) {
3682
- this.dependencyDomService.unregisterTask(this.dataItem);
3683
- }
3684
- this.viewChangesSubscription.unsubscribe();
3685
- }
3686
4064
  get taskWidth() {
3687
4065
  const itemDuration = this.mapper.extractFromTask(this.dataItem, 'end') - this.mapper.extractFromTask(this.dataItem, 'start');
3688
4066
  const durationInSlotUnits = itemDuration / this.slotUnitDuration;
3689
4067
  const width = durationInSlotUnits * this.slotWidth;
3690
4068
  return width;
3691
4069
  }
4070
+ /**
4071
+ * The `left` style prop has to be applied to the host element (.k-task-wrap), as the drag clue elements are displayed on .k-task-wrap hover.
4072
+ * Applying the `left` offset to the inner .k-task element leaves the .k-task-wrap element rendered with an offset of 0 somewhere on the left
4073
+ * and hovering just the .k-task element doesn't expose the drag clues.
4074
+ * Additionally, positioning the entire container takes care of positioning the hints as well.
4075
+ */
3692
4076
  get taskOffset() {
3693
4077
  const timeAfterViewStart = this.mapper.extractFromTask(this.dataItem, 'start') - this.viewService.viewStart;
3694
4078
  const offsetInSlotUnits = timeAfterViewStart / this.slotUnitDuration;
@@ -3700,6 +4084,23 @@ class GanttTaskBase {
3700
4084
  // fall-back to 0 in case no completionRatio is provided
3701
4085
  return isNumber(overlayWidth) ? overlayWidth : 0;
3702
4086
  }
4087
+ ngOnChanges(changes) {
4088
+ if (isPresent(changes.dataItem)) {
4089
+ if (isPresent(changes.dataItem.previousValue)) {
4090
+ this.dependencyDomService.unregisterTask(changes.dataItem.previousValue);
4091
+ }
4092
+ this.dependencyDomService.registerTask(this.dataItem, this.taskElement.nativeElement);
4093
+ }
4094
+ else if (isPresent(changes.activeView)) {
4095
+ this.dependencyDomService.notifyChanges();
4096
+ }
4097
+ }
4098
+ ngOnDestroy() {
4099
+ if (isPresent(this.dataItem)) {
4100
+ this.dependencyDomService.unregisterTask(this.dataItem);
4101
+ }
4102
+ this.viewChangesSubscription.unsubscribe();
4103
+ }
3703
4104
  }
3704
4105
  __decorate([
3705
4106
  HostBinding('class.k-task-wrap'),
@@ -3715,8 +4116,8 @@ __decorate([
3715
4116
  ], GanttTaskBase.prototype, "dataItem", void 0);
3716
4117
  __decorate([
3717
4118
  Input(),
3718
- __metadata("design:type", Number)
3719
- ], GanttTaskBase.prototype, "index", void 0);
4119
+ __metadata("design:type", Boolean)
4120
+ ], GanttTaskBase.prototype, "renderDependencyDragClues", void 0);
3720
4121
  __decorate([
3721
4122
  Input(),
3722
4123
  __metadata("design:type", Function)
@@ -3729,15 +4130,21 @@ __decorate([
3729
4130
  Input(),
3730
4131
  __metadata("design:type", Function)
3731
4132
  ], GanttTaskBase.prototype, "taskClass", void 0);
4133
+ __decorate([
4134
+ HostBinding('style.left.px'),
4135
+ __metadata("design:type", Number),
4136
+ __metadata("design:paramtypes", [])
4137
+ ], GanttTaskBase.prototype, "taskOffset", null);
3732
4138
 
3733
4139
  var GanttTaskComponent_1;
3734
4140
  /**
3735
4141
  * @hidden
3736
4142
  */
3737
4143
  let GanttTaskComponent = GanttTaskComponent_1 = class GanttTaskComponent extends GanttTaskBase {
3738
- constructor(mapper, timelineViewService, dependencyDomService, optionChangesService, cdr, editService) {
4144
+ constructor(editService, touchEnabled$$1, mapper, timelineViewService, dependencyDomService, optionChangesService, cdr) {
3739
4145
  super(mapper, timelineViewService, dependencyDomService, optionChangesService, cdr);
3740
4146
  this.editService = editService;
4147
+ this.touchEnabled = touchEnabled$$1;
3741
4148
  }
3742
4149
  onTaskDelete() {
3743
4150
  this.editService.dataItem = this.dataItem;
@@ -3767,9 +4174,7 @@ GanttTaskComponent = GanttTaskComponent_1 = __decorate([
3767
4174
  class="k-task k-task-single"
3768
4175
  [ngClass]="taskClass(dataItem)"
3769
4176
  [style.width.px]="taskWidth"
3770
- [style.left.px]="taskOffset"
3771
4177
  [attr.title]="mapper.extractFromTask(dataItem, 'title')"
3772
- [attr.data-task-index]="index"
3773
4178
  [class.k-state-selected]="isSelected(dataItem)"
3774
4179
  >
3775
4180
  <ng-container *ngIf="!taskTemplate">
@@ -3809,14 +4214,26 @@ GanttTaskComponent = GanttTaskComponent_1 = __decorate([
3809
4214
  >
3810
4215
  </ng-template>
3811
4216
  </div>
4217
+ <ng-container *ngIf="renderDependencyDragClues">
4218
+ <div
4219
+ class="k-task-dot k-task-start k-touch-action-none"
4220
+ [class.k-display-block]="touchEnabled"
4221
+ >
4222
+ </div>
4223
+ <div
4224
+ class="k-task-dot k-task-end k-touch-action-none"
4225
+ [class.k-display-block]="touchEnabled"
4226
+ >
4227
+ </div>
4228
+ </ng-container>
3812
4229
  `
3813
4230
  }),
3814
- __metadata("design:paramtypes", [MappingService,
4231
+ __param(1, Inject(TOUCH_ENABLED)),
4232
+ __metadata("design:paramtypes", [EditService, Boolean, MappingService,
3815
4233
  TimelineViewService,
3816
4234
  DependencyDomService,
3817
4235
  OptionChangesService,
3818
- ChangeDetectorRef,
3819
- EditService])
4236
+ ChangeDetectorRef])
3820
4237
  ], GanttTaskComponent);
3821
4238
 
3822
4239
  var GanttSummaryTaskComponent_1;
@@ -3824,8 +4241,9 @@ var GanttSummaryTaskComponent_1;
3824
4241
  * @hidden
3825
4242
  */
3826
4243
  let GanttSummaryTaskComponent = GanttSummaryTaskComponent_1 = class GanttSummaryTaskComponent extends GanttTaskBase {
3827
- constructor(mapper, timelineViewService, dependencyDomService, optionChangesService, cdr) {
4244
+ constructor(touchEnabled$$1, mapper, timelineViewService, dependencyDomService, optionChangesService, cdr) {
3828
4245
  super(mapper, timelineViewService, dependencyDomService, optionChangesService, cdr);
4246
+ this.touchEnabled = touchEnabled$$1;
3829
4247
  this.summaryWrapperClass = true;
3830
4248
  }
3831
4249
  };
@@ -3852,9 +4270,7 @@ GanttSummaryTaskComponent = GanttSummaryTaskComponent_1 = __decorate([
3852
4270
  class="k-task k-task-summary"
3853
4271
  [ngClass]="taskClass(dataItem)"
3854
4272
  [style.width.px]="taskWidth"
3855
- [style.left.px]="taskOffset"
3856
4273
  [attr.title]="mapper.extractFromTask(dataItem, 'title')"
3857
- [attr.data-task-index]="index"
3858
4274
  [class.k-state-selected]="isSelected(dataItem)"
3859
4275
  >
3860
4276
  <div *ngIf="!template; else summaryTemplate"
@@ -3876,9 +4292,22 @@ GanttSummaryTaskComponent = GanttSummaryTaskComponent_1 = __decorate([
3876
4292
  >
3877
4293
  </ng-template>
3878
4294
  </div>
4295
+ <ng-container *ngIf="renderDependencyDragClues">
4296
+ <div
4297
+ class="k-task-dot k-task-start k-touch-action-none"
4298
+ [class.k-display-block]="touchEnabled"
4299
+ >
4300
+ </div>
4301
+ <div
4302
+ class="k-task-dot k-task-end k-touch-action-none"
4303
+ [class.k-display-block]="touchEnabled"
4304
+ >
4305
+ </div>
4306
+ </ng-container>
3879
4307
  `
3880
4308
  }),
3881
- __metadata("design:paramtypes", [MappingService,
4309
+ __param(0, Inject(TOUCH_ENABLED)),
4310
+ __metadata("design:paramtypes", [Boolean, MappingService,
3882
4311
  TimelineViewService,
3883
4312
  DependencyDomService,
3884
4313
  OptionChangesService,
@@ -3890,8 +4319,9 @@ var GanttMilestoneTaskComponent_1;
3890
4319
  * @hidden
3891
4320
  */
3892
4321
  let GanttMilestoneTaskComponent = GanttMilestoneTaskComponent_1 = class GanttMilestoneTaskComponent extends GanttTaskBase {
3893
- constructor(mapper, timelineViewService, dependencyDomService, optionChangesService, cdr) {
4322
+ constructor(touchEnabled$$1, mapper, timelineViewService, dependencyDomService, optionChangesService, cdr) {
3894
4323
  super(mapper, timelineViewService, dependencyDomService, optionChangesService, cdr);
4324
+ this.touchEnabled = touchEnabled$$1;
3895
4325
  this.milestoneWrapperClass = true;
3896
4326
  }
3897
4327
  };
@@ -3913,15 +4343,26 @@ GanttMilestoneTaskComponent = GanttMilestoneTaskComponent_1 = __decorate([
3913
4343
  #task
3914
4344
  class="k-task k-task-milestone"
3915
4345
  [ngClass]="taskClass(dataItem)"
3916
- [style.left.px]="taskOffset"
3917
4346
  [attr.title]="mapper.extractFromTask(dataItem, 'title')"
3918
4347
  [class.k-state-selected]="isSelected(dataItem)"
3919
- [attr.data-task-index]="index"
3920
4348
  >
3921
4349
  </div>
4350
+ <ng-container *ngIf="renderDependencyDragClues">
4351
+ <div
4352
+ class="k-task-dot k-task-start k-touch-action-none"
4353
+ [class.k-display-block]="touchEnabled"
4354
+ >
4355
+ </div>
4356
+ <div
4357
+ class="k-task-dot k-task-end k-touch-action-none"
4358
+ [class.k-display-block]="touchEnabled"
4359
+ >
4360
+ </div>
4361
+ </ng-container>
3922
4362
  `
3923
4363
  }),
3924
- __metadata("design:paramtypes", [MappingService,
4364
+ __param(0, Inject(TOUCH_ENABLED)),
4365
+ __metadata("design:paramtypes", [Boolean, MappingService,
3925
4366
  TimelineViewService,
3926
4367
  DependencyDomService,
3927
4368
  OptionChangesService,
@@ -4254,23 +4695,6 @@ ViewSelectorComponent = __decorate([
4254
4695
  __metadata("design:paramtypes", [LocalizationService])
4255
4696
  ], ViewSelectorComponent);
4256
4697
 
4257
- /**
4258
- * The dependency type when two tasks are connected.
4259
- *
4260
- * The supported values are:
4261
- * * `FF`&mdash;from 'finish' to 'finish'
4262
- * * `FS`&mdash;from 'finish' to 'start'
4263
- * * `SS`&mdash;from 'start' to 'start'
4264
- * * `SF`&mdash;from 'start' to 'finish'
4265
- */
4266
- var DependencyType;
4267
- (function (DependencyType) {
4268
- DependencyType[DependencyType["FF"] = 0] = "FF";
4269
- DependencyType[DependencyType["FS"] = 1] = "FS";
4270
- DependencyType[DependencyType["SF"] = 2] = "SF";
4271
- DependencyType[DependencyType["SS"] = 3] = "SS"; // task B can't start before task A starts
4272
- })(DependencyType || (DependencyType = {}));
4273
-
4274
4698
  /**
4275
4699
  * @hidden
4276
4700
  *
@@ -4281,6 +4705,9 @@ const getOffsetRelativeToParent = (element, targetParent) => {
4281
4705
  top: 0,
4282
4706
  left: 0
4283
4707
  };
4708
+ if (!targetParent.contains(element)) {
4709
+ return offset;
4710
+ }
4284
4711
  let offsetParent = element;
4285
4712
  while (offsetParent && offsetParent !== targetParent) {
4286
4713
  offset.top += offsetParent.offsetTop;
@@ -4427,6 +4854,37 @@ const getArrowEast = (top, left, arrowSize) => {
4427
4854
  });
4428
4855
  return points;
4429
4856
  };
4857
+ /**
4858
+ * @hidden
4859
+ *
4860
+ * Translates the provided client `left` and `top` coords to coords relative to the provided container.
4861
+ * https://developer.mozilla.org/en-US/docs/Web/CSS/CSSOM_View/Coordinate_systems#standard_cssom_coordinate_systems
4862
+ */
4863
+ const clientToOffsetCoords = (clientLeft, clientTop, offsetContainer) => {
4864
+ // client (viewport) coordinates of the target container
4865
+ // https://developer.mozilla.org/en-US/docs/Web/API/Element/getBoundingClientRect#value
4866
+ const offsetContainerClientRect = offsetContainer.getBoundingClientRect();
4867
+ return {
4868
+ left: clientLeft - offsetContainerClientRect.left + offsetContainer.scrollLeft,
4869
+ top: clientTop - offsetContainerClientRect.top + offsetContainer.scrollTop
4870
+ };
4871
+ };
4872
+ /**
4873
+ * @hidden
4874
+ *
4875
+ * Retrieves the `left` and `top` values of the center of the provided element.
4876
+ * The retrieved values are relative to the current viewport (client values).
4877
+ * https://developer.mozilla.org/en-US/docs/Web/CSS/CSSOM_View/Coordinate_systems#standard_cssom_coordinate_systems
4878
+ */
4879
+ const getElementClientCenterCoords = (element) => {
4880
+ // client (viewport) coordinates of the targeted element
4881
+ // https://developer.mozilla.org/en-US/docs/Web/API/Element/getBoundingClientRect#value
4882
+ const { left, top, width, height } = element.getBoundingClientRect();
4883
+ return {
4884
+ left: left + (width / 2),
4885
+ top: top + (height / 2)
4886
+ };
4887
+ };
4430
4888
 
4431
4889
  /**
4432
4890
  * Defines the size of the arrow that will be drawn at the end of each Gantt dependency.
@@ -4502,6 +4960,540 @@ GanttDependencyDirective = __decorate([
4502
4960
  DependencyDomService])
4503
4961
  ], GanttDependencyDirective);
4504
4962
 
4963
+ /**
4964
+ * @hidden
4965
+ */
4966
+ let DragValidationTooltipComponent = class DragValidationTooltipComponent {
4967
+ /**
4968
+ * @hidden
4969
+ */
4970
+ constructor() {
4971
+ /**
4972
+ * Sets the status class of the attempted operation.
4973
+ * Note that the status will be ignored and the `neutral` status class will be rendered,
4974
+ * if the any of the fromTaskName or toTaskName are not populated.
4975
+ */
4976
+ this.isValid = false;
4977
+ }
4978
+ };
4979
+ DragValidationTooltipComponent = __decorate([
4980
+ Component({
4981
+ template: `
4982
+ <div
4983
+ class="k-tooltip k-gantt-tooltip-validation"
4984
+ [class.k-gantt-tooltip-valid]="showValidityStatus && isValid"
4985
+ [class.k-gantt-tooltip-invalid]="showValidityStatus && !isValid"
4986
+ >
4987
+ <div class="k-gantt-tooltip-validation-row">
4988
+ <span class="k-gantt-tooltip-validation-label">From:</span>
4989
+ <span class="k-gantt-tooltip-validation-value">{{ fromTaskName }}</span>
4990
+ </div>
4991
+ <div class="k-gantt-tooltip-validation-row">
4992
+ <span class="k-gantt-tooltip-validation-label">To:</span>
4993
+ <span class="k-gantt-tooltip-validation-value">{{ toTaskName }}</span>
4994
+ </div>
4995
+ </div>
4996
+ `,
4997
+ styles: [`
4998
+ .k-gantt-tooltip-validation {
4999
+ max-width: 200px;
5000
+ display: block;
5001
+ }
5002
+ .k-gantt-tooltip-validation::before {
5003
+ content: '';
5004
+ position: absolute;
5005
+ left: 0;
5006
+ top: 0;
5007
+ width: 4px;
5008
+ height: 100%;
5009
+ background: #656565;
5010
+ }
5011
+ .k-gantt-tooltip-validation.k-gantt-tooltip-valid::before {
5012
+ background: #37B400;
5013
+ }
5014
+ .k-gantt-tooltip-validation.k-gantt-tooltip-invalid::before {
5015
+ background: #F31700;
5016
+ }
5017
+ .k-gantt-tooltip-validation-row {
5018
+ white-space: nowrap;
5019
+ overflow: hidden;
5020
+ text-overflow: ellipsis;
5021
+ }
5022
+ .k-gantt-tooltip-validation-label {
5023
+ display: inline-flex;
5024
+ width: 50px;
5025
+ }
5026
+ .k-gantt-tooltip-validation-value {
5027
+ font-weight: bold;
5028
+ }
5029
+ `]
5030
+ })
5031
+ ], DragValidationTooltipComponent);
5032
+
5033
+ /**
5034
+ * When added to the .k-task-dot, the element will be kept with hover styles.
5035
+ * Used for the drag clue from which the dragging has started.
5036
+ */
5037
+ const DRAG_CLUE_HOVER_CLASS = 'k-state-hover';
5038
+ /**
5039
+ * Add the selection disabling class to the enitre container.
5040
+ * Otherwise existing selection on a given task text prevents dragging the clue even if the clue has `user-select: none` styles.
5041
+ */
5042
+ const USER_SELECT_NONE_CLASS = 'k-user-select-none';
5043
+ /**
5044
+ * When added to the .k-task-wrap, the containing .k-task-dot elements will be kept visible even when not hovered.
5045
+ * Used for the drag clue from which the dragging has started.
5046
+ */
5047
+ const TASK_WRAPPER_DRAG_CLASS = 'k-origin';
5048
+ /**
5049
+ * Use 20px margin between the pointer and the popup.
5050
+ * Could be made user-configurable if there's demand.
5051
+ */
5052
+ const DEFAULT_POPUP_VERTICAL_MARGIN = 20;
5053
+ /**
5054
+ * A directive which enables the creation of new dependencies via dragging.
5055
+ */
5056
+ let DependencyDragCreateDirective = class DependencyDragCreateDirective {
5057
+ constructor(gantt, zone, renderer, mapper, popupService, timelineScrollService) {
5058
+ this.gantt = gantt;
5059
+ this.zone = zone;
5060
+ this.renderer = renderer;
5061
+ this.mapper = mapper;
5062
+ this.popupService = popupService;
5063
+ this.timelineScrollService = timelineScrollService;
5064
+ /**
5065
+ * Specifies whether the validation tooltip will be displayed during drag operations.
5066
+ *
5067
+ * @default true
5068
+ */
5069
+ this.displayValidationTooltip = true;
5070
+ this.gantt.renderDependencyDragClues = true;
5071
+ }
5072
+ get container() {
5073
+ if (!isPresent(this.gantt.timeline) || !isPresent(this.gantt.timeline.timelineContent)) {
5074
+ return null;
5075
+ }
5076
+ return this.gantt.timeline.timelineContent.nativeElement;
5077
+ }
5078
+ get polyline() {
5079
+ if (!isPresent(this.gantt.timeline) || !isPresent(this.gantt.timeline.dependencyDragCreatePolyline)) {
5080
+ return null;
5081
+ }
5082
+ return this.gantt.timeline.dependencyDragCreatePolyline.nativeElement;
5083
+ }
5084
+ get popupContainer() {
5085
+ if (!isPresent(this.gantt.timeline) || !isPresent(this.gantt.timeline.dragPopupContainer)) {
5086
+ return null;
5087
+ }
5088
+ return this.gantt.timeline.dragPopupContainer;
5089
+ }
5090
+ ngAfterViewInit() {
5091
+ this.subscribeDraggable();
5092
+ this.addScrollListener();
5093
+ }
5094
+ ngOnDestroy() {
5095
+ this.unsubscribeDraggable();
5096
+ this.removeScrollListener();
5097
+ this.fromTaskClue = null;
5098
+ this.cancelScroll();
5099
+ this.closeDragPopup();
5100
+ }
5101
+ subscribeDraggable() {
5102
+ this.dragSubscriptions = this.gantt.timeline.timelineContainerPress
5103
+ .subscribe(this.handlePress.bind(this));
5104
+ this.dragSubscriptions.add(this.gantt.timeline.timelineContainerDrag
5105
+ .subscribe(this.handleDrag.bind(this)));
5106
+ this.dragSubscriptions.add(this.gantt.timeline.timelineContainerRelease
5107
+ .subscribe(this.handleRelease.bind(this)));
5108
+ }
5109
+ unsubscribeDraggable() {
5110
+ if (isPresent(this.dragSubscriptions)) {
5111
+ this.dragSubscriptions.unsubscribe();
5112
+ this.dragSubscriptions = null;
5113
+ }
5114
+ }
5115
+ handlePress({ clientX, clientY }) {
5116
+ // using `originalEvent.target` is not reliable under mobile devices with the current implementation of the draggable, so use this instead
5117
+ const target = elementFromPoint(clientX, clientY);
5118
+ if (isDependencyDragClue(target)) {
5119
+ this.fromTaskClue = target;
5120
+ this.assignDragStartClasses(this.fromTaskClue);
5121
+ // use the center of the target clue as polyline starting point
5122
+ const dragClueCenterCoords = getElementClientCenterCoords(this.fromTaskClue);
5123
+ // the polyline uses `position: aboslute`, so translate the client coordinates to offset coordinates (`left` and `top` relative to the timeline container)
5124
+ this.polylineStartCoords = clientToOffsetCoords(dragClueCenterCoords.left, dragClueCenterCoords.top, this.container);
5125
+ }
5126
+ }
5127
+ handleDrag({ clientX, clientY }) {
5128
+ if (isPresent(this.fromTaskClue)) {
5129
+ // the polyline uses `position: aboslute`, so translate the client coordinates to offset coordinates (`left` and `top` relative to the timeline container)
5130
+ const pointerOffsetCoords = clientToOffsetCoords(clientX, clientY, this.container);
5131
+ // the start coords are calculated just once per drag session in handlePress
5132
+ // use the current drag coords as polyline end coords
5133
+ this.updatePolyline(this.polylineStartCoords, pointerOffsetCoords);
5134
+ this.currentPointerClientCoords = { left: clientX, top: clientY };
5135
+ if (this.gantt.dragScrollSettings.enabled) {
5136
+ // use client coordinates for scroll trigger
5137
+ this.scrollPointIntoView(this.currentPointerClientCoords);
5138
+ }
5139
+ if (this.displayValidationTooltip) {
5140
+ this.updateDragPopup(pointerOffsetCoords);
5141
+ }
5142
+ }
5143
+ }
5144
+ handleRelease({ clientX, clientY }) {
5145
+ if (!isPresent(this.fromTaskClue)) {
5146
+ return;
5147
+ }
5148
+ // using `originalEvent.target` is not reliable under mobile devices with the current implementation of the draggable, so use this instead
5149
+ const target = elementFromPoint(clientX, clientY);
5150
+ if (isDependencyDragClue(target) && !sameTaskClues(this.fromTaskClue, target, this.container)) {
5151
+ this.zone.run(() => {
5152
+ const fromTaskClue = this.fromTaskClue;
5153
+ const toTaskClue = target;
5154
+ const fromTask = this.gantt.renderedTreeListItems[getClosestTaskIndex(fromTaskClue, this.container)];
5155
+ const toTask = this.gantt.renderedTreeListItems[getClosestTaskIndex(toTaskClue, this.container)];
5156
+ const dependencyType = getDependencyTypeFromTargetTasks(fromTaskClue, toTaskClue);
5157
+ const { fromId, toId, type } = this.mapper.dependencyFields;
5158
+ this.gantt.dependencyAdd.emit({
5159
+ fromTask: fromTask,
5160
+ toTask: toTask,
5161
+ type: dependencyType,
5162
+ isValid: this.gantt.validateNewDependency({
5163
+ [fromId]: this.mapper.extractFromTask(fromTask, 'id'),
5164
+ [toId]: this.mapper.extractFromTask(toTask, 'id'),
5165
+ [type]: dependencyType
5166
+ })
5167
+ });
5168
+ });
5169
+ }
5170
+ this.clearPolyline();
5171
+ this.removeDragStartClasses(this.fromTaskClue);
5172
+ this.fromTaskClue = null;
5173
+ this.cancelScroll();
5174
+ this.closeDragPopup();
5175
+ }
5176
+ updatePolyline(start, end) {
5177
+ const points = `${start.left},${start.top} ${end.left},${end.top}`;
5178
+ this.renderer.setAttribute(this.polyline, 'points', points);
5179
+ }
5180
+ clearPolyline() {
5181
+ this.renderer.removeAttribute(this.polyline, 'points');
5182
+ }
5183
+ assignDragStartClasses(dragClue) {
5184
+ if (!isPresent(dragClue)) {
5185
+ return;
5186
+ }
5187
+ this.renderer.addClass(this.container, USER_SELECT_NONE_CLASS);
5188
+ this.renderer.addClass(dragClue, DRAG_CLUE_HOVER_CLASS);
5189
+ const taskWrapper = getClosestTaskWrapper(dragClue, this.container);
5190
+ if (isPresent(taskWrapper)) {
5191
+ this.renderer.addClass(taskWrapper, TASK_WRAPPER_DRAG_CLASS);
5192
+ }
5193
+ }
5194
+ removeDragStartClasses(dragClue) {
5195
+ if (!isPresent(dragClue)) {
5196
+ return;
5197
+ }
5198
+ this.renderer.removeClass(this.container, USER_SELECT_NONE_CLASS);
5199
+ this.renderer.removeClass(dragClue, DRAG_CLUE_HOVER_CLASS);
5200
+ const taskWrapper = getClosestTaskWrapper(dragClue, this.container);
5201
+ if (isPresent(taskWrapper)) {
5202
+ this.renderer.removeClass(taskWrapper, TASK_WRAPPER_DRAG_CLASS);
5203
+ }
5204
+ }
5205
+ scrollPointIntoView({ left, top }) {
5206
+ this.timelineScrollService.requestScrollCancel();
5207
+ this.timelineScrollService.requestHorizontalScroll(left);
5208
+ this.timelineScrollService.requestVerticalScroll(top);
5209
+ }
5210
+ cancelScroll() {
5211
+ this.timelineScrollService.requestScrollCancel();
5212
+ }
5213
+ addScrollListener() {
5214
+ if (!isDocumentAvailable()) {
5215
+ return;
5216
+ }
5217
+ this.zone.runOutsideAngular(() => this.scrollListenerDisposer = this.renderer.listen(this.container, 'scroll', () => {
5218
+ // update the polyline only if we're currently dragging
5219
+ if (isPresent(this.fromTaskClue) && isPresent(this.currentPointerClientCoords)) {
5220
+ const { left, top } = this.currentPointerClientCoords;
5221
+ const pointerOffsetCoords = clientToOffsetCoords(left, top, this.container);
5222
+ this.updatePolyline(this.polylineStartCoords, pointerOffsetCoords);
5223
+ if (this.displayValidationTooltip) {
5224
+ this.updateDragPopup(pointerOffsetCoords);
5225
+ }
5226
+ }
5227
+ }));
5228
+ }
5229
+ removeScrollListener() {
5230
+ if (isPresent(this.scrollListenerDisposer)) {
5231
+ this.scrollListenerDisposer();
5232
+ this.scrollListenerDisposer = null;
5233
+ }
5234
+ }
5235
+ openDragPopup() {
5236
+ if (isPresent(this.dragPopup)) {
5237
+ this.closeDragPopup();
5238
+ }
5239
+ this.dragPopup = this.popupService.open({
5240
+ animate: false,
5241
+ content: DragValidationTooltipComponent,
5242
+ appendTo: this.popupContainer,
5243
+ positionMode: 'absolute',
5244
+ popupClass: 'k-popup-transparent'
5245
+ });
5246
+ }
5247
+ updateDragPopup(pointerOffsetPosition) {
5248
+ if (!isPresent(this.dragPopup)) {
5249
+ this.openDragPopup();
5250
+ }
5251
+ const tooltip = this.dragPopup.content.instance;
5252
+ const { fromTaskName, toTaskName, isValid, showValidityStatus } = this.getTooltipContext();
5253
+ if (tooltip.fromTaskName !== fromTaskName ||
5254
+ tooltip.toTaskName !== toTaskName ||
5255
+ tooltip.isValid !== isValid ||
5256
+ tooltip.showValidityStatus !== showValidityStatus) {
5257
+ tooltip.fromTaskName = fromTaskName;
5258
+ tooltip.toTaskName = toTaskName;
5259
+ tooltip.isValid = isValid;
5260
+ tooltip.showValidityStatus = showValidityStatus;
5261
+ this.dragPopup.content.changeDetectorRef.detectChanges();
5262
+ }
5263
+ this.dragPopup.popup.instance.offset = this.normalizePopupPosition(pointerOffsetPosition);
5264
+ this.dragPopup.popup.changeDetectorRef.detectChanges();
5265
+ }
5266
+ closeDragPopup() {
5267
+ if (isPresent(this.dragPopup)) {
5268
+ this.dragPopup.close();
5269
+ this.dragPopup = null;
5270
+ }
5271
+ }
5272
+ extractTaskName(target) {
5273
+ if (!isTaskWrapper(target, this.container)) {
5274
+ return null;
5275
+ }
5276
+ const taskIndex = getClosestTaskIndex(target, this.container);
5277
+ const task = this.gantt.renderedTreeListItems[taskIndex];
5278
+ const taskName = this.mapper.extractFromTask(task, 'title');
5279
+ return taskName;
5280
+ }
5281
+ getTooltipContext() {
5282
+ const fromTaskName = this.extractTaskName(this.fromTaskClue);
5283
+ const currentPointerTarget = elementFromPoint(this.currentPointerClientCoords.left, this.currentPointerClientCoords.top);
5284
+ const toTaskName = isTaskWrapper(currentPointerTarget, this.container) && !sameTaskClues(this.fromTaskClue, currentPointerTarget, this.container) ?
5285
+ this.extractTaskName(currentPointerTarget) :
5286
+ '';
5287
+ const showValidityStatus = isDependencyDragClue(currentPointerTarget) && !sameTaskClues(this.fromTaskClue, currentPointerTarget, this.container);
5288
+ const { fromId, toId, type } = this.mapper.dependencyFields;
5289
+ return {
5290
+ fromTaskName,
5291
+ toTaskName,
5292
+ showValidityStatus,
5293
+ isValid: showValidityStatus && this.gantt.validateNewDependency({
5294
+ [fromId]: this.mapper.extractFromTask(this.gantt.renderedTreeListItems[getClosestTaskIndex(this.fromTaskClue, this.container)], 'id'),
5295
+ [toId]: this.mapper.extractFromTask(this.gantt.renderedTreeListItems[getClosestTaskIndex(currentPointerTarget, this.container)], 'id'),
5296
+ [type]: getDependencyTypeFromTargetTasks(this.fromTaskClue, currentPointerTarget)
5297
+ })
5298
+ };
5299
+ }
5300
+ /**
5301
+ * Restricts the popup position to not go below the scroll height or width of the container.
5302
+ * Flips the position of the popup when there's not enough vertical space in the visible part of the container to render the popup.
5303
+ */
5304
+ normalizePopupPosition(pointerOffsetPosition) {
5305
+ let top = pointerOffsetPosition.top + DEFAULT_POPUP_VERTICAL_MARGIN;
5306
+ const containerClientBottom = this.container.clientHeight + this.container.scrollTop;
5307
+ const popupHeight = this.dragPopup.popupElement.querySelector('.k-tooltip').clientHeight;
5308
+ const enoughSpaceToRender = top < containerClientBottom - popupHeight;
5309
+ // flip the popup above the pointer if there's not enough space in the bottom of the container
5310
+ if (!enoughSpaceToRender) {
5311
+ // margin * 2 to account for the already applied margin
5312
+ top -= popupHeight + (DEFAULT_POPUP_VERTICAL_MARGIN * 2);
5313
+ }
5314
+ // center the popup horizontally according to the pointer position
5315
+ const popupWidth = this.dragPopup.popupElement.querySelector('.k-tooltip').clientWidth;
5316
+ const left = pointerOffsetPosition.left - popupWidth / 2;
5317
+ // don't allow the popup to be cut out of the viewport
5318
+ const minLeftTop = 0;
5319
+ // restrict the popup from being positioned beyond or before the available scrollable space
5320
+ return {
5321
+ left: fitToRange(left, minLeftTop, this.container.scrollWidth - popupWidth),
5322
+ top: fitToRange(top, minLeftTop, this.container.scrollHeight - popupHeight)
5323
+ };
5324
+ }
5325
+ };
5326
+ __decorate([
5327
+ Input(),
5328
+ __metadata("design:type", Boolean)
5329
+ ], DependencyDragCreateDirective.prototype, "displayValidationTooltip", void 0);
5330
+ DependencyDragCreateDirective = __decorate([
5331
+ Directive({
5332
+ selector: '[kendoGanttDependencyDragCreate]'
5333
+ }),
5334
+ __metadata("design:paramtypes", [GanttComponent,
5335
+ NgZone,
5336
+ Renderer2,
5337
+ MappingService,
5338
+ PopupService,
5339
+ TimelineScrollService])
5340
+ ], DependencyDragCreateDirective);
5341
+
5342
+ /**
5343
+ * @hidden
5344
+ */
5345
+ var ScrollDirection;
5346
+ (function (ScrollDirection) {
5347
+ ScrollDirection[ScrollDirection["Backwards"] = -1] = "Backwards";
5348
+ ScrollDirection[ScrollDirection["Forward"] = 1] = "Forward";
5349
+ })(ScrollDirection || (ScrollDirection = {}));
5350
+ /**
5351
+ * @hidden
5352
+ */
5353
+ var ScrollAxis;
5354
+ (function (ScrollAxis) {
5355
+ ScrollAxis["Vertical"] = "scrollTop";
5356
+ ScrollAxis["Horizontal"] = "scrollLeft";
5357
+ })(ScrollAxis || (ScrollAxis = {}));
5358
+
5359
+ /**
5360
+ * @hidden
5361
+ *
5362
+ * Checks if the beginning of the scrollable element is reached (top/left).
5363
+ * Floors the top value.
5364
+ */
5365
+ const isUpperLimitReached = (element, axis) => Math.floor(element[axis]) <= 0;
5366
+ /**
5367
+ * @hidden
5368
+ *
5369
+ * Checks if the end of the scrollable element is reached (bottom/right).
5370
+ * Ceils the top value.
5371
+ */
5372
+ const isBottomLimitReached = (element, axis) => {
5373
+ const elementSize = axis === ScrollAxis.Horizontal ?
5374
+ element.scrollWidth - element.clientWidth :
5375
+ element.scrollHeight - element.clientHeight;
5376
+ return Math.ceil(element[axis]) >= elementSize;
5377
+ };
5378
+ /**
5379
+ * @hidden
5380
+ *
5381
+ * Scrolls the element in the given direction by the provided step in the provided scroll axis.
5382
+ *
5383
+ * If the targeted scroll incrementation doesn't yield any result due to device pixel ratio issues (https://github.com/dimitar-pechev/RenderingIndependentScrollOffsets#readme),
5384
+ * increments the step with 1px and again attempts to change the scrollTop of the element, until the content is actually scrolled.
5385
+ *
5386
+ * Cuts the operation short after 20 unsuccessful attempts to prevent infinite loops in possible corner-case scenarios.
5387
+ */
5388
+ const scrollElement = (element, step, direction, scrollAxis) => {
5389
+ if (!(isPresent(element) && isDocumentAvailable())) {
5390
+ return;
5391
+ }
5392
+ const initialScrollPosition = element[scrollAxis];
5393
+ let currentStep = step;
5394
+ let iterations = 0;
5395
+ while (initialScrollPosition === element[scrollAxis] &&
5396
+ !(direction === ScrollDirection.Backwards && isUpperLimitReached(element, scrollAxis)) &&
5397
+ !(direction === ScrollDirection.Forward && isBottomLimitReached(element, scrollAxis)) &&
5398
+ iterations < 20 // cut the operation short in 20 attempts - in case of a wild corner case
5399
+ ) {
5400
+ element[scrollAxis] += (currentStep * direction);
5401
+ // try with a larger step if the current one doesn't update the scroll position successfully
5402
+ currentStep += 1;
5403
+ iterations += 1;
5404
+ }
5405
+ };
5406
+ /**
5407
+ * @hidden
5408
+ *
5409
+ * As client coordinates are not restricted to the range 0px - {viewportSize}px, but can have negative starting values or ending values greater than the viewport size,
5410
+ * this function extracts the visible boundaries of the provided element - fall-backing to 0 when the top/left are below 0,
5411
+ * and fall-backing to the actual visible size of the container for bottom/right.
5412
+ */
5413
+ const getViewportBoundaries = (element) => {
5414
+ const elementRect = element.getBoundingClientRect();
5415
+ // if the beginning of the scrollable container is above/before the current viewport, fall-back to 0
5416
+ const topLimit = Math.max(elementRect.top, 0);
5417
+ const leftLimit = Math.max(elementRect.left, 0);
5418
+ // if the end of the scrollable container is beneath/after the current viewport, fall-back to its client height
5419
+ // add the distance from the start of the viewport to the beginning of the container to ensure scrolling bottom begins when the actual end of the container is reached
5420
+ const bottomLimit = topLimit + Math.min(elementRect.bottom, element.clientHeight);
5421
+ const rightLimit = leftLimit + Math.min(elementRect.right, element.clientWidth);
5422
+ return {
5423
+ top: topLimit,
5424
+ bottom: bottomLimit,
5425
+ left: leftLimit,
5426
+ right: rightLimit
5427
+ };
5428
+ };
5429
+
5430
+ /**
5431
+ * @hidden
5432
+ */
5433
+ let TimelineScrollableDirective = class TimelineScrollableDirective {
5434
+ constructor(timelineScrollableContainer, scrollService, zone) {
5435
+ this.timelineScrollableContainer = timelineScrollableContainer;
5436
+ this.scrollService = scrollService;
5437
+ this.zone = zone;
5438
+ this.subscriptions = new Subscription();
5439
+ this.subscriptions.add(this.scrollService.horizontalScroll
5440
+ .subscribe(this.scrollHorizontallyTo.bind(this)));
5441
+ this.subscriptions.add(this.scrollService.verticalScroll
5442
+ .subscribe(this.scrollVerticallyTo.bind(this)));
5443
+ this.subscriptions.add(this.scrollService.scrollCancel
5444
+ .subscribe(this.cancelScroll.bind(this)));
5445
+ }
5446
+ ngOnDestroy() {
5447
+ this.subscriptions.unsubscribe();
5448
+ }
5449
+ scrollHorizontallyTo(left) {
5450
+ this.zone.runOutsideAngular(() => {
5451
+ const container = this.timelineScrollableContainer.nativeElement;
5452
+ const visibleBoundaries = getViewportBoundaries(container);
5453
+ if (left < visibleBoundaries.left + this.scrollSettings.threshold) {
5454
+ this.horizontalScrollInterval = setInterval(() => scrollElement(container, this.scrollSettings.step, ScrollDirection.Backwards, ScrollAxis.Horizontal), this.scrollSettings.interval);
5455
+ }
5456
+ else if (left > visibleBoundaries.right - this.scrollSettings.threshold) {
5457
+ this.horizontalScrollInterval = setInterval(() => scrollElement(container, this.scrollSettings.step, ScrollDirection.Forward, ScrollAxis.Horizontal), this.scrollSettings.interval);
5458
+ }
5459
+ });
5460
+ }
5461
+ scrollVerticallyTo(top) {
5462
+ this.zone.runOutsideAngular(() => {
5463
+ const container = this.timelineScrollableContainer.nativeElement;
5464
+ const visibleBoundaries = getViewportBoundaries(container);
5465
+ if (top < visibleBoundaries.top + this.scrollSettings.threshold) {
5466
+ this.verticalScrollInterval = setInterval(() => scrollElement(container, this.scrollSettings.step, ScrollDirection.Backwards, ScrollAxis.Vertical), this.scrollSettings.interval);
5467
+ }
5468
+ else if (top > visibleBoundaries.bottom - this.scrollSettings.threshold) {
5469
+ this.verticalScrollInterval = setInterval(() => scrollElement(container, this.scrollSettings.step, ScrollDirection.Forward, ScrollAxis.Vertical), this.scrollSettings.interval);
5470
+ }
5471
+ });
5472
+ }
5473
+ cancelScroll() {
5474
+ if (isPresent(this.verticalScrollInterval)) {
5475
+ clearInterval(this.verticalScrollInterval);
5476
+ this.verticalScrollInterval = null;
5477
+ }
5478
+ if (isPresent(this.horizontalScrollInterval)) {
5479
+ clearInterval(this.horizontalScrollInterval);
5480
+ this.horizontalScrollInterval = null;
5481
+ }
5482
+ }
5483
+ };
5484
+ __decorate([
5485
+ Input(),
5486
+ __metadata("design:type", Object)
5487
+ ], TimelineScrollableDirective.prototype, "scrollSettings", void 0);
5488
+ TimelineScrollableDirective = __decorate([
5489
+ Directive({
5490
+ selector: '[kendoGanttTimelineScrollable]'
5491
+ }),
5492
+ __metadata("design:paramtypes", [ElementRef,
5493
+ TimelineScrollService,
5494
+ NgZone])
5495
+ ], TimelineScrollableDirective);
5496
+
4505
5497
  var TimelineDayViewComponent_1;
4506
5498
  let TimelineDayViewComponent = TimelineDayViewComponent_1 = class TimelineDayViewComponent extends ViewBase {
4507
5499
  constructor(optionChangesService, dependencyDomService) {
@@ -5314,6 +6306,8 @@ const IMPORTED_MODULES = [
5314
6306
  ButtonsModule,
5315
6307
  DialogModule,
5316
6308
  EventsModule,
6309
+ PopupModule,
6310
+ DraggableModule,
5317
6311
  TabStripModule,
5318
6312
  GridModule,
5319
6313
  DropDownsModule
@@ -5346,6 +6340,7 @@ const DECLARATIONS = [
5346
6340
  FooterTemplateDirective,
5347
6341
  GanttExpandableDirective,
5348
6342
  GanttDependencyDirective,
6343
+ DependencyDragCreateDirective,
5349
6344
  TimelineDayViewComponent,
5350
6345
  TimelineWeekViewComponent,
5351
6346
  TimelineMonthViewComponent,
@@ -5354,9 +6349,12 @@ const DECLARATIONS = [
5354
6349
  CustomMessagesComponent,
5355
6350
  LocalizedMessagesDirective,
5356
6351
  GanttAddTaskComponent,
6352
+ DragValidationTooltipComponent,
6353
+ TimelineScrollableDirective,
5357
6354
  DependenciesTableComponent,
5358
6355
  TaskFieldsComponent
5359
6356
  ];
6357
+ const ɵ0$3 = touchEnabled;
5360
6358
  /**
5361
6359
  * Represents the [NgModule]({{ site.data.urls.angular['ngmoduleapi'] }})
5362
6360
  * definition for the Gantt component.
@@ -5395,52 +6393,19 @@ GanttModule = __decorate([
5395
6393
  imports: [...IMPORTED_MODULES],
5396
6394
  declarations: [...DECLARATIONS],
5397
6395
  exports: [...DECLARATIONS],
6396
+ entryComponents: [DragValidationTooltipComponent],
5398
6397
  providers: [{
5399
6398
  provide: L10N_PREFIX,
5400
6399
  useValue: 'kendo.gantt'
6400
+ }, {
6401
+ provide: TOUCH_ENABLED,
6402
+ useValue: ɵ0$3
5401
6403
  }]
5402
6404
  })
5403
6405
  ], GanttModule);
5404
6406
 
5405
- /**
5406
- * @hidden
5407
- */
5408
- class PreventableEvent {
5409
- constructor() {
5410
- this.prevented = false;
5411
- }
5412
- /**
5413
- * Prevents the default action for a specified event.
5414
- * In this way, the source component suppresses
5415
- * the built-in behavior that follows the event.
5416
- */
5417
- preventDefault() {
5418
- this.prevented = true;
5419
- }
5420
- /**
5421
- * Returns `true` if the event was prevented
5422
- * by any of its subscribers.
5423
- *
5424
- * @returns `true` if the default action was prevented.
5425
- * Otherwise, returns `false`.
5426
- */
5427
- isDefaultPrevented() {
5428
- return this.prevented;
5429
- }
5430
- }
5431
-
5432
- /**
5433
- * Called every time a user leaves an edited cell.
5434
- */
5435
- class CellCloseEvent extends PreventableEvent {
5436
- constructor(options) {
5437
- super();
5438
- Object.assign(this, options);
5439
- }
5440
- }
5441
-
5442
6407
  /**
5443
6408
  * Generated bundle index. Do not edit.
5444
6409
  */
5445
6410
 
5446
- export { MappingService, OptionChangesService, DependencyDomService, GanttDependencyDirective, GanttAddTaskComponent, DependenciesTableComponent, EditDialogComponent, EditService, TaskFieldsComponent, CustomMessagesComponent, GanttLocalizationService, LocalizedMessagesDirective, Messages, PreventableEvent, GanttHeaderTableBodyComponent, GanttMilestoneTaskComponent, GanttSummaryTaskComponent, GanttTaskBase, GanttTaskComponent, GanttTasksTableBodyComponent, ScrollSyncService, GanttTimelineComponent, TimelineBaseViewService, TimelineDayViewComponent, TimelineDayViewService, TimelineMonthViewComponent, TimelineMonthViewService, TimelineViewService, TimelineWeekViewComponent, TimelineWeekViewService, ViewBase, ToolbarComponent, ViewSelectorComponent, GanttComponent, GanttModule, GanttHierarchyBindingDirective, GanttFlatBindingDirective, GanttExpandableDirective, GanttTaskTemplateDirective, GanttTaskContentTemplateDirective, GanttSummaryTaskTemplateDirective, ToolbarTemplateDirective, SelectableDirective, DependencyType, CellCloseEvent, GanttColumnBase, GanttColumnComponent, GanttColumnGroupComponent, GanttSpanColumnComponent, CellTemplateDirective, HeaderTemplateDirective, FooterTemplateDirective, ColumnMenuTemplateDirective, FilterCellTemplateDirective, FilterMenuTemplateDirective, EditTemplateDirective };
6411
+ export { MappingService, OptionChangesService, TOUCH_ENABLED, DependencyDomService, GanttDependencyDirective, DragValidationTooltipComponent, GanttAddTaskComponent, DependenciesTableComponent, EditDialogComponent, EditService, TaskFieldsComponent, CustomMessagesComponent, GanttLocalizationService, LocalizedMessagesDirective, Messages, PreventableEvent, GanttHeaderTableBodyComponent, GanttMilestoneTaskComponent, GanttSummaryTaskComponent, GanttTaskBase, GanttTaskComponent, GanttTasksTableBodyComponent, ScrollSyncService, TimelineScrollableDirective, TimelineScrollService, GanttTimelineComponent, TimelineBaseViewService, TimelineDayViewComponent, TimelineDayViewService, TimelineMonthViewComponent, TimelineMonthViewService, TimelineViewService, TimelineWeekViewComponent, TimelineWeekViewService, ViewBase, ToolbarComponent, ViewSelectorComponent, GanttComponent, GanttModule, GanttHierarchyBindingDirective, GanttFlatBindingDirective, GanttExpandableDirective, DependencyDragCreateDirective, GanttTaskTemplateDirective, GanttTaskContentTemplateDirective, GanttSummaryTaskTemplateDirective, ToolbarTemplateDirective, SelectableDirective, DependencyType, CellCloseEvent, GanttColumnBase, GanttColumnComponent, GanttColumnGroupComponent, GanttSpanColumnComponent, CellTemplateDirective, HeaderTemplateDirective, FooterTemplateDirective, ColumnMenuTemplateDirective, FilterCellTemplateDirective, FilterMenuTemplateDirective, EditTemplateDirective };