@progress/kendo-angular-gantt 0.2.1-dev.202112091741 → 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 (158) hide show
  1. package/dist/cdn/js/kendo-angular-gantt.js +2 -2
  2. package/dist/cdn/main.js +4 -4
  3. package/dist/es/common/touch-enabled.js +9 -0
  4. package/dist/es/dependencies/utils.js +40 -5
  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/add-task.component.js +94 -0
  8. package/dist/es/editing/dependencies-table.component.js +131 -0
  9. package/dist/es/editing/edit-dialog.component.js +37 -6
  10. package/dist/es/editing/edit.service.js +89 -7
  11. package/dist/es/editing/task-fields.component.js +43 -0
  12. package/dist/es/editing/{util.js → utils.js} +0 -0
  13. package/dist/es/expanded-state/expandable.directive.js +4 -6
  14. package/dist/es/gantt.component.js +230 -45
  15. package/dist/es/gantt.module.js +36 -10
  16. package/dist/es/index.js +8 -1
  17. package/dist/es/localization/gantt-localization.service.js +26 -0
  18. package/dist/es/localization/messages.js +45 -1
  19. package/dist/es/main.js +1 -0
  20. package/dist/es/models/dependency-type.enum.js +16 -0
  21. package/dist/es/models/events/{add-event.interface.js → dependency-add-event.interface.js} +0 -0
  22. package/dist/es/models/events/{edit-event.interface.js → task-add-event.interface.js} +0 -0
  23. package/dist/es/models/models.js +1 -0
  24. package/dist/es/models/{events/remove-event.interface.js → toolbar-settings.js} +0 -0
  25. package/dist/es/models/{toolbar-position.js → view-item.interface.js} +0 -0
  26. package/dist/es/package-metadata.js +1 -1
  27. package/dist/es/rendering/gantt-milestone-task.component.js +7 -4
  28. package/dist/es/rendering/gantt-summary-task.component.js +7 -4
  29. package/dist/es/rendering/gantt-task-base.js +30 -19
  30. package/dist/es/rendering/gantt-task.component.js +8 -6
  31. package/dist/es/rendering/gantt-tasks-table-body.component.js +5 -1
  32. package/dist/es/scrolling/drag-scroll-settings.js +20 -0
  33. package/dist/es/scrolling/timeline-scroll.directive.js +89 -0
  34. package/dist/es/scrolling/timeline-scroll.service.js +39 -0
  35. package/dist/es/scrolling/utils.js +80 -0
  36. package/dist/es/timeline/gantt-timeline.component.js +45 -3
  37. package/dist/es/toolbar/toolbar.component.js +9 -1
  38. package/dist/es/utils.js +143 -12
  39. package/dist/es2015/common/touch-enabled.d.ts +9 -0
  40. package/dist/es2015/common/touch-enabled.js +9 -0
  41. package/dist/es2015/dependencies/utils.d.ts +15 -0
  42. package/dist/es2015/dependencies/utils.js +40 -5
  43. package/dist/es2015/dragging/dependency-drag-create.directive.d.ts +72 -0
  44. package/dist/es2015/dragging/dependency-drag-create.directive.js +324 -0
  45. package/dist/es2015/dragging/drag-validation-tooltip.component.d.ts +29 -0
  46. package/dist/es2015/dragging/drag-validation-tooltip.component.js +76 -0
  47. package/dist/es2015/editing/add-task.component.d.ts +45 -0
  48. package/dist/es2015/editing/add-task.component.js +102 -0
  49. package/dist/es2015/editing/dependencies-table.component.d.ts +39 -0
  50. package/dist/es2015/editing/dependencies-table.component.js +160 -0
  51. package/dist/es2015/editing/edit-dialog.component.d.ts +10 -3
  52. package/dist/es2015/editing/edit-dialog.component.js +55 -33
  53. package/dist/es2015/editing/edit.service.d.ts +24 -3
  54. package/dist/es2015/editing/edit.service.js +78 -10
  55. package/dist/es2015/editing/task-fields.component.d.ts +22 -0
  56. package/dist/es2015/editing/task-fields.component.js +67 -0
  57. package/dist/es2015/editing/{util.d.ts → utils.d.ts} +0 -0
  58. package/dist/es2015/editing/{util.js → utils.js} +0 -0
  59. package/dist/es2015/expanded-state/expandable.directive.d.ts +1 -2
  60. package/dist/es2015/expanded-state/expandable.directive.js +2 -7
  61. package/dist/es2015/gantt.component.d.ts +62 -18
  62. package/dist/es2015/gantt.component.js +290 -43
  63. package/dist/es2015/gantt.module.js +36 -10
  64. package/dist/es2015/index.d.ts +8 -1
  65. package/dist/es2015/index.js +8 -1
  66. package/dist/es2015/index.metadata.json +1 -1
  67. package/dist/es2015/localization/{treelist-messages.directive.d.ts → gantt-localization.service.d.ts} +4 -3
  68. package/dist/es2015/localization/gantt-localization.service.js +25 -0
  69. package/dist/es2015/localization/messages.d.ts +46 -2
  70. package/dist/es2015/localization/messages.js +45 -1
  71. package/dist/es2015/main.d.ts +1 -0
  72. package/dist/es2015/main.js +1 -0
  73. package/dist/es2015/models/dependency-type.enum.d.ts +1 -1
  74. package/dist/es2015/models/dependency-type.enum.js +16 -0
  75. package/dist/es2015/models/events/dependency-add-event.interface.d.ts +26 -0
  76. package/dist/es2015/models/events/{add-event.interface.js → dependency-add-event.interface.js} +0 -0
  77. package/dist/es2015/models/events/task-add-event.interface.d.ts +31 -0
  78. package/dist/es2015/models/events/{edit-event.interface.js → task-add-event.interface.js} +0 -0
  79. package/dist/es2015/models/events/task-edit-event.interface.d.ts +17 -4
  80. package/dist/es2015/models/models.d.ts +4 -3
  81. package/dist/es2015/models/models.js +1 -0
  82. package/dist/es2015/models/toolbar-settings.d.ts +29 -0
  83. package/dist/es2015/models/{events/remove-event.interface.js → toolbar-settings.js} +0 -0
  84. package/dist/es2015/models/view-item.interface.d.ts +35 -0
  85. package/dist/es2015/models/{toolbar-position.js → view-item.interface.js} +0 -0
  86. package/dist/es2015/package-metadata.js +1 -1
  87. package/dist/es2015/rendering/gantt-milestone-task.component.d.ts +2 -1
  88. package/dist/es2015/rendering/gantt-milestone-task.component.js +18 -5
  89. package/dist/es2015/rendering/gantt-summary-task.component.d.ts +2 -1
  90. package/dist/es2015/rendering/gantt-summary-task.component.js +18 -5
  91. package/dist/es2015/rendering/gantt-task-base.d.ts +11 -5
  92. package/dist/es2015/rendering/gantt-task-base.js +30 -19
  93. package/dist/es2015/rendering/gantt-task.component.d.ts +2 -1
  94. package/dist/es2015/rendering/gantt-task.component.js +19 -7
  95. package/dist/es2015/rendering/gantt-tasks-table-body.component.d.ts +1 -0
  96. package/dist/es2015/rendering/gantt-tasks-table-body.component.js +10 -3
  97. package/dist/es2015/scrolling/drag-scroll-settings.d.ts +47 -0
  98. package/dist/es2015/scrolling/drag-scroll-settings.js +20 -0
  99. package/dist/es2015/scrolling/timeline-scroll.directive.d.ts +24 -0
  100. package/dist/es2015/scrolling/timeline-scroll.directive.js +78 -0
  101. package/dist/es2015/scrolling/timeline-scroll.service.d.ts +20 -0
  102. package/dist/es2015/scrolling/timeline-scroll.service.js +44 -0
  103. package/dist/es2015/scrolling/utils.d.ts +29 -0
  104. package/dist/es2015/scrolling/utils.js +80 -0
  105. package/dist/es2015/timeline/gantt-timeline.component.d.ts +25 -2
  106. package/dist/es2015/timeline/gantt-timeline.component.js +56 -3
  107. package/dist/es2015/toolbar/toolbar-template.directive.d.ts +1 -1
  108. package/dist/es2015/toolbar/toolbar.component.d.ts +2 -0
  109. package/dist/es2015/toolbar/toolbar.component.js +10 -0
  110. package/dist/es2015/utils.d.ts +70 -8
  111. package/dist/es2015/utils.js +143 -12
  112. package/dist/fesm2015/index.js +1981 -424
  113. package/dist/fesm5/index.js +1784 -391
  114. package/dist/npm/common/touch-enabled.js +11 -0
  115. package/dist/npm/dependencies/utils.js +40 -5
  116. package/dist/npm/dragging/dependency-drag-create.directive.js +349 -0
  117. package/dist/npm/dragging/drag-validation-tooltip.component.js +29 -0
  118. package/dist/npm/editing/add-task.component.js +96 -0
  119. package/dist/npm/editing/dependencies-table.component.js +133 -0
  120. package/dist/npm/editing/edit-dialog.component.js +36 -5
  121. package/dist/npm/editing/edit.service.js +88 -6
  122. package/dist/npm/editing/task-fields.component.js +45 -0
  123. package/dist/npm/editing/{util.js → utils.js} +0 -0
  124. package/dist/npm/expanded-state/expandable.directive.js +3 -5
  125. package/dist/npm/gantt.component.js +231 -46
  126. package/dist/npm/gantt.module.js +34 -8
  127. package/dist/npm/index.js +16 -2
  128. package/dist/npm/localization/gantt-localization.service.js +28 -0
  129. package/dist/npm/localization/messages.js +45 -1
  130. package/dist/npm/main.js +2 -0
  131. package/dist/npm/models/dependency-type.enum.js +16 -0
  132. package/dist/npm/models/events/{add-event.interface.js → dependency-add-event.interface.js} +0 -0
  133. package/dist/npm/models/events/{edit-event.interface.js → task-add-event.interface.js} +0 -0
  134. package/dist/npm/models/models.js +2 -0
  135. package/dist/npm/models/{events/remove-event.interface.js → toolbar-settings.js} +0 -0
  136. package/dist/npm/models/{toolbar-position.js → view-item.interface.js} +0 -0
  137. package/dist/npm/package-metadata.js +1 -1
  138. package/dist/npm/rendering/gantt-milestone-task.component.js +6 -3
  139. package/dist/npm/rendering/gantt-summary-task.component.js +6 -3
  140. package/dist/npm/rendering/gantt-task-base.js +30 -19
  141. package/dist/npm/rendering/gantt-task.component.js +7 -5
  142. package/dist/npm/rendering/gantt-tasks-table-body.component.js +5 -1
  143. package/dist/npm/scrolling/drag-scroll-settings.js +22 -0
  144. package/dist/npm/scrolling/timeline-scroll.directive.js +91 -0
  145. package/dist/npm/scrolling/timeline-scroll.service.js +41 -0
  146. package/dist/npm/scrolling/utils.js +83 -0
  147. package/dist/npm/timeline/gantt-timeline.component.js +44 -2
  148. package/dist/npm/toolbar/toolbar.component.js +9 -1
  149. package/dist/npm/utils.js +143 -12
  150. package/dist/systemjs/kendo-angular-gantt.js +1 -1
  151. package/package.json +9 -6
  152. package/dist/es/localization/treelist-messages.directive.js +0 -31
  153. package/dist/es2015/localization/treelist-messages.directive.js +0 -29
  154. package/dist/es2015/models/events/add-event.interface.d.ts +0 -16
  155. package/dist/es2015/models/events/edit-event.interface.d.ts +0 -19
  156. package/dist/es2015/models/events/remove-event.interface.d.ts +0 -16
  157. package/dist/es2015/models/toolbar-position.d.ts +0 -9
  158. package/dist/npm/localization/treelist-messages.directive.js +0 -33
@@ -3,25 +3,28 @@
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
- import { of, Subject, Subscription, fromEvent } from 'rxjs';
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 { map, distinctUntilChanged, take, filter, switchMap } from 'rxjs/operators';
16
- import { LocalizationService, ComponentMessages, L10N_PREFIX } from '@progress/kendo-angular-l10n';
15
+ import { getter, touchEnabled } from '@progress/kendo-common';
16
+ import { map, distinctUntilChanged, take, expand, reduce, filter, switchMap } from 'rxjs/operators';
17
17
  import { CommonModule } from '@angular/common';
