orgchart 5.0.0 → 6.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/.github/workflows/publish.yml +32 -0
- package/README.md +172 -93
- package/README.zh-cn.md +163 -74
- package/README.zh-tw.md +163 -74
- package/bower.json +6 -9
- package/demo/10000-nodes.html +139 -0
- package/demo/ajax-datasource.html +46 -45
- package/demo/bottom2top.html +12 -9
- package/demo/center-on-selected-node.html +21 -17
- package/demo/color-coded.html +12 -9
- package/demo/css/style.css +28 -0
- package/demo/custom-icons.html +12 -9
- package/demo/custom-template.html +12 -9
- package/demo/data-prop-compact.html +11 -8
- package/demo/data-prop-hybrid.html +79 -50
- package/demo/default-collapsed.html +12 -9
- package/demo/drag-drop-hybrid-chart.html +17 -14
- package/demo/drag-drop.html +21 -16
- package/demo/edit-chart.html +148 -94
- package/demo/edit-hybrid-chart.html +178 -135
- package/demo/expand-to-given-depth.html +30 -22
- package/demo/export-chart-pdf.html +12 -9
- package/demo/export-chart-with-pictures.html +19 -12
- package/demo/export-chart.html +12 -9
- package/demo/family-tree.html +14 -11
- package/demo/familytree-custom-properties.html +108 -0
- package/demo/filter-node.html +104 -57
- package/demo/get-hierarchy.html +17 -12
- package/demo/get-related-nodes.html +27 -17
- package/demo/index.html +5 -2
- package/demo/integrate-map.html +32 -27
- package/demo/left2right.html +12 -9
- package/demo/level-offset.html +16 -15
- package/demo/link-node.html +12 -9
- package/demo/local-datasource.html +11 -8
- package/demo/minimap.html +224 -0
- package/demo/nodes-of-different-widths.html +11 -8
- package/demo/ondemand-loading-data.html +88 -91
- package/demo/option-createNode.html +28 -17
- package/demo/pan-zoom.html +20 -11
- package/demo/reload-data.html +17 -14
- package/demo/report-path.html +59 -29
- package/demo/responsive-design.html +14 -11
- package/demo/right2left.html +12 -9
- package/demo/toggle-sibs-resp.html +12 -9
- package/demo/ul-datasource.html +11 -8
- package/demo/vertical-level.html +12 -9
- package/dist/css/{jquery.orgchart.css → orgchart.css} +143 -80
- package/dist/css/orgchart.min.css +1 -0
- package/dist/js/orgchart.js +4101 -0
- package/dist/js/orgchart.min.js +2 -0
- package/dist/js/orgchart.min.js.map +1 -0
- package/gulpfile.js +37 -26
- package/package.json +32 -32
- package/src/css/{jquery.orgchart.css → orgchart.css} +143 -80
- package/src/js/orgchart.js +4101 -0
- package/test/cypress/e2e/demo-interactions.cy.js +91 -0
- package/test/cypress/e2e/demo-rendering.cy.js +100 -0
- package/test/cypress/e2e/drag-drop-hybrid-chart.cy.js +22 -0
- package/test/cypress/e2e/edit-chart.cy.js +20 -0
- package/test/cypress/e2e/level-offset.cy.js +21 -0
- package/test/cypress/e2e/minimap.cy.js +66 -0
- package/test/cypress/e2e/pan-zoom.cy.js +165 -0
- package/test/cypress/e2e/report-path.cy.js +20 -0
- package/test/cypress/e2e/vertical-vevel.cy.js +5 -3
- package/test/e2e/local-datasource/test.js +1 -1
- package/test/integration/init-tests.js +168 -62
- package/test/integration/tests.js +1034 -56
- package/test/unit/lifecycle-builders-export.tests.js +1426 -0
- package/test/unit/minimap.tests.js +210 -0
- package/test/unit/tests.js +2372 -252
- package/dist/css/jquery.orgchart.min.css +0 -1
- package/dist/js/jquery.orgchart.js +0 -1741
- package/dist/js/jquery.orgchart.min.js +0 -5
- package/dist/js/jquery.orgchart.min.js.map +0 -1
- package/src/js/jquery.orgchart.js +0 -1741
package/test/unit/tests.js
CHANGED
|
@@ -1,16 +1,139 @@
|
|
|
1
|
-
|
|
2
|
-
|
|
3
|
-
|
|
4
|
-
|
|
1
|
+
const chai = require("chai");
|
|
2
|
+
const sinon = require("sinon");
|
|
3
|
+
const sinonChai = require("sinon-chai").default;
|
|
4
|
+
const should = chai.should();
|
|
5
5
|
chai.use(sinonChai);
|
|
6
6
|
require('jsdom-global')();
|
|
7
|
-
|
|
8
|
-
require('../../src/js/
|
|
7
|
+
process.env.ORGCHART_TEST = '1';
|
|
8
|
+
const OrgChart = require('../../src/js/orgchart');
|
|
9
|
+
const getState = OrgChart.__testing__.getState;
|
|
10
|
+
const setState = OrgChart.__testing__.setState;
|
|
11
|
+
|
|
12
|
+
function query(selector, root) {
|
|
13
|
+
return (root || document).querySelector(selector);
|
|
14
|
+
}
|
|
15
|
+
|
|
16
|
+
function queryAll(selector, root) {
|
|
17
|
+
return Array.from((root || document).querySelectorAll(selector));
|
|
18
|
+
}
|
|
19
|
+
|
|
20
|
+
function createElementFromHtml(html) {
|
|
21
|
+
const template = document.createElement('template');
|
|
22
|
+
|
|
23
|
+
template.innerHTML = html.trim();
|
|
24
|
+
return template.content.firstElementChild;
|
|
25
|
+
}
|
|
26
|
+
|
|
27
|
+
function siblingElements(element, selector) {
|
|
28
|
+
if (!element || !element.parentElement) {
|
|
29
|
+
return [];
|
|
30
|
+
}
|
|
31
|
+
return Array.from(element.parentElement.children).filter(function (childEl) {
|
|
32
|
+
return childEl !== element && (!selector || childEl.matches(selector));
|
|
33
|
+
});
|
|
34
|
+
}
|
|
35
|
+
|
|
36
|
+
function childElements(element, selector) {
|
|
37
|
+
return Array.from(element ? element.children : []).filter(function (childEl) {
|
|
38
|
+
return !selector || childEl.matches(selector);
|
|
39
|
+
});
|
|
40
|
+
}
|
|
41
|
+
|
|
42
|
+
function closestElement(element, selector) {
|
|
43
|
+
return element ? element.closest(selector) : null;
|
|
44
|
+
}
|
|
45
|
+
|
|
46
|
+
function firstSibling(element, selector) {
|
|
47
|
+
return siblingElements(element, selector)[0] || null;
|
|
48
|
+
}
|
|
49
|
+
|
|
50
|
+
function previousSiblings(element, selector) {
|
|
51
|
+
const siblings = [];
|
|
52
|
+
let current = element ? element.previousElementSibling : null;
|
|
53
|
+
|
|
54
|
+
while (current) {
|
|
55
|
+
if (!selector || current.matches(selector)) {
|
|
56
|
+
siblings.push(current);
|
|
57
|
+
}
|
|
58
|
+
current = current.previousElementSibling;
|
|
59
|
+
}
|
|
60
|
+
|
|
61
|
+
return siblings;
|
|
62
|
+
}
|
|
63
|
+
|
|
64
|
+
function nextSiblings(element, selector) {
|
|
65
|
+
const siblings = [];
|
|
66
|
+
let current = element ? element.nextElementSibling : null;
|
|
67
|
+
|
|
68
|
+
while (current) {
|
|
69
|
+
if (!selector || current.matches(selector)) {
|
|
70
|
+
siblings.push(current);
|
|
71
|
+
}
|
|
72
|
+
current = current.nextElementSibling;
|
|
73
|
+
}
|
|
74
|
+
|
|
75
|
+
return siblings;
|
|
76
|
+
}
|
|
77
|
+
|
|
78
|
+
function addClasses(element, classNames) {
|
|
79
|
+
if (!element) {
|
|
80
|
+
return element;
|
|
81
|
+
}
|
|
82
|
+
|
|
83
|
+
classNames.split(/\s+/).filter(Boolean).forEach(function (className) {
|
|
84
|
+
element.classList.add(className);
|
|
85
|
+
});
|
|
86
|
+
|
|
87
|
+
return element;
|
|
88
|
+
}
|
|
89
|
+
|
|
90
|
+
function removeClasses(element, classNames) {
|
|
91
|
+
if (!element) {
|
|
92
|
+
return element;
|
|
93
|
+
}
|
|
94
|
+
|
|
95
|
+
classNames.split(/\s+/).filter(Boolean).forEach(function (className) {
|
|
96
|
+
element.classList.remove(className);
|
|
97
|
+
});
|
|
98
|
+
|
|
99
|
+
return element;
|
|
100
|
+
}
|
|
101
|
+
|
|
102
|
+
function matchesSelector(element, selector) {
|
|
103
|
+
return !!(element && element.matches(selector));
|
|
104
|
+
}
|
|
105
|
+
|
|
106
|
+
function setOneTimeListener(element, type, data, listener) {
|
|
107
|
+
function once(event) {
|
|
108
|
+
event.data = data;
|
|
109
|
+
element.removeEventListener(type, once);
|
|
110
|
+
listener.call(element, event);
|
|
111
|
+
}
|
|
112
|
+
|
|
113
|
+
element.addEventListener(type, once);
|
|
114
|
+
}
|
|
115
|
+
|
|
116
|
+
function triggerEvent(element, type) {
|
|
117
|
+
element.dispatchEvent(new window.Event(type, { bubbles: true }));
|
|
118
|
+
}
|
|
119
|
+
|
|
120
|
+
function refreshNodeReferences(chartEl) {
|
|
121
|
+
$laolao = query('#n1', chartEl);
|
|
122
|
+
$bomiao = query('#n2', chartEl);
|
|
123
|
+
$sumiao = query('#n3', chartEl);
|
|
124
|
+
$hongmiao = query('#n4', chartEl);
|
|
125
|
+
$tiehua = query('#n5', chartEl);
|
|
126
|
+
$heihei = query('#n6', chartEl);
|
|
127
|
+
$pangpang = query('#n7', chartEl);
|
|
128
|
+
$dandan = query('#n8', chartEl);
|
|
129
|
+
$erdan = query('#n9', chartEl);
|
|
130
|
+
$sandan = query('#n10', chartEl);
|
|
131
|
+
}
|
|
9
132
|
|
|
10
133
|
describe('orgchart -- unit tests', function () {
|
|
11
|
-
|
|
12
|
-
|
|
13
|
-
ds = {
|
|
134
|
+
let $container;
|
|
135
|
+
|
|
136
|
+
const ds = {
|
|
14
137
|
'id': 'n1',
|
|
15
138
|
'name': 'Lao Lao',
|
|
16
139
|
'title': 'general manager',
|
|
@@ -37,9 +160,40 @@ describe('orgchart -- unit tests', function () {
|
|
|
37
160
|
},
|
|
38
161
|
{ 'id': 'n4', 'name': 'Hong Miao', 'title': 'department manager' }
|
|
39
162
|
]
|
|
40
|
-
}
|
|
41
|
-
|
|
42
|
-
|
|
163
|
+
};
|
|
164
|
+
|
|
165
|
+
const baseDs = JSON.stringify({
|
|
166
|
+
'id': 'n1',
|
|
167
|
+
'name': 'Lao Lao',
|
|
168
|
+
'title': 'general manager',
|
|
169
|
+
'children': [
|
|
170
|
+
{ 'id': 'n2', 'name': 'Bo Miao', 'title': 'department manager' },
|
|
171
|
+
{ 'id': 'n3', 'name': 'Su Miao', 'title': 'department manager',
|
|
172
|
+
'children': [
|
|
173
|
+
{ 'id': 'n5', 'name': 'Tie Hua', 'title': 'senior engineer',
|
|
174
|
+
'children': [
|
|
175
|
+
{ 'id': 'n8', 'name': 'Dan Dan', 'title': 'engineer' }
|
|
176
|
+
]
|
|
177
|
+
},
|
|
178
|
+
{ 'id': 'n6', 'name': 'Hei Hei', 'title': 'senior engineer',
|
|
179
|
+
'children': [
|
|
180
|
+
{ 'id': 'n9', 'name': 'Er Dan', 'title': 'engineer' }
|
|
181
|
+
]
|
|
182
|
+
},
|
|
183
|
+
{ 'id': 'n7', 'name': 'Pang Pang', 'title': 'senior engineer',
|
|
184
|
+
'children': [
|
|
185
|
+
{ 'id': 'n10', 'name': 'San Dan', 'title': 'engineer' }
|
|
186
|
+
]
|
|
187
|
+
}
|
|
188
|
+
]
|
|
189
|
+
},
|
|
190
|
+
{ 'id': 'n4', 'name': 'Hong Miao', 'title': 'department manager' }
|
|
191
|
+
]
|
|
192
|
+
});
|
|
193
|
+
|
|
194
|
+
let oc = {};
|
|
195
|
+
|
|
196
|
+
const hierarchy = {
|
|
43
197
|
id: 'n1',
|
|
44
198
|
children: [
|
|
45
199
|
{ id: 'n2' },
|
|
@@ -64,49 +218,80 @@ describe('orgchart -- unit tests', function () {
|
|
|
64
218
|
},
|
|
65
219
|
{ id: 'n4' }
|
|
66
220
|
]
|
|
67
|
-
}
|
|
68
|
-
|
|
69
|
-
$
|
|
70
|
-
$
|
|
71
|
-
$
|
|
72
|
-
$
|
|
73
|
-
$
|
|
74
|
-
$
|
|
75
|
-
$
|
|
76
|
-
$
|
|
77
|
-
$
|
|
78
|
-
$
|
|
221
|
+
};
|
|
222
|
+
|
|
223
|
+
let $laolao;
|
|
224
|
+
let $bomiao;
|
|
225
|
+
let $sumiao;
|
|
226
|
+
let $hongmiao;
|
|
227
|
+
let $chunmiao;
|
|
228
|
+
let $tiehua;
|
|
229
|
+
let $heihei;
|
|
230
|
+
let $pangpang;
|
|
231
|
+
let $dandan;
|
|
232
|
+
let $erdan;
|
|
233
|
+
let $sandan;
|
|
79
234
|
|
|
80
235
|
beforeEach(function () {
|
|
81
|
-
|
|
236
|
+
document.body.innerHTML = '<div id="chart-container"></div>';
|
|
237
|
+
$container = document.getElementById('chart-container');
|
|
238
|
+
oc = new OrgChart({
|
|
239
|
+
chartContainer: '#chart-container',
|
|
82
240
|
'data': ds,
|
|
83
241
|
'nodeContent': 'title'
|
|
84
242
|
}),
|
|
85
|
-
$laolao =
|
|
86
|
-
$bomiao =
|
|
87
|
-
$sumiao =
|
|
88
|
-
$hongmiao =
|
|
89
|
-
$tiehua =
|
|
90
|
-
$heihei =
|
|
91
|
-
$pangpang =
|
|
92
|
-
$dandan =
|
|
93
|
-
$erdan =
|
|
94
|
-
$sandan =
|
|
95
|
-
});
|
|
96
|
-
|
|
243
|
+
$laolao = document.getElementById('n1'),
|
|
244
|
+
$bomiao = document.getElementById('n2'),
|
|
245
|
+
$sumiao = document.getElementById('n3'),
|
|
246
|
+
$hongmiao = document.getElementById('n4'),
|
|
247
|
+
$tiehua = document.getElementById('n5'),
|
|
248
|
+
$heihei = document.getElementById('n6'),
|
|
249
|
+
$pangpang = document.getElementById('n7'),
|
|
250
|
+
$dandan = document.getElementById('n8');
|
|
251
|
+
$erdan = document.getElementById('n9');
|
|
252
|
+
$sandan = document.getElementById('n10');
|
|
253
|
+
});
|
|
254
|
+
|
|
97
255
|
afterEach(function () {
|
|
98
256
|
$laolao = $bomiao = $sumiao = $hongmiao = $tiehua = $heihei = $pangpang = $dandan = $erdan = $sandan = null;
|
|
99
|
-
$container.
|
|
257
|
+
$container.innerHTML = '';
|
|
100
258
|
});
|
|
101
259
|
|
|
102
260
|
it('loopChart()', function () {
|
|
103
|
-
oc.loopChart(
|
|
261
|
+
oc.loopChart(query('.orgchart')).should.deep.equal(hierarchy);
|
|
262
|
+
});
|
|
263
|
+
|
|
264
|
+
it('exposes native chartContainer and chart instance properties', function () {
|
|
265
|
+
oc.chartContainer.should.equal($container);
|
|
266
|
+
oc.chartContainer.firstElementChild.should.equal(oc.chart);
|
|
267
|
+
oc.chart.should.have.property('nodeType', 1);
|
|
268
|
+
});
|
|
269
|
+
|
|
270
|
+
it('buildJsonDS() accepts a native li element', function () {
|
|
271
|
+
const ulContainer = document.createElement('ul');
|
|
272
|
+
|
|
273
|
+
ulContainer.innerHTML = '<li data-id="root" data-title="chief">Root<ul><li data-id="child">Child</li></ul></li>';
|
|
274
|
+
|
|
275
|
+
oc.buildJsonDS(ulContainer.firstElementChild).should.deep.equal({
|
|
276
|
+
id: 'root',
|
|
277
|
+
title: 'chief',
|
|
278
|
+
name: 'Root',
|
|
279
|
+
relationship: '001',
|
|
280
|
+
children: [
|
|
281
|
+
{
|
|
282
|
+
id: 'child',
|
|
283
|
+
name: 'Child',
|
|
284
|
+
relationship: '100'
|
|
285
|
+
}
|
|
286
|
+
]
|
|
287
|
+
});
|
|
104
288
|
});
|
|
105
289
|
|
|
106
290
|
it('getHierarchy()', function () {
|
|
107
291
|
oc.getHierarchy().should.deep.equal(hierarchy);
|
|
108
292
|
|
|
109
|
-
|
|
293
|
+
const oc2 = new OrgChart({
|
|
294
|
+
chartContainer: '#chart-container',
|
|
110
295
|
'data': { name: 'Lao Lao',
|
|
111
296
|
'children': [
|
|
112
297
|
{ name: 'Bo Miao' }
|
|
@@ -114,249 +299,617 @@ describe('orgchart -- unit tests', function () {
|
|
|
114
299
|
}
|
|
115
300
|
});
|
|
116
301
|
oc2.getHierarchy().should.include('Error');
|
|
117
|
-
oc2
|
|
302
|
+
oc2.chart.innerHTML = "";
|
|
118
303
|
oc2.getHierarchy().should.include('Error');
|
|
119
|
-
oc2
|
|
304
|
+
oc2.chart = null;
|
|
120
305
|
oc2.getHierarchy().should.include('Error');
|
|
121
306
|
});
|
|
122
307
|
|
|
123
|
-
it('
|
|
124
|
-
|
|
125
|
-
try {
|
|
126
|
-
$laolao = $('#n1');
|
|
127
|
-
$bomiao = $('#n2');
|
|
128
|
-
$sumiao = $('#n3');
|
|
129
|
-
$hongmiao = $('#n4');
|
|
130
|
-
$tiehua = $('#n5');
|
|
131
|
-
$heihei = $('#n6');
|
|
132
|
-
$pangpang = $('#n7');
|
|
133
|
-
$dandan = $('#n8');
|
|
134
|
-
$erdan = $('#n9');
|
|
135
|
-
$sandan = $('#n10');
|
|
136
|
-
|
|
137
|
-
oc.getNodeState($laolao).should.deep.equal({ 'exist': true, 'visible': true }, "laolao->self");
|
|
138
|
-
oc.getNodeState($laolao, 'parent').should.deep.equal({ 'exist': false, 'visible': false }, "laolao->parent");
|
|
139
|
-
oc.getNodeState($laolao, 'children').should.deep.equal({ 'exist': true, 'visible': true }, "laolao->children");
|
|
140
|
-
oc.getNodeState($laolao, 'siblings').should.deep.equal({ 'exist': false, 'visible': false }, "laolao->siblings");
|
|
141
|
-
|
|
142
|
-
oc.getNodeState($bomiao).should.deep.equal({ 'exist': true, 'visible': true }, "bomiao->self");
|
|
143
|
-
oc.getNodeState($bomiao, 'parent').should.deep.equal({ 'exist': true, 'visible': true }, "bomiao->parent");
|
|
144
|
-
oc.getNodeState($bomiao, 'children').should.deep.equal({ 'exist': false, 'visible': false }, "bomiao->children");
|
|
145
|
-
oc.getNodeState($bomiao, 'siblings').should.deep.equal({ 'exist': true, 'visible': true }, "bomiao->siblings");
|
|
146
|
-
|
|
147
|
-
oc.getNodeState($sumiao).should.deep.equal({ 'exist': true, 'visible': true }, "sumiao->self");
|
|
148
|
-
oc.getNodeState($sumiao, 'parent').should.deep.equal({ 'exist': true, 'visible': true }, "sumiao->parent");
|
|
149
|
-
oc.getNodeState($sumiao, 'children').should.deep.equal({ 'exist': true, 'visible': false }, "sumiao->children");
|
|
150
|
-
oc.getNodeState($sumiao, 'siblings').should.deep.equal({ 'exist': true, 'visible': true }, "sumiao->siblings");
|
|
151
|
-
|
|
152
|
-
oc.getNodeState($tiehua).should.deep.equal({ 'exist': true, 'visible': false }, "tiehua->self");
|
|
153
|
-
oc.getNodeState($tiehua, 'parent').should.deep.equal({ 'exist': true, 'visible': true }, "tiehua->parent");
|
|
154
|
-
oc.getNodeState($tiehua, 'children').should.deep.equal({ 'exist': true, 'visible': false }, "tiehua->children");
|
|
155
|
-
oc.getNodeState($tiehua, 'siblings').should.deep.equal({ 'exist': true, 'visible': false }, "tiehua->siblings");
|
|
156
|
-
|
|
157
|
-
oc.getNodeState($heihei).should.deep.equal({ 'exist': true, 'visible': false }, "heihei->self");
|
|
158
|
-
oc.getNodeState($heihei, 'parent').should.deep.equal({ 'exist': true, 'visible': true }, "heihei->parent");
|
|
159
|
-
oc.getNodeState($heihei, 'children').should.deep.equal({ 'exist': true, 'visible': false }, "heihei->children");
|
|
160
|
-
oc.getNodeState($heihei, 'siblings').should.deep.equal({ 'exist': true, 'visible': false }, "heihei->siblings");
|
|
161
|
-
|
|
162
|
-
oc.getNodeState($pangpang).should.deep.equal({ 'exist': true, 'visible': false }, "pangpang->self");
|
|
163
|
-
oc.getNodeState($pangpang, 'parent').should.deep.equal({ 'exist': true, 'visible': true }, "pangpang->parent");
|
|
164
|
-
oc.getNodeState($pangpang, 'children').should.deep.equal({ 'exist': true, 'visible': false }, "pangpang->children");
|
|
165
|
-
oc.getNodeState($pangpang, 'siblings').should.deep.equal({ 'exist': true, 'visible': false }, "pangpang->siblings");
|
|
166
|
-
|
|
167
|
-
oc.getNodeState($dandan).should.deep.equal({ 'exist': true, 'visible': false }, "dandan->self");
|
|
168
|
-
oc.getNodeState($dandan, 'parent').should.deep.equal({ 'exist': true, 'visible': false }, "dandan->parent");
|
|
169
|
-
oc.getNodeState($dandan, 'children').should.deep.equal({ 'exist': false, 'visible': false }, "dandan->children");
|
|
170
|
-
oc.getNodeState($dandan, 'siblings').should.deep.equal({ 'exist': false, 'visible': false }, "dandan->siblings");
|
|
308
|
+
it('triggerShowEvent() accepts a native node', function () {
|
|
309
|
+
const eventSpy = sinon.spy();
|
|
171
310
|
|
|
172
|
-
|
|
173
|
-
|
|
174
|
-
|
|
175
|
-
|
|
311
|
+
$sumiao.addEventListener('show-children.orgchart', eventSpy);
|
|
312
|
+
|
|
313
|
+
oc.triggerShowEvent($sumiao, 'children');
|
|
314
|
+
|
|
315
|
+
eventSpy.should.have.been.calledOnce;
|
|
316
|
+
eventSpy.firstCall.args[0].type.should.equal('show-children.orgchart');
|
|
317
|
+
});
|
|
318
|
+
|
|
319
|
+
it('triggerHideEvent() accepts a native node', function () {
|
|
320
|
+
const eventSpy = sinon.spy();
|
|
321
|
+
|
|
322
|
+
$sumiao.addEventListener('hide-children.orgchart', eventSpy);
|
|
323
|
+
|
|
324
|
+
oc.triggerHideEvent($sumiao, 'children');
|
|
325
|
+
|
|
326
|
+
eventSpy.should.have.been.calledOnce;
|
|
327
|
+
eventSpy.firstCall.args[0].type.should.equal('hide-children.orgchart');
|
|
328
|
+
});
|
|
329
|
+
|
|
330
|
+
it('getNodeState()', function () {
|
|
331
|
+
const stateDs = JSON.parse(baseDs);
|
|
332
|
+
let chartEl;
|
|
333
|
+
let laolaoEl;
|
|
334
|
+
let bomiaoEl;
|
|
335
|
+
let sumiaoEl;
|
|
336
|
+
let tiehuaEl;
|
|
337
|
+
let heiheiEl;
|
|
338
|
+
let pangpangEl;
|
|
339
|
+
let dandanEl;
|
|
340
|
+
|
|
341
|
+
$container.innerHTML = '';
|
|
342
|
+
oc = new OrgChart({
|
|
343
|
+
chartContainer: '#chart-container',
|
|
344
|
+
data: stateDs,
|
|
345
|
+
nodeContent: 'title',
|
|
346
|
+
visibleLevel: 2,
|
|
347
|
+
verticalLevel: 3
|
|
348
|
+
});
|
|
349
|
+
chartEl = oc.chart;
|
|
350
|
+
laolaoEl = query('#n1', chartEl);
|
|
351
|
+
bomiaoEl = query('#n2', chartEl);
|
|
352
|
+
sumiaoEl = query('#n3', chartEl);
|
|
353
|
+
tiehuaEl = query('#n5', chartEl);
|
|
354
|
+
heiheiEl = query('#n6', chartEl);
|
|
355
|
+
pangpangEl = query('#n7', chartEl);
|
|
356
|
+
dandanEl = query('#n8', chartEl);
|
|
357
|
+
|
|
358
|
+
oc.getNodeState(laolaoEl).should.deep.equal({ 'exist': true, 'visible': true }, 'laolao->self');
|
|
359
|
+
oc.getNodeState(laolaoEl, 'parent').should.deep.equal({ 'exist': false, 'visible': false }, 'laolao->parent');
|
|
360
|
+
oc.getNodeState(laolaoEl, 'children').should.deep.equal({ 'exist': true, 'visible': true }, 'laolao->children');
|
|
361
|
+
oc.getNodeState(laolaoEl, 'siblings').should.deep.equal({ 'exist': false, 'visible': false }, 'laolao->siblings');
|
|
362
|
+
|
|
363
|
+
oc.getNodeState(bomiaoEl).should.deep.equal({ 'exist': true, 'visible': true }, 'bomiao->self');
|
|
364
|
+
oc.getNodeState(bomiaoEl, 'parent').should.deep.equal({ 'exist': true, 'visible': true }, 'bomiao->parent');
|
|
365
|
+
oc.getNodeState(bomiaoEl, 'children').should.deep.equal({ 'exist': false, 'visible': false }, 'bomiao->children');
|
|
366
|
+
oc.getNodeState(bomiaoEl, 'siblings').should.deep.equal({ 'exist': true, 'visible': true }, 'bomiao->siblings');
|
|
367
|
+
|
|
368
|
+
oc.getNodeState(sumiaoEl).should.deep.equal({ 'exist': true, 'visible': true }, 'sumiao->self');
|
|
369
|
+
oc.getNodeState(sumiaoEl, 'parent').should.deep.equal({ 'exist': true, 'visible': true }, 'sumiao->parent');
|
|
370
|
+
oc.getNodeState(sumiaoEl, 'children').should.deep.equal({ 'exist': true, 'visible': false }, 'sumiao->children');
|
|
371
|
+
oc.getNodeState(sumiaoEl, 'siblings').should.deep.equal({ 'exist': true, 'visible': true }, 'sumiao->siblings');
|
|
372
|
+
|
|
373
|
+
oc.getNodeState(tiehuaEl).should.deep.equal({ 'exist': true, 'visible': false }, 'tiehua->self');
|
|
374
|
+
oc.getNodeState(tiehuaEl, 'parent').should.deep.equal({ 'exist': true, 'visible': true }, 'tiehua->parent');
|
|
375
|
+
oc.getNodeState(tiehuaEl, 'children').should.deep.equal({ 'exist': true, 'visible': false }, 'tiehua->children');
|
|
376
|
+
oc.getNodeState(tiehuaEl, 'siblings').should.deep.equal({ 'exist': true, 'visible': false }, 'tiehua->siblings');
|
|
377
|
+
|
|
378
|
+
oc.getNodeState(heiheiEl).should.deep.equal({ 'exist': true, 'visible': false }, 'heihei->self');
|
|
379
|
+
oc.getNodeState(heiheiEl, 'parent').should.deep.equal({ 'exist': true, 'visible': true }, 'heihei->parent');
|
|
380
|
+
oc.getNodeState(heiheiEl, 'children').should.deep.equal({ 'exist': true, 'visible': false }, 'heihei->children');
|
|
381
|
+
oc.getNodeState(heiheiEl, 'siblings').should.deep.equal({ 'exist': true, 'visible': false }, 'heihei->siblings');
|
|
382
|
+
|
|
383
|
+
oc.getNodeState(pangpangEl).should.deep.equal({ 'exist': true, 'visible': false }, 'pangpang->self');
|
|
384
|
+
oc.getNodeState(pangpangEl, 'parent').should.deep.equal({ 'exist': true, 'visible': true }, 'pangpang->parent');
|
|
385
|
+
oc.getNodeState(pangpangEl, 'children').should.deep.equal({ 'exist': true, 'visible': false }, 'pangpang->children');
|
|
386
|
+
oc.getNodeState(pangpangEl, 'siblings').should.deep.equal({ 'exist': true, 'visible': false }, 'pangpang->siblings');
|
|
387
|
+
|
|
388
|
+
oc.getNodeState(dandanEl).should.deep.equal({ 'exist': true, 'visible': false }, 'dandan->self');
|
|
389
|
+
oc.getNodeState(dandanEl, 'parent').should.deep.equal({ 'exist': true, 'visible': false }, 'dandan->parent');
|
|
390
|
+
oc.getNodeState(dandanEl, 'children').should.deep.equal({ 'exist': false, 'visible': false }, 'dandan->children');
|
|
391
|
+
oc.getNodeState(dandanEl, 'siblings').should.deep.equal({ 'exist': false, 'visible': false }, 'dandan->siblings');
|
|
392
|
+
});
|
|
393
|
+
|
|
394
|
+
it('triggerInitEvent() calls initCompleted with the native chart element', function () {
|
|
395
|
+
const originalMutationObserver = global.MutationObserver;
|
|
396
|
+
const originalWindowMutationObserver = window.MutationObserver;
|
|
397
|
+
const observeSpy = sinon.spy();
|
|
398
|
+
const disconnectSpy = sinon.spy();
|
|
399
|
+
const initCompletedSpy = sinon.spy();
|
|
400
|
+
|
|
401
|
+
const fakeMutationObserver = function (callback) {
|
|
402
|
+
this.observe = function (target, options) {
|
|
403
|
+
observeSpy(target, options);
|
|
404
|
+
callback([
|
|
405
|
+
{
|
|
406
|
+
addedNodes: [oc.chart]
|
|
407
|
+
}
|
|
408
|
+
]);
|
|
409
|
+
};
|
|
410
|
+
this.disconnect = disconnectSpy;
|
|
176
411
|
};
|
|
177
|
-
|
|
178
|
-
|
|
179
|
-
|
|
180
|
-
|
|
181
|
-
|
|
182
|
-
|
|
412
|
+
|
|
413
|
+
global.MutationObserver = fakeMutationObserver;
|
|
414
|
+
window.MutationObserver = fakeMutationObserver;
|
|
415
|
+
|
|
416
|
+
oc.options.initCompleted = initCompletedSpy;
|
|
417
|
+
oc.triggerInitEvent();
|
|
418
|
+
|
|
419
|
+
observeSpy.should.have.been.calledOnce;
|
|
420
|
+
observeSpy.firstCall.args[0].should.equal($container);
|
|
421
|
+
observeSpy.firstCall.args[1].should.deep.equal({ childList: true });
|
|
422
|
+
disconnectSpy.should.have.been.calledOnce;
|
|
423
|
+
initCompletedSpy.should.have.been.calledOnce;
|
|
424
|
+
initCompletedSpy.firstCall.args[0].should.equal(oc.chart);
|
|
425
|
+
|
|
426
|
+
global.MutationObserver = originalMutationObserver;
|
|
427
|
+
window.MutationObserver = originalWindowMutationObserver;
|
|
428
|
+
});
|
|
429
|
+
|
|
430
|
+
it('triggerInitEvent() triggers init.orgchart on the chart collection', function () {
|
|
431
|
+
const originalMutationObserver = global.MutationObserver;
|
|
432
|
+
const originalWindowMutationObserver = window.MutationObserver;
|
|
433
|
+
const eventSpy = sinon.spy();
|
|
434
|
+
|
|
435
|
+
const fakeMutationObserver = function (callback) {
|
|
436
|
+
this.observe = function () {
|
|
437
|
+
callback([
|
|
438
|
+
{
|
|
439
|
+
addedNodes: [oc.chart]
|
|
440
|
+
}
|
|
441
|
+
]);
|
|
442
|
+
};
|
|
443
|
+
this.disconnect = function () {};
|
|
444
|
+
};
|
|
445
|
+
|
|
446
|
+
global.MutationObserver = fakeMutationObserver;
|
|
447
|
+
window.MutationObserver = fakeMutationObserver;
|
|
448
|
+
oc.chart.addEventListener('init.orgchart', eventSpy);
|
|
449
|
+
|
|
450
|
+
oc.triggerInitEvent();
|
|
451
|
+
|
|
452
|
+
eventSpy.should.have.been.calledOnce;
|
|
453
|
+
eventSpy.firstCall.args[0].type.should.equal('init.orgchart');
|
|
454
|
+
|
|
455
|
+
global.MutationObserver = originalMutationObserver;
|
|
456
|
+
window.MutationObserver = originalWindowMutationObserver;
|
|
457
|
+
});
|
|
458
|
+
|
|
459
|
+
it('handleCompactNodes() tags compact nodes by compact-ancestor parity', function () {
|
|
460
|
+
const compactRootEl = document.createElement('div');
|
|
461
|
+
const compactChildEl = document.createElement('div');
|
|
462
|
+
const compactGrandchildEl = document.createElement('div');
|
|
463
|
+
|
|
464
|
+
compactRootEl.className = 'node compact';
|
|
465
|
+
compactChildEl.className = 'node compact';
|
|
466
|
+
compactGrandchildEl.className = 'node compact';
|
|
467
|
+
compactRootEl.appendChild(compactChildEl);
|
|
468
|
+
compactChildEl.appendChild(compactGrandchildEl);
|
|
469
|
+
oc.chart.appendChild(compactRootEl);
|
|
470
|
+
|
|
471
|
+
oc.handleCompactNodes();
|
|
472
|
+
|
|
473
|
+
compactRootEl.classList.contains('even').should.equal(true);
|
|
474
|
+
compactChildEl.classList.contains('odd').should.equal(true);
|
|
475
|
+
compactGrandchildEl.classList.contains('even').should.equal(true);
|
|
183
476
|
});
|
|
184
477
|
|
|
185
478
|
it('getRelatedNodes()', function () {
|
|
186
|
-
oc.getRelatedNodes().should.deep.equal(
|
|
187
|
-
oc.getRelatedNodes({}, 'children').should.deep.equal(
|
|
188
|
-
oc.getRelatedNodes(
|
|
189
|
-
oc.getRelatedNodes(
|
|
479
|
+
oc.getRelatedNodes().should.deep.equal([]);
|
|
480
|
+
oc.getRelatedNodes({}, 'children').should.deep.equal([]);
|
|
481
|
+
oc.getRelatedNodes(query('.hierarchy', oc.chart), 'children').should.deep.equal([]);
|
|
482
|
+
oc.getRelatedNodes(query('.node', oc.chart), 'child').should.deep.equal([]);
|
|
190
483
|
|
|
191
|
-
oc.getRelatedNodes($laolao, 'parent')
|
|
192
|
-
oc.getRelatedNodes($laolao, 'children').
|
|
193
|
-
oc.getRelatedNodes($laolao, 'siblings').should.deep.equal(
|
|
484
|
+
should.equal(oc.getRelatedNodes($laolao, 'parent'), null);
|
|
485
|
+
oc.getRelatedNodes($laolao, 'children').should.have.members([$bomiao, $sumiao, $hongmiao]);
|
|
486
|
+
oc.getRelatedNodes($laolao, 'siblings').should.deep.equal([]);
|
|
194
487
|
|
|
195
|
-
oc.getRelatedNodes($bomiao, 'parent').should.
|
|
488
|
+
oc.getRelatedNodes($bomiao, 'parent').should.equal($laolao);
|
|
196
489
|
oc.getRelatedNodes($bomiao, 'children').should.have.lengthOf(0);
|
|
197
|
-
oc.getRelatedNodes($bomiao, 'siblings').
|
|
490
|
+
oc.getRelatedNodes($bomiao, 'siblings').should.have.members([$sumiao, $hongmiao]);
|
|
198
491
|
});
|
|
199
492
|
|
|
200
493
|
it('getParent()', function () {
|
|
201
|
-
|
|
202
|
-
oc.getParent({})
|
|
203
|
-
oc.getParent(
|
|
494
|
+
should.equal(oc.getParent(), null);
|
|
495
|
+
should.equal(oc.getParent({}), null);
|
|
496
|
+
should.equal(oc.getParent(query('.hierarchy', oc.chart)), null);
|
|
204
497
|
|
|
205
|
-
oc.getParent($laolao)
|
|
206
|
-
oc.getParent($bomiao).should.
|
|
207
|
-
oc.getParent($sandan).should.
|
|
498
|
+
should.equal(oc.getParent($laolao), null);
|
|
499
|
+
oc.getParent($bomiao).should.equal($laolao);
|
|
500
|
+
oc.getParent($sandan).should.equal($pangpang);
|
|
208
501
|
});
|
|
209
502
|
|
|
210
503
|
it('getSiblings()', function () {
|
|
211
|
-
oc.getSiblings().should.deep.equal(
|
|
212
|
-
oc.getSiblings({}).should.deep.equal(
|
|
213
|
-
oc.getSiblings(
|
|
504
|
+
oc.getSiblings().should.deep.equal([]);
|
|
505
|
+
oc.getSiblings({}).should.deep.equal([]);
|
|
506
|
+
oc.getSiblings(query('.hierarchy', oc.chart)).should.deep.equal([]);
|
|
214
507
|
|
|
215
|
-
oc.getSiblings($laolao).should.deep.equal(
|
|
216
|
-
oc.getSiblings($bomiao).
|
|
217
|
-
oc.getSiblings($sandan).should.deep.equal(
|
|
508
|
+
oc.getSiblings($laolao).should.deep.equal([]);
|
|
509
|
+
oc.getSiblings($bomiao).should.have.members([$sumiao, $hongmiao]);
|
|
510
|
+
oc.getSiblings($sandan).should.deep.equal([]);
|
|
218
511
|
});
|
|
219
512
|
|
|
220
513
|
it('getChildren()', function () {
|
|
221
|
-
oc.getChildren().should.deep.equal(
|
|
222
|
-
oc.getChildren({}).should.deep.equal(
|
|
223
|
-
oc.getChildren(
|
|
514
|
+
oc.getChildren().should.deep.equal([]);
|
|
515
|
+
oc.getChildren({}).should.deep.equal([]);
|
|
516
|
+
oc.getChildren(query('.hierarchy', oc.chart)).should.deep.equal([]);
|
|
224
517
|
|
|
225
|
-
oc.getChildren($laolao).
|
|
226
|
-
oc.getChildren($bomiao).should.deep.equal(
|
|
227
|
-
oc.getChildren($sumiao).
|
|
228
|
-
oc.getChildren($sandan).should.deep.equal(
|
|
518
|
+
oc.getChildren($laolao).should.have.members([$bomiao, $sumiao, $hongmiao]);
|
|
519
|
+
oc.getChildren($bomiao).should.deep.equal([]);
|
|
520
|
+
oc.getChildren($sumiao).should.have.members([$tiehua, $heihei, $pangpang]);
|
|
521
|
+
oc.getChildren($sandan).should.deep.equal([]);
|
|
229
522
|
});
|
|
230
523
|
|
|
231
524
|
it('hideParent()', function () {
|
|
232
|
-
|
|
233
|
-
|
|
525
|
+
const spy = sinon.spy(oc, 'hideParent');
|
|
526
|
+
const spy2 = sinon.spy(oc, 'hideSiblings');
|
|
527
|
+
|
|
234
528
|
oc.hideParent($heihei);
|
|
529
|
+
setOneTimeListener($sumiao, 'transitionend', null, function (event) {
|
|
530
|
+
event.parent = parentEl;
|
|
531
|
+
spy.call(oc, event);
|
|
532
|
+
});
|
|
235
533
|
spy.should.have.been.callCount(2);
|
|
236
|
-
spy.getCall(0).should.
|
|
237
|
-
spy.getCall(1).should.
|
|
534
|
+
spy.getCall(0).args[0].should.equal($heihei);
|
|
535
|
+
spy.getCall(1).args[0].should.equal($sumiao);
|
|
238
536
|
spy2.should.have.been.callCount(2);
|
|
239
|
-
spy2.getCall(0).should.
|
|
240
|
-
spy2.getCall(1).should.
|
|
537
|
+
spy2.getCall(0).args[0].should.equal($heihei);
|
|
538
|
+
spy2.getCall(1).args[0].should.equal($sumiao);
|
|
539
|
+
});
|
|
540
|
+
|
|
541
|
+
it('hideParent() hides the transitioned parent node', function () {
|
|
542
|
+
oc.hideParent($sumiao);
|
|
543
|
+
|
|
544
|
+
triggerEvent($laolao, 'transitionend');
|
|
545
|
+
|
|
546
|
+
$laolao.classList.contains('sliding').should.equal(false);
|
|
547
|
+
$laolao.classList.contains('hidden').should.equal(true);
|
|
548
|
+
});
|
|
549
|
+
|
|
550
|
+
it('hideParent() clears inAjax when the parent node contains a spinner', function () {
|
|
551
|
+
const spinnerEl = document.createElement('i');
|
|
552
|
+
|
|
553
|
+
spinnerEl.className = 'spinner';
|
|
554
|
+
$sumiao.appendChild(spinnerEl);
|
|
555
|
+
setState(oc.chart, 'inAjax', true);
|
|
556
|
+
|
|
557
|
+
oc.hideParent($heihei);
|
|
558
|
+
|
|
559
|
+
getState(oc.chart, 'inAjax').should.be.false;
|
|
560
|
+
spinnerEl.remove();
|
|
241
561
|
});
|
|
242
562
|
|
|
243
563
|
it('hideParentEnd()', function () {
|
|
244
|
-
|
|
245
|
-
|
|
246
|
-
$sumiao
|
|
247
|
-
$sumiao
|
|
248
|
-
|
|
249
|
-
|
|
250
|
-
|
|
564
|
+
const parentEl = firstSibling(closestElement($heihei, '.nodes'), '.node');
|
|
565
|
+
|
|
566
|
+
addClasses($sumiao, 'sliding slide-down');
|
|
567
|
+
oc.hideParentEnd({ animatedNode: $sumiao, parent: parentEl });
|
|
568
|
+
matchesSelector($sumiao, 'sliding').should.be.false;
|
|
569
|
+
matchesSelector(parentEl, '.hidden').should.be.true;
|
|
570
|
+
});
|
|
571
|
+
|
|
572
|
+
it('hideParentEnd() accepts native animated and parent payloads', function () {
|
|
573
|
+
addClasses($sumiao, 'sliding');
|
|
574
|
+
removeClasses($sumiao, 'hidden');
|
|
575
|
+
|
|
576
|
+
oc.hideParentEnd({
|
|
577
|
+
animatedNode: $sumiao,
|
|
578
|
+
parent: $sumiao
|
|
579
|
+
});
|
|
580
|
+
|
|
581
|
+
$sumiao.classList.contains('sliding').should.equal(false);
|
|
582
|
+
$sumiao.classList.contains('hidden').should.equal(true);
|
|
583
|
+
});
|
|
584
|
+
|
|
585
|
+
it('hideParentEnd() accepts wrapped native animated and parent payloads', function () {
|
|
586
|
+
addClasses($sumiao, 'sliding');
|
|
587
|
+
|
|
588
|
+
oc.hideParentEnd({
|
|
589
|
+
originalEvent: {
|
|
590
|
+
target: $sumiao,
|
|
591
|
+
parent: $heihei
|
|
592
|
+
}
|
|
593
|
+
});
|
|
594
|
+
|
|
595
|
+
$sumiao.classList.contains('sliding').should.equal(false);
|
|
596
|
+
$heihei.classList.contains('hidden').should.equal(true);
|
|
251
597
|
});
|
|
252
598
|
|
|
253
599
|
it('showParent()', function () {
|
|
254
|
-
|
|
255
|
-
|
|
256
|
-
$
|
|
257
|
-
$
|
|
600
|
+
const spy = sinon.spy(oc, 'repaint');
|
|
601
|
+
|
|
602
|
+
addClasses(closestElement($heihei, '.hierarchy'), 'isAncestorsCollapsed');
|
|
603
|
+
addClasses($sumiao, 'slide-down hidden');
|
|
604
|
+
addClasses(closestElement($sumiao, '.hierarchy'), 'isAncestorsCollapsed');
|
|
605
|
+
addClasses($laolao, 'slide-down hidden');
|
|
258
606
|
oc.showParent($heihei);
|
|
259
607
|
spy.should.have.been.called;
|
|
260
|
-
$heihei
|
|
261
|
-
$sumiao
|
|
262
|
-
$sumiao
|
|
263
|
-
$laolao
|
|
264
|
-
$sumiao
|
|
265
|
-
$sumiao
|
|
608
|
+
matchesSelector(closestElement($heihei, '.hierarchy'), '.isAncestorsCollapsed').should.be.false;
|
|
609
|
+
matchesSelector($sumiao, '.slide-down, .hidden').should.be.false;
|
|
610
|
+
matchesSelector(closestElement($sumiao, '.hierarchy'), '.isAncestorsCollapsed').should.be.true;
|
|
611
|
+
matchesSelector($laolao, '.slide-down.hidden').should.be.true;
|
|
612
|
+
matchesSelector($sumiao, '.sliding').should.be.true;
|
|
613
|
+
matchesSelector($sumiao, '.slide-down').should.be.false;
|
|
266
614
|
});
|
|
267
615
|
|
|
268
616
|
it('showParentEnd()', function () {
|
|
269
|
-
|
|
270
|
-
|
|
271
|
-
|
|
272
|
-
|
|
273
|
-
$sumiao
|
|
617
|
+
const spy = sinon.spy(oc, 'showParentEnd');
|
|
618
|
+
const spy2 = sinon.spy(oc, 'isInAction');
|
|
619
|
+
const spy3 = sinon.spy(oc, 'switchVerticalArrow');
|
|
620
|
+
|
|
621
|
+
addClasses($sumiao, 'sliding');
|
|
622
|
+
removeClasses($sumiao, 'slide-down');
|
|
623
|
+
setOneTimeListener($sumiao, 'transitionend', null, function (event) {
|
|
624
|
+
event.node = $heihei;
|
|
625
|
+
spy.call(oc, event);
|
|
626
|
+
});
|
|
627
|
+
triggerEvent($sumiao, 'transitionend');
|
|
274
628
|
spy.should.have.been.called;
|
|
275
|
-
$sumiao
|
|
629
|
+
matchesSelector($sumiao, '.sliding').should.be.false;
|
|
276
630
|
spy2.should.have.been.calledWith($heihei);
|
|
277
631
|
spy3.should.not.have.been.called;
|
|
278
632
|
});
|
|
279
633
|
|
|
634
|
+
it('showParentEnd() accepts native animated and node payloads', function () {
|
|
635
|
+
addClasses($sumiao, 'sliding');
|
|
636
|
+
|
|
637
|
+
oc.showParentEnd({
|
|
638
|
+
animatedNode: $sumiao,
|
|
639
|
+
node: $heihei
|
|
640
|
+
});
|
|
641
|
+
|
|
642
|
+
$sumiao.classList.contains('sliding').should.equal(false);
|
|
643
|
+
});
|
|
644
|
+
|
|
645
|
+
it('showParentEnd() accepts wrapped native animated and node payloads', function () {
|
|
646
|
+
addClasses($sumiao, 'sliding');
|
|
647
|
+
|
|
648
|
+
oc.showParentEnd({
|
|
649
|
+
originalEvent: {
|
|
650
|
+
target: $sumiao,
|
|
651
|
+
node: $heihei
|
|
652
|
+
}
|
|
653
|
+
});
|
|
654
|
+
|
|
655
|
+
$sumiao.classList.contains('sliding').should.equal(false);
|
|
656
|
+
});
|
|
657
|
+
|
|
280
658
|
it('hideChildren()', function () {
|
|
281
|
-
|
|
659
|
+
const spy = sinon.spy(oc, 'repaint');
|
|
660
|
+
|
|
282
661
|
oc.hideChildren($sumiao);
|
|
662
|
+
|
|
283
663
|
spy.should.have.been.called;
|
|
284
|
-
$sumiao
|
|
285
|
-
$sumiao
|
|
286
|
-
$tiehua
|
|
287
|
-
$heihei
|
|
288
|
-
$pangpang
|
|
289
|
-
$erdan
|
|
664
|
+
matchesSelector(closestElement($sumiao, '.hierarchy'), '.isChildrenCollapsed').should.be.true;
|
|
665
|
+
childElements(firstSibling($sumiao, '.nodes'), '.isCollapsedDescendant').should.lengthOf(3);
|
|
666
|
+
matchesSelector($tiehua, '.sliding.slide-up').should.be.true;
|
|
667
|
+
matchesSelector($heihei, '.sliding.slide-up').should.be.true;
|
|
668
|
+
matchesSelector($pangpang, '.sliding.slide-up').should.be.true;
|
|
669
|
+
matchesSelector($erdan, '.sliding.slide-up').should.be.true;
|
|
290
670
|
});
|
|
291
671
|
|
|
292
672
|
it('hideChildrenEnd()', function () {
|
|
293
|
-
|
|
294
|
-
|
|
295
|
-
|
|
296
|
-
$tiehua
|
|
297
|
-
$tiehua
|
|
298
|
-
|
|
299
|
-
$tiehua.
|
|
300
|
-
$tiehua.closest('.nodes').is('.hidden').should.be.true;
|
|
673
|
+
const spy2 = sinon.spy(oc, 'isInAction');
|
|
674
|
+
const spy3 = sinon.spy(oc, 'switchVerticalArrow');
|
|
675
|
+
|
|
676
|
+
addClasses($tiehua, 'sliding slide-up');
|
|
677
|
+
oc.hideChildrenEnd({ animatedNodes: $tiehua, node: $sumiao });
|
|
678
|
+
matchesSelector($tiehua, '.sliding').should.be.false;
|
|
679
|
+
matchesSelector(closestElement($tiehua, '.nodes'), '.hidden').should.be.true;
|
|
301
680
|
spy2.should.have.been.calledWith($sumiao);
|
|
302
681
|
spy3.should.not.have.been.called;
|
|
303
682
|
});
|
|
304
683
|
|
|
684
|
+
it('hideChildrenEnd() accepts direct animated and node payloads', function () {
|
|
685
|
+
const bottomEdgeEl = query('.bottomEdge', $sumiao);
|
|
686
|
+
const verticalSpy = sinon.spy(oc, 'switchVerticalArrow');
|
|
687
|
+
|
|
688
|
+
removeClasses($tiehua, 'hidden');
|
|
689
|
+
addClasses($tiehua, 'sliding');
|
|
690
|
+
removeClasses(closestElement($tiehua, '.nodes'), 'hidden');
|
|
691
|
+
bottomEdgeEl.classList.add(oc.options.icons.collapseToDown);
|
|
692
|
+
|
|
693
|
+
oc.hideChildrenEnd({ animatedNodes: [$tiehua], node: $sumiao });
|
|
694
|
+
|
|
695
|
+
$tiehua.classList.contains('sliding').should.equal(false);
|
|
696
|
+
closestElement($tiehua, '.nodes').classList.contains('hidden').should.equal(true);
|
|
697
|
+
verticalSpy.should.have.been.calledWith(bottomEdgeEl);
|
|
698
|
+
|
|
699
|
+
verticalSpy.restore();
|
|
700
|
+
});
|
|
701
|
+
|
|
702
|
+
it('hideChildrenEnd() accepts wrapped native animated and node payloads', function () {
|
|
703
|
+
const bottomEdgeEl = query('.bottomEdge', $sumiao);
|
|
704
|
+
const verticalSpy = sinon.spy(oc, 'switchVerticalArrow');
|
|
705
|
+
|
|
706
|
+
removeClasses($tiehua, 'hidden');
|
|
707
|
+
addClasses($tiehua, 'sliding');
|
|
708
|
+
removeClasses(closestElement($tiehua, '.nodes'), 'hidden');
|
|
709
|
+
bottomEdgeEl.classList.add(oc.options.icons.collapseToDown);
|
|
710
|
+
|
|
711
|
+
oc.hideChildrenEnd({
|
|
712
|
+
originalEvent: {
|
|
713
|
+
animatedNodes: [$tiehua],
|
|
714
|
+
node: $sumiao
|
|
715
|
+
}
|
|
716
|
+
});
|
|
717
|
+
|
|
718
|
+
$tiehua.classList.contains('sliding').should.equal(false);
|
|
719
|
+
closestElement($tiehua, '.nodes').classList.contains('hidden').should.equal(true);
|
|
720
|
+
verticalSpy.should.have.been.calledWith(bottomEdgeEl);
|
|
721
|
+
|
|
722
|
+
verticalSpy.restore();
|
|
723
|
+
});
|
|
724
|
+
|
|
305
725
|
it('showChildren()', function () {
|
|
306
|
-
|
|
307
|
-
$sumiao
|
|
308
|
-
|
|
726
|
+
const spy = sinon.spy(oc, 'repaint');
|
|
727
|
+
const descendantsWrapperEl = firstSibling($sumiao, '.nodes');
|
|
728
|
+
|
|
729
|
+
queryAll('.node', descendantsWrapperEl).forEach(function (nodeEl) {
|
|
730
|
+
addClasses(nodeEl, 'slide-up');
|
|
731
|
+
});
|
|
732
|
+
queryAll('.nodes', descendantsWrapperEl).forEach(function (nodeEl) {
|
|
733
|
+
addClasses(nodeEl, 'hidden');
|
|
734
|
+
});
|
|
735
|
+
addClasses(descendantsWrapperEl, 'hidden');
|
|
309
736
|
oc.showChildren($sumiao);
|
|
310
|
-
spy.should.have.been.calledWith($tiehua
|
|
311
|
-
$tiehua
|
|
312
|
-
$heihei
|
|
313
|
-
$pangpang
|
|
314
|
-
$erdan
|
|
737
|
+
spy.should.have.been.calledWith($tiehua);
|
|
738
|
+
matchesSelector($tiehua, '.sliding:not(.slide-up)').should.be.true;
|
|
739
|
+
matchesSelector($heihei, '.sliding:not(.slide-up)').should.be.true;
|
|
740
|
+
matchesSelector($pangpang, '.sliding:not(.slide-up)').should.be.true;
|
|
741
|
+
matchesSelector($erdan, '.slide-up:not(.sliding)').should.be.true;
|
|
315
742
|
});
|
|
316
743
|
|
|
317
744
|
it('showChildrenEnd()', function () {
|
|
318
|
-
|
|
319
|
-
|
|
320
|
-
|
|
321
|
-
$tiehua
|
|
322
|
-
$tiehua
|
|
323
|
-
|
|
324
|
-
$tiehua.is('.sliding').should.be.false;
|
|
745
|
+
const spy2 = sinon.spy(oc, 'isInAction');
|
|
746
|
+
const spy3 = sinon.spy(oc, 'switchVerticalArrow');
|
|
747
|
+
|
|
748
|
+
addClasses($tiehua, 'sliding');
|
|
749
|
+
oc.showChildrenEnd({ node: $sumiao, animatedNodes: $tiehua });
|
|
750
|
+
matchesSelector($tiehua, '.sliding').should.be.false;
|
|
325
751
|
spy2.should.have.been.calledWith($sumiao);
|
|
326
752
|
spy3.should.not.have.been.called;
|
|
327
753
|
});
|
|
328
754
|
|
|
755
|
+
it('showChildrenEnd() accepts direct animated and node payloads', function () {
|
|
756
|
+
addClasses($tiehua, 'sliding');
|
|
757
|
+
|
|
758
|
+
oc.showChildrenEnd({
|
|
759
|
+
node: $sumiao,
|
|
760
|
+
animatedNodes: [$tiehua]
|
|
761
|
+
});
|
|
762
|
+
|
|
763
|
+
$tiehua.classList.contains('sliding').should.equal(false);
|
|
764
|
+
});
|
|
765
|
+
|
|
766
|
+
it('showChildrenEnd() accepts wrapped native animated and node payloads', function () {
|
|
767
|
+
addClasses($tiehua, 'sliding');
|
|
768
|
+
|
|
769
|
+
oc.showChildrenEnd({
|
|
770
|
+
originalEvent: {
|
|
771
|
+
node: $sumiao,
|
|
772
|
+
animatedNodes: [$tiehua]
|
|
773
|
+
}
|
|
774
|
+
});
|
|
775
|
+
|
|
776
|
+
$tiehua.classList.contains('sliding').should.equal(false);
|
|
777
|
+
});
|
|
778
|
+
|
|
779
|
+
it('showSiblingsEnd() accepts direct visible and node payloads', function () {
|
|
780
|
+
const topEdgeEl = query('.topEdge', $heihei);
|
|
781
|
+
const switchSpy = sinon.spy(oc, 'switchHorizontalArrow');
|
|
782
|
+
|
|
783
|
+
addClasses($tiehua, 'sliding');
|
|
784
|
+
addClasses($pangpang, 'sliding');
|
|
785
|
+
topEdgeEl.classList.add(oc.options.icons.expandToUp);
|
|
786
|
+
|
|
787
|
+
oc.showSiblingsEnd({
|
|
788
|
+
node: $heihei,
|
|
789
|
+
visibleNodes: [$tiehua, $pangpang]
|
|
790
|
+
});
|
|
791
|
+
|
|
792
|
+
$tiehua.classList.contains('sliding').should.equal(false);
|
|
793
|
+
$pangpang.classList.contains('sliding').should.equal(false);
|
|
794
|
+
switchSpy.should.have.been.calledWith($heihei);
|
|
795
|
+
topEdgeEl.classList.contains(oc.options.icons.expandToUp).should.equal(false);
|
|
796
|
+
topEdgeEl.classList.contains(oc.options.icons.collapseToDown).should.equal(true);
|
|
797
|
+
|
|
798
|
+
switchSpy.restore();
|
|
799
|
+
});
|
|
800
|
+
|
|
801
|
+
it('showSiblingsEnd() accepts wrapped native visible and node payloads', function () {
|
|
802
|
+
const topEdgeEl = query('.topEdge', $heihei);
|
|
803
|
+
const switchSpy = sinon.spy(oc, 'switchHorizontalArrow');
|
|
804
|
+
|
|
805
|
+
addClasses($tiehua, 'sliding');
|
|
806
|
+
addClasses($pangpang, 'sliding');
|
|
807
|
+
topEdgeEl.classList.add(oc.options.icons.expandToUp);
|
|
808
|
+
|
|
809
|
+
oc.showSiblingsEnd({
|
|
810
|
+
originalEvent: {
|
|
811
|
+
node: $heihei,
|
|
812
|
+
visibleNodes: [$tiehua, $pangpang]
|
|
813
|
+
}
|
|
814
|
+
});
|
|
815
|
+
|
|
816
|
+
$tiehua.classList.contains('sliding').should.equal(false);
|
|
817
|
+
$pangpang.classList.contains('sliding').should.equal(false);
|
|
818
|
+
switchSpy.should.have.been.calledWith($heihei);
|
|
819
|
+
topEdgeEl.classList.contains(oc.options.icons.expandToUp).should.equal(false);
|
|
820
|
+
topEdgeEl.classList.contains(oc.options.icons.collapseToDown).should.equal(true);
|
|
821
|
+
|
|
822
|
+
switchSpy.restore();
|
|
823
|
+
});
|
|
824
|
+
|
|
825
|
+
it('showRelatedParentEnd() removes sliding from a native animated node payload', function () {
|
|
826
|
+
addClasses($sumiao, 'sliding');
|
|
827
|
+
|
|
828
|
+
oc.showRelatedParentEnd({ animatedNode: $sumiao });
|
|
829
|
+
|
|
830
|
+
$sumiao.classList.contains('sliding').should.equal(false);
|
|
831
|
+
});
|
|
832
|
+
|
|
833
|
+
it('showRelatedParentEnd() accepts a wrapped native animated node payload', function () {
|
|
834
|
+
addClasses($sumiao, 'sliding');
|
|
835
|
+
|
|
836
|
+
oc.showRelatedParentEnd({
|
|
837
|
+
originalEvent: {
|
|
838
|
+
target: $sumiao
|
|
839
|
+
}
|
|
840
|
+
});
|
|
841
|
+
|
|
842
|
+
$sumiao.classList.contains('sliding').should.equal(false);
|
|
843
|
+
});
|
|
844
|
+
|
|
845
|
+
it('showSiblings() accepts a native node and reveals the requested side with animation', function () {
|
|
846
|
+
const repaintSpy = sinon.spy(oc, 'repaint');
|
|
847
|
+
|
|
848
|
+
addClasses(closestElement($tiehua, '.hierarchy'), 'hidden isCollapsedSibling left-sibs');
|
|
849
|
+
addClasses($tiehua, 'slide-right');
|
|
850
|
+
addClasses(closestElement($heihei, '.hierarchy'), 'isSiblingsCollapsed left-sibs isAncestorsCollapsed');
|
|
851
|
+
addClasses($sumiao, 'hidden slide-down');
|
|
852
|
+
|
|
853
|
+
oc.showSiblings($heihei, 'left');
|
|
854
|
+
|
|
855
|
+
repaintSpy.should.have.been.calledWith($sumiao);
|
|
856
|
+
closestElement($tiehua, '.hierarchy').classList.contains('hidden').should.equal(false);
|
|
857
|
+
closestElement($tiehua, '.hierarchy').classList.contains('isCollapsedSibling').should.equal(false);
|
|
858
|
+
closestElement($heihei, '.hierarchy').classList.contains('left-sibs').should.equal(false);
|
|
859
|
+
closestElement($heihei, '.hierarchy').classList.contains('isSiblingsCollapsed').should.equal(false);
|
|
860
|
+
$tiehua.classList.contains('sliding').should.equal(true);
|
|
861
|
+
$tiehua.classList.contains('slide-right').should.equal(false);
|
|
862
|
+
$sumiao.classList.contains('hidden').should.equal(false);
|
|
863
|
+
$sumiao.classList.contains('sliding').should.equal(true);
|
|
864
|
+
$sumiao.classList.contains('slide-down').should.equal(false);
|
|
865
|
+
|
|
866
|
+
repaintSpy.restore();
|
|
867
|
+
});
|
|
868
|
+
|
|
329
869
|
describe('hideSiblings()', function () {
|
|
330
870
|
context('when passing only one parameter -- node', function () {
|
|
331
871
|
it('should hide all the sibling nodes and their descendants', function () {
|
|
332
872
|
oc.hideSiblings($heihei);
|
|
333
|
-
$tiehua
|
|
334
|
-
$dandan
|
|
335
|
-
$pangpang
|
|
336
|
-
$sandan
|
|
337
|
-
$heihei
|
|
338
|
-
$heihei
|
|
873
|
+
matchesSelector($tiehua, '.sliding.slide-right').should.be.true;
|
|
874
|
+
matchesSelector($dandan, '.sliding.slide-right').should.be.true;
|
|
875
|
+
matchesSelector($pangpang, '.sliding.slide-left').should.be.true;
|
|
876
|
+
matchesSelector($sandan, '.sliding.slide-left').should.be.true;
|
|
877
|
+
matchesSelector(closestElement($heihei, '.hierarchy'), '.isSiblingsCollapsed').should.be.true;
|
|
878
|
+
siblingElements(closestElement($heihei, '.hierarchy'), '.isChildrenCollapsed.isCollapsedSibling').should.lengthOf(2);
|
|
879
|
+
});
|
|
880
|
+
|
|
881
|
+
it('clears inAjax when a sibling hierarchy contains a spinner', function () {
|
|
882
|
+
const spinnerEl = document.createElement('i');
|
|
883
|
+
|
|
884
|
+
spinnerEl.className = 'spinner';
|
|
885
|
+
closestElement($tiehua, '.hierarchy').appendChild(spinnerEl);
|
|
886
|
+
setState(oc.chart, 'inAjax', true);
|
|
887
|
+
|
|
888
|
+
oc.hideSiblings($heihei);
|
|
889
|
+
|
|
890
|
+
getState(oc.chart, 'inAjax').should.be.false;
|
|
891
|
+
spinnerEl.remove();
|
|
339
892
|
});
|
|
340
893
|
});
|
|
341
894
|
|
|
342
895
|
context('when passing two parameters -- node and direction', function () {
|
|
343
896
|
it('hide the left side sibling nodes and their descendants', function () {
|
|
344
897
|
oc.hideSiblings($heihei, 'left');
|
|
345
|
-
$heihei
|
|
346
|
-
$heihei
|
|
347
|
-
$heihei
|
|
348
|
-
$tiehua
|
|
349
|
-
$dandan
|
|
350
|
-
$pangpang
|
|
898
|
+
matchesSelector(closestElement($heihei, '.hierarchy'), '.isSiblingsCollapsed.left-sibs').should.be.true;
|
|
899
|
+
matchesSelector(closestElement($heihei, '.hierarchy').previousElementSibling, '.isChildrenCollapsed.isCollapsedSibling').should.be.true;
|
|
900
|
+
matchesSelector(closestElement($heihei, '.hierarchy').nextElementSibling, '.isChildrenCollapsed, .isCollapsedSibling').should.be.false;
|
|
901
|
+
matchesSelector($tiehua, '.sliding.slide-right').should.be.true;
|
|
902
|
+
matchesSelector($dandan, '.sliding.slide-right').should.be.true;
|
|
903
|
+
matchesSelector($pangpang, '.sliding').should.be.false;
|
|
351
904
|
});
|
|
352
905
|
it('hide the right side sibling nodes and their descendants', function () {
|
|
353
906
|
oc.hideSiblings($heihei, 'right');
|
|
354
|
-
$heihei
|
|
355
|
-
$heihei
|
|
356
|
-
$heihei
|
|
357
|
-
$pangpang
|
|
358
|
-
$sandan
|
|
359
|
-
$tiehua
|
|
907
|
+
matchesSelector(closestElement($heihei, '.hierarchy'), '.isSiblingsCollapsed.right-sibs').should.be.true;
|
|
908
|
+
matchesSelector(closestElement($heihei, '.hierarchy').nextElementSibling, '.isChildrenCollapsed.isCollapsedSibling').should.be.true;
|
|
909
|
+
matchesSelector(closestElement($heihei, '.hierarchy').previousElementSibling, '.isChildrenCollapsed, .isCollapsedSibling').should.be.false;
|
|
910
|
+
matchesSelector($pangpang, '.sliding.slide-left').should.be.true;
|
|
911
|
+
matchesSelector($sandan, '.sliding.slide-left').should.be.true;
|
|
912
|
+
matchesSelector($tiehua, '.sliding').should.be.false;
|
|
360
913
|
});
|
|
361
914
|
});
|
|
362
915
|
});
|
|
@@ -364,25 +917,29 @@ describe('orgchart -- unit tests', function () {
|
|
|
364
917
|
describe('hideSiblingsEnd()', function () {
|
|
365
918
|
context('when invoking transitionend event without specifying direction', function () {
|
|
366
919
|
it('clean up final classList for hidden siblings', function () {
|
|
367
|
-
|
|
368
|
-
|
|
369
|
-
|
|
370
|
-
|
|
920
|
+
const spy = sinon.spy(oc, 'hideSiblingsEnd');
|
|
921
|
+
const spy2 = sinon.spy(oc, 'isInAction');
|
|
922
|
+
const spy3 = sinon.spy(oc, 'switchVerticalArrow');
|
|
923
|
+
const nodeContainerEl = closestElement($heihei, '.hierarchy');
|
|
924
|
+
|
|
371
925
|
oc.hideSiblings($heihei);
|
|
372
|
-
|
|
926
|
+
|
|
927
|
+
setOneTimeListener($tiehua, 'transitionend', {
|
|
373
928
|
'node': $heihei,
|
|
374
|
-
'nodeContainer':
|
|
929
|
+
'nodeContainer': nodeContainerEl,
|
|
375
930
|
'direction': undefined,
|
|
376
931
|
'animatedNodes': $tiehua
|
|
377
932
|
}, spy.bind(oc));
|
|
378
|
-
$tiehua
|
|
933
|
+
triggerEvent($tiehua, 'transitionend');
|
|
379
934
|
spy.should.have.been.called;
|
|
380
|
-
$tiehua
|
|
381
|
-
$dandan
|
|
382
|
-
$pangpang
|
|
383
|
-
$sandan
|
|
384
|
-
|
|
385
|
-
|
|
935
|
+
matchesSelector($tiehua, '.slide-right:not(.sliding)').should.be.true;
|
|
936
|
+
matchesSelector($dandan, '.slide-up:not(.sliding, .slide-right)').should.be.true;
|
|
937
|
+
matchesSelector($pangpang, '.slide-left:not(.sibling)').should.be.true;
|
|
938
|
+
matchesSelector($sandan, '.slide-up:not(.sliding, .slide-left)').should.be.true;
|
|
939
|
+
siblingElements(nodeContainerEl, '.hidden').should.lengthOf(2);
|
|
940
|
+
siblingElements(nodeContainerEl).reduce(function (count, siblingEl) {
|
|
941
|
+
return count + queryAll('.nodes.hidden', siblingEl).length;
|
|
942
|
+
}, 0).should.equal(2);
|
|
386
943
|
spy2.should.have.been.calledWith($heihei);
|
|
387
944
|
spy3.should.not.have.been.called;
|
|
388
945
|
});
|
|
@@ -390,55 +947,1618 @@ describe('orgchart -- unit tests', function () {
|
|
|
390
947
|
|
|
391
948
|
context('when invoking transitionend event with specifying direction', function () {
|
|
392
949
|
it('clean up final classList for left side hidden siblings', function () {
|
|
393
|
-
|
|
394
|
-
|
|
395
|
-
|
|
396
|
-
|
|
950
|
+
const spy = sinon.spy(oc, 'hideSiblingsEnd');
|
|
951
|
+
const spy2 = sinon.spy(oc, 'isInAction');
|
|
952
|
+
const spy3 = sinon.spy(oc, 'switchVerticalArrow');
|
|
953
|
+
const nodeContainerEl = closestElement($heihei, '.hierarchy');
|
|
954
|
+
|
|
397
955
|
oc.hideSiblings($heihei, 'left');
|
|
398
|
-
|
|
956
|
+
|
|
957
|
+
setOneTimeListener($tiehua, 'transitionend', {
|
|
399
958
|
'node': $heihei,
|
|
400
|
-
'nodeContainer':
|
|
959
|
+
'nodeContainer': nodeContainerEl,
|
|
401
960
|
'direction': 'left',
|
|
402
961
|
'animatedNodes': $tiehua
|
|
403
962
|
}, spy.bind(oc));
|
|
404
|
-
$tiehua
|
|
963
|
+
triggerEvent($tiehua, 'transitionend');
|
|
405
964
|
spy.should.have.been.called;
|
|
406
|
-
$tiehua
|
|
407
|
-
$dandan
|
|
408
|
-
$pangpang
|
|
409
|
-
$sandan
|
|
410
|
-
|
|
411
|
-
|
|
412
|
-
|
|
965
|
+
matchesSelector($tiehua, '.slide-right:not(.sliding)').should.be.true;
|
|
966
|
+
matchesSelector($dandan, '.slide-up:not(.slide-right)').should.be.true;
|
|
967
|
+
matchesSelector($pangpang, '.slide-left').should.be.false;
|
|
968
|
+
matchesSelector($sandan, '.slide-up').should.be.false;
|
|
969
|
+
previousSiblings(nodeContainerEl, '.hidden').should.lengthOf(1);
|
|
970
|
+
previousSiblings(nodeContainerEl).reduce(function (count, siblingEl) {
|
|
971
|
+
return count + queryAll('.nodes.hidden', siblingEl).length;
|
|
972
|
+
}, 0).should.equal(1);
|
|
973
|
+
nextSiblings(nodeContainerEl).reduce(function (count, siblingEl) {
|
|
974
|
+
return count + queryAll('.nodes.hidden', siblingEl).length;
|
|
975
|
+
}, 0).should.equal(0);
|
|
413
976
|
spy2.should.have.been.calledWith($heihei);
|
|
414
977
|
spy3.should.not.have.been.called;
|
|
415
978
|
});
|
|
416
979
|
|
|
417
980
|
it('clean up final classList for right side hidden siblings', function () {
|
|
418
|
-
|
|
419
|
-
|
|
420
|
-
|
|
421
|
-
|
|
981
|
+
const spy2 = sinon.spy(oc, 'isInAction');
|
|
982
|
+
const spy3 = sinon.spy(oc, 'switchVerticalArrow');
|
|
983
|
+
const nodeContainerEl = closestElement($heihei, '.hierarchy');
|
|
984
|
+
|
|
422
985
|
oc.hideSiblings($heihei, 'right');
|
|
423
|
-
|
|
424
|
-
|
|
425
|
-
|
|
426
|
-
|
|
427
|
-
'
|
|
428
|
-
|
|
429
|
-
|
|
430
|
-
|
|
431
|
-
$
|
|
432
|
-
$
|
|
433
|
-
$
|
|
434
|
-
|
|
435
|
-
|
|
436
|
-
|
|
437
|
-
|
|
986
|
+
|
|
987
|
+
oc.hideSiblingsEnd({
|
|
988
|
+
node: $heihei,
|
|
989
|
+
nodeContainer: nodeContainerEl,
|
|
990
|
+
direction: 'right',
|
|
991
|
+
animatedNodes: $tiehua
|
|
992
|
+
});
|
|
993
|
+
matchesSelector($tiehua, '.slide-right').should.be.false;
|
|
994
|
+
matchesSelector($dandan, '.slide-up').should.be.false;
|
|
995
|
+
matchesSelector($pangpang, '.slide-left:not(.slidiing)').should.be.true;
|
|
996
|
+
matchesSelector($sandan, '.slide-up:not(.slide-left)').should.be.true;
|
|
997
|
+
nextSiblings(nodeContainerEl, '.hidden').should.lengthOf(1);
|
|
998
|
+
nextSiblings(nodeContainerEl).reduce(function (count, siblingEl) {
|
|
999
|
+
return count + queryAll('.nodes.hidden', siblingEl).length;
|
|
1000
|
+
}, 0).should.equal(1);
|
|
1001
|
+
previousSiblings(nodeContainerEl).reduce(function (count, siblingEl) {
|
|
1002
|
+
return count + queryAll('.nodes.hidden', siblingEl).length;
|
|
1003
|
+
}, 0).should.equal(0);
|
|
438
1004
|
spy2.should.have.been.calledWith($heihei);
|
|
439
1005
|
spy3.should.not.have.been.called;
|
|
440
1006
|
});
|
|
1007
|
+
|
|
1008
|
+
it('accepts direct node, container, and animated payloads', function () {
|
|
1009
|
+
const horizontalSpy = sinon.spy(oc, 'switchHorizontalArrow');
|
|
1010
|
+
const nodeContainerEl = closestElement($heihei, '.hierarchy');
|
|
1011
|
+
|
|
1012
|
+
oc.hideSiblings($heihei, 'left');
|
|
1013
|
+
addClasses($tiehua, 'sliding');
|
|
1014
|
+
removeClasses(closestElement($tiehua, '.nodes'), 'hidden');
|
|
1015
|
+
query('.leftEdge', $heihei).classList.add(oc.options.icons.collapseToLeft);
|
|
1016
|
+
|
|
1017
|
+
oc.hideSiblingsEnd({
|
|
1018
|
+
node: $heihei,
|
|
1019
|
+
nodeContainer: nodeContainerEl,
|
|
1020
|
+
direction: 'left',
|
|
1021
|
+
animatedNodes: [$tiehua]
|
|
1022
|
+
});
|
|
1023
|
+
|
|
1024
|
+
$tiehua.classList.contains('sliding').should.equal(false);
|
|
1025
|
+
nodeContainerEl.previousElementSibling.classList.contains('hidden').should.equal(true);
|
|
1026
|
+
horizontalSpy.should.have.been.calledWith($heihei);
|
|
1027
|
+
|
|
1028
|
+
horizontalSpy.restore();
|
|
1029
|
+
});
|
|
1030
|
+
|
|
1031
|
+
it('accepts wrapped native node, container, and animated payloads', function () {
|
|
1032
|
+
const horizontalSpy = sinon.spy(oc, 'switchHorizontalArrow');
|
|
1033
|
+
const nodeContainerEl = closestElement($heihei, '.hierarchy');
|
|
1034
|
+
|
|
1035
|
+
oc.hideSiblings($heihei, 'left');
|
|
1036
|
+
addClasses($tiehua, 'sliding');
|
|
1037
|
+
removeClasses(closestElement($tiehua, '.nodes'), 'hidden');
|
|
1038
|
+
query('.leftEdge', $heihei).classList.add(oc.options.icons.collapseToLeft);
|
|
1039
|
+
|
|
1040
|
+
oc.hideSiblingsEnd({
|
|
1041
|
+
originalEvent: {
|
|
1042
|
+
node: $heihei,
|
|
1043
|
+
nodeContainer: nodeContainerEl,
|
|
1044
|
+
direction: 'left',
|
|
1045
|
+
animatedNodes: [$tiehua]
|
|
1046
|
+
}
|
|
1047
|
+
});
|
|
1048
|
+
|
|
1049
|
+
$tiehua.classList.contains('sliding').should.equal(false);
|
|
1050
|
+
nodeContainerEl.previousElementSibling.classList.contains('hidden').should.equal(true);
|
|
1051
|
+
horizontalSpy.should.have.been.calledWith($heihei);
|
|
1052
|
+
|
|
1053
|
+
horizontalSpy.restore();
|
|
1054
|
+
});
|
|
441
1055
|
});
|
|
442
1056
|
});
|
|
443
1057
|
|
|
444
|
-
|
|
1058
|
+
it('nodeEnterLeaveHandler() accepts a native node payload for relationship checks', function () {
|
|
1059
|
+
const spy = sinon.spy(oc, 'switchHorizontalArrow');
|
|
1060
|
+
oc.nodeEnterLeaveHandler({ type: 'mouseenter', node: $sumiao });
|
|
1061
|
+
spy.should.have.been.calledWith($sumiao);
|
|
1062
|
+
});
|
|
1063
|
+
|
|
1064
|
+
it('nodeEnterLeaveHandler() removes arrow classes from a native node payload on mouseleave', function () {
|
|
1065
|
+
const nodeEl = $sumiao;
|
|
1066
|
+
|
|
1067
|
+
Array.from(nodeEl.querySelectorAll('.edge')).forEach(function (edgeEl) {
|
|
1068
|
+
edgeEl.classList.add(
|
|
1069
|
+
oc.options.icons.expandToUp,
|
|
1070
|
+
oc.options.icons.collapseToDown,
|
|
1071
|
+
oc.options.icons.collapseToLeft,
|
|
1072
|
+
oc.options.icons.expandToRight
|
|
1073
|
+
);
|
|
1074
|
+
});
|
|
1075
|
+
|
|
1076
|
+
oc.nodeEnterLeaveHandler({ type: 'mouseleave', node: nodeEl });
|
|
1077
|
+
|
|
1078
|
+
Array.from(nodeEl.querySelectorAll('.edge')).forEach(function (edgeEl) {
|
|
1079
|
+
edgeEl.classList.contains(oc.options.icons.expandToUp).should.equal(false);
|
|
1080
|
+
edgeEl.classList.contains(oc.options.icons.collapseToDown).should.equal(false);
|
|
1081
|
+
edgeEl.classList.contains(oc.options.icons.collapseToLeft).should.equal(false);
|
|
1082
|
+
edgeEl.classList.contains(oc.options.icons.expandToRight).should.equal(false);
|
|
1083
|
+
});
|
|
1084
|
+
});
|
|
1085
|
+
|
|
1086
|
+
it('nodeEnterLeaveHandler() accepts wrapped native node payloads', function () {
|
|
1087
|
+
const spy = sinon.spy(oc, 'switchHorizontalArrow');
|
|
1088
|
+
|
|
1089
|
+
oc.nodeEnterLeaveHandler({
|
|
1090
|
+
originalEvent: {
|
|
1091
|
+
type: 'mouseenter',
|
|
1092
|
+
currentTarget: $sumiao
|
|
1093
|
+
}
|
|
1094
|
+
});
|
|
1095
|
+
|
|
1096
|
+
spy.should.have.been.calledWith($sumiao);
|
|
1097
|
+
spy.restore();
|
|
1098
|
+
});
|
|
1099
|
+
|
|
1100
|
+
it('HideFirstParentEnd() accepts a native top edge payload', function () {
|
|
1101
|
+
const topEdgeEl = query('.topEdge', $heihei);
|
|
1102
|
+
const verticalSpy = sinon.spy(oc, 'switchVerticalArrow');
|
|
1103
|
+
const horizontalSpy = sinon.spy(oc, 'switchHorizontalArrow');
|
|
1104
|
+
|
|
1105
|
+
topEdgeEl.classList.add(oc.options.icons.expandToUp);
|
|
1106
|
+
oc.HideFirstParentEnd({ topEdge: topEdgeEl });
|
|
1107
|
+
|
|
1108
|
+
verticalSpy.should.have.been.calledWith(topEdgeEl);
|
|
1109
|
+
horizontalSpy.should.have.been.calledWith($heihei);
|
|
1110
|
+
|
|
1111
|
+
verticalSpy.restore();
|
|
1112
|
+
horizontalSpy.restore();
|
|
1113
|
+
});
|
|
1114
|
+
|
|
1115
|
+
it('HideFirstParentEnd() accepts a wrapped native top edge payload', function () {
|
|
1116
|
+
const topEdgeEl = query('.topEdge', $heihei);
|
|
1117
|
+
const verticalSpy = sinon.spy(oc, 'switchVerticalArrow');
|
|
1118
|
+
const horizontalSpy = sinon.spy(oc, 'switchHorizontalArrow');
|
|
1119
|
+
|
|
1120
|
+
topEdgeEl.classList.add(oc.options.icons.expandToUp);
|
|
1121
|
+
oc.HideFirstParentEnd({
|
|
1122
|
+
originalEvent: {
|
|
1123
|
+
topEdge: topEdgeEl
|
|
1124
|
+
}
|
|
1125
|
+
});
|
|
1126
|
+
|
|
1127
|
+
verticalSpy.should.have.been.calledWith(topEdgeEl);
|
|
1128
|
+
horizontalSpy.should.have.been.calledWith($heihei);
|
|
1129
|
+
|
|
1130
|
+
verticalSpy.restore();
|
|
1131
|
+
horizontalSpy.restore();
|
|
1132
|
+
});
|
|
1133
|
+
|
|
1134
|
+
it('nodeClickHandler() focuses the native node payload and clears previous focus', function () {
|
|
1135
|
+
addClasses($bomiao, 'focused');
|
|
1136
|
+
|
|
1137
|
+
oc.nodeClickHandler({ node: $sumiao });
|
|
1138
|
+
|
|
1139
|
+
$bomiao.classList.contains('focused').should.equal(false);
|
|
1140
|
+
$sumiao.classList.contains('focused').should.equal(true);
|
|
1141
|
+
});
|
|
1142
|
+
|
|
1143
|
+
it('nodeClickHandler() focuses a wrapped native node payload', function () {
|
|
1144
|
+
addClasses($bomiao, 'focused');
|
|
1145
|
+
|
|
1146
|
+
oc.nodeClickHandler({
|
|
1147
|
+
originalEvent: {
|
|
1148
|
+
currentTarget: $sumiao
|
|
1149
|
+
}
|
|
1150
|
+
});
|
|
1151
|
+
|
|
1152
|
+
$bomiao.classList.contains('focused').should.equal(false);
|
|
1153
|
+
$sumiao.classList.contains('focused').should.equal(true);
|
|
1154
|
+
});
|
|
1155
|
+
|
|
1156
|
+
it('init() clears focused nodes when clicking the chart background', function () {
|
|
1157
|
+
addClasses($bomiao, 'focused');
|
|
1158
|
+
addClasses($sumiao, 'focused');
|
|
1159
|
+
|
|
1160
|
+
oc.chart.dispatchEvent(new window.MouseEvent('click', { bubbles: true }));
|
|
1161
|
+
|
|
1162
|
+
$bomiao.classList.contains('focused').should.equal(false);
|
|
1163
|
+
$sumiao.classList.contains('focused').should.equal(false);
|
|
1164
|
+
});
|
|
1165
|
+
|
|
1166
|
+
it('init() clears focused nodes from a wrapped native background click payload', function () {
|
|
1167
|
+
const wrappedClickEvent = new window.Event('click', { bubbles: true });
|
|
1168
|
+
|
|
1169
|
+
addClasses($bomiao, 'focused');
|
|
1170
|
+
addClasses($sumiao, 'focused');
|
|
1171
|
+
|
|
1172
|
+
wrappedClickEvent.originalEvent = {
|
|
1173
|
+
target: oc.chart
|
|
1174
|
+
};
|
|
1175
|
+
oc.chart.dispatchEvent(wrappedClickEvent);
|
|
1176
|
+
|
|
1177
|
+
$bomiao.classList.contains('focused').should.equal(false);
|
|
1178
|
+
$sumiao.classList.contains('focused').should.equal(false);
|
|
1179
|
+
});
|
|
1180
|
+
|
|
1181
|
+
it('init() appends the export button only once', function () {
|
|
1182
|
+
let oc2;
|
|
1183
|
+
|
|
1184
|
+
Array.from(document.querySelectorAll('.oc-export-btn')).forEach(function (exportButtonEl) {
|
|
1185
|
+
exportButtonEl.remove();
|
|
1186
|
+
});
|
|
1187
|
+
|
|
1188
|
+
oc2 = new OrgChart({
|
|
1189
|
+
chartContainer: '#chart-container',
|
|
1190
|
+
data: ds,
|
|
1191
|
+
exportButton: true
|
|
1192
|
+
});
|
|
1193
|
+
|
|
1194
|
+
document.querySelectorAll('.oc-export-btn').length.should.equal(1);
|
|
1195
|
+
|
|
1196
|
+
oc2.init();
|
|
1197
|
+
|
|
1198
|
+
document.querySelectorAll('.oc-export-btn').length.should.equal(1);
|
|
1199
|
+
Array.from(document.querySelectorAll('.oc-export-btn')).forEach(function (exportButtonEl) {
|
|
1200
|
+
exportButtonEl.remove();
|
|
1201
|
+
});
|
|
1202
|
+
});
|
|
1203
|
+
|
|
1204
|
+
it('attachExportButton() creates a native export button that calls export()', function () {
|
|
1205
|
+
const exportStub = sinon.stub(oc, 'export');
|
|
1206
|
+
|
|
1207
|
+
Array.from(document.querySelectorAll('.oc-export-btn')).forEach(function (exportButtonEl) {
|
|
1208
|
+
exportButtonEl.remove();
|
|
1209
|
+
});
|
|
1210
|
+
|
|
1211
|
+
oc.attachExportButton();
|
|
1212
|
+
document.querySelectorAll('.oc-export-btn').length.should.equal(1);
|
|
1213
|
+
document.querySelector('.oc-export-btn').dispatchEvent(new window.MouseEvent('click', { bubbles: true }));
|
|
1214
|
+
exportStub.should.have.been.calledOnce;
|
|
1215
|
+
|
|
1216
|
+
exportStub.restore();
|
|
1217
|
+
Array.from(document.querySelectorAll('.oc-export-btn')).forEach(function (exportButtonEl) {
|
|
1218
|
+
exportButtonEl.remove();
|
|
1219
|
+
});
|
|
1220
|
+
});
|
|
1221
|
+
|
|
1222
|
+
it('topEdgeClickHandler() passes a native node to hideParent()', function () {
|
|
1223
|
+
const spy = sinon.spy(oc, 'hideParent');
|
|
1224
|
+
const spy2 = sinon.spy(oc, 'triggerHideEvent');
|
|
1225
|
+
|
|
1226
|
+
oc.topEdgeClickHandler({ edge: query('.topEdge', $heihei), node: $heihei });
|
|
1227
|
+
|
|
1228
|
+
spy.should.have.been.calledWith($heihei);
|
|
1229
|
+
spy2.should.have.been.called;
|
|
1230
|
+
});
|
|
1231
|
+
|
|
1232
|
+
it('topEdgeClickHandler() accepts wrapped native edge payloads', function () {
|
|
1233
|
+
const spy = sinon.spy(oc, 'hideParent');
|
|
1234
|
+
|
|
1235
|
+
oc.topEdgeClickHandler({
|
|
1236
|
+
originalEvent: {
|
|
1237
|
+
currentTarget: $heihei,
|
|
1238
|
+
target: query('.topEdge', $heihei)
|
|
1239
|
+
}
|
|
1240
|
+
});
|
|
1241
|
+
|
|
1242
|
+
spy.should.have.been.calledWith($heihei);
|
|
1243
|
+
spy.restore();
|
|
1244
|
+
});
|
|
1245
|
+
|
|
1246
|
+
it('bottomEdgeClickHandler() passes a native node to hideChildren()', function () {
|
|
1247
|
+
const spy = sinon.spy(oc, 'hideChildren');
|
|
1248
|
+
const spy2 = sinon.spy(oc, 'triggerHideEvent');
|
|
1249
|
+
|
|
1250
|
+
oc.bottomEdgeClickHandler({ edge: query('.bottomEdge', $sumiao), node: $sumiao });
|
|
1251
|
+
|
|
1252
|
+
spy.should.have.been.calledWith($sumiao);
|
|
1253
|
+
spy2.should.have.been.called;
|
|
1254
|
+
});
|
|
1255
|
+
|
|
1256
|
+
it('bottomEdgeClickHandler() accepts wrapped native node payloads', function () {
|
|
1257
|
+
const spy = sinon.spy(oc, 'hideChildren');
|
|
1258
|
+
|
|
1259
|
+
oc.bottomEdgeClickHandler({
|
|
1260
|
+
originalEvent: {
|
|
1261
|
+
currentTarget: $sumiao
|
|
1262
|
+
}
|
|
1263
|
+
});
|
|
1264
|
+
|
|
1265
|
+
spy.should.have.been.calledWith($sumiao);
|
|
1266
|
+
spy.restore();
|
|
1267
|
+
});
|
|
1268
|
+
|
|
1269
|
+
it('hEdgeClickHandler() passes a native node to hideSiblings()', function () {
|
|
1270
|
+
const spy = sinon.spy(oc, 'hideSiblings');
|
|
1271
|
+
const spy2 = sinon.spy(oc, 'triggerHideEvent');
|
|
1272
|
+
|
|
1273
|
+
oc.hEdgeClickHandler({ edge: query('.leftEdge', $sumiao), node: $sumiao });
|
|
1274
|
+
|
|
1275
|
+
spy.should.have.been.calledWith($sumiao);
|
|
1276
|
+
spy2.should.have.been.called;
|
|
1277
|
+
});
|
|
1278
|
+
|
|
1279
|
+
it('hEdgeClickHandler() accepts wrapped native edge payloads', function () {
|
|
1280
|
+
const spy = sinon.spy(oc, 'hideSiblings');
|
|
1281
|
+
|
|
1282
|
+
oc.hEdgeClickHandler({
|
|
1283
|
+
originalEvent: {
|
|
1284
|
+
currentTarget: $sumiao,
|
|
1285
|
+
target: query('.leftEdge', $sumiao)
|
|
1286
|
+
}
|
|
1287
|
+
});
|
|
1288
|
+
|
|
1289
|
+
spy.should.have.been.calledWith($sumiao);
|
|
1290
|
+
spy.restore();
|
|
1291
|
+
});
|
|
1292
|
+
|
|
1293
|
+
it('hEdgeClickHandler() restores the collapsed parent after topEdgeClickHandler()', function () {
|
|
1294
|
+
oc.topEdgeClickHandler({ edge: query('.topEdge', $sumiao), node: $sumiao });
|
|
1295
|
+
triggerEvent($bomiao, 'transitionend');
|
|
1296
|
+
triggerEvent($laolao, 'transitionend');
|
|
1297
|
+
|
|
1298
|
+
oc.hEdgeClickHandler({ edge: query('.leftEdge', $sumiao), node: $sumiao });
|
|
1299
|
+
|
|
1300
|
+
closestElement($sumiao, '.hierarchy').classList.contains('isAncestorsCollapsed').should.equal(false);
|
|
1301
|
+
$laolao.classList.contains('hidden').should.equal(false);
|
|
1302
|
+
$laolao.classList.contains('slide-down').should.equal(false);
|
|
1303
|
+
$laolao.classList.contains('sliding').should.equal(true);
|
|
1304
|
+
});
|
|
1305
|
+
|
|
1306
|
+
it('startLoading() and endLoading() accept a native edge node', function () {
|
|
1307
|
+
const edgeEl = query('.bottomEdge', $sumiao);
|
|
1308
|
+
|
|
1309
|
+
oc.startLoading(edgeEl).should.be.true;
|
|
1310
|
+
matchesSelector(edgeEl, '.hidden').should.be.true;
|
|
1311
|
+
queryAll('.spinner', edgeEl.parentElement).should.have.lengthOf(1);
|
|
1312
|
+
getState(oc.chart, 'inAjax').should.be.true;
|
|
1313
|
+
|
|
1314
|
+
oc.endLoading(edgeEl);
|
|
1315
|
+
matchesSelector(edgeEl, '.hidden').should.be.false;
|
|
1316
|
+
queryAll('.spinner', edgeEl.parentElement).should.have.lengthOf(0);
|
|
1317
|
+
getState(oc.chart, 'inAjax').should.be.false;
|
|
1318
|
+
});
|
|
1319
|
+
|
|
1320
|
+
it('startLoading() and endLoading() toggle native export buttons', function () {
|
|
1321
|
+
const edgeEl = query('.bottomEdge', $sumiao);
|
|
1322
|
+
const exportButtonEl = document.createElement('button');
|
|
1323
|
+
|
|
1324
|
+
exportButtonEl.className = 'oc-export-btn';
|
|
1325
|
+
document.body.appendChild(exportButtonEl);
|
|
1326
|
+
|
|
1327
|
+
oc.startLoading(edgeEl);
|
|
1328
|
+
exportButtonEl.disabled.should.equal(true);
|
|
1329
|
+
|
|
1330
|
+
oc.endLoading(edgeEl);
|
|
1331
|
+
exportButtonEl.disabled.should.equal(false);
|
|
1332
|
+
|
|
1333
|
+
exportButtonEl.remove();
|
|
1334
|
+
});
|
|
1335
|
+
|
|
1336
|
+
it('stopAjax() accepts a native node level element', function () {
|
|
1337
|
+
const nodeLevelEl = oc.getChildren($sumiao)[0].closest('.nodes');
|
|
1338
|
+
const spinnerEl = document.createElement('i');
|
|
1339
|
+
|
|
1340
|
+
spinnerEl.className = 'spinner';
|
|
1341
|
+
nodeLevelEl.appendChild(spinnerEl);
|
|
1342
|
+
setState(oc.chart, 'inAjax', true);
|
|
1343
|
+
|
|
1344
|
+
oc.stopAjax(nodeLevelEl);
|
|
1345
|
+
|
|
1346
|
+
getState(oc.chart, 'inAjax').should.be.false;
|
|
1347
|
+
spinnerEl.remove();
|
|
1348
|
+
});
|
|
1349
|
+
|
|
1350
|
+
it('backToLooseHandler() and backToCompactHandler() toggle compact mode classes', function () {
|
|
1351
|
+
const compactNodeEl = createElementFromHtml('<div class="node compact"><i class="backToCompactSymbol hidden"></i><i class="backToLooseSymbol"></i></div>');
|
|
1352
|
+
|
|
1353
|
+
$container.appendChild(compactNodeEl);
|
|
1354
|
+
|
|
1355
|
+
oc.backToLooseHandler({ compactNode: compactNodeEl });
|
|
1356
|
+
matchesSelector(compactNodeEl, '.looseMode').should.be.true;
|
|
1357
|
+
matchesSelector(query('.backToLooseSymbol', compactNodeEl), '.hidden').should.be.true;
|
|
1358
|
+
matchesSelector(query('.backToCompactSymbol', compactNodeEl), '.hidden').should.be.false;
|
|
1359
|
+
|
|
1360
|
+
oc.backToCompactHandler({ compactNode: compactNodeEl });
|
|
1361
|
+
matchesSelector(compactNodeEl, '.looseMode').should.be.false;
|
|
1362
|
+
matchesSelector(query('.backToCompactSymbol', compactNodeEl), '.hidden').should.be.true;
|
|
1363
|
+
matchesSelector(query('.backToLooseSymbol', compactNodeEl), '.hidden').should.be.false;
|
|
1364
|
+
});
|
|
1365
|
+
|
|
1366
|
+
it('backToLooseHandler() and backToCompactHandler() accept wrapped native compact-node payloads', function () {
|
|
1367
|
+
const compactNodeEl = createElementFromHtml('<div class="node compact"><i class="backToCompactSymbol hidden"></i><i class="backToLooseSymbol"></i></div>');
|
|
1368
|
+
|
|
1369
|
+
$container.appendChild(compactNodeEl);
|
|
1370
|
+
|
|
1371
|
+
oc.backToLooseHandler({
|
|
1372
|
+
originalEvent: {
|
|
1373
|
+
currentTarget: compactNodeEl
|
|
1374
|
+
}
|
|
1375
|
+
});
|
|
1376
|
+
matchesSelector(compactNodeEl, '.looseMode').should.be.true;
|
|
1377
|
+
|
|
1378
|
+
oc.backToCompactHandler({
|
|
1379
|
+
originalEvent: {
|
|
1380
|
+
currentTarget: compactNodeEl
|
|
1381
|
+
}
|
|
1382
|
+
});
|
|
1383
|
+
matchesSelector(compactNodeEl, '.looseMode').should.be.false;
|
|
1384
|
+
});
|
|
1385
|
+
|
|
1386
|
+
it('toggleVNodes() expands vertical descendants from a native toggle button payload', function () {
|
|
1387
|
+
const spy = sinon.spy(oc, 'repaint');
|
|
1388
|
+
const toggleHostEl = createElementFromHtml('<div class="node"><i class="toggleBtn"></i></div>');
|
|
1389
|
+
const descWrapperEl = createElementFromHtml('<ul class="nodes hidden"><li class="hierarchy"><div class="node slide-up">child</div></li></ul>');
|
|
1390
|
+
let childNodeEl;
|
|
1391
|
+
|
|
1392
|
+
$container.appendChild(toggleHostEl);
|
|
1393
|
+
$container.appendChild(descWrapperEl);
|
|
1394
|
+
childNodeEl = query('.node', descWrapperEl);
|
|
1395
|
+
|
|
1396
|
+
oc.toggleVNodes({ toggleButton: query('.toggleBtn', toggleHostEl) });
|
|
1397
|
+
|
|
1398
|
+
spy.should.have.been.calledWith(childNodeEl);
|
|
1399
|
+
matchesSelector(descWrapperEl, '.hidden').should.be.false;
|
|
1400
|
+
matchesSelector(childNodeEl, '.sliding').should.be.true;
|
|
1401
|
+
matchesSelector(childNodeEl, '.slide-up').should.be.false;
|
|
1402
|
+
});
|
|
1403
|
+
|
|
1404
|
+
it('toggleVNodes() accepts a wrapped native toggle button payload', function () {
|
|
1405
|
+
const toggleHostEl = createElementFromHtml('<div class="node"><i class="toggleBtn"></i></div>');
|
|
1406
|
+
const descWrapperEl = createElementFromHtml('<ul class="nodes hidden"><li class="hierarchy"><div class="node slide-up">child</div></li></ul>');
|
|
1407
|
+
|
|
1408
|
+
$container.appendChild(toggleHostEl);
|
|
1409
|
+
$container.appendChild(descWrapperEl);
|
|
1410
|
+
|
|
1411
|
+
oc.toggleVNodes({
|
|
1412
|
+
originalEvent: {
|
|
1413
|
+
target: query('.toggleBtn', toggleHostEl)
|
|
1414
|
+
}
|
|
1415
|
+
});
|
|
1416
|
+
|
|
1417
|
+
matchesSelector(descWrapperEl, '.hidden').should.be.false;
|
|
1418
|
+
});
|
|
1419
|
+
|
|
1420
|
+
it('toggleVNodes() collapses vertical descendants from a native toggle button payload', function () {
|
|
1421
|
+
const toggleHostEl = createElementFromHtml('<div class="node"><i class="toggleBtn"></i></div>');
|
|
1422
|
+
const descWrapperEl = createElementFromHtml('<ul class="nodes"><li class="hierarchy"><div class="node">child<i class="toggleBtn oci-plus-square oci-minus-square"></i></div></li></ul>');
|
|
1423
|
+
let nestedToggleBtnEl;
|
|
1424
|
+
let childNodeEl;
|
|
1425
|
+
|
|
1426
|
+
$container.appendChild(toggleHostEl);
|
|
1427
|
+
$container.appendChild(descWrapperEl);
|
|
1428
|
+
nestedToggleBtnEl = query('.node .toggleBtn', descWrapperEl);
|
|
1429
|
+
childNodeEl = query('.node', descWrapperEl);
|
|
1430
|
+
|
|
1431
|
+
oc.toggleVNodes({ toggleButton: query('.toggleBtn', toggleHostEl) });
|
|
1432
|
+
|
|
1433
|
+
matchesSelector(childNodeEl, '.sliding.slide-up').should.be.true;
|
|
1434
|
+
nestedToggleBtnEl.classList.contains('oci-plus-square').should.be.false;
|
|
1435
|
+
nestedToggleBtnEl.classList.contains('oci-minus-square').should.be.false;
|
|
1436
|
+
});
|
|
1437
|
+
|
|
1438
|
+
it('expandVNodesEnd() accepts direct vNodes payloads', function () {
|
|
1439
|
+
const descWrapperEl = createElementFromHtml('<ul class="nodes"><li class="hierarchy"><div class="node sliding">child</div></li></ul>');
|
|
1440
|
+
const childNodeEl = query('.node', descWrapperEl);
|
|
1441
|
+
|
|
1442
|
+
$container.appendChild(descWrapperEl);
|
|
1443
|
+
|
|
1444
|
+
oc.expandVNodesEnd({ vNodes: [childNodeEl] });
|
|
1445
|
+
|
|
1446
|
+
childNodeEl.classList.contains('sliding').should.equal(false);
|
|
1447
|
+
});
|
|
1448
|
+
|
|
1449
|
+
it('expandVNodesEnd() accepts wrapped native vNodes payloads', function () {
|
|
1450
|
+
const descWrapperEl = createElementFromHtml('<ul class="nodes"><li class="hierarchy"><div class="node sliding">child</div></li></ul>');
|
|
1451
|
+
const childNodeEl = query('.node', descWrapperEl);
|
|
1452
|
+
|
|
1453
|
+
$container.appendChild(descWrapperEl);
|
|
1454
|
+
|
|
1455
|
+
oc.expandVNodesEnd({
|
|
1456
|
+
originalEvent: {
|
|
1457
|
+
vNodes: [childNodeEl]
|
|
1458
|
+
}
|
|
1459
|
+
});
|
|
1460
|
+
|
|
1461
|
+
childNodeEl.classList.contains('sliding').should.equal(false);
|
|
1462
|
+
});
|
|
1463
|
+
|
|
1464
|
+
it('collapseVNodesEnd() accepts direct vNodes payloads', function () {
|
|
1465
|
+
const descWrapperEl = createElementFromHtml('<ul class="nodes"><li class="hierarchy"><div class="node sliding">child</div></li></ul>');
|
|
1466
|
+
const childNodeEl = query('.node', descWrapperEl);
|
|
1467
|
+
|
|
1468
|
+
$container.appendChild(descWrapperEl);
|
|
1469
|
+
|
|
1470
|
+
oc.collapseVNodesEnd({ vNodes: [childNodeEl] });
|
|
1471
|
+
|
|
1472
|
+
childNodeEl.classList.contains('sliding').should.equal(false);
|
|
1473
|
+
descWrapperEl.classList.contains('hidden').should.equal(true);
|
|
1474
|
+
});
|
|
1475
|
+
|
|
1476
|
+
it('collapseVNodesEnd() accepts wrapped native vNodes payloads', function () {
|
|
1477
|
+
const descWrapperEl = createElementFromHtml('<ul class="nodes"><li class="hierarchy"><div class="node sliding">child</div></li></ul>');
|
|
1478
|
+
const childNodeEl = query('.node', descWrapperEl);
|
|
1479
|
+
|
|
1480
|
+
$container.appendChild(descWrapperEl);
|
|
1481
|
+
|
|
1482
|
+
oc.collapseVNodesEnd({
|
|
1483
|
+
originalEvent: {
|
|
1484
|
+
vNodes: [childNodeEl]
|
|
1485
|
+
}
|
|
1486
|
+
});
|
|
1487
|
+
|
|
1488
|
+
childNodeEl.classList.contains('sliding').should.equal(false);
|
|
1489
|
+
descWrapperEl.classList.contains('hidden').should.equal(true);
|
|
1490
|
+
});
|
|
1491
|
+
|
|
1492
|
+
it('filterAllowedDropNodes() accepts a native dragged node', function () {
|
|
1493
|
+
oc.filterAllowedDropNodes($heihei);
|
|
1494
|
+
|
|
1495
|
+
getState(oc.chart, 'dragged').should.equal($heihei);
|
|
1496
|
+
$laolao.classList.contains('allowedDrop').should.be.true;
|
|
1497
|
+
queryAll('.allowedDrop', oc.chart).length.should.be.above(0);
|
|
1498
|
+
});
|
|
1499
|
+
|
|
1500
|
+
it('filterAllowedDropNodes() passes native node arguments to dropCriteria', function () {
|
|
1501
|
+
const dropCriteria = sinon.stub().returns(true);
|
|
1502
|
+
|
|
1503
|
+
oc.options.dropCriteria = dropCriteria;
|
|
1504
|
+
|
|
1505
|
+
oc.filterAllowedDropNodes($heihei);
|
|
1506
|
+
|
|
1507
|
+
dropCriteria.should.have.been.called;
|
|
1508
|
+
dropCriteria.firstCall.args[0].should.equal($heihei);
|
|
1509
|
+
dropCriteria.firstCall.args[1].should.equal($sumiao);
|
|
1510
|
+
dropCriteria.firstCall.args[2].should.have.property('nodeType', 1);
|
|
1511
|
+
});
|
|
1512
|
+
|
|
1513
|
+
it('dragstartHandler() passes a native dragged node payload to filterAllowedDropNodes()', function () {
|
|
1514
|
+
const spy = sinon.spy(oc, 'filterAllowedDropNodes');
|
|
1515
|
+
const dataTransfer = { setData: sinon.spy() };
|
|
1516
|
+
|
|
1517
|
+
oc.dragstartHandler({ draggedNode: $heihei, originalEvent: { dataTransfer: dataTransfer } });
|
|
1518
|
+
|
|
1519
|
+
dataTransfer.setData.should.have.been.called;
|
|
1520
|
+
spy.should.have.been.calledWith($heihei);
|
|
1521
|
+
});
|
|
1522
|
+
|
|
1523
|
+
it('dragstartHandler() accepts a wrapped native dragged node payload', function () {
|
|
1524
|
+
const spy = sinon.spy(oc, 'filterAllowedDropNodes');
|
|
1525
|
+
const dataTransfer = { setData: sinon.spy() };
|
|
1526
|
+
|
|
1527
|
+
oc.dragstartHandler({
|
|
1528
|
+
originalEvent: {
|
|
1529
|
+
target: $heihei,
|
|
1530
|
+
dataTransfer: dataTransfer
|
|
1531
|
+
}
|
|
1532
|
+
});
|
|
1533
|
+
|
|
1534
|
+
dataTransfer.setData.should.have.been.called;
|
|
1535
|
+
spy.should.have.been.calledWith($heihei);
|
|
1536
|
+
spy.restore();
|
|
1537
|
+
});
|
|
1538
|
+
|
|
1539
|
+
it('createGhostNode() accepts a native source node payload and creates a ghost image', function () {
|
|
1540
|
+
const setDragImageSpy = sinon.spy();
|
|
1541
|
+
const sourceNodeEl = $heihei;
|
|
1542
|
+
|
|
1543
|
+
oc.chart.style.transform = 'matrix(1, 0, 0, 1, 10, 20)';
|
|
1544
|
+
sourceNodeEl.getBoundingClientRect = function () {
|
|
1545
|
+
return { width: 120, height: 40, left: 10, top: 20 };
|
|
1546
|
+
};
|
|
1547
|
+
|
|
1548
|
+
oc.createGhostNode({
|
|
1549
|
+
sourceNode: sourceNodeEl,
|
|
1550
|
+
originalEvent: {
|
|
1551
|
+
offsetX: 5,
|
|
1552
|
+
offsetY: 6,
|
|
1553
|
+
dataTransfer: { setDragImage: setDragImageSpy }
|
|
1554
|
+
}
|
|
1555
|
+
});
|
|
1556
|
+
|
|
1557
|
+
const ghostNodeEl = oc.chart.querySelector('.ghost-node');
|
|
1558
|
+
should.exist(ghostNodeEl);
|
|
1559
|
+
ghostNodeEl.getAttribute('width').should.equal('120');
|
|
1560
|
+
ghostNodeEl.getAttribute('height').should.equal('40');
|
|
1561
|
+
setDragImageSpy.should.have.been.calledOnce;
|
|
1562
|
+
setDragImageSpy.firstCall.args[0].should.equal(ghostNodeEl);
|
|
1563
|
+
});
|
|
1564
|
+
|
|
1565
|
+
it('createGhostNode() accepts a wrapped native source node payload', function () {
|
|
1566
|
+
const setDragImageSpy = sinon.spy();
|
|
1567
|
+
const sourceNodeEl = $heihei;
|
|
1568
|
+
|
|
1569
|
+
oc.chart.style.transform = 'matrix(1, 0, 0, 1, 10, 20)';
|
|
1570
|
+
sourceNodeEl.getBoundingClientRect = function () {
|
|
1571
|
+
return { width: 120, height: 40, left: 10, top: 20 };
|
|
1572
|
+
};
|
|
1573
|
+
|
|
1574
|
+
oc.createGhostNode({
|
|
1575
|
+
originalEvent: {
|
|
1576
|
+
target: sourceNodeEl,
|
|
1577
|
+
offsetX: 5,
|
|
1578
|
+
offsetY: 6,
|
|
1579
|
+
dataTransfer: { setDragImage: setDragImageSpy }
|
|
1580
|
+
}
|
|
1581
|
+
});
|
|
1582
|
+
|
|
1583
|
+
should.exist(oc.chart.querySelector('.ghost-node'));
|
|
1584
|
+
setDragImageSpy.should.have.been.calledOnce;
|
|
1585
|
+
});
|
|
1586
|
+
|
|
1587
|
+
it('dragoverHandler() accepts a native drop zone payload', function () {
|
|
1588
|
+
const disallowedEvent = {
|
|
1589
|
+
dropZone: $bomiao,
|
|
1590
|
+
originalEvent: { dataTransfer: { dropEffect: 'move' } },
|
|
1591
|
+
preventDefault: sinon.spy()
|
|
1592
|
+
};
|
|
1593
|
+
disallowedEvent.originalEvent.preventDefault = disallowedEvent.preventDefault;
|
|
1594
|
+
const allowedEvent = {
|
|
1595
|
+
dropZone: addClasses($hongmiao, 'allowedDrop'),
|
|
1596
|
+
originalEvent: { dataTransfer: { dropEffect: 'move' } },
|
|
1597
|
+
preventDefault: sinon.spy()
|
|
1598
|
+
};
|
|
1599
|
+
allowedEvent.originalEvent.preventDefault = allowedEvent.preventDefault;
|
|
1600
|
+
|
|
1601
|
+
oc.dragoverHandler(disallowedEvent);
|
|
1602
|
+
oc.dragoverHandler(allowedEvent);
|
|
1603
|
+
|
|
1604
|
+
disallowedEvent.originalEvent.dataTransfer.dropEffect.should.equal('none');
|
|
1605
|
+
disallowedEvent.preventDefault.should.not.have.been.called;
|
|
1606
|
+
allowedEvent.preventDefault.should.have.been.calledOnce;
|
|
1607
|
+
});
|
|
1608
|
+
|
|
1609
|
+
it('dragoverHandler() accepts wrapped native drop-zone payloads', function () {
|
|
1610
|
+
const wrappedEvent = {
|
|
1611
|
+
originalEvent: {
|
|
1612
|
+
currentTarget: addClasses($hongmiao, 'allowedDrop'),
|
|
1613
|
+
dataTransfer: { dropEffect: 'move' },
|
|
1614
|
+
preventDefault: sinon.spy()
|
|
1615
|
+
}
|
|
1616
|
+
};
|
|
1617
|
+
|
|
1618
|
+
oc.dragoverHandler(wrappedEvent);
|
|
1619
|
+
|
|
1620
|
+
wrappedEvent.originalEvent.preventDefault.should.have.been.calledOnce;
|
|
1621
|
+
});
|
|
1622
|
+
|
|
1623
|
+
it('dragendHandler() removes allowedDrop from all nodes', function () {
|
|
1624
|
+
addClasses($bomiao, 'allowedDrop');
|
|
1625
|
+
addClasses($hongmiao, 'allowedDrop');
|
|
1626
|
+
|
|
1627
|
+
oc.dragendHandler({});
|
|
1628
|
+
|
|
1629
|
+
queryAll('.allowedDrop', oc.chart).should.have.lengthOf(0);
|
|
1630
|
+
});
|
|
1631
|
+
|
|
1632
|
+
it('dropHandler() accepts a native drop zone for non-node drags', async function () {
|
|
1633
|
+
const spy = sinon.spy();
|
|
1634
|
+
const foreignEl = createElementFromHtml('<div class="foreign-item"></div>');
|
|
1635
|
+
|
|
1636
|
+
oc.chart.addEventListener('otherdropped.orgchart', spy);
|
|
1637
|
+
setState(oc.chart, 'dragged', foreignEl);
|
|
1638
|
+
|
|
1639
|
+
await oc.dropHandler({ dropZone: $bomiao });
|
|
1640
|
+
|
|
1641
|
+
spy.should.have.been.calledOnce;
|
|
1642
|
+
spy.firstCall.args[0].type.should.equal('otherdropped.orgchart');
|
|
1643
|
+
spy.firstCall.args[0].detail.dropZone.should.equal($bomiao);
|
|
1644
|
+
});
|
|
1645
|
+
|
|
1646
|
+
it('dropHandler() accepts a wrapped native drop zone for non-node drags', async function () {
|
|
1647
|
+
const spy = sinon.spy();
|
|
1648
|
+
const foreignEl = createElementFromHtml('<div class="foreign-item"></div>');
|
|
1649
|
+
|
|
1650
|
+
oc.chart.addEventListener('otherdropped.orgchart', spy);
|
|
1651
|
+
setState(oc.chart, 'dragged', foreignEl);
|
|
1652
|
+
|
|
1653
|
+
await oc.dropHandler({
|
|
1654
|
+
originalEvent: {
|
|
1655
|
+
currentTarget: $bomiao
|
|
1656
|
+
}
|
|
1657
|
+
});
|
|
1658
|
+
|
|
1659
|
+
spy.should.have.been.calledOnce;
|
|
1660
|
+
spy.firstCall.args[0].detail.dropZone.should.equal($bomiao);
|
|
1661
|
+
});
|
|
1662
|
+
|
|
1663
|
+
it('dropHandler() accepts a native drop zone for node drags', async function () {
|
|
1664
|
+
const originalJSONDigger = global.JSONDigger;
|
|
1665
|
+
|
|
1666
|
+
global.JSONDigger = function () {
|
|
1667
|
+
return {
|
|
1668
|
+
findOneNode: function () {
|
|
1669
|
+
return null;
|
|
1670
|
+
}
|
|
1671
|
+
};
|
|
1672
|
+
};
|
|
1673
|
+
setState(oc.chart, 'dragged', $bomiao);
|
|
1674
|
+
addClasses($hongmiao, 'allowedDrop');
|
|
1675
|
+
|
|
1676
|
+
await oc.dropHandler({ dropZone: $hongmiao });
|
|
1677
|
+
|
|
1678
|
+
queryAll('#n2', firstSibling($hongmiao, '.nodes')).should.lengthOf(1);
|
|
1679
|
+
childElements(firstSibling($laolao, '.nodes'), '.hierarchy').should.lengthOf(2);
|
|
1680
|
+
global.JSONDigger = originalJSONDigger;
|
|
1681
|
+
});
|
|
1682
|
+
|
|
1683
|
+
it('dropHandler() keeps nodedrop payloads as native nodes', async function () {
|
|
1684
|
+
const originalJSONDigger = global.JSONDigger;
|
|
1685
|
+
const spy = sinon.spy();
|
|
1686
|
+
|
|
1687
|
+
global.JSONDigger = function () {
|
|
1688
|
+
return {
|
|
1689
|
+
findOneNode: function () {
|
|
1690
|
+
return null;
|
|
1691
|
+
}
|
|
1692
|
+
};
|
|
1693
|
+
};
|
|
1694
|
+
oc.chart.addEventListener('nodedrop.orgchart', spy);
|
|
1695
|
+
setState(oc.chart, 'dragged', $bomiao);
|
|
1696
|
+
addClasses($hongmiao, 'allowedDrop');
|
|
1697
|
+
|
|
1698
|
+
await oc.dropHandler({ dropZone: $hongmiao });
|
|
1699
|
+
|
|
1700
|
+
spy.should.have.been.calledOnce;
|
|
1701
|
+
spy.firstCall.args[0].type.should.equal('nodedrop.orgchart');
|
|
1702
|
+
spy.firstCall.args[0].detail.draggedNode.should.equal($bomiao);
|
|
1703
|
+
spy.firstCall.args[0].detail.dragZone.should.equal($laolao);
|
|
1704
|
+
spy.firstCall.args[0].detail.dropZone.should.equal($hongmiao);
|
|
1705
|
+
global.JSONDigger = originalJSONDigger;
|
|
1706
|
+
});
|
|
1707
|
+
|
|
1708
|
+
it('dropHandler() removes source child container when dragged node was the only child', async function () {
|
|
1709
|
+
const originalJSONDigger = global.JSONDigger;
|
|
1710
|
+
|
|
1711
|
+
global.JSONDigger = function () {
|
|
1712
|
+
return {
|
|
1713
|
+
findOneNode: function () {
|
|
1714
|
+
return null;
|
|
1715
|
+
}
|
|
1716
|
+
};
|
|
1717
|
+
};
|
|
1718
|
+
setState(oc.chart, 'dragged', $dandan);
|
|
1719
|
+
addClasses($hongmiao, 'allowedDrop');
|
|
1720
|
+
|
|
1721
|
+
await oc.dropHandler({ dropZone: $hongmiao });
|
|
1722
|
+
|
|
1723
|
+
queryAll('#n8', firstSibling($hongmiao, '.nodes')).should.lengthOf(1);
|
|
1724
|
+
siblingElements($tiehua, '.nodes').should.lengthOf(0);
|
|
1725
|
+
childElements($tiehua, '.bottomEdge, .parentNodeSymbol').should.lengthOf(0);
|
|
1726
|
+
global.JSONDigger = originalJSONDigger;
|
|
1727
|
+
});
|
|
1728
|
+
|
|
1729
|
+
it('touchmoveHandler() passes a native dragged node payload to filterAllowedDropNodes()', function () {
|
|
1730
|
+
const spy = sinon.spy(oc, 'filterAllowedDropNodes');
|
|
1731
|
+
const createDragImageStub = sinon.stub(oc, 'createDragImage').returns(document.createElement('div'));
|
|
1732
|
+
const moveDragImageStub = sinon.stub(oc, 'moveDragImage');
|
|
1733
|
+
const originalElementFromPoint = document.elementFromPoint;
|
|
1734
|
+
|
|
1735
|
+
document.elementFromPoint = function () {
|
|
1736
|
+
return $bomiao;
|
|
1737
|
+
};
|
|
1738
|
+
|
|
1739
|
+
oc.touchHandled = true;
|
|
1740
|
+
oc.touchMoved = false;
|
|
1741
|
+
oc.touchmoveHandler({
|
|
1742
|
+
draggedNode: $heihei,
|
|
1743
|
+
touches: [{ clientX: 0, clientY: 0 }],
|
|
1744
|
+
preventDefault: function () {}
|
|
1745
|
+
});
|
|
1746
|
+
|
|
1747
|
+
spy.should.have.been.calledWith($heihei);
|
|
1748
|
+
createDragImageStub.should.have.been.called;
|
|
1749
|
+
moveDragImageStub.should.have.been.called;
|
|
1750
|
+
oc.touchTargetNode.should.equal($bomiao);
|
|
1751
|
+
|
|
1752
|
+
document.elementFromPoint = originalElementFromPoint;
|
|
1753
|
+
moveDragImageStub.restore();
|
|
1754
|
+
createDragImageStub.restore();
|
|
1755
|
+
});
|
|
1756
|
+
|
|
1757
|
+
it('touchmoveHandler() accepts wrapped native touch payloads', function () {
|
|
1758
|
+
const spy = sinon.spy(oc, 'filterAllowedDropNodes');
|
|
1759
|
+
const createDragImageStub = sinon.stub(oc, 'createDragImage').returns(document.createElement('div'));
|
|
1760
|
+
const moveDragImageStub = sinon.stub(oc, 'moveDragImage');
|
|
1761
|
+
const originalElementFromPoint = document.elementFromPoint;
|
|
1762
|
+
|
|
1763
|
+
document.elementFromPoint = function () {
|
|
1764
|
+
return $bomiao;
|
|
1765
|
+
};
|
|
1766
|
+
|
|
1767
|
+
oc.touchHandled = true;
|
|
1768
|
+
oc.touchMoved = false;
|
|
1769
|
+
oc.touchmoveHandler({
|
|
1770
|
+
originalEvent: {
|
|
1771
|
+
currentTarget: $heihei,
|
|
1772
|
+
touches: [{ clientX: 0, clientY: 0 }],
|
|
1773
|
+
preventDefault: function () {}
|
|
1774
|
+
}
|
|
1775
|
+
});
|
|
1776
|
+
|
|
1777
|
+
spy.should.have.been.calledWith($heihei);
|
|
1778
|
+
createDragImageStub.should.have.been.called;
|
|
1779
|
+
moveDragImageStub.should.have.been.called;
|
|
1780
|
+
oc.touchTargetNode.should.equal($bomiao);
|
|
1781
|
+
|
|
1782
|
+
document.elementFromPoint = originalElementFromPoint;
|
|
1783
|
+
moveDragImageStub.restore();
|
|
1784
|
+
createDragImageStub.restore();
|
|
1785
|
+
spy.restore();
|
|
1786
|
+
});
|
|
1787
|
+
|
|
1788
|
+
it('touchstartHandler() accepts a wrapped native touch payload', function () {
|
|
1789
|
+
const preventDefaultSpy = sinon.spy();
|
|
1790
|
+
|
|
1791
|
+
oc.touchHandled = false;
|
|
1792
|
+
oc.touchMoved = true;
|
|
1793
|
+
|
|
1794
|
+
oc.touchstartHandler({
|
|
1795
|
+
originalEvent: {
|
|
1796
|
+
touches: [{ clientX: 0, clientY: 0 }],
|
|
1797
|
+
preventDefault: preventDefaultSpy
|
|
1798
|
+
}
|
|
1799
|
+
});
|
|
1800
|
+
|
|
1801
|
+
oc.touchHandled.should.equal(true);
|
|
1802
|
+
oc.touchMoved.should.equal(false);
|
|
1803
|
+
preventDefaultSpy.should.have.been.calledOnce;
|
|
1804
|
+
});
|
|
1805
|
+
|
|
1806
|
+
it('getTouchPoint() accepts a wrapped native touch payload', function () {
|
|
1807
|
+
const touchPoint = oc.getTouchPoint({
|
|
1808
|
+
originalEvent: {
|
|
1809
|
+
touches: [{ clientX: 12, clientY: 34 }]
|
|
1810
|
+
}
|
|
1811
|
+
});
|
|
1812
|
+
|
|
1813
|
+
touchPoint.x.should.equal(12);
|
|
1814
|
+
touchPoint.y.should.equal(34);
|
|
1815
|
+
});
|
|
1816
|
+
|
|
1817
|
+
it('touchendHandler() passes a native drop zone to dropHandler() after touch drag', function () {
|
|
1818
|
+
const destroyDragImageStub = sinon.stub(oc, 'destroyDragImage');
|
|
1819
|
+
const dropHandlerStub = sinon.stub(oc, 'dropHandler');
|
|
1820
|
+
const dragendHandlerStub = sinon.stub(oc, 'dragendHandler');
|
|
1821
|
+
|
|
1822
|
+
oc.touchHandled = true;
|
|
1823
|
+
oc.touchMoved = true;
|
|
1824
|
+
oc.touchTargetNode = $bomiao;
|
|
1825
|
+
|
|
1826
|
+
oc.touchendHandler({});
|
|
1827
|
+
|
|
1828
|
+
destroyDragImageStub.should.have.been.calledOnce;
|
|
1829
|
+
dropHandlerStub.should.have.been.calledOnce;
|
|
1830
|
+
dropHandlerStub.firstCall.args[0].dropZone.should.equal($bomiao);
|
|
1831
|
+
dragendHandlerStub.should.have.been.calledOnce;
|
|
1832
|
+
should.equal(oc.touchTargetNode, null);
|
|
1833
|
+
oc.touchHandled.should.equal(false);
|
|
1834
|
+
|
|
1835
|
+
dragendHandlerStub.restore();
|
|
1836
|
+
dropHandlerStub.restore();
|
|
1837
|
+
destroyDragImageStub.restore();
|
|
1838
|
+
});
|
|
1839
|
+
|
|
1840
|
+
it('touchendHandler() dispatches a native click when touch did not move', function () {
|
|
1841
|
+
const destroyDragImageStub = sinon.stub(oc, 'destroyDragImage');
|
|
1842
|
+
const clickSpy = sinon.spy();
|
|
1843
|
+
const targetEl = document.createElement('div');
|
|
1844
|
+
|
|
1845
|
+
targetEl.addEventListener('click', clickSpy);
|
|
1846
|
+
oc.touchHandled = true;
|
|
1847
|
+
oc.touchMoved = false;
|
|
1848
|
+
|
|
1849
|
+
oc.touchendHandler({
|
|
1850
|
+
target: targetEl,
|
|
1851
|
+
changedTouches: [{ screenX: 1, screenY: 2, clientX: 3, clientY: 4 }],
|
|
1852
|
+
ctrlKey: false,
|
|
1853
|
+
altKey: false,
|
|
1854
|
+
shiftKey: false,
|
|
1855
|
+
metaKey: false
|
|
1856
|
+
});
|
|
1857
|
+
|
|
1858
|
+
destroyDragImageStub.should.have.been.calledOnce;
|
|
1859
|
+
clickSpy.should.have.been.calledOnce;
|
|
1860
|
+
clickSpy.firstCall.args[0].type.should.equal('click');
|
|
1861
|
+
clickSpy.firstCall.args[0].clientX.should.equal(3);
|
|
1862
|
+
clickSpy.firstCall.args[0].clientY.should.equal(4);
|
|
1863
|
+
oc.touchHandled.should.equal(false);
|
|
1864
|
+
|
|
1865
|
+
destroyDragImageStub.restore();
|
|
1866
|
+
});
|
|
1867
|
+
|
|
1868
|
+
it('touchendHandler() accepts wrapped native touchend payloads', function () {
|
|
1869
|
+
const destroyDragImageStub = sinon.stub(oc, 'destroyDragImage');
|
|
1870
|
+
const clickSpy = sinon.spy();
|
|
1871
|
+
const targetEl = document.createElement('div');
|
|
1872
|
+
|
|
1873
|
+
targetEl.addEventListener('click', clickSpy);
|
|
1874
|
+
oc.touchHandled = true;
|
|
1875
|
+
oc.touchMoved = false;
|
|
1876
|
+
|
|
1877
|
+
oc.touchendHandler({
|
|
1878
|
+
originalEvent: {
|
|
1879
|
+
target: targetEl,
|
|
1880
|
+
changedTouches: [{ screenX: 1, screenY: 2, clientX: 3, clientY: 4 }],
|
|
1881
|
+
ctrlKey: false,
|
|
1882
|
+
altKey: false,
|
|
1883
|
+
shiftKey: false,
|
|
1884
|
+
metaKey: false
|
|
1885
|
+
}
|
|
1886
|
+
});
|
|
1887
|
+
|
|
1888
|
+
destroyDragImageStub.should.have.been.calledOnce;
|
|
1889
|
+
clickSpy.should.have.been.calledOnce;
|
|
1890
|
+
oc.touchHandled.should.equal(false);
|
|
1891
|
+
|
|
1892
|
+
destroyDragImageStub.restore();
|
|
1893
|
+
});
|
|
1894
|
+
|
|
1895
|
+
it('getUpperLevel() and getLowerLevel() accept native nodes', function () {
|
|
1896
|
+
oc.getUpperLevel($laolao).should.equal(1);
|
|
1897
|
+
oc.getUpperLevel($dandan).should.equal(4);
|
|
1898
|
+
oc.getLowerLevel($laolao).should.equal(4);
|
|
1899
|
+
oc.getLowerLevel($dandan).should.equal(1);
|
|
1900
|
+
});
|
|
1901
|
+
|
|
1902
|
+
it('getLevelOrderNodes() accepts a native root node', function () {
|
|
1903
|
+
const levels = oc.getLevelOrderNodes($laolao);
|
|
1904
|
+
|
|
1905
|
+
levels.should.have.lengthOf(4);
|
|
1906
|
+
levels[0][0].should.equal($laolao);
|
|
1907
|
+
levels[1].map(function (nodeEl) { return nodeEl.id; }).should.deep.equal(['n2', 'n3', 'n4']);
|
|
1908
|
+
levels[2].map(function (nodeEl) { return nodeEl.id; }).should.deep.equal(['n5', 'n6', 'n7']);
|
|
1909
|
+
levels[3].map(function (nodeEl) { return nodeEl.id; }).should.deep.equal(['n8', 'n9', 'n10']);
|
|
1910
|
+
});
|
|
1911
|
+
|
|
1912
|
+
it('isInAction() accepts a native node and inspects native edge classes', function () {
|
|
1913
|
+
const nodeEl = $sumiao;
|
|
1914
|
+
const topEdgeEl = nodeEl.querySelector('.topEdge');
|
|
1915
|
+
|
|
1916
|
+
should.exist(topEdgeEl);
|
|
1917
|
+
topEdgeEl.classList.add(oc.options.icons.expandToUp);
|
|
1918
|
+
oc.isInAction(nodeEl).should.equal(true);
|
|
1919
|
+
|
|
1920
|
+
topEdgeEl.classList.remove(oc.options.icons.expandToUp);
|
|
1921
|
+
oc.isInAction(nodeEl).should.equal(false);
|
|
1922
|
+
});
|
|
1923
|
+
|
|
1924
|
+
it('switchHorizontalArrow() accepts a native node and toggles edge classes from native siblings', function () {
|
|
1925
|
+
const nodeEl = $sumiao;
|
|
1926
|
+
const leftEdgeEl = nodeEl.querySelector('.leftEdge');
|
|
1927
|
+
const rightEdgeEl = nodeEl.querySelector('.rightEdge');
|
|
1928
|
+
|
|
1929
|
+
oc.switchHorizontalArrow(nodeEl);
|
|
1930
|
+
leftEdgeEl.classList.contains(oc.options.icons.expandToRight).should.equal(true);
|
|
1931
|
+
leftEdgeEl.classList.contains(oc.options.icons.collapseToLeft).should.equal(false);
|
|
1932
|
+
rightEdgeEl.classList.contains(oc.options.icons.collapseToLeft).should.equal(true);
|
|
1933
|
+
rightEdgeEl.classList.contains(oc.options.icons.expandToRight).should.equal(false);
|
|
1934
|
+
|
|
1935
|
+
siblingElements(closestElement($sumiao, '.hierarchy')).forEach(function (siblingEl) {
|
|
1936
|
+
addClasses(siblingEl, 'hidden');
|
|
1937
|
+
});
|
|
1938
|
+
oc.switchHorizontalArrow(nodeEl);
|
|
1939
|
+
|
|
1940
|
+
leftEdgeEl.classList.contains(oc.options.icons.expandToRight).should.equal(false);
|
|
1941
|
+
leftEdgeEl.classList.contains(oc.options.icons.collapseToLeft).should.equal(true);
|
|
1942
|
+
rightEdgeEl.classList.contains(oc.options.icons.collapseToLeft).should.equal(false);
|
|
1943
|
+
rightEdgeEl.classList.contains(oc.options.icons.expandToRight).should.equal(true);
|
|
1944
|
+
});
|
|
1945
|
+
|
|
1946
|
+
it('switchVerticalArrow() accepts a native edge element and toggles vertical arrow classes', function () {
|
|
1947
|
+
const bottomEdgeEl = $sumiao.querySelector('.bottomEdge');
|
|
1948
|
+
|
|
1949
|
+
should.exist(bottomEdgeEl);
|
|
1950
|
+
bottomEdgeEl.classList.add(oc.options.icons.expandToUp);
|
|
1951
|
+
|
|
1952
|
+
oc.switchVerticalArrow(bottomEdgeEl);
|
|
1953
|
+
bottomEdgeEl.classList.contains(oc.options.icons.expandToUp).should.equal(false);
|
|
1954
|
+
bottomEdgeEl.classList.contains(oc.options.icons.collapseToDown).should.equal(true);
|
|
1955
|
+
|
|
1956
|
+
oc.switchVerticalArrow(bottomEdgeEl);
|
|
1957
|
+
bottomEdgeEl.classList.contains(oc.options.icons.expandToUp).should.equal(true);
|
|
1958
|
+
bottomEdgeEl.classList.contains(oc.options.icons.collapseToDown).should.equal(false);
|
|
1959
|
+
});
|
|
1960
|
+
|
|
1961
|
+
it('panStartHandler() accepts a native chart element and updates transform on mousemove', function () {
|
|
1962
|
+
let moveEvent;
|
|
1963
|
+
|
|
1964
|
+
oc.chart.style.transform = 'none';
|
|
1965
|
+
|
|
1966
|
+
oc.panStartHandler({
|
|
1967
|
+
chart: oc.chart,
|
|
1968
|
+
target: oc.chart,
|
|
1969
|
+
pageX: 10,
|
|
1970
|
+
pageY: 20
|
|
1971
|
+
});
|
|
1972
|
+
|
|
1973
|
+
getState(oc.chart, 'panning').should.equal(true);
|
|
1974
|
+
moveEvent = new window.Event('mousemove', { bubbles: true });
|
|
1975
|
+
Object.defineProperty(moveEvent, 'pageX', { value: 30 });
|
|
1976
|
+
Object.defineProperty(moveEvent, 'pageY', { value: 45 });
|
|
1977
|
+
oc.chart.dispatchEvent(moveEvent);
|
|
1978
|
+
|
|
1979
|
+
oc.chart.style.transform.should.equal('matrix(1, 0, 0, 1, 20, 25)');
|
|
1980
|
+
});
|
|
1981
|
+
|
|
1982
|
+
it('panStartHandler() accepts wrapped native event payloads', function () {
|
|
1983
|
+
oc.chart.style.transform = 'none';
|
|
1984
|
+
|
|
1985
|
+
oc.panStartHandler({
|
|
1986
|
+
chart: oc.chart,
|
|
1987
|
+
originalEvent: {
|
|
1988
|
+
target: oc.chart,
|
|
1989
|
+
pageX: 10,
|
|
1990
|
+
pageY: 20
|
|
1991
|
+
}
|
|
1992
|
+
});
|
|
1993
|
+
|
|
1994
|
+
getState(oc.chart, 'panning').should.equal(true);
|
|
1995
|
+
});
|
|
1996
|
+
|
|
1997
|
+
it('panEndHandler() accepts a native chart element', function () {
|
|
1998
|
+
setState(oc.chart, 'panning', true);
|
|
1999
|
+
oc.chart.style.cursor = 'move';
|
|
2000
|
+
|
|
2001
|
+
oc.panEndHandler({ chart: oc.chart });
|
|
2002
|
+
|
|
2003
|
+
getState(oc.chart, 'panning').should.equal(false);
|
|
2004
|
+
oc.chart.style.cursor.should.equal('default');
|
|
2005
|
+
});
|
|
2006
|
+
|
|
2007
|
+
it('panEndHandler() accepts wrapped native chart payloads', function () {
|
|
2008
|
+
setState(oc.chart, 'panning', true);
|
|
2009
|
+
oc.chart.style.cursor = 'move';
|
|
2010
|
+
|
|
2011
|
+
oc.panEndHandler({
|
|
2012
|
+
originalEvent: {
|
|
2013
|
+
currentTarget: oc.chart
|
|
2014
|
+
}
|
|
2015
|
+
});
|
|
2016
|
+
|
|
2017
|
+
getState(oc.chart, 'panning').should.equal(false);
|
|
2018
|
+
oc.chart.style.cursor.should.equal('default');
|
|
2019
|
+
});
|
|
2020
|
+
|
|
2021
|
+
it('panEndHandler() removes both mousemove and touchmove listeners', function () {
|
|
2022
|
+
const removedTypes = [];
|
|
2023
|
+
const originalRemoveEventListener = oc.chart.removeEventListener;
|
|
2024
|
+
|
|
2025
|
+
oc.chart.removeEventListener = function (type, listener, options) {
|
|
2026
|
+
removedTypes.push(type);
|
|
2027
|
+
return originalRemoveEventListener.call(this, type, listener, options);
|
|
2028
|
+
};
|
|
2029
|
+
|
|
2030
|
+
oc.panStartHandler({
|
|
2031
|
+
chart: oc.chart,
|
|
2032
|
+
target: oc.chart,
|
|
2033
|
+
pageX: 10,
|
|
2034
|
+
pageY: 20
|
|
2035
|
+
});
|
|
2036
|
+
oc.panEndHandler({ chart: oc.chart });
|
|
2037
|
+
|
|
2038
|
+
removedTypes.should.include('mousemove');
|
|
2039
|
+
removedTypes.should.include('touchmove');
|
|
2040
|
+
|
|
2041
|
+
oc.chart.removeEventListener = originalRemoveEventListener;
|
|
2042
|
+
});
|
|
2043
|
+
|
|
2044
|
+
it('bindPan() wires document pan-end events with the native chart element', function () {
|
|
2045
|
+
const panChart = new OrgChart({
|
|
2046
|
+
chartContainer: '#chart-container',
|
|
2047
|
+
data: ds
|
|
2048
|
+
});
|
|
2049
|
+
const panEndSpy = sinon.stub(panChart, 'panEndHandler');
|
|
2050
|
+
|
|
2051
|
+
panChart.bindPan();
|
|
2052
|
+
document.dispatchEvent(new window.MouseEvent('mouseup', { bubbles: true }));
|
|
2053
|
+
|
|
2054
|
+
panEndSpy.should.have.been.called;
|
|
2055
|
+
panEndSpy.lastCall.args[0].chart.should.equal(panChart.chart);
|
|
2056
|
+
});
|
|
2057
|
+
|
|
2058
|
+
it('unbindPan() removes the native document pan-end listeners', function () {
|
|
2059
|
+
const panChart = new OrgChart({
|
|
2060
|
+
chartContainer: '#chart-container',
|
|
2061
|
+
data: ds
|
|
2062
|
+
});
|
|
2063
|
+
const panEndSpy = sinon.stub(panChart, 'panEndHandler');
|
|
2064
|
+
|
|
2065
|
+
panChart.bindPan();
|
|
2066
|
+
panChart.unbindPan();
|
|
2067
|
+
document.dispatchEvent(new window.MouseEvent('mouseup', { bubbles: true }));
|
|
2068
|
+
|
|
2069
|
+
panEndSpy.should.not.have.been.called;
|
|
2070
|
+
});
|
|
2071
|
+
|
|
2072
|
+
it('setChartScale() accepts a native chart element', function () {
|
|
2073
|
+
oc.chart.style.transform = 'none';
|
|
2074
|
+
sinon.stub(oc.chart, 'getBoundingClientRect').returns({ left: 0, top: 0 });
|
|
2075
|
+
sinon.stub(oc.chartContainer, 'getBoundingClientRect').returns({
|
|
2076
|
+
left: 0,
|
|
2077
|
+
top: 0,
|
|
2078
|
+
right: 200,
|
|
2079
|
+
bottom: 100,
|
|
2080
|
+
width: 200,
|
|
2081
|
+
height: 100
|
|
2082
|
+
});
|
|
2083
|
+
oc.setChartScale(oc.chart, 1.2);
|
|
2084
|
+
|
|
2085
|
+
oc.chart.style.transform.should.equal('matrix(1.2, 0, 0, 1.2, -20, -10)');
|
|
2086
|
+
});
|
|
2087
|
+
|
|
2088
|
+
it('setChartScale() keeps the chart-local anchor fixed even when the chart is offset inside the container', function () {
|
|
2089
|
+
sinon.stub(oc.chart, 'getBoundingClientRect').returns({ left: 100, top: 200 });
|
|
2090
|
+
oc.chart.style.transform = 'matrix(1, 0, 0, 1, 0, 0)';
|
|
2091
|
+
oc.setChartScale(oc.chart, 1.2, { x: 160, y: 245 });
|
|
2092
|
+
|
|
2093
|
+
oc.chart.style.transform.should.equal('matrix(1.2, 0, 0, 1.2, -12, -9)');
|
|
2094
|
+
});
|
|
2095
|
+
|
|
2096
|
+
it('zoomStartHandler() stores pinch state on the native chart element', function () {
|
|
2097
|
+
const pinchDistStub = sinon.stub(oc, 'getPinchDist').returns(12);
|
|
2098
|
+
const pinchCenterStub = sinon.stub(oc, 'getPinchCenter').returns({ x: 20, y: 30 });
|
|
2099
|
+
|
|
2100
|
+
oc.zoomStartHandler({
|
|
2101
|
+
orgChart: oc,
|
|
2102
|
+
touches: [{ clientX: 0, clientY: 0 }, { clientX: 3, clientY: 4 }]
|
|
2103
|
+
});
|
|
2104
|
+
|
|
2105
|
+
getState(oc.chart, 'pinching').should.equal(true);
|
|
2106
|
+
getState(oc.chart, 'pinchDistStart').should.equal(12);
|
|
2107
|
+
getState(oc.chart, 'pinchCenterStart').should.deep.equal({ x: 20, y: 30 });
|
|
2108
|
+
getState(oc.chart, 'pinchCenterEnd').should.deep.equal({ x: 20, y: 30 });
|
|
2109
|
+
|
|
2110
|
+
pinchDistStub.restore();
|
|
2111
|
+
pinchCenterStub.restore();
|
|
2112
|
+
});
|
|
2113
|
+
|
|
2114
|
+
it('zoomStartHandler() accepts wrapped native touch payloads', function () {
|
|
2115
|
+
const pinchDistStub = sinon.stub(oc, 'getPinchDist').returns(12);
|
|
2116
|
+
const pinchCenterStub = sinon.stub(oc, 'getPinchCenter').returns({ x: 20, y: 30 });
|
|
2117
|
+
|
|
2118
|
+
oc.zoomStartHandler({
|
|
2119
|
+
orgChart: oc,
|
|
2120
|
+
originalEvent: {
|
|
2121
|
+
touches: [{ clientX: 0, clientY: 0 }, { clientX: 3, clientY: 4 }]
|
|
2122
|
+
}
|
|
2123
|
+
});
|
|
2124
|
+
|
|
2125
|
+
getState(oc.chart, 'pinching').should.equal(true);
|
|
2126
|
+
getState(oc.chart, 'pinchDistStart').should.equal(12);
|
|
2127
|
+
getState(oc.chart, 'pinchCenterStart').should.deep.equal({ x: 20, y: 30 });
|
|
2128
|
+
|
|
2129
|
+
pinchDistStub.restore();
|
|
2130
|
+
pinchCenterStub.restore();
|
|
2131
|
+
});
|
|
2132
|
+
|
|
2133
|
+
it('zoomingHandler() stores pinch distance on the native chart element', function () {
|
|
2134
|
+
const pinchDistStub = sinon.stub(oc, 'getPinchDist').returns(18);
|
|
2135
|
+
const pinchCenterStub = sinon.stub(oc, 'getPinchCenter').returns({ x: 24, y: 36 });
|
|
2136
|
+
|
|
2137
|
+
setState(oc.chart, 'pinching', true);
|
|
2138
|
+
oc.zoomingHandler({ orgChart: oc });
|
|
2139
|
+
|
|
2140
|
+
getState(oc.chart, 'pinchDistEnd').should.equal(18);
|
|
2141
|
+
getState(oc.chart, 'pinchCenterEnd').should.deep.equal({ x: 24, y: 36 });
|
|
2142
|
+
|
|
2143
|
+
pinchDistStub.restore();
|
|
2144
|
+
pinchCenterStub.restore();
|
|
2145
|
+
});
|
|
2146
|
+
|
|
2147
|
+
it('zoomingHandler() accepts wrapped native touch payloads', function () {
|
|
2148
|
+
const pinchDistStub = sinon.stub(oc, 'getPinchDist').returns(18);
|
|
2149
|
+
const pinchCenterStub = sinon.stub(oc, 'getPinchCenter').returns({ x: 24, y: 36 });
|
|
2150
|
+
|
|
2151
|
+
setState(oc.chart, 'pinching', true);
|
|
2152
|
+
oc.zoomingHandler({
|
|
2153
|
+
orgChart: oc,
|
|
2154
|
+
originalEvent: {
|
|
2155
|
+
touches: [{ clientX: 0, clientY: 0 }, { clientX: 3, clientY: 4 }]
|
|
2156
|
+
}
|
|
2157
|
+
});
|
|
2158
|
+
|
|
2159
|
+
getState(oc.chart, 'pinchDistEnd').should.equal(18);
|
|
2160
|
+
getState(oc.chart, 'pinchCenterEnd').should.deep.equal({ x: 24, y: 36 });
|
|
2161
|
+
|
|
2162
|
+
pinchDistStub.restore();
|
|
2163
|
+
pinchCenterStub.restore();
|
|
2164
|
+
});
|
|
2165
|
+
|
|
2166
|
+
it('getPinchDist() accepts a native touch payload', function () {
|
|
2167
|
+
const distance = oc.getPinchDist({
|
|
2168
|
+
touches: [{ clientX: 0, clientY: 0 }, { clientX: 3, clientY: 4 }]
|
|
2169
|
+
});
|
|
2170
|
+
|
|
2171
|
+
distance.should.equal(5);
|
|
2172
|
+
});
|
|
2173
|
+
|
|
2174
|
+
it('getPinchCenter() accepts a native touch payload', function () {
|
|
2175
|
+
const pinchCenter = oc.getPinchCenter({
|
|
2176
|
+
touches: [{ clientX: 10, clientY: 20 }, { clientX: 30, clientY: 40 }]
|
|
2177
|
+
});
|
|
2178
|
+
|
|
2179
|
+
pinchCenter.should.deep.equal({ x: 20, y: 30 });
|
|
2180
|
+
});
|
|
2181
|
+
|
|
2182
|
+
it('zoomWheelHandler() passes the mouse anchor to setChartScale()', function () {
|
|
2183
|
+
const spy = sinon.spy(oc, 'setChartScale');
|
|
2184
|
+
const preventDefaultSpy = sinon.spy();
|
|
2185
|
+
sinon.stub(oc.chartContainer, 'getBoundingClientRect').returns({
|
|
2186
|
+
left: 10,
|
|
2187
|
+
top: 20,
|
|
2188
|
+
right: 210,
|
|
2189
|
+
bottom: 120,
|
|
2190
|
+
width: 200,
|
|
2191
|
+
height: 100
|
|
2192
|
+
});
|
|
2193
|
+
|
|
2194
|
+
oc.zoomWheelHandler({
|
|
2195
|
+
orgChart: oc,
|
|
2196
|
+
originalEvent: {
|
|
2197
|
+
deltaY: -1,
|
|
2198
|
+
clientX: 60,
|
|
2199
|
+
clientY: 45,
|
|
2200
|
+
preventDefault: preventDefaultSpy
|
|
2201
|
+
}
|
|
2202
|
+
});
|
|
2203
|
+
|
|
2204
|
+
preventDefaultSpy.should.have.been.calledOnce;
|
|
2205
|
+
spy.should.have.been.calledWith(oc.chart, 1.2, { x: 60, y: 45 });
|
|
2206
|
+
});
|
|
2207
|
+
|
|
2208
|
+
it('zoomWheelHandler() ignores wheel input when the pointer is outside the chart container', function () {
|
|
2209
|
+
const spy = sinon.spy(oc, 'setChartScale');
|
|
2210
|
+
const preventDefaultSpy = sinon.spy();
|
|
2211
|
+
sinon.stub(oc.chartContainer, 'getBoundingClientRect').returns({
|
|
2212
|
+
left: 10,
|
|
2213
|
+
top: 20,
|
|
2214
|
+
right: 210,
|
|
2215
|
+
bottom: 120,
|
|
2216
|
+
width: 200,
|
|
2217
|
+
height: 100
|
|
2218
|
+
});
|
|
2219
|
+
|
|
2220
|
+
oc.zoomWheelHandler({
|
|
2221
|
+
orgChart: oc,
|
|
2222
|
+
originalEvent: {
|
|
2223
|
+
deltaY: -1,
|
|
2224
|
+
clientX: 5,
|
|
2225
|
+
clientY: 45,
|
|
2226
|
+
preventDefault: preventDefaultSpy
|
|
2227
|
+
}
|
|
2228
|
+
});
|
|
2229
|
+
|
|
2230
|
+
preventDefaultSpy.should.not.have.been.called;
|
|
2231
|
+
spy.should.not.have.been.called;
|
|
2232
|
+
});
|
|
2233
|
+
|
|
2234
|
+
it('bindZoom() wires wheel events with the native chart container', function () {
|
|
2235
|
+
const zoomChart = new OrgChart({
|
|
2236
|
+
chartContainer: '#chart-container',
|
|
2237
|
+
data: ds
|
|
2238
|
+
});
|
|
2239
|
+
const zoomWheelSpy = sinon.stub(zoomChart, 'zoomWheelHandler');
|
|
2240
|
+
|
|
2241
|
+
zoomChart.bindZoom();
|
|
2242
|
+
zoomChart.chartContainer.dispatchEvent(new window.Event('wheel', { bubbles: true }));
|
|
2243
|
+
|
|
2244
|
+
zoomWheelSpy.should.have.been.called;
|
|
2245
|
+
zoomWheelSpy.lastCall.args[0].orgChart.should.equal(zoomChart);
|
|
2246
|
+
});
|
|
2247
|
+
|
|
2248
|
+
it('unbindZoom() removes native zoom listeners', function () {
|
|
2249
|
+
const zoomChart = new OrgChart({
|
|
2250
|
+
chartContainer: '#chart-container',
|
|
2251
|
+
data: ds
|
|
2252
|
+
});
|
|
2253
|
+
const zoomWheelSpy = sinon.stub(zoomChart, 'zoomWheelHandler');
|
|
2254
|
+
|
|
2255
|
+
zoomChart.bindZoom();
|
|
2256
|
+
zoomChart.unbindZoom();
|
|
2257
|
+
zoomChart.chartContainer.dispatchEvent(new window.Event('wheel', { bubbles: true }));
|
|
2258
|
+
|
|
2259
|
+
zoomWheelSpy.should.not.have.been.called;
|
|
2260
|
+
});
|
|
2261
|
+
|
|
2262
|
+
it('zoomEndHandler() passes a native chart element to setChartScale()', function () {
|
|
2263
|
+
const spy = sinon.spy(oc, 'setChartScale');
|
|
2264
|
+
|
|
2265
|
+
setState(oc.chart, 'pinching', true);
|
|
2266
|
+
setState(oc.chart, 'pinchDistStart', 10);
|
|
2267
|
+
setState(oc.chart, 'pinchDistEnd', 20);
|
|
2268
|
+
setState(oc.chart, 'pinchCenterEnd', { x: 50, y: 60 });
|
|
2269
|
+
oc.zoomEndHandler({ orgChart: oc });
|
|
2270
|
+
|
|
2271
|
+
spy.should.have.been.calledWith(oc.chart, 1.2, { x: 50, y: 60 });
|
|
2272
|
+
});
|
|
2273
|
+
|
|
2274
|
+
it('createNode() passes a native node to bindDragDrop() when draggable is enabled', function () {
|
|
2275
|
+
const draggableChart = new OrgChart({
|
|
2276
|
+
chartContainer: '#chart-container',
|
|
2277
|
+
data: ds,
|
|
2278
|
+
draggable: true
|
|
2279
|
+
});
|
|
2280
|
+
const spy = sinon.spy(draggableChart, 'bindDragDrop');
|
|
2281
|
+
|
|
2282
|
+
draggableChart.createNode({ id: 'n11', name: 'Li Xin', relationship: '000', level: 0 });
|
|
2283
|
+
|
|
2284
|
+
spy.should.have.been.called;
|
|
2285
|
+
spy.firstCall.args[0].nodeType.should.equal(1);
|
|
2286
|
+
});
|
|
2287
|
+
|
|
2288
|
+
it('buildInferiorNodes() accepts native hierarchy and node elements for vertical children', function () {
|
|
2289
|
+
const verticalChart = new OrgChart({
|
|
2290
|
+
chartContainer: '#chart-container',
|
|
2291
|
+
data: ds,
|
|
2292
|
+
verticalLevel: 2,
|
|
2293
|
+
visibleLevel: 1
|
|
2294
|
+
});
|
|
2295
|
+
const hierarchyEl = document.createElement('li');
|
|
2296
|
+
let nodeEl;
|
|
2297
|
+
let verticalNodesEl;
|
|
2298
|
+
|
|
2299
|
+
hierarchyEl.className = 'hierarchy';
|
|
2300
|
+
nodeEl = verticalChart.createNode({ id: 'n11', name: 'Parent', relationship: '001', level: 1 });
|
|
2301
|
+
hierarchyEl.appendChild(nodeEl);
|
|
2302
|
+
|
|
2303
|
+
verticalChart.buildInferiorNodes(hierarchyEl, nodeEl, {
|
|
2304
|
+
collapsed: true,
|
|
2305
|
+
children: [{ id: 'n12', name: 'Child', relationship: '000' }]
|
|
2306
|
+
}, 1);
|
|
2307
|
+
|
|
2308
|
+
verticalNodesEl = Array.from(hierarchyEl.children).find(function (childEl) {
|
|
2309
|
+
return childEl.classList && childEl.classList.contains('nodes');
|
|
2310
|
+
});
|
|
2311
|
+
|
|
2312
|
+
should.exist(verticalNodesEl);
|
|
2313
|
+
verticalNodesEl.classList.contains('vertical').should.equal(true);
|
|
2314
|
+
verticalNodesEl.classList.contains('hidden').should.equal(true);
|
|
2315
|
+
verticalNodesEl.querySelector('#n12').should.not.equal(null);
|
|
2316
|
+
});
|
|
2317
|
+
|
|
2318
|
+
it('buildInferiorNodes() keeps compact descendants on the native node element', function () {
|
|
2319
|
+
const hierarchyEl = document.createElement('li');
|
|
2320
|
+
const nodeEl = oc.createNode({ id: 'n11', name: 'Parent', relationship: '001', level: 0 });
|
|
2321
|
+
|
|
2322
|
+
hierarchyEl.className = 'hierarchy';
|
|
2323
|
+
hierarchyEl.appendChild(nodeEl);
|
|
2324
|
+
|
|
2325
|
+
oc.buildInferiorNodes(hierarchyEl, nodeEl, {
|
|
2326
|
+
compact: true,
|
|
2327
|
+
children: [{ id: 'n12', name: 'Child', relationship: '000' }]
|
|
2328
|
+
}, 0);
|
|
2329
|
+
|
|
2330
|
+
nodeEl.classList.contains('compact').should.equal(true);
|
|
2331
|
+
should.equal(hierarchyEl.querySelector('.nodes'), null);
|
|
2332
|
+
nodeEl.querySelector('#n12').should.not.equal(null);
|
|
2333
|
+
});
|
|
2334
|
+
|
|
2335
|
+
it('buildHierarchy() accepts a native hierarchy element for family tree spouse layout', function () {
|
|
2336
|
+
const hierarchyEl = document.createElement('li');
|
|
2337
|
+
let wrapperEl;
|
|
2338
|
+
|
|
2339
|
+
hierarchyEl.className = 'hierarchy';
|
|
2340
|
+
|
|
2341
|
+
oc.buildHierarchy(hierarchyEl, [[
|
|
2342
|
+
{ id: 'n11', name: 'Spouse A', relationship: '001', outsider: false },
|
|
2343
|
+
{
|
|
2344
|
+
id: 'n12',
|
|
2345
|
+
name: 'Spouse B',
|
|
2346
|
+
relationship: '001',
|
|
2347
|
+
outsider: true,
|
|
2348
|
+
children: [[{ id: 'n13', name: 'Child', relationship: '000' }]]
|
|
2349
|
+
}
|
|
2350
|
+
]]);
|
|
2351
|
+
|
|
2352
|
+
wrapperEl = hierarchyEl.firstElementChild;
|
|
2353
|
+
|
|
2354
|
+
should.exist(wrapperEl);
|
|
2355
|
+
wrapperEl.classList.contains('couple').should.equal(true);
|
|
2356
|
+
Array.from(wrapperEl.children).filter(function (childEl) {
|
|
2357
|
+
return childEl.classList && childEl.classList.contains('node');
|
|
2358
|
+
}).length.should.equal(2);
|
|
2359
|
+
wrapperEl.querySelector('#n12').should.not.equal(null);
|
|
2360
|
+
wrapperEl.querySelector('.nodes').should.not.equal(null);
|
|
2361
|
+
});
|
|
2362
|
+
|
|
2363
|
+
it('addAncestors() wraps the original root content into a different hierarchy from the new ancestor', function () {
|
|
2364
|
+
let ancestorNodeEl;
|
|
2365
|
+
let originalRootNodeEl;
|
|
2366
|
+
|
|
2367
|
+
oc.addAncestors({ id: 'n0', name: 'Lao Ye', relationship: '001' }, 'n0');
|
|
2368
|
+
|
|
2369
|
+
ancestorNodeEl = document.getElementById('n0');
|
|
2370
|
+
originalRootNodeEl = document.getElementById('n1');
|
|
2371
|
+
|
|
2372
|
+
should.exist(ancestorNodeEl);
|
|
2373
|
+
should.exist(originalRootNodeEl);
|
|
2374
|
+
originalRootNodeEl.closest('.hierarchy').should.not.equal(ancestorNodeEl.closest('.hierarchy'));
|
|
2375
|
+
});
|
|
2376
|
+
|
|
2377
|
+
it('addDescendants() accepts a native parent element and appends descendant hierarchy nodes', function () {
|
|
2378
|
+
oc.addDescendants([{ id: 'n11', name: 'Li Xin' }], $bomiao);
|
|
2379
|
+
|
|
2380
|
+
should.exist($bomiao.nextElementSibling);
|
|
2381
|
+
matchesSelector($bomiao.nextElementSibling, '.nodes').should.be.true;
|
|
2382
|
+
childElements($bomiao.nextElementSibling, '.hierarchy').should.have.lengthOf(1);
|
|
2383
|
+
queryAll('#n11', $bomiao.nextElementSibling).should.have.lengthOf(1);
|
|
2384
|
+
});
|
|
2385
|
+
|
|
2386
|
+
it('showDropZones() accepts a native dragged node', function () {
|
|
2387
|
+
oc.showDropZones($heihei);
|
|
2388
|
+
|
|
2389
|
+
getState(oc.chart, 'dragged').should.equal($heihei);
|
|
2390
|
+
queryAll('.allowedDrop', oc.chart).length.should.equal(queryAll('.node', oc.chart).length);
|
|
2391
|
+
});
|
|
2392
|
+
|
|
2393
|
+
it('hideDropZones() clears all allowedDrop classes', function () {
|
|
2394
|
+
oc.showDropZones($heihei);
|
|
2395
|
+
|
|
2396
|
+
oc.hideDropZones();
|
|
2397
|
+
|
|
2398
|
+
queryAll('.allowedDrop', oc.chart).should.have.lengthOf(0);
|
|
2399
|
+
});
|
|
2400
|
+
|
|
2401
|
+
it('processExternalDrop() accepts native drop and dragged nodes', function () {
|
|
2402
|
+
const dropSpy = sinon.spy();
|
|
2403
|
+
|
|
2404
|
+
$bomiao.addEventListener('drop', dropSpy);
|
|
2405
|
+
|
|
2406
|
+
oc.processExternalDrop($bomiao, $heihei);
|
|
2407
|
+
|
|
2408
|
+
getState(oc.chart, 'dragged').should.equal($heihei);
|
|
2409
|
+
dropSpy.should.have.been.calledOnce;
|
|
2410
|
+
dropSpy.firstCall.args[0].type.should.equal('drop');
|
|
2411
|
+
});
|
|
2412
|
+
|
|
2413
|
+
it('exportPNG() creates and reuses a native download anchor', function () {
|
|
2414
|
+
const originalNavigator = window.navigator;
|
|
2415
|
+
const originalClick = window.HTMLAnchorElement.prototype.click;
|
|
2416
|
+
const originalWebkitAppearance = document.documentElement.style.WebkitAppearance;
|
|
2417
|
+
const clickSpy = sinon.spy();
|
|
2418
|
+
const fakeCanvas = {
|
|
2419
|
+
toDataURL: function () {
|
|
2420
|
+
return 'data:image/png;base64,fake';
|
|
2421
|
+
}
|
|
2422
|
+
};
|
|
2423
|
+
|
|
2424
|
+
Object.defineProperty(window, 'navigator', {
|
|
2425
|
+
configurable: true,
|
|
2426
|
+
value: {
|
|
2427
|
+
appName: 'Netscape',
|
|
2428
|
+
appVersion: 'Chrome'
|
|
2429
|
+
}
|
|
2430
|
+
});
|
|
2431
|
+
document.documentElement.style.WebkitAppearance = 'none';
|
|
2432
|
+
window.HTMLAnchorElement.prototype.click = clickSpy;
|
|
2433
|
+
|
|
2434
|
+
oc.exportPNG(fakeCanvas, 'UnitExportPng');
|
|
2435
|
+
oc.exportPNG(fakeCanvas, 'UnitExportPng2');
|
|
2436
|
+
|
|
2437
|
+
queryAll('.download-btn', $container).should.have.lengthOf(1);
|
|
2438
|
+
query('.download-btn', $container).getAttribute('download').should.equal('UnitExportPng2.png');
|
|
2439
|
+
query('.download-btn', $container).getAttribute('href').should.equal('data:image/png;base64,fake');
|
|
2440
|
+
clickSpy.callCount.should.equal(2);
|
|
2441
|
+
|
|
2442
|
+
Object.defineProperty(window, 'navigator', {
|
|
2443
|
+
configurable: true,
|
|
2444
|
+
value: originalNavigator
|
|
2445
|
+
});
|
|
2446
|
+
document.documentElement.style.WebkitAppearance = originalWebkitAppearance;
|
|
2447
|
+
window.HTMLAnchorElement.prototype.click = originalClick;
|
|
2448
|
+
});
|
|
2449
|
+
|
|
2450
|
+
it('export() passes the visible chart element to html2canvas and exports png by default', function (done) {
|
|
2451
|
+
const originalHtml2canvas = global.html2canvas;
|
|
2452
|
+
const originalWindowHtml2canvas = window.html2canvas;
|
|
2453
|
+
const exportPNGStub = sinon.stub(oc, 'exportPNG');
|
|
2454
|
+
const fakeCanvas = {
|
|
2455
|
+
toDataURL: function () {
|
|
2456
|
+
return 'data:image/png;base64,fake';
|
|
2457
|
+
}
|
|
2458
|
+
};
|
|
2459
|
+
|
|
2460
|
+
global.html2canvas = function (element, options) {
|
|
2461
|
+
try {
|
|
2462
|
+
element.should.equal(oc.chart);
|
|
2463
|
+
options.width.should.equal(oc.chart.clientWidth);
|
|
2464
|
+
options.height.should.equal(oc.chart.clientHeight);
|
|
2465
|
+
options.scale.should.equal(2);
|
|
2466
|
+
options.useCORS.should.equal(true);
|
|
2467
|
+
} catch (error) {
|
|
2468
|
+
done(error);
|
|
2469
|
+
return {
|
|
2470
|
+
then: function () {}
|
|
2471
|
+
};
|
|
2472
|
+
}
|
|
2473
|
+
|
|
2474
|
+
return {
|
|
2475
|
+
then: function (resolve) {
|
|
2476
|
+
resolve(fakeCanvas);
|
|
2477
|
+
return {
|
|
2478
|
+
then: function () {}
|
|
2479
|
+
};
|
|
2480
|
+
}
|
|
2481
|
+
};
|
|
2482
|
+
};
|
|
2483
|
+
|
|
2484
|
+
window.html2canvas = global.html2canvas;
|
|
2485
|
+
|
|
2486
|
+
oc.export('UnitExport');
|
|
2487
|
+
|
|
2488
|
+
setTimeout(function () {
|
|
2489
|
+
try {
|
|
2490
|
+
exportPNGStub.should.have.been.calledOnce;
|
|
2491
|
+
exportPNGStub.firstCall.args[0].should.equal(fakeCanvas);
|
|
2492
|
+
exportPNGStub.firstCall.args[1].should.equal('UnitExport');
|
|
2493
|
+
$container.classList.contains('canvasContainer').should.be.false;
|
|
2494
|
+
query('.mask', $container).classList.contains('hidden').should.be.true;
|
|
2495
|
+
global.html2canvas = originalHtml2canvas;
|
|
2496
|
+
window.html2canvas = originalWindowHtml2canvas;
|
|
2497
|
+
exportPNGStub.restore();
|
|
2498
|
+
done();
|
|
2499
|
+
} catch (error) {
|
|
2500
|
+
global.html2canvas = originalHtml2canvas;
|
|
2501
|
+
window.html2canvas = originalWindowHtml2canvas;
|
|
2502
|
+
exportPNGStub.restore();
|
|
2503
|
+
done(error);
|
|
2504
|
+
}
|
|
2505
|
+
}, 0);
|
|
2506
|
+
});
|
|
2507
|
+
|
|
2508
|
+
it('export() returns false when the chart container already has a spinner', function () {
|
|
2509
|
+
const html2canvasStub = sinon.stub(global, 'html2canvas');
|
|
2510
|
+
const spinnerEl = document.createElement('i');
|
|
2511
|
+
|
|
2512
|
+
spinnerEl.className = 'spinner';
|
|
2513
|
+
$container.appendChild(spinnerEl);
|
|
2514
|
+
|
|
2515
|
+
oc.export('BlockedExport').should.equal(false);
|
|
2516
|
+
html2canvasStub.should.not.have.been.called;
|
|
2517
|
+
|
|
2518
|
+
spinnerEl.remove();
|
|
2519
|
+
html2canvasStub.restore();
|
|
2520
|
+
});
|
|
2521
|
+
|
|
2522
|
+
it('export() routes pdf exports to exportPDF()', function (done) {
|
|
2523
|
+
const originalHtml2canvas = global.html2canvas;
|
|
2524
|
+
const originalWindowHtml2canvas = window.html2canvas;
|
|
2525
|
+
const exportPDFStub = sinon.stub(oc, 'exportPDF');
|
|
2526
|
+
const fakeCanvas = {
|
|
2527
|
+
toDataURL: function () {
|
|
2528
|
+
return 'data:image/png;base64,fake';
|
|
2529
|
+
}
|
|
2530
|
+
};
|
|
2531
|
+
|
|
2532
|
+
global.html2canvas = function () {
|
|
2533
|
+
return {
|
|
2534
|
+
then: function (resolve) {
|
|
2535
|
+
resolve(fakeCanvas);
|
|
2536
|
+
return {
|
|
2537
|
+
then: function () {}
|
|
2538
|
+
};
|
|
2539
|
+
}
|
|
2540
|
+
};
|
|
2541
|
+
};
|
|
2542
|
+
|
|
2543
|
+
window.html2canvas = global.html2canvas;
|
|
2544
|
+
|
|
2545
|
+
oc.export('UnitExportPdf', 'pdf');
|
|
2546
|
+
|
|
2547
|
+
setTimeout(function () {
|
|
2548
|
+
try {
|
|
2549
|
+
exportPDFStub.should.have.been.calledOnce;
|
|
2550
|
+
exportPDFStub.firstCall.args[0].should.equal(fakeCanvas);
|
|
2551
|
+
exportPDFStub.firstCall.args[1].should.equal('UnitExportPdf');
|
|
2552
|
+
global.html2canvas = originalHtml2canvas;
|
|
2553
|
+
window.html2canvas = originalWindowHtml2canvas;
|
|
2554
|
+
exportPDFStub.restore();
|
|
2555
|
+
done();
|
|
2556
|
+
} catch (error) {
|
|
2557
|
+
global.html2canvas = originalHtml2canvas;
|
|
2558
|
+
window.html2canvas = originalWindowHtml2canvas;
|
|
2559
|
+
exportPDFStub.restore();
|
|
2560
|
+
done(error);
|
|
2561
|
+
}
|
|
2562
|
+
}, 0);
|
|
2563
|
+
});
|
|
2564
|
+
});
|