@progress/kendo-angular-gantt 0.3.0-dev.202112141015 → 1.0.0-dev.202201191538
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.
- package/dist/cdn/js/kendo-angular-gantt.js +2 -2
- package/dist/cdn/main.js +1 -23
- package/dist/es/common/touch-enabled.js +9 -0
- package/dist/es/dependencies/utils.js +40 -5
- package/dist/es/dragging/dependency-drag-create.directive.js +347 -0
- package/dist/es/dragging/drag-validation-tooltip.component.js +27 -0
- package/dist/es/editing/dependencies-table.component.js +131 -0
- package/dist/es/editing/edit-dialog.component.js +39 -8
- package/dist/es/editing/edit.service.js +91 -8
- package/dist/es/editing/task-fields.component.js +43 -0
- package/dist/es/editing/{util.js → utils.js} +0 -0
- package/dist/es/gantt.component.js +352 -44
- package/dist/es/gantt.module.js +35 -9
- package/dist/es/index.js +8 -0
- package/dist/es/localization/gantt-localization.service.js +26 -0
- package/dist/es/main.js +1 -0
- package/dist/es/models/dependency-type.enum.js +16 -0
- package/dist/es/models/events/{edit-event.interface.js → dependency-add-event.interface.js} +0 -0
- package/dist/es/models/events/{remove-event.interface.js → task-delete-event.interface.js} +0 -0
- package/dist/es/models/models.js +1 -0
- package/dist/{es2015/models/events/edit-event.interface.js → es/models/view-item.interface.js} +0 -0
- package/dist/{es2015/models/events/remove-event.interface.js → es/navigation/navigation-models.js} +0 -0
- package/dist/es/navigation/navigation.service.js +390 -0
- package/dist/es/navigation/utils.js +77 -0
- package/dist/es/package-metadata.js +1 -1
- package/dist/es/rendering/gantt-milestone-task.component.js +12 -6
- package/dist/es/rendering/gantt-summary-task.component.js +27 -6
- package/dist/es/rendering/gantt-task-base.js +84 -22
- package/dist/es/rendering/gantt-task.component.js +13 -8
- package/dist/es/rendering/gantt-tasks-table-body.component.js +13 -5
- package/dist/es/scrolling/drag-scroll-settings.js +20 -0
- package/dist/es/scrolling/timeline-scroll.directive.js +89 -0
- package/dist/es/scrolling/timeline-scroll.service.js +39 -0
- package/dist/es/scrolling/utils.js +80 -0
- package/dist/es/timeline/gantt-timeline.component.js +50 -4
- package/dist/es/toolbar/toolbar.component.js +12 -13
- package/dist/es/toolbar/view-selector.component.js +1 -1
- package/dist/es/utils.js +153 -12
- package/dist/es2015/common/touch-enabled.d.ts +9 -0
- package/dist/es2015/common/touch-enabled.js +9 -0
- package/dist/es2015/dependencies/utils.d.ts +15 -0
- package/dist/es2015/dependencies/utils.js +40 -5
- package/dist/es2015/dragging/dependency-drag-create.directive.d.ts +72 -0
- package/dist/es2015/dragging/dependency-drag-create.directive.js +324 -0
- package/dist/es2015/dragging/drag-validation-tooltip.component.d.ts +29 -0
- package/dist/es2015/dragging/drag-validation-tooltip.component.js +76 -0
- package/dist/es2015/editing/dependencies-table.component.d.ts +39 -0
- package/dist/es2015/editing/dependencies-table.component.js +160 -0
- package/dist/es2015/editing/edit-dialog.component.d.ts +11 -4
- package/dist/es2015/editing/edit-dialog.component.js +66 -36
- package/dist/es2015/editing/edit.service.d.ts +22 -5
- package/dist/es2015/editing/edit.service.js +80 -11
- package/dist/es2015/editing/task-fields.component.d.ts +22 -0
- package/dist/es2015/editing/task-fields.component.js +67 -0
- package/dist/es2015/editing/{util.d.ts → utils.d.ts} +2 -2
- package/dist/es2015/editing/{util.js → utils.js} +0 -0
- package/dist/es2015/gantt.component.d.ts +116 -23
- package/dist/es2015/gantt.component.js +329 -48
- package/dist/es2015/gantt.module.js +35 -9
- package/dist/es2015/index.d.ts +8 -0
- package/dist/es2015/index.js +8 -0
- package/dist/es2015/index.metadata.json +1 -1
- package/dist/es2015/{models/events/remove-event.interface.d.ts → localization/gantt-localization.service.d.ts} +6 -7
- package/dist/es2015/localization/gantt-localization.service.js +25 -0
- package/dist/es2015/main.d.ts +1 -0
- package/dist/es2015/main.js +1 -0
- package/dist/es2015/models/dependency-type.enum.d.ts +1 -1
- package/dist/es2015/models/dependency-type.enum.js +16 -0
- package/dist/es2015/models/events/dependency-add-event.interface.d.ts +26 -0
- package/dist/es2015/models/events/dependency-add-event.interface.js +4 -0
- package/dist/es2015/models/events/task-click-event.interface.d.ts +3 -3
- package/dist/es2015/models/events/task-delete-event.interface.d.ts +21 -0
- package/dist/es2015/models/events/task-delete-event.interface.js +4 -0
- package/dist/es2015/models/events/task-edit-event.interface.d.ts +36 -6
- package/dist/es2015/models/models.d.ts +4 -2
- package/dist/es2015/models/models.js +1 -0
- package/dist/es2015/models/view-item.interface.d.ts +35 -0
- package/dist/es2015/models/view-item.interface.js +4 -0
- package/dist/es2015/navigation/navigation-models.d.ts +34 -0
- package/dist/es2015/navigation/navigation-models.js +4 -0
- package/dist/es2015/navigation/navigation.service.d.ts +126 -0
- package/dist/es2015/navigation/navigation.service.js +355 -0
- package/dist/es2015/navigation/utils.d.ts +26 -0
- package/dist/es2015/navigation/utils.js +69 -0
- package/dist/es2015/package-metadata.js +1 -1
- package/dist/es2015/rendering/gantt-milestone-task.component.d.ts +3 -1
- package/dist/es2015/rendering/gantt-milestone-task.component.js +35 -8
- package/dist/es2015/rendering/gantt-summary-task.component.d.ts +5 -1
- package/dist/es2015/rendering/gantt-summary-task.component.js +47 -8
- package/dist/es2015/rendering/gantt-task-base.d.ts +20 -6
- package/dist/es2015/rendering/gantt-task-base.js +75 -22
- package/dist/es2015/rendering/gantt-task.component.d.ts +4 -2
- package/dist/es2015/rendering/gantt-task.component.js +47 -13
- package/dist/es2015/rendering/gantt-tasks-table-body.component.d.ts +6 -3
- package/dist/es2015/rendering/gantt-tasks-table-body.component.js +27 -9
- package/dist/es2015/scrolling/drag-scroll-settings.d.ts +47 -0
- package/dist/es2015/scrolling/drag-scroll-settings.js +20 -0
- package/dist/es2015/scrolling/scroll-sync.service.d.ts +1 -1
- package/dist/es2015/scrolling/timeline-scroll.directive.d.ts +24 -0
- package/dist/es2015/scrolling/timeline-scroll.directive.js +78 -0
- package/dist/es2015/scrolling/timeline-scroll.service.d.ts +20 -0
- package/dist/es2015/scrolling/timeline-scroll.service.js +44 -0
- package/dist/es2015/scrolling/utils.d.ts +29 -0
- package/dist/es2015/scrolling/utils.js +80 -0
- package/dist/es2015/timeline/gantt-timeline.component.d.ts +29 -4
- package/dist/es2015/timeline/gantt-timeline.component.js +67 -5
- package/dist/es2015/toolbar/toolbar.component.d.ts +4 -5
- package/dist/es2015/toolbar/toolbar.component.js +12 -13
- package/dist/es2015/toolbar/view-selector.component.js +3 -1
- package/dist/es2015/utils.d.ts +77 -8
- package/dist/es2015/utils.js +153 -12
- package/dist/fesm2015/index.js +2807 -788
- package/dist/fesm5/index.js +2633 -688
- package/dist/{es2015/models/events/edit-event.interface.d.ts → npm/common/touch-enabled.js} +4 -12
- package/dist/npm/dependencies/utils.js +40 -5
- package/dist/npm/dragging/dependency-drag-create.directive.js +349 -0
- package/dist/npm/dragging/drag-validation-tooltip.component.js +29 -0
- package/dist/npm/editing/dependencies-table.component.js +133 -0
- package/dist/npm/editing/edit-dialog.component.js +38 -7
- package/dist/npm/editing/edit.service.js +90 -7
- package/dist/npm/editing/task-fields.component.js +45 -0
- package/dist/npm/editing/{util.js → utils.js} +0 -0
- package/dist/npm/gantt.component.js +354 -46
- package/dist/npm/gantt.module.js +33 -7
- package/dist/npm/index.js +16 -0
- package/dist/npm/localization/gantt-localization.service.js +28 -0
- package/dist/npm/main.js +2 -0
- package/dist/npm/models/dependency-type.enum.js +16 -0
- package/dist/npm/models/events/{edit-event.interface.js → dependency-add-event.interface.js} +0 -0
- package/dist/npm/models/events/{remove-event.interface.js → task-delete-event.interface.js} +0 -0
- package/dist/npm/models/models.js +2 -0
- package/dist/npm/models/view-item.interface.js +6 -0
- package/dist/npm/navigation/navigation-models.js +6 -0
- package/dist/npm/navigation/navigation.service.js +392 -0
- package/dist/npm/navigation/utils.js +79 -0
- package/dist/npm/package-metadata.js +1 -1
- package/dist/npm/rendering/gantt-milestone-task.component.js +11 -5
- package/dist/npm/rendering/gantt-summary-task.component.js +26 -5
- package/dist/npm/rendering/gantt-task-base.js +84 -22
- package/dist/npm/rendering/gantt-task.component.js +12 -7
- package/dist/npm/rendering/gantt-tasks-table-body.component.js +13 -5
- package/dist/npm/scrolling/drag-scroll-settings.js +22 -0
- package/dist/npm/scrolling/timeline-scroll.directive.js +91 -0
- package/dist/npm/scrolling/timeline-scroll.service.js +41 -0
- package/dist/npm/scrolling/utils.js +83 -0
- package/dist/npm/timeline/gantt-timeline.component.js +49 -3
- package/dist/npm/toolbar/toolbar.component.js +10 -11
- package/dist/npm/toolbar/view-selector.component.js +1 -1
- package/dist/npm/utils.js +153 -12
- package/dist/systemjs/kendo-angular-gantt.js +1 -1
- package/package.json +23 -19
package/dist/fesm2015/index.js
CHANGED
|
@@ -3,37 +3,802 @@
|
|
|
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 {
|
|
6
|
+
import { Injectable, NgZone, EventEmitter, ViewChild, ElementRef, ViewContainerRef, HostBinding, Input, TemplateRef, Output, Component, Renderer2, Directive, Optional, QueryList, ContentChildren, ContentChild, forwardRef, SkipSelf, Host, Injector, 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 {
|
|
9
|
+
import { Subject, Subscription, fromEvent, of, forkJoin, EMPTY, isObservable } from 'rxjs';
|
|
10
10
|
import { validatePackage } from '@progress/kendo-licensing';
|
|
11
|
-
import {
|
|
11
|
+
import { closestInScope, matchesClasses, isDocumentAvailable, Keys, hasObservers, anyChanged, EventsModule, DraggableModule } from '@progress/kendo-angular-common';
|
|
12
|
+
import { map, distinctUntilChanged, take, filter, switchMap, expand, reduce } from 'rxjs/operators';
|
|
13
|
+
import { getter, touchEnabled } from '@progress/kendo-common';
|
|
14
|
+
import { LocalizationService, ComponentMessages, L10N_PREFIX } from '@progress/kendo-angular-l10n';
|
|
12
15
|
import { IntlService } from '@progress/kendo-angular-intl';
|
|
13
16
|
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';
|
|
17
17
|
import { CommonModule } from '@angular/common';
|
|
18
|
-
import {
|
|
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';
|
|
28
|
+
|
|
29
|
+
/**
|
|
30
|
+
* @hidden
|
|
31
|
+
*/
|
|
32
|
+
const packageMetadata = {
|
|
33
|
+
name: '@progress/kendo-angular-gantt',
|
|
34
|
+
productName: 'Kendo UI for Angular',
|
|
35
|
+
productCodes: ['KENDOUIANGULAR', 'KENDOUICOMPLETE'],
|
|
36
|
+
publishDate: 1642606197,
|
|
37
|
+
version: '',
|
|
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'
|
|
39
|
+
};
|
|
40
|
+
|
|
41
|
+
/**
|
|
42
|
+
* @hidden
|
|
43
|
+
*/
|
|
44
|
+
let ScrollSyncService = class ScrollSyncService {
|
|
45
|
+
constructor(ngZone) {
|
|
46
|
+
this.ngZone = ngZone;
|
|
47
|
+
this.changes = new Subject();
|
|
48
|
+
this.elements = [];
|
|
49
|
+
this.subscriptions = new Subscription();
|
|
50
|
+
this.subscriptions.add(this.changes.subscribe(args => {
|
|
51
|
+
this.scroll(args);
|
|
52
|
+
}));
|
|
53
|
+
}
|
|
54
|
+
registerElement(el, sourceType) {
|
|
55
|
+
this.elements.push({ element: el, sourceType });
|
|
56
|
+
if (sourceType === "timeline" || sourceType === "treelist") {
|
|
57
|
+
this.ngZone.runOutsideAngular(() => {
|
|
58
|
+
const obs = fromEvent(el, 'scroll').pipe(map(({ target: { scrollTop, scrollLeft } }) => ({
|
|
59
|
+
scrollTop,
|
|
60
|
+
scrollLeft,
|
|
61
|
+
sourceType
|
|
62
|
+
})));
|
|
63
|
+
const comparisonFn = sourceType === 'timeline' ?
|
|
64
|
+
(x, y) => (x.scrollTop === y.scrollTop) && (x.scrollLeft === y.scrollLeft) :
|
|
65
|
+
(x, y) => (x.scrollTop === y.scrollTop);
|
|
66
|
+
this.subscriptions.add(obs.pipe(distinctUntilChanged(comparisonFn))
|
|
67
|
+
.subscribe((event) => this.changes.next(event)));
|
|
68
|
+
});
|
|
69
|
+
}
|
|
70
|
+
}
|
|
71
|
+
ngOnDestroy() {
|
|
72
|
+
this.subscriptions.unsubscribe();
|
|
73
|
+
this.elements = null;
|
|
74
|
+
}
|
|
75
|
+
syncScrollTop(sourceType, targetType) {
|
|
76
|
+
const source = this.elements.find(element => element.sourceType === sourceType);
|
|
77
|
+
const target = this.elements.find(element => element.sourceType === targetType);
|
|
78
|
+
// Need to wait for the splitter pane's content to be rendered
|
|
79
|
+
this.ngZone.onStable.pipe(take(1)).subscribe(() => target.element.scrollTop = source.element.scrollTop);
|
|
80
|
+
}
|
|
81
|
+
resetTimelineScrollLeft() {
|
|
82
|
+
const source = this.elements.find(element => element.sourceType === 'timeline');
|
|
83
|
+
source.element.scrollLeft = 0;
|
|
84
|
+
}
|
|
85
|
+
scroll({ scrollTop, scrollLeft, sourceType }) {
|
|
86
|
+
this.ngZone.runOutsideAngular(() => {
|
|
87
|
+
if (sourceType === 'timeline') {
|
|
88
|
+
const header = this.elements.find(element => element.sourceType === 'header').element;
|
|
89
|
+
header.scrollLeft = scrollLeft;
|
|
90
|
+
if (!this.syncingTimeline) {
|
|
91
|
+
this.syncingTreeList = true;
|
|
92
|
+
const treelist = this.elements.find(element => element.sourceType === 'treelist').element;
|
|
93
|
+
treelist.scrollTop = scrollTop;
|
|
94
|
+
}
|
|
95
|
+
this.syncingTimeline = false;
|
|
96
|
+
}
|
|
97
|
+
if (sourceType === 'treelist') {
|
|
98
|
+
if (!this.syncingTreeList) {
|
|
99
|
+
this.syncingTimeline = true;
|
|
100
|
+
const timeline = this.elements.find(element => element.sourceType === 'timeline').element;
|
|
101
|
+
timeline.scrollTop = scrollTop;
|
|
102
|
+
}
|
|
103
|
+
this.syncingTreeList = false;
|
|
104
|
+
}
|
|
105
|
+
});
|
|
106
|
+
}
|
|
107
|
+
};
|
|
108
|
+
ScrollSyncService = __decorate([
|
|
109
|
+
Injectable(),
|
|
110
|
+
__metadata("design:paramtypes", [NgZone])
|
|
111
|
+
], ScrollSyncService);
|
|
112
|
+
|
|
113
|
+
/**
|
|
114
|
+
* @hidden
|
|
115
|
+
*/
|
|
116
|
+
const DEFAULT_DEPENDENCY_MODEL_FIELDS = Object.freeze({
|
|
117
|
+
toId: 'toId',
|
|
118
|
+
fromId: 'fromId',
|
|
119
|
+
id: 'id',
|
|
120
|
+
type: 'type'
|
|
121
|
+
});
|
|
122
|
+
|
|
123
|
+
/**
|
|
124
|
+
* @hidden
|
|
125
|
+
*/
|
|
126
|
+
const DEFAULT_TASK_MODEL_FIELDS = Object.freeze({
|
|
127
|
+
id: 'id',
|
|
128
|
+
start: 'start',
|
|
129
|
+
end: 'end',
|
|
130
|
+
title: 'title',
|
|
131
|
+
completionRatio: 'completionRatio',
|
|
132
|
+
children: 'children'
|
|
133
|
+
});
|
|
134
|
+
|
|
135
|
+
/**
|
|
136
|
+
* The dependency type when two tasks are connected.
|
|
137
|
+
*
|
|
138
|
+
* The supported values are:
|
|
139
|
+
* * `FF`—from 'finish' to 'finish'
|
|
140
|
+
* * `FS`—from 'finish' to 'start'
|
|
141
|
+
* * `SS`—from 'start' to 'start'
|
|
142
|
+
* * `SF`—from 'start' to 'finish'
|
|
143
|
+
*/
|
|
144
|
+
var DependencyType;
|
|
145
|
+
(function (DependencyType) {
|
|
146
|
+
DependencyType[DependencyType["FF"] = 0] = "FF";
|
|
147
|
+
DependencyType[DependencyType["FS"] = 1] = "FS";
|
|
148
|
+
DependencyType[DependencyType["SF"] = 2] = "SF";
|
|
149
|
+
DependencyType[DependencyType["SS"] = 3] = "SS"; // task B can't start before task A starts
|
|
150
|
+
})(DependencyType || (DependencyType = {}));
|
|
151
|
+
|
|
152
|
+
/**
|
|
153
|
+
* @hidden
|
|
154
|
+
*/
|
|
155
|
+
const isWorkDay = (date, start, end) => {
|
|
156
|
+
return date.getDay() >= start && date.getDay() <= end;
|
|
157
|
+
};
|
|
158
|
+
/**
|
|
159
|
+
* @hidden
|
|
160
|
+
*/
|
|
161
|
+
const isWorkHour = (date, start, end) => {
|
|
162
|
+
return date.getHours() >= start && date.getHours() <= end;
|
|
163
|
+
};
|
|
164
|
+
/**
|
|
165
|
+
* @hidden
|
|
166
|
+
*/
|
|
167
|
+
const isPresent = (item) => item !== null && item !== undefined;
|
|
168
|
+
/**
|
|
169
|
+
* @hidden
|
|
170
|
+
*
|
|
171
|
+
* Normalized the data to an array in case a falsy value is passed
|
|
172
|
+
* or a TreeListDataResult object (applicable for the data-binding directives).
|
|
173
|
+
*/
|
|
174
|
+
const normalizeGanttData = (data) => {
|
|
175
|
+
if (!isPresent(data)) {
|
|
176
|
+
return [];
|
|
177
|
+
}
|
|
178
|
+
else if (Array.isArray(data.data)) {
|
|
179
|
+
return data.data;
|
|
180
|
+
}
|
|
181
|
+
else {
|
|
182
|
+
return data;
|
|
183
|
+
}
|
|
184
|
+
};
|
|
185
|
+
/**
|
|
186
|
+
* @hidden
|
|
187
|
+
*
|
|
188
|
+
* Returns a new date with the specified hours, minutes, seconds and millliseconds set.
|
|
189
|
+
* Only the hours are required, the rest of the params are set to `0` by default.
|
|
190
|
+
*/
|
|
191
|
+
const setTime = (date, hours, minutes = 0, seconds = 0, milliseconds = 0) => {
|
|
192
|
+
if (!isPresent(date)) {
|
|
193
|
+
return null;
|
|
194
|
+
}
|
|
195
|
+
const result = cloneDate(date);
|
|
196
|
+
result.setHours(hours);
|
|
197
|
+
result.setMinutes(minutes);
|
|
198
|
+
result.setSeconds(seconds);
|
|
199
|
+
result.setMilliseconds(milliseconds);
|
|
200
|
+
return result;
|
|
201
|
+
};
|
|
202
|
+
/**
|
|
203
|
+
* @hidden
|
|
204
|
+
*
|
|
205
|
+
* Returns the last day of a week.
|
|
206
|
+
* @param standingPoint - Any day of the target week.
|
|
207
|
+
* @param firstWeekDay - The week's starting day (e.g. Monday, Tuesday, etc.)
|
|
208
|
+
*/
|
|
209
|
+
const lastDayOfWeek = (standingPoint, firstWeekDay) => {
|
|
210
|
+
const followingWeek = addWeeks(standingPoint, 1);
|
|
211
|
+
const firstDayOfFollowingWeek = firstDayInWeek(followingWeek, firstWeekDay);
|
|
212
|
+
const lastDayOfTargetWeek = addDays(firstDayOfFollowingWeek, -1);
|
|
213
|
+
return lastDayOfTargetWeek;
|
|
214
|
+
};
|
|
215
|
+
/**
|
|
216
|
+
* Persists the intially resolved scrollbar width value.
|
|
217
|
+
*/
|
|
218
|
+
let SCROLLBAR_WIDTH;
|
|
219
|
+
/**
|
|
220
|
+
* @hidden
|
|
221
|
+
*
|
|
222
|
+
* Gets the default scrollbar width accoring to the current environment.
|
|
223
|
+
*/
|
|
224
|
+
const scrollbarWidth = () => {
|
|
225
|
+
if (!isDocumentAvailable()) {
|
|
226
|
+
return;
|
|
227
|
+
}
|
|
228
|
+
// calculate scrollbar width only once, then return the cached value
|
|
229
|
+
if (isNaN(SCROLLBAR_WIDTH)) {
|
|
230
|
+
const div = document.createElement('div');
|
|
231
|
+
div.style.cssText = 'overflow: scroll; overflow-x: hidden; zoom: 1; clear: both; display: block;';
|
|
232
|
+
div.innerHTML = ' ';
|
|
233
|
+
document.body.appendChild(div);
|
|
234
|
+
SCROLLBAR_WIDTH = div.offsetWidth - div.scrollWidth;
|
|
235
|
+
document.body.removeChild(div);
|
|
236
|
+
}
|
|
237
|
+
return SCROLLBAR_WIDTH;
|
|
238
|
+
};
|
|
239
|
+
/**
|
|
240
|
+
* @hidden
|
|
241
|
+
*/
|
|
242
|
+
const isColumnGroup = (column) => column.isColumnGroup;
|
|
243
|
+
/**
|
|
244
|
+
* @hidden
|
|
245
|
+
*/
|
|
246
|
+
const isNumber = (contender) => typeof contender === 'number' && !isNaN(contender);
|
|
247
|
+
/**
|
|
248
|
+
* @hidden
|
|
249
|
+
*/
|
|
250
|
+
const isString = (contender) => typeof contender === 'string';
|
|
251
|
+
/**
|
|
252
|
+
* @hidden
|
|
253
|
+
*
|
|
254
|
+
* Gets the closest timeline task wrapper element from an event target.
|
|
255
|
+
* Restricts the search up to the provided parent element from the second param.
|
|
256
|
+
*/
|
|
257
|
+
const getClosestTaskWrapper = (element, parentScope) => {
|
|
258
|
+
return closestInScope(element, matchesClasses('k-task-wrap'), parentScope);
|
|
259
|
+
};
|
|
260
|
+
/**
|
|
261
|
+
* @hidden
|
|
262
|
+
*
|
|
263
|
+
* Checks whether the queried item or its parent items has a `k-task-wrap` selector.
|
|
264
|
+
* Restricts the search up to the provided parent element from the second param.
|
|
265
|
+
*/
|
|
266
|
+
const isTaskWrapper = (contender, parentScope) => {
|
|
267
|
+
const taskWrapper = closestInScope(contender, matchesClasses('k-task-wrap'), parentScope);
|
|
268
|
+
return isPresent(taskWrapper);
|
|
269
|
+
};
|
|
270
|
+
/**
|
|
271
|
+
* @hidden
|
|
272
|
+
*
|
|
273
|
+
* Gets the closest timeline task element index from an event target.
|
|
274
|
+
* Uses the `data-task-index` attribute assigned to each task.
|
|
275
|
+
* Restricts the search up to the provided parent element from the second param.
|
|
276
|
+
*/
|
|
277
|
+
const getClosestTaskIndex = (element, parentScope) => {
|
|
278
|
+
const task = closestInScope(element, matchesClasses('k-task-wrap'), parentScope);
|
|
279
|
+
if (!isPresent(task)) {
|
|
280
|
+
return null;
|
|
281
|
+
}
|
|
282
|
+
return Number(task.getAttribute('data-task-index'));
|
|
283
|
+
};
|
|
284
|
+
/**
|
|
285
|
+
* @hidden
|
|
286
|
+
*
|
|
287
|
+
* Checks whether the queried item or its parent items has a `k-task` selector.
|
|
288
|
+
* Restricts the search up to the provided parent element from the second param.
|
|
289
|
+
*/
|
|
290
|
+
const isTask = (contender, parentScope) => {
|
|
291
|
+
const task = closestInScope(contender, matchesClasses('k-task'), parentScope);
|
|
292
|
+
return isPresent(task);
|
|
293
|
+
};
|
|
294
|
+
/**
|
|
295
|
+
* @hidden
|
|
296
|
+
*
|
|
297
|
+
* Checks whether the queried item or its parent items has a `k-toolbar` selector.
|
|
298
|
+
* Restricts the search up to the provided parent element from the second param.
|
|
299
|
+
*/
|
|
300
|
+
const isToolbar = (contender, parentScope) => {
|
|
301
|
+
const toolbar = closestInScope(contender, matchesClasses('k-gantt-toolbar'), parentScope);
|
|
302
|
+
return isPresent(toolbar);
|
|
303
|
+
};
|
|
304
|
+
/**
|
|
305
|
+
* @hidden
|
|
306
|
+
*
|
|
307
|
+
* Checks whether the queried item or its parent items has a `k-task-actions` selector - used for the clear button.
|
|
308
|
+
* Restricts the search up to the provided parent element from the second param.
|
|
309
|
+
*/
|
|
310
|
+
const isClearButton = (contender, parentScope) => {
|
|
311
|
+
const clearButtonContainer = closestInScope(contender, matchesClasses('k-task-actions'), parentScope);
|
|
312
|
+
return isPresent(clearButtonContainer);
|
|
313
|
+
};
|
|
314
|
+
/**
|
|
315
|
+
* @hidden
|
|
316
|
+
*
|
|
317
|
+
* Checks whether the queried item has a `k-task-dot` selector - used for the dependency drag clues.
|
|
318
|
+
*/
|
|
319
|
+
const isDependencyDragClue = (element) => {
|
|
320
|
+
if (!isPresent(element)) {
|
|
321
|
+
return false;
|
|
322
|
+
}
|
|
323
|
+
return element.classList.contains('k-task-dot');
|
|
324
|
+
};
|
|
325
|
+
/**
|
|
326
|
+
* @hidden
|
|
327
|
+
*
|
|
328
|
+
* Checks whether the queried item has a `k-task-dot` & `k-task-start` selector - used for the dependency drag start clues.
|
|
329
|
+
*/
|
|
330
|
+
const isDependencyDragStartClue = (element) => {
|
|
331
|
+
if (!isPresent(element)) {
|
|
332
|
+
return false;
|
|
333
|
+
}
|
|
334
|
+
return element.classList.contains('k-task-dot') && element.classList.contains('k-task-start');
|
|
335
|
+
};
|
|
336
|
+
/**
|
|
337
|
+
* @hidden
|
|
338
|
+
*
|
|
339
|
+
* Gets the `DependencyType` for an attempted dependency create from the provided two elements.
|
|
340
|
+
* The two linked drag clue HTML elements are used to extract this data (via their CSS classes).
|
|
341
|
+
*/
|
|
342
|
+
const getDependencyTypeFromTargetTasks = (fromTaskClue, toTaskClue) => {
|
|
343
|
+
if (!isDependencyDragClue(fromTaskClue) || !isDependencyDragClue(toTaskClue)) {
|
|
344
|
+
return null;
|
|
345
|
+
}
|
|
346
|
+
const fromTaskType = isDependencyDragStartClue(fromTaskClue) ? 'S' : 'F';
|
|
347
|
+
const toTaskType = isDependencyDragStartClue(toTaskClue) ? 'S' : 'F';
|
|
348
|
+
const dependencyTypeName = `${fromTaskType}${toTaskType}`;
|
|
349
|
+
switch (dependencyTypeName) {
|
|
350
|
+
case 'FF': return DependencyType.FF;
|
|
351
|
+
case 'FS': return DependencyType.FS;
|
|
352
|
+
case 'SF': return DependencyType.SF;
|
|
353
|
+
case 'SS': return DependencyType.SS;
|
|
354
|
+
default: return null;
|
|
355
|
+
}
|
|
356
|
+
};
|
|
357
|
+
/**
|
|
358
|
+
* @hidden
|
|
359
|
+
*
|
|
360
|
+
* Checks whether the two provided drag clues belong to the same task element.
|
|
361
|
+
*/
|
|
362
|
+
const sameTaskClues = (fromTaskClue, toTaskClue, parentScope) => {
|
|
363
|
+
if (!isPresent(fromTaskClue) || !isPresent(toTaskClue)) {
|
|
364
|
+
return false;
|
|
365
|
+
}
|
|
366
|
+
const fromTaskWrapper = getClosestTaskWrapper(fromTaskClue, parentScope);
|
|
367
|
+
const toTaskWrapper = getClosestTaskWrapper(toTaskClue, parentScope);
|
|
368
|
+
return fromTaskWrapper === toTaskWrapper;
|
|
369
|
+
};
|
|
370
|
+
/**
|
|
371
|
+
* @hidden
|
|
372
|
+
*
|
|
373
|
+
* Fits a contender number between a min and max range.
|
|
374
|
+
* If the contender is below the min value, the min value is returned.
|
|
375
|
+
* If the contender is above the max value, the max value is returned.
|
|
376
|
+
*/
|
|
377
|
+
const fitToRange = (contender, min, max) => {
|
|
378
|
+
if (!isPresent(contender) || contender < min) {
|
|
379
|
+
return min;
|
|
380
|
+
}
|
|
381
|
+
else if (contender > max) {
|
|
382
|
+
return max;
|
|
383
|
+
}
|
|
384
|
+
else {
|
|
385
|
+
return contender;
|
|
386
|
+
}
|
|
387
|
+
};
|
|
388
|
+
/**
|
|
389
|
+
* @hidden
|
|
390
|
+
*
|
|
391
|
+
* Checks whether either of the two provided tasks is a parent of the other.
|
|
392
|
+
*/
|
|
393
|
+
const areParentChild = (taskA, taskB) => {
|
|
394
|
+
let parentChildRelationship = false;
|
|
395
|
+
let taskAParent = taskA;
|
|
396
|
+
while (isPresent(taskAParent) && isPresent(taskAParent.data)) {
|
|
397
|
+
if (taskAParent.data === taskB.data) {
|
|
398
|
+
parentChildRelationship = true;
|
|
399
|
+
break;
|
|
400
|
+
}
|
|
401
|
+
taskAParent = taskAParent.parent;
|
|
402
|
+
}
|
|
403
|
+
let taskBParent = taskB;
|
|
404
|
+
while (!parentChildRelationship && isPresent(taskBParent) && isPresent(taskBParent.data)) {
|
|
405
|
+
if (taskBParent.data === taskA.data) {
|
|
406
|
+
parentChildRelationship = true;
|
|
407
|
+
break;
|
|
408
|
+
}
|
|
409
|
+
taskBParent = taskBParent.parent;
|
|
410
|
+
}
|
|
411
|
+
return parentChildRelationship;
|
|
412
|
+
};
|
|
413
|
+
/**
|
|
414
|
+
* @hidden
|
|
415
|
+
*
|
|
416
|
+
* Extracts an element from the provided client coords.
|
|
417
|
+
* Using the `event.target` is not reliable under mobile devices with the current implementation of the draggable, so use this instead.
|
|
418
|
+
*/
|
|
419
|
+
const elementFromPoint = (clientX, clientY) => {
|
|
420
|
+
if (!isDocumentAvailable()) {
|
|
421
|
+
return null;
|
|
422
|
+
}
|
|
423
|
+
return document.elementFromPoint(clientX, clientY);
|
|
424
|
+
};
|
|
425
|
+
|
|
426
|
+
/**
|
|
427
|
+
* @hidden
|
|
428
|
+
*/
|
|
429
|
+
let MappingService = class MappingService {
|
|
430
|
+
/**
|
|
431
|
+
* @hidden
|
|
432
|
+
*/
|
|
433
|
+
constructor() {
|
|
434
|
+
this._taskFields = Object.assign({}, DEFAULT_TASK_MODEL_FIELDS);
|
|
435
|
+
this._dependencyFields = Object.assign({}, DEFAULT_DEPENDENCY_MODEL_FIELDS);
|
|
436
|
+
}
|
|
437
|
+
/**
|
|
438
|
+
* Gets or sets the model fields for the task data items.
|
|
439
|
+
* Uses the default values for fields which are not specified.
|
|
440
|
+
*/
|
|
441
|
+
set taskFields(fields) {
|
|
442
|
+
this._taskFields = Object.assign({}, DEFAULT_TASK_MODEL_FIELDS, fields);
|
|
443
|
+
}
|
|
444
|
+
get taskFields() {
|
|
445
|
+
return this._taskFields;
|
|
446
|
+
}
|
|
447
|
+
/**
|
|
448
|
+
* Gets or sets the model fields for the depenency data items.
|
|
449
|
+
* Uses the default values for fields which are not specified.
|
|
450
|
+
*/
|
|
451
|
+
set dependencyFields(fields) {
|
|
452
|
+
this._dependencyFields = Object.assign({}, DEFAULT_DEPENDENCY_MODEL_FIELDS, fields);
|
|
453
|
+
}
|
|
454
|
+
get dependencyFields() {
|
|
455
|
+
return this._dependencyFields;
|
|
456
|
+
}
|
|
457
|
+
/**
|
|
458
|
+
* Retrieves the value for the specified task field.
|
|
459
|
+
* Supports nested fields as well (e.g. 'manager.id').
|
|
460
|
+
*/
|
|
461
|
+
extractFromTask(dataItem, field) {
|
|
462
|
+
if (!isPresent(this.taskFields)) {
|
|
463
|
+
return null;
|
|
464
|
+
}
|
|
465
|
+
return getter(this.taskFields[field])(dataItem);
|
|
466
|
+
}
|
|
467
|
+
/**
|
|
468
|
+
* Retrieves the value for the specified dependency field.
|
|
469
|
+
* Supports nested fields as well (e.g. 'manager.id').
|
|
470
|
+
*/
|
|
471
|
+
extractFromDependency(dataItem, field) {
|
|
472
|
+
if (!isPresent(this.dependencyFields)) {
|
|
473
|
+
return null;
|
|
474
|
+
}
|
|
475
|
+
return getter(this.dependencyFields[field])(dataItem);
|
|
476
|
+
}
|
|
477
|
+
};
|
|
478
|
+
MappingService = __decorate([
|
|
479
|
+
Injectable()
|
|
480
|
+
], MappingService);
|
|
481
|
+
|
|
482
|
+
/**
|
|
483
|
+
* @hidden
|
|
484
|
+
*/
|
|
485
|
+
let DependencyDomService = class DependencyDomService {
|
|
486
|
+
constructor(mapper) {
|
|
487
|
+
this.mapper = mapper;
|
|
488
|
+
this.notifier = new Subject();
|
|
489
|
+
/**
|
|
490
|
+
* Maps each rendered task to its HTML element.
|
|
491
|
+
* Uses the task ID field value as key.
|
|
492
|
+
*/
|
|
493
|
+
this.tasks = new Map();
|
|
494
|
+
}
|
|
495
|
+
/**
|
|
496
|
+
* Emits each time some of the tasks or the view have changed.
|
|
497
|
+
* Fires also on the first change of the table rows and the parent container.
|
|
498
|
+
*/
|
|
499
|
+
get taskChanges() {
|
|
500
|
+
return this.notifier.asObservable();
|
|
501
|
+
}
|
|
502
|
+
get dependencyDomArgs() {
|
|
503
|
+
return {
|
|
504
|
+
tasks: this.tasks,
|
|
505
|
+
contentContainer: this.contentContainer,
|
|
506
|
+
timelineRow: this.timelineRow
|
|
507
|
+
};
|
|
508
|
+
}
|
|
509
|
+
ngOnDestroy() {
|
|
510
|
+
this.tasks.clear();
|
|
511
|
+
this.tasks = null;
|
|
512
|
+
this.contentContainer = null;
|
|
513
|
+
}
|
|
514
|
+
registerTimelineRow(timelineRow) {
|
|
515
|
+
this.timelineRow = timelineRow;
|
|
516
|
+
this.notifyChanges();
|
|
517
|
+
}
|
|
518
|
+
registerContentContainer(contentContainer) {
|
|
519
|
+
this.contentContainer = contentContainer;
|
|
520
|
+
this.notifyChanges();
|
|
521
|
+
}
|
|
522
|
+
registerTask(task, element) {
|
|
523
|
+
const id = this.mapper.extractFromTask(task, 'id');
|
|
524
|
+
this.tasks.set(id, element);
|
|
525
|
+
this.notifyChanges();
|
|
526
|
+
}
|
|
527
|
+
unregisterTask(task) {
|
|
528
|
+
const id = this.mapper.extractFromTask(task, 'id');
|
|
529
|
+
this.tasks.delete(id);
|
|
530
|
+
this.notifyChanges();
|
|
531
|
+
}
|
|
532
|
+
/**
|
|
533
|
+
* Notifies all dependency directives that a change in one of the elements has occured.
|
|
534
|
+
*/
|
|
535
|
+
notifyChanges() {
|
|
536
|
+
this.notifier.next(this.dependencyDomArgs);
|
|
537
|
+
}
|
|
538
|
+
};
|
|
539
|
+
DependencyDomService = __decorate([
|
|
540
|
+
Injectable(),
|
|
541
|
+
__metadata("design:paramtypes", [MappingService])
|
|
542
|
+
], DependencyDomService);
|
|
543
|
+
|
|
544
|
+
/**
|
|
545
|
+
* @hidden
|
|
546
|
+
*/
|
|
547
|
+
let GanttTimelineComponent = class GanttTimelineComponent {
|
|
548
|
+
constructor(scrollSyncService, dependencyDomService, renderer, zone) {
|
|
549
|
+
this.scrollSyncService = scrollSyncService;
|
|
550
|
+
this.dependencyDomService = dependencyDomService;
|
|
551
|
+
this.renderer = renderer;
|
|
552
|
+
this.zone = zone;
|
|
553
|
+
this.hostClass = true;
|
|
554
|
+
this.dependencies = [];
|
|
555
|
+
// as all drag-and-drop operations are on the timeline container, use a single draggable instance
|
|
556
|
+
this.timelineContainerPress = new EventEmitter();
|
|
557
|
+
this.timelineContainerDrag = new EventEmitter();
|
|
558
|
+
this.timelineContainerRelease = new EventEmitter();
|
|
559
|
+
this.subscriptions = new Subscription();
|
|
560
|
+
this.subscriptions.add(
|
|
561
|
+
// task changes indicates change in row content, number, height, etc.
|
|
562
|
+
this.dependencyDomService.taskChanges
|
|
563
|
+
.pipe(filter(args => isPresent(args.timelineRow)), switchMap(args => this.zone.onStable.pipe(take(1), map(() => args))) // ensure the content is rendered
|
|
564
|
+
)
|
|
565
|
+
.subscribe(({ timelineRow }) => {
|
|
566
|
+
const timelineRowHeight = isDocumentAvailable() ? timelineRow.getBoundingClientRect().height : 0;
|
|
567
|
+
this.renderer.setStyle(this.timelineColumns.nativeElement, 'height', `${(this.rows || []).length * timelineRowHeight}px`);
|
|
568
|
+
}));
|
|
569
|
+
}
|
|
570
|
+
/**
|
|
571
|
+
* Specifies whether the draggable will attach or detach its pointer event listeners.
|
|
572
|
+
*/
|
|
573
|
+
get draggableEnabled() {
|
|
574
|
+
return this.renderDependencyDragClues;
|
|
575
|
+
}
|
|
576
|
+
ngAfterViewInit() {
|
|
577
|
+
const timelineHeader = this.timelineHeaderWrap.nativeElement;
|
|
578
|
+
const rightContainer = this.timelineContent.nativeElement;
|
|
579
|
+
this.scrollSyncService.registerElement(rightContainer, 'timeline');
|
|
580
|
+
this.scrollSyncService.registerElement(timelineHeader, 'header');
|
|
581
|
+
this.dependencyDomService.registerContentContainer(this.tasksContainer.nativeElement);
|
|
582
|
+
}
|
|
583
|
+
ngOnDestroy() {
|
|
584
|
+
this.subscriptions.unsubscribe();
|
|
585
|
+
}
|
|
586
|
+
isNonWorking(item) {
|
|
587
|
+
return item.hasOwnProperty('isWorking') && !item.isWorking;
|
|
588
|
+
}
|
|
589
|
+
};
|
|
590
|
+
__decorate([
|
|
591
|
+
ViewChild('timelineContent', { static: true }),
|
|
592
|
+
__metadata("design:type", ElementRef)
|
|
593
|
+
], GanttTimelineComponent.prototype, "timelineContent", void 0);
|
|
594
|
+
__decorate([
|
|
595
|
+
ViewChild('timelineColumns', { static: true }),
|
|
596
|
+
__metadata("design:type", ElementRef)
|
|
597
|
+
], GanttTimelineComponent.prototype, "timelineColumns", void 0);
|
|
598
|
+
__decorate([
|
|
599
|
+
ViewChild('timelineHeaderWrap', { static: true }),
|
|
600
|
+
__metadata("design:type", ElementRef)
|
|
601
|
+
], GanttTimelineComponent.prototype, "timelineHeaderWrap", void 0);
|
|
602
|
+
__decorate([
|
|
603
|
+
ViewChild('tasksContainer', { static: true }),
|
|
604
|
+
__metadata("design:type", ElementRef)
|
|
605
|
+
], GanttTimelineComponent.prototype, "tasksContainer", void 0);
|
|
606
|
+
__decorate([
|
|
607
|
+
ViewChild('dragPopupContainer', { static: false, read: ViewContainerRef }),
|
|
608
|
+
__metadata("design:type", ViewContainerRef)
|
|
609
|
+
], GanttTimelineComponent.prototype, "dragPopupContainer", void 0);
|
|
610
|
+
__decorate([
|
|
611
|
+
ViewChild('dependencyDragCreatePolyline', { static: false }),
|
|
612
|
+
__metadata("design:type", ElementRef)
|
|
613
|
+
], GanttTimelineComponent.prototype, "dependencyDragCreatePolyline", void 0);
|
|
614
|
+
__decorate([
|
|
615
|
+
HostBinding('class.k-gantt-timeline'),
|
|
616
|
+
__metadata("design:type", Boolean)
|
|
617
|
+
], GanttTimelineComponent.prototype, "hostClass", void 0);
|
|
618
|
+
__decorate([
|
|
619
|
+
Input(),
|
|
620
|
+
__metadata("design:type", Array)
|
|
621
|
+
], GanttTimelineComponent.prototype, "rows", void 0);
|
|
622
|
+
__decorate([
|
|
623
|
+
Input(),
|
|
624
|
+
__metadata("design:type", Array)
|
|
625
|
+
], GanttTimelineComponent.prototype, "slots", void 0);
|
|
626
|
+
__decorate([
|
|
627
|
+
Input(),
|
|
628
|
+
__metadata("design:type", Array)
|
|
629
|
+
], GanttTimelineComponent.prototype, "groupSlots", void 0);
|
|
630
|
+
__decorate([
|
|
631
|
+
Input(),
|
|
632
|
+
__metadata("design:type", Number)
|
|
633
|
+
], GanttTimelineComponent.prototype, "tableWidth", void 0);
|
|
634
|
+
__decorate([
|
|
635
|
+
Input(),
|
|
636
|
+
__metadata("design:type", String)
|
|
637
|
+
], GanttTimelineComponent.prototype, "activeView", void 0);
|
|
638
|
+
__decorate([
|
|
639
|
+
Input(),
|
|
640
|
+
__metadata("design:type", TemplateRef)
|
|
641
|
+
], GanttTimelineComponent.prototype, "taskContentTemplate", void 0);
|
|
642
|
+
__decorate([
|
|
643
|
+
Input(),
|
|
644
|
+
__metadata("design:type", TemplateRef)
|
|
645
|
+
], GanttTimelineComponent.prototype, "taskTemplate", void 0);
|
|
646
|
+
__decorate([
|
|
647
|
+
Input(),
|
|
648
|
+
__metadata("design:type", TemplateRef)
|
|
649
|
+
], GanttTimelineComponent.prototype, "summaryTaskTemplate", void 0);
|
|
650
|
+
__decorate([
|
|
651
|
+
Input(),
|
|
652
|
+
__metadata("design:type", Function)
|
|
653
|
+
], GanttTimelineComponent.prototype, "taskClass", void 0);
|
|
654
|
+
__decorate([
|
|
655
|
+
Input(),
|
|
656
|
+
__metadata("design:type", Boolean)
|
|
657
|
+
], GanttTimelineComponent.prototype, "renderDependencyDragClues", void 0);
|
|
658
|
+
__decorate([
|
|
659
|
+
Input(),
|
|
660
|
+
__metadata("design:type", Object)
|
|
661
|
+
], GanttTimelineComponent.prototype, "dragScrollSettings", void 0);
|
|
662
|
+
__decorate([
|
|
663
|
+
Input(),
|
|
664
|
+
__metadata("design:type", Boolean)
|
|
665
|
+
], GanttTimelineComponent.prototype, "selectable", void 0);
|
|
666
|
+
__decorate([
|
|
667
|
+
Input(),
|
|
668
|
+
__metadata("design:type", Function)
|
|
669
|
+
], GanttTimelineComponent.prototype, "isTaskSelected", void 0);
|
|
670
|
+
__decorate([
|
|
671
|
+
Input(),
|
|
672
|
+
__metadata("design:type", Function)
|
|
673
|
+
], GanttTimelineComponent.prototype, "isExpanded", void 0);
|
|
674
|
+
__decorate([
|
|
675
|
+
Input(),
|
|
676
|
+
__metadata("design:type", Array)
|
|
677
|
+
], GanttTimelineComponent.prototype, "dependencies", void 0);
|
|
678
|
+
__decorate([
|
|
679
|
+
Output(),
|
|
680
|
+
__metadata("design:type", EventEmitter)
|
|
681
|
+
], GanttTimelineComponent.prototype, "timelineContainerPress", void 0);
|
|
682
|
+
__decorate([
|
|
683
|
+
Output(),
|
|
684
|
+
__metadata("design:type", EventEmitter)
|
|
685
|
+
], GanttTimelineComponent.prototype, "timelineContainerDrag", void 0);
|
|
686
|
+
__decorate([
|
|
687
|
+
Output(),
|
|
688
|
+
__metadata("design:type", EventEmitter)
|
|
689
|
+
], GanttTimelineComponent.prototype, "timelineContainerRelease", void 0);
|
|
690
|
+
GanttTimelineComponent = __decorate([
|
|
691
|
+
Component({
|
|
692
|
+
selector: 'kendo-gantt-timeline',
|
|
693
|
+
template: `
|
|
694
|
+
<div class="k-timeline k-grid k-widget">
|
|
695
|
+
<div class="k-grid-header">
|
|
696
|
+
<div #timelineHeaderWrap class="k-grid-header-wrap">
|
|
697
|
+
<table
|
|
698
|
+
role="presentation"
|
|
699
|
+
[style.width.px]="tableWidth"
|
|
700
|
+
>
|
|
701
|
+
<tbody
|
|
702
|
+
kendoGanttHeaderTableBody
|
|
703
|
+
[groupSlots]="groupSlots"
|
|
704
|
+
[slots]="slots">
|
|
705
|
+
</tbody>
|
|
706
|
+
</table>
|
|
707
|
+
</div>
|
|
708
|
+
</div>
|
|
709
|
+
<!-- tabindex="-1" required for https://bugzilla.mozilla.org/show_bug.cgi?id=1069739 -->
|
|
710
|
+
<div
|
|
711
|
+
#timelineContent
|
|
712
|
+
class="k-grid-content"
|
|
713
|
+
tabindex="-1"
|
|
714
|
+
role="tree"
|
|
715
|
+
aria-roledescription="Timeline"
|
|
716
|
+
kendoGanttTimelineScrollable
|
|
717
|
+
[scrollSettings]="dragScrollSettings"
|
|
718
|
+
kendoDraggable
|
|
719
|
+
[enableDrag]="draggableEnabled"
|
|
720
|
+
(kendoPress)="timelineContainerPress.emit($event)"
|
|
721
|
+
(kendoDrag)="timelineContainerDrag.emit($event)"
|
|
722
|
+
(kendoRelease)="timelineContainerRelease.emit($event)"
|
|
723
|
+
>
|
|
724
|
+
<div class="k-gantt-tables">
|
|
725
|
+
<table
|
|
726
|
+
class="k-gantt-rows"
|
|
727
|
+
[style.width.px]="tableWidth"
|
|
728
|
+
role="presentation"
|
|
729
|
+
>
|
|
730
|
+
<tbody>
|
|
731
|
+
<tr *ngFor="let item of rows; let i = index;"
|
|
732
|
+
[class.k-alt]="i % 2"
|
|
733
|
+
>
|
|
734
|
+
<td></td>
|
|
735
|
+
</tr>
|
|
736
|
+
</tbody>
|
|
737
|
+
</table>
|
|
25
738
|
|
|
26
|
-
|
|
27
|
-
|
|
28
|
-
|
|
29
|
-
|
|
30
|
-
|
|
31
|
-
|
|
32
|
-
|
|
33
|
-
|
|
34
|
-
|
|
35
|
-
|
|
36
|
-
|
|
739
|
+
<table
|
|
740
|
+
#timelineColumns
|
|
741
|
+
class="k-gantt-columns"
|
|
742
|
+
role="presentation"
|
|
743
|
+
[style.width.px]="tableWidth"
|
|
744
|
+
>
|
|
745
|
+
<colgroup>
|
|
746
|
+
<col *ngFor="let item of slots">
|
|
747
|
+
</colgroup>
|
|
748
|
+
|
|
749
|
+
<tbody>
|
|
750
|
+
<tr>
|
|
751
|
+
<td *ngFor="let item of slots"
|
|
752
|
+
[class.k-nonwork-hour]="isNonWorking(item)"
|
|
753
|
+
>
|
|
754
|
+
</td>
|
|
755
|
+
</tr>
|
|
756
|
+
</tbody>
|
|
757
|
+
</table>
|
|
758
|
+
|
|
759
|
+
<table
|
|
760
|
+
#tasksContainer
|
|
761
|
+
class="k-gantt-tasks"
|
|
762
|
+
role="presentation"
|
|
763
|
+
style="border-collapse: collapse;"
|
|
764
|
+
[style.width.px]="tableWidth"
|
|
765
|
+
>
|
|
766
|
+
<tbody
|
|
767
|
+
kendoGanttTasksTableBody
|
|
768
|
+
[rows]="rows"
|
|
769
|
+
[activeView]="activeView"
|
|
770
|
+
[taskContentTemplate]="taskContentTemplate"
|
|
771
|
+
[taskTemplate]="taskTemplate"
|
|
772
|
+
[summaryTaskTemplate]="summaryTaskTemplate"
|
|
773
|
+
[taskClass]="taskClass"
|
|
774
|
+
[isExpanded]="isExpanded"
|
|
775
|
+
[selectable]="selectable"
|
|
776
|
+
[isTaskSelected]="isTaskSelected"
|
|
777
|
+
[renderDependencyDragClues]="renderDependencyDragClues"
|
|
778
|
+
>
|
|
779
|
+
</tbody>
|
|
780
|
+
</table>
|
|
781
|
+
</div>
|
|
782
|
+
<svg class="k-gantt-dependencies-svg">
|
|
783
|
+
<polyline
|
|
784
|
+
*ngFor="let dependency of dependencies"
|
|
785
|
+
kendoGanttDependency
|
|
786
|
+
[dependency]="dependency"
|
|
787
|
+
/>
|
|
788
|
+
<polyline #dependencyDragCreatePolyline />
|
|
789
|
+
</svg>
|
|
790
|
+
|
|
791
|
+
<!-- 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 -->
|
|
792
|
+
<ng-container #dragPopupContainer></ng-container>
|
|
793
|
+
</div>
|
|
794
|
+
</div>
|
|
795
|
+
`
|
|
796
|
+
}),
|
|
797
|
+
__metadata("design:paramtypes", [ScrollSyncService,
|
|
798
|
+
DependencyDomService,
|
|
799
|
+
Renderer2,
|
|
800
|
+
NgZone])
|
|
801
|
+
], GanttTimelineComponent);
|
|
37
802
|
|
|
38
803
|
/**
|
|
39
804
|
* The base class for the column components of the Gantt.
|
|
@@ -631,140 +1396,43 @@ const taskClassCallback = () => null;
|
|
|
631
1396
|
* @hidden
|
|
632
1397
|
*/
|
|
633
1398
|
const isSelected = () => false;
|
|
634
|
-
|
|
635
|
-
/**
|
|
636
|
-
* @hidden
|
|
637
|
-
*/
|
|
638
|
-
const isWorkDay = (date, start, end) => {
|
|
639
|
-
return date.getDay() >= start && date.getDay() <= end;
|
|
640
|
-
};
|
|
641
|
-
/**
|
|
642
|
-
* @hidden
|
|
643
|
-
*/
|
|
644
|
-
const isWorkHour = (date, start, end) => {
|
|
645
|
-
return date.getHours() >= start && date.getHours() <= end;
|
|
646
|
-
};
|
|
647
|
-
/**
|
|
648
|
-
* @hidden
|
|
649
|
-
*/
|
|
650
|
-
const isPresent = (item) => item !== null && item !== undefined;
|
|
651
|
-
/**
|
|
652
|
-
* @hidden
|
|
653
|
-
*
|
|
654
|
-
* Normalized the data to an array in case a falsy value is passed
|
|
655
|
-
* or a TreeListDataResult object (applicable for the data-binding directives).
|
|
656
|
-
*/
|
|
657
|
-
const normalizeGanttData = (data) => {
|
|
658
|
-
if (!isPresent(data)) {
|
|
659
|
-
return [];
|
|
660
|
-
}
|
|
661
|
-
else if (Array.isArray(data.data)) {
|
|
662
|
-
return data.data;
|
|
663
|
-
}
|
|
664
|
-
else {
|
|
665
|
-
return data;
|
|
666
|
-
}
|
|
667
|
-
};
|
|
668
|
-
/**
|
|
669
|
-
* @hidden
|
|
670
|
-
*
|
|
671
|
-
* Returns a new date with the specified hours, minutes, seconds and millliseconds set.
|
|
672
|
-
* Only the hours are required, the rest of the params are set to `0` by default.
|
|
673
|
-
*/
|
|
674
|
-
const setTime = (date, hours, minutes = 0, seconds = 0, milliseconds = 0) => {
|
|
675
|
-
if (!isPresent(date)) {
|
|
676
|
-
return null;
|
|
677
|
-
}
|
|
678
|
-
const result = cloneDate(date);
|
|
679
|
-
result.setHours(hours);
|
|
680
|
-
result.setMinutes(minutes);
|
|
681
|
-
result.setSeconds(seconds);
|
|
682
|
-
result.setMilliseconds(milliseconds);
|
|
683
|
-
return result;
|
|
684
|
-
};
|
|
685
|
-
/**
|
|
686
|
-
* @hidden
|
|
687
|
-
*
|
|
688
|
-
* Returns the last day of a week.
|
|
689
|
-
* @param standingPoint - Any day of the target week.
|
|
690
|
-
* @param firstWeekDay - The week's starting day (e.g. Monday, Tuesday, etc.)
|
|
691
|
-
*/
|
|
692
|
-
const lastDayOfWeek = (standingPoint, firstWeekDay) => {
|
|
693
|
-
const followingWeek = addWeeks(standingPoint, 1);
|
|
694
|
-
const firstDayOfFollowingWeek = firstDayInWeek(followingWeek, firstWeekDay);
|
|
695
|
-
const lastDayOfTargetWeek = addDays(firstDayOfFollowingWeek, -1);
|
|
696
|
-
return lastDayOfTargetWeek;
|
|
697
|
-
};
|
|
698
|
-
/**
|
|
699
|
-
* Persists the intially resolved scrollbar width value.
|
|
700
|
-
*/
|
|
701
|
-
let SCROLLBAR_WIDTH;
|
|
702
|
-
/**
|
|
703
|
-
* @hidden
|
|
704
|
-
*
|
|
705
|
-
* Gets the default scrollbar width accoring to the current environment.
|
|
706
|
-
*/
|
|
707
|
-
const scrollbarWidth = () => {
|
|
708
|
-
if (!isDocumentAvailable()) {
|
|
709
|
-
return;
|
|
710
|
-
}
|
|
711
|
-
// calculate scrollbar width only once, then return the cached value
|
|
712
|
-
if (isNaN(SCROLLBAR_WIDTH)) {
|
|
713
|
-
const div = document.createElement('div');
|
|
714
|
-
div.style.cssText = 'overflow: scroll; overflow-x: hidden; zoom: 1; clear: both; display: block;';
|
|
715
|
-
div.innerHTML = ' ';
|
|
716
|
-
document.body.appendChild(div);
|
|
717
|
-
SCROLLBAR_WIDTH = div.offsetWidth - div.scrollWidth;
|
|
718
|
-
document.body.removeChild(div);
|
|
719
|
-
}
|
|
720
|
-
return SCROLLBAR_WIDTH;
|
|
721
|
-
};
|
|
722
|
-
/**
|
|
723
|
-
* @hidden
|
|
724
|
-
*/
|
|
725
|
-
const isColumnGroup = (column) => column.isColumnGroup;
|
|
726
|
-
/**
|
|
727
|
-
* @hidden
|
|
728
|
-
*/
|
|
729
|
-
const isNumber = (contender) => typeof contender === 'number' && !isNaN(contender);
|
|
730
|
-
/**
|
|
731
|
-
* @hidden
|
|
732
|
-
*/
|
|
733
|
-
const isString = (contender) => typeof contender === 'string';
|
|
734
|
-
/**
|
|
735
|
-
* @hidden
|
|
736
|
-
*
|
|
737
|
-
* Gets the closest timeline task element index from an event target.
|
|
738
|
-
* Uses the `data-task-index` attribute assigned to each task.
|
|
739
|
-
* Restricts the search up to the provided gantt element from the second param.
|
|
740
|
-
*/
|
|
741
|
-
const getClosestTaskIndex = (element, gantt) => {
|
|
742
|
-
const task = closestInScope(element, matchesClasses('k-task'), gantt);
|
|
743
|
-
if (!isPresent(task)) {
|
|
744
|
-
return null;
|
|
745
|
-
}
|
|
746
|
-
return Number(task.getAttribute('data-task-index'));
|
|
747
|
-
};
|
|
748
|
-
/**
|
|
749
|
-
* @hidden
|
|
750
|
-
*
|
|
751
|
-
* 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.
|
|
753
|
-
*/
|
|
754
|
-
const isTask = (contender, gantt) => {
|
|
755
|
-
const task = closestInScope(contender, matchesClasses('k-task'), gantt);
|
|
756
|
-
return isPresent(task);
|
|
757
|
-
};
|
|
1399
|
+
|
|
758
1400
|
/**
|
|
759
1401
|
* @hidden
|
|
760
|
-
*
|
|
761
|
-
* 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.
|
|
763
1402
|
*/
|
|
764
|
-
|
|
765
|
-
|
|
766
|
-
|
|
767
|
-
}
|
|
1403
|
+
class PreventableEvent {
|
|
1404
|
+
constructor() {
|
|
1405
|
+
this.prevented = false;
|
|
1406
|
+
}
|
|
1407
|
+
/**
|
|
1408
|
+
* Prevents the default action for a specified event.
|
|
1409
|
+
* In this way, the source component suppresses
|
|
1410
|
+
* the built-in behavior that follows the event.
|
|
1411
|
+
*/
|
|
1412
|
+
preventDefault() {
|
|
1413
|
+
this.prevented = true;
|
|
1414
|
+
}
|
|
1415
|
+
/**
|
|
1416
|
+
* Returns `true` if the event was prevented
|
|
1417
|
+
* by any of its subscribers.
|
|
1418
|
+
*
|
|
1419
|
+
* @returns `true` if the default action was prevented.
|
|
1420
|
+
* Otherwise, returns `false`.
|
|
1421
|
+
*/
|
|
1422
|
+
isDefaultPrevented() {
|
|
1423
|
+
return this.prevented;
|
|
1424
|
+
}
|
|
1425
|
+
}
|
|
1426
|
+
|
|
1427
|
+
/**
|
|
1428
|
+
* Called every time a user leaves an edited cell.
|
|
1429
|
+
*/
|
|
1430
|
+
class CellCloseEvent extends PreventableEvent {
|
|
1431
|
+
constructor(options) {
|
|
1432
|
+
super();
|
|
1433
|
+
Object.assign(this, options);
|
|
1434
|
+
}
|
|
1435
|
+
}
|
|
768
1436
|
|
|
769
1437
|
/**
|
|
770
1438
|
* @hidden
|
|
@@ -920,84 +1588,6 @@ class TimelineBaseViewService {
|
|
|
920
1588
|
}
|
|
921
1589
|
}
|
|
922
1590
|
|
|
923
|
-
/**
|
|
924
|
-
* @hidden
|
|
925
|
-
*/
|
|
926
|
-
const DEFAULT_DEPENDENCY_MODEL_FIELDS = Object.freeze({
|
|
927
|
-
toId: 'toId',
|
|
928
|
-
fromId: 'fromId',
|
|
929
|
-
id: 'id',
|
|
930
|
-
type: 'type'
|
|
931
|
-
});
|
|
932
|
-
|
|
933
|
-
/**
|
|
934
|
-
* @hidden
|
|
935
|
-
*/
|
|
936
|
-
const DEFAULT_TASK_MODEL_FIELDS = Object.freeze({
|
|
937
|
-
id: 'id',
|
|
938
|
-
start: 'start',
|
|
939
|
-
end: 'end',
|
|
940
|
-
title: 'title',
|
|
941
|
-
completionRatio: 'completionRatio',
|
|
942
|
-
children: 'children'
|
|
943
|
-
});
|
|
944
|
-
|
|
945
|
-
/**
|
|
946
|
-
* @hidden
|
|
947
|
-
*/
|
|
948
|
-
let MappingService = class MappingService {
|
|
949
|
-
/**
|
|
950
|
-
* @hidden
|
|
951
|
-
*/
|
|
952
|
-
constructor() {
|
|
953
|
-
this._taskFields = Object.assign({}, DEFAULT_TASK_MODEL_FIELDS);
|
|
954
|
-
this._dependencyFields = Object.assign({}, DEFAULT_DEPENDENCY_MODEL_FIELDS);
|
|
955
|
-
}
|
|
956
|
-
/**
|
|
957
|
-
* Gets or sets the model fields for the task data items.
|
|
958
|
-
* Uses the default values for fields which are not specified.
|
|
959
|
-
*/
|
|
960
|
-
set taskFields(fields) {
|
|
961
|
-
this._taskFields = Object.assign({}, DEFAULT_TASK_MODEL_FIELDS, fields);
|
|
962
|
-
}
|
|
963
|
-
get taskFields() {
|
|
964
|
-
return this._taskFields;
|
|
965
|
-
}
|
|
966
|
-
/**
|
|
967
|
-
* Gets or sets the model fields for the depenency data items.
|
|
968
|
-
* Uses the default values for fields which are not specified.
|
|
969
|
-
*/
|
|
970
|
-
set dependencyFields(fields) {
|
|
971
|
-
this._dependencyFields = Object.assign({}, DEFAULT_DEPENDENCY_MODEL_FIELDS, fields);
|
|
972
|
-
}
|
|
973
|
-
get dependencyFields() {
|
|
974
|
-
return this._dependencyFields;
|
|
975
|
-
}
|
|
976
|
-
/**
|
|
977
|
-
* Retrieves the value for the specified task field.
|
|
978
|
-
* Supports nested fields as well (e.g. 'manager.id').
|
|
979
|
-
*/
|
|
980
|
-
extractFromTask(dataItem, field) {
|
|
981
|
-
if (!isPresent(this.taskFields)) {
|
|
982
|
-
return null;
|
|
983
|
-
}
|
|
984
|
-
return getter(this.taskFields[field])(dataItem);
|
|
985
|
-
}
|
|
986
|
-
/**
|
|
987
|
-
* Retrieves the value for the specified dependency field.
|
|
988
|
-
* Supports nested fields as well (e.g. 'manager.id').
|
|
989
|
-
*/
|
|
990
|
-
extractFromDependency(dataItem, field) {
|
|
991
|
-
if (!isPresent(this.dependencyFields)) {
|
|
992
|
-
return null;
|
|
993
|
-
}
|
|
994
|
-
return getter(this.dependencyFields[field])(dataItem);
|
|
995
|
-
}
|
|
996
|
-
};
|
|
997
|
-
MappingService = __decorate([
|
|
998
|
-
Injectable()
|
|
999
|
-
], MappingService);
|
|
1000
|
-
|
|
1001
1591
|
/**
|
|
1002
1592
|
* @hidden
|
|
1003
1593
|
*/
|
|
@@ -1187,171 +1777,567 @@ TimelineViewService = __decorate([
|
|
|
1187
1777
|
/**
|
|
1188
1778
|
* @hidden
|
|
1189
1779
|
*/
|
|
1190
|
-
let
|
|
1191
|
-
constructor(
|
|
1192
|
-
this.
|
|
1193
|
-
this.
|
|
1194
|
-
this.
|
|
1195
|
-
this.
|
|
1196
|
-
this.
|
|
1197
|
-
|
|
1198
|
-
|
|
1780
|
+
let EditService = class EditService {
|
|
1781
|
+
constructor(mapper) {
|
|
1782
|
+
this.mapper = mapper;
|
|
1783
|
+
this.showEditingDialog = new Subject();
|
|
1784
|
+
this.taskDelete = new Subject();
|
|
1785
|
+
this.editEvent = new Subject();
|
|
1786
|
+
this.addEvent = new Subject();
|
|
1787
|
+
this.predecessors = [];
|
|
1788
|
+
this.successors = [];
|
|
1789
|
+
this.updatedItems = [];
|
|
1790
|
+
this.deletedItems = [];
|
|
1791
|
+
this.itemIndex = (item, data) => {
|
|
1792
|
+
return data.findIndex(dataItem => this.mapper.extractFromTask(dataItem, 'id') === this.mapper.extractFromTask(item, 'id'));
|
|
1793
|
+
};
|
|
1199
1794
|
}
|
|
1200
|
-
|
|
1201
|
-
this
|
|
1202
|
-
|
|
1203
|
-
|
|
1204
|
-
|
|
1205
|
-
scrollTop,
|
|
1206
|
-
scrollLeft,
|
|
1207
|
-
sourceType
|
|
1208
|
-
})));
|
|
1209
|
-
const comparisonFn = sourceType === 'timeline' ?
|
|
1210
|
-
(x, y) => (x.scrollTop === y.scrollTop) && (x.scrollLeft === y.scrollLeft) :
|
|
1211
|
-
(x, y) => (x.scrollTop === y.scrollTop);
|
|
1212
|
-
this.subscriptions.add(obs.pipe(distinctUntilChanged(comparisonFn))
|
|
1213
|
-
.subscribe((event) => this.changes.next(event)));
|
|
1214
|
-
});
|
|
1215
|
-
}
|
|
1795
|
+
set dependencies(items) {
|
|
1796
|
+
// Can this whole thing be moved to edit-dialog? Dependencies might not be needed here
|
|
1797
|
+
const dataItemId = this.mapper.extractFromTask(this.dataItem, 'id');
|
|
1798
|
+
this.predecessors = items.filter(item => this.mapper.extractFromDependency(item, 'toId') === dataItemId);
|
|
1799
|
+
this.successors = items.filter(item => this.mapper.extractFromDependency(item, 'fromId') === dataItemId);
|
|
1216
1800
|
}
|
|
1217
|
-
|
|
1218
|
-
this.
|
|
1219
|
-
this.elements = null;
|
|
1801
|
+
get dependencies() {
|
|
1802
|
+
return [...this.predecessors, ...this.successors];
|
|
1220
1803
|
}
|
|
1221
|
-
|
|
1222
|
-
|
|
1223
|
-
|
|
1224
|
-
|
|
1225
|
-
this.
|
|
1804
|
+
createEditDialog(dataItem, taskFormGroup, dependencies) {
|
|
1805
|
+
this.dataItem = dataItem;
|
|
1806
|
+
this.taskFormGroup = taskFormGroup;
|
|
1807
|
+
this.dependencies = dependencies;
|
|
1808
|
+
this.showEditingDialog.next(true);
|
|
1226
1809
|
}
|
|
1227
|
-
|
|
1228
|
-
|
|
1229
|
-
|
|
1810
|
+
closeEditDialog() {
|
|
1811
|
+
this.showEditingDialog.next(false);
|
|
1812
|
+
this.dataItem = undefined;
|
|
1813
|
+
this.taskFormGroup = undefined;
|
|
1814
|
+
this.dependencies = [];
|
|
1815
|
+
this.updatedItems = [];
|
|
1816
|
+
this.deletedItems = [];
|
|
1230
1817
|
}
|
|
1231
|
-
|
|
1232
|
-
this.
|
|
1233
|
-
|
|
1234
|
-
|
|
1235
|
-
|
|
1236
|
-
|
|
1237
|
-
|
|
1238
|
-
|
|
1239
|
-
|
|
1240
|
-
|
|
1241
|
-
|
|
1818
|
+
triggerEditEvent(editResultType) {
|
|
1819
|
+
this.editEvent.next({
|
|
1820
|
+
taskFormGroup: this.taskFormGroup,
|
|
1821
|
+
dataItem: this.dataItem,
|
|
1822
|
+
dependencies: {
|
|
1823
|
+
createdItems: this.getCreatedDependencies(),
|
|
1824
|
+
updatedItems: this.updatedItems,
|
|
1825
|
+
deletedItems: this.deletedItems
|
|
1826
|
+
},
|
|
1827
|
+
editResultType
|
|
1828
|
+
});
|
|
1829
|
+
}
|
|
1830
|
+
updateDependencies(item) {
|
|
1831
|
+
if (!this.isNew(item)) {
|
|
1832
|
+
// update
|
|
1833
|
+
const index = this.itemIndex(item, this.updatedItems);
|
|
1834
|
+
if (index !== -1) {
|
|
1835
|
+
this.updatedItems.splice(index, 1, item);
|
|
1242
1836
|
}
|
|
1243
|
-
|
|
1244
|
-
|
|
1245
|
-
this.syncingTimeline = true;
|
|
1246
|
-
const timeline = this.elements.find(element => element.sourceType === 'timeline').element;
|
|
1247
|
-
timeline.scrollTop = scrollTop;
|
|
1248
|
-
}
|
|
1249
|
-
this.syncingTreeList = false;
|
|
1837
|
+
else {
|
|
1838
|
+
this.updatedItems.push(item);
|
|
1250
1839
|
}
|
|
1251
|
-
}
|
|
1840
|
+
}
|
|
1841
|
+
}
|
|
1842
|
+
getCreatedDependencies() {
|
|
1843
|
+
return this.dependencies.filter(item => this.mapper.extractFromDependency(item, 'id') === null);
|
|
1844
|
+
}
|
|
1845
|
+
deleteDependency(item) {
|
|
1846
|
+
const updatedIndex = this.itemIndex(item, this.updatedItems);
|
|
1847
|
+
if (updatedIndex !== -1) {
|
|
1848
|
+
this.updatedItems.splice(updatedIndex, 1);
|
|
1849
|
+
}
|
|
1850
|
+
if (!this.isNew(item)) {
|
|
1851
|
+
this.deletedItems.push(item);
|
|
1852
|
+
}
|
|
1853
|
+
}
|
|
1854
|
+
loadTasks(initialValues, isInitializer = true) {
|
|
1855
|
+
return forkJoin(initialValues.map(v => this.getElementById(v))).pipe(map((value) => value.reduce((acc, item) => acc = acc.concat(normalizeGanttData(item)), [])), expand(values => {
|
|
1856
|
+
if (values.some(el => this.hasChildren(el))) {
|
|
1857
|
+
return this.loadTasks(values, false);
|
|
1858
|
+
}
|
|
1859
|
+
return EMPTY;
|
|
1860
|
+
}), reduce((acc, values) => acc.concat(values), isInitializer ? [...initialValues] : []));
|
|
1861
|
+
}
|
|
1862
|
+
getElementById(item) {
|
|
1863
|
+
const children = this.fetchChildren(item);
|
|
1864
|
+
if (isObservable(children)) {
|
|
1865
|
+
return children;
|
|
1866
|
+
}
|
|
1867
|
+
return of(children);
|
|
1868
|
+
}
|
|
1869
|
+
isNew(item) {
|
|
1870
|
+
return !isPresent(this.mapper.extractFromDependency(item, 'id'));
|
|
1252
1871
|
}
|
|
1253
1872
|
};
|
|
1254
|
-
|
|
1873
|
+
EditService = __decorate([
|
|
1255
1874
|
Injectable(),
|
|
1256
|
-
__metadata("design:paramtypes", [
|
|
1257
|
-
],
|
|
1875
|
+
__metadata("design:paramtypes", [MappingService])
|
|
1876
|
+
], EditService);
|
|
1877
|
+
|
|
1878
|
+
/**
|
|
1879
|
+
* @hidden
|
|
1880
|
+
*
|
|
1881
|
+
* Notifies the timeline-scroll.directive to scroll into view to requested coordinates.
|
|
1882
|
+
* The scrolling is performed based on client (viewport) coordinates.
|
|
1883
|
+
*/
|
|
1884
|
+
let TimelineScrollService = class TimelineScrollService {
|
|
1885
|
+
/**
|
|
1886
|
+
* @hidden
|
|
1887
|
+
*
|
|
1888
|
+
* Notifies the timeline-scroll.directive to scroll into view to requested coordinates.
|
|
1889
|
+
* The scrolling is performed based on client (viewport) coordinates.
|
|
1890
|
+
*/
|
|
1891
|
+
constructor() {
|
|
1892
|
+
this.horizontalScroll = new Subject();
|
|
1893
|
+
this.verticalScroll = new Subject();
|
|
1894
|
+
this.scrollCancel = new Subject();
|
|
1895
|
+
}
|
|
1896
|
+
ngOnDestroy() {
|
|
1897
|
+
this.horizontalScroll.complete();
|
|
1898
|
+
this.verticalScroll.complete();
|
|
1899
|
+
this.scrollCancel.complete();
|
|
1900
|
+
}
|
|
1901
|
+
requestHorizontalScroll(clientTop) {
|
|
1902
|
+
this.horizontalScroll.next(clientTop);
|
|
1903
|
+
}
|
|
1904
|
+
requestVerticalScroll(clientLeft) {
|
|
1905
|
+
this.verticalScroll.next(clientLeft);
|
|
1906
|
+
}
|
|
1907
|
+
requestScrollCancel() {
|
|
1908
|
+
this.scrollCancel.next();
|
|
1909
|
+
}
|
|
1910
|
+
};
|
|
1911
|
+
TimelineScrollService = __decorate([
|
|
1912
|
+
Injectable()
|
|
1913
|
+
], TimelineScrollService);
|
|
1914
|
+
|
|
1915
|
+
/**
|
|
1916
|
+
* @hidden
|
|
1917
|
+
*
|
|
1918
|
+
* Needed to keep the Gantt's LocalizationService reference and be able to use it component's inside the TabStrip
|
|
1919
|
+
*/
|
|
1920
|
+
let GanttLocalizationService = class GanttLocalizationService {
|
|
1921
|
+
constructor(localizationService) {
|
|
1922
|
+
this.localizationService = localizationService;
|
|
1923
|
+
}
|
|
1924
|
+
get(token) {
|
|
1925
|
+
return this.localizationService.get(token);
|
|
1926
|
+
}
|
|
1927
|
+
};
|
|
1928
|
+
GanttLocalizationService = __decorate([
|
|
1929
|
+
Injectable(),
|
|
1930
|
+
__metadata("design:paramtypes", [LocalizationService])
|
|
1931
|
+
], GanttLocalizationService);
|
|
1932
|
+
|
|
1933
|
+
// TODO: add those keys to `import { Keys } from '@progress/kendo-angular-common';`
|
|
1934
|
+
var NumpadKeys;
|
|
1935
|
+
(function (NumpadKeys) {
|
|
1936
|
+
NumpadKeys[NumpadKeys["Digit1"] = 97] = "Digit1";
|
|
1937
|
+
NumpadKeys[NumpadKeys["Digit2"] = 98] = "Digit2";
|
|
1938
|
+
NumpadKeys[NumpadKeys["Digit3"] = 99] = "Digit3";
|
|
1939
|
+
NumpadKeys[NumpadKeys["Digit4"] = 100] = "Digit4";
|
|
1940
|
+
})(NumpadKeys || (NumpadKeys = {}));
|
|
1941
|
+
/**
|
|
1942
|
+
* @hidden
|
|
1943
|
+
*/
|
|
1944
|
+
const isArrowUpDownKey = (keyCode) => [
|
|
1945
|
+
Keys.ArrowUp,
|
|
1946
|
+
Keys.ArrowDown
|
|
1947
|
+
].some(arrowKeyCode => keyCode === arrowKeyCode);
|
|
1948
|
+
/**
|
|
1949
|
+
* @hidden
|
|
1950
|
+
*/
|
|
1951
|
+
const isNavigationKey = (keyCode) => [
|
|
1952
|
+
Keys.ArrowUp,
|
|
1953
|
+
Keys.ArrowDown,
|
|
1954
|
+
Keys.Home,
|
|
1955
|
+
Keys.End
|
|
1956
|
+
].some(navigationKeyCode => keyCode === navigationKeyCode);
|
|
1957
|
+
/**
|
|
1958
|
+
* @hidden
|
|
1959
|
+
*/
|
|
1960
|
+
const isExpandCollapseKey = (keyCode, altKey) => {
|
|
1961
|
+
return altKey && [
|
|
1962
|
+
Keys.ArrowLeft,
|
|
1963
|
+
Keys.ArrowRight
|
|
1964
|
+
].some(navigationKeyCode => keyCode === navigationKeyCode);
|
|
1965
|
+
};
|
|
1966
|
+
/**
|
|
1967
|
+
* @hidden
|
|
1968
|
+
*/
|
|
1969
|
+
const isViewDigitKey = (keyCode) => [
|
|
1970
|
+
Keys.Digit1,
|
|
1971
|
+
NumpadKeys.Digit1,
|
|
1972
|
+
Keys.Digit2,
|
|
1973
|
+
NumpadKeys.Digit2,
|
|
1974
|
+
Keys.Digit3,
|
|
1975
|
+
NumpadKeys.Digit3,
|
|
1976
|
+
Keys.Digit4,
|
|
1977
|
+
NumpadKeys.Digit4
|
|
1978
|
+
].some(digitKeyCode => keyCode === digitKeyCode);
|
|
1979
|
+
/**
|
|
1980
|
+
* @hidden
|
|
1981
|
+
*
|
|
1982
|
+
* Returns the corresponding view index for the pressed digit key (Digit 1 => 0, Digit 2 => 1, etc.).
|
|
1983
|
+
*/
|
|
1984
|
+
const getIndexFromViewDigitKeyCode = (keyCode) => {
|
|
1985
|
+
switch (keyCode) {
|
|
1986
|
+
case NumpadKeys.Digit1:
|
|
1987
|
+
case Keys.Digit1: return 0;
|
|
1988
|
+
case NumpadKeys.Digit2:
|
|
1989
|
+
case Keys.Digit2: return 1;
|
|
1990
|
+
case NumpadKeys.Digit3:
|
|
1991
|
+
case Keys.Digit3: return 2;
|
|
1992
|
+
case NumpadKeys.Digit4:
|
|
1993
|
+
case Keys.Digit4: return 3;
|
|
1994
|
+
default: return null;
|
|
1995
|
+
}
|
|
1996
|
+
};
|
|
1258
1997
|
|
|
1259
1998
|
/**
|
|
1260
1999
|
* @hidden
|
|
1261
2000
|
*/
|
|
1262
|
-
let
|
|
1263
|
-
constructor(
|
|
1264
|
-
this.
|
|
1265
|
-
this.
|
|
2001
|
+
let NavigationService = class NavigationService {
|
|
2002
|
+
constructor(zone, renderer, scrollSyncService) {
|
|
2003
|
+
this.zone = zone;
|
|
2004
|
+
this.renderer = renderer;
|
|
2005
|
+
this.scrollSyncService = scrollSyncService;
|
|
1266
2006
|
/**
|
|
1267
|
-
*
|
|
1268
|
-
*
|
|
2007
|
+
* Notifies when the tasks' focused and interactive (tabindex) state has changed.
|
|
2008
|
+
*
|
|
2009
|
+
* All tasks are rendered with tabindex="-1".
|
|
2010
|
+
* When one is clicked, or when some navigation key keyboard key is pressed, it should be focused, assigned the focus class, and its tabindex updated to 0.
|
|
2011
|
+
* All other tasks should get -1 tabindex and have the focus class removed from them.
|
|
1269
2012
|
*/
|
|
1270
|
-
this.
|
|
2013
|
+
this.taskStatusChanges = new Subject();
|
|
2014
|
+
/**
|
|
2015
|
+
* Keeps track of whether the Timeline part is focused.
|
|
2016
|
+
* Used when the index of the task elements change (tasks are changed, pushed to, spliced from, etc.)
|
|
2017
|
+
* and their status should be updated accordingly.
|
|
2018
|
+
*/
|
|
2019
|
+
this.isTimelineFocused = false;
|
|
2020
|
+
/**
|
|
2021
|
+
* Keeps track of which part has last been focused.
|
|
2022
|
+
* Used when calling `gantt.focus()` to determine which part of the component should receive focus.
|
|
2023
|
+
*/
|
|
2024
|
+
this.treeListLastActive = false;
|
|
2025
|
+
/**
|
|
2026
|
+
* Keeps track of which part has last been focused.
|
|
2027
|
+
* Used when calling `gantt.focus()` to determine which part of the component should receive focus.
|
|
2028
|
+
*/
|
|
2029
|
+
this.timelineLastActive = false;
|
|
2030
|
+
this._enabled = false;
|
|
2031
|
+
this._activeTimelineIndex = 0;
|
|
2032
|
+
this._activeTreeListCell = { rowIndex: 0, colIndex: 0 };
|
|
1271
2033
|
}
|
|
1272
2034
|
/**
|
|
1273
|
-
*
|
|
1274
|
-
* Fires also on the first change of the table rows and the parent container.
|
|
2035
|
+
* Specifies whether navigation is enabled.
|
|
1275
2036
|
*/
|
|
1276
|
-
get
|
|
1277
|
-
return this.
|
|
2037
|
+
get enabled() {
|
|
2038
|
+
return this._enabled;
|
|
1278
2039
|
}
|
|
1279
|
-
|
|
2040
|
+
/**
|
|
2041
|
+
* Used to retrieve read-only data about the currently active task.
|
|
2042
|
+
*/
|
|
2043
|
+
get activeTask() {
|
|
1280
2044
|
return {
|
|
1281
|
-
|
|
1282
|
-
|
|
1283
|
-
timelineRow: this.timelineRow
|
|
2045
|
+
activeIndex: this.activeTimelineIndex,
|
|
2046
|
+
isFocused: this.isTimelineFocused
|
|
1284
2047
|
};
|
|
1285
2048
|
}
|
|
2049
|
+
/**
|
|
2050
|
+
* Persists the expected TreeList focused cell coords.
|
|
2051
|
+
* When the tasks in the Timeline are navigated through, the expected TreeList focus target should also change,
|
|
2052
|
+
* in order to allow back-tabbing from the Timeline to the same row in the TreeList.
|
|
2053
|
+
*/
|
|
2054
|
+
set activeTreeListCell(cell) {
|
|
2055
|
+
this._activeTreeListCell = cell;
|
|
2056
|
+
}
|
|
2057
|
+
get activeTreeListCell() {
|
|
2058
|
+
const firstAvailableIndex = 0;
|
|
2059
|
+
const lastAvailableRowIndex = this.treeListHeaderRowsCount + this.gantt.treeList.view.data.length - 1;
|
|
2060
|
+
const rowIndex = fitToRange(this._activeTreeListCell.rowIndex, firstAvailableIndex, lastAvailableRowIndex);
|
|
2061
|
+
const lastAvailableColIndex = this.gantt.columns.length;
|
|
2062
|
+
const colIndex = fitToRange(this._activeTreeListCell.colIndex, firstAvailableIndex, lastAvailableColIndex);
|
|
2063
|
+
return { rowIndex, colIndex };
|
|
2064
|
+
}
|
|
2065
|
+
/**
|
|
2066
|
+
* Persists the expected Timeline focused task index.
|
|
2067
|
+
* When the cells in the TreeList are navigated through, the expected Timeline focus target should also change,
|
|
2068
|
+
* in order to allow tabbing from the TreeList to the same row in the Timeline.
|
|
2069
|
+
*/
|
|
2070
|
+
set activeTimelineIndex(index) {
|
|
2071
|
+
this._activeTimelineIndex = index;
|
|
2072
|
+
}
|
|
2073
|
+
get activeTimelineIndex() {
|
|
2074
|
+
const firstAvailableIndex = 0;
|
|
2075
|
+
const lastAvailableIndex = this.gantt.treeList.view.data.length - 1;
|
|
2076
|
+
return fitToRange(this._activeTimelineIndex, firstAvailableIndex, lastAvailableIndex);
|
|
2077
|
+
}
|
|
2078
|
+
/**
|
|
2079
|
+
* The TreeList row index takes into account the header and filter rows.
|
|
2080
|
+
* Used when translating Timeline task indices to TreeList row indices.
|
|
2081
|
+
*/
|
|
2082
|
+
get treeListHeaderRowsCount() {
|
|
2083
|
+
// captures nested group header rows + filter row if we start supporting it at some point
|
|
2084
|
+
return this.treeListElement.querySelectorAll('.k-grid-header tr').length;
|
|
2085
|
+
}
|
|
2086
|
+
initialize({ gantt, host, treeListElement, timelineElement }) {
|
|
2087
|
+
// no private property setters in TypeScript, so use a getter and a poorly named private prop for this value
|
|
2088
|
+
this._enabled = true;
|
|
2089
|
+
this.gantt = gantt;
|
|
2090
|
+
this.host = host;
|
|
2091
|
+
this.treeListElement = treeListElement;
|
|
2092
|
+
this.timelineElement = timelineElement;
|
|
2093
|
+
// TODO: fix in the splitter package and remove
|
|
2094
|
+
// move the splitbar HTML element between the two panes to keep the visial tabbing order in tact
|
|
2095
|
+
const splitbar = this.host.querySelector('.k-splitbar');
|
|
2096
|
+
if (isPresent(splitbar) && isPresent(splitbar.previousElementSibling) && isPresent(splitbar.after)) {
|
|
2097
|
+
splitbar.after(splitbar.previousElementSibling);
|
|
2098
|
+
}
|
|
2099
|
+
this.zone.runOutsideAngular(() => {
|
|
2100
|
+
this.eventListenerDisposers = [
|
|
2101
|
+
this.renderer.listen(this.host, 'keydown', this.handleKeydown.bind(this)),
|
|
2102
|
+
this.renderer.listen(this.treeListElement, 'mousedown', this.focusTreeList.bind(this)),
|
|
2103
|
+
this.renderer.listen(this.treeListElement, 'focusin', this.handleTreeListFocusIn.bind(this)),
|
|
2104
|
+
this.renderer.listen(this.timelineElement, 'mousedown', this.handleTimelineMousedown.bind(this)),
|
|
2105
|
+
this.renderer.listen(this.timelineElement, 'focusin', this.handleTimelineFocusIn.bind(this)),
|
|
2106
|
+
this.renderer.listen(this.timelineElement, 'focusout', this.handleTimelineFocusOut.bind(this))
|
|
2107
|
+
];
|
|
2108
|
+
});
|
|
2109
|
+
}
|
|
1286
2110
|
ngOnDestroy() {
|
|
1287
|
-
this.
|
|
1288
|
-
|
|
1289
|
-
|
|
2111
|
+
if (isPresent(this.eventListenerDisposers)) {
|
|
2112
|
+
this.eventListenerDisposers.forEach(removeListener => removeListener());
|
|
2113
|
+
this.eventListenerDisposers = null;
|
|
2114
|
+
}
|
|
2115
|
+
this.gantt = null;
|
|
2116
|
+
this.host = null;
|
|
2117
|
+
this.treeListElement = null;
|
|
2118
|
+
this.timelineElement = null;
|
|
1290
2119
|
}
|
|
1291
|
-
|
|
1292
|
-
|
|
1293
|
-
|
|
2120
|
+
/**
|
|
2121
|
+
* Focuses either the last active TreeList cell, or the last active Timeline task,
|
|
2122
|
+
* dependening on which of the two last held focus.
|
|
2123
|
+
*
|
|
2124
|
+
* Focuses the first TreeList cell by default.
|
|
2125
|
+
*/
|
|
2126
|
+
focusLastActiveItem() {
|
|
2127
|
+
if (this.gantt.data.length === 0 || (!this.treeListLastActive && !this.timelineLastActive)) {
|
|
2128
|
+
this.focusCell(0, 0);
|
|
2129
|
+
}
|
|
2130
|
+
else if (this.treeListLastActive) {
|
|
2131
|
+
const { rowIndex, colIndex } = this.activeTreeListCell;
|
|
2132
|
+
this.gantt.treeList.focusCell(rowIndex, colIndex);
|
|
2133
|
+
}
|
|
2134
|
+
else if (this.timelineLastActive) {
|
|
2135
|
+
this.focusTask(this.activeTimelineIndex);
|
|
2136
|
+
}
|
|
1294
2137
|
}
|
|
1295
|
-
|
|
1296
|
-
|
|
1297
|
-
|
|
2138
|
+
/**
|
|
2139
|
+
* Focuses the targeted TreeList cell regardless of the last peresisted target.
|
|
2140
|
+
*/
|
|
2141
|
+
focusCell(rowIndex, colIndex) {
|
|
2142
|
+
this.activeTreeListCell = { rowIndex, colIndex };
|
|
2143
|
+
this.activeTimelineIndex = rowIndex - this.treeListHeaderRowsCount;
|
|
2144
|
+
this.gantt.treeList.focusCell(this.activeTreeListCell.rowIndex, this.activeTreeListCell.colIndex);
|
|
1298
2145
|
}
|
|
1299
|
-
|
|
1300
|
-
|
|
1301
|
-
|
|
1302
|
-
|
|
2146
|
+
/**
|
|
2147
|
+
* Focuses the targeted Timeline task regardless of the last peresisted target.
|
|
2148
|
+
*/
|
|
2149
|
+
focusTask(index) {
|
|
2150
|
+
this.activeTimelineIndex = index;
|
|
2151
|
+
this.isTimelineFocused = true;
|
|
2152
|
+
this.activeTreeListCell = {
|
|
2153
|
+
rowIndex: index + this.treeListHeaderRowsCount,
|
|
2154
|
+
colIndex: this.activeTreeListCell.colIndex
|
|
2155
|
+
};
|
|
2156
|
+
this.notifyTaskStatusChange();
|
|
1303
2157
|
}
|
|
1304
|
-
|
|
1305
|
-
|
|
1306
|
-
|
|
1307
|
-
|
|
2158
|
+
/**
|
|
2159
|
+
* Updates the focus target flags and notifies the active task to update its focused state.
|
|
2160
|
+
*/
|
|
2161
|
+
handleTimelineFocusIn({ target }) {
|
|
2162
|
+
this.treeListLastActive = false;
|
|
2163
|
+
this.timelineLastActive = true;
|
|
2164
|
+
this.isTimelineFocused = true;
|
|
2165
|
+
if (isTask(target, this.timelineElement)) {
|
|
2166
|
+
this.notifyTaskStatusChange();
|
|
2167
|
+
}
|
|
1308
2168
|
}
|
|
1309
2169
|
/**
|
|
1310
|
-
*
|
|
2170
|
+
* Updates the timeline focus state flag and notifies the active task to update its focused state.
|
|
1311
2171
|
*/
|
|
1312
|
-
|
|
1313
|
-
this.
|
|
2172
|
+
handleTimelineFocusOut({ relatedTarget }) {
|
|
2173
|
+
this.isTimelineFocused = this.timelineElement.contains(relatedTarget);
|
|
2174
|
+
// update the task element only if the new focus target is not in the Timeline - focus change between tasks is handled in the focusin handler
|
|
2175
|
+
if (!isTask(relatedTarget, this.timelineElement)) {
|
|
2176
|
+
this.notifyTaskStatusChange();
|
|
2177
|
+
}
|
|
1314
2178
|
}
|
|
1315
|
-
};
|
|
1316
|
-
DependencyDomService = __decorate([
|
|
1317
|
-
Injectable(),
|
|
1318
|
-
__metadata("design:paramtypes", [MappingService])
|
|
1319
|
-
], DependencyDomService);
|
|
1320
|
-
|
|
1321
|
-
/**
|
|
1322
|
-
* @hidden
|
|
1323
|
-
*/
|
|
1324
|
-
let EditService = class EditService {
|
|
1325
2179
|
/**
|
|
1326
|
-
*
|
|
2180
|
+
* Updates the focus target flags and corrects the TreeList focus target if needed.
|
|
2181
|
+
* As the TreeList will keep its last focused cell with tabindex="0",
|
|
2182
|
+
* this methods forcefully focuses the correct cell,
|
|
2183
|
+
* when navigating in the Timeline has updated the expected TreeList focus target.
|
|
1327
2184
|
*/
|
|
1328
|
-
|
|
1329
|
-
this.
|
|
1330
|
-
this.
|
|
1331
|
-
|
|
1332
|
-
this.
|
|
2185
|
+
handleTreeListFocusIn(event) {
|
|
2186
|
+
this.treeListLastActive = true;
|
|
2187
|
+
this.timelineLastActive = false;
|
|
2188
|
+
// if the previous focus target was in the TreeList, rely on its component navigation and just record the focused item index
|
|
2189
|
+
if (this.treeListElement.contains(event.relatedTarget)) {
|
|
2190
|
+
const { colIndex, rowIndex } = this.gantt.treeList.activeCell;
|
|
2191
|
+
this.activeTreeListCell = { colIndex, rowIndex };
|
|
2192
|
+
}
|
|
2193
|
+
else {
|
|
2194
|
+
// if the previous focus target was outside the TreeList, ensure the expected focus coords are used
|
|
2195
|
+
const { rowIndex, colIndex } = this.activeTreeListCell;
|
|
2196
|
+
this.gantt.treeList.focusCell(rowIndex, colIndex); // activates the target cell even if it has tabindex="-1"
|
|
2197
|
+
}
|
|
2198
|
+
this.activeTimelineIndex = this.gantt.treeList.activeCell.dataRowIndex;
|
|
2199
|
+
this.notifyTaskStatusChange();
|
|
2200
|
+
if (this.gantt.treeList.activeCell.dataRowIndex >= 0) {
|
|
2201
|
+
this.scrollHorizontallyToTask(this.activeTimelineIndex);
|
|
2202
|
+
this.scrollSyncService.syncScrollTop('treelist', 'timeline');
|
|
2203
|
+
}
|
|
1333
2204
|
}
|
|
1334
|
-
|
|
1335
|
-
|
|
1336
|
-
|
|
1337
|
-
|
|
2205
|
+
handleKeydown(event) {
|
|
2206
|
+
const { keyCode, target, altKey } = event;
|
|
2207
|
+
const isTimelineActive = this.timelineElement.contains(target);
|
|
2208
|
+
if (isTimelineActive) {
|
|
2209
|
+
if (isArrowUpDownKey(keyCode)) {
|
|
2210
|
+
const direction = keyCode === Keys.ArrowUp ? -1 : 1;
|
|
2211
|
+
this.activeTimelineIndex = this.activeTimelineIndex + direction;
|
|
2212
|
+
this.activeTreeListCell = {
|
|
2213
|
+
rowIndex: this.activeTimelineIndex + this.treeListHeaderRowsCount,
|
|
2214
|
+
colIndex: this.activeTreeListCell.colIndex
|
|
2215
|
+
};
|
|
2216
|
+
}
|
|
2217
|
+
else if (keyCode === Keys.Home) {
|
|
2218
|
+
this.activeTimelineIndex = 0;
|
|
2219
|
+
this.activeTreeListCell = {
|
|
2220
|
+
rowIndex: this.activeTimelineIndex + this.treeListHeaderRowsCount,
|
|
2221
|
+
colIndex: this.activeTreeListCell.colIndex
|
|
2222
|
+
};
|
|
2223
|
+
}
|
|
2224
|
+
else if (keyCode === Keys.End) {
|
|
2225
|
+
const lastAvailableIndex = this.gantt.treeList.view.data.length - 1;
|
|
2226
|
+
this.activeTimelineIndex = lastAvailableIndex;
|
|
2227
|
+
this.activeTreeListCell = {
|
|
2228
|
+
rowIndex: this.activeTimelineIndex + this.treeListHeaderRowsCount,
|
|
2229
|
+
colIndex: this.activeTreeListCell.colIndex
|
|
2230
|
+
};
|
|
2231
|
+
}
|
|
2232
|
+
if (isNavigationKey(keyCode)) {
|
|
2233
|
+
this.scrollHorizontallyToTask(this.activeTimelineIndex);
|
|
2234
|
+
this.scrollSyncService.syncScrollTop('timeline', 'treelist');
|
|
2235
|
+
this.notifyTaskStatusChange();
|
|
2236
|
+
event.preventDefault();
|
|
2237
|
+
}
|
|
2238
|
+
if (keyCode === Keys.Space && hasObservers(this.gantt.selectionChange)) {
|
|
2239
|
+
const task = this.gantt.renderedTreeListItems[this.activeTimelineIndex];
|
|
2240
|
+
const selectionAction = this.gantt.getSelectionAction(event, task);
|
|
2241
|
+
if (isPresent(task) && !this.gantt.isSameSelection(selectionAction, task)) {
|
|
2242
|
+
this.zone.run(() => this.gantt.notifySelectionChange(task, selectionAction));
|
|
2243
|
+
}
|
|
2244
|
+
event.preventDefault();
|
|
2245
|
+
}
|
|
2246
|
+
if (keyCode === Keys.Enter && hasObservers(this.gantt.taskClick)) {
|
|
2247
|
+
const task = this.gantt.renderedTreeListItems[this.activeTimelineIndex];
|
|
2248
|
+
if (isPresent(task)) {
|
|
2249
|
+
this.zone.run(() => this.gantt.notifyTaskClick(event, task, this.activeTimelineIndex));
|
|
2250
|
+
}
|
|
2251
|
+
event.preventDefault();
|
|
2252
|
+
}
|
|
2253
|
+
if (isExpandCollapseKey(keyCode, altKey)) {
|
|
2254
|
+
const task = this.gantt.renderedTreeListItems[this.activeTimelineIndex];
|
|
2255
|
+
if (isPresent(task) && this.gantt.hasChildren(task)) {
|
|
2256
|
+
const shouldExpand = keyCode === Keys.ArrowRight;
|
|
2257
|
+
const isExpanded = this.gantt.isExpanded(task);
|
|
2258
|
+
const sameState = shouldExpand === isExpanded;
|
|
2259
|
+
if (!sameState) {
|
|
2260
|
+
this.zone.run(() => {
|
|
2261
|
+
const expandEvent = { dataItem: task };
|
|
2262
|
+
// order is not arbitrary
|
|
2263
|
+
// the TreeList emits the individual events first, then the combined `expandStateChange` event
|
|
2264
|
+
const individualEmitter = shouldExpand ? this.gantt.rowExpand : this.gantt.rowCollapse;
|
|
2265
|
+
individualEmitter.emit(expandEvent);
|
|
2266
|
+
this.gantt.expandStateChange.emit(Object.assign({}, expandEvent, { expand: shouldExpand }));
|
|
2267
|
+
this.gantt.updateView();
|
|
2268
|
+
this.scrollHorizontallyToTask(this.activeTimelineIndex);
|
|
2269
|
+
});
|
|
2270
|
+
}
|
|
2271
|
+
}
|
|
2272
|
+
event.preventDefault();
|
|
2273
|
+
}
|
|
2274
|
+
}
|
|
2275
|
+
const isTreeListActive = this.treeListElement.contains(target);
|
|
2276
|
+
if (keyCode === Keys.Delete && (isTimelineActive || isTreeListActive) && hasObservers(this.gantt.taskDelete)) {
|
|
2277
|
+
const taskIndex = isTreeListActive ?
|
|
2278
|
+
this.gantt.treeList.activeCell.dataRowIndex :
|
|
2279
|
+
this.activeTimelineIndex;
|
|
2280
|
+
const task = this.gantt.renderedTreeListItems[taskIndex];
|
|
2281
|
+
if (isPresent(task)) {
|
|
2282
|
+
this.zone.run(() => this.gantt.notifyTaskDelete(task));
|
|
2283
|
+
}
|
|
2284
|
+
}
|
|
2285
|
+
if (isViewDigitKey(keyCode) && !isToolbar(target, this.host) && !this.gantt.isInEditMode) {
|
|
2286
|
+
const targetViewIndex = getIndexFromViewDigitKeyCode(keyCode);
|
|
2287
|
+
const availableViews = this.gantt.views.toArray();
|
|
2288
|
+
const targetView = availableViews[targetViewIndex];
|
|
2289
|
+
if (isPresent(targetView) && targetView.type !== this.gantt.activeView) {
|
|
2290
|
+
this.zone.run(() => this.gantt.changeActiveView(targetView.type));
|
|
2291
|
+
}
|
|
2292
|
+
}
|
|
1338
2293
|
}
|
|
1339
|
-
|
|
1340
|
-
|
|
1341
|
-
|
|
1342
|
-
|
|
2294
|
+
/**
|
|
2295
|
+
* Filters for task mousedown in the Timeline.
|
|
2296
|
+
*/
|
|
2297
|
+
handleTimelineMousedown({ target }) {
|
|
2298
|
+
if (isTask(target, this.host) && !isClearButton(target, this.host)) {
|
|
2299
|
+
const taskIndex = getClosestTaskIndex(target, this.host);
|
|
2300
|
+
this.focusTask(taskIndex);
|
|
2301
|
+
}
|
|
1343
2302
|
}
|
|
1344
|
-
|
|
1345
|
-
|
|
1346
|
-
|
|
1347
|
-
|
|
1348
|
-
|
|
1349
|
-
|
|
2303
|
+
/**
|
|
2304
|
+
* Scrolls horizontally to the beginning of the target task if the beginning of its content is not in the viewport.
|
|
2305
|
+
*/
|
|
2306
|
+
scrollHorizontallyToTask(index) {
|
|
2307
|
+
const task = this.timelineElement.querySelectorAll('.k-task-wrap').item(index);
|
|
2308
|
+
if (!isPresent(task)) {
|
|
2309
|
+
return;
|
|
2310
|
+
}
|
|
2311
|
+
// scroll horizontally to the item if less than 200px from the beginning of its content are visible
|
|
2312
|
+
const targetVisibleWidth = 200;
|
|
2313
|
+
const isScrollBeforeTask = (this.timelineElement.clientWidth + this.timelineElement.scrollLeft) < (task.offsetLeft + targetVisibleWidth);
|
|
2314
|
+
const isScrollAfterTask = this.timelineElement.scrollLeft > task.offsetLeft;
|
|
2315
|
+
if (isScrollBeforeTask || isScrollAfterTask) {
|
|
2316
|
+
this.timelineElement.scrollLeft = task.offsetLeft;
|
|
2317
|
+
}
|
|
2318
|
+
}
|
|
2319
|
+
/**
|
|
2320
|
+
* Focus the TreeList on TreeList mousedown.
|
|
2321
|
+
* A nasty hack to trick `handleTreeListFocusIn` into regarding the previous focus target as again the TreeList.
|
|
2322
|
+
* Otherwise cell clicks are wrongly overwritten in `handleTreeListFocusIn` and the click focus target is not respected.
|
|
2323
|
+
*/
|
|
2324
|
+
focusTreeList() {
|
|
2325
|
+
this.gantt.treeList.focus();
|
|
2326
|
+
}
|
|
2327
|
+
/**
|
|
2328
|
+
* Fires the `taskStatusChanges` event with active and focused status retrieved from
|
|
2329
|
+
* `this.activeTimelineIndex` and `this.isTimelineFocused`.
|
|
2330
|
+
*/
|
|
2331
|
+
notifyTaskStatusChange() {
|
|
2332
|
+
this.taskStatusChanges.next(this.activeTask);
|
|
1350
2333
|
}
|
|
1351
2334
|
};
|
|
1352
|
-
|
|
1353
|
-
Injectable()
|
|
1354
|
-
|
|
2335
|
+
NavigationService = __decorate([
|
|
2336
|
+
Injectable(),
|
|
2337
|
+
__metadata("design:paramtypes", [NgZone,
|
|
2338
|
+
Renderer2,
|
|
2339
|
+
ScrollSyncService])
|
|
2340
|
+
], NavigationService);
|
|
1355
2341
|
|
|
1356
2342
|
/**
|
|
1357
2343
|
* @hidden
|
|
@@ -1655,6 +2641,12 @@ const mapPath = (item) => ({
|
|
|
1655
2641
|
var GanttComponent_1;
|
|
1656
2642
|
const TREELIST_GROUP_COLUMNS_CLASS = 'k-gantt-treelist-nested-columns';
|
|
1657
2643
|
const DEFAULT_VIEW = 'week';
|
|
2644
|
+
const DEFAULT_DRAG_SCROLL_SETTINGS = {
|
|
2645
|
+
enabled: true,
|
|
2646
|
+
step: 3,
|
|
2647
|
+
interval: 1,
|
|
2648
|
+
threshold: 10
|
|
2649
|
+
};
|
|
1658
2650
|
/**
|
|
1659
2651
|
* Represents the Kendo UI Gantt component for Angular.
|
|
1660
2652
|
*
|
|
@@ -1727,7 +2719,7 @@ const DEFAULT_VIEW = 'week';
|
|
|
1727
2719
|
* ```
|
|
1728
2720
|
*/
|
|
1729
2721
|
let GanttComponent = GanttComponent_1 = class GanttComponent {
|
|
1730
|
-
constructor(timelineViewService, scrollSyncService, renderer, mapper, optionChangesService, dependencyDomService, editService, localizationService, hostElement, zone) {
|
|
2722
|
+
constructor(timelineViewService, scrollSyncService, renderer, mapper, optionChangesService, dependencyDomService, editService, localizationService, hostElement, zone, navigationService) {
|
|
1731
2723
|
this.timelineViewService = timelineViewService;
|
|
1732
2724
|
this.scrollSyncService = scrollSyncService;
|
|
1733
2725
|
this.renderer = renderer;
|
|
@@ -1738,13 +2730,33 @@ let GanttComponent = GanttComponent_1 = class GanttComponent {
|
|
|
1738
2730
|
this.localizationService = localizationService;
|
|
1739
2731
|
this.hostElement = hostElement;
|
|
1740
2732
|
this.zone = zone;
|
|
2733
|
+
this.navigationService = navigationService;
|
|
2734
|
+
/**
|
|
2735
|
+
* @hidden
|
|
2736
|
+
*/
|
|
2737
|
+
this.roleDescription = 'Gantt Chart';
|
|
2738
|
+
/**
|
|
2739
|
+
* @hidden
|
|
2740
|
+
*/
|
|
2741
|
+
this.role = 'application';
|
|
1741
2742
|
this.hostClasses = true;
|
|
1742
2743
|
/**
|
|
1743
|
-
*
|
|
2744
|
+
* Specifies a callback that determines if the given task is selected ([see example]({% slug selection_gantt %}#toc-custom-selection)).
|
|
1744
2745
|
*
|
|
1745
2746
|
* > The [`selectable`]({% slug api_gantt_ganttcomponent %}#toc-selectable) prop has to be set to `true` in order for this callback to be executed.
|
|
1746
2747
|
*/
|
|
1747
2748
|
this.isSelected = isSelected;
|
|
2749
|
+
/**
|
|
2750
|
+
* Specifies a callback that determines if a new dependency is valid.
|
|
2751
|
+
* Used when evaluating if an attempt to create a new dependency will result in a valid link between the two tasks
|
|
2752
|
+
* [see example]({% slug editing_drag_create_dependencies_gantt %}#toc-validation).
|
|
2753
|
+
*
|
|
2754
|
+
* By defalut, dependencies are deemed invalid when:
|
|
2755
|
+
* - The two tasks are in a parent-child relationship.
|
|
2756
|
+
* - The two tasks are already dependent on one another. Only one dependency is allowed per pair.
|
|
2757
|
+
* - The start or end times of the two tasks are incompatible with the attempted dependency type.
|
|
2758
|
+
*/
|
|
2759
|
+
this.validateNewDependency = this.defaultValidateNewDependencyCallback.bind(this);
|
|
1748
2760
|
/**
|
|
1749
2761
|
* Fires when the Gantt selection is changed through user interaction.
|
|
1750
2762
|
*
|
|
@@ -1760,14 +2772,6 @@ let GanttComponent = GanttComponent_1 = class GanttComponent {
|
|
|
1760
2772
|
* > When applied, the [`SelectableDirective`]({% slug api_gantt_selectabledirective %}) sets `selectable` to `true` internally.
|
|
1761
2773
|
*/
|
|
1762
2774
|
this.selectable = false;
|
|
1763
|
-
/**
|
|
1764
|
-
* Gets or sets the callback function that retrieves the child items for a particular item.
|
|
1765
|
-
*/
|
|
1766
|
-
this.fetchChildren = fetchChildren;
|
|
1767
|
-
/**
|
|
1768
|
-
* Gets or sets the callback function that indicates if a particular item has child items.
|
|
1769
|
-
*/
|
|
1770
|
-
this.hasChildren = hasChildren;
|
|
1771
2775
|
/**
|
|
1772
2776
|
* Defines the dependencies that will be drawn between the rendered tasks.
|
|
1773
2777
|
*
|
|
@@ -1806,6 +2810,12 @@ let GanttComponent = GanttComponent_1 = class GanttComponent {
|
|
|
1806
2810
|
* The end of the work week (index based).
|
|
1807
2811
|
*/
|
|
1808
2812
|
this.workWeekEnd = 5;
|
|
2813
|
+
/**
|
|
2814
|
+
* If set to `true`, the user can use dedicated shortcuts to interact with the Gantt.
|
|
2815
|
+
* By default, navigation is disabled for the TreeList and Timeline parts of the component,
|
|
2816
|
+
* ([see example]({% slug keyboard_navigation_gantt %})).
|
|
2817
|
+
*/
|
|
2818
|
+
this.navigable = false;
|
|
1809
2819
|
/**
|
|
1810
2820
|
* Indicates whether the Gantt columns will be resized during initialization so that they fit their headers and row content.
|
|
1811
2821
|
* Columns with autoSize set to false are excluded.
|
|
@@ -1849,7 +2859,8 @@ let GanttComponent = GanttComponent_1 = class GanttComponent {
|
|
|
1849
2859
|
*/
|
|
1850
2860
|
this.cellClose = new EventEmitter();
|
|
1851
2861
|
/**
|
|
1852
|
-
* Fires when the end user clicks the `Delete` button in the task editing dialog
|
|
2862
|
+
* Fires when the end user clicks the `Delete` button in the task editing dialog,
|
|
2863
|
+
* the task delete icon, or presses the `Delete` key on the keyboard when a task in the timeline is focused.
|
|
1853
2864
|
* Use the event handler to open a confirmation dialog when necessary.
|
|
1854
2865
|
*/
|
|
1855
2866
|
this.taskDelete = new EventEmitter();
|
|
@@ -1873,6 +2884,11 @@ let GanttComponent = GanttComponent_1 = class GanttComponent {
|
|
|
1873
2884
|
* Fires when the user adds a task.
|
|
1874
2885
|
*/
|
|
1875
2886
|
this.taskAdd = new EventEmitter();
|
|
2887
|
+
/**
|
|
2888
|
+
* Fires when the user adds a dependency via dragging
|
|
2889
|
+
* [see example]({% slug editing_drag_create_dependencies_gantt %}#toc-basic-concepts).
|
|
2890
|
+
*/
|
|
2891
|
+
this.dependencyAdd = new EventEmitter();
|
|
1876
2892
|
/**
|
|
1877
2893
|
* Fires when the sorting of the Gantt is changed.
|
|
1878
2894
|
* You have to handle the event yourself and sort the data.
|
|
@@ -1929,6 +2945,15 @@ let GanttComponent = GanttComponent_1 = class GanttComponent {
|
|
|
1929
2945
|
* Fires when a task is clicked.
|
|
1930
2946
|
*/
|
|
1931
2947
|
this.taskClick = new EventEmitter();
|
|
2948
|
+
/**
|
|
2949
|
+
* @hidden
|
|
2950
|
+
*
|
|
2951
|
+
* Specifies whether the dependency drag clues will be rendered.
|
|
2952
|
+
* Set internally by the dependency-drag-create directive.
|
|
2953
|
+
*
|
|
2954
|
+
* @default false
|
|
2955
|
+
*/
|
|
2956
|
+
this.renderDependencyDragClues = false;
|
|
1932
2957
|
/**
|
|
1933
2958
|
* @hidden
|
|
1934
2959
|
*
|
|
@@ -1945,6 +2970,7 @@ let GanttComponent = GanttComponent_1 = class GanttComponent {
|
|
|
1945
2970
|
this.showConfirmationDialog = false;
|
|
1946
2971
|
this._columns = new QueryList();
|
|
1947
2972
|
this._data = [];
|
|
2973
|
+
this._dragScrollSettings = Object.assign({}, DEFAULT_DRAG_SCROLL_SETTINGS);
|
|
1948
2974
|
this._timelinePaneOptions = Object.assign({}, DEFAULT_TIMELINE_PANE_SETTINGS);
|
|
1949
2975
|
this._treeListPaneOptions = Object.assign({}, DEFAULT_TREELIST_PANE_SETTINGS);
|
|
1950
2976
|
this._rowClass = rowClassCallback;
|
|
@@ -1955,6 +2981,8 @@ let GanttComponent = GanttComponent_1 = class GanttComponent {
|
|
|
1955
2981
|
addTaskTool: 'none',
|
|
1956
2982
|
viewSelectorTool: 'top'
|
|
1957
2983
|
};
|
|
2984
|
+
this._fetchChildren = fetchChildren;
|
|
2985
|
+
this._hasChildren = hasChildren;
|
|
1958
2986
|
this.rtl = false;
|
|
1959
2987
|
this.optionChangesSubscriptions = new Subscription();
|
|
1960
2988
|
this.editServiceSubscription = new Subscription();
|
|
@@ -1967,16 +2995,24 @@ let GanttComponent = GanttComponent_1 = class GanttComponent {
|
|
|
1967
2995
|
}));
|
|
1968
2996
|
this.editService.getSelectedItem = this.getFirstSelectedItem.bind(this);
|
|
1969
2997
|
this.editServiceSubscription.add(this.editService.showEditingDialog.subscribe(show => this.showEditingDialog = show));
|
|
1970
|
-
this.editServiceSubscription.add(this.editService.
|
|
2998
|
+
this.editServiceSubscription.add(this.editService.taskDelete.subscribe(task => {
|
|
2999
|
+
if (hasObservers(this.taskDelete)) {
|
|
3000
|
+
this.zone.run(() => this.notifyTaskDelete(task));
|
|
3001
|
+
}
|
|
3002
|
+
}));
|
|
1971
3003
|
this.editServiceSubscription.add(this.editService.editEvent.subscribe(args => {
|
|
1972
3004
|
this[args.editResultType].emit({
|
|
1973
|
-
|
|
3005
|
+
taskFormGroup: args.taskFormGroup,
|
|
1974
3006
|
item: getEditItem(args.dataItem, this.treeList.view.data, this.mapper),
|
|
3007
|
+
dependencies: args.dependencies,
|
|
1975
3008
|
sender: this
|
|
1976
3009
|
});
|
|
1977
3010
|
this.showConfirmationDialog = this.showEditingDialog = false;
|
|
1978
|
-
this.editService.dataItem = this.editService.
|
|
3011
|
+
this.editService.dataItem = this.editService.taskFormGroup = null;
|
|
1979
3012
|
this.updateView();
|
|
3013
|
+
if (this.navigable) {
|
|
3014
|
+
this.focus();
|
|
3015
|
+
}
|
|
1980
3016
|
}));
|
|
1981
3017
|
this.editServiceSubscription.add(this.editService.addEvent.subscribe(args => {
|
|
1982
3018
|
const selectedItem = this.getFirstSelectedItem();
|
|
@@ -2000,6 +3036,12 @@ let GanttComponent = GanttComponent_1 = class GanttComponent {
|
|
|
2000
3036
|
set toolbarTemplate(customToolbarTemplate) {
|
|
2001
3037
|
this._customToolbarTemplate = customToolbarTemplate;
|
|
2002
3038
|
}
|
|
3039
|
+
get hostRoleDescriptionAttr() {
|
|
3040
|
+
return this.roleDescription;
|
|
3041
|
+
}
|
|
3042
|
+
get hostRoleAttr() {
|
|
3043
|
+
return this.role;
|
|
3044
|
+
}
|
|
2003
3045
|
get dir() {
|
|
2004
3046
|
return this.direction;
|
|
2005
3047
|
}
|
|
@@ -2082,6 +3124,26 @@ let GanttComponent = GanttComponent_1 = class GanttComponent {
|
|
|
2082
3124
|
get toolbarSettings() {
|
|
2083
3125
|
return this._toolbarSettings;
|
|
2084
3126
|
}
|
|
3127
|
+
/**
|
|
3128
|
+
* Gets or sets the callback function that retrieves the child items for a particular item.
|
|
3129
|
+
*/
|
|
3130
|
+
set fetchChildren(fn) {
|
|
3131
|
+
this._fetchChildren = fn;
|
|
3132
|
+
this.editService.fetchChildren = fn;
|
|
3133
|
+
}
|
|
3134
|
+
get fetchChildren() {
|
|
3135
|
+
return this._fetchChildren;
|
|
3136
|
+
}
|
|
3137
|
+
/**
|
|
3138
|
+
* Gets or sets the callback function that indicates if a particular item has child items.
|
|
3139
|
+
*/
|
|
3140
|
+
set hasChildren(fn) {
|
|
3141
|
+
this._hasChildren = fn;
|
|
3142
|
+
this.editService.hasChildren = fn;
|
|
3143
|
+
}
|
|
3144
|
+
get hasChildren() {
|
|
3145
|
+
return this._hasChildren;
|
|
3146
|
+
}
|
|
2085
3147
|
/**
|
|
2086
3148
|
* The options of the timeline splitter pane. By default the pane is `collapsible`,
|
|
2087
3149
|
* `resizable`, not `collapsed`, and its `size` is `'50%'`.
|
|
@@ -2137,6 +3199,17 @@ let GanttComponent = GanttComponent_1 = class GanttComponent {
|
|
|
2137
3199
|
get taskIdField() {
|
|
2138
3200
|
return this.mapper.taskFields.id;
|
|
2139
3201
|
}
|
|
3202
|
+
/**
|
|
3203
|
+
* Specifies the settings for auto-scrolling during dragging
|
|
3204
|
+
* when the pointer moves outside of the container bounderies
|
|
3205
|
+
* [see example]({% slug editing_drag_create_dependencies_gantt %}#toc-auto-scrolling).
|
|
3206
|
+
*/
|
|
3207
|
+
set dragScrollSettings(settings) {
|
|
3208
|
+
this._dragScrollSettings = Object.assign({}, DEFAULT_DRAG_SCROLL_SETTINGS, settings);
|
|
3209
|
+
}
|
|
3210
|
+
get dragScrollSettings() {
|
|
3211
|
+
return this._dragScrollSettings;
|
|
3212
|
+
}
|
|
2140
3213
|
/**
|
|
2141
3214
|
* @hidden
|
|
2142
3215
|
*/
|
|
@@ -2146,6 +3219,15 @@ let GanttComponent = GanttComponent_1 = class GanttComponent {
|
|
|
2146
3219
|
}
|
|
2147
3220
|
return this.treeList.view.data.map(item => item.data);
|
|
2148
3221
|
}
|
|
3222
|
+
/**
|
|
3223
|
+
* @hidden
|
|
3224
|
+
*/
|
|
3225
|
+
get viewItems() {
|
|
3226
|
+
if (!isPresent(this.treeList)) {
|
|
3227
|
+
return [];
|
|
3228
|
+
}
|
|
3229
|
+
return this.treeList.view.data;
|
|
3230
|
+
}
|
|
2149
3231
|
/**
|
|
2150
3232
|
* @hidden
|
|
2151
3233
|
*/
|
|
@@ -2192,8 +3274,8 @@ let GanttComponent = GanttComponent_1 = class GanttComponent {
|
|
|
2192
3274
|
/**
|
|
2193
3275
|
* @hidden
|
|
2194
3276
|
*/
|
|
2195
|
-
get
|
|
2196
|
-
return this.
|
|
3277
|
+
get isInEditMode() {
|
|
3278
|
+
return this.showEditingDialog || this.showConfirmationDialog || this.treeList.isEditing();
|
|
2197
3279
|
}
|
|
2198
3280
|
ngOnChanges(changes) {
|
|
2199
3281
|
if (anyChanged(['data', 'activeView', 'workWeekStart', 'workWeekEnd', 'workDayStart', 'workDayEnd'], changes)) {
|
|
@@ -2202,6 +3284,14 @@ let GanttComponent = GanttComponent_1 = class GanttComponent {
|
|
|
2202
3284
|
}
|
|
2203
3285
|
ngAfterViewInit() {
|
|
2204
3286
|
this.updateTreeListMargin();
|
|
3287
|
+
if (this.navigable) {
|
|
3288
|
+
this.navigationService.initialize({
|
|
3289
|
+
gantt: this,
|
|
3290
|
+
host: this.hostElement.nativeElement,
|
|
3291
|
+
treeListElement: this.treeList.wrapper.nativeElement,
|
|
3292
|
+
timelineElement: this.timeline.timelineContent.nativeElement
|
|
3293
|
+
});
|
|
3294
|
+
}
|
|
2205
3295
|
const leftContainer = this.treeList.wrapper.nativeElement.querySelector('kendo-treelist-list > div');
|
|
2206
3296
|
this.scrollSyncService.registerElement(leftContainer, 'treelist');
|
|
2207
3297
|
}
|
|
@@ -2219,6 +3309,34 @@ let GanttComponent = GanttComponent_1 = class GanttComponent {
|
|
|
2219
3309
|
this.localizationSubscription.unsubscribe();
|
|
2220
3310
|
}
|
|
2221
3311
|
}
|
|
3312
|
+
/**
|
|
3313
|
+
* Focuses the last active cell or task in the Gantt.
|
|
3314
|
+
* If no item has previously been focused, the first cell of the TreeList part will receive focus,
|
|
3315
|
+
* ([see example]({% slug keyboard_navigation_gantt %}#toc-controlling-the-focus)).
|
|
3316
|
+
*/
|
|
3317
|
+
focus() {
|
|
3318
|
+
if (this.navigable) {
|
|
3319
|
+
this.navigationService.focusLastActiveItem();
|
|
3320
|
+
}
|
|
3321
|
+
}
|
|
3322
|
+
/**
|
|
3323
|
+
* Focuses the targeted cell in the TreeList part of the component,
|
|
3324
|
+
* ([see example]({% slug keyboard_navigation_gantt %}#toc-controlling-the-focus)).
|
|
3325
|
+
*/
|
|
3326
|
+
focusCell(rowIndex, colIndex) {
|
|
3327
|
+
if (this.navigable) {
|
|
3328
|
+
this.navigationService.focusCell(rowIndex, colIndex);
|
|
3329
|
+
}
|
|
3330
|
+
}
|
|
3331
|
+
/**
|
|
3332
|
+
* Focuses the targeted task in the Timeline part of the component,
|
|
3333
|
+
* ([see example]({% slug keyboard_navigation_gantt %}#toc-controlling-the-focus)).
|
|
3334
|
+
*/
|
|
3335
|
+
focusTask(taskIndex) {
|
|
3336
|
+
if (this.navigable) {
|
|
3337
|
+
this.navigationService.focusTask(taskIndex);
|
|
3338
|
+
}
|
|
3339
|
+
}
|
|
2222
3340
|
/**
|
|
2223
3341
|
* Applies the minimum possible width for the specified column,
|
|
2224
3342
|
* so that the whole text fits without wrapping. This method expects the Gantt
|
|
@@ -2283,7 +3401,10 @@ let GanttComponent = GanttComponent_1 = class GanttComponent {
|
|
|
2283
3401
|
*/
|
|
2284
3402
|
editTask(dataItem, formGroup) {
|
|
2285
3403
|
if (!this.showEditingDialog) {
|
|
2286
|
-
this.
|
|
3404
|
+
const taskId = this.mapper.extractFromTask(dataItem, 'id');
|
|
3405
|
+
const dependencies = this.dependencies.filter(item => this.mapper.extractFromDependency(item, 'toId') === taskId
|
|
3406
|
+
|| this.mapper.extractFromDependency(item, 'fromId') === taskId);
|
|
3407
|
+
this.editService.createEditDialog(dataItem, formGroup, dependencies);
|
|
2287
3408
|
}
|
|
2288
3409
|
}
|
|
2289
3410
|
/**
|
|
@@ -2300,6 +3421,15 @@ let GanttComponent = GanttComponent_1 = class GanttComponent {
|
|
|
2300
3421
|
openConfirmationDialog() {
|
|
2301
3422
|
this.showConfirmationDialog = true;
|
|
2302
3423
|
}
|
|
3424
|
+
/**
|
|
3425
|
+
* @hidden
|
|
3426
|
+
*/
|
|
3427
|
+
handleConfirmationDialogClose() {
|
|
3428
|
+
this.showConfirmationDialog = false;
|
|
3429
|
+
if (this.navigable) {
|
|
3430
|
+
this.focus();
|
|
3431
|
+
}
|
|
3432
|
+
}
|
|
2303
3433
|
/**
|
|
2304
3434
|
* Opens a cell for editing.
|
|
2305
3435
|
*/
|
|
@@ -2384,7 +3514,7 @@ let GanttComponent = GanttComponent_1 = class GanttComponent {
|
|
|
2384
3514
|
if (hasObservers(this.taskClick)) {
|
|
2385
3515
|
const taskIndex = getClosestTaskIndex(target, gantt);
|
|
2386
3516
|
const task = this.renderedTreeListItems[taskIndex];
|
|
2387
|
-
this.zone.run(() => this.
|
|
3517
|
+
this.zone.run(() => this.notifyTaskClick(event, task, taskIndex));
|
|
2388
3518
|
}
|
|
2389
3519
|
}
|
|
2390
3520
|
/**
|
|
@@ -2402,8 +3532,8 @@ let GanttComponent = GanttComponent_1 = class GanttComponent {
|
|
|
2402
3532
|
if ((hasObservers(this.selectionChange) && !this.isSameSelection(selectionAction, task)) ||
|
|
2403
3533
|
hasObservers(this.taskClick)) {
|
|
2404
3534
|
this.zone.run(() => {
|
|
2405
|
-
this.
|
|
2406
|
-
this.
|
|
3535
|
+
this.notifySelectionChange(task, selectionAction);
|
|
3536
|
+
this.notifyTaskClick(event, task, taskIndex);
|
|
2407
3537
|
});
|
|
2408
3538
|
}
|
|
2409
3539
|
}
|
|
@@ -2440,7 +3570,7 @@ let GanttComponent = GanttComponent_1 = class GanttComponent {
|
|
|
2440
3570
|
}
|
|
2441
3571
|
const task = event.items.map(item => item.dataItem)[0]; // single selection only currently available
|
|
2442
3572
|
const action = event.action;
|
|
2443
|
-
this.
|
|
3573
|
+
this.notifySelectionChange(task, action);
|
|
2444
3574
|
}
|
|
2445
3575
|
/**
|
|
2446
3576
|
* @hidden
|
|
@@ -2491,7 +3621,7 @@ let GanttComponent = GanttComponent_1 = class GanttComponent {
|
|
|
2491
3621
|
dataItem: task,
|
|
2492
3622
|
originalEvent: event,
|
|
2493
3623
|
sender: this,
|
|
2494
|
-
|
|
3624
|
+
index: taskIndex,
|
|
2495
3625
|
type: 'dblclick'
|
|
2496
3626
|
}));
|
|
2497
3627
|
}
|
|
@@ -2502,16 +3632,35 @@ let GanttComponent = GanttComponent_1 = class GanttComponent {
|
|
|
2502
3632
|
getText(token) {
|
|
2503
3633
|
return this.localizationService.get(token);
|
|
2504
3634
|
}
|
|
2505
|
-
|
|
3635
|
+
/**
|
|
3636
|
+
* @hidden
|
|
3637
|
+
*/
|
|
3638
|
+
changeActiveView(view) {
|
|
3639
|
+
if (view !== this.activeView) {
|
|
3640
|
+
this.activeView = view;
|
|
3641
|
+
this.loadTimelineData();
|
|
3642
|
+
this.scrollSyncService.resetTimelineScrollLeft();
|
|
3643
|
+
this.activeViewChange.emit(view);
|
|
3644
|
+
}
|
|
3645
|
+
}
|
|
3646
|
+
/**
|
|
3647
|
+
* @hidden
|
|
3648
|
+
*/
|
|
3649
|
+
notifyTaskClick(event, dataItem, itemIndex) {
|
|
3650
|
+
// simulates the TreeList `cellClick` event triggered by enter press (type: 'click')
|
|
3651
|
+
const type = event instanceof KeyboardEvent ? 'click' : event.type;
|
|
2506
3652
|
this.taskClick.emit({
|
|
2507
3653
|
originalEvent: event,
|
|
2508
3654
|
dataItem: dataItem,
|
|
2509
|
-
|
|
2510
|
-
type:
|
|
3655
|
+
index: itemIndex,
|
|
3656
|
+
type: type,
|
|
2511
3657
|
sender: this
|
|
2512
3658
|
});
|
|
2513
3659
|
}
|
|
2514
|
-
|
|
3660
|
+
/**
|
|
3661
|
+
* @hidden
|
|
3662
|
+
*/
|
|
3663
|
+
notifySelectionChange(dataItem, action) {
|
|
2515
3664
|
if (this.isSameSelection(action, dataItem)) {
|
|
2516
3665
|
return;
|
|
2517
3666
|
}
|
|
@@ -2522,6 +3671,29 @@ let GanttComponent = GanttComponent_1 = class GanttComponent {
|
|
|
2522
3671
|
});
|
|
2523
3672
|
this.treeList.updateView();
|
|
2524
3673
|
}
|
|
3674
|
+
/**
|
|
3675
|
+
* @hidden
|
|
3676
|
+
*/
|
|
3677
|
+
notifyTaskDelete(task) {
|
|
3678
|
+
this.editService.dataItem = task;
|
|
3679
|
+
this.taskDelete.emit({
|
|
3680
|
+
item: getEditItem(task, this.treeList.view.data, this.mapper),
|
|
3681
|
+
sender: this
|
|
3682
|
+
});
|
|
3683
|
+
}
|
|
3684
|
+
/**
|
|
3685
|
+
* @hidden
|
|
3686
|
+
*/
|
|
3687
|
+
isSameSelection(action, dataItem) {
|
|
3688
|
+
return action === 'select' && this.isSelected(dataItem);
|
|
3689
|
+
}
|
|
3690
|
+
/**
|
|
3691
|
+
* @hidden
|
|
3692
|
+
*/
|
|
3693
|
+
getSelectionAction({ ctrlKey, metaKey }, dataItem) {
|
|
3694
|
+
const shouldToggleSelection = ctrlKey || metaKey;
|
|
3695
|
+
return (shouldToggleSelection && this.isSelected(dataItem)) ? 'remove' : 'select';
|
|
3696
|
+
}
|
|
2525
3697
|
updateTreeListGroupClass(columns = this.columns) {
|
|
2526
3698
|
if (!isPresent(this.treeList)) {
|
|
2527
3699
|
return;
|
|
@@ -2548,23 +3720,65 @@ let GanttComponent = GanttComponent_1 = class GanttComponent {
|
|
|
2548
3720
|
}
|
|
2549
3721
|
return this.views.find(view => view.type === this.activeView);
|
|
2550
3722
|
}
|
|
2551
|
-
isSameSelection(action, dataItem) {
|
|
2552
|
-
return action === 'select' && this.isSelected(dataItem);
|
|
2553
|
-
}
|
|
2554
|
-
getSelectionAction({ ctrlKey, metaKey }, dataItem) {
|
|
2555
|
-
const shouldToggleSelection = ctrlKey || metaKey;
|
|
2556
|
-
return (shouldToggleSelection && this.isSelected(dataItem)) ? 'remove' : 'select';
|
|
2557
|
-
}
|
|
2558
3723
|
getFirstSelectedItem() {
|
|
2559
3724
|
const isSelectedCallback = this.isSelected || isSelected;
|
|
2560
3725
|
const loadedItems = this.renderedTreeListItems || [];
|
|
2561
3726
|
return loadedItems.find(isSelectedCallback);
|
|
2562
3727
|
}
|
|
3728
|
+
defaultValidateNewDependencyCallback(dependency) {
|
|
3729
|
+
const fromTaskId = this.mapper.extractFromDependency(dependency, 'fromId');
|
|
3730
|
+
const toTaskId = this.mapper.extractFromDependency(dependency, 'toId');
|
|
3731
|
+
const fromTask = this.treeList.view.data.find(task => this.mapper.extractFromTask(task.data, 'id') === fromTaskId);
|
|
3732
|
+
const toTask = this.treeList.view.data.find(task => this.mapper.extractFromTask(task.data, 'id') === toTaskId);
|
|
3733
|
+
// mark as invalid if the attempted dependency is lacking valid from- and to-tasks
|
|
3734
|
+
// or when the from- and to-tasks are actually the same task
|
|
3735
|
+
if (!isPresent(fromTask) || !isPresent(fromTask.data) ||
|
|
3736
|
+
!isPresent(toTask) || !isPresent(toTask.data) ||
|
|
3737
|
+
fromTask.data === toTask.data) {
|
|
3738
|
+
return false;
|
|
3739
|
+
}
|
|
3740
|
+
const tasksDependentOnOneAnother = this.dependencies.some(current => {
|
|
3741
|
+
const currentFromId = this.mapper.extractFromDependency(current, 'fromId');
|
|
3742
|
+
const currentToId = this.mapper.extractFromDependency(current, 'toId');
|
|
3743
|
+
return (fromTaskId === currentFromId && toTaskId === currentToId) ||
|
|
3744
|
+
(toTaskId === currentFromId && fromTaskId === currentToId);
|
|
3745
|
+
});
|
|
3746
|
+
// mark as invalid if the attempted dependency is trying to connect already dependent tasks
|
|
3747
|
+
// mark as invalid if the two tasks are in parent-child relationship
|
|
3748
|
+
if (tasksDependentOnOneAnother || areParentChild(fromTask, toTask)) {
|
|
3749
|
+
return false;
|
|
3750
|
+
}
|
|
3751
|
+
const fromTaskStart = this.mapper.extractFromTask(fromTask.data, 'start');
|
|
3752
|
+
const fromTaskEnd = this.mapper.extractFromTask(fromTask.data, 'end');
|
|
3753
|
+
const toTaskStart = this.mapper.extractFromTask(toTask.data, 'start');
|
|
3754
|
+
const toTaskEnd = this.mapper.extractFromTask(toTask.data, 'end');
|
|
3755
|
+
// if the two tasks are available to be connected via a dependency,
|
|
3756
|
+
// check if their start and end time allow for the attempted dependency type
|
|
3757
|
+
switch (this.mapper.extractFromDependency(dependency, 'type')) {
|
|
3758
|
+
// finish to finish (FF) — the from-task ends before the to-task can end
|
|
3759
|
+
case DependencyType.FF:
|
|
3760
|
+
return fromTaskEnd <= toTaskEnd;
|
|
3761
|
+
// finish to start (FS) — the from-task ends before the to-task can begin
|
|
3762
|
+
case DependencyType.FS:
|
|
3763
|
+
return fromTaskEnd <= toTaskStart;
|
|
3764
|
+
// start to finish (SF) — the from-task begins before the to-task can end
|
|
3765
|
+
case DependencyType.SF:
|
|
3766
|
+
return fromTaskStart <= toTaskEnd;
|
|
3767
|
+
// start to start (SS) — the from-task begins before the to-task can begin
|
|
3768
|
+
case DependencyType.SS:
|
|
3769
|
+
return fromTaskStart <= toTaskStart;
|
|
3770
|
+
default: return false;
|
|
3771
|
+
}
|
|
3772
|
+
}
|
|
2563
3773
|
};
|
|
2564
3774
|
__decorate([
|
|
2565
3775
|
ViewChild(TreeListComponent, { static: true }),
|
|
2566
3776
|
__metadata("design:type", TreeListComponent)
|
|
2567
3777
|
], GanttComponent.prototype, "treeList", void 0);
|
|
3778
|
+
__decorate([
|
|
3779
|
+
ViewChild(GanttTimelineComponent, { static: false }),
|
|
3780
|
+
__metadata("design:type", GanttTimelineComponent)
|
|
3781
|
+
], GanttComponent.prototype, "timeline", void 0);
|
|
2568
3782
|
__decorate([
|
|
2569
3783
|
ContentChild(GanttTaskContentTemplateDirective, { static: true }),
|
|
2570
3784
|
__metadata("design:type", GanttTaskContentTemplateDirective)
|
|
@@ -2581,6 +3795,24 @@ __decorate([
|
|
|
2581
3795
|
ContentChildren(ToolbarTemplateDirective),
|
|
2582
3796
|
__metadata("design:type", QueryList)
|
|
2583
3797
|
], GanttComponent.prototype, "toolbarTemplateChildren", void 0);
|
|
3798
|
+
__decorate([
|
|
3799
|
+
Input('aria-roledescription'),
|
|
3800
|
+
__metadata("design:type", String)
|
|
3801
|
+
], GanttComponent.prototype, "roleDescription", void 0);
|
|
3802
|
+
__decorate([
|
|
3803
|
+
HostBinding('attr.aria-roledescription'),
|
|
3804
|
+
__metadata("design:type", String),
|
|
3805
|
+
__metadata("design:paramtypes", [])
|
|
3806
|
+
], GanttComponent.prototype, "hostRoleDescriptionAttr", null);
|
|
3807
|
+
__decorate([
|
|
3808
|
+
Input('role'),
|
|
3809
|
+
__metadata("design:type", String)
|
|
3810
|
+
], GanttComponent.prototype, "role", void 0);
|
|
3811
|
+
__decorate([
|
|
3812
|
+
HostBinding('attr.role'),
|
|
3813
|
+
__metadata("design:type", String),
|
|
3814
|
+
__metadata("design:paramtypes", [])
|
|
3815
|
+
], GanttComponent.prototype, "hostRoleAttr", null);
|
|
2584
3816
|
__decorate([
|
|
2585
3817
|
HostBinding('class.k-gantt'),
|
|
2586
3818
|
__metadata("design:type", Boolean)
|
|
@@ -2623,6 +3855,10 @@ __decorate([
|
|
|
2623
3855
|
Input(),
|
|
2624
3856
|
__metadata("design:type", Function)
|
|
2625
3857
|
], GanttComponent.prototype, "isSelected", void 0);
|
|
3858
|
+
__decorate([
|
|
3859
|
+
Input(),
|
|
3860
|
+
__metadata("design:type", Function)
|
|
3861
|
+
], GanttComponent.prototype, "validateNewDependency", void 0);
|
|
2626
3862
|
__decorate([
|
|
2627
3863
|
Output(),
|
|
2628
3864
|
__metadata("design:type", EventEmitter)
|
|
@@ -2638,12 +3874,14 @@ __decorate([
|
|
|
2638
3874
|
], GanttComponent.prototype, "toolbarSettings", null);
|
|
2639
3875
|
__decorate([
|
|
2640
3876
|
Input(),
|
|
2641
|
-
__metadata("design:type", Function)
|
|
2642
|
-
|
|
3877
|
+
__metadata("design:type", Function),
|
|
3878
|
+
__metadata("design:paramtypes", [Function])
|
|
3879
|
+
], GanttComponent.prototype, "fetchChildren", null);
|
|
2643
3880
|
__decorate([
|
|
2644
3881
|
Input(),
|
|
2645
|
-
__metadata("design:type", Function)
|
|
2646
|
-
|
|
3882
|
+
__metadata("design:type", Function),
|
|
3883
|
+
__metadata("design:paramtypes", [Function])
|
|
3884
|
+
], GanttComponent.prototype, "hasChildren", null);
|
|
2647
3885
|
__decorate([
|
|
2648
3886
|
Input(),
|
|
2649
3887
|
__metadata("design:type", Array)
|
|
@@ -2680,6 +3918,10 @@ __decorate([
|
|
|
2680
3918
|
Input(),
|
|
2681
3919
|
__metadata("design:type", Number)
|
|
2682
3920
|
], GanttComponent.prototype, "workWeekEnd", void 0);
|
|
3921
|
+
__decorate([
|
|
3922
|
+
Input(),
|
|
3923
|
+
__metadata("design:type", Boolean)
|
|
3924
|
+
], GanttComponent.prototype, "navigable", void 0);
|
|
2683
3925
|
__decorate([
|
|
2684
3926
|
Input(),
|
|
2685
3927
|
__metadata("design:type", Object),
|
|
@@ -2720,6 +3962,11 @@ __decorate([
|
|
|
2720
3962
|
Input(),
|
|
2721
3963
|
__metadata("design:type", Boolean)
|
|
2722
3964
|
], GanttComponent.prototype, "columnsResizable", void 0);
|
|
3965
|
+
__decorate([
|
|
3966
|
+
Input(),
|
|
3967
|
+
__metadata("design:type", Object),
|
|
3968
|
+
__metadata("design:paramtypes", [Object])
|
|
3969
|
+
], GanttComponent.prototype, "dragScrollSettings", null);
|
|
2723
3970
|
__decorate([
|
|
2724
3971
|
Output(),
|
|
2725
3972
|
__metadata("design:type", EventEmitter)
|
|
@@ -2760,6 +4007,10 @@ __decorate([
|
|
|
2760
4007
|
Output(),
|
|
2761
4008
|
__metadata("design:type", EventEmitter)
|
|
2762
4009
|
], GanttComponent.prototype, "taskAdd", void 0);
|
|
4010
|
+
__decorate([
|
|
4011
|
+
Output(),
|
|
4012
|
+
__metadata("design:type", EventEmitter)
|
|
4013
|
+
], GanttComponent.prototype, "dependencyAdd", void 0);
|
|
2763
4014
|
__decorate([
|
|
2764
4015
|
Output(),
|
|
2765
4016
|
__metadata("design:type", EventEmitter)
|
|
@@ -2817,6 +4068,7 @@ GanttComponent = GanttComponent_1 = __decorate([
|
|
|
2817
4068
|
selector: 'kendo-gantt',
|
|
2818
4069
|
exportAs: 'kendoGantt',
|
|
2819
4070
|
providers: [
|
|
4071
|
+
GanttLocalizationService,
|
|
2820
4072
|
LocalizationService,
|
|
2821
4073
|
{
|
|
2822
4074
|
provide: DataBoundTreeComponent,
|
|
@@ -2834,7 +4086,9 @@ GanttComponent = GanttComponent_1 = __decorate([
|
|
|
2834
4086
|
DependencyDomService,
|
|
2835
4087
|
MappingService,
|
|
2836
4088
|
OptionChangesService,
|
|
2837
|
-
EditService
|
|
4089
|
+
EditService,
|
|
4090
|
+
TimelineScrollService,
|
|
4091
|
+
NavigationService
|
|
2838
4092
|
],
|
|
2839
4093
|
template: `
|
|
2840
4094
|
<ng-container kendoGanttLocalizedMessages
|
|
@@ -3061,6 +4315,7 @@ GanttComponent = GanttComponent_1 = __decorate([
|
|
|
3061
4315
|
[data]="data"
|
|
3062
4316
|
[hasChildren]="hasChildren"
|
|
3063
4317
|
[fetchChildren]="fetchChildren"
|
|
4318
|
+
[navigable]="navigable"
|
|
3064
4319
|
[isExpanded]="isExpanded"
|
|
3065
4320
|
[autoSize]="columnsAutoSize"
|
|
3066
4321
|
[columnMenu]="columnMenu"
|
|
@@ -3149,7 +4404,9 @@ GanttComponent = GanttComponent_1 = __decorate([
|
|
|
3149
4404
|
[scrollable]="false">
|
|
3150
4405
|
<kendo-gantt-timeline
|
|
3151
4406
|
*ngIf="views && views.length"
|
|
3152
|
-
[
|
|
4407
|
+
[renderDependencyDragClues]="renderDependencyDragClues"
|
|
4408
|
+
[dragScrollSettings]="dragScrollSettings"
|
|
4409
|
+
[rows]="viewItems"
|
|
3153
4410
|
[slots]="timelineSlots"
|
|
3154
4411
|
[groupSlots]="timelineGroupSlots"
|
|
3155
4412
|
[tableWidth]="tableWidth"
|
|
@@ -3159,7 +4416,8 @@ GanttComponent = GanttComponent_1 = __decorate([
|
|
|
3159
4416
|
[summaryTaskTemplate]="summaryTaskTemplate?.templateRef"
|
|
3160
4417
|
[taskClass]="taskClass"
|
|
3161
4418
|
[dependencies]="dependencies"
|
|
3162
|
-
[
|
|
4419
|
+
[isExpanded]="isExpanded"
|
|
4420
|
+
[selectable]="selectable"
|
|
3163
4421
|
[isTaskSelected]="isTaskSelected"
|
|
3164
4422
|
[kendoEventsOutsideAngular]="{
|
|
3165
4423
|
click: handleTimelineClick,
|
|
@@ -3178,18 +4436,21 @@ GanttComponent = GanttComponent_1 = __decorate([
|
|
|
3178
4436
|
[showViewSelector]="toolbarSettings.viewSelectorTool === 'bottom' || toolbarSettings.viewSelectorTool === 'both'"
|
|
3179
4437
|
class="k-gantt-footer k-toolbar k-gantt-toolbar"
|
|
3180
4438
|
position="bottom"></kendo-gantt-toolbar>
|
|
3181
|
-
<kendo-gantt-edit-dialog
|
|
4439
|
+
<kendo-gantt-edit-dialog
|
|
4440
|
+
*ngIf="showEditingDialog"
|
|
4441
|
+
[data]="data">
|
|
4442
|
+
</kendo-gantt-edit-dialog>
|
|
3182
4443
|
<kendo-dialog
|
|
3183
4444
|
*ngIf="showConfirmationDialog"
|
|
3184
4445
|
[width]="575"
|
|
3185
4446
|
[height]="170"
|
|
3186
4447
|
[title]="getText('confirmationDialogTitle')"
|
|
3187
|
-
(close)="
|
|
3188
|
-
<span>{{getText('confirmationDialogContent')}}</span>
|
|
4448
|
+
(close)="handleConfirmationDialogClose()">
|
|
4449
|
+
<span>{{ getText('confirmationDialogContent') }}</span>
|
|
3189
4450
|
<kendo-dialog-actions layout="normal">
|
|
3190
4451
|
<kendo-treelist-spacer></kendo-treelist-spacer>
|
|
3191
4452
|
<button kendoButton [primary]="true" (click)="handleDeleteConfirmation()">{{ getText('deleteButtonText') }}</button>
|
|
3192
|
-
<button kendoButton (click)="
|
|
4453
|
+
<button kendoButton (click)="handleConfirmationDialogClose()">{{ getText('cancelButtonText') }}</button>
|
|
3193
4454
|
</kendo-dialog-actions>
|
|
3194
4455
|
</kendo-dialog>
|
|
3195
4456
|
`
|
|
@@ -3203,205 +4464,14 @@ GanttComponent = GanttComponent_1 = __decorate([
|
|
|
3203
4464
|
EditService,
|
|
3204
4465
|
LocalizationService,
|
|
3205
4466
|
ElementRef,
|
|
3206
|
-
NgZone
|
|
4467
|
+
NgZone,
|
|
4468
|
+
NavigationService])
|
|
3207
4469
|
], GanttComponent);
|
|
3208
4470
|
|
|
3209
4471
|
/**
|
|
3210
4472
|
* @hidden
|
|
3211
4473
|
*/
|
|
3212
|
-
|
|
3213
|
-
constructor(scrollSyncService, dependencyDomService, renderer, zone) {
|
|
3214
|
-
this.scrollSyncService = scrollSyncService;
|
|
3215
|
-
this.dependencyDomService = dependencyDomService;
|
|
3216
|
-
this.renderer = renderer;
|
|
3217
|
-
this.zone = zone;
|
|
3218
|
-
this.hostClass = true;
|
|
3219
|
-
this.dependencies = [];
|
|
3220
|
-
this.subscriptions = new Subscription();
|
|
3221
|
-
this.subscriptions.add(
|
|
3222
|
-
// task changes indicates change in row content, number, height, etc.
|
|
3223
|
-
this.dependencyDomService.taskChanges
|
|
3224
|
-
.pipe(filter(args => isPresent(args.timelineRow)), switchMap(args => this.zone.onStable.pipe(take(1), map(() => args))) // ensure the content is rendered
|
|
3225
|
-
)
|
|
3226
|
-
.subscribe(({ timelineRow }) => {
|
|
3227
|
-
const timelineRowHeight = isDocumentAvailable() ? timelineRow.getBoundingClientRect().height : 0;
|
|
3228
|
-
this.renderer.setStyle(this.timelineColumns.nativeElement, 'height', `${(this.rows || []).length * timelineRowHeight}px`);
|
|
3229
|
-
}));
|
|
3230
|
-
}
|
|
3231
|
-
ngAfterViewInit() {
|
|
3232
|
-
const timelineHeader = this.timelineHeaderWrap.nativeElement;
|
|
3233
|
-
const rightContainer = this.timelineContent.nativeElement;
|
|
3234
|
-
this.scrollSyncService.registerElement(rightContainer, 'timeline');
|
|
3235
|
-
this.scrollSyncService.registerElement(timelineHeader, 'header');
|
|
3236
|
-
this.dependencyDomService.registerContentContainer(this.tasksContainer.nativeElement);
|
|
3237
|
-
}
|
|
3238
|
-
ngOnDestroy() {
|
|
3239
|
-
this.subscriptions.unsubscribe();
|
|
3240
|
-
}
|
|
3241
|
-
isNonWorking(item) {
|
|
3242
|
-
return item.hasOwnProperty('isWorking') && !item.isWorking;
|
|
3243
|
-
}
|
|
3244
|
-
};
|
|
3245
|
-
__decorate([
|
|
3246
|
-
ViewChild('timelineContent', { static: true }),
|
|
3247
|
-
__metadata("design:type", ElementRef)
|
|
3248
|
-
], GanttTimelineComponent.prototype, "timelineContent", void 0);
|
|
3249
|
-
__decorate([
|
|
3250
|
-
ViewChild('timelineColumns', { static: true }),
|
|
3251
|
-
__metadata("design:type", ElementRef)
|
|
3252
|
-
], GanttTimelineComponent.prototype, "timelineColumns", void 0);
|
|
3253
|
-
__decorate([
|
|
3254
|
-
ViewChild('timelineHeaderWrap', { static: true }),
|
|
3255
|
-
__metadata("design:type", ElementRef)
|
|
3256
|
-
], GanttTimelineComponent.prototype, "timelineHeaderWrap", void 0);
|
|
3257
|
-
__decorate([
|
|
3258
|
-
ViewChild('tasksContainer', { static: true }),
|
|
3259
|
-
__metadata("design:type", ElementRef)
|
|
3260
|
-
], GanttTimelineComponent.prototype, "tasksContainer", void 0);
|
|
3261
|
-
__decorate([
|
|
3262
|
-
HostBinding('class.k-gantt-timeline'),
|
|
3263
|
-
__metadata("design:type", Boolean)
|
|
3264
|
-
], GanttTimelineComponent.prototype, "hostClass", void 0);
|
|
3265
|
-
__decorate([
|
|
3266
|
-
Input(),
|
|
3267
|
-
__metadata("design:type", Array)
|
|
3268
|
-
], GanttTimelineComponent.prototype, "rows", void 0);
|
|
3269
|
-
__decorate([
|
|
3270
|
-
Input(),
|
|
3271
|
-
__metadata("design:type", Array)
|
|
3272
|
-
], GanttTimelineComponent.prototype, "slots", void 0);
|
|
3273
|
-
__decorate([
|
|
3274
|
-
Input(),
|
|
3275
|
-
__metadata("design:type", Array)
|
|
3276
|
-
], GanttTimelineComponent.prototype, "groupSlots", void 0);
|
|
3277
|
-
__decorate([
|
|
3278
|
-
Input(),
|
|
3279
|
-
__metadata("design:type", Number)
|
|
3280
|
-
], GanttTimelineComponent.prototype, "tableWidth", void 0);
|
|
3281
|
-
__decorate([
|
|
3282
|
-
Input(),
|
|
3283
|
-
__metadata("design:type", String)
|
|
3284
|
-
], GanttTimelineComponent.prototype, "activeView", void 0);
|
|
3285
|
-
__decorate([
|
|
3286
|
-
Input(),
|
|
3287
|
-
__metadata("design:type", TemplateRef)
|
|
3288
|
-
], GanttTimelineComponent.prototype, "taskContentTemplate", void 0);
|
|
3289
|
-
__decorate([
|
|
3290
|
-
Input(),
|
|
3291
|
-
__metadata("design:type", TemplateRef)
|
|
3292
|
-
], GanttTimelineComponent.prototype, "taskTemplate", void 0);
|
|
3293
|
-
__decorate([
|
|
3294
|
-
Input(),
|
|
3295
|
-
__metadata("design:type", TemplateRef)
|
|
3296
|
-
], GanttTimelineComponent.prototype, "summaryTaskTemplate", void 0);
|
|
3297
|
-
__decorate([
|
|
3298
|
-
Input(),
|
|
3299
|
-
__metadata("design:type", Function)
|
|
3300
|
-
], GanttTimelineComponent.prototype, "taskClass", void 0);
|
|
3301
|
-
__decorate([
|
|
3302
|
-
Input(),
|
|
3303
|
-
__metadata("design:type", Function)
|
|
3304
|
-
], GanttTimelineComponent.prototype, "isTaskSelected", void 0);
|
|
3305
|
-
__decorate([
|
|
3306
|
-
Input(),
|
|
3307
|
-
__metadata("design:type", Function)
|
|
3308
|
-
], GanttTimelineComponent.prototype, "hasChildren", void 0);
|
|
3309
|
-
__decorate([
|
|
3310
|
-
Input(),
|
|
3311
|
-
__metadata("design:type", Array)
|
|
3312
|
-
], GanttTimelineComponent.prototype, "dependencies", void 0);
|
|
3313
|
-
GanttTimelineComponent = __decorate([
|
|
3314
|
-
Component({
|
|
3315
|
-
selector: 'kendo-gantt-timeline',
|
|
3316
|
-
template: `
|
|
3317
|
-
<div class="k-timeline k-grid k-widget">
|
|
3318
|
-
<div class="k-grid-header">
|
|
3319
|
-
<div #timelineHeaderWrap class="k-grid-header-wrap">
|
|
3320
|
-
<table
|
|
3321
|
-
role="presentation"
|
|
3322
|
-
[style.width.px]="tableWidth"
|
|
3323
|
-
>
|
|
3324
|
-
<tbody
|
|
3325
|
-
kendoGanttHeaderTableBody
|
|
3326
|
-
[groupSlots]="groupSlots"
|
|
3327
|
-
[slots]="slots">
|
|
3328
|
-
</tbody>
|
|
3329
|
-
</table>
|
|
3330
|
-
</div>
|
|
3331
|
-
</div>
|
|
3332
|
-
<div #timelineContent class="k-grid-content">
|
|
3333
|
-
<div class="k-gantt-tables">
|
|
3334
|
-
<table
|
|
3335
|
-
class="k-gantt-rows"
|
|
3336
|
-
[style.width.px]="tableWidth"
|
|
3337
|
-
role="presentation"
|
|
3338
|
-
>
|
|
3339
|
-
<tbody>
|
|
3340
|
-
<tr *ngFor="let item of rows; let i = index;"
|
|
3341
|
-
[class.k-alt]="i % 2"
|
|
3342
|
-
>
|
|
3343
|
-
<td></td>
|
|
3344
|
-
</tr>
|
|
3345
|
-
</tbody>
|
|
3346
|
-
</table>
|
|
3347
|
-
|
|
3348
|
-
<table
|
|
3349
|
-
#timelineColumns
|
|
3350
|
-
class="k-gantt-columns"
|
|
3351
|
-
role="presentation"
|
|
3352
|
-
[style.width.px]="tableWidth"
|
|
3353
|
-
>
|
|
3354
|
-
<colgroup>
|
|
3355
|
-
<col *ngFor="let item of slots">
|
|
3356
|
-
</colgroup>
|
|
3357
|
-
|
|
3358
|
-
<tbody>
|
|
3359
|
-
<tr>
|
|
3360
|
-
<td *ngFor="let item of slots"
|
|
3361
|
-
[class.k-nonwork-hour]="isNonWorking(item)"
|
|
3362
|
-
>
|
|
3363
|
-
</td>
|
|
3364
|
-
</tr>
|
|
3365
|
-
</tbody>
|
|
3366
|
-
</table>
|
|
3367
|
-
|
|
3368
|
-
<table
|
|
3369
|
-
#tasksContainer
|
|
3370
|
-
class="k-gantt-tasks"
|
|
3371
|
-
role="presentation"
|
|
3372
|
-
style="border-collapse: collapse;"
|
|
3373
|
-
[style.width.px]="tableWidth"
|
|
3374
|
-
>
|
|
3375
|
-
<tbody
|
|
3376
|
-
kendoGanttTasksTableBody
|
|
3377
|
-
[rows]="rows"
|
|
3378
|
-
[activeView]="activeView"
|
|
3379
|
-
[taskContentTemplate]="taskContentTemplate"
|
|
3380
|
-
[taskTemplate]="taskTemplate"
|
|
3381
|
-
[summaryTaskTemplate]="summaryTaskTemplate"
|
|
3382
|
-
[taskClass]="taskClass"
|
|
3383
|
-
[hasChildren]="hasChildren"
|
|
3384
|
-
[isTaskSelected]="isTaskSelected"
|
|
3385
|
-
>
|
|
3386
|
-
</tbody>
|
|
3387
|
-
</table>
|
|
3388
|
-
</div>
|
|
3389
|
-
<svg class="k-gantt-dependencies-svg">
|
|
3390
|
-
<polyline
|
|
3391
|
-
*ngFor="let dependency of dependencies"
|
|
3392
|
-
kendoGanttDependency
|
|
3393
|
-
[dependency]="dependency"
|
|
3394
|
-
/>
|
|
3395
|
-
</svg>
|
|
3396
|
-
</div>
|
|
3397
|
-
</div>
|
|
3398
|
-
`
|
|
3399
|
-
}),
|
|
3400
|
-
__metadata("design:paramtypes", [ScrollSyncService,
|
|
3401
|
-
DependencyDomService,
|
|
3402
|
-
Renderer2,
|
|
3403
|
-
NgZone])
|
|
3404
|
-
], GanttTimelineComponent);
|
|
4474
|
+
const TOUCH_ENABLED = new InjectionToken('gantt-touch-enabled');
|
|
3405
4475
|
|
|
3406
4476
|
/**
|
|
3407
4477
|
* @hidden
|
|
@@ -3418,8 +4488,8 @@ let GanttTasksTableBodyComponent = class GanttTasksTableBodyComponent {
|
|
|
3418
4488
|
this.dependencyDomService.registerTimelineRow(timelineRow.nativeElement);
|
|
3419
4489
|
}
|
|
3420
4490
|
}
|
|
3421
|
-
isMileStone(
|
|
3422
|
-
return !
|
|
4491
|
+
isMileStone(item) {
|
|
4492
|
+
return !item.hasChildren && isEqual(this.mapper.extractFromTask(item.data, 'start'), this.mapper.extractFromTask(item.data, 'end'));
|
|
3423
4493
|
}
|
|
3424
4494
|
};
|
|
3425
4495
|
__decorate([
|
|
@@ -3427,6 +4497,10 @@ __decorate([
|
|
|
3427
4497
|
__metadata("design:type", ElementRef),
|
|
3428
4498
|
__metadata("design:paramtypes", [ElementRef])
|
|
3429
4499
|
], GanttTasksTableBodyComponent.prototype, "timelineRow", null);
|
|
4500
|
+
__decorate([
|
|
4501
|
+
Input(),
|
|
4502
|
+
__metadata("design:type", Boolean)
|
|
4503
|
+
], GanttTasksTableBodyComponent.prototype, "selectable", void 0);
|
|
3430
4504
|
__decorate([
|
|
3431
4505
|
Input(),
|
|
3432
4506
|
__metadata("design:type", Array)
|
|
@@ -3454,11 +4528,15 @@ __decorate([
|
|
|
3454
4528
|
__decorate([
|
|
3455
4529
|
Input(),
|
|
3456
4530
|
__metadata("design:type", Function)
|
|
3457
|
-
], GanttTasksTableBodyComponent.prototype, "
|
|
4531
|
+
], GanttTasksTableBodyComponent.prototype, "isExpanded", void 0);
|
|
3458
4532
|
__decorate([
|
|
3459
4533
|
Input(),
|
|
3460
4534
|
__metadata("design:type", Function)
|
|
3461
4535
|
], GanttTasksTableBodyComponent.prototype, "isTaskSelected", void 0);
|
|
4536
|
+
__decorate([
|
|
4537
|
+
Input(),
|
|
4538
|
+
__metadata("design:type", Boolean)
|
|
4539
|
+
], GanttTasksTableBodyComponent.prototype, "renderDependencyDragClues", void 0);
|
|
3462
4540
|
GanttTasksTableBodyComponent = __decorate([
|
|
3463
4541
|
Component({
|
|
3464
4542
|
selector: '[kendoGanttTasksTableBody]',
|
|
@@ -3467,33 +4545,43 @@ GanttTasksTableBodyComponent = __decorate([
|
|
|
3467
4545
|
<td>
|
|
3468
4546
|
<kendo-gantt-milestone-task
|
|
3469
4547
|
*ngIf="isMileStone(item); else task"
|
|
3470
|
-
[dataItem]="item"
|
|
4548
|
+
[dataItem]="item.data"
|
|
4549
|
+
[level]="item.level"
|
|
3471
4550
|
[activeView]="activeView"
|
|
3472
4551
|
[taskClass]="taskClass"
|
|
4552
|
+
[selectable]="selectable"
|
|
3473
4553
|
[isSelected]="isTaskSelected"
|
|
3474
4554
|
[index]="index"
|
|
4555
|
+
[renderDependencyDragClues]="renderDependencyDragClues"
|
|
3475
4556
|
>
|
|
3476
4557
|
</kendo-gantt-milestone-task>
|
|
3477
4558
|
<ng-template #task>
|
|
3478
4559
|
<kendo-gantt-summary-task
|
|
3479
|
-
*ngIf="hasChildren
|
|
3480
|
-
[dataItem]="item"
|
|
4560
|
+
*ngIf="item.hasChildren"
|
|
4561
|
+
[dataItem]="item.data"
|
|
4562
|
+
[level]="item.level"
|
|
3481
4563
|
[template]="summaryTaskTemplate"
|
|
3482
4564
|
[activeView]="activeView"
|
|
3483
4565
|
[taskClass]="taskClass"
|
|
4566
|
+
[selectable]="selectable"
|
|
3484
4567
|
[isSelected]="isTaskSelected"
|
|
4568
|
+
[isExpanded]="isExpanded"
|
|
3485
4569
|
[index]="index"
|
|
4570
|
+
[renderDependencyDragClues]="renderDependencyDragClues"
|
|
3486
4571
|
>
|
|
3487
4572
|
</kendo-gantt-summary-task>
|
|
3488
4573
|
<kendo-gantt-task
|
|
3489
|
-
*ngIf="!hasChildren
|
|
3490
|
-
[dataItem]="item"
|
|
4574
|
+
*ngIf="!item.hasChildren"
|
|
4575
|
+
[dataItem]="item.data"
|
|
4576
|
+
[level]="item.level"
|
|
3491
4577
|
[taskContentTemplate]="taskContentTemplate"
|
|
3492
4578
|
[taskTemplate]="taskTemplate"
|
|
3493
4579
|
[activeView]="activeView"
|
|
3494
4580
|
[taskClass]="taskClass"
|
|
4581
|
+
[selectable]="selectable"
|
|
3495
4582
|
[isSelected]="isTaskSelected"
|
|
3496
4583
|
[index]="index"
|
|
4584
|
+
[renderDependencyDragClues]="renderDependencyDragClues"
|
|
3497
4585
|
>
|
|
3498
4586
|
</kendo-gantt-task>
|
|
3499
4587
|
</ng-template>
|
|
@@ -3538,22 +4626,32 @@ const slotUnitDuration = {
|
|
|
3538
4626
|
week: MS_PER_DAY,
|
|
3539
4627
|
month: MS_PER_DAY * 7
|
|
3540
4628
|
};
|
|
4629
|
+
const FOCUSED_CLASS = 'k-focus';
|
|
3541
4630
|
/**
|
|
3542
4631
|
* @hidden
|
|
3543
4632
|
*/
|
|
3544
4633
|
class GanttTaskBase {
|
|
3545
4634
|
constructor(mapper, // left public to be available for usage in the templates
|
|
3546
|
-
timelineViewService, dependencyDomService, optionChangesService, cdr) {
|
|
4635
|
+
timelineViewService, dependencyDomService, optionChangesService, cdr, navigationService) {
|
|
3547
4636
|
this.mapper = mapper;
|
|
3548
4637
|
this.timelineViewService = timelineViewService;
|
|
3549
4638
|
this.dependencyDomService = dependencyDomService;
|
|
3550
4639
|
this.optionChangesService = optionChangesService;
|
|
3551
4640
|
this.cdr = cdr;
|
|
4641
|
+
this.navigationService = navigationService;
|
|
3552
4642
|
this.wrapperClass = true;
|
|
3553
|
-
this.
|
|
3554
|
-
this.
|
|
3555
|
-
this.cdr.markForCheck();
|
|
3556
|
-
|
|
4643
|
+
this.subscriptions = new Subscription();
|
|
4644
|
+
this.subscriptions.add(this.optionChangesService.viewChanges
|
|
4645
|
+
.subscribe(() => this.cdr.markForCheck()));
|
|
4646
|
+
this.subscriptions.add(this.navigationService.taskStatusChanges
|
|
4647
|
+
.subscribe(this.updateActiveState.bind(this)));
|
|
4648
|
+
}
|
|
4649
|
+
get taskIndexAttribute() {
|
|
4650
|
+
return this.index;
|
|
4651
|
+
}
|
|
4652
|
+
get ariaSelected() {
|
|
4653
|
+
// assinging null will not render the attribute at all (desired in selectable="false" mode)
|
|
4654
|
+
return this.selectable ? String(this.isSelected(this.dataItem)) : null;
|
|
3557
4655
|
}
|
|
3558
4656
|
get slotUnitDuration() {
|
|
3559
4657
|
return slotUnitDuration[this.activeView];
|
|
@@ -3561,25 +4659,8 @@ class GanttTaskBase {
|
|
|
3561
4659
|
get viewService() {
|
|
3562
4660
|
return this.timelineViewService.service(this.activeView);
|
|
3563
4661
|
}
|
|
3564
|
-
get slotWidth() {
|
|
3565
|
-
return this.viewService.options.slotWidth;
|
|
3566
|
-
}
|
|
3567
|
-
ngOnChanges(changes) {
|
|
3568
|
-
if (isPresent(changes.dataItem)) {
|
|
3569
|
-
if (isPresent(changes.dataItem.previousValue)) {
|
|
3570
|
-
this.dependencyDomService.unregisterTask(changes.dataItem.previousValue);
|
|
3571
|
-
}
|
|
3572
|
-
this.dependencyDomService.registerTask(this.dataItem, this.taskElement.nativeElement);
|
|
3573
|
-
}
|
|
3574
|
-
else if (isPresent(changes.activeView)) {
|
|
3575
|
-
this.dependencyDomService.notifyChanges();
|
|
3576
|
-
}
|
|
3577
|
-
}
|
|
3578
|
-
ngOnDestroy() {
|
|
3579
|
-
if (isPresent(this.dataItem)) {
|
|
3580
|
-
this.dependencyDomService.unregisterTask(this.dataItem);
|
|
3581
|
-
}
|
|
3582
|
-
this.viewChangesSubscription.unsubscribe();
|
|
4662
|
+
get slotWidth() {
|
|
4663
|
+
return this.viewService.options.slotWidth;
|
|
3583
4664
|
}
|
|
3584
4665
|
get taskWidth() {
|
|
3585
4666
|
const itemDuration = this.mapper.extractFromTask(this.dataItem, 'end') - this.mapper.extractFromTask(this.dataItem, 'start');
|
|
@@ -3587,6 +4668,12 @@ class GanttTaskBase {
|
|
|
3587
4668
|
const width = durationInSlotUnits * this.slotWidth;
|
|
3588
4669
|
return width;
|
|
3589
4670
|
}
|
|
4671
|
+
/**
|
|
4672
|
+
* 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.
|
|
4673
|
+
* 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
|
|
4674
|
+
* and hovering just the .k-task element doesn't expose the drag clues.
|
|
4675
|
+
* Additionally, positioning the entire container takes care of positioning the hints as well.
|
|
4676
|
+
*/
|
|
3590
4677
|
get taskOffset() {
|
|
3591
4678
|
const timeAfterViewStart = this.mapper.extractFromTask(this.dataItem, 'start') - this.viewService.viewStart;
|
|
3592
4679
|
const offsetInSlotUnits = timeAfterViewStart / this.slotUnitDuration;
|
|
@@ -3598,11 +4685,48 @@ class GanttTaskBase {
|
|
|
3598
4685
|
// fall-back to 0 in case no completionRatio is provided
|
|
3599
4686
|
return isNumber(overlayWidth) ? overlayWidth : 0;
|
|
3600
4687
|
}
|
|
4688
|
+
ngOnChanges(changes) {
|
|
4689
|
+
if (isPresent(changes.dataItem)) {
|
|
4690
|
+
if (isPresent(changes.dataItem.previousValue)) {
|
|
4691
|
+
this.dependencyDomService.unregisterTask(changes.dataItem.previousValue);
|
|
4692
|
+
}
|
|
4693
|
+
this.dependencyDomService.registerTask(this.dataItem, this.taskElement.nativeElement);
|
|
4694
|
+
}
|
|
4695
|
+
else if (isPresent(changes.activeView)) {
|
|
4696
|
+
this.dependencyDomService.notifyChanges();
|
|
4697
|
+
}
|
|
4698
|
+
if (this.navigationService.enabled && isPresent(changes.index)) {
|
|
4699
|
+
this.updateActiveState(this.navigationService.activeTask);
|
|
4700
|
+
}
|
|
4701
|
+
}
|
|
4702
|
+
ngOnDestroy() {
|
|
4703
|
+
if (isPresent(this.dataItem)) {
|
|
4704
|
+
this.dependencyDomService.unregisterTask(this.dataItem);
|
|
4705
|
+
}
|
|
4706
|
+
this.subscriptions.unsubscribe();
|
|
4707
|
+
}
|
|
4708
|
+
updateActiveState({ activeIndex, isFocused }) {
|
|
4709
|
+
const isActive = activeIndex === this.index;
|
|
4710
|
+
const tabindex = isActive ? '0' : '-1';
|
|
4711
|
+
this.taskElement.nativeElement.setAttribute('tabindex', tabindex);
|
|
4712
|
+
if (isActive && isFocused) {
|
|
4713
|
+
this.taskElement.nativeElement.focus();
|
|
4714
|
+
this.taskElement.nativeElement.classList.add(FOCUSED_CLASS);
|
|
4715
|
+
}
|
|
4716
|
+
else {
|
|
4717
|
+
this.taskElement.nativeElement.classList.remove(FOCUSED_CLASS);
|
|
4718
|
+
}
|
|
4719
|
+
}
|
|
3601
4720
|
}
|
|
3602
4721
|
__decorate([
|
|
3603
4722
|
HostBinding('class.k-task-wrap'),
|
|
3604
4723
|
__metadata("design:type", Boolean)
|
|
3605
4724
|
], GanttTaskBase.prototype, "wrapperClass", void 0);
|
|
4725
|
+
__decorate([
|
|
4726
|
+
HostBinding('attr.data-task-index'),
|
|
4727
|
+
__metadata("design:type", Number),
|
|
4728
|
+
__metadata("design:paramtypes", [])
|
|
4729
|
+
], GanttTaskBase.prototype, "taskIndexAttribute", null);
|
|
3606
4730
|
__decorate([
|
|
3607
4731
|
ViewChild('task', { static: true }),
|
|
3608
4732
|
__metadata("design:type", ElementRef)
|
|
@@ -3615,6 +4739,18 @@ __decorate([
|
|
|
3615
4739
|
Input(),
|
|
3616
4740
|
__metadata("design:type", Number)
|
|
3617
4741
|
], GanttTaskBase.prototype, "index", void 0);
|
|
4742
|
+
__decorate([
|
|
4743
|
+
Input(),
|
|
4744
|
+
__metadata("design:type", Number)
|
|
4745
|
+
], GanttTaskBase.prototype, "level", void 0);
|
|
4746
|
+
__decorate([
|
|
4747
|
+
Input(),
|
|
4748
|
+
__metadata("design:type", Boolean)
|
|
4749
|
+
], GanttTaskBase.prototype, "renderDependencyDragClues", void 0);
|
|
4750
|
+
__decorate([
|
|
4751
|
+
Input(),
|
|
4752
|
+
__metadata("design:type", Boolean)
|
|
4753
|
+
], GanttTaskBase.prototype, "selectable", void 0);
|
|
3618
4754
|
__decorate([
|
|
3619
4755
|
Input(),
|
|
3620
4756
|
__metadata("design:type", Function)
|
|
@@ -3627,19 +4763,25 @@ __decorate([
|
|
|
3627
4763
|
Input(),
|
|
3628
4764
|
__metadata("design:type", Function)
|
|
3629
4765
|
], GanttTaskBase.prototype, "taskClass", void 0);
|
|
4766
|
+
__decorate([
|
|
4767
|
+
HostBinding('style.left.px'),
|
|
4768
|
+
__metadata("design:type", Number),
|
|
4769
|
+
__metadata("design:paramtypes", [])
|
|
4770
|
+
], GanttTaskBase.prototype, "taskOffset", null);
|
|
3630
4771
|
|
|
3631
4772
|
var GanttTaskComponent_1;
|
|
3632
4773
|
/**
|
|
3633
4774
|
* @hidden
|
|
3634
4775
|
*/
|
|
3635
4776
|
let GanttTaskComponent = GanttTaskComponent_1 = class GanttTaskComponent extends GanttTaskBase {
|
|
3636
|
-
constructor(mapper, timelineViewService, dependencyDomService, optionChangesService, cdr,
|
|
3637
|
-
super(mapper, timelineViewService, dependencyDomService, optionChangesService, cdr);
|
|
4777
|
+
constructor(editService, touchEnabled$$1, mapper, timelineViewService, dependencyDomService, optionChangesService, cdr, navigationService) {
|
|
4778
|
+
super(mapper, timelineViewService, dependencyDomService, optionChangesService, cdr, navigationService);
|
|
3638
4779
|
this.editService = editService;
|
|
4780
|
+
this.touchEnabled = touchEnabled$$1;
|
|
3639
4781
|
}
|
|
3640
4782
|
onTaskDelete() {
|
|
3641
4783
|
this.editService.dataItem = this.dataItem;
|
|
3642
|
-
this.editService.
|
|
4784
|
+
this.editService.taskDelete.next(this.dataItem);
|
|
3643
4785
|
}
|
|
3644
4786
|
};
|
|
3645
4787
|
__decorate([
|
|
@@ -3663,17 +4805,19 @@ GanttTaskComponent = GanttTaskComponent_1 = __decorate([
|
|
|
3663
4805
|
<div
|
|
3664
4806
|
#task
|
|
3665
4807
|
class="k-task k-task-single"
|
|
4808
|
+
role="treeitem"
|
|
3666
4809
|
[ngClass]="taskClass(dataItem)"
|
|
3667
4810
|
[style.width.px]="taskWidth"
|
|
3668
|
-
[style.left.px]="taskOffset"
|
|
3669
4811
|
[attr.title]="mapper.extractFromTask(dataItem, 'title')"
|
|
3670
|
-
[attr.data-task-index]="index"
|
|
3671
4812
|
[class.k-state-selected]="isSelected(dataItem)"
|
|
4813
|
+
[attr.aria-selected]="ariaSelected"
|
|
4814
|
+
[attr.aria-level]="level + 1"
|
|
3672
4815
|
>
|
|
3673
4816
|
<ng-container *ngIf="!taskTemplate">
|
|
3674
4817
|
<div
|
|
3675
4818
|
class="k-task-complete"
|
|
3676
4819
|
[style.width.px]="completionOverlayWidth"
|
|
4820
|
+
aria-hidden="true"
|
|
3677
4821
|
>
|
|
3678
4822
|
</div>
|
|
3679
4823
|
<div class="k-task-content">
|
|
@@ -3688,10 +4832,17 @@ GanttTaskComponent = GanttTaskComponent_1 = __decorate([
|
|
|
3688
4832
|
>
|
|
3689
4833
|
</ng-template>
|
|
3690
4834
|
</div>
|
|
3691
|
-
<span
|
|
4835
|
+
<span
|
|
4836
|
+
class="k-task-actions"
|
|
4837
|
+
aria-hidden="true"
|
|
4838
|
+
>
|
|
3692
4839
|
<span
|
|
3693
|
-
|
|
3694
|
-
|
|
4840
|
+
class="k-link k-task-delete"
|
|
4841
|
+
[kendoEventsOutsideAngular]="{
|
|
4842
|
+
click: onTaskDelete
|
|
4843
|
+
}"
|
|
4844
|
+
[scope]="this"
|
|
4845
|
+
>
|
|
3695
4846
|
<span class="k-icon k-i-close"></span>
|
|
3696
4847
|
</span>
|
|
3697
4848
|
</span>
|
|
@@ -3707,14 +4858,36 @@ GanttTaskComponent = GanttTaskComponent_1 = __decorate([
|
|
|
3707
4858
|
>
|
|
3708
4859
|
</ng-template>
|
|
3709
4860
|
</div>
|
|
3710
|
-
|
|
4861
|
+
<ng-container *ngIf="renderDependencyDragClues">
|
|
4862
|
+
<div
|
|
4863
|
+
class="k-task-dot k-task-start k-touch-action-none"
|
|
4864
|
+
[class.k-display-block]="touchEnabled"
|
|
4865
|
+
>
|
|
4866
|
+
</div>
|
|
4867
|
+
<div
|
|
4868
|
+
class="k-task-dot k-task-end k-touch-action-none"
|
|
4869
|
+
[class.k-display-block]="touchEnabled"
|
|
4870
|
+
>
|
|
4871
|
+
</div>
|
|
4872
|
+
</ng-container>
|
|
4873
|
+
`,
|
|
4874
|
+
styles: [`
|
|
4875
|
+
.k-task.k-focus {
|
|
4876
|
+
box-shadow: 0 0 4px 3px grey;
|
|
4877
|
+
outline: none;
|
|
4878
|
+
}
|
|
4879
|
+
.k-task.k-focus.k-state-selected {
|
|
4880
|
+
box-shadow: 0 0 4px 3px #ffaea8;
|
|
4881
|
+
}
|
|
4882
|
+
`]
|
|
3711
4883
|
}),
|
|
3712
|
-
|
|
4884
|
+
__param(1, Inject(TOUCH_ENABLED)),
|
|
4885
|
+
__metadata("design:paramtypes", [EditService, Boolean, MappingService,
|
|
3713
4886
|
TimelineViewService,
|
|
3714
4887
|
DependencyDomService,
|
|
3715
4888
|
OptionChangesService,
|
|
3716
4889
|
ChangeDetectorRef,
|
|
3717
|
-
|
|
4890
|
+
NavigationService])
|
|
3718
4891
|
], GanttTaskComponent);
|
|
3719
4892
|
|
|
3720
4893
|
var GanttSummaryTaskComponent_1;
|
|
@@ -3722,10 +4895,17 @@ var GanttSummaryTaskComponent_1;
|
|
|
3722
4895
|
* @hidden
|
|
3723
4896
|
*/
|
|
3724
4897
|
let GanttSummaryTaskComponent = GanttSummaryTaskComponent_1 = class GanttSummaryTaskComponent extends GanttTaskBase {
|
|
3725
|
-
constructor(mapper, timelineViewService, dependencyDomService, optionChangesService, cdr) {
|
|
3726
|
-
super(mapper, timelineViewService, dependencyDomService, optionChangesService, cdr);
|
|
4898
|
+
constructor(touchEnabled$$1, mapper, timelineViewService, dependencyDomService, optionChangesService, cdr, navigationService) {
|
|
4899
|
+
super(mapper, timelineViewService, dependencyDomService, optionChangesService, cdr, navigationService);
|
|
4900
|
+
this.touchEnabled = touchEnabled$$1;
|
|
3727
4901
|
this.summaryWrapperClass = true;
|
|
3728
4902
|
}
|
|
4903
|
+
get ariaExpanded() {
|
|
4904
|
+
// if no callback is provided, all child items are displayed and the item is regarded as expanded
|
|
4905
|
+
// replicates the TreeList aria-expanded behavior
|
|
4906
|
+
const isExpanded = !isPresent(this.isExpanded) || this.isExpanded(this.dataItem);
|
|
4907
|
+
return String(isExpanded);
|
|
4908
|
+
}
|
|
3729
4909
|
};
|
|
3730
4910
|
__decorate([
|
|
3731
4911
|
HostBinding('class.k-summary-wrap'),
|
|
@@ -3735,6 +4915,10 @@ __decorate([
|
|
|
3735
4915
|
Input(),
|
|
3736
4916
|
__metadata("design:type", TemplateRef)
|
|
3737
4917
|
], GanttSummaryTaskComponent.prototype, "template", void 0);
|
|
4918
|
+
__decorate([
|
|
4919
|
+
Input(),
|
|
4920
|
+
__metadata("design:type", Function)
|
|
4921
|
+
], GanttSummaryTaskComponent.prototype, "isExpanded", void 0);
|
|
3738
4922
|
GanttSummaryTaskComponent = GanttSummaryTaskComponent_1 = __decorate([
|
|
3739
4923
|
Component({
|
|
3740
4924
|
selector: 'kendo-gantt-summary-task',
|
|
@@ -3747,13 +4931,15 @@ GanttSummaryTaskComponent = GanttSummaryTaskComponent_1 = __decorate([
|
|
|
3747
4931
|
template: `
|
|
3748
4932
|
<div
|
|
3749
4933
|
#task
|
|
4934
|
+
role="treeitem"
|
|
3750
4935
|
class="k-task k-task-summary"
|
|
3751
4936
|
[ngClass]="taskClass(dataItem)"
|
|
3752
4937
|
[style.width.px]="taskWidth"
|
|
3753
|
-
[style.left.px]="taskOffset"
|
|
3754
4938
|
[attr.title]="mapper.extractFromTask(dataItem, 'title')"
|
|
3755
|
-
[attr.data-task-index]="index"
|
|
3756
4939
|
[class.k-state-selected]="isSelected(dataItem)"
|
|
4940
|
+
[attr.aria-selected]="ariaSelected"
|
|
4941
|
+
[attr.aria-expanded]="ariaExpanded"
|
|
4942
|
+
[attr.aria-level]="level + 1"
|
|
3757
4943
|
>
|
|
3758
4944
|
<div *ngIf="!template; else summaryTemplate"
|
|
3759
4945
|
class="k-task-summary-progress"
|
|
@@ -3774,13 +4960,36 @@ GanttSummaryTaskComponent = GanttSummaryTaskComponent_1 = __decorate([
|
|
|
3774
4960
|
>
|
|
3775
4961
|
</ng-template>
|
|
3776
4962
|
</div>
|
|
3777
|
-
|
|
4963
|
+
<ng-container *ngIf="renderDependencyDragClues">
|
|
4964
|
+
<div
|
|
4965
|
+
class="k-task-dot k-task-start k-touch-action-none"
|
|
4966
|
+
[class.k-display-block]="touchEnabled"
|
|
4967
|
+
>
|
|
4968
|
+
</div>
|
|
4969
|
+
<div
|
|
4970
|
+
class="k-task-dot k-task-end k-touch-action-none"
|
|
4971
|
+
[class.k-display-block]="touchEnabled"
|
|
4972
|
+
>
|
|
4973
|
+
</div>
|
|
4974
|
+
</ng-container>
|
|
4975
|
+
`,
|
|
4976
|
+
styles: [`
|
|
4977
|
+
.k-task.k-focus {
|
|
4978
|
+
box-shadow: 0 0 4px 3px grey;
|
|
4979
|
+
outline: none;
|
|
4980
|
+
}
|
|
4981
|
+
.k-task.k-focus.k-state-selected {
|
|
4982
|
+
box-shadow: 0 0 4px 3px #ffaea8;
|
|
4983
|
+
}
|
|
4984
|
+
`]
|
|
3778
4985
|
}),
|
|
3779
|
-
|
|
4986
|
+
__param(0, Inject(TOUCH_ENABLED)),
|
|
4987
|
+
__metadata("design:paramtypes", [Boolean, MappingService,
|
|
3780
4988
|
TimelineViewService,
|
|
3781
4989
|
DependencyDomService,
|
|
3782
4990
|
OptionChangesService,
|
|
3783
|
-
ChangeDetectorRef
|
|
4991
|
+
ChangeDetectorRef,
|
|
4992
|
+
NavigationService])
|
|
3784
4993
|
], GanttSummaryTaskComponent);
|
|
3785
4994
|
|
|
3786
4995
|
var GanttMilestoneTaskComponent_1;
|
|
@@ -3788,8 +4997,9 @@ var GanttMilestoneTaskComponent_1;
|
|
|
3788
4997
|
* @hidden
|
|
3789
4998
|
*/
|
|
3790
4999
|
let GanttMilestoneTaskComponent = GanttMilestoneTaskComponent_1 = class GanttMilestoneTaskComponent extends GanttTaskBase {
|
|
3791
|
-
constructor(mapper, timelineViewService, dependencyDomService, optionChangesService, cdr) {
|
|
3792
|
-
super(mapper, timelineViewService, dependencyDomService, optionChangesService, cdr);
|
|
5000
|
+
constructor(touchEnabled$$1, mapper, timelineViewService, dependencyDomService, optionChangesService, cdr, navigationService) {
|
|
5001
|
+
super(mapper, timelineViewService, dependencyDomService, optionChangesService, cdr, navigationService);
|
|
5002
|
+
this.touchEnabled = touchEnabled$$1;
|
|
3793
5003
|
this.milestoneWrapperClass = true;
|
|
3794
5004
|
}
|
|
3795
5005
|
};
|
|
@@ -3809,21 +5019,45 @@ GanttMilestoneTaskComponent = GanttMilestoneTaskComponent_1 = __decorate([
|
|
|
3809
5019
|
template: `
|
|
3810
5020
|
<div
|
|
3811
5021
|
#task
|
|
5022
|
+
role="treeitem"
|
|
3812
5023
|
class="k-task k-task-milestone"
|
|
3813
5024
|
[ngClass]="taskClass(dataItem)"
|
|
3814
|
-
[style.left.px]="taskOffset"
|
|
3815
5025
|
[attr.title]="mapper.extractFromTask(dataItem, 'title')"
|
|
3816
5026
|
[class.k-state-selected]="isSelected(dataItem)"
|
|
3817
|
-
[attr.
|
|
5027
|
+
[attr.aria-selected]="ariaSelected"
|
|
5028
|
+
[attr.aria-level]="level + 1"
|
|
3818
5029
|
>
|
|
3819
5030
|
</div>
|
|
3820
|
-
|
|
5031
|
+
<ng-container *ngIf="renderDependencyDragClues">
|
|
5032
|
+
<div
|
|
5033
|
+
class="k-task-dot k-task-start k-touch-action-none"
|
|
5034
|
+
[class.k-display-block]="touchEnabled"
|
|
5035
|
+
>
|
|
5036
|
+
</div>
|
|
5037
|
+
<div
|
|
5038
|
+
class="k-task-dot k-task-end k-touch-action-none"
|
|
5039
|
+
[class.k-display-block]="touchEnabled"
|
|
5040
|
+
>
|
|
5041
|
+
</div>
|
|
5042
|
+
</ng-container>
|
|
5043
|
+
`,
|
|
5044
|
+
styles: [`
|
|
5045
|
+
.k-task.k-focus {
|
|
5046
|
+
box-shadow: 0 0 4px 3px grey;
|
|
5047
|
+
outline: none;
|
|
5048
|
+
}
|
|
5049
|
+
.k-task.k-focus.k-state-selected {
|
|
5050
|
+
box-shadow: 0 0 4px 3px #ffaea8;
|
|
5051
|
+
}
|
|
5052
|
+
`]
|
|
3821
5053
|
}),
|
|
3822
|
-
|
|
5054
|
+
__param(0, Inject(TOUCH_ENABLED)),
|
|
5055
|
+
__metadata("design:paramtypes", [Boolean, MappingService,
|
|
3823
5056
|
TimelineViewService,
|
|
3824
5057
|
DependencyDomService,
|
|
3825
5058
|
OptionChangesService,
|
|
3826
|
-
ChangeDetectorRef
|
|
5059
|
+
ChangeDetectorRef,
|
|
5060
|
+
NavigationService])
|
|
3827
5061
|
], GanttMilestoneTaskComponent);
|
|
3828
5062
|
|
|
3829
5063
|
/**
|
|
@@ -4019,10 +5253,10 @@ SelectableDirective = __decorate([
|
|
|
4019
5253
|
* @hidden
|
|
4020
5254
|
*/
|
|
4021
5255
|
let ToolbarComponent = class ToolbarComponent {
|
|
4022
|
-
constructor(gantt
|
|
5256
|
+
constructor(gantt) {
|
|
4023
5257
|
this.gantt = gantt;
|
|
4024
|
-
this.scrollSyncService = scrollSyncService;
|
|
4025
5258
|
this.context = {};
|
|
5259
|
+
this.role = 'toolbar';
|
|
4026
5260
|
}
|
|
4027
5261
|
set position(value) {
|
|
4028
5262
|
this.context.position = this._position = value;
|
|
@@ -4038,13 +5272,14 @@ let ToolbarComponent = class ToolbarComponent {
|
|
|
4038
5272
|
const templatePosition = ganttToolbarTemplate ? ganttToolbarTemplate.position : null;
|
|
4039
5273
|
return ganttToolbarTemplate && (templatePosition === 'both' || templatePosition === this.position);
|
|
4040
5274
|
}
|
|
4041
|
-
|
|
4042
|
-
this.gantt.
|
|
4043
|
-
this.gantt.loadTimelineData();
|
|
4044
|
-
this.gantt.activeViewChange.emit(e);
|
|
4045
|
-
this.scrollSyncService.resetTimelineScrollLeft();
|
|
5275
|
+
handleViewChange(view) {
|
|
5276
|
+
this.gantt.changeActiveView(view);
|
|
4046
5277
|
}
|
|
4047
5278
|
};
|
|
5279
|
+
__decorate([
|
|
5280
|
+
HostBinding('attr.role'),
|
|
5281
|
+
__metadata("design:type", String)
|
|
5282
|
+
], ToolbarComponent.prototype, "role", void 0);
|
|
4048
5283
|
__decorate([
|
|
4049
5284
|
Input(),
|
|
4050
5285
|
__metadata("design:type", Boolean)
|
|
@@ -4069,7 +5304,7 @@ ToolbarComponent = __decorate([
|
|
|
4069
5304
|
*ngIf="showViewSelector"
|
|
4070
5305
|
[views]="gantt.viewTypes"
|
|
4071
5306
|
[activeView]="gantt.activeView"
|
|
4072
|
-
(activeViewChange)="
|
|
5307
|
+
(activeViewChange)="handleViewChange($event)"></kendo-gantt-view-selector>
|
|
4073
5308
|
</ng-container>
|
|
4074
5309
|
<ng-template
|
|
4075
5310
|
*ngIf="renderTemplate"
|
|
@@ -4079,8 +5314,7 @@ ToolbarComponent = __decorate([
|
|
|
4079
5314
|
</ng-template>
|
|
4080
5315
|
`
|
|
4081
5316
|
}),
|
|
4082
|
-
__metadata("design:paramtypes", [GanttComponent
|
|
4083
|
-
ScrollSyncService])
|
|
5317
|
+
__metadata("design:paramtypes", [GanttComponent])
|
|
4084
5318
|
], ToolbarComponent);
|
|
4085
5319
|
|
|
4086
5320
|
/**
|
|
@@ -4135,7 +5369,9 @@ ViewSelectorComponent = __decorate([
|
|
|
4135
5369
|
Component({
|
|
4136
5370
|
selector: 'kendo-gantt-view-selector',
|
|
4137
5371
|
template: `
|
|
4138
|
-
<select
|
|
5372
|
+
<select
|
|
5373
|
+
class="k-dropdownlist k-picker k-rounded-md k-views-dropdown"
|
|
5374
|
+
aria-label="View Selector"
|
|
4139
5375
|
[value]="activeView"
|
|
4140
5376
|
(change)="activeViewChange.emit($event.target.value)">
|
|
4141
5377
|
<option *ngFor="let view of views" [value]="view">{{getViewTypeText(view)}}</option>
|
|
@@ -4162,6 +5398,9 @@ const getOffsetRelativeToParent = (element, targetParent) => {
|
|
|
4162
5398
|
top: 0,
|
|
4163
5399
|
left: 0
|
|
4164
5400
|
};
|
|
5401
|
+
if (!targetParent.contains(element)) {
|
|
5402
|
+
return offset;
|
|
5403
|
+
}
|
|
4165
5404
|
let offsetParent = element;
|
|
4166
5405
|
while (offsetParent && offsetParent !== targetParent) {
|
|
4167
5406
|
offset.top += offsetParent.offsetTop;
|
|
@@ -4195,9 +5434,9 @@ const dependencyCoordinates = (from, to, rowHeight, type, minDistanceBeforeTurn,
|
|
|
4195
5434
|
| |
|
|
4196
5435
|
[[[]]]- -[[[]]]
|
|
4197
5436
|
*/
|
|
4198
|
-
if (type ===
|
|
5437
|
+
if (type === DependencyType.FF || type === DependencyType.SS) {
|
|
4199
5438
|
// polyline start from first task
|
|
4200
|
-
const dir = type ===
|
|
5439
|
+
const dir = type === DependencyType.SS ? 'left' : 'right';
|
|
4201
5440
|
top = from.top;
|
|
4202
5441
|
left = from[dir];
|
|
4203
5442
|
points.push({ top, left });
|
|
@@ -4223,9 +5462,9 @@ const dependencyCoordinates = (from, to, rowHeight, type, minDistanceBeforeTurn,
|
|
|
4223
5462
|
|
|
|
4224
5463
|
-[[[]]]
|
|
4225
5464
|
*/
|
|
4226
|
-
const startDir = type ===
|
|
4227
|
-
const endDir = type ===
|
|
4228
|
-
const additionalTurn = type ===
|
|
5465
|
+
const startDir = type === DependencyType.SF ? 'left' : 'right';
|
|
5466
|
+
const endDir = type === DependencyType.SF ? 'right' : 'left';
|
|
5467
|
+
const additionalTurn = type === DependencyType.SF
|
|
4229
5468
|
? from[startDir] - minDistanceBeforeTurn * 2 < to[endDir]
|
|
4230
5469
|
: from[startDir] + minDistanceBeforeTurn * 2 > to[endDir];
|
|
4231
5470
|
// polyline start from first task
|
|
@@ -4308,80 +5547,645 @@ const getArrowEast = (top, left, arrowSize) => {
|
|
|
4308
5547
|
});
|
|
4309
5548
|
return points;
|
|
4310
5549
|
};
|
|
5550
|
+
/**
|
|
5551
|
+
* @hidden
|
|
5552
|
+
*
|
|
5553
|
+
* Translates the provided client `left` and `top` coords to coords relative to the provided container.
|
|
5554
|
+
* https://developer.mozilla.org/en-US/docs/Web/CSS/CSSOM_View/Coordinate_systems#standard_cssom_coordinate_systems
|
|
5555
|
+
*/
|
|
5556
|
+
const clientToOffsetCoords = (clientLeft, clientTop, offsetContainer) => {
|
|
5557
|
+
// client (viewport) coordinates of the target container
|
|
5558
|
+
// https://developer.mozilla.org/en-US/docs/Web/API/Element/getBoundingClientRect#value
|
|
5559
|
+
const offsetContainerClientRect = offsetContainer.getBoundingClientRect();
|
|
5560
|
+
return {
|
|
5561
|
+
left: clientLeft - offsetContainerClientRect.left + offsetContainer.scrollLeft,
|
|
5562
|
+
top: clientTop - offsetContainerClientRect.top + offsetContainer.scrollTop
|
|
5563
|
+
};
|
|
5564
|
+
};
|
|
5565
|
+
/**
|
|
5566
|
+
* @hidden
|
|
5567
|
+
*
|
|
5568
|
+
* Retrieves the `left` and `top` values of the center of the provided element.
|
|
5569
|
+
* The retrieved values are relative to the current viewport (client values).
|
|
5570
|
+
* https://developer.mozilla.org/en-US/docs/Web/CSS/CSSOM_View/Coordinate_systems#standard_cssom_coordinate_systems
|
|
5571
|
+
*/
|
|
5572
|
+
const getElementClientCenterCoords = (element) => {
|
|
5573
|
+
// client (viewport) coordinates of the targeted element
|
|
5574
|
+
// https://developer.mozilla.org/en-US/docs/Web/API/Element/getBoundingClientRect#value
|
|
5575
|
+
const { left, top, width, height } = element.getBoundingClientRect();
|
|
5576
|
+
return {
|
|
5577
|
+
left: left + (width / 2),
|
|
5578
|
+
top: top + (height / 2)
|
|
5579
|
+
};
|
|
5580
|
+
};
|
|
5581
|
+
|
|
5582
|
+
/**
|
|
5583
|
+
* Defines the size of the arrow that will be drawn at the end of each Gantt dependency.
|
|
5584
|
+
*/
|
|
5585
|
+
const ARROW_SIZE = 4;
|
|
5586
|
+
/**
|
|
5587
|
+
* Defines the distance the polyline will cover from the task element before making a turn.
|
|
5588
|
+
*/
|
|
5589
|
+
const MIN_DISTANCE_BEFORE_TURN = 10;
|
|
5590
|
+
/**
|
|
5591
|
+
* @hidden
|
|
5592
|
+
*/
|
|
5593
|
+
let GanttDependencyDirective = class GanttDependencyDirective {
|
|
5594
|
+
constructor(polyline, zone, renderer, mapper, dependencyDomService) {
|
|
5595
|
+
this.polyline = polyline;
|
|
5596
|
+
this.zone = zone;
|
|
5597
|
+
this.renderer = renderer;
|
|
5598
|
+
this.mapper = mapper;
|
|
5599
|
+
this.dependencyDomService = dependencyDomService;
|
|
5600
|
+
this.subscriptions = new Subscription();
|
|
5601
|
+
this.subscriptions.add(dependencyDomService.taskChanges
|
|
5602
|
+
.pipe(switchMap(changes =>
|
|
5603
|
+
// reacts only on the very last event emission,
|
|
5604
|
+
// ensures that the tasks are drawn in the DOM
|
|
5605
|
+
this.zone.onStable.pipe(take(1), map(() => changes))))
|
|
5606
|
+
.subscribe(changes => this.updatePoints(changes)));
|
|
5607
|
+
}
|
|
5608
|
+
ngOnDestroy() {
|
|
5609
|
+
this.subscriptions.unsubscribe();
|
|
5610
|
+
}
|
|
5611
|
+
ngOnChanges(changes) {
|
|
5612
|
+
if (isPresent(changes.dependency)) {
|
|
5613
|
+
this.updatePoints(this.dependencyDomService.dependencyDomArgs);
|
|
5614
|
+
}
|
|
5615
|
+
}
|
|
5616
|
+
updatePoints({ timelineRow, contentContainer, tasks }) {
|
|
5617
|
+
if (!isPresent(timelineRow) || !isPresent(contentContainer) ||
|
|
5618
|
+
!isPresent(tasks) || tasks.size === 0 ||
|
|
5619
|
+
!tasks.has(this.mapper.extractFromDependency(this.dependency, 'fromId')) || !tasks.has(this.mapper.extractFromDependency(this.dependency, 'toId'))) {
|
|
5620
|
+
this.clearPoints();
|
|
5621
|
+
return;
|
|
5622
|
+
}
|
|
5623
|
+
const fromCoordinates = getElementRect(tasks.get(this.mapper.extractFromDependency(this.dependency, 'fromId')), contentContainer);
|
|
5624
|
+
const toCoordinates = getElementRect(tasks.get(this.mapper.extractFromDependency(this.dependency, 'toId')), contentContainer);
|
|
5625
|
+
const timelineRowHeight = isDocumentAvailable() ? timelineRow.getBoundingClientRect().height : 0;
|
|
5626
|
+
const points = dependencyCoordinates(fromCoordinates, toCoordinates, timelineRowHeight, this.dependency.type, MIN_DISTANCE_BEFORE_TURN, ARROW_SIZE);
|
|
5627
|
+
this.drawPoints(points);
|
|
5628
|
+
}
|
|
5629
|
+
clearPoints() {
|
|
5630
|
+
this.renderer.setAttribute(this.polyline.nativeElement, 'points', '');
|
|
5631
|
+
}
|
|
5632
|
+
drawPoints(points) {
|
|
5633
|
+
if (!isPresent(points) || points.length === 0) {
|
|
5634
|
+
this.clearPoints();
|
|
5635
|
+
return;
|
|
5636
|
+
}
|
|
5637
|
+
const parsedCoords = points.map(({ left, top }) => `${left},${top}`).join(' ');
|
|
5638
|
+
this.renderer.setAttribute(this.polyline.nativeElement, 'points', parsedCoords);
|
|
5639
|
+
}
|
|
5640
|
+
};
|
|
5641
|
+
__decorate([
|
|
5642
|
+
Input(),
|
|
5643
|
+
__metadata("design:type", Object)
|
|
5644
|
+
], GanttDependencyDirective.prototype, "dependency", void 0);
|
|
5645
|
+
GanttDependencyDirective = __decorate([
|
|
5646
|
+
Directive({
|
|
5647
|
+
selector: '[kendoGanttDependency]'
|
|
5648
|
+
}),
|
|
5649
|
+
__metadata("design:paramtypes", [ElementRef,
|
|
5650
|
+
NgZone,
|
|
5651
|
+
Renderer2,
|
|
5652
|
+
MappingService,
|
|
5653
|
+
DependencyDomService])
|
|
5654
|
+
], GanttDependencyDirective);
|
|
5655
|
+
|
|
5656
|
+
/**
|
|
5657
|
+
* @hidden
|
|
5658
|
+
*/
|
|
5659
|
+
let DragValidationTooltipComponent = class DragValidationTooltipComponent {
|
|
5660
|
+
/**
|
|
5661
|
+
* @hidden
|
|
5662
|
+
*/
|
|
5663
|
+
constructor() {
|
|
5664
|
+
/**
|
|
5665
|
+
* Sets the status class of the attempted operation.
|
|
5666
|
+
* Note that the status will be ignored and the `neutral` status class will be rendered,
|
|
5667
|
+
* if the any of the fromTaskName or toTaskName are not populated.
|
|
5668
|
+
*/
|
|
5669
|
+
this.isValid = false;
|
|
5670
|
+
}
|
|
5671
|
+
};
|
|
5672
|
+
DragValidationTooltipComponent = __decorate([
|
|
5673
|
+
Component({
|
|
5674
|
+
template: `
|
|
5675
|
+
<div
|
|
5676
|
+
class="k-tooltip k-gantt-tooltip-validation"
|
|
5677
|
+
[class.k-gantt-tooltip-valid]="showValidityStatus && isValid"
|
|
5678
|
+
[class.k-gantt-tooltip-invalid]="showValidityStatus && !isValid"
|
|
5679
|
+
>
|
|
5680
|
+
<div class="k-gantt-tooltip-validation-row">
|
|
5681
|
+
<span class="k-gantt-tooltip-validation-label">From:</span>
|
|
5682
|
+
<span class="k-gantt-tooltip-validation-value">{{ fromTaskName }}</span>
|
|
5683
|
+
</div>
|
|
5684
|
+
<div class="k-gantt-tooltip-validation-row">
|
|
5685
|
+
<span class="k-gantt-tooltip-validation-label">To:</span>
|
|
5686
|
+
<span class="k-gantt-tooltip-validation-value">{{ toTaskName }}</span>
|
|
5687
|
+
</div>
|
|
5688
|
+
</div>
|
|
5689
|
+
`,
|
|
5690
|
+
styles: [`
|
|
5691
|
+
.k-gantt-tooltip-validation {
|
|
5692
|
+
max-width: 200px;
|
|
5693
|
+
display: block;
|
|
5694
|
+
}
|
|
5695
|
+
.k-gantt-tooltip-validation::before {
|
|
5696
|
+
content: '';
|
|
5697
|
+
position: absolute;
|
|
5698
|
+
left: 0;
|
|
5699
|
+
top: 0;
|
|
5700
|
+
width: 4px;
|
|
5701
|
+
height: 100%;
|
|
5702
|
+
background: #656565;
|
|
5703
|
+
}
|
|
5704
|
+
.k-gantt-tooltip-validation.k-gantt-tooltip-valid::before {
|
|
5705
|
+
background: #37B400;
|
|
5706
|
+
}
|
|
5707
|
+
.k-gantt-tooltip-validation.k-gantt-tooltip-invalid::before {
|
|
5708
|
+
background: #F31700;
|
|
5709
|
+
}
|
|
5710
|
+
.k-gantt-tooltip-validation-row {
|
|
5711
|
+
white-space: nowrap;
|
|
5712
|
+
overflow: hidden;
|
|
5713
|
+
text-overflow: ellipsis;
|
|
5714
|
+
}
|
|
5715
|
+
.k-gantt-tooltip-validation-label {
|
|
5716
|
+
display: inline-flex;
|
|
5717
|
+
width: 50px;
|
|
5718
|
+
}
|
|
5719
|
+
.k-gantt-tooltip-validation-value {
|
|
5720
|
+
font-weight: bold;
|
|
5721
|
+
}
|
|
5722
|
+
`]
|
|
5723
|
+
})
|
|
5724
|
+
], DragValidationTooltipComponent);
|
|
5725
|
+
|
|
5726
|
+
/**
|
|
5727
|
+
* When added to the .k-task-dot, the element will be kept with hover styles.
|
|
5728
|
+
* Used for the drag clue from which the dragging has started.
|
|
5729
|
+
*/
|
|
5730
|
+
const DRAG_CLUE_HOVER_CLASS = 'k-state-hover';
|
|
5731
|
+
/**
|
|
5732
|
+
* Add the selection disabling class to the enitre container.
|
|
5733
|
+
* Otherwise existing selection on a given task text prevents dragging the clue even if the clue has `user-select: none` styles.
|
|
5734
|
+
*/
|
|
5735
|
+
const USER_SELECT_NONE_CLASS = 'k-user-select-none';
|
|
5736
|
+
/**
|
|
5737
|
+
* When added to the .k-task-wrap, the containing .k-task-dot elements will be kept visible even when not hovered.
|
|
5738
|
+
* Used for the drag clue from which the dragging has started.
|
|
5739
|
+
*/
|
|
5740
|
+
const TASK_WRAPPER_DRAG_CLASS = 'k-origin';
|
|
5741
|
+
/**
|
|
5742
|
+
* Use 20px margin between the pointer and the popup.
|
|
5743
|
+
* Could be made user-configurable if there's demand.
|
|
5744
|
+
*/
|
|
5745
|
+
const DEFAULT_POPUP_VERTICAL_MARGIN = 20;
|
|
5746
|
+
/**
|
|
5747
|
+
* A directive which enables the creation of new dependencies via dragging.
|
|
5748
|
+
*/
|
|
5749
|
+
let DependencyDragCreateDirective = class DependencyDragCreateDirective {
|
|
5750
|
+
constructor(gantt, zone, renderer, mapper, popupService, timelineScrollService) {
|
|
5751
|
+
this.gantt = gantt;
|
|
5752
|
+
this.zone = zone;
|
|
5753
|
+
this.renderer = renderer;
|
|
5754
|
+
this.mapper = mapper;
|
|
5755
|
+
this.popupService = popupService;
|
|
5756
|
+
this.timelineScrollService = timelineScrollService;
|
|
5757
|
+
/**
|
|
5758
|
+
* Specifies whether the validation tooltip will be displayed during drag operations.
|
|
5759
|
+
*
|
|
5760
|
+
* @default true
|
|
5761
|
+
*/
|
|
5762
|
+
this.displayValidationTooltip = true;
|
|
5763
|
+
this.gantt.renderDependencyDragClues = true;
|
|
5764
|
+
}
|
|
5765
|
+
get container() {
|
|
5766
|
+
if (!isPresent(this.gantt.timeline) || !isPresent(this.gantt.timeline.timelineContent)) {
|
|
5767
|
+
return null;
|
|
5768
|
+
}
|
|
5769
|
+
return this.gantt.timeline.timelineContent.nativeElement;
|
|
5770
|
+
}
|
|
5771
|
+
get polyline() {
|
|
5772
|
+
if (!isPresent(this.gantt.timeline) || !isPresent(this.gantt.timeline.dependencyDragCreatePolyline)) {
|
|
5773
|
+
return null;
|
|
5774
|
+
}
|
|
5775
|
+
return this.gantt.timeline.dependencyDragCreatePolyline.nativeElement;
|
|
5776
|
+
}
|
|
5777
|
+
get popupContainer() {
|
|
5778
|
+
if (!isPresent(this.gantt.timeline) || !isPresent(this.gantt.timeline.dragPopupContainer)) {
|
|
5779
|
+
return null;
|
|
5780
|
+
}
|
|
5781
|
+
return this.gantt.timeline.dragPopupContainer;
|
|
5782
|
+
}
|
|
5783
|
+
ngAfterViewInit() {
|
|
5784
|
+
this.subscribeDraggable();
|
|
5785
|
+
this.addScrollListener();
|
|
5786
|
+
}
|
|
5787
|
+
ngOnDestroy() {
|
|
5788
|
+
this.unsubscribeDraggable();
|
|
5789
|
+
this.removeScrollListener();
|
|
5790
|
+
this.fromTaskClue = null;
|
|
5791
|
+
this.cancelScroll();
|
|
5792
|
+
this.closeDragPopup();
|
|
5793
|
+
}
|
|
5794
|
+
subscribeDraggable() {
|
|
5795
|
+
this.dragSubscriptions = this.gantt.timeline.timelineContainerPress
|
|
5796
|
+
.subscribe(this.handlePress.bind(this));
|
|
5797
|
+
this.dragSubscriptions.add(this.gantt.timeline.timelineContainerDrag
|
|
5798
|
+
.subscribe(this.handleDrag.bind(this)));
|
|
5799
|
+
this.dragSubscriptions.add(this.gantt.timeline.timelineContainerRelease
|
|
5800
|
+
.subscribe(this.handleRelease.bind(this)));
|
|
5801
|
+
}
|
|
5802
|
+
unsubscribeDraggable() {
|
|
5803
|
+
if (isPresent(this.dragSubscriptions)) {
|
|
5804
|
+
this.dragSubscriptions.unsubscribe();
|
|
5805
|
+
this.dragSubscriptions = null;
|
|
5806
|
+
}
|
|
5807
|
+
}
|
|
5808
|
+
handlePress({ clientX, clientY }) {
|
|
5809
|
+
// using `originalEvent.target` is not reliable under mobile devices with the current implementation of the draggable, so use this instead
|
|
5810
|
+
const target = elementFromPoint(clientX, clientY);
|
|
5811
|
+
if (isDependencyDragClue(target)) {
|
|
5812
|
+
this.fromTaskClue = target;
|
|
5813
|
+
this.assignDragStartClasses(this.fromTaskClue);
|
|
5814
|
+
// use the center of the target clue as polyline starting point
|
|
5815
|
+
const dragClueCenterCoords = getElementClientCenterCoords(this.fromTaskClue);
|
|
5816
|
+
// the polyline uses `position: aboslute`, so translate the client coordinates to offset coordinates (`left` and `top` relative to the timeline container)
|
|
5817
|
+
this.polylineStartCoords = clientToOffsetCoords(dragClueCenterCoords.left, dragClueCenterCoords.top, this.container);
|
|
5818
|
+
}
|
|
5819
|
+
}
|
|
5820
|
+
handleDrag({ clientX, clientY }) {
|
|
5821
|
+
if (isPresent(this.fromTaskClue)) {
|
|
5822
|
+
// the polyline uses `position: aboslute`, so translate the client coordinates to offset coordinates (`left` and `top` relative to the timeline container)
|
|
5823
|
+
const pointerOffsetCoords = clientToOffsetCoords(clientX, clientY, this.container);
|
|
5824
|
+
// the start coords are calculated just once per drag session in handlePress
|
|
5825
|
+
// use the current drag coords as polyline end coords
|
|
5826
|
+
this.updatePolyline(this.polylineStartCoords, pointerOffsetCoords);
|
|
5827
|
+
this.currentPointerClientCoords = { left: clientX, top: clientY };
|
|
5828
|
+
if (this.gantt.dragScrollSettings.enabled) {
|
|
5829
|
+
// use client coordinates for scroll trigger
|
|
5830
|
+
this.scrollPointIntoView(this.currentPointerClientCoords);
|
|
5831
|
+
}
|
|
5832
|
+
if (this.displayValidationTooltip) {
|
|
5833
|
+
this.updateDragPopup(pointerOffsetCoords);
|
|
5834
|
+
}
|
|
5835
|
+
}
|
|
5836
|
+
}
|
|
5837
|
+
handleRelease({ clientX, clientY }) {
|
|
5838
|
+
if (!isPresent(this.fromTaskClue)) {
|
|
5839
|
+
return;
|
|
5840
|
+
}
|
|
5841
|
+
// using `originalEvent.target` is not reliable under mobile devices with the current implementation of the draggable, so use this instead
|
|
5842
|
+
const target = elementFromPoint(clientX, clientY);
|
|
5843
|
+
if (isDependencyDragClue(target) && !sameTaskClues(this.fromTaskClue, target, this.container)) {
|
|
5844
|
+
this.zone.run(() => {
|
|
5845
|
+
const fromTaskClue = this.fromTaskClue;
|
|
5846
|
+
const toTaskClue = target;
|
|
5847
|
+
const fromTask = this.gantt.renderedTreeListItems[getClosestTaskIndex(fromTaskClue, this.container)];
|
|
5848
|
+
const toTask = this.gantt.renderedTreeListItems[getClosestTaskIndex(toTaskClue, this.container)];
|
|
5849
|
+
const dependencyType = getDependencyTypeFromTargetTasks(fromTaskClue, toTaskClue);
|
|
5850
|
+
const { fromId, toId, type } = this.mapper.dependencyFields;
|
|
5851
|
+
this.gantt.dependencyAdd.emit({
|
|
5852
|
+
fromTask: fromTask,
|
|
5853
|
+
toTask: toTask,
|
|
5854
|
+
type: dependencyType,
|
|
5855
|
+
isValid: this.gantt.validateNewDependency({
|
|
5856
|
+
[fromId]: this.mapper.extractFromTask(fromTask, 'id'),
|
|
5857
|
+
[toId]: this.mapper.extractFromTask(toTask, 'id'),
|
|
5858
|
+
[type]: dependencyType
|
|
5859
|
+
})
|
|
5860
|
+
});
|
|
5861
|
+
});
|
|
5862
|
+
}
|
|
5863
|
+
this.clearPolyline();
|
|
5864
|
+
this.removeDragStartClasses(this.fromTaskClue);
|
|
5865
|
+
this.fromTaskClue = null;
|
|
5866
|
+
this.cancelScroll();
|
|
5867
|
+
this.closeDragPopup();
|
|
5868
|
+
}
|
|
5869
|
+
updatePolyline(start, end) {
|
|
5870
|
+
const points = `${start.left},${start.top} ${end.left},${end.top}`;
|
|
5871
|
+
this.renderer.setAttribute(this.polyline, 'points', points);
|
|
5872
|
+
}
|
|
5873
|
+
clearPolyline() {
|
|
5874
|
+
this.renderer.removeAttribute(this.polyline, 'points');
|
|
5875
|
+
}
|
|
5876
|
+
assignDragStartClasses(dragClue) {
|
|
5877
|
+
if (!isPresent(dragClue)) {
|
|
5878
|
+
return;
|
|
5879
|
+
}
|
|
5880
|
+
this.renderer.addClass(this.container, USER_SELECT_NONE_CLASS);
|
|
5881
|
+
this.renderer.addClass(dragClue, DRAG_CLUE_HOVER_CLASS);
|
|
5882
|
+
const taskWrapper = getClosestTaskWrapper(dragClue, this.container);
|
|
5883
|
+
if (isPresent(taskWrapper)) {
|
|
5884
|
+
this.renderer.addClass(taskWrapper, TASK_WRAPPER_DRAG_CLASS);
|
|
5885
|
+
}
|
|
5886
|
+
}
|
|
5887
|
+
removeDragStartClasses(dragClue) {
|
|
5888
|
+
if (!isPresent(dragClue)) {
|
|
5889
|
+
return;
|
|
5890
|
+
}
|
|
5891
|
+
this.renderer.removeClass(this.container, USER_SELECT_NONE_CLASS);
|
|
5892
|
+
this.renderer.removeClass(dragClue, DRAG_CLUE_HOVER_CLASS);
|
|
5893
|
+
const taskWrapper = getClosestTaskWrapper(dragClue, this.container);
|
|
5894
|
+
if (isPresent(taskWrapper)) {
|
|
5895
|
+
this.renderer.removeClass(taskWrapper, TASK_WRAPPER_DRAG_CLASS);
|
|
5896
|
+
}
|
|
5897
|
+
}
|
|
5898
|
+
scrollPointIntoView({ left, top }) {
|
|
5899
|
+
this.timelineScrollService.requestScrollCancel();
|
|
5900
|
+
this.timelineScrollService.requestHorizontalScroll(left);
|
|
5901
|
+
this.timelineScrollService.requestVerticalScroll(top);
|
|
5902
|
+
}
|
|
5903
|
+
cancelScroll() {
|
|
5904
|
+
this.timelineScrollService.requestScrollCancel();
|
|
5905
|
+
}
|
|
5906
|
+
addScrollListener() {
|
|
5907
|
+
if (!isDocumentAvailable()) {
|
|
5908
|
+
return;
|
|
5909
|
+
}
|
|
5910
|
+
this.zone.runOutsideAngular(() => this.scrollListenerDisposer = this.renderer.listen(this.container, 'scroll', () => {
|
|
5911
|
+
// update the polyline only if we're currently dragging
|
|
5912
|
+
if (isPresent(this.fromTaskClue) && isPresent(this.currentPointerClientCoords)) {
|
|
5913
|
+
const { left, top } = this.currentPointerClientCoords;
|
|
5914
|
+
const pointerOffsetCoords = clientToOffsetCoords(left, top, this.container);
|
|
5915
|
+
this.updatePolyline(this.polylineStartCoords, pointerOffsetCoords);
|
|
5916
|
+
if (this.displayValidationTooltip) {
|
|
5917
|
+
this.updateDragPopup(pointerOffsetCoords);
|
|
5918
|
+
}
|
|
5919
|
+
}
|
|
5920
|
+
}));
|
|
5921
|
+
}
|
|
5922
|
+
removeScrollListener() {
|
|
5923
|
+
if (isPresent(this.scrollListenerDisposer)) {
|
|
5924
|
+
this.scrollListenerDisposer();
|
|
5925
|
+
this.scrollListenerDisposer = null;
|
|
5926
|
+
}
|
|
5927
|
+
}
|
|
5928
|
+
openDragPopup() {
|
|
5929
|
+
if (isPresent(this.dragPopup)) {
|
|
5930
|
+
this.closeDragPopup();
|
|
5931
|
+
}
|
|
5932
|
+
this.dragPopup = this.popupService.open({
|
|
5933
|
+
animate: false,
|
|
5934
|
+
content: DragValidationTooltipComponent,
|
|
5935
|
+
appendTo: this.popupContainer,
|
|
5936
|
+
positionMode: 'absolute',
|
|
5937
|
+
popupClass: 'k-popup-transparent'
|
|
5938
|
+
});
|
|
5939
|
+
}
|
|
5940
|
+
updateDragPopup(pointerOffsetPosition) {
|
|
5941
|
+
if (!isPresent(this.dragPopup)) {
|
|
5942
|
+
this.openDragPopup();
|
|
5943
|
+
}
|
|
5944
|
+
const tooltip = this.dragPopup.content.instance;
|
|
5945
|
+
const { fromTaskName, toTaskName, isValid, showValidityStatus } = this.getTooltipContext();
|
|
5946
|
+
if (tooltip.fromTaskName !== fromTaskName ||
|
|
5947
|
+
tooltip.toTaskName !== toTaskName ||
|
|
5948
|
+
tooltip.isValid !== isValid ||
|
|
5949
|
+
tooltip.showValidityStatus !== showValidityStatus) {
|
|
5950
|
+
tooltip.fromTaskName = fromTaskName;
|
|
5951
|
+
tooltip.toTaskName = toTaskName;
|
|
5952
|
+
tooltip.isValid = isValid;
|
|
5953
|
+
tooltip.showValidityStatus = showValidityStatus;
|
|
5954
|
+
this.dragPopup.content.changeDetectorRef.detectChanges();
|
|
5955
|
+
}
|
|
5956
|
+
this.dragPopup.popup.instance.offset = this.normalizePopupPosition(pointerOffsetPosition);
|
|
5957
|
+
this.dragPopup.popup.changeDetectorRef.detectChanges();
|
|
5958
|
+
}
|
|
5959
|
+
closeDragPopup() {
|
|
5960
|
+
if (isPresent(this.dragPopup)) {
|
|
5961
|
+
this.dragPopup.close();
|
|
5962
|
+
this.dragPopup = null;
|
|
5963
|
+
}
|
|
5964
|
+
}
|
|
5965
|
+
extractTaskName(target) {
|
|
5966
|
+
if (!isTaskWrapper(target, this.container)) {
|
|
5967
|
+
return null;
|
|
5968
|
+
}
|
|
5969
|
+
const taskIndex = getClosestTaskIndex(target, this.container);
|
|
5970
|
+
const task = this.gantt.renderedTreeListItems[taskIndex];
|
|
5971
|
+
const taskName = this.mapper.extractFromTask(task, 'title');
|
|
5972
|
+
return taskName;
|
|
5973
|
+
}
|
|
5974
|
+
getTooltipContext() {
|
|
5975
|
+
const fromTaskName = this.extractTaskName(this.fromTaskClue);
|
|
5976
|
+
const currentPointerTarget = elementFromPoint(this.currentPointerClientCoords.left, this.currentPointerClientCoords.top);
|
|
5977
|
+
const toTaskName = isTaskWrapper(currentPointerTarget, this.container) && !sameTaskClues(this.fromTaskClue, currentPointerTarget, this.container) ?
|
|
5978
|
+
this.extractTaskName(currentPointerTarget) :
|
|
5979
|
+
'';
|
|
5980
|
+
const showValidityStatus = isDependencyDragClue(currentPointerTarget) && !sameTaskClues(this.fromTaskClue, currentPointerTarget, this.container);
|
|
5981
|
+
const { fromId, toId, type } = this.mapper.dependencyFields;
|
|
5982
|
+
return {
|
|
5983
|
+
fromTaskName,
|
|
5984
|
+
toTaskName,
|
|
5985
|
+
showValidityStatus,
|
|
5986
|
+
isValid: showValidityStatus && this.gantt.validateNewDependency({
|
|
5987
|
+
[fromId]: this.mapper.extractFromTask(this.gantt.renderedTreeListItems[getClosestTaskIndex(this.fromTaskClue, this.container)], 'id'),
|
|
5988
|
+
[toId]: this.mapper.extractFromTask(this.gantt.renderedTreeListItems[getClosestTaskIndex(currentPointerTarget, this.container)], 'id'),
|
|
5989
|
+
[type]: getDependencyTypeFromTargetTasks(this.fromTaskClue, currentPointerTarget)
|
|
5990
|
+
})
|
|
5991
|
+
};
|
|
5992
|
+
}
|
|
5993
|
+
/**
|
|
5994
|
+
* Restricts the popup position to not go below the scroll height or width of the container.
|
|
5995
|
+
* Flips the position of the popup when there's not enough vertical space in the visible part of the container to render the popup.
|
|
5996
|
+
*/
|
|
5997
|
+
normalizePopupPosition(pointerOffsetPosition) {
|
|
5998
|
+
let top = pointerOffsetPosition.top + DEFAULT_POPUP_VERTICAL_MARGIN;
|
|
5999
|
+
const containerClientBottom = this.container.clientHeight + this.container.scrollTop;
|
|
6000
|
+
const popupHeight = this.dragPopup.popupElement.querySelector('.k-tooltip').clientHeight;
|
|
6001
|
+
const enoughSpaceToRender = top < containerClientBottom - popupHeight;
|
|
6002
|
+
// flip the popup above the pointer if there's not enough space in the bottom of the container
|
|
6003
|
+
if (!enoughSpaceToRender) {
|
|
6004
|
+
// margin * 2 to account for the already applied margin
|
|
6005
|
+
top -= popupHeight + (DEFAULT_POPUP_VERTICAL_MARGIN * 2);
|
|
6006
|
+
}
|
|
6007
|
+
// center the popup horizontally according to the pointer position
|
|
6008
|
+
const popupWidth = this.dragPopup.popupElement.querySelector('.k-tooltip').clientWidth;
|
|
6009
|
+
const left = pointerOffsetPosition.left - popupWidth / 2;
|
|
6010
|
+
// don't allow the popup to be cut out of the viewport
|
|
6011
|
+
const minLeftTop = 0;
|
|
6012
|
+
// restrict the popup from being positioned beyond or before the available scrollable space
|
|
6013
|
+
return {
|
|
6014
|
+
left: fitToRange(left, minLeftTop, this.container.scrollWidth - popupWidth),
|
|
6015
|
+
top: fitToRange(top, minLeftTop, this.container.scrollHeight - popupHeight)
|
|
6016
|
+
};
|
|
6017
|
+
}
|
|
6018
|
+
};
|
|
6019
|
+
__decorate([
|
|
6020
|
+
Input(),
|
|
6021
|
+
__metadata("design:type", Boolean)
|
|
6022
|
+
], DependencyDragCreateDirective.prototype, "displayValidationTooltip", void 0);
|
|
6023
|
+
DependencyDragCreateDirective = __decorate([
|
|
6024
|
+
Directive({
|
|
6025
|
+
selector: '[kendoGanttDependencyDragCreate]'
|
|
6026
|
+
}),
|
|
6027
|
+
__metadata("design:paramtypes", [GanttComponent,
|
|
6028
|
+
NgZone,
|
|
6029
|
+
Renderer2,
|
|
6030
|
+
MappingService,
|
|
6031
|
+
PopupService,
|
|
6032
|
+
TimelineScrollService])
|
|
6033
|
+
], DependencyDragCreateDirective);
|
|
4311
6034
|
|
|
4312
6035
|
/**
|
|
4313
|
-
*
|
|
6036
|
+
* @hidden
|
|
4314
6037
|
*/
|
|
4315
|
-
|
|
6038
|
+
var ScrollDirection;
|
|
6039
|
+
(function (ScrollDirection) {
|
|
6040
|
+
ScrollDirection[ScrollDirection["Backwards"] = -1] = "Backwards";
|
|
6041
|
+
ScrollDirection[ScrollDirection["Forward"] = 1] = "Forward";
|
|
6042
|
+
})(ScrollDirection || (ScrollDirection = {}));
|
|
4316
6043
|
/**
|
|
4317
|
-
*
|
|
6044
|
+
* @hidden
|
|
4318
6045
|
*/
|
|
4319
|
-
|
|
6046
|
+
var ScrollAxis;
|
|
6047
|
+
(function (ScrollAxis) {
|
|
6048
|
+
ScrollAxis["Vertical"] = "scrollTop";
|
|
6049
|
+
ScrollAxis["Horizontal"] = "scrollLeft";
|
|
6050
|
+
})(ScrollAxis || (ScrollAxis = {}));
|
|
6051
|
+
|
|
4320
6052
|
/**
|
|
4321
6053
|
* @hidden
|
|
6054
|
+
*
|
|
6055
|
+
* Checks if the beginning of the scrollable element is reached (top/left).
|
|
6056
|
+
* Floors the top value.
|
|
4322
6057
|
*/
|
|
4323
|
-
|
|
4324
|
-
|
|
4325
|
-
|
|
6058
|
+
const isUpperLimitReached = (element, axis) => Math.floor(element[axis]) <= 0;
|
|
6059
|
+
/**
|
|
6060
|
+
* @hidden
|
|
6061
|
+
*
|
|
6062
|
+
* Checks if the end of the scrollable element is reached (bottom/right).
|
|
6063
|
+
* Ceils the top value.
|
|
6064
|
+
*/
|
|
6065
|
+
const isBottomLimitReached = (element, axis) => {
|
|
6066
|
+
const elementSize = axis === ScrollAxis.Horizontal ?
|
|
6067
|
+
element.scrollWidth - element.clientWidth :
|
|
6068
|
+
element.scrollHeight - element.clientHeight;
|
|
6069
|
+
return Math.ceil(element[axis]) >= elementSize;
|
|
6070
|
+
};
|
|
6071
|
+
/**
|
|
6072
|
+
* @hidden
|
|
6073
|
+
*
|
|
6074
|
+
* Scrolls the element in the given direction by the provided step in the provided scroll axis.
|
|
6075
|
+
*
|
|
6076
|
+
* If the targeted scroll incrementation doesn't yield any result due to device pixel ratio issues (https://github.com/dimitar-pechev/RenderingIndependentScrollOffsets#readme),
|
|
6077
|
+
* increments the step with 1px and again attempts to change the scrollTop of the element, until the content is actually scrolled.
|
|
6078
|
+
*
|
|
6079
|
+
* Cuts the operation short after 20 unsuccessful attempts to prevent infinite loops in possible corner-case scenarios.
|
|
6080
|
+
*/
|
|
6081
|
+
const scrollElement = (element, step, direction, scrollAxis) => {
|
|
6082
|
+
if (!(isPresent(element) && isDocumentAvailable())) {
|
|
6083
|
+
return;
|
|
6084
|
+
}
|
|
6085
|
+
const initialScrollPosition = element[scrollAxis];
|
|
6086
|
+
let currentStep = step;
|
|
6087
|
+
let iterations = 0;
|
|
6088
|
+
while (initialScrollPosition === element[scrollAxis] &&
|
|
6089
|
+
!(direction === ScrollDirection.Backwards && isUpperLimitReached(element, scrollAxis)) &&
|
|
6090
|
+
!(direction === ScrollDirection.Forward && isBottomLimitReached(element, scrollAxis)) &&
|
|
6091
|
+
iterations < 20 // cut the operation short in 20 attempts - in case of a wild corner case
|
|
6092
|
+
) {
|
|
6093
|
+
element[scrollAxis] += (currentStep * direction);
|
|
6094
|
+
// try with a larger step if the current one doesn't update the scroll position successfully
|
|
6095
|
+
currentStep += 1;
|
|
6096
|
+
iterations += 1;
|
|
6097
|
+
}
|
|
6098
|
+
};
|
|
6099
|
+
/**
|
|
6100
|
+
* @hidden
|
|
6101
|
+
*
|
|
6102
|
+
* 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,
|
|
6103
|
+
* this function extracts the visible boundaries of the provided element - fall-backing to 0 when the top/left are below 0,
|
|
6104
|
+
* and fall-backing to the actual visible size of the container for bottom/right.
|
|
6105
|
+
*/
|
|
6106
|
+
const getViewportBoundaries = (element) => {
|
|
6107
|
+
const elementRect = element.getBoundingClientRect();
|
|
6108
|
+
// if the beginning of the scrollable container is above/before the current viewport, fall-back to 0
|
|
6109
|
+
const topLimit = Math.max(elementRect.top, 0);
|
|
6110
|
+
const leftLimit = Math.max(elementRect.left, 0);
|
|
6111
|
+
// if the end of the scrollable container is beneath/after the current viewport, fall-back to its client height
|
|
6112
|
+
// 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
|
|
6113
|
+
const bottomLimit = topLimit + Math.min(elementRect.bottom, element.clientHeight);
|
|
6114
|
+
const rightLimit = leftLimit + Math.min(elementRect.right, element.clientWidth);
|
|
6115
|
+
return {
|
|
6116
|
+
top: topLimit,
|
|
6117
|
+
bottom: bottomLimit,
|
|
6118
|
+
left: leftLimit,
|
|
6119
|
+
right: rightLimit
|
|
6120
|
+
};
|
|
6121
|
+
};
|
|
6122
|
+
|
|
6123
|
+
/**
|
|
6124
|
+
* @hidden
|
|
6125
|
+
*/
|
|
6126
|
+
let TimelineScrollableDirective = class TimelineScrollableDirective {
|
|
6127
|
+
constructor(timelineScrollableContainer, scrollService, zone) {
|
|
6128
|
+
this.timelineScrollableContainer = timelineScrollableContainer;
|
|
6129
|
+
this.scrollService = scrollService;
|
|
4326
6130
|
this.zone = zone;
|
|
4327
|
-
this.renderer = renderer;
|
|
4328
|
-
this.mapper = mapper;
|
|
4329
|
-
this.dependencyDomService = dependencyDomService;
|
|
4330
6131
|
this.subscriptions = new Subscription();
|
|
4331
|
-
this.subscriptions.add(
|
|
4332
|
-
.
|
|
4333
|
-
|
|
4334
|
-
|
|
4335
|
-
this.
|
|
4336
|
-
.subscribe(
|
|
6132
|
+
this.subscriptions.add(this.scrollService.horizontalScroll
|
|
6133
|
+
.subscribe(this.scrollHorizontallyTo.bind(this)));
|
|
6134
|
+
this.subscriptions.add(this.scrollService.verticalScroll
|
|
6135
|
+
.subscribe(this.scrollVerticallyTo.bind(this)));
|
|
6136
|
+
this.subscriptions.add(this.scrollService.scrollCancel
|
|
6137
|
+
.subscribe(this.cancelScroll.bind(this)));
|
|
4337
6138
|
}
|
|
4338
6139
|
ngOnDestroy() {
|
|
4339
6140
|
this.subscriptions.unsubscribe();
|
|
4340
6141
|
}
|
|
4341
|
-
|
|
4342
|
-
|
|
4343
|
-
this.
|
|
4344
|
-
|
|
4345
|
-
|
|
4346
|
-
|
|
4347
|
-
|
|
4348
|
-
|
|
4349
|
-
|
|
4350
|
-
|
|
4351
|
-
|
|
4352
|
-
}
|
|
4353
|
-
const fromCoordinates = getElementRect(tasks.get(this.mapper.extractFromDependency(this.dependency, 'fromId')), contentContainer);
|
|
4354
|
-
const toCoordinates = getElementRect(tasks.get(this.mapper.extractFromDependency(this.dependency, 'toId')), contentContainer);
|
|
4355
|
-
const timelineRowHeight = isDocumentAvailable() ? timelineRow.getBoundingClientRect().height : 0;
|
|
4356
|
-
const points = dependencyCoordinates(fromCoordinates, toCoordinates, timelineRowHeight, this.dependency.type, MIN_DISTANCE_BEFORE_TURN, ARROW_SIZE);
|
|
4357
|
-
this.drawPoints(points);
|
|
6142
|
+
scrollHorizontallyTo(left) {
|
|
6143
|
+
this.zone.runOutsideAngular(() => {
|
|
6144
|
+
const container = this.timelineScrollableContainer.nativeElement;
|
|
6145
|
+
const visibleBoundaries = getViewportBoundaries(container);
|
|
6146
|
+
if (left < visibleBoundaries.left + this.scrollSettings.threshold) {
|
|
6147
|
+
this.horizontalScrollInterval = setInterval(() => scrollElement(container, this.scrollSettings.step, ScrollDirection.Backwards, ScrollAxis.Horizontal), this.scrollSettings.interval);
|
|
6148
|
+
}
|
|
6149
|
+
else if (left > visibleBoundaries.right - this.scrollSettings.threshold) {
|
|
6150
|
+
this.horizontalScrollInterval = setInterval(() => scrollElement(container, this.scrollSettings.step, ScrollDirection.Forward, ScrollAxis.Horizontal), this.scrollSettings.interval);
|
|
6151
|
+
}
|
|
6152
|
+
});
|
|
4358
6153
|
}
|
|
4359
|
-
|
|
4360
|
-
this.
|
|
6154
|
+
scrollVerticallyTo(top) {
|
|
6155
|
+
this.zone.runOutsideAngular(() => {
|
|
6156
|
+
const container = this.timelineScrollableContainer.nativeElement;
|
|
6157
|
+
const visibleBoundaries = getViewportBoundaries(container);
|
|
6158
|
+
if (top < visibleBoundaries.top + this.scrollSettings.threshold) {
|
|
6159
|
+
this.verticalScrollInterval = setInterval(() => scrollElement(container, this.scrollSettings.step, ScrollDirection.Backwards, ScrollAxis.Vertical), this.scrollSettings.interval);
|
|
6160
|
+
}
|
|
6161
|
+
else if (top > visibleBoundaries.bottom - this.scrollSettings.threshold) {
|
|
6162
|
+
this.verticalScrollInterval = setInterval(() => scrollElement(container, this.scrollSettings.step, ScrollDirection.Forward, ScrollAxis.Vertical), this.scrollSettings.interval);
|
|
6163
|
+
}
|
|
6164
|
+
});
|
|
4361
6165
|
}
|
|
4362
|
-
|
|
4363
|
-
if (
|
|
4364
|
-
this.
|
|
4365
|
-
|
|
6166
|
+
cancelScroll() {
|
|
6167
|
+
if (isPresent(this.verticalScrollInterval)) {
|
|
6168
|
+
clearInterval(this.verticalScrollInterval);
|
|
6169
|
+
this.verticalScrollInterval = null;
|
|
6170
|
+
}
|
|
6171
|
+
if (isPresent(this.horizontalScrollInterval)) {
|
|
6172
|
+
clearInterval(this.horizontalScrollInterval);
|
|
6173
|
+
this.horizontalScrollInterval = null;
|
|
4366
6174
|
}
|
|
4367
|
-
const parsedCoords = points.map(({ left, top }) => `${left},${top}`).join(' ');
|
|
4368
|
-
this.renderer.setAttribute(this.polyline.nativeElement, 'points', parsedCoords);
|
|
4369
6175
|
}
|
|
4370
6176
|
};
|
|
4371
6177
|
__decorate([
|
|
4372
6178
|
Input(),
|
|
4373
6179
|
__metadata("design:type", Object)
|
|
4374
|
-
],
|
|
4375
|
-
|
|
6180
|
+
], TimelineScrollableDirective.prototype, "scrollSettings", void 0);
|
|
6181
|
+
TimelineScrollableDirective = __decorate([
|
|
4376
6182
|
Directive({
|
|
4377
|
-
selector: '[
|
|
6183
|
+
selector: '[kendoGanttTimelineScrollable]'
|
|
4378
6184
|
}),
|
|
4379
6185
|
__metadata("design:paramtypes", [ElementRef,
|
|
4380
|
-
|
|
4381
|
-
|
|
4382
|
-
|
|
4383
|
-
DependencyDomService])
|
|
4384
|
-
], GanttDependencyDirective);
|
|
6186
|
+
TimelineScrollService,
|
|
6187
|
+
NgZone])
|
|
6188
|
+
], TimelineScrollableDirective);
|
|
4385
6189
|
|
|
4386
6190
|
var TimelineDayViewComponent_1;
|
|
4387
6191
|
let TimelineDayViewComponent = TimelineDayViewComponent_1 = class TimelineDayViewComponent extends ViewBase {
|
|
@@ -4459,25 +6263,46 @@ TimelineMonthViewComponent = TimelineMonthViewComponent_1 = __decorate([
|
|
|
4459
6263
|
* @hidden
|
|
4460
6264
|
*/
|
|
4461
6265
|
let EditDialogComponent = class EditDialogComponent {
|
|
4462
|
-
constructor(mapper, editService, localizationService) {
|
|
6266
|
+
constructor(mapper, editService, cdr, localizationService) {
|
|
4463
6267
|
this.mapper = mapper;
|
|
4464
6268
|
this.editService = editService;
|
|
6269
|
+
this.cdr = cdr;
|
|
4465
6270
|
this.localizationService = localizationService;
|
|
4466
6271
|
}
|
|
6272
|
+
ngOnInit() {
|
|
6273
|
+
this.editService.loadTasks(this.data).subscribe(value => {
|
|
6274
|
+
this.loadedTasks = value;
|
|
6275
|
+
});
|
|
6276
|
+
}
|
|
6277
|
+
get predecessors() {
|
|
6278
|
+
return this.editService.predecessors;
|
|
6279
|
+
}
|
|
6280
|
+
set predecessors(items) {
|
|
6281
|
+
this.editService.predecessors = items;
|
|
6282
|
+
}
|
|
6283
|
+
get successors() {
|
|
6284
|
+
return this.editService.successors;
|
|
6285
|
+
}
|
|
6286
|
+
set successors(items) {
|
|
6287
|
+
this.editService.successors = items;
|
|
6288
|
+
}
|
|
4467
6289
|
getText(token) {
|
|
4468
6290
|
return this.localizationService.get(token);
|
|
4469
6291
|
}
|
|
6292
|
+
getDependencyType(typeId) {
|
|
6293
|
+
return DependencyType[typeId];
|
|
6294
|
+
}
|
|
4470
6295
|
handleEditingResult(editResultType) {
|
|
4471
6296
|
this.editService.triggerEditEvent(editResultType);
|
|
4472
6297
|
}
|
|
4473
|
-
|
|
4474
|
-
this.editService.
|
|
6298
|
+
handleTaskDelete() {
|
|
6299
|
+
this.editService.taskDelete.next(this.editService.dataItem);
|
|
4475
6300
|
}
|
|
4476
6301
|
};
|
|
4477
6302
|
__decorate([
|
|
4478
6303
|
Input(),
|
|
4479
|
-
__metadata("design:type",
|
|
4480
|
-
], EditDialogComponent.prototype, "
|
|
6304
|
+
__metadata("design:type", Array)
|
|
6305
|
+
], EditDialogComponent.prototype, "data", void 0);
|
|
4481
6306
|
EditDialogComponent = __decorate([
|
|
4482
6307
|
Component({
|
|
4483
6308
|
selector: 'kendo-gantt-edit-dialog',
|
|
@@ -4489,36 +6314,44 @@ EditDialogComponent = __decorate([
|
|
|
4489
6314
|
(close)="handleEditingResult('cancel')">
|
|
4490
6315
|
<kendo-dialog-messages
|
|
4491
6316
|
[closeTitle]="getText('taskEditingDialogCloseTitle')"></kendo-dialog-messages>
|
|
4492
|
-
|
|
4493
|
-
|
|
4494
|
-
|
|
4495
|
-
<
|
|
4496
|
-
|
|
4497
|
-
|
|
4498
|
-
|
|
4499
|
-
|
|
4500
|
-
|
|
4501
|
-
|
|
4502
|
-
|
|
4503
|
-
|
|
4504
|
-
|
|
4505
|
-
|
|
4506
|
-
|
|
4507
|
-
|
|
4508
|
-
|
|
4509
|
-
|
|
4510
|
-
<
|
|
4511
|
-
|
|
4512
|
-
|
|
4513
|
-
|
|
4514
|
-
|
|
4515
|
-
|
|
4516
|
-
|
|
4517
|
-
|
|
4518
|
-
|
|
4519
|
-
|
|
6317
|
+
|
|
6318
|
+
<kendo-tabstrip [keepTabContent]="true" style="height: 345px;">
|
|
6319
|
+
<kendo-tabstrip-tab [title]="getText('taskEditingGeneralTabTitle')" [selected]="true">
|
|
6320
|
+
<ng-template kendoTabContent>
|
|
6321
|
+
<kendo-gantt-task-fields></kendo-gantt-task-fields>
|
|
6322
|
+
</ng-template>
|
|
6323
|
+
</kendo-tabstrip-tab>
|
|
6324
|
+
<kendo-tabstrip-tab [title]="getText('taskEditingPredecessorsTabTitle')">
|
|
6325
|
+
<ng-template kendoTabContent>
|
|
6326
|
+
<kendo-gantt-dependencies-table
|
|
6327
|
+
[tasks]="loadedTasks"
|
|
6328
|
+
[(dependencies)]="predecessors"
|
|
6329
|
+
dependencyType="predecessor"
|
|
6330
|
+
>
|
|
6331
|
+
</kendo-gantt-dependencies-table>
|
|
6332
|
+
</ng-template>
|
|
6333
|
+
</kendo-tabstrip-tab>
|
|
6334
|
+
<kendo-tabstrip-tab [title]="getText('taskEditingSuccessorsTabTitle')">
|
|
6335
|
+
<ng-template kendoTabContent>
|
|
6336
|
+
<kendo-gantt-dependencies-table
|
|
6337
|
+
[tasks]="loadedTasks"
|
|
6338
|
+
[(dependencies)]="successors"
|
|
6339
|
+
dependencyType="successor">
|
|
6340
|
+
</kendo-gantt-dependencies-table>
|
|
6341
|
+
</ng-template>
|
|
6342
|
+
</kendo-tabstrip-tab>
|
|
6343
|
+
</kendo-tabstrip>
|
|
6344
|
+
|
|
4520
6345
|
<kendo-dialog-actions layout="normal">
|
|
4521
|
-
<button
|
|
6346
|
+
<button
|
|
6347
|
+
kendoButton
|
|
6348
|
+
[kendoEventsOutsideAngular]="{
|
|
6349
|
+
click: handleTaskDelete
|
|
6350
|
+
}"
|
|
6351
|
+
[scope]="this"
|
|
6352
|
+
>
|
|
6353
|
+
{{ getText('deleteButtonText') }}
|
|
6354
|
+
</button>
|
|
4522
6355
|
<kendo-treelist-spacer></kendo-treelist-spacer>
|
|
4523
6356
|
<button kendoButton [primary]="true" (click)="handleEditingResult('save')">{{ getText('saveButtonText') }}</button>
|
|
4524
6357
|
<button kendoButton (click)="handleEditingResult('cancel')">{{ getText('cancelButtonText') }}</button>
|
|
@@ -4528,6 +6361,7 @@ EditDialogComponent = __decorate([
|
|
|
4528
6361
|
}),
|
|
4529
6362
|
__metadata("design:paramtypes", [MappingService,
|
|
4530
6363
|
EditService,
|
|
6364
|
+
ChangeDetectorRef,
|
|
4531
6365
|
LocalizationService])
|
|
4532
6366
|
], EditDialogComponent);
|
|
4533
6367
|
|
|
@@ -4954,6 +6788,213 @@ GanttAddTaskComponent = __decorate([
|
|
|
4954
6788
|
NgZone])
|
|
4955
6789
|
], GanttAddTaskComponent);
|
|
4956
6790
|
|
|
6791
|
+
/**
|
|
6792
|
+
* @hidden
|
|
6793
|
+
*/
|
|
6794
|
+
let DependenciesTableComponent = class DependenciesTableComponent {
|
|
6795
|
+
constructor(mapper, editService, localizationService) {
|
|
6796
|
+
this.mapper = mapper;
|
|
6797
|
+
this.editService = editService;
|
|
6798
|
+
this.localizationService = localizationService;
|
|
6799
|
+
this.dependenciesChange = new EventEmitter();
|
|
6800
|
+
this.selectedKeys = [];
|
|
6801
|
+
this.formGroups = new FormArray([]);
|
|
6802
|
+
this.dependencyTypes = this.getDependencyTypes();
|
|
6803
|
+
}
|
|
6804
|
+
get taskId() {
|
|
6805
|
+
return this.editService.dataItem.id;
|
|
6806
|
+
}
|
|
6807
|
+
// The target dependency id field
|
|
6808
|
+
// e.g. if Predecessors, we have the `fromId` which is the currently edited task,
|
|
6809
|
+
// while the `toId` is missing (needs to be selected by the user)
|
|
6810
|
+
get dependencyIdField() {
|
|
6811
|
+
return this.dependencyType === 'predecessor' ? 'fromId' : 'toId';
|
|
6812
|
+
}
|
|
6813
|
+
ngOnInit() {
|
|
6814
|
+
// generate the FormGroups per each Grid row
|
|
6815
|
+
if (this.formGroups.controls.length === 0) {
|
|
6816
|
+
const fields = this.mapper.dependencyFields;
|
|
6817
|
+
this.dependencies.forEach(item => {
|
|
6818
|
+
const formGroup = new FormGroup({
|
|
6819
|
+
[fields.id]: new FormControl(this.mapper.extractFromDependency(item, 'id')),
|
|
6820
|
+
[fields.fromId]: new FormControl(this.mapper.extractFromDependency(item, 'fromId'), Validators.required),
|
|
6821
|
+
[fields.toId]: new FormControl(this.mapper.extractFromDependency(item, 'toId'), Validators.required),
|
|
6822
|
+
[fields.type]: new FormControl(this.mapper.extractFromDependency(item, 'type'), Validators.required)
|
|
6823
|
+
});
|
|
6824
|
+
this.formGroups.push(formGroup);
|
|
6825
|
+
});
|
|
6826
|
+
}
|
|
6827
|
+
this.formGroups.valueChanges.subscribe(val => {
|
|
6828
|
+
this.formGroups.controls.forEach(control => {
|
|
6829
|
+
if (control.dirty) {
|
|
6830
|
+
this.editService.updateDependencies(control.value);
|
|
6831
|
+
}
|
|
6832
|
+
});
|
|
6833
|
+
this.dependenciesChange.emit(val);
|
|
6834
|
+
});
|
|
6835
|
+
}
|
|
6836
|
+
getFormControl(dataItemIndex, field) {
|
|
6837
|
+
// return the FormControl for the respective column editor
|
|
6838
|
+
return this.formGroups.controls
|
|
6839
|
+
.find((_control, index) => index === dataItemIndex)
|
|
6840
|
+
.get(this.mapper.dependencyFields[field]);
|
|
6841
|
+
}
|
|
6842
|
+
getText(token) {
|
|
6843
|
+
return this.localizationService.get(token);
|
|
6844
|
+
}
|
|
6845
|
+
getDependencyTypes() {
|
|
6846
|
+
const types = Object.keys(DependencyType)
|
|
6847
|
+
.filter(value => typeof DependencyType[value] === 'number')
|
|
6848
|
+
.map(type => {
|
|
6849
|
+
return {
|
|
6850
|
+
type,
|
|
6851
|
+
id: DependencyType[type]
|
|
6852
|
+
};
|
|
6853
|
+
});
|
|
6854
|
+
return types;
|
|
6855
|
+
}
|
|
6856
|
+
addHandler() {
|
|
6857
|
+
const fields = this.mapper.dependencyFields;
|
|
6858
|
+
const formGroup = new FormGroup({
|
|
6859
|
+
[fields.id]: new FormControl(),
|
|
6860
|
+
[fields.fromId]: new FormControl(this.dependencyIdField === 'toId' ? this.taskId : null, Validators.required),
|
|
6861
|
+
[fields.toId]: new FormControl(this.dependencyIdField === 'fromId' ? this.taskId : null, Validators.required),
|
|
6862
|
+
[fields.type]: new FormControl(null, Validators.required)
|
|
6863
|
+
});
|
|
6864
|
+
this.formGroups.push(formGroup);
|
|
6865
|
+
}
|
|
6866
|
+
removeHandler() {
|
|
6867
|
+
const [selectedIndex] = this.selectedKeys;
|
|
6868
|
+
const item = this.formGroups.at(selectedIndex).value;
|
|
6869
|
+
this.editService.deleteDependency(item);
|
|
6870
|
+
this.formGroups.removeAt(selectedIndex);
|
|
6871
|
+
}
|
|
6872
|
+
};
|
|
6873
|
+
__decorate([
|
|
6874
|
+
Input(),
|
|
6875
|
+
__metadata("design:type", Array)
|
|
6876
|
+
], DependenciesTableComponent.prototype, "tasks", void 0);
|
|
6877
|
+
__decorate([
|
|
6878
|
+
Input(),
|
|
6879
|
+
__metadata("design:type", Array)
|
|
6880
|
+
], DependenciesTableComponent.prototype, "dependencies", void 0);
|
|
6881
|
+
__decorate([
|
|
6882
|
+
Input(),
|
|
6883
|
+
__metadata("design:type", String)
|
|
6884
|
+
], DependenciesTableComponent.prototype, "dependencyType", void 0);
|
|
6885
|
+
__decorate([
|
|
6886
|
+
Output(),
|
|
6887
|
+
__metadata("design:type", EventEmitter)
|
|
6888
|
+
], DependenciesTableComponent.prototype, "dependenciesChange", void 0);
|
|
6889
|
+
DependenciesTableComponent = __decorate([
|
|
6890
|
+
Component({
|
|
6891
|
+
selector: 'kendo-gantt-dependencies-table',
|
|
6892
|
+
template: `
|
|
6893
|
+
<kendo-grid
|
|
6894
|
+
[data]="dependencies"
|
|
6895
|
+
[selectable]="{ mode: 'single' }"
|
|
6896
|
+
[(selectedKeys)]="selectedKeys"
|
|
6897
|
+
kendoGridSelectBy
|
|
6898
|
+
[height]="275"
|
|
6899
|
+
>
|
|
6900
|
+
<ng-template kendoGridToolbarTemplate>
|
|
6901
|
+
<button kendoButton (click)="addHandler()">
|
|
6902
|
+
{{ getText('taskEditingDependenciesAddButtonText') }}
|
|
6903
|
+
</button>
|
|
6904
|
+
<button kendoButton (click)="removeHandler()" [disabled]="selectedKeys.length === 0">
|
|
6905
|
+
{{ getText('taskEditingDependenciesRemoveButtonText') }}
|
|
6906
|
+
</button>
|
|
6907
|
+
</ng-template>
|
|
6908
|
+
<kendo-grid-column [title]="getText('taskEditingDependenciesGridNameColumnTitle')" [field]="dependencyIdField">
|
|
6909
|
+
<ng-template kendoGridCellTemplate let-dataItem="dataItem" let-column="column" let-rowIndex="rowIndex">
|
|
6910
|
+
<kendo-dropdownlist
|
|
6911
|
+
[data]="tasks"
|
|
6912
|
+
textField="title"
|
|
6913
|
+
valueField="id"
|
|
6914
|
+
[valuePrimitive]="true"
|
|
6915
|
+
[formControl]="getFormControl(rowIndex, column.field)"
|
|
6916
|
+
>
|
|
6917
|
+
</kendo-dropdownlist>
|
|
6918
|
+
</ng-template>
|
|
6919
|
+
</kendo-grid-column>
|
|
6920
|
+
<kendo-grid-column [title]="getText('taskEditingDependenciesGridTypeColumnTitle')" field="type">
|
|
6921
|
+
<ng-template kendoGridCellTemplate let-dataItem="dataItem" let-column="column" let-rowIndex="rowIndex">
|
|
6922
|
+
<kendo-dropdownlist
|
|
6923
|
+
[data]="dependencyTypes"
|
|
6924
|
+
textField="type"
|
|
6925
|
+
valueField="id"
|
|
6926
|
+
[valuePrimitive]="true"
|
|
6927
|
+
[formControl]="getFormControl(rowIndex, column.field)"
|
|
6928
|
+
>
|
|
6929
|
+
</kendo-dropdownlist>
|
|
6930
|
+
</ng-template>
|
|
6931
|
+
</kendo-grid-column>
|
|
6932
|
+
</kendo-grid>
|
|
6933
|
+
`
|
|
6934
|
+
}),
|
|
6935
|
+
__metadata("design:paramtypes", [MappingService,
|
|
6936
|
+
EditService,
|
|
6937
|
+
GanttLocalizationService])
|
|
6938
|
+
], DependenciesTableComponent);
|
|
6939
|
+
|
|
6940
|
+
/**
|
|
6941
|
+
* @hidden
|
|
6942
|
+
*/
|
|
6943
|
+
let TaskFieldsComponent = class TaskFieldsComponent {
|
|
6944
|
+
constructor(mapper, editService, localizationService) {
|
|
6945
|
+
this.mapper = mapper;
|
|
6946
|
+
this.editService = editService;
|
|
6947
|
+
this.localizationService = localizationService;
|
|
6948
|
+
}
|
|
6949
|
+
/**
|
|
6950
|
+
* @hidden
|
|
6951
|
+
*/
|
|
6952
|
+
get formGroup() {
|
|
6953
|
+
return this.editService.taskFormGroup;
|
|
6954
|
+
}
|
|
6955
|
+
getText(token) {
|
|
6956
|
+
return this.localizationService.get(token);
|
|
6957
|
+
}
|
|
6958
|
+
};
|
|
6959
|
+
TaskFieldsComponent = __decorate([
|
|
6960
|
+
Component({
|
|
6961
|
+
selector: 'kendo-gantt-task-fields',
|
|
6962
|
+
template: `
|
|
6963
|
+
<form class="k-form" [formGroup]="formGroup">
|
|
6964
|
+
<kendo-formfield *ngIf="formGroup.contains(mapper.taskFields.title)">
|
|
6965
|
+
<kendo-label [for]="mapper.taskFields.title" [text]="getText('titleFieldInputLabel')"></kendo-label>
|
|
6966
|
+
<input kendoTextBox [formControlName]="mapper.taskFields.title" />
|
|
6967
|
+
</kendo-formfield>
|
|
6968
|
+
<div class="k-hstack">
|
|
6969
|
+
<kendo-formfield [style.width.%]="49" *ngIf="formGroup.contains(mapper.taskFields.start)">
|
|
6970
|
+
<kendo-label [for]="mapper.taskFields.start" [text]="getText('startFieldInputLabel')"></kendo-label>
|
|
6971
|
+
<kendo-datetimepicker [formControlName]="mapper.taskFields.start"></kendo-datetimepicker>
|
|
6972
|
+
</kendo-formfield>
|
|
6973
|
+
<kendo-treelist-spacer></kendo-treelist-spacer>
|
|
6974
|
+
<kendo-formfield [style.width.%]="49" *ngIf="formGroup.contains(mapper.taskFields.end)">
|
|
6975
|
+
<kendo-label [for]="mapper.taskFields.end" [text]="getText('endFieldInputLabel')"></kendo-label>
|
|
6976
|
+
<kendo-datetimepicker [formControlName]="mapper.taskFields.end"></kendo-datetimepicker>
|
|
6977
|
+
</kendo-formfield>
|
|
6978
|
+
</div>
|
|
6979
|
+
<kendo-formfield [style.width.%]="49" *ngIf="formGroup.contains(mapper.taskFields.completionRatio)">
|
|
6980
|
+
<kendo-label [for]="mapper.taskFields.completionRatio" [text]="getText('completionRatioFieldInputLabel')"></kendo-label>
|
|
6981
|
+
<kendo-numerictextbox
|
|
6982
|
+
[formControlName]="mapper.taskFields.completionRatio"
|
|
6983
|
+
[min]="0"
|
|
6984
|
+
[max]="1"
|
|
6985
|
+
[decimals]="2"
|
|
6986
|
+
format="p2"
|
|
6987
|
+
[step]="0.01"
|
|
6988
|
+
></kendo-numerictextbox>
|
|
6989
|
+
</kendo-formfield>
|
|
6990
|
+
</form>
|
|
6991
|
+
`
|
|
6992
|
+
}),
|
|
6993
|
+
__metadata("design:paramtypes", [MappingService,
|
|
6994
|
+
EditService,
|
|
6995
|
+
GanttLocalizationService])
|
|
6996
|
+
], TaskFieldsComponent);
|
|
6997
|
+
|
|
4957
6998
|
const IMPORTED_MODULES = [
|
|
4958
6999
|
CommonModule,
|
|
4959
7000
|
ReactiveFormsModule,
|
|
@@ -4965,7 +7006,12 @@ const IMPORTED_MODULES = [
|
|
|
4965
7006
|
TreeListModule,
|
|
4966
7007
|
ButtonsModule,
|
|
4967
7008
|
DialogModule,
|
|
4968
|
-
EventsModule
|
|
7009
|
+
EventsModule,
|
|
7010
|
+
PopupModule,
|
|
7011
|
+
DraggableModule,
|
|
7012
|
+
TabStripModule,
|
|
7013
|
+
GridModule,
|
|
7014
|
+
DropDownsModule
|
|
4969
7015
|
];
|
|
4970
7016
|
const DECLARATIONS = [
|
|
4971
7017
|
GanttComponent,
|
|
@@ -4995,6 +7041,7 @@ const DECLARATIONS = [
|
|
|
4995
7041
|
FooterTemplateDirective,
|
|
4996
7042
|
GanttExpandableDirective,
|
|
4997
7043
|
GanttDependencyDirective,
|
|
7044
|
+
DependencyDragCreateDirective,
|
|
4998
7045
|
TimelineDayViewComponent,
|
|
4999
7046
|
TimelineWeekViewComponent,
|
|
5000
7047
|
TimelineMonthViewComponent,
|
|
@@ -5002,8 +7049,13 @@ const DECLARATIONS = [
|
|
|
5002
7049
|
EditDialogComponent,
|
|
5003
7050
|
CustomMessagesComponent,
|
|
5004
7051
|
LocalizedMessagesDirective,
|
|
5005
|
-
GanttAddTaskComponent
|
|
7052
|
+
GanttAddTaskComponent,
|
|
7053
|
+
DragValidationTooltipComponent,
|
|
7054
|
+
TimelineScrollableDirective,
|
|
7055
|
+
DependenciesTableComponent,
|
|
7056
|
+
TaskFieldsComponent
|
|
5006
7057
|
];
|
|
7058
|
+
const ɵ0$3 = touchEnabled;
|
|
5007
7059
|
/**
|
|
5008
7060
|
* Represents the [NgModule]({{ site.data.urls.angular['ngmoduleapi'] }})
|
|
5009
7061
|
* definition for the Gantt component.
|
|
@@ -5042,52 +7094,19 @@ GanttModule = __decorate([
|
|
|
5042
7094
|
imports: [...IMPORTED_MODULES],
|
|
5043
7095
|
declarations: [...DECLARATIONS],
|
|
5044
7096
|
exports: [...DECLARATIONS],
|
|
7097
|
+
entryComponents: [DragValidationTooltipComponent],
|
|
5045
7098
|
providers: [{
|
|
5046
7099
|
provide: L10N_PREFIX,
|
|
5047
7100
|
useValue: 'kendo.gantt'
|
|
7101
|
+
}, {
|
|
7102
|
+
provide: TOUCH_ENABLED,
|
|
7103
|
+
useValue: ɵ0$3
|
|
5048
7104
|
}]
|
|
5049
7105
|
})
|
|
5050
7106
|
], GanttModule);
|
|
5051
7107
|
|
|
5052
|
-
/**
|
|
5053
|
-
* @hidden
|
|
5054
|
-
*/
|
|
5055
|
-
class PreventableEvent {
|
|
5056
|
-
constructor() {
|
|
5057
|
-
this.prevented = false;
|
|
5058
|
-
}
|
|
5059
|
-
/**
|
|
5060
|
-
* Prevents the default action for a specified event.
|
|
5061
|
-
* In this way, the source component suppresses
|
|
5062
|
-
* the built-in behavior that follows the event.
|
|
5063
|
-
*/
|
|
5064
|
-
preventDefault() {
|
|
5065
|
-
this.prevented = true;
|
|
5066
|
-
}
|
|
5067
|
-
/**
|
|
5068
|
-
* Returns `true` if the event was prevented
|
|
5069
|
-
* by any of its subscribers.
|
|
5070
|
-
*
|
|
5071
|
-
* @returns `true` if the default action was prevented.
|
|
5072
|
-
* Otherwise, returns `false`.
|
|
5073
|
-
*/
|
|
5074
|
-
isDefaultPrevented() {
|
|
5075
|
-
return this.prevented;
|
|
5076
|
-
}
|
|
5077
|
-
}
|
|
5078
|
-
|
|
5079
|
-
/**
|
|
5080
|
-
* Called every time a user leaves an edited cell.
|
|
5081
|
-
*/
|
|
5082
|
-
class CellCloseEvent extends PreventableEvent {
|
|
5083
|
-
constructor(options) {
|
|
5084
|
-
super();
|
|
5085
|
-
Object.assign(this, options);
|
|
5086
|
-
}
|
|
5087
|
-
}
|
|
5088
|
-
|
|
5089
7108
|
/**
|
|
5090
7109
|
* Generated bundle index. Do not edit.
|
|
5091
7110
|
*/
|
|
5092
7111
|
|
|
5093
|
-
export { MappingService, OptionChangesService, DependencyDomService, GanttDependencyDirective, GanttAddTaskComponent, EditDialogComponent, EditService, CustomMessagesComponent, LocalizedMessagesDirective, Messages, PreventableEvent, GanttHeaderTableBodyComponent, GanttMilestoneTaskComponent, GanttSummaryTaskComponent, GanttTaskBase, GanttTaskComponent, GanttTasksTableBodyComponent, ScrollSyncService, GanttTimelineComponent, TimelineBaseViewService, TimelineDayViewComponent, TimelineDayViewService, TimelineMonthViewComponent, TimelineMonthViewService, TimelineViewService, TimelineWeekViewComponent, TimelineWeekViewService, ViewBase, ToolbarComponent, ViewSelectorComponent, GanttComponent, GanttModule, GanttHierarchyBindingDirective, GanttFlatBindingDirective, GanttExpandableDirective, GanttTaskTemplateDirective, GanttTaskContentTemplateDirective, GanttSummaryTaskTemplateDirective, ToolbarTemplateDirective, SelectableDirective, CellCloseEvent, GanttColumnBase, GanttColumnComponent, GanttColumnGroupComponent, GanttSpanColumnComponent, CellTemplateDirective, HeaderTemplateDirective, FooterTemplateDirective, ColumnMenuTemplateDirective, FilterCellTemplateDirective, FilterMenuTemplateDirective, EditTemplateDirective };
|
|
7112
|
+
export { MappingService, OptionChangesService, TOUCH_ENABLED, DependencyDomService, GanttDependencyDirective, DragValidationTooltipComponent, GanttAddTaskComponent, DependenciesTableComponent, EditDialogComponent, EditService, TaskFieldsComponent, CustomMessagesComponent, GanttLocalizationService, LocalizedMessagesDirective, Messages, PreventableEvent, NavigationService, 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 };
|