jsgantt-improved 2.8.9 → 3.0.0
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/.mocharc.cjs +5 -0
- package/.travis.yml +0 -2
- package/Documentation.md +1 -1
- package/dist/draw_columns.js +171 -0
- package/dist/draw_dependencies.js +97 -0
- package/dist/e2e/app.e2e-spec.js +3 -3
- package/dist/e2e/app.e2e-spec.js.map +1 -1
- package/dist/e2e/app.po.js +5 -5
- package/dist/e2e/app.po.js.map +1 -1
- package/dist/jsgantt.js +580 -473
- package/dist/json.js +200 -0
- package/dist/lang.js +1635 -0
- package/dist/options.js +219 -0
- package/dist/playwright.config.js +33 -0
- package/dist/playwright.config.js.map +1 -0
- package/dist/src/draw.js +149 -148
- package/dist/src/draw.js.map +1 -1
- package/dist/src/draw_columns.js +66 -63
- package/dist/src/draw_columns.js.map +1 -1
- package/dist/src/draw_dependencies.js +4 -2
- package/dist/src/draw_dependencies.js.map +1 -1
- package/dist/src/events.js +72 -54
- package/dist/src/events.js.map +1 -1
- package/dist/src/json.js +10 -7
- package/dist/src/json.js.map +1 -1
- package/dist/src/lang.js +1 -1
- package/dist/src/lang.js.map +1 -1
- package/dist/src/options.js +14 -13
- package/dist/src/options.js.map +1 -1
- package/dist/src/task.js +61 -49
- package/dist/src/task.js.map +1 -1
- package/dist/src/utils/date_utils.js +46 -15
- package/dist/src/utils/date_utils.js.map +1 -1
- package/dist/src/utils/draw_utils.js +24 -18
- package/dist/src/utils/draw_utils.js.map +1 -1
- package/dist/src/utils/general_utils.js +59 -36
- package/dist/src/utils/general_utils.js.map +1 -1
- package/dist/src/utils.js +498 -0
- package/dist/src/utils.js.map +1 -0
- package/dist/src/xml.js +74 -67
- package/dist/src/xml.js.map +1 -1
- package/dist/test/e2e/gantt.page.js +150 -0
- package/dist/test/e2e/gantt.page.js.map +1 -0
- package/dist/test/e2e/issue172-row-alignment.spec.js +198 -0
- package/dist/test/e2e/issue172-row-alignment.spec.js.map +1 -0
- package/dist/test/e2e/issue207-bar-axis-alignment.spec.js +329 -0
- package/dist/test/e2e/issue207-bar-axis-alignment.spec.js.map +1 -0
- package/dist/test/e2e/issue255-show-weekends.spec.js +102 -0
- package/dist/test/e2e/issue255-show-weekends.spec.js.map +1 -0
- package/dist/test/e2e/issue349-taskname-click-event.spec.js +270 -0
- package/dist/test/e2e/issue349-taskname-click-event.spec.js.map +1 -0
- package/dist/test/e2e/issue48-dependency-lines.spec.js +204 -0
- package/dist/test/e2e/issue48-dependency-lines.spec.js.map +1 -0
- package/dist/test/e2e/issue54-month-today.spec.js +181 -0
- package/dist/test/e2e/issue54-month-today.spec.js.map +1 -0
- package/dist/test/e2e/issue68-working-days.spec.js +243 -0
- package/dist/test/e2e/issue68-working-days.spec.js.map +1 -0
- package/dist/test/e2e/zoom-alignment.spec.js +133 -0
- package/dist/test/e2e/zoom-alignment.spec.js.map +1 -0
- package/dist/test/index.js +3 -8
- package/dist/test/index.js.map +1 -1
- package/dist/test/unit/date-utils.spec.js +180 -0
- package/dist/test/unit/date-utils.spec.js.map +1 -0
- package/dist/test/unit/draw-cols-chart.spec.js +105 -0
- package/dist/test/unit/draw-cols-chart.spec.js.map +1 -0
- package/dist/test/unit/gantt-chart-constructor.spec.js +85 -0
- package/dist/test/unit/gantt-chart-constructor.spec.js.map +1 -0
- package/dist/test/unit/helpers.js +67 -0
- package/dist/test/unit/helpers.js.map +1 -0
- package/dist/test/unit/task-item.spec.js +46 -0
- package/dist/test/unit/task-item.spec.js.map +1 -0
- package/dist/test/unit/task-management.spec.js +141 -0
- package/dist/test/unit/task-management.spec.js.map +1 -0
- package/dist/test/unit/working-days.spec.js +109 -0
- package/dist/test/unit/working-days.spec.js.map +1 -0
- package/dist/utils/draw_utils.js +169 -0
- package/dist/utils/general_utils.js +498 -0
- package/dist/xml.js +345 -0
- package/dist-e2e/gantt.page.js +79 -0
- package/dist-e2e/gantt.page.js.map +1 -0
- package/dist-e2e/issue-setMinDate-setMaxDate.spec.js +96 -0
- package/dist-e2e/issue172-row-alignment.spec.js +90 -0
- package/dist-e2e/issue172-row-alignment.spec.js.map +1 -0
- package/dist-e2e/issue207-bar-axis-alignment.spec.js +161 -0
- package/dist-e2e/issue207-bar-axis-alignment.spec.js.map +1 -0
- package/dist-e2e/issue349-taskname-click-event.spec.js +170 -0
- package/dist-e2e/issue349-taskname-click-event.spec.js.map +1 -0
- package/dist-e2e/issue375-column-visibility.spec.js +129 -0
- package/dist-e2e/issue375-column-visibility.spec.js.map +1 -0
- package/dist-e2e/issue54-month-today.spec.js +84 -0
- package/dist-e2e/issue54-month-today.spec.js.map +1 -0
- package/dist-e2e/issue68-working-days.spec.js +105 -0
- package/dist-e2e/issue68-working-days.spec.js.map +1 -0
- package/docs/index.js +5 -2
- package/docs/jsgantt.js +5749 -0
- package/jsgantt.js +5749 -0
- package/package.json +10 -18
- package/pw-e2e.config.js +13 -0
- package/test-results/.last-run.json +4 -0
- package/protractor.conf.js +0 -29
package/dist/xml.js
ADDED
|
@@ -0,0 +1,345 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
+
exports.getXMLTask = exports.getXMLProject = exports.AddXMLTask = exports.getXMLNodeValue = exports.findXMLNode = exports.parseXMLString = exports.parseXML = void 0;
|
|
4
|
+
var task_1 = require("./task");
|
|
5
|
+
var date_utils_1 = require("./utils/date_utils");
|
|
6
|
+
var draw_utils_1 = require("./utils/draw_utils");
|
|
7
|
+
var general_utils_1 = require("./utils/general_utils");
|
|
8
|
+
var parseXML = function (pFile, pGanttVar) {
|
|
9
|
+
return (0, general_utils_1.makeRequest)(pFile, false, false)
|
|
10
|
+
.then(function (xmlDoc) {
|
|
11
|
+
(0, exports.AddXMLTask)(pGanttVar, xmlDoc);
|
|
12
|
+
});
|
|
13
|
+
};
|
|
14
|
+
exports.parseXML = parseXML;
|
|
15
|
+
var parseXMLString = function (pStr, pGanttVar) {
|
|
16
|
+
var xmlDoc;
|
|
17
|
+
if (typeof window.DOMParser != 'undefined') {
|
|
18
|
+
xmlDoc = (new window.DOMParser()).parseFromString(pStr, 'text/xml');
|
|
19
|
+
}
|
|
20
|
+
else if (typeof window.ActiveXObject != 'undefined' &&
|
|
21
|
+
new window.ActiveXObject('Microsoft.XMLDOM')) {
|
|
22
|
+
xmlDoc = new window.ActiveXObject('Microsoft.XMLDOM');
|
|
23
|
+
xmlDoc.async = 'false';
|
|
24
|
+
xmlDoc.loadXML(pStr);
|
|
25
|
+
}
|
|
26
|
+
(0, exports.AddXMLTask)(pGanttVar, xmlDoc);
|
|
27
|
+
};
|
|
28
|
+
exports.parseXMLString = parseXMLString;
|
|
29
|
+
var findXMLNode = function (pRoot, pNodeName) {
|
|
30
|
+
var vRetValue;
|
|
31
|
+
try {
|
|
32
|
+
vRetValue = pRoot.getElementsByTagName(pNodeName);
|
|
33
|
+
}
|
|
34
|
+
catch (error) {
|
|
35
|
+
;
|
|
36
|
+
} // do nothing, we'll return undefined
|
|
37
|
+
return vRetValue;
|
|
38
|
+
};
|
|
39
|
+
exports.findXMLNode = findXMLNode;
|
|
40
|
+
// pType can be 1=numeric, 2=String, all other values just return raw data
|
|
41
|
+
var getXMLNodeValue = function (pRoot, pNodeName, pType, pDefault) {
|
|
42
|
+
var vRetValue;
|
|
43
|
+
try {
|
|
44
|
+
vRetValue = pRoot.getElementsByTagName(pNodeName)[0].childNodes[0].nodeValue;
|
|
45
|
+
}
|
|
46
|
+
catch (error) {
|
|
47
|
+
if (typeof pDefault != 'undefined')
|
|
48
|
+
vRetValue = pDefault;
|
|
49
|
+
}
|
|
50
|
+
if (typeof vRetValue != 'undefined' && vRetValue != null) {
|
|
51
|
+
if (pType == 1)
|
|
52
|
+
vRetValue *= 1;
|
|
53
|
+
else if (pType == 2)
|
|
54
|
+
vRetValue = vRetValue.toString();
|
|
55
|
+
}
|
|
56
|
+
return vRetValue;
|
|
57
|
+
};
|
|
58
|
+
exports.getXMLNodeValue = getXMLNodeValue;
|
|
59
|
+
var AddXMLTask = function (pGanttVar, pXmlDoc) {
|
|
60
|
+
var project = '';
|
|
61
|
+
var Task;
|
|
62
|
+
var n = 0;
|
|
63
|
+
var m = 0;
|
|
64
|
+
var i = 0;
|
|
65
|
+
var j = 0;
|
|
66
|
+
var k = 0;
|
|
67
|
+
var maxPID = 0;
|
|
68
|
+
var ass = new Array();
|
|
69
|
+
var assRes = new Array();
|
|
70
|
+
var res = new Array();
|
|
71
|
+
var pars = new Array();
|
|
72
|
+
var projNode = (0, exports.findXMLNode)(pXmlDoc, 'Project');
|
|
73
|
+
if (typeof projNode != 'undefined' && projNode.length > 0) {
|
|
74
|
+
project = projNode[0].getAttribute('xmlns');
|
|
75
|
+
}
|
|
76
|
+
if (project == 'http://schemas.microsoft.com/project') {
|
|
77
|
+
pGanttVar.setDateInputFormat('yyyy-mm-dd');
|
|
78
|
+
Task = (0, exports.findXMLNode)(pXmlDoc, 'Task');
|
|
79
|
+
if (typeof Task == 'undefined')
|
|
80
|
+
n = 0;
|
|
81
|
+
else
|
|
82
|
+
n = Task.length;
|
|
83
|
+
var resources = (0, exports.findXMLNode)(pXmlDoc, 'Resource');
|
|
84
|
+
if (typeof resources == 'undefined') {
|
|
85
|
+
n = 0;
|
|
86
|
+
m = 0;
|
|
87
|
+
}
|
|
88
|
+
else
|
|
89
|
+
m = resources.length;
|
|
90
|
+
for (i = 0; i < m; i++) {
|
|
91
|
+
var resname = (0, exports.getXMLNodeValue)(resources[i], 'Name', 2, '');
|
|
92
|
+
var uid = (0, exports.getXMLNodeValue)(resources[i], 'UID', 1, -1);
|
|
93
|
+
if (resname.length > 0 && uid > 0)
|
|
94
|
+
res[uid] = resname;
|
|
95
|
+
}
|
|
96
|
+
var assignments = (0, exports.findXMLNode)(pXmlDoc, 'Assignment');
|
|
97
|
+
if (typeof assignments == 'undefined')
|
|
98
|
+
j = 0;
|
|
99
|
+
else
|
|
100
|
+
j = assignments.length;
|
|
101
|
+
for (i = 0; i < j; i++) {
|
|
102
|
+
var uid = void 0;
|
|
103
|
+
var resUID = (0, exports.getXMLNodeValue)(assignments[i], 'ResourceUID', 1, -1);
|
|
104
|
+
uid = (0, exports.getXMLNodeValue)(assignments[i], 'TaskUID', 1, -1);
|
|
105
|
+
if (uid > 0) {
|
|
106
|
+
if (resUID > 0)
|
|
107
|
+
assRes[uid] = res[resUID];
|
|
108
|
+
ass[uid] = assignments[i];
|
|
109
|
+
}
|
|
110
|
+
}
|
|
111
|
+
// Store information about parent UIDs in an easily searchable form
|
|
112
|
+
for (i = 0; i < n; i++) {
|
|
113
|
+
var uid = void 0;
|
|
114
|
+
uid = (0, exports.getXMLNodeValue)(Task[i], 'UID', 1, 0);
|
|
115
|
+
var vOutlineNumber = void 0;
|
|
116
|
+
if (uid != 0)
|
|
117
|
+
vOutlineNumber = (0, exports.getXMLNodeValue)(Task[i], 'OutlineNumber', 2, '0');
|
|
118
|
+
if (uid > 0)
|
|
119
|
+
pars[vOutlineNumber] = uid;
|
|
120
|
+
if (uid > maxPID)
|
|
121
|
+
maxPID = uid;
|
|
122
|
+
}
|
|
123
|
+
for (i = 0; i < n; i++) {
|
|
124
|
+
// optional parameters may not have an entry
|
|
125
|
+
// Task ID must NOT be zero otherwise it will be skipped
|
|
126
|
+
var pID = (0, exports.getXMLNodeValue)(Task[i], 'UID', 1, 0);
|
|
127
|
+
if (pID != 0) {
|
|
128
|
+
var pName = (0, exports.getXMLNodeValue)(Task[i], 'Name', 2, 'No Task Name');
|
|
129
|
+
var pStart = (0, exports.getXMLNodeValue)(Task[i], 'Start', 2, '');
|
|
130
|
+
var pEnd = (0, exports.getXMLNodeValue)(Task[i], 'Finish', 2, '');
|
|
131
|
+
var pPlanStart = (0, exports.getXMLNodeValue)(Task[i], 'PlanStart', 2, '');
|
|
132
|
+
var pPlanEnd = (0, exports.getXMLNodeValue)(Task[i], 'PlanFinish', 2, '');
|
|
133
|
+
var pDuration = (0, exports.getXMLNodeValue)(Task[i], 'Duration', 2, '');
|
|
134
|
+
var pLink = (0, exports.getXMLNodeValue)(Task[i], 'HyperlinkAddress', 2, '');
|
|
135
|
+
var pMile = (0, exports.getXMLNodeValue)(Task[i], 'Milestone', 1, 0);
|
|
136
|
+
var pComp = (0, exports.getXMLNodeValue)(Task[i], 'PercentWorkComplete', 1, 0);
|
|
137
|
+
var pCost = (0, exports.getXMLNodeValue)(Task[i], 'Cost', 2, 0);
|
|
138
|
+
var pGroup = (0, exports.getXMLNodeValue)(Task[i], 'Summary', 1, 0);
|
|
139
|
+
var pParent = 0;
|
|
140
|
+
var vOutlineLevel = (0, exports.getXMLNodeValue)(Task[i], 'OutlineLevel', 1, 0);
|
|
141
|
+
var vOutlineNumber = void 0;
|
|
142
|
+
if (vOutlineLevel > 1) {
|
|
143
|
+
vOutlineNumber = (0, exports.getXMLNodeValue)(Task[i], 'OutlineNumber', 2, '0');
|
|
144
|
+
pParent = pars[vOutlineNumber.substr(0, vOutlineNumber.lastIndexOf('.'))];
|
|
145
|
+
}
|
|
146
|
+
var pNotes = void 0;
|
|
147
|
+
try {
|
|
148
|
+
pNotes = Task[i].getElementsByTagName('Notes')[0].childNodes[1].nodeValue; //this should be a CDATA node
|
|
149
|
+
}
|
|
150
|
+
catch (error) {
|
|
151
|
+
pNotes = '';
|
|
152
|
+
}
|
|
153
|
+
var pRes = void 0;
|
|
154
|
+
if (typeof assRes[pID] != 'undefined')
|
|
155
|
+
pRes = assRes[pID];
|
|
156
|
+
else
|
|
157
|
+
pRes = '';
|
|
158
|
+
var predecessors = (0, exports.findXMLNode)(Task[i], 'PredecessorLink');
|
|
159
|
+
if (typeof predecessors == 'undefined')
|
|
160
|
+
j = 0;
|
|
161
|
+
else
|
|
162
|
+
j = predecessors.length;
|
|
163
|
+
var pDepend = '';
|
|
164
|
+
for (k = 0; k < j; k++) {
|
|
165
|
+
var depUID = (0, exports.getXMLNodeValue)(predecessors[k], 'PredecessorUID', 1, -1);
|
|
166
|
+
var depType = (0, exports.getXMLNodeValue)(predecessors[k], 'Type', 1, 1);
|
|
167
|
+
if (depUID > 0) {
|
|
168
|
+
if (pDepend.length > 0)
|
|
169
|
+
pDepend += ',';
|
|
170
|
+
switch (depType) {
|
|
171
|
+
case 0:
|
|
172
|
+
pDepend += depUID + 'FF';
|
|
173
|
+
break;
|
|
174
|
+
case 1:
|
|
175
|
+
pDepend += depUID + 'FS';
|
|
176
|
+
break;
|
|
177
|
+
case 2:
|
|
178
|
+
pDepend += depUID + 'SF';
|
|
179
|
+
break;
|
|
180
|
+
case 3:
|
|
181
|
+
pDepend += depUID + 'SS';
|
|
182
|
+
break;
|
|
183
|
+
default:
|
|
184
|
+
pDepend += depUID + 'FS';
|
|
185
|
+
break;
|
|
186
|
+
}
|
|
187
|
+
}
|
|
188
|
+
}
|
|
189
|
+
var pOpen = 1;
|
|
190
|
+
var pCaption = '';
|
|
191
|
+
var pClass = void 0;
|
|
192
|
+
if (pGroup > 0)
|
|
193
|
+
pClass = 'ggroupblack';
|
|
194
|
+
else if (pMile > 0)
|
|
195
|
+
pClass = 'gmilestone';
|
|
196
|
+
else
|
|
197
|
+
pClass = 'gtaskblue';
|
|
198
|
+
// check for split tasks
|
|
199
|
+
var splits = (0, exports.findXMLNode)(ass[pID], 'TimephasedData');
|
|
200
|
+
if (typeof splits == 'undefined')
|
|
201
|
+
j = 0;
|
|
202
|
+
else
|
|
203
|
+
j = splits.length;
|
|
204
|
+
var vSplitStart = pStart;
|
|
205
|
+
var vSplitEnd = pEnd;
|
|
206
|
+
var vSubCreated = false;
|
|
207
|
+
var vDepend = pDepend.replace(/,*[0-9]+[FS]F/g, '');
|
|
208
|
+
for (k = 0; k < j; k++) {
|
|
209
|
+
var vDuration = (0, exports.getXMLNodeValue)(splits[k], 'Value', 2, '0');
|
|
210
|
+
//remove all text
|
|
211
|
+
vDuration = '0' + vDuration.replace(/\D/g, '');
|
|
212
|
+
vDuration *= 1;
|
|
213
|
+
if ((vDuration == 0 && !vSubCreated) || (k + 1 == j && pGroup == 2)) {
|
|
214
|
+
// No time booked in the given period (or last entry)
|
|
215
|
+
// Make sure the parent task is set as a combined group
|
|
216
|
+
pGroup = 2;
|
|
217
|
+
// Handle last loop
|
|
218
|
+
if (k + 1 == j)
|
|
219
|
+
vDepend = pDepend.replace(/,*[0-9]+[FS]S/g, '');
|
|
220
|
+
// Now create a subtask
|
|
221
|
+
maxPID++;
|
|
222
|
+
vSplitEnd = (0, exports.getXMLNodeValue)(splits[k], (k + 1 == j) ? 'Finish' : 'Start', 2, '');
|
|
223
|
+
pGanttVar.AddTaskItem(new task_1.TaskItem(maxPID, pName, vSplitStart, vSplitEnd, 'gtaskblue', pLink, pMile, pRes, pComp, 0, pID, pOpen, vDepend, pCaption, pNotes, pGanttVar, pCost, pPlanStart, pPlanEnd, pDuration));
|
|
224
|
+
vSubCreated = true;
|
|
225
|
+
vDepend = '';
|
|
226
|
+
}
|
|
227
|
+
else if (vDuration != 0 && vSubCreated) {
|
|
228
|
+
vSplitStart = (0, exports.getXMLNodeValue)(splits[k], 'Start', 2, '');
|
|
229
|
+
vSubCreated = false;
|
|
230
|
+
}
|
|
231
|
+
}
|
|
232
|
+
if (vSubCreated)
|
|
233
|
+
pDepend = '';
|
|
234
|
+
// Finally add the task
|
|
235
|
+
pGanttVar.AddTaskItem(new task_1.TaskItem(pID, pName, pStart, pEnd, pClass, pLink, pMile, pRes, pComp, pGroup, pParent, pOpen, pDepend, pCaption, pNotes, pGanttVar, pCost, pPlanStart, pPlanEnd, pDuration, undefined, undefined, pClass));
|
|
236
|
+
}
|
|
237
|
+
}
|
|
238
|
+
}
|
|
239
|
+
else {
|
|
240
|
+
Task = pXmlDoc.getElementsByTagName('task');
|
|
241
|
+
n = Task.length;
|
|
242
|
+
for (i = 0; i < n; i++) {
|
|
243
|
+
// optional parameters may not have an entry
|
|
244
|
+
// Task ID must NOT be zero otherwise it will be skipped
|
|
245
|
+
var pID = (0, exports.getXMLNodeValue)(Task[i], 'pID', 1, 0);
|
|
246
|
+
if (pID != 0) {
|
|
247
|
+
var pName = (0, exports.getXMLNodeValue)(Task[i], 'pName', 2, 'No Task Name');
|
|
248
|
+
var pStart = (0, exports.getXMLNodeValue)(Task[i], 'pStart', 2, '');
|
|
249
|
+
var pEnd = (0, exports.getXMLNodeValue)(Task[i], 'pEnd', 2, '');
|
|
250
|
+
var pPlanStart = (0, exports.getXMLNodeValue)(Task[i], 'pPlanStart', 2, '');
|
|
251
|
+
var pPlanEnd = (0, exports.getXMLNodeValue)(Task[i], 'pPlanEnd', 2, '');
|
|
252
|
+
var pDuration = (0, exports.getXMLNodeValue)(Task[i], 'pDuration', 2, '');
|
|
253
|
+
var pLink = (0, exports.getXMLNodeValue)(Task[i], 'pLink', 2, '');
|
|
254
|
+
var pMile = (0, exports.getXMLNodeValue)(Task[i], 'pMile', 1, 0);
|
|
255
|
+
var pComp = (0, exports.getXMLNodeValue)(Task[i], 'pComp', 1, 0);
|
|
256
|
+
var pCost = (0, exports.getXMLNodeValue)(Task[i], 'pCost', 2, 0);
|
|
257
|
+
var pGroup = (0, exports.getXMLNodeValue)(Task[i], 'pGroup', 1, 0);
|
|
258
|
+
var pParent = (0, exports.getXMLNodeValue)(Task[i], 'pParent', 1, 0);
|
|
259
|
+
var pRes = (0, exports.getXMLNodeValue)(Task[i], 'pRes', 2, '');
|
|
260
|
+
var pOpen = (0, exports.getXMLNodeValue)(Task[i], 'pOpen', 1, 1);
|
|
261
|
+
var pDepend = (0, exports.getXMLNodeValue)(Task[i], 'pDepend', 2, '');
|
|
262
|
+
var pCaption = (0, exports.getXMLNodeValue)(Task[i], 'pCaption', 2, '');
|
|
263
|
+
var pNotes = (0, exports.getXMLNodeValue)(Task[i], 'pNotes', 2, '');
|
|
264
|
+
var pClass = (0, exports.getXMLNodeValue)(Task[i], 'pClass', 2, '');
|
|
265
|
+
var pPlanClass = (0, exports.getXMLNodeValue)(Task[i], 'pPlanClass', 2, '');
|
|
266
|
+
if (typeof pClass == 'undefined') {
|
|
267
|
+
if (pGroup > 0)
|
|
268
|
+
pClass = 'ggroupblack';
|
|
269
|
+
else if (pMile > 0)
|
|
270
|
+
pClass = 'gmilestone';
|
|
271
|
+
else
|
|
272
|
+
pClass = 'gtaskblue';
|
|
273
|
+
}
|
|
274
|
+
if (typeof pPlanClass == 'undefined')
|
|
275
|
+
pPlanClass = pClass;
|
|
276
|
+
// Finally add the task
|
|
277
|
+
pGanttVar.AddTaskItem(new task_1.TaskItem(pID, pName, pStart, pEnd, pClass, pLink, pMile, pRes, pComp, pGroup, pParent, pOpen, pDepend, pCaption, pNotes, pGanttVar, pCost, pPlanStart, pPlanEnd, pDuration, undefined, undefined, pPlanClass));
|
|
278
|
+
}
|
|
279
|
+
}
|
|
280
|
+
}
|
|
281
|
+
};
|
|
282
|
+
exports.AddXMLTask = AddXMLTask;
|
|
283
|
+
var getXMLProject = function () {
|
|
284
|
+
var vProject = '<?xml version="1.0" encoding="UTF-8" standalone="yes"?><project xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance">';
|
|
285
|
+
for (var i = 0; i < this.vTaskList.length; i++) {
|
|
286
|
+
vProject += this.getXMLTask(i, true);
|
|
287
|
+
}
|
|
288
|
+
vProject += '</project>';
|
|
289
|
+
return vProject;
|
|
290
|
+
};
|
|
291
|
+
exports.getXMLProject = getXMLProject;
|
|
292
|
+
var getXMLTask = function (pID, pIdx) {
|
|
293
|
+
var i = 0;
|
|
294
|
+
var vIdx = -1;
|
|
295
|
+
var vTask = '';
|
|
296
|
+
var vOutFrmt = (0, date_utils_1.parseDateFormatStr)(this.getDateInputFormat() + ' HH:MI:SS');
|
|
297
|
+
if (pIdx === true)
|
|
298
|
+
vIdx = pID;
|
|
299
|
+
else {
|
|
300
|
+
for (i = 0; i < this.vTaskList.length; i++) {
|
|
301
|
+
if (this.vTaskList[i].getID() == pID) {
|
|
302
|
+
vIdx = i;
|
|
303
|
+
break;
|
|
304
|
+
}
|
|
305
|
+
}
|
|
306
|
+
}
|
|
307
|
+
if (vIdx >= 0 && vIdx < this.vTaskList.length) {
|
|
308
|
+
/* Simplest way to return case sensitive node names is to just build a string */
|
|
309
|
+
vTask = '<task>';
|
|
310
|
+
vTask += '<pID>' + this.vTaskList[vIdx].getID() + '</pID>';
|
|
311
|
+
vTask += '<pName>' + this.vTaskList[vIdx].getName() + '</pName>';
|
|
312
|
+
vTask += '<pStart>' + (0, date_utils_1.formatDateStr)(this.vTaskList[vIdx].getStart(), vOutFrmt, this.vLangs[this.vLang]) + '</pStart>';
|
|
313
|
+
vTask += '<pEnd>' + (0, date_utils_1.formatDateStr)(this.vTaskList[vIdx].getEnd(), vOutFrmt, this.vLangs[this.vLang]) + '</pEnd>';
|
|
314
|
+
vTask += '<pPlanStart>' + (0, date_utils_1.formatDateStr)(this.vTaskList[vIdx].getPlanStart(), vOutFrmt, this.vLangs[this.vLang]) + '</pPlanStart>';
|
|
315
|
+
vTask += '<pPlanEnd>' + (0, date_utils_1.formatDateStr)(this.vTaskList[vIdx].getPlanEnd(), vOutFrmt, this.vLangs[this.vLang]) + '</pPlanEnd>';
|
|
316
|
+
vTask += '<pDuration>' + this.vTaskList[vIdx].getDuration() + '</pDuration>';
|
|
317
|
+
vTask += '<pClass>' + this.vTaskList[vIdx].getClass() + '</pClass>';
|
|
318
|
+
vTask += '<pLink>' + this.vTaskList[vIdx].getLink() + '</pLink>';
|
|
319
|
+
vTask += '<pMile>' + this.vTaskList[vIdx].getMile() + '</pMile>';
|
|
320
|
+
if (this.vTaskList[vIdx].getResource() != '\u00A0')
|
|
321
|
+
vTask += '<pRes>' + this.vTaskList[vIdx].getResource() + '</pRes>';
|
|
322
|
+
vTask += '<pComp>' + this.vTaskList[vIdx].getCompVal() + '</pComp>';
|
|
323
|
+
vTask += '<pCost>' + this.vTaskList[vIdx].getCost() + '</pCost>';
|
|
324
|
+
vTask += '<pGroup>' + this.vTaskList[vIdx].getGroup() + '</pGroup>';
|
|
325
|
+
vTask += '<pParent>' + this.vTaskList[vIdx].getParent() + '</pParent>';
|
|
326
|
+
vTask += '<pOpen>' + this.vTaskList[vIdx].getOpen() + '</pOpen>';
|
|
327
|
+
vTask += '<pDepend>';
|
|
328
|
+
var vDepList = this.vTaskList[vIdx].getDepend();
|
|
329
|
+
for (i = 0; i < vDepList.length; i++) {
|
|
330
|
+
if (i > 0)
|
|
331
|
+
vTask += ',';
|
|
332
|
+
if (vDepList[i] > 0)
|
|
333
|
+
vTask += vDepList[i] + this.vTaskList[vIdx].getDepType()[i];
|
|
334
|
+
}
|
|
335
|
+
vTask += '</pDepend>';
|
|
336
|
+
vTask += '<pCaption>' + this.vTaskList[vIdx].getCaption() + '</pCaption>';
|
|
337
|
+
var vTmpFrag = document.createDocumentFragment();
|
|
338
|
+
var vTmpDiv = (0, draw_utils_1.newNode)(vTmpFrag, 'div', null, null, this.vTaskList[vIdx].getNotes().innerHTML);
|
|
339
|
+
vTask += '<pNotes>' + vTmpDiv.innerHTML + '</pNotes>';
|
|
340
|
+
vTask += '<pPlanClass>' + this.vTaskList[vIdx].getPlanClass() + '</pPlanClass>';
|
|
341
|
+
vTask += '</task>';
|
|
342
|
+
}
|
|
343
|
+
return vTask;
|
|
344
|
+
};
|
|
345
|
+
exports.getXMLTask = getXMLTask;
|
|
@@ -0,0 +1,79 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
/**
|
|
3
|
+
* Page Object Model for the jsGantt demo page.
|
|
4
|
+
* Wraps common selectors and helpers used across e2e specs.
|
|
5
|
+
*/
|
|
6
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
7
|
+
exports.GanttPage = exports.DEMO_URL = void 0;
|
|
8
|
+
exports.DEMO_URL = 'demo.html';
|
|
9
|
+
class GanttPage {
|
|
10
|
+
constructor(page) {
|
|
11
|
+
this.page = page;
|
|
12
|
+
}
|
|
13
|
+
async goto(url = exports.DEMO_URL) {
|
|
14
|
+
await this.page.goto(url, { waitUntil: 'load' });
|
|
15
|
+
await this.page.waitForSelector('#embedded-Gantt .gcharttable', { timeout: 10000 });
|
|
16
|
+
// Allow layout to settle
|
|
17
|
+
await this.page.waitForTimeout(400);
|
|
18
|
+
}
|
|
19
|
+
/**
|
|
20
|
+
* Apply CSS zoom to the Gantt container, simulating browser-level zoom.
|
|
21
|
+
* zoom=1.0 restores 100%.
|
|
22
|
+
*/
|
|
23
|
+
async applyZoom(zoom) {
|
|
24
|
+
await this.page.evaluate((z) => {
|
|
25
|
+
const el = document.querySelector('#embedded-Gantt');
|
|
26
|
+
if (el)
|
|
27
|
+
el.style.zoom = z === 1 ? '' : String(z);
|
|
28
|
+
}, zoom);
|
|
29
|
+
}
|
|
30
|
+
/**
|
|
31
|
+
* Measure bar positions relative to the chart table's left edge.
|
|
32
|
+
* Returns up to `limit` bars.
|
|
33
|
+
*/
|
|
34
|
+
async getBarMetrics(limit = 8) {
|
|
35
|
+
return this.page.evaluate((lim) => {
|
|
36
|
+
const chartTable = document.querySelector('.gcharttable');
|
|
37
|
+
if (!chartTable)
|
|
38
|
+
return [];
|
|
39
|
+
const chartRect = chartTable.getBoundingClientRect();
|
|
40
|
+
return Array.from(document.querySelectorAll('[id*="bardiv_"]'))
|
|
41
|
+
.slice(0, lim)
|
|
42
|
+
.map(bar => {
|
|
43
|
+
const el = bar;
|
|
44
|
+
const rect = el.getBoundingClientRect();
|
|
45
|
+
return {
|
|
46
|
+
id: el.id.replace(/.*bardiv_/, 'bar_'),
|
|
47
|
+
styleLeft: parseInt(el.style.left || '0', 10),
|
|
48
|
+
styleWidth: parseInt(el.style.width || '0', 10),
|
|
49
|
+
viewportLeft: Math.round((rect.left - chartRect.left) * 100) / 100,
|
|
50
|
+
viewportWidth: Math.round(rect.width * 100) / 100,
|
|
51
|
+
};
|
|
52
|
+
});
|
|
53
|
+
}, limit);
|
|
54
|
+
}
|
|
55
|
+
/**
|
|
56
|
+
* Measure the last header row's column widths in viewport pixels.
|
|
57
|
+
* The last row is the finest date granularity (day/week/month).
|
|
58
|
+
*/
|
|
59
|
+
async getColumnMetrics(limit = 20) {
|
|
60
|
+
return this.page.evaluate((lim) => {
|
|
61
|
+
const headerTable = document.querySelector('.gcharttableh');
|
|
62
|
+
if (!headerTable)
|
|
63
|
+
return [];
|
|
64
|
+
const rows = headerTable.querySelectorAll('tr');
|
|
65
|
+
const lastRow = rows[rows.length - 1];
|
|
66
|
+
if (!lastRow)
|
|
67
|
+
return [];
|
|
68
|
+
return Array.from(lastRow.querySelectorAll('td'))
|
|
69
|
+
.slice(0, lim)
|
|
70
|
+
.map((td, i) => ({
|
|
71
|
+
index: i,
|
|
72
|
+
text: td.innerText.trim().slice(0, 10),
|
|
73
|
+
viewportWidth: Math.round(td.getBoundingClientRect().width * 100) / 100,
|
|
74
|
+
}));
|
|
75
|
+
}, limit);
|
|
76
|
+
}
|
|
77
|
+
}
|
|
78
|
+
exports.GanttPage = GanttPage;
|
|
79
|
+
//# sourceMappingURL=gantt.page.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"gantt.page.js","sourceRoot":"","sources":["../test/e2e/gantt.page.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,96 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
/**
|
|
3
|
+
* E2E tests for setMinDate / setMaxDate via setOptions.
|
|
4
|
+
*
|
|
5
|
+
* Bug: passing vMinDate or vMaxDate to setOptions threw
|
|
6
|
+
* "TypeError: this.setMinDate is not a function"
|
|
7
|
+
* because no setter existed on GanttChart for those options.
|
|
8
|
+
*
|
|
9
|
+
* Fix: added setMinDate / setMaxDate setters that store the override date string,
|
|
10
|
+
* and updated Draw() to use them (falling back to auto-computed dates when empty).
|
|
11
|
+
*/
|
|
12
|
+
var _a;
|
|
13
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
14
|
+
const test_1 = require("@playwright/test");
|
|
15
|
+
const BASE_URL = (_a = process.env.JSGANTT_E2E_BASE_URL) !== null && _a !== void 0 ? _a : 'http://localhost:8080';
|
|
16
|
+
async function gotoDemo(page) {
|
|
17
|
+
const url = BASE_URL.replace(/\/$/, '') + '/demo.html';
|
|
18
|
+
await page.goto(url, { waitUntil: 'load' });
|
|
19
|
+
await page.waitForFunction(() => typeof window.JSGantt !== 'undefined', { timeout: 15000 });
|
|
20
|
+
}
|
|
21
|
+
test_1.test.describe('setMinDate / setMaxDate via setOptions', () => {
|
|
22
|
+
test_1.test('setOptions with vMinDate and vMaxDate does not throw', async ({ page }) => {
|
|
23
|
+
await gotoDemo(page);
|
|
24
|
+
const result = await page.evaluate(() => {
|
|
25
|
+
const container = document.getElementById('embedded-Gantt');
|
|
26
|
+
container.innerHTML = '';
|
|
27
|
+
let error = null;
|
|
28
|
+
try {
|
|
29
|
+
const g = new window.JSGantt.GanttChart(container, 'week');
|
|
30
|
+
g.setOptions({
|
|
31
|
+
vDateInputFormat: 'yyyy-mm-dd',
|
|
32
|
+
vMinDate: '2024-01-01',
|
|
33
|
+
vMaxDate: '2024-06-30',
|
|
34
|
+
vFormat: 'week',
|
|
35
|
+
});
|
|
36
|
+
const T = window.JSGantt.TaskItem;
|
|
37
|
+
g.AddTaskItem(new T(1, 'Task A', '2024-02-01', '2024-04-30', 'gtaskblue', '', 0, '', 0, 0, 0, 1, '', '', '', g));
|
|
38
|
+
g.Draw();
|
|
39
|
+
} catch (e) {
|
|
40
|
+
error = e.message;
|
|
41
|
+
}
|
|
42
|
+
return { error };
|
|
43
|
+
});
|
|
44
|
+
test_1.expect(result.error, 'setOptions with vMinDate/vMaxDate should not throw').toBeNull();
|
|
45
|
+
});
|
|
46
|
+
|
|
47
|
+
test_1.test('vMinDate overrides the chart start boundary', async ({ page }) => {
|
|
48
|
+
await gotoDemo(page);
|
|
49
|
+
const result = await page.evaluate(() => {
|
|
50
|
+
const container = document.getElementById('embedded-Gantt');
|
|
51
|
+
container.innerHTML = '';
|
|
52
|
+
const g = new window.JSGantt.GanttChart(container, 'week');
|
|
53
|
+
g.setOptions({
|
|
54
|
+
vDateInputFormat: 'yyyy-mm-dd',
|
|
55
|
+
vMinDate: '2024-01-01',
|
|
56
|
+
vMaxDate: '2024-12-31',
|
|
57
|
+
vFormat: 'week',
|
|
58
|
+
vShowDeps: 0,
|
|
59
|
+
});
|
|
60
|
+
const T = window.JSGantt.TaskItem;
|
|
61
|
+
// Task starts in March — with vMinDate=Jan 1, the chart should start before March
|
|
62
|
+
g.AddTaskItem(new T(1, 'Task A', '2024-03-01', '2024-05-31', 'gtaskblue', '', 0, '', 0, 0, 0, 1, '', '', '', g));
|
|
63
|
+
g.Draw();
|
|
64
|
+
// Check that chart head table was rendered inside our container
|
|
65
|
+
const chartHead = container.querySelector('.gcharthead');
|
|
66
|
+
const chartTable = container.querySelector('.gcharttable');
|
|
67
|
+
const allText = container.innerHTML;
|
|
68
|
+
return {
|
|
69
|
+
hasChartHead: !!chartHead,
|
|
70
|
+
hasChartTable: !!chartTable,
|
|
71
|
+
contains2024: allText.includes('2024'),
|
|
72
|
+
};
|
|
73
|
+
});
|
|
74
|
+
test_1.expect(result.hasChartTable, 'chart table should be rendered').toBe(true);
|
|
75
|
+
test_1.expect(result.contains2024, 'chart should show year 2024 from vMinDate/vMaxDate range').toBe(true);
|
|
76
|
+
});
|
|
77
|
+
|
|
78
|
+
test_1.test('getMinDate and getMaxDate return the set values', async ({ page }) => {
|
|
79
|
+
await gotoDemo(page);
|
|
80
|
+
const result = await page.evaluate(() => {
|
|
81
|
+
const container = document.getElementById('embedded-Gantt');
|
|
82
|
+
container.innerHTML = '';
|
|
83
|
+
const g = new window.JSGantt.GanttChart(container, 'week');
|
|
84
|
+
g.setOptions({
|
|
85
|
+
vMinDate: '2024-01-01',
|
|
86
|
+
vMaxDate: '2024-12-31',
|
|
87
|
+
});
|
|
88
|
+
return {
|
|
89
|
+
minDate: g.getMinDate(),
|
|
90
|
+
maxDate: g.getMaxDate(),
|
|
91
|
+
};
|
|
92
|
+
});
|
|
93
|
+
test_1.expect(result.minDate).toBe('2024-01-01');
|
|
94
|
+
test_1.expect(result.maxDate).toBe('2024-12-31');
|
|
95
|
+
});
|
|
96
|
+
});
|
|
@@ -0,0 +1,90 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
/**
|
|
3
|
+
* E2E tests for issue #172: Week view creates a "step" (vertical row
|
|
4
|
+
* misalignment) between the left task-list panel and the right chart panel.
|
|
5
|
+
*
|
|
6
|
+
* Root behaviour tested:
|
|
7
|
+
* For every format (week, month, day, quarter), and for the specific
|
|
8
|
+
* combination reported in the issue (week format with hidden columns),
|
|
9
|
+
* the top edge of each body row in .gtasktable must align with the
|
|
10
|
+
* corresponding row in .gcharttable within ALIGN_TOLERANCE_PX.
|
|
11
|
+
*
|
|
12
|
+
* Additionally the left and right header panels must be the same total
|
|
13
|
+
* height so the body rows stay in sync even after scrolling.
|
|
14
|
+
*/
|
|
15
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
16
|
+
const test_1 = require("@playwright/test");
|
|
17
|
+
const ALIGN_TOLERANCE_PX = 2;
|
|
18
|
+
async function gotoDemo(page) {
|
|
19
|
+
var _a;
|
|
20
|
+
const baseURL = (_a = process.env.JSGANTT_E2E_BASE_URL) !== null && _a !== void 0 ? _a : 'http://localhost:8080';
|
|
21
|
+
const url = baseURL.replace(/\/$/, '') + '/demo.html';
|
|
22
|
+
await page.goto(url, { waitUntil: 'load' });
|
|
23
|
+
await page.waitForFunction(() => typeof window.JSGantt !== 'undefined', { timeout: 15000 });
|
|
24
|
+
}
|
|
25
|
+
async function measureRowAlignment(page, format, options = {}) {
|
|
26
|
+
return page.evaluate(({ fmt, opts }) => {
|
|
27
|
+
const container = document.getElementById('embedded-Gantt');
|
|
28
|
+
container.innerHTML = '';
|
|
29
|
+
const g = new window.JSGantt.GanttChart(container, fmt);
|
|
30
|
+
g.setOptions(Object.assign({ vFormat: fmt, vShowDeps: 0, vLang: 'en' }, opts));
|
|
31
|
+
const T = window.JSGantt.TaskItem;
|
|
32
|
+
g.AddTaskItem(new T(1, 'Group A', '2024-01-01', '2024-03-31', 'ggroupblack', '', 0, '', 0, 1, 0, 1, '', '', '', g));
|
|
33
|
+
g.AddTaskItem(new T(2, 'Task 1', '2024-01-01', '2024-01-14', 'gtaskblue', '', 0, 'R1', 0, 0, 1, 1, '', '', '', g));
|
|
34
|
+
g.AddTaskItem(new T(3, 'Task 2', '2024-01-15', '2024-02-28', 'gtaskgreen', '', 0, 'R2', 0, 0, 1, 1, '', '', '', g));
|
|
35
|
+
g.AddTaskItem(new T(4, 'Task 3', '2024-03-01', '2024-03-31', 'gtaskorange', '', 0, 'R3', 0, 0, 1, 1, '', '', '', g));
|
|
36
|
+
g.Draw();
|
|
37
|
+
const leftTable = document.querySelector('.gtasktable');
|
|
38
|
+
const rightTable = document.querySelector('.gcharttable');
|
|
39
|
+
const leftHeaderEl = document.querySelector('.gtasktableh');
|
|
40
|
+
const rightHeaderEl = document.querySelector('.gcharttableh');
|
|
41
|
+
if (!leftTable || !rightTable || !leftHeaderEl || !rightHeaderEl) {
|
|
42
|
+
return { leftHeaderHeight: 0, rightHeaderHeight: 0, maxBodyDrift: -1, rowCount: 0, misalignedRows: [] };
|
|
43
|
+
}
|
|
44
|
+
const leftHeaderHeight = Math.round(leftHeaderEl.getBoundingClientRect().height * 10) / 10;
|
|
45
|
+
const rightHeaderHeight = Math.round(rightHeaderEl.getBoundingClientRect().height * 10) / 10;
|
|
46
|
+
const leftRows = Array.from(leftTable.querySelectorAll('tr')).map(tr => Math.round(tr.getBoundingClientRect().top * 10) / 10);
|
|
47
|
+
const rightRows = Array.from(rightTable.querySelectorAll('tr')).map(tr => Math.round(tr.getBoundingClientRect().top * 10) / 10);
|
|
48
|
+
const count = Math.min(leftRows.length, rightRows.length);
|
|
49
|
+
let maxBodyDrift = 0;
|
|
50
|
+
const misalignedRows = [];
|
|
51
|
+
for (let i = 0; i < count; i++) {
|
|
52
|
+
const drift = Math.abs(leftRows[i] - rightRows[i]);
|
|
53
|
+
if (drift > maxBodyDrift)
|
|
54
|
+
maxBodyDrift = drift;
|
|
55
|
+
if (drift > 2)
|
|
56
|
+
misalignedRows.push({ index: i, leftTop: leftRows[i], rightTop: rightRows[i], drift });
|
|
57
|
+
}
|
|
58
|
+
return { leftHeaderHeight, rightHeaderHeight, maxBodyDrift: Math.round(maxBodyDrift * 10) / 10, rowCount: count, misalignedRows };
|
|
59
|
+
}, { fmt: format, opts: options });
|
|
60
|
+
}
|
|
61
|
+
const FORMATS = ['week', 'month', 'day', 'quarter'];
|
|
62
|
+
test_1.test.describe('Issue #172 — left/right panel row alignment', () => {
|
|
63
|
+
for (const fmt of FORMATS) {
|
|
64
|
+
(0, test_1.test)(`${fmt} format: body rows are aligned between task list and chart`, async ({ page }) => {
|
|
65
|
+
await gotoDemo(page);
|
|
66
|
+
const result = await measureRowAlignment(page, fmt);
|
|
67
|
+
(0, test_1.expect)(result.rowCount, `should find task rows in ${fmt} format`).toBeGreaterThan(0);
|
|
68
|
+
(0, test_1.expect)(result.maxBodyDrift, `${fmt}: max row drift=${result.maxBodyDrift}px; misaligned: ${JSON.stringify(result.misalignedRows)}`).toBeLessThanOrEqual(ALIGN_TOLERANCE_PX);
|
|
69
|
+
});
|
|
70
|
+
(0, test_1.test)(`${fmt} format: left and right header panels are the same height`, async ({ page }) => {
|
|
71
|
+
await gotoDemo(page);
|
|
72
|
+
const result = await measureRowAlignment(page, fmt);
|
|
73
|
+
const heightDiff = Math.abs(result.leftHeaderHeight - result.rightHeaderHeight);
|
|
74
|
+
(0, test_1.expect)(heightDiff, `${fmt}: left header=${result.leftHeaderHeight}px, right header=${result.rightHeaderHeight}px, diff=${heightDiff}px`).toBeLessThanOrEqual(ALIGN_TOLERANCE_PX);
|
|
75
|
+
});
|
|
76
|
+
}
|
|
77
|
+
(0, test_1.test)('week format with hidden columns (exact scenario from issue #172)', async ({ page }) => {
|
|
78
|
+
await gotoDemo(page);
|
|
79
|
+
// The issue was reported with columns hidden via editor options
|
|
80
|
+
const result = await measureRowAlignment(page, 'week', {
|
|
81
|
+
vShowRes: 0, vShowCost: 0, vShowComp: 0, vShowDur: 0,
|
|
82
|
+
vShowStartDate: 0, vShowEndDate: 0,
|
|
83
|
+
});
|
|
84
|
+
(0, test_1.expect)(result.rowCount, 'should find task rows').toBeGreaterThan(0);
|
|
85
|
+
(0, test_1.expect)(result.maxBodyDrift, `week+hidden cols: max drift=${result.maxBodyDrift}px; misaligned rows: ${JSON.stringify(result.misalignedRows)}`).toBeLessThanOrEqual(ALIGN_TOLERANCE_PX);
|
|
86
|
+
const heightDiff = Math.abs(result.leftHeaderHeight - result.rightHeaderHeight);
|
|
87
|
+
(0, test_1.expect)(heightDiff, `header height mismatch: left=${result.leftHeaderHeight}px right=${result.rightHeaderHeight}px`).toBeLessThanOrEqual(ALIGN_TOLERANCE_PX);
|
|
88
|
+
});
|
|
89
|
+
});
|
|
90
|
+
//# sourceMappingURL=issue172-row-alignment.spec.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"issue172-row-alignment.spec.js","sourceRoot":"","sources":["../test/e2e/issue172-row-alignment.spec.ts"],"names":[],"mappings":"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"}
|