18
- import { SplitterModule } from '@progress/kendo-angular-layout';
18
+ import { FormArray, FormGroup, FormControl, Validators, ReactiveFormsModule } from '@angular/forms';
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 { FormGroup, 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';
26
+ import { GridModule } from '@progress/kendo-angular-grid';
27
+ import { DropDownsModule } from '@progress/kendo-angular-dropdowns';
25
28
 
26
29
  /**
27
30
  * @hidden
@@ -30,7 +33,7 @@ const packageMetadata = {
30
33
  name: '@progress/kendo-angular-gantt',
31
34
  productName: 'Kendo UI for Angular',
32
35
  productCodes: ['KENDOUIANGULAR', 'KENDOUICOMPLETE'],
33
- publishDate: 1639071314,
36
+ publishDate: 1642086647,
34
37
  version: '',
35
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'
36
39
  };
@@ -632,6 +635,60 @@ const taskClassCallback = () => null;
632
635
  */
633
636
  const isSelected = () => false;
634
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
+
635
692
  /**
636
693
  * @hidden
637
694
  */
@@ -731,15 +788,34 @@ const isNumber = (contender) => typeof contender === 'number' && !isNaN(contende
731
788
  * @hidden
732
789
  */
733
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
+ };
734
810
  /**
735
811
  * @hidden
736
812
  *
737
813
  * Gets the closest timeline task element index from an event target.
738
814
  * Uses the `data-task-index` attribute assigned to each task.
739
- * 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.
740
816
  */
741
- const getClosestTaskIndex = (element, gantt) => {
742
- const task = closestInScope(element, matchesClasses('k-task'), gantt);
817
+ const getClosestTaskIndex = (element, parentScope) => {
818
+ const task = closestInScope(element, matchesClasses('k-task-wrap'), parentScope);
743
819
  if (!isPresent(task)) {
744
820
  return null;
745
821
  }
@@ -749,22 +825,133 @@ const getClosestTaskIndex = (element, gantt) => {
749
825
  * @hidden
750
826
  *
751
827
  * Checks whether the queried item or its parent items has a `k-task` selector.
752
- * 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.
753
829
  */
754
- const isTask = (contender, gantt) => {
755
- const task = closestInScope(contender, matchesClasses('k-task'), gantt);
830
+ const isTask = (contender, parentScope) => {
831
+ const task = closestInScope(contender, matchesClasses('k-task'), parentScope);
756
832
  return isPresent(task);
757
833
  };
758
834
  /**
759
835
  * @hidden
760
836
  *
761
837
  * Checks whether the queried item or its parent items has a `k-task-actions` selector - used for the clear button.
762
- * 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.
763
839
  */
764
- const isClearButton = (contender, gantt) => {
765
- const clearButtonContainer = closestInScope(contender, matchesClasses('k-task-actions'), gantt);
840
+ const isClearButton = (contender, parentScope) => {
841
+ const clearButtonContainer = closestInScope(contender, matchesClasses('k-task-actions'), parentScope);
766
842
  return isPresent(clearButtonContainer);
767
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
+ };
768
955
 
769
956
  /**
770
957
  * @hidden
@@ -1322,36 +1509,156 @@ DependencyDomService = __decorate([
1322
1509
  * @hidden
1323
1510
  */
1324
1511
  let EditService = class EditService {
1325
- /**
1326
- * @hidden
1327
- */
1328
- constructor() {
1512
+ constructor(mapper) {
1513
+ this.mapper = mapper;
1329
1514
  this.showEditingDialog = new Subject();
1330
1515
  this.showConfirmationDialog = new Subject();
1331
1516
  this.editEvent = new Subject();
1517
+ this.addEvent = new Subject();
1518
+ this.updatedItems = [];
1519
+ this.deletedItems = [];
1520
+ this.itemIndex = (item, data) => {
1521
+ return data.findIndex(dataItem => this.mapper.extractFromTask(dataItem, 'id') === this.mapper.extractFromTask(item, 'id'));
1522
+ };
1332
1523
  }
1333
- createEditDialog(dataItem, formGroup) {
1524
+ set dependencies(items) {
1525
+ // Can this whole thing be moved to edit-dialog? Dependencies might not be needed here
1526
+ const dataItemId = this.mapper.extractFromTask(this.dataItem, 'id');
1527
+ this.predecessors = items.filter(item => this.mapper.extractFromDependency(item, 'toId') === dataItemId);
1528
+ this.successors = items.filter(item => this.mapper.extractFromDependency(item, 'fromId') === dataItemId);
1529
+ }
1530
+ get dependencies() {
1531
+ return [...this.predecessors, ...this.successors];
1532
+ }
1533
+ createEditDialog(dataItem, taskFormGroup, dependencies) {
1334
1534
  this.dataItem = dataItem;
1335
- this.formGroup = formGroup;
1535
+ this.taskFormGroup = taskFormGroup;
1536
+ this.dependencies = dependencies;
1336
1537
  this.showEditingDialog.next(true);
1337
1538
  }
1338
1539
  closeEditDialog() {
1339
1540
  this.showEditingDialog.next(false);
1340
1541
  this.dataItem = undefined;
1341
- this.formGroup = undefined;
1542
+ this.taskFormGroup = undefined;
1543
+ this.dependencies = [];
1544
+ this.updatedItems = [];
1545
+ this.deletedItems = [];
1342
1546
  }
1343
1547
  triggerEditEvent(editResultType) {
1344
1548
  this.editEvent.next({
1345
- formGroup: this.formGroup,
1549
+ taskFormGroup: this.taskFormGroup,
1346
1550
  dataItem: this.dataItem,
1551
+ dependencies: {
1552
+ createdItems: this.getCreatedDependencies(),
1553
+ updatedItems: this.updatedItems,
1554
+ deletedItems: this.deletedItems
1555
+ },
1347
1556
  editResultType
1348
1557
  });
1349
1558
  }
1559
+ updateDependencies(item) {
1560
+ if (!this.isNew(item)) {
1561
+ // update
1562
+ const index = this.itemIndex(item, this.updatedItems);
1563
+ if (index !== -1) {
1564
+ this.updatedItems.splice(index, 1, item);
1565
+ }
1566
+ else {
1567
+ this.updatedItems.push(item);
1568
+ }
1569
+ }
1570
+ }
1571
+ getCreatedDependencies() {
1572
+ return this.dependencies.filter(item => this.mapper.extractFromDependency(item, 'id') === null);
1573
+ }
1574
+ deleteDependency(item) {
1575
+ const updatedIndex = this.itemIndex(item, this.updatedItems);
1576
+ if (updatedIndex !== -1) {
1577
+ this.updatedItems.splice(updatedIndex, 1);
1578
+ }
1579
+ if (!this.isNew(item)) {
1580
+ this.deletedItems.push(item);
1581
+ }
1582
+ }
1583
+ loadTasks(initialValues, isInitializer = true) {
1584
+ return forkJoin(initialValues.map(v => this.getElementById(v))).pipe(map((value) => value.reduce((acc, item) => acc = acc.concat(normalizeGanttData(item)), [])), expand(values => {
1585
+ if (values.some(el => this.hasChildren(el))) {
1586
+ return this.loadTasks(values, false);
1587
+ }
1588
+ return EMPTY;
1589
+ }), reduce((acc, values) => acc.concat(values), isInitializer ? [...initialValues] : []));
1590
+ }
1591
+ getElementById(item) {
1592
+ const children = this.fetchChildren(item);
1593
+ if (isObservable(children)) {
1594
+ return children;
1595
+ }
1596
+ return of(children);
1597
+ }
1598
+ isNew(item) {
1599
+ return !isPresent(this.mapper.extractFromDependency(item, 'id'));
1600
+ }
1350
1601
  };
1351
1602
  EditService = __decorate([
1352
- Injectable()
1603
+ Injectable(),
1604
+ __metadata("design:paramtypes", [MappingService])
1353
1605
  ], EditService);
1354
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
+
1355
1662
  /**
1356
1663
  * @hidden
1357
1664
  */
@@ -1610,39 +1917,289 @@ ToolbarTemplateDirective = __decorate([
1610
1917
  ], ToolbarTemplateDirective);
1611
1918
 
1612
1919
  /**
1613
- * The base class for the column components of the Gantt.
1920
+ * @hidden
1614
1921
  */
1615
- 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
+ }
1616
1945
  /**
1617
- *
1618
- * @hidden
1946
+ * Specifies whether the draggable will attach or detach its pointer event listeners.
1619
1947
  */
1620
- constructor(optionChangesService, dependencyDomService) {
1621
- this.optionChangesService = optionChangesService;
1622
- this.dependencyDomService = dependencyDomService;
1623
- /**
1624
- * The width of the time slot headers. Values are treated as pixels.
1625
- *
1626
- * @default 100
1627
- */
1628
- this.slotWidth = 100;
1948
+ get draggableEnabled() {
1949
+ return this.renderDependencyDragClues;
1629
1950
  }
1630
- ngOnChanges(changes) {
1631
- if (anyChanged(['slotWidth'], changes)) {
1632
- this.optionChangesService.notifyColumnChanges();
1633
- this.dependencyDomService.notifyChanges();
1634
- }
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);
1635
1957
  }
1636
- }
1958
+ ngOnDestroy() {
1959
+ this.subscriptions.unsubscribe();
1960
+ }
1961
+ isNonWorking(item) {
1962
+ return item.hasOwnProperty('isWorking') && !item.isWorking;
1963
+ }
1964
+ };
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);
1637
2005
  __decorate([
1638
2006
  Input(),
1639
2007
  __metadata("design:type", Number)
1640
- ], ViewBase.prototype, "slotWidth", void 0);
1641
-
1642
- /**
1643
- * @hidden
1644
- */
1645
- const getEditItem = (dataItem, data, mapper) => {
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) => {
1646
2203
  const treeListDataItem = data.find(item => mapper.extractFromTask(item.data, 'id') === mapper.extractFromTask(dataItem, 'id'));
1647
2204
  return mapPath(treeListDataItem);
1648
2205
  };
@@ -1654,6 +2211,12 @@ const mapPath = (item) => ({
1654
2211
  var GanttComponent_1;
1655
2212
  const TREELIST_GROUP_COLUMNS_CLASS = 'k-gantt-treelist-nested-columns';
1656
2213
  const DEFAULT_VIEW = 'week';
2214
+ const DEFAULT_DRAG_SCROLL_SETTINGS = {
2215
+ enabled: true,
2216
+ step: 3,
2217
+ interval: 1,
2218
+ threshold: 10
2219
+ };
1657
2220
  /**
1658
2221
  * Represents the Kendo UI Gantt component for Angular.
1659
2222
  *
@@ -1739,11 +2302,22 @@ let GanttComponent = GanttComponent_1 = class GanttComponent {
1739
2302
  this.zone = zone;
1740
2303
  this.hostClasses = true;
1741
2304
  /**
1742
- * 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)).
1743
2306
  *
1744
2307
  * > The [`selectable`]({% slug api_gantt_ganttcomponent %}#toc-selectable) prop has to be set to `true` in order for this callback to be executed.
1745
2308
  */
1746
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);
1747
2321
  /**
1748
2322
  * Fires when the Gantt selection is changed through user interaction.
1749
2323
  *
@@ -1759,25 +2333,6 @@ let GanttComponent = GanttComponent_1 = class GanttComponent {
1759
2333
  * > When applied, the [`SelectableDirective`]({% slug api_gantt_selectabledirective %}) sets `selectable` to `true` internally.
1760
2334
  */
1761
2335
  this.selectable = false;
1762
- /**
1763
- * The position of the toolbar.
1764
- *
1765
- * The possible values are:
1766
- * - `top`&mdash;Positions the toolbar above the Gantt panes.
1767
- * - `bottom`&mdash;Positions the toolbar below the Gantt panes.
1768
- * - `both`&mdash;Displays two toolbar instances. Positions the first one above,
1769
- * and the second one - below the Gantt panes.
1770
- * - `none`&mdash;No toolbar is rendered.
1771
- */
1772
- this.toolbarPosition = 'top';
1773
- /**
1774
- * Gets or sets the callback function that retrieves the child items for a particular item.
1775
- */
1776
- this.fetchChildren = fetchChildren;
1777
- /**
1778
- * Gets or sets the callback function that indicates if a particular item has child items.
1779
- */
1780
- this.hasChildren = hasChildren;
1781
2336
  /**
1782
2337
  * Defines the dependencies that will be drawn between the rendered tasks.
1783
2338
  *
@@ -1879,6 +2434,15 @@ let GanttComponent = GanttComponent_1 = class GanttComponent {
1879
2434
  * Fires when the user saves an edited task.
1880
2435
  */
1881
2436
  this.save = new EventEmitter();
2437
+ /**
2438
+ * Fires when the user adds a task.
2439
+ */
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();
1882
2446
  /**
1883
2447
  * Fires when the sorting of the Gantt is changed.
1884
2448
  * You have to handle the event yourself and sort the data.
@@ -1935,6 +2499,15 @@ let GanttComponent = GanttComponent_1 = class GanttComponent {
1935
2499
  * Fires when a task is clicked.
1936
2500
  */
1937
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;
1938
2511
  /**
1939
2512
  * @hidden
1940
2513
  *
@@ -1951,11 +2524,19 @@ let GanttComponent = GanttComponent_1 = class GanttComponent {
1951
2524
  this.showConfirmationDialog = false;
1952
2525
  this._columns = new QueryList();
1953
2526
  this._data = [];
2527
+ this._dragScrollSettings = Object.assign({}, DEFAULT_DRAG_SCROLL_SETTINGS);
1954
2528
  this._timelinePaneOptions = Object.assign({}, DEFAULT_TIMELINE_PANE_SETTINGS);
1955
2529
  this._treeListPaneOptions = Object.assign({}, DEFAULT_TREELIST_PANE_SETTINGS);
1956
2530
  this._rowClass = rowClassCallback;
1957
2531
  this._taskClass = taskClassCallback;
1958
2532
  this._activeView = DEFAULT_VIEW;
2533
+ this._toolbarSettings = {
2534
+ position: 'top',
2535
+ addTaskTool: 'none',
2536
+ viewSelectorTool: 'top'
2537
+ };
2538
+ this._fetchChildren = fetchChildren;
2539
+ this._hasChildren = hasChildren;
1959
2540
  this.rtl = false;
1960
2541
  this.optionChangesSubscriptions = new Subscription();
1961
2542
  this.editServiceSubscription = new Subscription();
@@ -1966,16 +2547,26 @@ let GanttComponent = GanttComponent_1 = class GanttComponent {
1966
2547
  this.optionChangesSubscriptions.add(this.optionChangesService.columnChanges.subscribe(() => {
1967
2548
  this.treeList.columns.notifyOnChanges();
1968
2549
  }));
2550
+ this.editService.getSelectedItem = this.getFirstSelectedItem.bind(this);
1969
2551
  this.editServiceSubscription.add(this.editService.showEditingDialog.subscribe(show => this.showEditingDialog = show));
1970
2552
  this.editServiceSubscription.add(this.editService.showConfirmationDialog.subscribe(() => this.taskDelete.emit()));
1971
2553
  this.editServiceSubscription.add(this.editService.editEvent.subscribe(args => {
1972
2554
  this[args.editResultType].emit({
1973
- formGroup: args.formGroup,
2555
+ taskFormGroup: args.taskFormGroup,
1974
2556
  item: getEditItem(args.dataItem, this.treeList.view.data, this.mapper),
2557
+ dependencies: args.dependencies,
1975
2558
  sender: this
1976
2559
  });
1977
2560
  this.showConfirmationDialog = this.showEditingDialog = false;
1978
- this.editService.dataItem = this.editService.formGroup = null;
2561
+ this.editService.dataItem = this.editService.taskFormGroup = null;
2562
+ this.updateView();
2563
+ }));
2564
+ this.editServiceSubscription.add(this.editService.addEvent.subscribe(args => {
2565
+ const selectedItem = this.getFirstSelectedItem();
2566
+ this.taskAdd.emit({
2567
+ actionType: args.actionType,
2568
+ selectedItem: selectedItem ? getEditItem(selectedItem, this.treeList.view.data, this.mapper) : null
2569
+ });
1979
2570
  this.updateView();
1980
2571
  }));
1981
2572
  this.localizationSubscription = this.localizationService.changes.subscribe(({ rtl }) => {
@@ -2051,6 +2642,49 @@ let GanttComponent = GanttComponent_1 = class GanttComponent {
2051
2642
  get data() {
2052
2643
  return this._data;
2053
2644
  }
2645
+ /**
2646
+ * The toolbar configuration. Defines the position and content of the toolbar(s).
2647
+ * The available properties are `position`, `addTaskTool`, and `viewSelectorTool`.
2648
+ * All are optional and default to `top`.
2649
+ *
2650
+ * The possible values for each option are:
2651
+ * - `top`&mdash;Positions the toolbar above the Gantt panes. Renders the respective tool in the top toolbar.
2652
+ * - `bottom`&mdash;Positions the toolbar below the Gantt panes. Renders the respective tool in the bottom toolbar.
2653
+ * - `both`&mdash;Displays two toolbar instances. Positions the first one above,
2654
+ * and the second one - below the Gantt panes. Renders the respective tool in the both toolbars.
2655
+ * - `none`&mdash;No toolbar is rendered when used for setting `position`.
2656
+ * No add task or view selector tool is rendered when used for setting `addTaskTool` or `viewSelectorTool`.
2657
+ */
2658
+ set toolbarSettings(value) {
2659
+ this._toolbarSettings = {
2660
+ position: value.position || 'top',
2661
+ addTaskTool: value.addTaskTool || 'none',
2662
+ viewSelectorTool: value.viewSelectorTool || 'top'
2663
+ };
2664
+ }
2665
+ get toolbarSettings() {
2666
+ return this._toolbarSettings;
2667
+ }
2668
+ /**
2669
+ * Gets or sets the callback function that retrieves the child items for a particular item.
2670
+ */
2671
+ set fetchChildren(fn) {
2672
+ this._fetchChildren = fn;
2673
+ this.editService.fetchChildren = fn;
2674
+ }
2675
+ get fetchChildren() {
2676
+ return this._fetchChildren;
2677
+ }
2678
+ /**
2679
+ * Gets or sets the callback function that indicates if a particular item has child items.
2680
+ */
2681
+ set hasChildren(fn) {
2682
+ this._hasChildren = fn;
2683
+ this.editService.hasChildren = fn;
2684
+ }
2685
+ get hasChildren() {
2686
+ return this._hasChildren;
2687
+ }
2054
2688
  /**
2055
2689
  * The options of the timeline splitter pane. By default the pane is `collapsible`,
2056
2690
  * `resizable`, not `collapsed`, and its `size` is `'50%'`.
@@ -2106,6 +2740,17 @@ let GanttComponent = GanttComponent_1 = class GanttComponent {
2106
2740
  get taskIdField() {
2107
2741
  return this.mapper.taskFields.id;
2108
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
+ }
2109
2754
  /**
2110
2755
  * @hidden
2111
2756
  */
@@ -2158,12 +2803,6 @@ let GanttComponent = GanttComponent_1 = class GanttComponent {
2158
2803
  get viewTypes() {
2159
2804
  return this.views.map(view => view.type);
2160
2805
  }
2161
- /**
2162
- * @hidden
2163
- */
2164
- get editDialogFormGroup() {
2165
- return this.editService.formGroup;
2166
- }
2167
2806
  ngOnChanges(changes) {
2168
2807
  if (anyChanged(['data', 'activeView', 'workWeekStart', 'workWeekEnd', 'workDayStart', 'workDayEnd'], changes)) {
2169
2808
  this.loadTimelineData();
@@ -2252,7 +2891,10 @@ let GanttComponent = GanttComponent_1 = class GanttComponent {
2252
2891
  */
2253
2892
  editTask(dataItem, formGroup) {
2254
2893
  if (!this.showEditingDialog) {
2255
- this.editService.createEditDialog(dataItem, formGroup);
2894
+ const taskId = this.mapper.extractFromTask(dataItem, 'id');
2895
+ const dependencies = this.dependencies.filter(item => this.mapper.extractFromDependency(item, 'toId') === taskId
2896
+ || this.mapper.extractFromDependency(item, 'fromId') === taskId);
2897
+ this.editService.createEditDialog(dataItem, formGroup, dependencies);
2256
2898
  }
2257
2899
  }
2258
2900
  /**
@@ -2325,7 +2967,7 @@ let GanttComponent = GanttComponent_1 = class GanttComponent {
2325
2967
  * @hidden
2326
2968
  */
2327
2969
  showToolbar(position) {
2328
- return this.toolbarPosition !== 'none' && ([position, 'both'].indexOf(this.toolbarPosition) > -1);
2970
+ return this.toolbarSettings.position !== 'none' && ([position, 'both'].indexOf(this.toolbarSettings.position) > -1);
2329
2971
  }
2330
2972
  /**
2331
2973
  * @hidden
@@ -2524,11 +3166,65 @@ let GanttComponent = GanttComponent_1 = class GanttComponent {
2524
3166
  const shouldToggleSelection = ctrlKey || metaKey;
2525
3167
  return (shouldToggleSelection && this.isSelected(dataItem)) ? 'remove' : 'select';
2526
3168
  }
3169
+ getFirstSelectedItem() {
3170
+ const isSelectedCallback = this.isSelected || isSelected;
3171
+ const loadedItems = this.renderedTreeListItems || [];
3172
+ return loadedItems.find(isSelectedCallback);
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
+ }
2527
3219
  };
2528
3220
  __decorate([
2529
3221
  ViewChild(TreeListComponent, { static: true }),
2530
3222
  __metadata("design:type", TreeListComponent)
2531
3223
  ], GanttComponent.prototype, "treeList", void 0);
3224
+ __decorate([
3225
+ ViewChild(GanttTimelineComponent, { static: false }),
3226
+ __metadata("design:type", GanttTimelineComponent)
3227
+ ], GanttComponent.prototype, "timeline", void 0);
2532
3228
  __decorate([
2533
3229
  ContentChild(GanttTaskContentTemplateDirective, { static: true }),
2534
3230
  __metadata("design:type", GanttTaskContentTemplateDirective)
@@ -2587,6 +3283,10 @@ __decorate([
2587
3283
  Input(),
2588
3284
  __metadata("design:type", Function)
2589
3285
  ], GanttComponent.prototype, "isSelected", void 0);
3286
+ __decorate([
3287
+ Input(),
3288
+ __metadata("design:type", Function)
3289
+ ], GanttComponent.prototype, "validateNewDependency", void 0);
2590
3290
  __decorate([
2591
3291
  Output(),
2592
3292
  __metadata("design:type", EventEmitter)
@@ -2597,16 +3297,19 @@ __decorate([
2597
3297
  ], GanttComponent.prototype, "selectable", void 0);
2598
3298
  __decorate([
2599
3299
  Input(),
2600
- __metadata("design:type", String)
2601
- ], GanttComponent.prototype, "toolbarPosition", void 0);
3300
+ __metadata("design:type", Object),
3301
+ __metadata("design:paramtypes", [Object])
3302
+ ], GanttComponent.prototype, "toolbarSettings", null);
2602
3303
  __decorate([
2603
3304
  Input(),
2604
- __metadata("design:type", Function)
2605
- ], GanttComponent.prototype, "fetchChildren", void 0);
3305
+ __metadata("design:type", Function),
3306
+ __metadata("design:paramtypes", [Function])
3307
+ ], GanttComponent.prototype, "fetchChildren", null);
2606
3308
  __decorate([
2607
3309
  Input(),
2608
- __metadata("design:type", Function)
2609
- ], GanttComponent.prototype, "hasChildren", void 0);
3310
+ __metadata("design:type", Function),
3311
+ __metadata("design:paramtypes", [Function])
3312
+ ], GanttComponent.prototype, "hasChildren", null);
2610
3313
  __decorate([
2611
3314
  Input(),
2612
3315
  __metadata("design:type", Array)
@@ -2683,6 +3386,11 @@ __decorate([
2683
3386
  Input(),
2684
3387
  __metadata("design:type", Boolean)
2685
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);
2686
3394
  __decorate([
2687
3395
  Output(),
2688
3396
  __metadata("design:type", EventEmitter)
@@ -2719,6 +3427,14 @@ __decorate([
2719
3427
  Output(),
2720
3428
  __metadata("design:type", EventEmitter)
2721
3429
  ], GanttComponent.prototype, "save", void 0);
3430
+ __decorate([
3431
+ Output(),
3432
+ __metadata("design:type", EventEmitter)
3433
+ ], GanttComponent.prototype, "taskAdd", void 0);
3434
+ __decorate([
3435
+ Output(),
3436
+ __metadata("design:type", EventEmitter)
3437
+ ], GanttComponent.prototype, "dependencyAdd", void 0);
2722
3438
  __decorate([
2723
3439
  Output(),
2724
3440
  __metadata("design:type", EventEmitter)
@@ -2776,6 +3492,7 @@ GanttComponent = GanttComponent_1 = __decorate([
2776
3492
  selector: 'kendo-gantt',
2777
3493
  exportAs: 'kendoGantt',
2778
3494
  providers: [
3495
+ GanttLocalizationService,
2779
3496
  LocalizationService,
2780
3497
  {
2781
3498
  provide: DataBoundTreeComponent,
@@ -2793,17 +3510,39 @@ GanttComponent = GanttComponent_1 = __decorate([
2793
3510
  DependencyDomService,
2794
3511
  MappingService,
2795
3512
  OptionChangesService,
2796
- EditService
3513
+ EditService,
3514
+ TimelineScrollService
2797
3515
  ],
2798
3516
  template: `
2799
3517
  <ng-container kendoGanttLocalizedMessages
2800
- i18n-taskDeleteLabel="kendo.gantt.taskDeleteLabel|The label of the task delete icon"
2801
- taskDeleteLabel="Delete"
3518
+ i18n-taskEditingGeneralTabTitle="kendo.gantt.taskEditingGeneralTabTitle|The title of the 'General' tab of the editing dialog TabStrip"
3519
+ taskEditingGeneralTabTitle="General"
2802
3520
 
2803
- i18n-taskEditingDialogTitle="kendo.gantt.taskEditingDialogTitle|The title of the task editing dialog"
2804
- taskEditingDialogTitle="Editing Task"
3521
+ i18n-taskEditingPredecessorsTabTitle="kendo.gantt.taskEditingPredecessorsTabTitle|The title of the 'Predecessors' dependencies tab of the editing dialog TabStrip"
3522
+ taskEditingPredecessorsTabTitle="Predecessors"
2805
3523
 
2806
- i18n-taskEditingDialogCloseTitle="kendo.gantt.taskEditingDialogCloseTitle|The title of the task editing dialog close button"
3524
+ i18n-taskEditingSuccessorsTabTitle="kendo.gantt.taskEditingSuccessorsTabTitle|The title of the 'Successors' dependencies tab of the editing dialog TabStrip"
3525
+ taskEditingSuccessorsTabTitle="Successors"
3526
+
3527
+ i18n-taskEditingDependenciesAddButtonText="kendo.gantt.taskEditingDependenciesAddButtonText|The text of the 'Add' button in the dependencies tabs of the editing dialog TabStrip"
3528
+ taskEditingDependenciesAddButtonText="Add"
3529
+
3530
+ i18n-taskEditingDependenciesRemoveButtonText="kendo.gantt.taskEditingDependenciesRemoveButtonText|The text of the 'Remove' button in the dependencies tabs of the editing dialog TabStrip"
3531
+ taskEditingDependenciesRemoveButtonText="Remove"
3532
+
3533
+ i18n-taskEditingDependenciesGridNameColumnTitle="kendo.gantt.taskEditingDependenciesGridNameColumnTitle|The title of the 'Task Title' Grid column in the dependencies tabs of the editing dialog TabStrip"
3534
+ taskEditingDependenciesGridNameColumnTitle="Task Title"
3535
+
3536
+ i18n-taskEditingDependenciesGridTypeColumnTitle="kendo.gantt.taskEditingDependenciesGridTypeColumnTitle|The title of the 'Type' Grid column in the dependencies tabs of the editing dialog TabStrip"
3537
+ taskEditingDependenciesGridTypeColumnTitle="Type"
3538
+
3539
+ i18n-taskDeleteLabel="kendo.gantt.taskDeleteLabel|The label of the task delete icon"
3540
+ taskDeleteLabel="Delete"
3541
+
3542
+ i18n-taskEditingDialogTitle="kendo.gantt.taskEditingDialogTitle|The title of the task editing dialog"
3543
+ taskEditingDialogTitle="Editing Task"
3544
+
3545
+ i18n-taskEditingDialogCloseTitle="kendo.gantt.taskEditingDialogCloseTitle|The title of the task editing dialog close button"
2807
3546
  taskEditingDialogCloseTitle="Close"
2808
3547
 
2809
3548
  i18n-confirmationDialogCloseTitle="kendo.gantt.confirmationDialogCloseTitle|The title of the confirmation dialog close button"
@@ -2848,6 +3587,18 @@ GanttComponent = GanttComponent_1 = __decorate([
2848
3587
  i18n-yearViewText-disabled="kendo.gantt.yearViewText|The text of the year view in the ViewSelector component"
2849
3588
  yearViewText="Year"
2850
3589
 
3590
+ i18n-addTaskText="kendo.gantt.addTaskText|The text of the DropDownButton in the AddTask component"
3591
+ addTaskText="Add Task"
3592
+
3593
+ i18n-addChildText="kendo.gantt.addChildText|The text of the 'Add Child' option in the AddTask component"
3594
+ addChildText="Add Child"
3595
+
3596
+ i18n-addAboveText="kendo.gantt.addAboveText|The text of the 'Add Above' option in the AddTask component"
3597
+ addAboveText="Add Above"
3598
+
3599
+ i18n-addBelowText="kendo.gantt.addBelowText|The text of the 'Add Below' option in the AddTask component"
3600
+ addBelowText="Add Below"
3601
+
2851
3602
  i18n-noRecords="kendo.gantt.noRecords|The label visible in the TreeList when there are no records"
2852
3603
  noRecords="No records available."
2853
3604
 
@@ -2969,6 +3720,8 @@ GanttComponent = GanttComponent_1 = __decorate([
2969
3720
  columnsReset="Reset"></ng-container>
2970
3721
  <kendo-gantt-toolbar
2971
3722
  *ngIf="showToolbar('top')"
3723
+ [showAddTask]="toolbarSettings.addTaskTool === 'top' || toolbarSettings.addTaskTool === 'both'"
3724
+ [showViewSelector]="toolbarSettings.viewSelectorTool === 'top' || toolbarSettings.viewSelectorTool === 'both'"
2972
3725
  class="k-gantt-header k-toolbar k-gantt-toolbar"
2973
3726
  position="top"></kendo-gantt-toolbar>
2974
3727
  <div class="k-gantt-content">
@@ -3018,7 +3771,47 @@ GanttComponent = GanttComponent_1 = __decorate([
3018
3771
  }"
3019
3772
  [scope]="this"
3020
3773
  >
3021
- <kendo-treelist-messages [kendoGanttTreeListMessages]="localizationService"></kendo-treelist-messages>
3774
+ <kendo-treelist-messages
3775
+ [noRecords]="getText('noRecords')"
3776
+ [filter]="getText('filter')"
3777
+ [filterEqOperator]="getText('filterEqOperator')"
3778
+ [filterNotEqOperator]="getText('filterNotEqOperator')"
3779
+ [filterIsNullOperator]="getText('filterIsNullOperator')"
3780
+ [filterIsNotNullOperator]="getText('filterIsNotNullOperator')"
3781
+ [filterIsEmptyOperator]="getText('filterIsEmptyOperator')"
3782
+ [filterIsNotEmptyOperator]="getText('filterIsNotEmptyOperator')"
3783
+ [filterStartsWithOperator]="getText('filterStartsWithOperator')"
3784
+ [filterContainsOperator]="getText('filterContainsOperator')"
3785
+ [filterNotContainsOperator]="getText('filterNotContainsOperator')"
3786
+ [filterEndsWithOperator]="getText('filterEndsWithOperator')"
3787
+ [filterGteOperator]="getText('filterGteOperator')"
3788
+ [filterGtOperator]="getText('filterGtOperator')"
3789
+ [filterLteOperator]="getText('filterLteOperator')"
3790
+ [filterLtOperator]="getText('filterLtOperator')"
3791
+ [filterIsTrue]="getText('filterIsTrue')"
3792
+ [filterIsFalse]="getText('filterIsFalse')"
3793
+ [filterBooleanAll]="getText('filterBooleanAll')"
3794
+ [filterAfterOrEqualOperator]="getText('filterAfterOrEqualOperator')"
3795
+ [filterAfterOperator]="getText('filterAfterOperator')"
3796
+ [filterBeforeOperator]="getText('filterBeforeOperator')"
3797
+ [filterBeforeOrEqualOperator]="getText('filterBeforeOrEqualOperator')"
3798
+ [filterFilterButton]="getText('filterFilterButton')"
3799
+ [filterClearButton]="getText('filterClearButton')"
3800
+ [filterAndLogic]="getText('filterAndLogic')"
3801
+ [filterOrLogic]="getText('filterOrLogic')"
3802
+ [loading]="getText('loading')"
3803
+ [columnMenu]="getText('columnMenu')"
3804
+ [columns]="getText('columns')"
3805
+ [sortable]="getText('sortable')"
3806
+ [sortAscending]="getText('sortAscending')"
3807
+ [sortDescending]="getText('sortDescending')"
3808
+ [sortedAscending]="getText('sortedAscending')"
3809
+ [sortedDescending]="getText('sortedDescending')"
3810
+ [sortedDefault]="getText('sortedDefault')"
3811
+ [columnsApply]="getText('columnsApply')"
3812
+ [columnsReset]="getText('columnsReset')"
3813
+ >
3814
+ </kendo-treelist-messages>
3022
3815
  </kendo-treelist>
3023
3816
  </kendo-splitter-pane>
3024
3817
  <kendo-splitter-pane
@@ -3033,6 +3826,8 @@ GanttComponent = GanttComponent_1 = __decorate([
3033
3826
  [scrollable]="false">
3034
3827
  <kendo-gantt-timeline
3035
3828
  *ngIf="views && views.length"
3829
+ [renderDependencyDragClues]="renderDependencyDragClues"
3830
+ [dragScrollSettings]="dragScrollSettings"
3036
3831
  [rows]="renderedTreeListItems"
3037
3832
  [slots]="timelineSlots"
3038
3833
  [groupSlots]="timelineGroupSlots"
@@ -3058,16 +3853,21 @@ GanttComponent = GanttComponent_1 = __decorate([
3058
3853
  </div>
3059
3854
  <kendo-gantt-toolbar
3060
3855
  *ngIf="showToolbar('bottom')"
3856
+ [showAddTask]="toolbarSettings.addTaskTool === 'bottom' || toolbarSettings.addTaskTool === 'both'"
3857
+ [showViewSelector]="toolbarSettings.viewSelectorTool === 'bottom' || toolbarSettings.viewSelectorTool === 'both'"
3061
3858
  class="k-gantt-footer k-toolbar k-gantt-toolbar"
3062
3859
  position="bottom"></kendo-gantt-toolbar>
3063
- <kendo-gantt-edit-dialog *ngIf="showEditingDialog" [formGroup]="editDialogFormGroup"></kendo-gantt-edit-dialog>
3860
+ <kendo-gantt-edit-dialog
3861
+ *ngIf="showEditingDialog"
3862
+ [data]="data">
3863
+ </kendo-gantt-edit-dialog>
3064
3864
  <kendo-dialog
3065
3865
  *ngIf="showConfirmationDialog"
3066
3866
  [width]="575"
3067
3867
  [height]="170"
3068
3868
  [title]="getText('confirmationDialogTitle')"
3069
3869
  (close)="showConfirmationDialog = false;">
3070
- <span>{{getText('confirmationDialogContent')}}</span>
3870
+ <span>{{ getText('confirmationDialogContent') }}</span>
3071
3871
  <kendo-dialog-actions layout="normal">
3072
3872
  <kendo-treelist-spacer></kendo-treelist-spacer>
3073
3873
  <button kendoButton [primary]="true" (click)="handleDeleteConfirmation()">{{ getText('deleteButtonText') }}</button>
@@ -3091,199 +3891,7 @@ GanttComponent = GanttComponent_1 = __decorate([
3091
3891
  /**
3092
3892
  * @hidden
3093
3893
  */
3094
- let GanttTimelineComponent = class GanttTimelineComponent {
3095
- constructor(scrollSyncService, dependencyDomService, renderer, zone) {
3096
- this.scrollSyncService = scrollSyncService;
3097
- this.dependencyDomService = dependencyDomService;
3098
- this.renderer = renderer;
3099
- this.zone = zone;
3100
- this.hostClass = true;
3101
- this.dependencies = [];
3102
- this.subscriptions = new Subscription();
3103
- this.subscriptions.add(
3104
- // task changes indicates change in row content, number, height, etc.
3105
- this.dependencyDomService.taskChanges
3106
- .pipe(filter(args => isPresent(args.timelineRow)), switchMap(args => this.zone.onStable.pipe(take(1), map(() => args))) // ensure the content is rendered
3107
- )
3108
- .subscribe(({ timelineRow }) => {
3109
- const timelineRowHeight = isDocumentAvailable() ? timelineRow.getBoundingClientRect().height : 0;
3110
- this.renderer.setStyle(this.timelineColumns.nativeElement, 'height', `${(this.rows || []).length * timelineRowHeight}px`);
3111
- }));
3112
- }
3113
- ngAfterViewInit() {
3114
- const timelineHeader = this.timelineHeaderWrap.nativeElement;
3115
- const rightContainer = this.timelineContent.nativeElement;
3116
- this.scrollSyncService.registerElement(rightContainer, 'timeline');
3117
- this.scrollSyncService.registerElement(timelineHeader, 'header');
3118
- this.dependencyDomService.registerContentContainer(this.tasksContainer.nativeElement);
3119
- }
3120
- ngOnDestroy() {
3121
- this.subscriptions.unsubscribe();
3122
- }
3123
- isNonWorking(item) {
3124
- return item.hasOwnProperty('isWorking') && !item.isWorking;
3125
- }
3126
- };
3127
- __decorate([
3128
- ViewChild('timelineContent', { static: true }),
3129
- __metadata("design:type", ElementRef)
3130
- ], GanttTimelineComponent.prototype, "timelineContent", void 0);
3131
- __decorate([
3132
- ViewChild('timelineColumns', { static: true }),
3133
- __metadata("design:type", ElementRef)
3134
- ], GanttTimelineComponent.prototype, "timelineColumns", void 0);
3135
- __decorate([
3136
- ViewChild('timelineHeaderWrap', { static: true }),
3137
- __metadata("design:type", ElementRef)
3138
- ], GanttTimelineComponent.prototype, "timelineHeaderWrap", void 0);
3139
- __decorate([
3140
- ViewChild('tasksContainer', { static: true }),
3141
- __metadata("design:type", ElementRef)
3142
- ], GanttTimelineComponent.prototype, "tasksContainer", void 0);
3143
- __decorate([
3144
- HostBinding('class.k-gantt-timeline'),
3145
- __metadata("design:type", Boolean)
3146
- ], GanttTimelineComponent.prototype, "hostClass", void 0);
3147
- __decorate([
3148
- Input(),
3149
- __metadata("design:type", Array)
3150
- ], GanttTimelineComponent.prototype, "rows", void 0);
3151
- __decorate([
3152
- Input(),
3153
- __metadata("design:type", Array)
3154
- ], GanttTimelineComponent.prototype, "slots", void 0);
3155
- __decorate([
3156
- Input(),
3157
- __metadata("design:type", Array)
3158
- ], GanttTimelineComponent.prototype, "groupSlots", void 0);
3159
- __decorate([
3160
- Input(),
3161
- __metadata("design:type", Number)
3162
- ], GanttTimelineComponent.prototype, "tableWidth", void 0);
3163
- __decorate([
3164
- Input(),
3165
- __metadata("design:type", String)
3166
- ], GanttTimelineComponent.prototype, "activeView", void 0);
3167
- __decorate([
3168
- Input(),
3169
- __metadata("design:type", TemplateRef)
3170
- ], GanttTimelineComponent.prototype, "taskContentTemplate", void 0);
3171
- __decorate([
3172
- Input(),
3173
- __metadata("design:type", TemplateRef)
3174
- ], GanttTimelineComponent.prototype, "taskTemplate", void 0);
3175
- __decorate([
3176
- Input(),
3177
- __metadata("design:type", TemplateRef)
3178
- ], GanttTimelineComponent.prototype, "summaryTaskTemplate", void 0);
3179
- __decorate([
3180
- Input(),
3181
- __metadata("design:type", Function)
3182
- ], GanttTimelineComponent.prototype, "taskClass", void 0);
3183
- __decorate([
3184
- Input(),
3185
- __metadata("design:type", Function)
3186
- ], GanttTimelineComponent.prototype, "isTaskSelected", void 0);
3187
- __decorate([
3188
- Input(),
3189
- __metadata("design:type", Function)
3190
- ], GanttTimelineComponent.prototype, "hasChildren", void 0);
3191
- __decorate([
3192
- Input(),
3193
- __metadata("design:type", Array)
3194
- ], GanttTimelineComponent.prototype, "dependencies", void 0);
3195
- GanttTimelineComponent = __decorate([
3196
- Component({
3197
- selector: 'kendo-gantt-timeline',
3198
- template: `
3199
- <div class="k-timeline k-grid k-widget">
3200
- <div class="k-grid-header">
3201
- <div #timelineHeaderWrap class="k-grid-header-wrap">
3202
- <table
3203
- role="presentation"
3204
- [style.width.px]="tableWidth"
3205
- >
3206
- <tbody
3207
- kendoGanttHeaderTableBody
3208
- [groupSlots]="groupSlots"
3209
- [slots]="slots">
3210
- </tbody>
3211
- </table>
3212
- </div>
3213
- </div>
3214
- <div #timelineContent class="k-grid-content">
3215
- <div class="k-gantt-tables">
3216
- <table
3217
- class="k-gantt-rows"
3218
- [style.width.px]="tableWidth"
3219
- role="presentation"
3220
- >
3221
- <tbody>
3222
- <tr *ngFor="let item of rows; let i = index;"
3223
- [class.k-alt]="i % 2"
3224
- >
3225
- <td></td>
3226
- </tr>
3227
- </tbody>
3228
- </table>
3229
-
3230
- <table
3231
- #timelineColumns
3232
- class="k-gantt-columns"
3233
- role="presentation"
3234
- [style.width.px]="tableWidth"
3235
- >
3236
- <colgroup>
3237
- <col *ngFor="let item of slots">
3238
- </colgroup>
3239
-
3240
- <tbody>
3241
- <tr>
3242
- <td *ngFor="let item of slots"
3243
- [class.k-nonwork-hour]="isNonWorking(item)"
3244
- >
3245
- </td>
3246
- </tr>
3247
- </tbody>
3248
- </table>
3249
-
3250
- <table
3251
- #tasksContainer
3252
- class="k-gantt-tasks"
3253
- role="presentation"
3254
- style="border-collapse: collapse;"
3255
- [style.width.px]="tableWidth"
3256
- >
3257
- <tbody
3258
- kendoGanttTasksTableBody
3259
- [rows]="rows"
3260
- [activeView]="activeView"
3261
- [taskContentTemplate]="taskContentTemplate"
3262
- [taskTemplate]="taskTemplate"
3263
- [summaryTaskTemplate]="summaryTaskTemplate"
3264
- [taskClass]="taskClass"
3265
- [hasChildren]="hasChildren"
3266
- [isTaskSelected]="isTaskSelected"
3267
- >
3268
- </tbody>
3269
- </table>
3270
- </div>
3271
- <svg class="k-gantt-dependencies-svg">
3272
- <polyline
3273
- *ngFor="let dependency of dependencies"
3274
- kendoGanttDependency
3275
- [dependency]="dependency"
3276
- />
3277
- </svg>
3278
- </div>
3279
- </div>
3280
- `
3281
- }),
3282
- __metadata("design:paramtypes", [ScrollSyncService,
3283
- DependencyDomService,
3284
- Renderer2,
3285
- NgZone])
3286
- ], GanttTimelineComponent);
3894
+ const TOUCH_ENABLED = new InjectionToken('gantt-touch-enabled');
3287
3895
 
3288
3896
  /**
3289
3897
  * @hidden
@@ -3341,6 +3949,10 @@ __decorate([
3341
3949
  Input(),
3342
3950
  __metadata("design:type", Function)
3343
3951
  ], GanttTasksTableBodyComponent.prototype, "isTaskSelected", void 0);
3952
+ __decorate([
3953
+ Input(),
3954
+ __metadata("design:type", Boolean)
3955
+ ], GanttTasksTableBodyComponent.prototype, "renderDependencyDragClues", void 0);
3344
3956
  GanttTasksTableBodyComponent = __decorate([
3345
3957
  Component({
3346
3958
  selector: '[kendoGanttTasksTableBody]',
@@ -3353,7 +3965,8 @@ GanttTasksTableBodyComponent = __decorate([
3353
3965
  [activeView]="activeView"
3354
3966
  [taskClass]="taskClass"
3355
3967
  [isSelected]="isTaskSelected"
3356
- [index]="index"
3968
+ [attr.data-task-index]="index"
3969
+ [renderDependencyDragClues]="renderDependencyDragClues"
3357
3970
  >
3358
3971
  </kendo-gantt-milestone-task>
3359
3972
  <ng-template #task>
@@ -3364,7 +3977,8 @@ GanttTasksTableBodyComponent = __decorate([
3364
3977
  [activeView]="activeView"
3365
3978
  [taskClass]="taskClass"
3366
3979
  [isSelected]="isTaskSelected"
3367
- [index]="index"
3980
+ [attr.data-task-index]="index"
3981
+ [renderDependencyDragClues]="renderDependencyDragClues"
3368
3982
  >
3369
3983
  </kendo-gantt-summary-task>
3370
3984
  <kendo-gantt-task
@@ -3375,7 +3989,8 @@ GanttTasksTableBodyComponent = __decorate([
3375
3989
  [activeView]="activeView"
3376
3990
  [taskClass]="taskClass"
3377
3991
  [isSelected]="isTaskSelected"
3378
- [index]="index"
3992
+ [attr.data-task-index]="index"
3993
+ [renderDependencyDragClues]="renderDependencyDragClues"
3379
3994
  >
3380
3995
  </kendo-gantt-task>
3381
3996
  </ng-template>
@@ -3446,29 +4061,18 @@ class GanttTaskBase {
3446
4061
  get slotWidth() {
3447
4062
  return this.viewService.options.slotWidth;
3448
4063
  }
3449
- ngOnChanges(changes) {
3450
- if (isPresent(changes.dataItem)) {
3451
- if (isPresent(changes.dataItem.previousValue)) {
3452
- this.dependencyDomService.unregisterTask(changes.dataItem.previousValue);
3453
- }
3454
- this.dependencyDomService.registerTask(this.dataItem, this.taskElement.nativeElement);
3455
- }
3456
- else if (isPresent(changes.activeView)) {
3457
- this.dependencyDomService.notifyChanges();
3458
- }
3459
- }
3460
- ngOnDestroy() {
3461
- if (isPresent(this.dataItem)) {
3462
- this.dependencyDomService.unregisterTask(this.dataItem);
3463
- }
3464
- this.viewChangesSubscription.unsubscribe();
3465
- }
3466
4064
  get taskWidth() {
3467
4065
  const itemDuration = this.mapper.extractFromTask(this.dataItem, 'end') - this.mapper.extractFromTask(this.dataItem, 'start');
3468
4066
  const durationInSlotUnits = itemDuration / this.slotUnitDuration;
3469
4067
  const width = durationInSlotUnits * this.slotWidth;
3470
4068
  return width;
3471
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
+ */
3472
4076
  get taskOffset() {
3473
4077
  const timeAfterViewStart = this.mapper.extractFromTask(this.dataItem, 'start') - this.viewService.viewStart;
3474
4078
  const offsetInSlotUnits = timeAfterViewStart / this.slotUnitDuration;
@@ -3480,6 +4084,23 @@ class GanttTaskBase {
3480
4084
  // fall-back to 0 in case no completionRatio is provided
3481
4085
  return isNumber(overlayWidth) ? overlayWidth : 0;
3482
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
+ }
3483
4104
  }
3484
4105
  __decorate([
3485
4106
  HostBinding('class.k-task-wrap'),
@@ -3495,8 +4116,8 @@ __decorate([
3495
4116
  ], GanttTaskBase.prototype, "dataItem", void 0);
3496
4117
  __decorate([
3497
4118
  Input(),
3498
- __metadata("design:type", Number)
3499
- ], GanttTaskBase.prototype, "index", void 0);
4119
+ __metadata("design:type", Boolean)
4120
+ ], GanttTaskBase.prototype, "renderDependencyDragClues", void 0);
3500
4121
  __decorate([
3501
4122
  Input(),
3502
4123
  __metadata("design:type", Function)
@@ -3509,15 +4130,21 @@ __decorate([
3509
4130
  Input(),
3510
4131
  __metadata("design:type", Function)
3511
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);
3512
4138
 
3513
4139
  var GanttTaskComponent_1;
3514
4140
  /**
3515
4141
  * @hidden
3516
4142
  */
3517
4143
  let GanttTaskComponent = GanttTaskComponent_1 = class GanttTaskComponent extends GanttTaskBase {
3518
- constructor(mapper, timelineViewService, dependencyDomService, optionChangesService, cdr, editService) {
4144
+ constructor(editService, touchEnabled$$1, mapper, timelineViewService, dependencyDomService, optionChangesService, cdr) {
3519
4145
  super(mapper, timelineViewService, dependencyDomService, optionChangesService, cdr);
3520
4146
  this.editService = editService;
4147
+ this.touchEnabled = touchEnabled$$1;
3521
4148
  }
3522
4149
  onTaskDelete() {
3523
4150
  this.editService.dataItem = this.dataItem;
@@ -3547,9 +4174,7 @@ GanttTaskComponent = GanttTaskComponent_1 = __decorate([
3547
4174
  class="k-task k-task-single"
3548
4175
  [ngClass]="taskClass(dataItem)"
3549
4176
  [style.width.px]="taskWidth"
3550
- [style.left.px]="taskOffset"
3551
4177
  [attr.title]="mapper.extractFromTask(dataItem, 'title')"
3552
- [attr.data-task-index]="index"
3553
4178
  [class.k-state-selected]="isSelected(dataItem)"
3554
4179
  >
3555
4180
  <ng-container *ngIf="!taskTemplate">
@@ -3589,14 +4214,26 @@ GanttTaskComponent = GanttTaskComponent_1 = __decorate([
3589
4214
  >
3590
4215
  </ng-template>
3591
4216
  </div>
3592
- `
3593
- }),
3594
- __metadata("design:paramtypes", [MappingService,
3595
- TimelineViewService,
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>
4229
+ `
4230
+ }),
4231
+ __param(1, Inject(TOUCH_ENABLED)),
4232
+ __metadata("design:paramtypes", [EditService, Boolean, MappingService,
4233
+ TimelineViewService,
3596
4234
  DependencyDomService,
3597
4235
  OptionChangesService,
3598
- ChangeDetectorRef,
3599
- EditService])
4236
+ ChangeDetectorRef])
3600
4237
  ], GanttTaskComponent);
3601
4238
 
3602
4239
  var GanttSummaryTaskComponent_1;
@@ -3604,8 +4241,9 @@ var GanttSummaryTaskComponent_1;
3604
4241
  * @hidden
3605
4242
  */
3606
4243
  let GanttSummaryTaskComponent = GanttSummaryTaskComponent_1 = class GanttSummaryTaskComponent extends GanttTaskBase {
3607
- constructor(mapper, timelineViewService, dependencyDomService, optionChangesService, cdr) {
4244
+ constructor(touchEnabled$$1, mapper, timelineViewService, dependencyDomService, optionChangesService, cdr) {
3608
4245
  super(mapper, timelineViewService, dependencyDomService, optionChangesService, cdr);
4246
+ this.touchEnabled = touchEnabled$$1;
3609
4247
  this.summaryWrapperClass = true;
3610
4248
  }
3611
4249
  };
@@ -3632,9 +4270,7 @@ GanttSummaryTaskComponent = GanttSummaryTaskComponent_1 = __decorate([
3632
4270
  class="k-task k-task-summary"
3633
4271
  [ngClass]="taskClass(dataItem)"
3634
4272
  [style.width.px]="taskWidth"
3635
- [style.left.px]="taskOffset"
3636
4273
  [attr.title]="mapper.extractFromTask(dataItem, 'title')"
3637
- [attr.data-task-index]="index"
3638
4274
  [class.k-state-selected]="isSelected(dataItem)"
3639
4275
  >
3640
4276
  <div *ngIf="!template; else summaryTemplate"
@@ -3656,9 +4292,22 @@ GanttSummaryTaskComponent = GanttSummaryTaskComponent_1 = __decorate([
3656
4292
  >
3657
4293
  </ng-template>
3658
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>
3659
4307
  `
3660
4308
  }),
3661
- __metadata("design:paramtypes", [MappingService,
4309
+ __param(0, Inject(TOUCH_ENABLED)),
4310
+ __metadata("design:paramtypes", [Boolean, MappingService,
3662
4311
  TimelineViewService,
3663
4312
  DependencyDomService,
3664
4313
  OptionChangesService,
@@ -3670,8 +4319,9 @@ var GanttMilestoneTaskComponent_1;
3670
4319
  * @hidden
3671
4320
  */
3672
4321
  let GanttMilestoneTaskComponent = GanttMilestoneTaskComponent_1 = class GanttMilestoneTaskComponent extends GanttTaskBase {
3673
- constructor(mapper, timelineViewService, dependencyDomService, optionChangesService, cdr) {
4322
+ constructor(touchEnabled$$1, mapper, timelineViewService, dependencyDomService, optionChangesService, cdr) {
3674
4323
  super(mapper, timelineViewService, dependencyDomService, optionChangesService, cdr);
4324
+ this.touchEnabled = touchEnabled$$1;
3675
4325
  this.milestoneWrapperClass = true;
3676
4326
  }
3677
4327
  };
@@ -3693,15 +4343,26 @@ GanttMilestoneTaskComponent = GanttMilestoneTaskComponent_1 = __decorate([
3693
4343
  #task
3694
4344
  class="k-task k-task-milestone"
3695
4345
  [ngClass]="taskClass(dataItem)"
3696
- [style.left.px]="taskOffset"
3697
4346
  [attr.title]="mapper.extractFromTask(dataItem, 'title')"
3698
4347
  [class.k-state-selected]="isSelected(dataItem)"
3699
- [attr.data-task-index]="index"
3700
4348
  >
3701
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>
3702
4362
  `
3703
4363
  }),
3704
- __metadata("design:paramtypes", [MappingService,
4364
+ __param(0, Inject(TOUCH_ENABLED)),
4365
+ __metadata("design:paramtypes", [Boolean, MappingService,
3705
4366
  TimelineViewService,
3706
4367
  DependencyDomService,
3707
4368
  OptionChangesService,
@@ -3772,10 +4433,6 @@ GanttHierarchyBindingDirective = __decorate([
3772
4433
  * A directive which controls the expanded state of the items.
3773
4434
  */
3774
4435
  let GanttExpandableDirective = class GanttExpandableDirective extends ExpandableDirective {
3775
- // fixes an injection error in some builds/ng-versions (e.g. StackBlitz)
3776
- constructor(gantt) {
3777
- super(gantt);
3778
- }
3779
4436
  };
3780
4437
  __decorate([
3781
4438
  Input(),
@@ -3785,8 +4442,7 @@ GanttExpandableDirective = __decorate([
3785
4442
  Directive({
3786
4443
  exportAs: 'kendoGanttExpandable',
3787
4444
  selector: '[kendoGanttExpandable]'
3788
- }),
3789
- __metadata("design:paramtypes", [ExpandableTreeComponent])
4445
+ })
3790
4446
  ], GanttExpandableDirective);
3791
4447
 
3792
4448
  /**
@@ -3932,6 +4588,14 @@ let ToolbarComponent = class ToolbarComponent {
3932
4588
  this.scrollSyncService.resetTimelineScrollLeft();
3933
4589
  }
3934
4590
  };
4591
+ __decorate([
4592
+ Input(),
4593
+ __metadata("design:type", Boolean)
4594
+ ], ToolbarComponent.prototype, "showAddTask", void 0);
4595
+ __decorate([
4596
+ Input(),
4597
+ __metadata("design:type", Boolean)
4598
+ ], ToolbarComponent.prototype, "showViewSelector", void 0);
3935
4599
  __decorate([
3936
4600
  Input(),
3937
4601
  __metadata("design:type", String),
@@ -3942,8 +4606,10 @@ ToolbarComponent = __decorate([
3942
4606
  selector: 'kendo-gantt-toolbar',
3943
4607
  template: `
3944
4608
  <ng-container *ngIf="!renderTemplate">
4609
+ <kendo-gantt-add-task *ngIf="showAddTask"></kendo-gantt-add-task>
3945
4610
  <span class="k-spacer k-toolbar-spacer"></span>
3946
4611
  <kendo-gantt-view-selector
4612
+ *ngIf="showViewSelector"
3947
4613
  [views]="gantt.viewTypes"
3948
4614
  [activeView]="gantt.activeView"
3949
4615
  (activeViewChange)="onViewChange($event)"></kendo-gantt-view-selector>
@@ -4039,6 +4705,9 @@ const getOffsetRelativeToParent = (element, targetParent) => {
4039
4705
  top: 0,
4040
4706
  left: 0
4041
4707
  };
4708
+ if (!targetParent.contains(element)) {
4709
+ return offset;
4710
+ }
4042
4711
  let offsetParent = element;
4043
4712
  while (offsetParent && offsetParent !== targetParent) {
4044
4713
  offset.top += offsetParent.offsetTop;
@@ -4072,9 +4741,9 @@ const dependencyCoordinates = (from, to, rowHeight, type, minDistanceBeforeTurn,
4072
4741
  | |
4073
4742
  [[[]]]- -[[[]]]
4074
4743
  */
4075
- if (type === 0 /* FF */ || type === 3 /* SS */) {
4744
+ if (type === DependencyType.FF || type === DependencyType.SS) {
4076
4745
  // polyline start from first task
4077
- const dir = type === 3 /* SS */ ? 'left' : 'right';
4746
+ const dir = type === DependencyType.SS ? 'left' : 'right';
4078
4747
  top = from.top;
4079
4748
  left = from[dir];
4080
4749
  points.push({ top, left });
@@ -4100,9 +4769,9 @@ const dependencyCoordinates = (from, to, rowHeight, type, minDistanceBeforeTurn,
4100
4769
  |
4101
4770
  -[[[]]]
4102
4771
  */
4103
- const startDir = type === 2 /* SF */ ? 'left' : 'right';
4104
- const endDir = type === 2 /* SF */ ? 'right' : 'left';
4105
- const additionalTurn = type === 2 /* SF */
4772
+ const startDir = type === DependencyType.SF ? 'left' : 'right';
4773
+ const endDir = type === DependencyType.SF ? 'right' : 'left';
4774
+ const additionalTurn = type === DependencyType.SF
4106
4775
  ? from[startDir] - minDistanceBeforeTurn * 2 < to[endDir]
4107
4776
  : from[startDir] + minDistanceBeforeTurn * 2 > to[endDir];
4108
4777
  // polyline start from first task
@@ -4185,6 +4854,37 @@ const getArrowEast = (top, left, arrowSize) => {
4185
4854
  });
4186
4855
  return points;
4187
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
+ };
4188
4888
 
4189
4889
  /**
4190
4890
  * Defines the size of the arrow that will be drawn at the end of each Gantt dependency.
@@ -4260,6 +4960,540 @@ GanttDependencyDirective = __decorate([
4260
4960
  DependencyDomService])
4261
4961
  ], GanttDependencyDirective);
4262
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
+
4263
5497
  var TimelineDayViewComponent_1;
4264
5498
  let TimelineDayViewComponent = TimelineDayViewComponent_1 = class TimelineDayViewComponent extends ViewBase {
4265
5499
  constructor(optionChangesService, dependencyDomService) {
@@ -4336,14 +5570,35 @@ TimelineMonthViewComponent = TimelineMonthViewComponent_1 = __decorate([
4336
5570
  * @hidden
4337
5571
  */
4338
5572
  let EditDialogComponent = class EditDialogComponent {
4339
- constructor(mapper, editService, localizationService) {
5573
+ constructor(mapper, editService, cdr, localizationService) {
4340
5574
  this.mapper = mapper;
4341
5575
  this.editService = editService;
5576
+ this.cdr = cdr;
4342
5577
  this.localizationService = localizationService;
4343
5578
  }
5579
+ ngOnInit() {
5580
+ this.editService.loadTasks(this.data).subscribe(value => {
5581
+ this.loadedTasks = value;
5582
+ });
5583
+ }
5584
+ get predecessors() {
5585
+ return this.editService.predecessors;
5586
+ }
5587
+ set predecessors(items) {
5588
+ this.editService.predecessors = items;
5589
+ }
5590
+ get successors() {
5591
+ return this.editService.successors;
5592
+ }
5593
+ set successors(items) {
5594
+ this.editService.successors = items;
5595
+ }
4344
5596
  getText(token) {
4345
5597
  return this.localizationService.get(token);
4346
5598
  }
5599
+ getDependencyType(typeId) {
5600
+ return DependencyType[typeId];
5601
+ }
4347
5602
  handleEditingResult(editResultType) {
4348
5603
  this.editService.triggerEditEvent(editResultType);
4349
5604
  }
@@ -4353,8 +5608,8 @@ let EditDialogComponent = class EditDialogComponent {
4353
5608
  };
4354
5609
  __decorate([
4355
5610
  Input(),
4356
- __metadata("design:type", FormGroup)
4357
- ], EditDialogComponent.prototype, "formGroup", void 0);
5611
+ __metadata("design:type", Array)
5612
+ ], EditDialogComponent.prototype, "data", void 0);
4358
5613
  EditDialogComponent = __decorate([
4359
5614
  Component({
4360
5615
  selector: 'kendo-gantt-edit-dialog',
@@ -4366,34 +5621,34 @@ EditDialogComponent = __decorate([
4366
5621
  (close)="handleEditingResult('cancel')">
4367
5622
  <kendo-dialog-messages
4368
5623
  [closeTitle]="getText('taskEditingDialogCloseTitle')"></kendo-dialog-messages>
4369
- <form class="k-form" [formGroup]="formGroup">
4370
- <kendo-formfield *ngIf="formGroup.contains(mapper.taskFields.title)">
4371
- <kendo-label [for]="mapper.taskFields.title" [text]="getText('titleFieldInputLabel')"></kendo-label>
4372
- <input class="k-textbox" [formControlName]="mapper.taskFields.title" />
4373
- </kendo-formfield>
4374
- <div class="k-hstack">
4375
- <kendo-formfield [style.width.%]="49" *ngIf="formGroup.contains(mapper.taskFields.start)">
4376
- <kendo-label [for]="mapper.taskFields.start" [text]="getText('startFieldInputLabel')"></kendo-label>
4377
- <kendo-datetimepicker [formControlName]="mapper.taskFields.start"></kendo-datetimepicker>
4378
- </kendo-formfield>
4379
- <kendo-treelist-spacer></kendo-treelist-spacer>
4380
- <kendo-formfield [style.width.%]="49" *ngIf="formGroup.contains(mapper.taskFields.end)">
4381
- <kendo-label [for]="mapper.taskFields.end" [text]="getText('endFieldInputLabel')"></kendo-label>
4382
- <kendo-datetimepicker [formControlName]="mapper.taskFields.end"></kendo-datetimepicker>
4383
- </kendo-formfield>
4384
- </div>
4385
- <kendo-formfield [style.width.%]="49" *ngIf="formGroup.contains(mapper.taskFields.completionRatio)">
4386
- <kendo-label [for]="mapper.taskFields.completionRatio" [text]="getText('completionRatioFieldInputLabel')"></kendo-label>
4387
- <kendo-numerictextbox
4388
- [formControlName]="mapper.taskFields.completionRatio"
4389
- [min]="0"
4390
- [max]="1"
4391
- [decimals]="2"
4392
- format="p2"
4393
- [step]="0.01"
4394
- ></kendo-numerictextbox>
4395
- </kendo-formfield>
4396
- </form>
5624
+
5625
+ <kendo-tabstrip [keepTabContent]="true">
5626
+ <kendo-tabstrip-tab [title]="getText('taskEditingGeneralTabTitle')" [selected]="true">
5627
+ <ng-template kendoTabContent>
5628
+ <kendo-gantt-task-fields></kendo-gantt-task-fields>
5629
+ </ng-template>
5630
+ </kendo-tabstrip-tab>
5631
+ <kendo-tabstrip-tab [title]="getText('taskEditingPredecessorsTabTitle')">
5632
+ <ng-template kendoTabContent>
5633
+ <kendo-gantt-dependencies-table
5634
+ [tasks]="loadedTasks"
5635
+ [(dependencies)]="predecessors"
5636
+ dependencyType="predecessor"
5637
+ >
5638
+ </kendo-gantt-dependencies-table>
5639
+ </ng-template>
5640
+ </kendo-tabstrip-tab>
5641
+ <kendo-tabstrip-tab [title]="getText('taskEditingSuccessorsTabTitle')">
5642
+ <ng-template kendoTabContent>
5643
+ <kendo-gantt-dependencies-table
5644
+ [tasks]="loadedTasks"
5645
+ [(dependencies)]="successors"
5646
+ dependencyType="successor">
5647
+ </kendo-gantt-dependencies-table>
5648
+ </ng-template>
5649
+ </kendo-tabstrip-tab>
5650
+ </kendo-tabstrip>
5651
+
4397
5652
  <kendo-dialog-actions layout="normal">
4398
5653
  <button kendoButton (click)="onTaskDelete()">{{ getText('deleteButtonText') }}</button>
4399
5654
  <kendo-treelist-spacer></kendo-treelist-spacer>
@@ -4405,6 +5660,7 @@ EditDialogComponent = __decorate([
4405
5660
  }),
4406
5661
  __metadata("design:paramtypes", [MappingService,
4407
5662
  EditService,
5663
+ ChangeDetectorRef,
4408
5664
  LocalizationService])
4409
5665
  ], EditDialogComponent);
4410
5666
 
@@ -4413,6 +5669,38 @@ EditDialogComponent = __decorate([
4413
5669
  */
4414
5670
  class Messages extends ComponentMessages {
4415
5671
  }
5672
+ __decorate([
5673
+ Input(),
5674
+ __metadata("design:type", String)
5675
+ ], Messages.prototype, "taskEditingGeneralTabTitle", void 0);
5676
+ __decorate([
5677
+ Input(),
5678
+ __metadata("design:type", String)
5679
+ ], Messages.prototype, "taskEditingPredecessorsTabTitle", void 0);
5680
+ __decorate([
5681
+ Input(),
5682
+ __metadata("design:type", String)
5683
+ ], Messages.prototype, "taskEditingSuccessorsTabTitle", void 0);
5684
+ __decorate([
5685
+ Input(),
5686
+ __metadata("design:type", String)
5687
+ ], Messages.prototype, "taskEditingDependenciesAddButtonText", void 0);
5688
+ __decorate([
5689
+ Input(),
5690
+ __metadata("design:type", String)
5691
+ ], Messages.prototype, "taskEditingDependenciesRemoveButtonText", void 0);
5692
+ __decorate([
5693
+ Input(),
5694
+ __metadata("design:type", String)
5695
+ ], Messages.prototype, "taskEditingDependenciesGridNameColumnTitle", void 0);
5696
+ __decorate([
5697
+ Input(),
5698
+ __metadata("design:type", String)
5699
+ ], Messages.prototype, "taskEditingDependenciesGridTypeColumnTitle", void 0);
5700
+ __decorate([
5701
+ Input(),
5702
+ __metadata("design:type", String)
5703
+ ], Messages.prototype, "deleteButtonText", void 0);
4416
5704
  __decorate([
4417
5705
  Input(),
4418
5706
  __metadata("design:type", String)
@@ -4436,7 +5724,19 @@ __decorate([
4436
5724
  __decorate([
4437
5725
  Input(),
4438
5726
  __metadata("design:type", String)
4439
- ], Messages.prototype, "deleteButtonText", void 0);
5727
+ ], Messages.prototype, "addTaskText", void 0);
5728
+ __decorate([
5729
+ Input(),
5730
+ __metadata("design:type", String)
5731
+ ], Messages.prototype, "addChildText", void 0);
5732
+ __decorate([
5733
+ Input(),
5734
+ __metadata("design:type", String)
5735
+ ], Messages.prototype, "addAboveText", void 0);
5736
+ __decorate([
5737
+ Input(),
5738
+ __metadata("design:type", String)
5739
+ ], Messages.prototype, "addBelowText", void 0);
4440
5740
  __decorate([
4441
5741
  Input(),
4442
5742
  __metadata("design:type", String)
@@ -4693,27 +5993,306 @@ LocalizedMessagesDirective = LocalizedMessagesDirective_1 = __decorate([
4693
5993
  __metadata("design:paramtypes", [LocalizationService])
4694
5994
  ], LocalizedMessagesDirective);
4695
5995
 
5996
+ /**
5997
+ * The UI for adding new items to the Gantt.
5998
+ * Use it within a toolbar template to provide a custom icon or list of options.
5999
+ */
6000
+ let GanttAddTaskComponent = class GanttAddTaskComponent {
6001
+ constructor(localizationService, editService, ngZone) {
6002
+ this.localizationService = localizationService;
6003
+ this.editService = editService;
6004
+ this.ngZone = ngZone;
6005
+ /**
6006
+ * Sets the data of the DropDownButton.
6007
+ * > The data has to be provided in an array-like list.
6008
+ */
6009
+ this.data = [{
6010
+ text: this.getText('addChildText'),
6011
+ type: 'addChild'
6012
+ }, {
6013
+ text: this.getText('addAboveText'),
6014
+ type: 'addAbove'
6015
+ }, {
6016
+ text: this.getText('addBelowText'),
6017
+ type: 'addBelow'
6018
+ }];
6019
+ /**
6020
+ * Defines the name of an existing icon in a Kendo UI theme.
6021
+ * @default 'plus'
6022
+ */
6023
+ this.icon = 'plus';
6024
+ }
6025
+ /**
6026
+ * @hidden
6027
+ */
6028
+ getText(message) {
6029
+ return this.localizationService.get(message);
6030
+ }
6031
+ /**
6032
+ * @hidden
6033
+ */
6034
+ handleOpen(e) {
6035
+ if (!this.editService.getSelectedItem()) {
6036
+ e.preventDefault();
6037
+ }
6038
+ }
6039
+ /**
6040
+ * @hidden
6041
+ */
6042
+ handleMouseClick() {
6043
+ if (!this.editService.getSelectedItem()) {
6044
+ this.ngZone.run(() => {
6045
+ this.editService.addEvent.next({
6046
+ selectedItem: null,
6047
+ actionType: 'addTask'
6048
+ });
6049
+ });
6050
+ }
6051
+ }
6052
+ /**
6053
+ * @hidden
6054
+ */
6055
+ handleItemClick(e) {
6056
+ this.editService.addEvent.next({
6057
+ actionType: e.type,
6058
+ selectedItem: null
6059
+ });
6060
+ }
6061
+ };
6062
+ __decorate([
6063
+ Input(),
6064
+ __metadata("design:type", Array)
6065
+ ], GanttAddTaskComponent.prototype, "data", void 0);
6066
+ __decorate([
6067
+ Input(),
6068
+ __metadata("design:type", String)
6069
+ ], GanttAddTaskComponent.prototype, "icon", void 0);
6070
+ GanttAddTaskComponent = __decorate([
6071
+ Component({
6072
+ selector: 'kendo-gantt-add-task',
6073
+ template: `
6074
+ <kendo-dropdownbutton
6075
+ [data]="data"
6076
+ [icon]="icon"
6077
+ [kendoEventsOutsideAngular]="{ click: handleMouseClick }"
6078
+ [scope]="this"
6079
+ (itemClick)="handleItemClick($event)"
6080
+ (open)="handleOpen($event)">
6081
+ {{ getText('addTaskText') }}
6082
+ </kendo-dropdownbutton>
6083
+ `
6084
+ }),
6085
+ __metadata("design:paramtypes", [LocalizationService,
6086
+ EditService,
6087
+ NgZone])
6088
+ ], GanttAddTaskComponent);
6089
+
4696
6090
  /**
4697
6091
  * @hidden
4698
6092
  */
4699
- let GanttTreeListMessagesDirective = class GanttTreeListMessagesDirective {
4700
- constructor(localizationService) {
6093
+ let DependenciesTableComponent = class DependenciesTableComponent {
6094
+ constructor(mapper, editService, localizationService) {
6095
+ this.mapper = mapper;
6096
+ this.editService = editService;
4701
6097
  this.localizationService = localizationService;
6098
+ this.dependenciesChange = new EventEmitter();
6099
+ this.selectedKeys = [];
6100
+ this.formGroups = new FormArray([]);
6101
+ this.dependencyTypes = this.getDependencyTypes();
6102
+ }
6103
+ get taskId() {
6104
+ return this.editService.dataItem.id;
6105
+ }
6106
+ // The target dependency id field
6107
+ // e.g. if Predecessors, we have the `fromId` which is the currently edited task,
6108
+ // while the `toId` is missing (needs to be selected by the user)
6109
+ get dependencyIdField() {
6110
+ return this.dependencyType === 'predecessor' ? 'fromId' : 'toId';
6111
+ }
6112
+ ngOnInit() {
6113
+ // generate the FormGroups per each Grid row
6114
+ if (this.formGroups.controls.length === 0) {
6115
+ const fields = this.mapper.dependencyFields;
6116
+ this.dependencies.forEach(item => {
6117
+ const formGroup = new FormGroup({
6118
+ [fields.id]: new FormControl(this.mapper.extractFromDependency(item, 'id')),
6119
+ [fields.fromId]: new FormControl(this.mapper.extractFromDependency(item, 'fromId'), Validators.required),
6120
+ [fields.toId]: new FormControl(this.mapper.extractFromDependency(item, 'toId'), Validators.required),
6121
+ [fields.type]: new FormControl(this.mapper.extractFromDependency(item, 'type'), Validators.required)
6122
+ });
6123
+ this.formGroups.push(formGroup);
6124
+ });
6125
+ }
6126
+ this.formGroups.valueChanges.subscribe(val => {
6127
+ this.formGroups.controls.forEach(control => {
6128
+ if (control.dirty) {
6129
+ this.editService.updateDependencies(control.value);
6130
+ }
6131
+ });
6132
+ this.dependenciesChange.emit(val);
6133
+ });
4702
6134
  }
4703
- ngAfterViewInit() {
4704
- const treeListServiceDictionary = this.localizationService.dictionary;
4705
- Object.keys(treeListServiceDictionary)
4706
- .forEach(token => treeListServiceDictionary[token] = this.kendoGanttTreeListMessages.get(token.replace('kendo.treelist.', '')));
6135
+ getFormControl(dataItemIndex, field) {
6136
+ // return the FormControl for the respective column editor
6137
+ return this.formGroups.controls
6138
+ .find((_control, index) => index === dataItemIndex)
6139
+ .get(this.mapper.dependencyFields[field]);
6140
+ }
6141
+ getText(token) {
6142
+ return this.localizationService.get(token);
6143
+ }
6144
+ getDependencyTypes() {
6145
+ const types = Object.keys(DependencyType)
6146
+ .filter(value => typeof DependencyType[value] === 'number')
6147
+ .map(type => {
6148
+ return {
6149
+ type,
6150
+ id: DependencyType[type]
6151
+ };
6152
+ });
6153
+ return types;
6154
+ }
6155
+ addHandler() {
6156
+ const fields = this.mapper.dependencyFields;
6157
+ const formGroup = new FormGroup({
6158
+ [fields.id]: new FormControl(),
6159
+ [fields.fromId]: new FormControl(this.dependencyIdField === 'toId' ? this.taskId : null, Validators.required),
6160
+ [fields.toId]: new FormControl(this.dependencyIdField === 'fromId' ? this.taskId : null, Validators.required),
6161
+ [fields.type]: new FormControl(null, Validators.required)
6162
+ });
6163
+ this.formGroups.push(formGroup);
6164
+ }
6165
+ removeHandler() {
6166
+ const [selectedIndex] = this.selectedKeys;
6167
+ const item = this.formGroups.at(selectedIndex).value;
6168
+ this.editService.deleteDependency(item);
6169
+ this.formGroups.removeAt(selectedIndex);
4707
6170
  }
4708
6171
  };
4709
6172
  __decorate([
4710
6173
  Input(),
4711
- __metadata("design:type", LocalizationService)
4712
- ], GanttTreeListMessagesDirective.prototype, "kendoGanttTreeListMessages", void 0);
4713
- GanttTreeListMessagesDirective = __decorate([
4714
- Directive({ selector: '[kendoGanttTreeListMessages]' }),
4715
- __metadata("design:paramtypes", [LocalizationService])
4716
- ], GanttTreeListMessagesDirective);
6174
+ __metadata("design:type", Array)
6175
+ ], DependenciesTableComponent.prototype, "tasks", void 0);
6176
+ __decorate([
6177
+ Input(),
6178
+ __metadata("design:type", Array)
6179
+ ], DependenciesTableComponent.prototype, "dependencies", void 0);
6180
+ __decorate([
6181
+ Input(),
6182
+ __metadata("design:type", String)
6183
+ ], DependenciesTableComponent.prototype, "dependencyType", void 0);
6184
+ __decorate([
6185
+ Output(),
6186
+ __metadata("design:type", EventEmitter)
6187
+ ], DependenciesTableComponent.prototype, "dependenciesChange", void 0);
6188
+ DependenciesTableComponent = __decorate([
6189
+ Component({
6190
+ selector: 'kendo-gantt-dependencies-table',
6191
+ template: `
6192
+ <kendo-grid
6193
+ [data]="dependencies"
6194
+ [selectable]="{ mode: 'single' }"
6195
+ [(selectedKeys)]="selectedKeys"
6196
+ kendoGridSelectBy
6197
+ [height]="295"
6198
+ >
6199
+ <ng-template kendoGridToolbarTemplate>
6200
+ <button kendoButton (click)="addHandler()">
6201
+ {{ getText('taskEditingDependenciesAddButtonText') }}
6202
+ </button>
6203
+ <button kendoButton (click)="removeHandler()" [disabled]="selectedKeys.length === 0">
6204
+ {{ getText('taskEditingDependenciesRemoveButtonText') }}
6205
+ </button>
6206
+ </ng-template>
6207
+ <kendo-grid-column [title]="getText('taskEditingDependenciesGridNameColumnTitle')" [field]="dependencyIdField">
6208
+ <ng-template kendoGridCellTemplate let-dataItem="dataItem" let-column="column" let-rowIndex="rowIndex">
6209
+ <kendo-dropdownlist
6210
+ [data]="tasks"
6211
+ textField="title"
6212
+ valueField="id"
6213
+ [valuePrimitive]="true"
6214
+ [formControl]="getFormControl(rowIndex, column.field)"
6215
+ >
6216
+ </kendo-dropdownlist>
6217
+ </ng-template>
6218
+ </kendo-grid-column>
6219
+ <kendo-grid-column [title]="getText('taskEditingDependenciesGridTypeColumnTitle')" field="type">
6220
+ <ng-template kendoGridCellTemplate let-dataItem="dataItem" let-column="column" let-rowIndex="rowIndex">
6221
+ <kendo-dropdownlist
6222
+ [data]="dependencyTypes"
6223
+ textField="type"
6224
+ valueField="id"
6225
+ [valuePrimitive]="true"
6226
+ [formControl]="getFormControl(rowIndex, column.field)"
6227
+ >
6228
+ </kendo-dropdownlist>
6229
+ </ng-template>
6230
+ </kendo-grid-column>
6231
+ </kendo-grid>
6232
+ `
6233
+ }),
6234
+ __metadata("design:paramtypes", [MappingService,
6235
+ EditService,
6236
+ GanttLocalizationService])
6237
+ ], DependenciesTableComponent);
6238
+
6239
+ /**
6240
+ * @hidden
6241
+ */
6242
+ let TaskFieldsComponent = class TaskFieldsComponent {
6243
+ constructor(mapper, editService, localizationService) {
6244
+ this.mapper = mapper;
6245
+ this.editService = editService;
6246
+ this.localizationService = localizationService;
6247
+ }
6248
+ /**
6249
+ * @hidden
6250
+ */
6251
+ get formGroup() {
6252
+ return this.editService.taskFormGroup;
6253
+ }
6254
+ getText(token) {
6255
+ return this.localizationService.get(token);
6256
+ }
6257
+ };
6258
+ TaskFieldsComponent = __decorate([
6259
+ Component({
6260
+ selector: 'kendo-gantt-task-fields',
6261
+ template: `
6262
+ <form class="k-form" [formGroup]="formGroup">
6263
+ <kendo-formfield *ngIf="formGroup.contains(mapper.taskFields.title)">
6264
+ <kendo-label [for]="mapper.taskFields.title" [text]="getText('titleFieldInputLabel')"></kendo-label>
6265
+ <input class="k-textbox" [formControlName]="mapper.taskFields.title" />
6266
+ </kendo-formfield>
6267
+ <div class="k-hstack">
6268
+ <kendo-formfield [style.width.%]="49" *ngIf="formGroup.contains(mapper.taskFields.start)">
6269
+ <kendo-label [for]="mapper.taskFields.start" [text]="getText('startFieldInputLabel')"></kendo-label>
6270
+ <kendo-datetimepicker [formControlName]="mapper.taskFields.start"></kendo-datetimepicker>
6271
+ </kendo-formfield>
6272
+ <kendo-treelist-spacer></kendo-treelist-spacer>
6273
+ <kendo-formfield [style.width.%]="49" *ngIf="formGroup.contains(mapper.taskFields.end)">
6274
+ <kendo-label [for]="mapper.taskFields.end" [text]="getText('endFieldInputLabel')"></kendo-label>
6275
+ <kendo-datetimepicker [formControlName]="mapper.taskFields.end"></kendo-datetimepicker>
6276
+ </kendo-formfield>
6277
+ </div>
6278
+ <kendo-formfield [style.width.%]="49" *ngIf="formGroup.contains(mapper.taskFields.completionRatio)">
6279
+ <kendo-label [for]="mapper.taskFields.completionRatio" [text]="getText('completionRatioFieldInputLabel')"></kendo-label>
6280
+ <kendo-numerictextbox
6281
+ [formControlName]="mapper.taskFields.completionRatio"
6282
+ [min]="0"
6283
+ [max]="1"
6284
+ [decimals]="2"
6285
+ format="p2"
6286
+ [step]="0.01"
6287
+ ></kendo-numerictextbox>
6288
+ </kendo-formfield>
6289
+ </form>
6290
+ `
6291
+ }),
6292
+ __metadata("design:paramtypes", [MappingService,
6293
+ EditService,
6294
+ GanttLocalizationService])
6295
+ ], TaskFieldsComponent);
4717
6296
 
4718
6297
  const IMPORTED_MODULES = [
4719
6298
  CommonModule,
@@ -4726,7 +6305,12 @@ const IMPORTED_MODULES = [
4726
6305
  TreeListModule,
4727
6306
  ButtonsModule,
4728
6307
  DialogModule,
4729
- EventsModule
6308
+ EventsModule,
6309
+ PopupModule,
6310
+ DraggableModule,
6311
+ TabStripModule,
6312
+ GridModule,
6313
+ DropDownsModule
4730
6314
  ];
4731
6315
  const DECLARATIONS = [
4732
6316
  GanttComponent,
@@ -4756,6 +6340,7 @@ const DECLARATIONS = [
4756
6340
  FooterTemplateDirective,
4757
6341
  GanttExpandableDirective,
4758
6342
  GanttDependencyDirective,
6343
+ DependencyDragCreateDirective,
4759
6344
  TimelineDayViewComponent,
4760
6345
  TimelineWeekViewComponent,
4761
6346
  TimelineMonthViewComponent,
@@ -4763,8 +6348,13 @@ const DECLARATIONS = [
4763
6348
  EditDialogComponent,
4764
6349
  CustomMessagesComponent,
4765
6350
  LocalizedMessagesDirective,
4766
- GanttTreeListMessagesDirective
6351
+ GanttAddTaskComponent,
6352
+ DragValidationTooltipComponent,
6353
+ TimelineScrollableDirective,
6354
+ DependenciesTableComponent,
6355
+ TaskFieldsComponent
4767
6356
  ];
6357
+ const ɵ0$3 = touchEnabled;
4768
6358
  /**
4769
6359
  * Represents the [NgModule]({{ site.data.urls.angular['ngmoduleapi'] }})
4770
6360
  * definition for the Gantt component.
@@ -4803,52 +6393,19 @@ GanttModule = __decorate([
4803
6393
  imports: [...IMPORTED_MODULES],
4804
6394
  declarations: [...DECLARATIONS],
4805
6395
  exports: [...DECLARATIONS],
6396
+ entryComponents: [DragValidationTooltipComponent],
4806
6397
  providers: [{
4807
6398
  provide: L10N_PREFIX,
4808
6399
  useValue: 'kendo.gantt'
6400
+ }, {
6401
+ provide: TOUCH_ENABLED,
6402
+ useValue: ɵ0$3
4809
6403
  }]
4810
6404
  })
4811
6405
  ], GanttModule);
4812
6406
 
4813
- /**
4814
- * @hidden
4815
- */
4816
- class PreventableEvent {
4817
- constructor() {
4818
- this.prevented = false;
4819
- }
4820
- /**
4821
- * Prevents the default action for a specified event.
4822
- * In this way, the source component suppresses
4823
- * the built-in behavior that follows the event.
4824
- */
4825
- preventDefault() {
4826
- this.prevented = true;
4827
- }
4828
- /**
4829
- * Returns `true` if the event was prevented
4830
- * by any of its subscribers.
4831
- *
4832
- * @returns `true` if the default action was prevented.
4833
- * Otherwise, returns `false`.
4834
- */
4835
- isDefaultPrevented() {
4836
- return this.prevented;
4837
- }
4838
- }
4839
-
4840
- /**
4841
- * Called every time a user leaves an edited cell.
4842
- */
4843
- class CellCloseEvent extends PreventableEvent {
4844
- constructor(options) {
4845
- super();
4846
- Object.assign(this, options);
4847
- }
4848
- }
4849
-
4850
6407
  /**
4851
6408
  * Generated bundle index. Do not edit.
4852
6409
  */
4853
6410
 
4854
- export { MappingService, OptionChangesService, DependencyDomService, GanttDependencyDirective, EditDialogComponent, EditService, CustomMessagesComponent, LocalizedMessagesDirective, Messages, GanttTreeListMessagesDirective, 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, 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 };