orgchart 5.0.0 → 7.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 +35 -0
- package/README.md +214 -123
- package/README.zh-cn.md +232 -100
- package/README.zh-tw.md +232 -100
- 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 +144 -94
- package/demo/edit-hybrid-chart.html +177 -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 +10 -3
- 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 +166 -112
- package/demo/option-createNode.html +28 -17
- package/demo/options-compact-drag.html +82 -0
- package/demo/options-export-navigation.html +76 -0
- package/demo/options-horizontal-template.html +80 -0
- package/demo/options-hybrid-navigation.html +71 -0
- 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} +154 -80
- package/dist/css/orgchart.min.css +1 -0
- package/dist/js/orgchart.js +4474 -0
- package/dist/js/orgchart.min.js +2 -0
- package/dist/js/orgchart.min.js.map +1 -0
- package/gulpfile.js +42 -27
- package/package.json +33 -32
- package/src/css/{jquery.orgchart.css → orgchart.css} +154 -80
- package/src/js/orgchart.js +4474 -0
- package/test/compatibility/README.md +123 -0
- package/test/compatibility/browser.tests.js +1279 -0
- package/test/compatibility/options.tests.js +628 -0
- package/test/cypress/e2e/demo-interactions.cy.js +91 -0
- package/test/cypress/e2e/demo-rendering.cy.js +161 -0
- package/test/cypress/e2e/drag-drop-hybrid-chart.cy.js +23 -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/local-datasource.cy.js +16 -16
- package/test/cypress/e2e/minimap.cy.js +66 -0
- package/test/cypress/e2e/ondemand-loading-data.cy.js +34 -10
- package/test/cypress/e2e/pan-zoom.cy.js +165 -0
- package/test/cypress/e2e/report-path.cy.js +20 -0
- package/test/cypress/e2e/toggle-sibs-resp.cy.js +4 -4
- package/test/cypress/e2e/vertical-vevel.cy.js +7 -5
- package/test/e2e/local-datasource/test.js +1 -1
- package/test/integration/init-tests.js +192 -99
- package/test/integration/tests.js +1043 -57
- package/test/unit/lifecycle-builders-export.tests.js +1487 -0
- package/test/unit/minimap.tests.js +210 -0
- package/test/unit/tests.js +2372 -253
- 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,78 @@ 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
|
-
|
|
82
|
-
|
|
236
|
+
document.body.innerHTML = '<div id="chart-container"></div>';
|
|
237
|
+
$container = document.getElementById('chart-container');
|
|
238
|
+
oc = new OrgChart({
|
|
239
|
+
chartContainer: '#chart-container',
|
|
240
|
+
'data': JSON.parse(JSON.stringify(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
|
+
children: [
|
|
280
|
+
{
|
|
281
|
+
id: 'child',
|
|
282
|
+
name: 'Child'
|
|
283
|
+
}
|
|
284
|
+
]
|
|
285
|
+
});
|
|
104
286
|
});
|
|
105
287
|
|
|
106
288
|
it('getHierarchy()', function () {
|
|
107
289
|
oc.getHierarchy().should.deep.equal(hierarchy);
|
|
108
290
|
|
|
109
|
-
|
|
291
|
+
const oc2 = new OrgChart({
|
|
292
|
+
chartContainer: '#chart-container',
|
|
110
293
|
'data': { name: 'Lao Lao',
|
|
111
294
|
'children': [
|
|
112
295
|
{ name: 'Bo Miao' }
|
|
@@ -114,249 +297,621 @@ describe('orgchart -- unit tests', function () {
|
|
|
114
297
|
}
|
|
115
298
|
});
|
|
116
299
|
oc2.getHierarchy().should.include('Error');
|
|
117
|
-
oc2
|
|
300
|
+
oc2.chart.innerHTML = "";
|
|
118
301
|
oc2.getHierarchy().should.include('Error');
|
|
119
|
-
oc2
|
|
302
|
+
oc2.chart = null;
|
|
120
303
|
oc2.getHierarchy().should.include('Error');
|
|
121
304
|
});
|
|
122
305
|
|
|
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");
|
|
306
|
+
it('triggerShowEvent() accepts a native node', function () {
|
|
307
|
+
const eventSpy = sinon.spy();
|
|
171
308
|
|
|
172
|
-
|
|
173
|
-
|
|
174
|
-
|
|
175
|
-
|
|
309
|
+
$sumiao.addEventListener('show-children.orgchart', eventSpy);
|
|
310
|
+
|
|
311
|
+
oc.triggerShowEvent($sumiao, 'children');
|
|
312
|
+
|
|
313
|
+
eventSpy.should.have.been.calledOnce;
|
|
314
|
+
eventSpy.firstCall.args[0].type.should.equal('show-children.orgchart');
|
|
315
|
+
});
|
|
316
|
+
|
|
317
|
+
it('triggerHideEvent() accepts a native node', function () {
|
|
318
|
+
const eventSpy = sinon.spy();
|
|
319
|
+
|
|
320
|
+
$sumiao.addEventListener('hide-children.orgchart', eventSpy);
|
|
321
|
+
|
|
322
|
+
oc.triggerHideEvent($sumiao, 'children');
|
|
323
|
+
|
|
324
|
+
eventSpy.should.have.been.calledOnce;
|
|
325
|
+
eventSpy.firstCall.args[0].type.should.equal('hide-children.orgchart');
|
|
326
|
+
});
|
|
327
|
+
|
|
328
|
+
it('getNodeState()', function () {
|
|
329
|
+
const stateDs = JSON.parse(baseDs);
|
|
330
|
+
let chartEl;
|
|
331
|
+
let laolaoEl;
|
|
332
|
+
let bomiaoEl;
|
|
333
|
+
let sumiaoEl;
|
|
334
|
+
let tiehuaEl;
|
|
335
|
+
let heiheiEl;
|
|
336
|
+
let pangpangEl;
|
|
337
|
+
let dandanEl;
|
|
338
|
+
|
|
339
|
+
$container.innerHTML = '';
|
|
340
|
+
oc = new OrgChart({
|
|
341
|
+
chartContainer: '#chart-container',
|
|
342
|
+
data: stateDs,
|
|
343
|
+
nodeContent: 'title',
|
|
344
|
+
visibleLevel: 2,
|
|
345
|
+
verticalLevel: 3
|
|
346
|
+
});
|
|
347
|
+
chartEl = oc.chart;
|
|
348
|
+
laolaoEl = query('#n1', chartEl);
|
|
349
|
+
bomiaoEl = query('#n2', chartEl);
|
|
350
|
+
sumiaoEl = query('#n3', chartEl);
|
|
351
|
+
tiehuaEl = query('#n5', chartEl);
|
|
352
|
+
heiheiEl = query('#n6', chartEl);
|
|
353
|
+
pangpangEl = query('#n7', chartEl);
|
|
354
|
+
dandanEl = query('#n8', chartEl);
|
|
355
|
+
|
|
356
|
+
oc.getNodeState(laolaoEl).should.deep.equal({ 'exist': true, 'visible': true }, 'laolao->self');
|
|
357
|
+
oc.getNodeState(laolaoEl, 'parent').should.deep.equal({ 'exist': false, 'visible': false }, 'laolao->parent');
|
|
358
|
+
oc.getNodeState(laolaoEl, 'children').should.deep.equal({ 'exist': true, 'visible': true }, 'laolao->children');
|
|
359
|
+
oc.getNodeState(laolaoEl, 'siblings').should.deep.equal({ 'exist': false, 'visible': false }, 'laolao->siblings');
|
|
360
|
+
|
|
361
|
+
oc.getNodeState(bomiaoEl).should.deep.equal({ 'exist': true, 'visible': true }, 'bomiao->self');
|
|
362
|
+
oc.getNodeState(bomiaoEl, 'parent').should.deep.equal({ 'exist': true, 'visible': true }, 'bomiao->parent');
|
|
363
|
+
oc.getNodeState(bomiaoEl, 'children').should.deep.equal({ 'exist': false, 'visible': false }, 'bomiao->children');
|
|
364
|
+
oc.getNodeState(bomiaoEl, 'siblings').should.deep.equal({ 'exist': true, 'visible': true }, 'bomiao->siblings');
|
|
365
|
+
|
|
366
|
+
oc.getNodeState(sumiaoEl).should.deep.equal({ 'exist': true, 'visible': true }, 'sumiao->self');
|
|
367
|
+
oc.getNodeState(sumiaoEl, 'parent').should.deep.equal({ 'exist': true, 'visible': true }, 'sumiao->parent');
|
|
368
|
+
oc.getNodeState(sumiaoEl, 'children').should.deep.equal({ 'exist': true, 'visible': false }, 'sumiao->children');
|
|
369
|
+
oc.getNodeState(sumiaoEl, 'siblings').should.deep.equal({ 'exist': true, 'visible': true }, 'sumiao->siblings');
|
|
370
|
+
|
|
371
|
+
oc.getNodeState(tiehuaEl).should.deep.equal({ 'exist': true, 'visible': false }, 'tiehua->self');
|
|
372
|
+
oc.getNodeState(tiehuaEl, 'parent').should.deep.equal({ 'exist': true, 'visible': true }, 'tiehua->parent');
|
|
373
|
+
oc.getNodeState(tiehuaEl, 'children').should.deep.equal({ 'exist': true, 'visible': false }, 'tiehua->children');
|
|
374
|
+
oc.getNodeState(tiehuaEl, 'siblings').should.deep.equal({ 'exist': true, 'visible': false }, 'tiehua->siblings');
|
|
375
|
+
|
|
376
|
+
oc.getNodeState(heiheiEl).should.deep.equal({ 'exist': true, 'visible': false }, 'heihei->self');
|
|
377
|
+
oc.getNodeState(heiheiEl, 'parent').should.deep.equal({ 'exist': true, 'visible': true }, 'heihei->parent');
|
|
378
|
+
oc.getNodeState(heiheiEl, 'children').should.deep.equal({ 'exist': true, 'visible': false }, 'heihei->children');
|
|
379
|
+
oc.getNodeState(heiheiEl, 'siblings').should.deep.equal({ 'exist': true, 'visible': false }, 'heihei->siblings');
|
|
380
|
+
|
|
381
|
+
oc.getNodeState(pangpangEl).should.deep.equal({ 'exist': true, 'visible': false }, 'pangpang->self');
|
|
382
|
+
oc.getNodeState(pangpangEl, 'parent').should.deep.equal({ 'exist': true, 'visible': true }, 'pangpang->parent');
|
|
383
|
+
oc.getNodeState(pangpangEl, 'children').should.deep.equal({ 'exist': true, 'visible': false }, 'pangpang->children');
|
|
384
|
+
oc.getNodeState(pangpangEl, 'siblings').should.deep.equal({ 'exist': true, 'visible': false }, 'pangpang->siblings');
|
|
385
|
+
|
|
386
|
+
oc.getNodeState(dandanEl).should.deep.equal({ 'exist': true, 'visible': false }, 'dandan->self');
|
|
387
|
+
oc.getNodeState(dandanEl, 'parent').should.deep.equal({ 'exist': true, 'visible': false }, 'dandan->parent');
|
|
388
|
+
oc.getNodeState(dandanEl, 'children').should.deep.equal({ 'exist': false, 'visible': false }, 'dandan->children');
|
|
389
|
+
oc.getNodeState(dandanEl, 'siblings').should.deep.equal({ 'exist': false, 'visible': false }, 'dandan->siblings');
|
|
390
|
+
});
|
|
391
|
+
|
|
392
|
+
it('triggerInitEvent() calls initCompleted with the native chart element', function () {
|
|
393
|
+
const originalMutationObserver = global.MutationObserver;
|
|
394
|
+
const originalWindowMutationObserver = window.MutationObserver;
|
|
395
|
+
const observeSpy = sinon.spy();
|
|
396
|
+
const disconnectSpy = sinon.spy();
|
|
397
|
+
const initCompletedSpy = sinon.spy();
|
|
398
|
+
|
|
399
|
+
const fakeMutationObserver = function (callback) {
|
|
400
|
+
this.observe = function (target, options) {
|
|
401
|
+
observeSpy(target, options);
|
|
402
|
+
callback([
|
|
403
|
+
{
|
|
404
|
+
addedNodes: [oc.chart]
|
|
405
|
+
}
|
|
406
|
+
]);
|
|
407
|
+
};
|
|
408
|
+
this.disconnect = disconnectSpy;
|
|
176
409
|
};
|
|
177
|
-
|
|
178
|
-
|
|
179
|
-
|
|
180
|
-
|
|
181
|
-
|
|
182
|
-
|
|
410
|
+
|
|
411
|
+
global.MutationObserver = fakeMutationObserver;
|
|
412
|
+
window.MutationObserver = fakeMutationObserver;
|
|
413
|
+
|
|
414
|
+
oc.options.initCompleted = initCompletedSpy;
|
|
415
|
+
oc.triggerInitEvent();
|
|
416
|
+
|
|
417
|
+
observeSpy.should.have.been.calledOnce;
|
|
418
|
+
observeSpy.firstCall.args[0].should.equal($container);
|
|
419
|
+
observeSpy.firstCall.args[1].should.deep.equal({ childList: true });
|
|
420
|
+
disconnectSpy.should.have.been.calledOnce;
|
|
421
|
+
initCompletedSpy.should.have.been.calledOnce;
|
|
422
|
+
initCompletedSpy.firstCall.args[0].should.equal(oc.chart);
|
|
423
|
+
|
|
424
|
+
global.MutationObserver = originalMutationObserver;
|
|
425
|
+
window.MutationObserver = originalWindowMutationObserver;
|
|
426
|
+
});
|
|
427
|
+
|
|
428
|
+
it('triggerInitEvent() triggers init.orgchart on the chart collection', function () {
|
|
429
|
+
const originalMutationObserver = global.MutationObserver;
|
|
430
|
+
const originalWindowMutationObserver = window.MutationObserver;
|
|
431
|
+
const eventSpy = sinon.spy();
|
|
432
|
+
|
|
433
|
+
const fakeMutationObserver = function (callback) {
|
|
434
|
+
this.observe = function () {
|
|
435
|
+
callback([
|
|
436
|
+
{
|
|
437
|
+
addedNodes: [oc.chart]
|
|
438
|
+
}
|
|
439
|
+
]);
|
|
440
|
+
};
|
|
441
|
+
this.disconnect = function () {};
|
|
442
|
+
};
|
|
443
|
+
|
|
444
|
+
global.MutationObserver = fakeMutationObserver;
|
|
445
|
+
window.MutationObserver = fakeMutationObserver;
|
|
446
|
+
oc.chart.addEventListener('init.orgchart', eventSpy);
|
|
447
|
+
|
|
448
|
+
oc.triggerInitEvent();
|
|
449
|
+
|
|
450
|
+
eventSpy.should.have.been.calledOnce;
|
|
451
|
+
eventSpy.firstCall.args[0].type.should.equal('init.orgchart');
|
|
452
|
+
|
|
453
|
+
global.MutationObserver = originalMutationObserver;
|
|
454
|
+
window.MutationObserver = originalWindowMutationObserver;
|
|
455
|
+
});
|
|
456
|
+
|
|
457
|
+
it('handleCompactNodes() tags compact nodes by compact-ancestor parity', function () {
|
|
458
|
+
const compactRootEl = document.createElement('div');
|
|
459
|
+
const compactChildEl = document.createElement('div');
|
|
460
|
+
const compactGrandchildEl = document.createElement('div');
|
|
461
|
+
|
|
462
|
+
compactRootEl.className = 'node compact';
|
|
463
|
+
compactChildEl.className = 'node compact';
|
|
464
|
+
compactGrandchildEl.className = 'node compact';
|
|
465
|
+
compactRootEl.appendChild(compactChildEl);
|
|
466
|
+
compactChildEl.appendChild(compactGrandchildEl);
|
|
467
|
+
oc.chart.appendChild(compactRootEl);
|
|
468
|
+
|
|
469
|
+
oc.handleCompactNodes();
|
|
470
|
+
|
|
471
|
+
compactRootEl.classList.contains('even').should.equal(true);
|
|
472
|
+
compactChildEl.classList.contains('odd').should.equal(true);
|
|
473
|
+
compactGrandchildEl.classList.contains('even').should.equal(true);
|
|
183
474
|
});
|
|
184
475
|
|
|
185
476
|
it('getRelatedNodes()', function () {
|
|
186
|
-
oc.getRelatedNodes().should.deep.equal(
|
|
187
|
-
oc.getRelatedNodes({}, 'children').should.deep.equal(
|
|
188
|
-
oc.getRelatedNodes(
|
|
189
|
-
oc.getRelatedNodes(
|
|
477
|
+
oc.getRelatedNodes().should.deep.equal([]);
|
|
478
|
+
oc.getRelatedNodes({}, 'children').should.deep.equal([]);
|
|
479
|
+
oc.getRelatedNodes(query('.hierarchy', oc.chart), 'children').should.deep.equal([]);
|
|
480
|
+
oc.getRelatedNodes(query('.node', oc.chart), 'child').should.deep.equal([]);
|
|
190
481
|
|
|
191
|
-
oc.getRelatedNodes($laolao, 'parent')
|
|
192
|
-
oc.getRelatedNodes($laolao, 'children').
|
|
193
|
-
oc.getRelatedNodes($laolao, 'siblings').should.deep.equal(
|
|
482
|
+
should.equal(oc.getRelatedNodes($laolao, 'parent'), null);
|
|
483
|
+
oc.getRelatedNodes($laolao, 'children').should.have.members([$bomiao, $sumiao, $hongmiao]);
|
|
484
|
+
oc.getRelatedNodes($laolao, 'siblings').should.deep.equal([]);
|
|
194
485
|
|
|
195
|
-
oc.getRelatedNodes($bomiao, 'parent').should.
|
|
486
|
+
oc.getRelatedNodes($bomiao, 'parent').should.equal($laolao);
|
|
196
487
|
oc.getRelatedNodes($bomiao, 'children').should.have.lengthOf(0);
|
|
197
|
-
oc.getRelatedNodes($bomiao, 'siblings').
|
|
488
|
+
oc.getRelatedNodes($bomiao, 'siblings').should.have.members([$sumiao, $hongmiao]);
|
|
198
489
|
});
|
|
199
490
|
|
|
200
491
|
it('getParent()', function () {
|
|
201
|
-
|
|
202
|
-
oc.getParent({})
|
|
203
|
-
oc.getParent(
|
|
492
|
+
should.equal(oc.getParent(), null);
|
|
493
|
+
should.equal(oc.getParent({}), null);
|
|
494
|
+
should.equal(oc.getParent(query('.hierarchy', oc.chart)), null);
|
|
204
495
|
|
|
205
|
-
oc.getParent($laolao)
|
|
206
|
-
oc.getParent($bomiao).should.
|
|
207
|
-
oc.getParent($sandan).should.
|
|
496
|
+
should.equal(oc.getParent($laolao), null);
|
|
497
|
+
oc.getParent($bomiao).should.equal($laolao);
|
|
498
|
+
oc.getParent($sandan).should.equal($pangpang);
|
|
208
499
|
});
|
|
209
500
|
|
|
210
501
|
it('getSiblings()', function () {
|
|
211
|
-
oc.getSiblings().should.deep.equal(
|
|
212
|
-
oc.getSiblings({}).should.deep.equal(
|
|
213
|
-
oc.getSiblings(
|
|
502
|
+
oc.getSiblings().should.deep.equal([]);
|
|
503
|
+
oc.getSiblings({}).should.deep.equal([]);
|
|
504
|
+
oc.getSiblings(query('.hierarchy', oc.chart)).should.deep.equal([]);
|
|
214
505
|
|
|
215
|
-
oc.getSiblings($laolao).should.deep.equal(
|
|
216
|
-
oc.getSiblings($bomiao).
|
|
217
|
-
oc.getSiblings($sandan).should.deep.equal(
|
|
506
|
+
oc.getSiblings($laolao).should.deep.equal([]);
|
|
507
|
+
oc.getSiblings($bomiao).should.have.members([$sumiao, $hongmiao]);
|
|
508
|
+
oc.getSiblings($sandan).should.deep.equal([]);
|
|
218
509
|
});
|
|
219
510
|
|
|
220
511
|
it('getChildren()', function () {
|
|
221
|
-
oc.getChildren().should.deep.equal(
|
|
222
|
-
oc.getChildren({}).should.deep.equal(
|
|
223
|
-
oc.getChildren(
|
|
512
|
+
oc.getChildren().should.deep.equal([]);
|
|
513
|
+
oc.getChildren({}).should.deep.equal([]);
|
|
514
|
+
oc.getChildren(query('.hierarchy', oc.chart)).should.deep.equal([]);
|
|
224
515
|
|
|
225
|
-
oc.getChildren($laolao).
|
|
226
|
-
oc.getChildren($bomiao).should.deep.equal(
|
|
227
|
-
oc.getChildren($sumiao).
|
|
228
|
-
oc.getChildren($sandan).should.deep.equal(
|
|
516
|
+
oc.getChildren($laolao).should.have.members([$bomiao, $sumiao, $hongmiao]);
|
|
517
|
+
oc.getChildren($bomiao).should.deep.equal([]);
|
|
518
|
+
oc.getChildren($sumiao).should.have.members([$tiehua, $heihei, $pangpang]);
|
|
519
|
+
oc.getChildren($sandan).should.deep.equal([]);
|
|
229
520
|
});
|
|
230
521
|
|
|
231
522
|
it('hideParent()', function () {
|
|
232
|
-
|
|
233
|
-
|
|
523
|
+
const spy = sinon.spy(oc, 'hideParent');
|
|
524
|
+
const spy2 = sinon.spy(oc, 'hideSiblings');
|
|
525
|
+
|
|
234
526
|
oc.hideParent($heihei);
|
|
527
|
+
setOneTimeListener($sumiao, 'transitionend', null, function (event) {
|
|
528
|
+
event.parent = parentEl;
|
|
529
|
+
spy.call(oc, event);
|
|
530
|
+
});
|
|
235
531
|
spy.should.have.been.callCount(2);
|
|
236
|
-
spy.getCall(0).should.
|
|
237
|
-
spy.getCall(1).should.
|
|
532
|
+
spy.getCall(0).args[0].should.equal($heihei);
|
|
533
|
+
spy.getCall(1).args[0].should.equal($sumiao);
|
|
238
534
|
spy2.should.have.been.callCount(2);
|
|
239
|
-
spy2.getCall(0).should.
|
|
240
|
-
spy2.getCall(1).should.
|
|
535
|
+
spy2.getCall(0).args[0].should.equal($heihei);
|
|
536
|
+
spy2.getCall(1).args[0].should.equal($sumiao);
|
|
537
|
+
});
|
|
538
|
+
|
|
539
|
+
it('hideParent() hides the transitioned parent node', function () {
|
|
540
|
+
oc.hideParent($sumiao);
|
|
541
|
+
|
|
542
|
+
triggerEvent($laolao, 'transitionend');
|
|
543
|
+
|
|
544
|
+
$laolao.classList.contains('sliding').should.equal(false);
|
|
545
|
+
$laolao.classList.contains('hidden').should.equal(true);
|
|
546
|
+
});
|
|
547
|
+
|
|
548
|
+
it('hideParent() clears inAjax when the parent node contains a spinner', function () {
|
|
549
|
+
const spinnerEl = document.createElement('i');
|
|
550
|
+
|
|
551
|
+
spinnerEl.className = 'spinner';
|
|
552
|
+
$sumiao.appendChild(spinnerEl);
|
|
553
|
+
setState(oc.chart, 'inAjax', true);
|
|
554
|
+
|
|
555
|
+
oc.hideParent($heihei);
|
|
556
|
+
|
|
557
|
+
getState(oc.chart, 'inAjax').should.be.false;
|
|
558
|
+
spinnerEl.remove();
|
|
241
559
|
});
|
|
242
560
|
|
|
243
561
|
it('hideParentEnd()', function () {
|
|
244
|
-
|
|
245
|
-
|
|
246
|
-
$sumiao
|
|
247
|
-
$sumiao
|
|
248
|
-
|
|
249
|
-
|
|
250
|
-
|
|
562
|
+
const parentEl = firstSibling(closestElement($heihei, '.nodes'), '.node');
|
|
563
|
+
|
|
564
|
+
addClasses($sumiao, 'sliding slide-down');
|
|
565
|
+
oc.hideParentEnd({ animatedNode: $sumiao, parent: parentEl });
|
|
566
|
+
matchesSelector($sumiao, 'sliding').should.be.false;
|
|
567
|
+
matchesSelector(parentEl, '.hidden').should.be.true;
|
|
568
|
+
});
|
|
569
|
+
|
|
570
|
+
it('hideParentEnd() accepts native animated and parent payloads', function () {
|
|
571
|
+
addClasses($sumiao, 'sliding');
|
|
572
|
+
removeClasses($sumiao, 'hidden');
|
|
573
|
+
|
|
574
|
+
oc.hideParentEnd({
|
|
575
|
+
animatedNode: $sumiao,
|
|
576
|
+
parent: $sumiao
|
|
577
|
+
});
|
|
578
|
+
|
|
579
|
+
$sumiao.classList.contains('sliding').should.equal(false);
|
|
580
|
+
$sumiao.classList.contains('hidden').should.equal(true);
|
|
581
|
+
});
|
|
582
|
+
|
|
583
|
+
it('hideParentEnd() accepts wrapped native animated and parent payloads', function () {
|
|
584
|
+
addClasses($sumiao, 'sliding');
|
|
585
|
+
|
|
586
|
+
oc.hideParentEnd({
|
|
587
|
+
originalEvent: {
|
|
588
|
+
target: $sumiao,
|
|
589
|
+
parent: $heihei
|
|
590
|
+
}
|
|
591
|
+
});
|
|
592
|
+
|
|
593
|
+
$sumiao.classList.contains('sliding').should.equal(false);
|
|
594
|
+
$heihei.classList.contains('hidden').should.equal(true);
|
|
251
595
|
});
|
|
252
596
|
|
|
253
597
|
it('showParent()', function () {
|
|
254
|
-
|
|
255
|
-
|
|
256
|
-
$
|
|
257
|
-
$
|
|
598
|
+
const spy = sinon.spy(oc, 'repaint');
|
|
599
|
+
|
|
600
|
+
addClasses(closestElement($heihei, '.hierarchy'), 'isAncestorsCollapsed');
|
|
601
|
+
addClasses($sumiao, 'slide-down hidden');
|
|
602
|
+
addClasses(closestElement($sumiao, '.hierarchy'), 'isAncestorsCollapsed');
|
|
603
|
+
addClasses($laolao, 'slide-down hidden');
|
|
258
604
|
oc.showParent($heihei);
|
|
259
605
|
spy.should.have.been.called;
|
|
260
|
-
$heihei
|
|
261
|
-
$sumiao
|
|
262
|
-
$sumiao
|
|
263
|
-
$laolao
|
|
264
|
-
$sumiao
|
|
265
|
-
$sumiao
|
|
606
|
+
matchesSelector(closestElement($heihei, '.hierarchy'), '.isAncestorsCollapsed').should.be.false;
|
|
607
|
+
matchesSelector($sumiao, '.slide-down, .hidden').should.be.false;
|
|
608
|
+
matchesSelector(closestElement($sumiao, '.hierarchy'), '.isAncestorsCollapsed').should.be.true;
|
|
609
|
+
matchesSelector($laolao, '.slide-down.hidden').should.be.true;
|
|
610
|
+
matchesSelector($sumiao, '.sliding').should.be.true;
|
|
611
|
+
matchesSelector($sumiao, '.slide-down').should.be.false;
|
|
266
612
|
});
|
|
267
613
|
|
|
268
614
|
it('showParentEnd()', function () {
|
|
269
|
-
|
|
270
|
-
|
|
271
|
-
|
|
272
|
-
|
|
273
|
-
$sumiao
|
|
615
|
+
const spy = sinon.spy(oc, 'showParentEnd');
|
|
616
|
+
const spy2 = sinon.spy(oc, 'isInAction');
|
|
617
|
+
const spy3 = sinon.spy(oc, 'switchVerticalArrow');
|
|
618
|
+
|
|
619
|
+
addClasses($sumiao, 'sliding');
|
|
620
|
+
removeClasses($sumiao, 'slide-down');
|
|
621
|
+
setOneTimeListener($sumiao, 'transitionend', null, function (event) {
|
|
622
|
+
event.node = $heihei;
|
|
623
|
+
spy.call(oc, event);
|
|
624
|
+
});
|
|
625
|
+
triggerEvent($sumiao, 'transitionend');
|
|
274
626
|
spy.should.have.been.called;
|
|
275
|
-
$sumiao
|
|
627
|
+
matchesSelector($sumiao, '.sliding').should.be.false;
|
|
276
628
|
spy2.should.have.been.calledWith($heihei);
|
|
277
629
|
spy3.should.not.have.been.called;
|
|
278
630
|
});
|
|
279
631
|
|
|
632
|
+
it('showParentEnd() accepts native animated and node payloads', function () {
|
|
633
|
+
addClasses($sumiao, 'sliding');
|
|
634
|
+
|
|
635
|
+
oc.showParentEnd({
|
|
636
|
+
animatedNode: $sumiao,
|
|
637
|
+
node: $heihei
|
|
638
|
+
});
|
|
639
|
+
|
|
640
|
+
$sumiao.classList.contains('sliding').should.equal(false);
|
|
641
|
+
});
|
|
642
|
+
|
|
643
|
+
it('showParentEnd() accepts wrapped native animated and node payloads', function () {
|
|
644
|
+
addClasses($sumiao, 'sliding');
|
|
645
|
+
|
|
646
|
+
oc.showParentEnd({
|
|
647
|
+
originalEvent: {
|
|
648
|
+
target: $sumiao,
|
|
649
|
+
node: $heihei
|
|
650
|
+
}
|
|
651
|
+
});
|
|
652
|
+
|
|
653
|
+
$sumiao.classList.contains('sliding').should.equal(false);
|
|
654
|
+
});
|
|
655
|
+
|
|
280
656
|
it('hideChildren()', function () {
|
|
281
|
-
|
|
657
|
+
const spy = sinon.spy(oc, 'repaint');
|
|
658
|
+
|
|
282
659
|
oc.hideChildren($sumiao);
|
|
660
|
+
|
|
283
661
|
spy.should.have.been.called;
|
|
284
|
-
$sumiao
|
|
285
|
-
$sumiao
|
|
286
|
-
$tiehua
|
|
287
|
-
$heihei
|
|
288
|
-
$pangpang
|
|
289
|
-
$erdan
|
|
662
|
+
matchesSelector(closestElement($sumiao, '.hierarchy'), '.isChildrenCollapsed').should.be.true;
|
|
663
|
+
childElements(firstSibling($sumiao, '.nodes'), '.isCollapsedDescendant').should.lengthOf(3);
|
|
664
|
+
matchesSelector($tiehua, '.sliding.slide-up').should.be.true;
|
|
665
|
+
matchesSelector($heihei, '.sliding.slide-up').should.be.true;
|
|
666
|
+
matchesSelector($pangpang, '.sliding.slide-up').should.be.true;
|
|
667
|
+
matchesSelector($erdan, '.sliding.slide-up').should.be.true;
|
|
290
668
|
});
|
|
291
669
|
|
|
292
670
|
it('hideChildrenEnd()', function () {
|
|
293
|
-
|
|
294
|
-
|
|
295
|
-
|
|
296
|
-
$tiehua
|
|
297
|
-
$tiehua
|
|
298
|
-
|
|
299
|
-
$tiehua.
|
|
300
|
-
$tiehua.closest('.nodes').is('.hidden').should.be.true;
|
|
671
|
+
const spy2 = sinon.spy(oc, 'isInAction');
|
|
672
|
+
const spy3 = sinon.spy(oc, 'switchVerticalArrow');
|
|
673
|
+
|
|
674
|
+
addClasses($tiehua, 'sliding slide-up');
|
|
675
|
+
oc.hideChildrenEnd({ animatedNodes: $tiehua, node: $sumiao });
|
|
676
|
+
matchesSelector($tiehua, '.sliding').should.be.false;
|
|
677
|
+
matchesSelector(closestElement($tiehua, '.nodes'), '.hidden').should.be.true;
|
|
301
678
|
spy2.should.have.been.calledWith($sumiao);
|
|
302
679
|
spy3.should.not.have.been.called;
|
|
303
680
|
});
|
|
304
681
|
|
|
682
|
+
it('hideChildrenEnd() accepts direct animated and node payloads', function () {
|
|
683
|
+
$sumiao.dispatchEvent(new window.MouseEvent('mouseenter'));
|
|
684
|
+
const bottomEdgeEl = query('.bottomEdge', $sumiao);
|
|
685
|
+
const verticalSpy = sinon.spy(oc, 'switchVerticalArrow');
|
|
686
|
+
|
|
687
|
+
removeClasses($tiehua, 'hidden');
|
|
688
|
+
addClasses($tiehua, 'sliding');
|
|
689
|
+
removeClasses(closestElement($tiehua, '.nodes'), 'hidden');
|
|
690
|
+
bottomEdgeEl.classList.add(oc.options.icons.collapseToDown);
|
|
691
|
+
|
|
692
|
+
oc.hideChildrenEnd({ animatedNodes: [$tiehua], node: $sumiao });
|
|
693
|
+
|
|
694
|
+
$tiehua.classList.contains('sliding').should.equal(false);
|
|
695
|
+
closestElement($tiehua, '.nodes').classList.contains('hidden').should.equal(true);
|
|
696
|
+
verticalSpy.should.have.been.calledWith(bottomEdgeEl);
|
|
697
|
+
|
|
698
|
+
verticalSpy.restore();
|
|
699
|
+
});
|
|
700
|
+
|
|
701
|
+
it('hideChildrenEnd() accepts wrapped native animated and node payloads', function () {
|
|
702
|
+
$sumiao.dispatchEvent(new window.MouseEvent('mouseenter'));
|
|
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
|
+
$heihei.dispatchEvent(new window.MouseEvent('mouseenter'));
|
|
781
|
+
const topEdgeEl = query('.topEdge', $heihei);
|
|
782
|
+
const switchSpy = sinon.spy(oc, 'switchHorizontalArrow');
|
|
783
|
+
|
|
784
|
+
addClasses($tiehua, 'sliding');
|
|
785
|
+
addClasses($pangpang, 'sliding');
|
|
786
|
+
topEdgeEl.classList.add(oc.options.icons.expandToUp);
|
|
787
|
+
|
|
788
|
+
oc.showSiblingsEnd({
|
|
789
|
+
node: $heihei,
|
|
790
|
+
visibleNodes: [$tiehua, $pangpang]
|
|
791
|
+
});
|
|
792
|
+
|
|
793
|
+
$tiehua.classList.contains('sliding').should.equal(false);
|
|
794
|
+
$pangpang.classList.contains('sliding').should.equal(false);
|
|
795
|
+
switchSpy.should.have.been.calledWith($heihei);
|
|
796
|
+
topEdgeEl.classList.contains(oc.options.icons.expandToUp).should.equal(false);
|
|
797
|
+
topEdgeEl.classList.contains(oc.options.icons.collapseToDown).should.equal(true);
|
|
798
|
+
|
|
799
|
+
switchSpy.restore();
|
|
800
|
+
});
|
|
801
|
+
|
|
802
|
+
it('showSiblingsEnd() accepts wrapped native visible and node payloads', function () {
|
|
803
|
+
$heihei.dispatchEvent(new window.MouseEvent('mouseenter'));
|
|
804
|
+
const topEdgeEl = query('.topEdge', $heihei);
|
|
805
|
+
const switchSpy = sinon.spy(oc, 'switchHorizontalArrow');
|
|
806
|
+
|
|
807
|
+
addClasses($tiehua, 'sliding');
|
|
808
|
+
addClasses($pangpang, 'sliding');
|
|
809
|
+
topEdgeEl.classList.add(oc.options.icons.expandToUp);
|
|
810
|
+
|
|
811
|
+
oc.showSiblingsEnd({
|
|
812
|
+
originalEvent: {
|
|
813
|
+
node: $heihei,
|
|
814
|
+
visibleNodes: [$tiehua, $pangpang]
|
|
815
|
+
}
|
|
816
|
+
});
|
|
817
|
+
|
|
818
|
+
$tiehua.classList.contains('sliding').should.equal(false);
|
|
819
|
+
$pangpang.classList.contains('sliding').should.equal(false);
|
|
820
|
+
switchSpy.should.have.been.calledWith($heihei);
|
|
821
|
+
topEdgeEl.classList.contains(oc.options.icons.expandToUp).should.equal(false);
|
|
822
|
+
topEdgeEl.classList.contains(oc.options.icons.collapseToDown).should.equal(true);
|
|
823
|
+
|
|
824
|
+
switchSpy.restore();
|
|
825
|
+
});
|
|
826
|
+
|
|
827
|
+
it('showRelatedParentEnd() removes sliding from a native animated node payload', function () {
|
|
828
|
+
addClasses($sumiao, 'sliding');
|
|
829
|
+
|
|
830
|
+
oc.showRelatedParentEnd({ animatedNode: $sumiao });
|
|
831
|
+
|
|
832
|
+
$sumiao.classList.contains('sliding').should.equal(false);
|
|
833
|
+
});
|
|
834
|
+
|
|
835
|
+
it('showRelatedParentEnd() accepts a wrapped native animated node payload', function () {
|
|
836
|
+
addClasses($sumiao, 'sliding');
|
|
837
|
+
|
|
838
|
+
oc.showRelatedParentEnd({
|
|
839
|
+
originalEvent: {
|
|
840
|
+
target: $sumiao
|
|
841
|
+
}
|
|
842
|
+
});
|
|
843
|
+
|
|
844
|
+
$sumiao.classList.contains('sliding').should.equal(false);
|
|
845
|
+
});
|
|
846
|
+
|
|
847
|
+
it('showSiblings() accepts a native node and reveals the requested side with animation', function () {
|
|
848
|
+
const repaintSpy = sinon.spy(oc, 'repaint');
|
|
849
|
+
|
|
850
|
+
addClasses(closestElement($tiehua, '.hierarchy'), 'hidden isCollapsedSibling left-sibs');
|
|
851
|
+
addClasses($tiehua, 'slide-right');
|
|
852
|
+
addClasses(closestElement($heihei, '.hierarchy'), 'isSiblingsCollapsed left-sibs isAncestorsCollapsed');
|
|
853
|
+
addClasses($sumiao, 'hidden slide-down');
|
|
854
|
+
|
|
855
|
+
oc.showSiblings($heihei, 'left');
|
|
856
|
+
|
|
857
|
+
repaintSpy.should.have.been.calledWith($sumiao);
|
|
858
|
+
closestElement($tiehua, '.hierarchy').classList.contains('hidden').should.equal(false);
|
|
859
|
+
closestElement($tiehua, '.hierarchy').classList.contains('isCollapsedSibling').should.equal(false);
|
|
860
|
+
closestElement($heihei, '.hierarchy').classList.contains('left-sibs').should.equal(false);
|
|
861
|
+
closestElement($heihei, '.hierarchy').classList.contains('isSiblingsCollapsed').should.equal(false);
|
|
862
|
+
$tiehua.classList.contains('sliding').should.equal(true);
|
|
863
|
+
$tiehua.classList.contains('slide-right').should.equal(false);
|
|
864
|
+
$sumiao.classList.contains('hidden').should.equal(false);
|
|
865
|
+
$sumiao.classList.contains('sliding').should.equal(true);
|
|
866
|
+
$sumiao.classList.contains('slide-down').should.equal(false);
|
|
867
|
+
|
|
868
|
+
repaintSpy.restore();
|
|
869
|
+
});
|
|
870
|
+
|
|
329
871
|
describe('hideSiblings()', function () {
|
|
330
872
|
context('when passing only one parameter -- node', function () {
|
|
331
873
|
it('should hide all the sibling nodes and their descendants', function () {
|
|
332
874
|
oc.hideSiblings($heihei);
|
|
333
|
-
$tiehua
|
|
334
|
-
$dandan
|
|
335
|
-
$pangpang
|
|
336
|
-
$sandan
|
|
337
|
-
$heihei
|
|
338
|
-
$heihei
|
|
875
|
+
matchesSelector($tiehua, '.sliding.slide-right').should.be.true;
|
|
876
|
+
matchesSelector($dandan, '.sliding.slide-right').should.be.true;
|
|
877
|
+
matchesSelector($pangpang, '.sliding.slide-left').should.be.true;
|
|
878
|
+
matchesSelector($sandan, '.sliding.slide-left').should.be.true;
|
|
879
|
+
matchesSelector(closestElement($heihei, '.hierarchy'), '.isSiblingsCollapsed').should.be.true;
|
|
880
|
+
siblingElements(closestElement($heihei, '.hierarchy'), '.isChildrenCollapsed.isCollapsedSibling').should.lengthOf(2);
|
|
881
|
+
});
|
|
882
|
+
|
|
883
|
+
it('clears inAjax when a sibling hierarchy contains a spinner', function () {
|
|
884
|
+
const spinnerEl = document.createElement('i');
|
|
885
|
+
|
|
886
|
+
spinnerEl.className = 'spinner';
|
|
887
|
+
closestElement($tiehua, '.hierarchy').appendChild(spinnerEl);
|
|
888
|
+
setState(oc.chart, 'inAjax', true);
|
|
889
|
+
|
|
890
|
+
oc.hideSiblings($heihei);
|
|
891
|
+
|
|
892
|
+
getState(oc.chart, 'inAjax').should.be.false;
|
|
893
|
+
spinnerEl.remove();
|
|
339
894
|
});
|
|
340
895
|
});
|
|
341
896
|
|
|
342
897
|
context('when passing two parameters -- node and direction', function () {
|
|
343
898
|
it('hide the left side sibling nodes and their descendants', function () {
|
|
344
899
|
oc.hideSiblings($heihei, 'left');
|
|
345
|
-
$heihei
|
|
346
|
-
$heihei
|
|
347
|
-
$heihei
|
|
348
|
-
$tiehua
|
|
349
|
-
$dandan
|
|
350
|
-
$pangpang
|
|
900
|
+
matchesSelector(closestElement($heihei, '.hierarchy'), '.isSiblingsCollapsed.left-sibs').should.be.true;
|
|
901
|
+
matchesSelector(closestElement($heihei, '.hierarchy').previousElementSibling, '.isChildrenCollapsed.isCollapsedSibling').should.be.true;
|
|
902
|
+
matchesSelector(closestElement($heihei, '.hierarchy').nextElementSibling, '.isChildrenCollapsed, .isCollapsedSibling').should.be.false;
|
|
903
|
+
matchesSelector($tiehua, '.sliding.slide-right').should.be.true;
|
|
904
|
+
matchesSelector($dandan, '.sliding.slide-right').should.be.true;
|
|
905
|
+
matchesSelector($pangpang, '.sliding').should.be.false;
|
|
351
906
|
});
|
|
352
907
|
it('hide the right side sibling nodes and their descendants', function () {
|
|
353
908
|
oc.hideSiblings($heihei, 'right');
|
|
354
|
-
$heihei
|
|
355
|
-
$heihei
|
|
356
|
-
$heihei
|
|
357
|
-
$pangpang
|
|
358
|
-
$sandan
|
|
359
|
-
$tiehua
|
|
909
|
+
matchesSelector(closestElement($heihei, '.hierarchy'), '.isSiblingsCollapsed.right-sibs').should.be.true;
|
|
910
|
+
matchesSelector(closestElement($heihei, '.hierarchy').nextElementSibling, '.isChildrenCollapsed.isCollapsedSibling').should.be.true;
|
|
911
|
+
matchesSelector(closestElement($heihei, '.hierarchy').previousElementSibling, '.isChildrenCollapsed, .isCollapsedSibling').should.be.false;
|
|
912
|
+
matchesSelector($pangpang, '.sliding.slide-left').should.be.true;
|
|
913
|
+
matchesSelector($sandan, '.sliding.slide-left').should.be.true;
|
|
914
|
+
matchesSelector($tiehua, '.sliding').should.be.false;
|
|
360
915
|
});
|
|
361
916
|
});
|
|
362
917
|
});
|
|
@@ -364,25 +919,29 @@ describe('orgchart -- unit tests', function () {
|
|
|
364
919
|
describe('hideSiblingsEnd()', function () {
|
|
365
920
|
context('when invoking transitionend event without specifying direction', function () {
|
|
366
921
|
it('clean up final classList for hidden siblings', function () {
|
|
367
|
-
|
|
368
|
-
|
|
369
|
-
|
|
370
|
-
|
|
922
|
+
const spy = sinon.spy(oc, 'hideSiblingsEnd');
|
|
923
|
+
const spy2 = sinon.spy(oc, 'isInAction');
|
|
924
|
+
const spy3 = sinon.spy(oc, 'switchVerticalArrow');
|
|
925
|
+
const nodeContainerEl = closestElement($heihei, '.hierarchy');
|
|
926
|
+
|
|
371
927
|
oc.hideSiblings($heihei);
|
|
372
|
-
|
|
928
|
+
|
|
929
|
+
setOneTimeListener($tiehua, 'transitionend', {
|
|
373
930
|
'node': $heihei,
|
|
374
|
-
'nodeContainer':
|
|
931
|
+
'nodeContainer': nodeContainerEl,
|
|
375
932
|
'direction': undefined,
|
|
376
933
|
'animatedNodes': $tiehua
|
|
377
934
|
}, spy.bind(oc));
|
|
378
|
-
$tiehua
|
|
935
|
+
triggerEvent($tiehua, 'transitionend');
|
|
379
936
|
spy.should.have.been.called;
|
|
380
|
-
$tiehua
|
|
381
|
-
$dandan
|
|
382
|
-
$pangpang
|
|
383
|
-
$sandan
|
|
384
|
-
|
|
385
|
-
|
|
937
|
+
matchesSelector($tiehua, '.slide-right:not(.sliding)').should.be.true;
|
|
938
|
+
matchesSelector($dandan, '.slide-up:not(.sliding, .slide-right)').should.be.true;
|
|
939
|
+
matchesSelector($pangpang, '.slide-left:not(.sibling)').should.be.true;
|
|
940
|
+
matchesSelector($sandan, '.slide-up:not(.sliding, .slide-left)').should.be.true;
|
|
941
|
+
siblingElements(nodeContainerEl, '.hidden').should.lengthOf(2);
|
|
942
|
+
siblingElements(nodeContainerEl).reduce(function (count, siblingEl) {
|
|
943
|
+
return count + queryAll('.nodes.hidden', siblingEl).length;
|
|
944
|
+
}, 0).should.equal(2);
|
|
386
945
|
spy2.should.have.been.calledWith($heihei);
|
|
387
946
|
spy3.should.not.have.been.called;
|
|
388
947
|
});
|
|
@@ -390,55 +949,1615 @@ describe('orgchart -- unit tests', function () {
|
|
|
390
949
|
|
|
391
950
|
context('when invoking transitionend event with specifying direction', function () {
|
|
392
951
|
it('clean up final classList for left side hidden siblings', function () {
|
|
393
|
-
|
|
394
|
-
|
|
395
|
-
|
|
396
|
-
|
|
952
|
+
const spy = sinon.spy(oc, 'hideSiblingsEnd');
|
|
953
|
+
const spy2 = sinon.spy(oc, 'isInAction');
|
|
954
|
+
const spy3 = sinon.spy(oc, 'switchVerticalArrow');
|
|
955
|
+
const nodeContainerEl = closestElement($heihei, '.hierarchy');
|
|
956
|
+
|
|
397
957
|
oc.hideSiblings($heihei, 'left');
|
|
398
|
-
|
|
958
|
+
|
|
959
|
+
setOneTimeListener($tiehua, 'transitionend', {
|
|
399
960
|
'node': $heihei,
|
|
400
|
-
'nodeContainer':
|
|
961
|
+
'nodeContainer': nodeContainerEl,
|
|
401
962
|
'direction': 'left',
|
|
402
963
|
'animatedNodes': $tiehua
|
|
403
964
|
}, spy.bind(oc));
|
|
404
|
-
$tiehua
|
|
965
|
+
triggerEvent($tiehua, 'transitionend');
|
|
405
966
|
spy.should.have.been.called;
|
|
406
|
-
$tiehua
|
|
407
|
-
$dandan
|
|
408
|
-
$pangpang
|
|
409
|
-
$sandan
|
|
410
|
-
|
|
411
|
-
|
|
412
|
-
|
|
967
|
+
matchesSelector($tiehua, '.slide-right:not(.sliding)').should.be.true;
|
|
968
|
+
matchesSelector($dandan, '.slide-up:not(.slide-right)').should.be.true;
|
|
969
|
+
matchesSelector($pangpang, '.slide-left').should.be.false;
|
|
970
|
+
matchesSelector($sandan, '.slide-up').should.be.false;
|
|
971
|
+
previousSiblings(nodeContainerEl, '.hidden').should.lengthOf(1);
|
|
972
|
+
previousSiblings(nodeContainerEl).reduce(function (count, siblingEl) {
|
|
973
|
+
return count + queryAll('.nodes.hidden', siblingEl).length;
|
|
974
|
+
}, 0).should.equal(1);
|
|
975
|
+
nextSiblings(nodeContainerEl).reduce(function (count, siblingEl) {
|
|
976
|
+
return count + queryAll('.nodes.hidden', siblingEl).length;
|
|
977
|
+
}, 0).should.equal(0);
|
|
413
978
|
spy2.should.have.been.calledWith($heihei);
|
|
414
979
|
spy3.should.not.have.been.called;
|
|
415
980
|
});
|
|
416
981
|
|
|
417
982
|
it('clean up final classList for right side hidden siblings', function () {
|
|
418
|
-
|
|
419
|
-
|
|
420
|
-
|
|
421
|
-
|
|
983
|
+
const spy2 = sinon.spy(oc, 'isInAction');
|
|
984
|
+
const spy3 = sinon.spy(oc, 'switchVerticalArrow');
|
|
985
|
+
const nodeContainerEl = closestElement($heihei, '.hierarchy');
|
|
986
|
+
|
|
422
987
|
oc.hideSiblings($heihei, 'right');
|
|
423
|
-
|
|
424
|
-
|
|
425
|
-
|
|
426
|
-
|
|
427
|
-
'
|
|
428
|
-
|
|
429
|
-
|
|
430
|
-
|
|
431
|
-
$
|
|
432
|
-
$
|
|
433
|
-
$
|
|
434
|
-
|
|
435
|
-
|
|
436
|
-
|
|
437
|
-
|
|
988
|
+
|
|
989
|
+
oc.hideSiblingsEnd({
|
|
990
|
+
node: $heihei,
|
|
991
|
+
nodeContainer: nodeContainerEl,
|
|
992
|
+
direction: 'right',
|
|
993
|
+
animatedNodes: $tiehua
|
|
994
|
+
});
|
|
995
|
+
matchesSelector($tiehua, '.slide-right').should.be.false;
|
|
996
|
+
matchesSelector($dandan, '.slide-up').should.be.false;
|
|
997
|
+
matchesSelector($pangpang, '.slide-left:not(.slidiing)').should.be.true;
|
|
998
|
+
matchesSelector($sandan, '.slide-up:not(.slide-left)').should.be.true;
|
|
999
|
+
nextSiblings(nodeContainerEl, '.hidden').should.lengthOf(1);
|
|
1000
|
+
nextSiblings(nodeContainerEl).reduce(function (count, siblingEl) {
|
|
1001
|
+
return count + queryAll('.nodes.hidden', siblingEl).length;
|
|
1002
|
+
}, 0).should.equal(1);
|
|
1003
|
+
previousSiblings(nodeContainerEl).reduce(function (count, siblingEl) {
|
|
1004
|
+
return count + queryAll('.nodes.hidden', siblingEl).length;
|
|
1005
|
+
}, 0).should.equal(0);
|
|
438
1006
|
spy2.should.have.been.calledWith($heihei);
|
|
439
1007
|
spy3.should.not.have.been.called;
|
|
440
1008
|
});
|
|
1009
|
+
|
|
1010
|
+
it('accepts direct node, container, and animated payloads', function () {
|
|
1011
|
+
$heihei.dispatchEvent(new window.MouseEvent('mouseenter'));
|
|
1012
|
+
const horizontalSpy = sinon.spy(oc, 'switchHorizontalArrow');
|
|
1013
|
+
const nodeContainerEl = closestElement($heihei, '.hierarchy');
|
|
1014
|
+
|
|
1015
|
+
oc.hideSiblings($heihei, 'left');
|
|
1016
|
+
addClasses($tiehua, 'sliding');
|
|
1017
|
+
removeClasses(closestElement($tiehua, '.nodes'), 'hidden');
|
|
1018
|
+
query('.leftEdge', $heihei).classList.add(oc.options.icons.collapseToLeft);
|
|
1019
|
+
|
|
1020
|
+
oc.hideSiblingsEnd({
|
|
1021
|
+
node: $heihei,
|
|
1022
|
+
nodeContainer: nodeContainerEl,
|
|
1023
|
+
direction: 'left',
|
|
1024
|
+
animatedNodes: [$tiehua]
|
|
1025
|
+
});
|
|
1026
|
+
|
|
1027
|
+
$tiehua.classList.contains('sliding').should.equal(false);
|
|
1028
|
+
nodeContainerEl.previousElementSibling.classList.contains('hidden').should.equal(true);
|
|
1029
|
+
horizontalSpy.should.have.been.calledWith($heihei);
|
|
1030
|
+
|
|
1031
|
+
horizontalSpy.restore();
|
|
1032
|
+
});
|
|
1033
|
+
|
|
1034
|
+
it('accepts wrapped native node, container, and animated payloads', function () {
|
|
1035
|
+
$heihei.dispatchEvent(new window.MouseEvent('mouseenter'));
|
|
1036
|
+
const horizontalSpy = sinon.spy(oc, 'switchHorizontalArrow');
|
|
1037
|
+
const nodeContainerEl = closestElement($heihei, '.hierarchy');
|
|
1038
|
+
|
|
1039
|
+
oc.hideSiblings($heihei, 'left');
|
|
1040
|
+
addClasses($tiehua, 'sliding');
|
|
1041
|
+
removeClasses(closestElement($tiehua, '.nodes'), 'hidden');
|
|
1042
|
+
query('.leftEdge', $heihei).classList.add(oc.options.icons.collapseToLeft);
|
|
1043
|
+
|
|
1044
|
+
oc.hideSiblingsEnd({
|
|
1045
|
+
originalEvent: {
|
|
1046
|
+
node: $heihei,
|
|
1047
|
+
nodeContainer: nodeContainerEl,
|
|
1048
|
+
direction: 'left',
|
|
1049
|
+
animatedNodes: [$tiehua]
|
|
1050
|
+
}
|
|
1051
|
+
});
|
|
1052
|
+
|
|
1053
|
+
$tiehua.classList.contains('sliding').should.equal(false);
|
|
1054
|
+
nodeContainerEl.previousElementSibling.classList.contains('hidden').should.equal(true);
|
|
1055
|
+
horizontalSpy.should.have.been.calledWith($heihei);
|
|
1056
|
+
|
|
1057
|
+
horizontalSpy.restore();
|
|
1058
|
+
});
|
|
441
1059
|
});
|
|
442
1060
|
});
|
|
443
1061
|
|
|
444
|
-
|
|
1062
|
+
it('nodeEnterLeaveHandler() accepts a native node payload for relationship checks', function () {
|
|
1063
|
+
const spy = sinon.spy(oc, 'switchHorizontalArrow');
|
|
1064
|
+
oc.nodeEnterLeaveHandler({ type: 'mouseenter', node: $sumiao });
|
|
1065
|
+
spy.should.have.been.calledWith($sumiao);
|
|
1066
|
+
});
|
|
1067
|
+
|
|
1068
|
+
it('nodeEnterLeaveHandler() removes controls from a native node payload on mouseleave', function () {
|
|
1069
|
+
const nodeEl = $sumiao;
|
|
1070
|
+
|
|
1071
|
+
nodeEl.dispatchEvent(new window.MouseEvent('mouseenter'));
|
|
1072
|
+
nodeEl.querySelectorAll('.edge').length.should.equal(4);
|
|
1073
|
+
|
|
1074
|
+
oc.nodeEnterLeaveHandler({ type: 'mouseleave', node: nodeEl });
|
|
1075
|
+
|
|
1076
|
+
nodeEl.querySelectorAll('.edge').length.should.equal(0);
|
|
1077
|
+
});
|
|
1078
|
+
|
|
1079
|
+
it('nodeEnterLeaveHandler() accepts wrapped native node payloads', function () {
|
|
1080
|
+
const spy = sinon.spy(oc, 'switchHorizontalArrow');
|
|
1081
|
+
|
|
1082
|
+
oc.nodeEnterLeaveHandler({
|
|
1083
|
+
originalEvent: {
|
|
1084
|
+
type: 'mouseenter',
|
|
1085
|
+
currentTarget: $sumiao
|
|
1086
|
+
}
|
|
1087
|
+
});
|
|
1088
|
+
|
|
1089
|
+
spy.should.have.been.calledWith($sumiao);
|
|
1090
|
+
spy.restore();
|
|
1091
|
+
});
|
|
1092
|
+
|
|
1093
|
+
it('HideFirstParentEnd() accepts a native top edge payload', function () {
|
|
1094
|
+
$heihei.dispatchEvent(new window.MouseEvent('mouseenter'));
|
|
1095
|
+
const topEdgeEl = query('.topEdge', $heihei);
|
|
1096
|
+
const verticalSpy = sinon.spy(oc, 'switchVerticalArrow');
|
|
1097
|
+
const horizontalSpy = sinon.spy(oc, 'switchHorizontalArrow');
|
|
1098
|
+
|
|
1099
|
+
topEdgeEl.classList.add(oc.options.icons.expandToUp);
|
|
1100
|
+
oc.HideFirstParentEnd({ topEdge: topEdgeEl });
|
|
1101
|
+
|
|
1102
|
+
verticalSpy.should.have.been.calledWith(topEdgeEl);
|
|
1103
|
+
horizontalSpy.should.have.been.calledWith($heihei);
|
|
1104
|
+
|
|
1105
|
+
verticalSpy.restore();
|
|
1106
|
+
horizontalSpy.restore();
|
|
1107
|
+
});
|
|
1108
|
+
|
|
1109
|
+
it('HideFirstParentEnd() accepts a wrapped native top edge payload', function () {
|
|
1110
|
+
$heihei.dispatchEvent(new window.MouseEvent('mouseenter'));
|
|
1111
|
+
const topEdgeEl = query('.topEdge', $heihei);
|
|
1112
|
+
const verticalSpy = sinon.spy(oc, 'switchVerticalArrow');
|
|
1113
|
+
const horizontalSpy = sinon.spy(oc, 'switchHorizontalArrow');
|
|
1114
|
+
|
|
1115
|
+
topEdgeEl.classList.add(oc.options.icons.expandToUp);
|
|
1116
|
+
oc.HideFirstParentEnd({
|
|
1117
|
+
originalEvent: {
|
|
1118
|
+
topEdge: topEdgeEl
|
|
1119
|
+
}
|
|
1120
|
+
});
|
|
1121
|
+
|
|
1122
|
+
verticalSpy.should.have.been.calledWith(topEdgeEl);
|
|
1123
|
+
horizontalSpy.should.have.been.calledWith($heihei);
|
|
1124
|
+
|
|
1125
|
+
verticalSpy.restore();
|
|
1126
|
+
horizontalSpy.restore();
|
|
1127
|
+
});
|
|
1128
|
+
|
|
1129
|
+
it('nodeClickHandler() focuses the native node payload and clears previous focus', function () {
|
|
1130
|
+
addClasses($bomiao, 'focused');
|
|
1131
|
+
|
|
1132
|
+
oc.nodeClickHandler({ node: $sumiao });
|
|
1133
|
+
|
|
1134
|
+
$bomiao.classList.contains('focused').should.equal(false);
|
|
1135
|
+
$sumiao.classList.contains('focused').should.equal(true);
|
|
1136
|
+
});
|
|
1137
|
+
|
|
1138
|
+
it('nodeClickHandler() focuses a wrapped native node payload', function () {
|
|
1139
|
+
addClasses($bomiao, 'focused');
|
|
1140
|
+
|
|
1141
|
+
oc.nodeClickHandler({
|
|
1142
|
+
originalEvent: {
|
|
1143
|
+
currentTarget: $sumiao
|
|
1144
|
+
}
|
|
1145
|
+
});
|
|
1146
|
+
|
|
1147
|
+
$bomiao.classList.contains('focused').should.equal(false);
|
|
1148
|
+
$sumiao.classList.contains('focused').should.equal(true);
|
|
1149
|
+
});
|
|
1150
|
+
|
|
1151
|
+
it('init() clears focused nodes when clicking the chart background', function () {
|
|
1152
|
+
addClasses($bomiao, 'focused');
|
|
1153
|
+
addClasses($sumiao, 'focused');
|
|
1154
|
+
|
|
1155
|
+
oc.chart.dispatchEvent(new window.MouseEvent('click', { bubbles: true }));
|
|
1156
|
+
|
|
1157
|
+
$bomiao.classList.contains('focused').should.equal(false);
|
|
1158
|
+
$sumiao.classList.contains('focused').should.equal(false);
|
|
1159
|
+
});
|
|
1160
|
+
|
|
1161
|
+
it('init() clears focused nodes from a wrapped native background click payload', function () {
|
|
1162
|
+
const wrappedClickEvent = new window.Event('click', { bubbles: true });
|
|
1163
|
+
|
|
1164
|
+
addClasses($bomiao, 'focused');
|
|
1165
|
+
addClasses($sumiao, 'focused');
|
|
1166
|
+
|
|
1167
|
+
wrappedClickEvent.originalEvent = {
|
|
1168
|
+
target: oc.chart
|
|
1169
|
+
};
|
|
1170
|
+
oc.chart.dispatchEvent(wrappedClickEvent);
|
|
1171
|
+
|
|
1172
|
+
$bomiao.classList.contains('focused').should.equal(false);
|
|
1173
|
+
$sumiao.classList.contains('focused').should.equal(false);
|
|
1174
|
+
});
|
|
1175
|
+
|
|
1176
|
+
it('init() appends the export button only once', function () {
|
|
1177
|
+
let oc2;
|
|
1178
|
+
|
|
1179
|
+
Array.from(document.querySelectorAll('.oc-export-btn')).forEach(function (exportButtonEl) {
|
|
1180
|
+
exportButtonEl.remove();
|
|
1181
|
+
});
|
|
1182
|
+
|
|
1183
|
+
oc2 = new OrgChart({
|
|
1184
|
+
chartContainer: '#chart-container',
|
|
1185
|
+
data: ds,
|
|
1186
|
+
exportButton: true
|
|
1187
|
+
});
|
|
1188
|
+
|
|
1189
|
+
document.querySelectorAll('.oc-export-btn').length.should.equal(1);
|
|
1190
|
+
|
|
1191
|
+
oc2.init();
|
|
1192
|
+
|
|
1193
|
+
document.querySelectorAll('.oc-export-btn').length.should.equal(1);
|
|
1194
|
+
Array.from(document.querySelectorAll('.oc-export-btn')).forEach(function (exportButtonEl) {
|
|
1195
|
+
exportButtonEl.remove();
|
|
1196
|
+
});
|
|
1197
|
+
});
|
|
1198
|
+
|
|
1199
|
+
it('attachExportButton() creates a native export button that calls export()', function () {
|
|
1200
|
+
const exportStub = sinon.stub(oc, 'export');
|
|
1201
|
+
|
|
1202
|
+
Array.from(document.querySelectorAll('.oc-export-btn')).forEach(function (exportButtonEl) {
|
|
1203
|
+
exportButtonEl.remove();
|
|
1204
|
+
});
|
|
1205
|
+
|
|
1206
|
+
oc.attachExportButton();
|
|
1207
|
+
document.querySelectorAll('.oc-export-btn').length.should.equal(1);
|
|
1208
|
+
document.querySelector('.oc-export-btn').dispatchEvent(new window.MouseEvent('click', { bubbles: true }));
|
|
1209
|
+
exportStub.should.have.been.calledOnce;
|
|
1210
|
+
|
|
1211
|
+
exportStub.restore();
|
|
1212
|
+
Array.from(document.querySelectorAll('.oc-export-btn')).forEach(function (exportButtonEl) {
|
|
1213
|
+
exportButtonEl.remove();
|
|
1214
|
+
});
|
|
1215
|
+
});
|
|
1216
|
+
|
|
1217
|
+
it('topEdgeClickHandler() passes a native node to hideParent()', function () {
|
|
1218
|
+
const spy = sinon.spy(oc, 'hideParent');
|
|
1219
|
+
const spy2 = sinon.spy(oc, 'triggerHideEvent');
|
|
1220
|
+
|
|
1221
|
+
oc.topEdgeClickHandler({ edge: query('.topEdge', $heihei), node: $heihei });
|
|
1222
|
+
|
|
1223
|
+
spy.should.have.been.calledWith($heihei);
|
|
1224
|
+
spy2.should.have.been.called;
|
|
1225
|
+
});
|
|
1226
|
+
|
|
1227
|
+
it('topEdgeClickHandler() accepts wrapped native edge payloads', function () {
|
|
1228
|
+
const spy = sinon.spy(oc, 'hideParent');
|
|
1229
|
+
|
|
1230
|
+
oc.topEdgeClickHandler({
|
|
1231
|
+
originalEvent: {
|
|
1232
|
+
currentTarget: $heihei,
|
|
1233
|
+
target: query('.topEdge', $heihei)
|
|
1234
|
+
}
|
|
1235
|
+
});
|
|
1236
|
+
|
|
1237
|
+
spy.should.have.been.calledWith($heihei);
|
|
1238
|
+
spy.restore();
|
|
1239
|
+
});
|
|
1240
|
+
|
|
1241
|
+
it('bottomEdgeClickHandler() passes a native node to hideChildren()', function () {
|
|
1242
|
+
const spy = sinon.spy(oc, 'hideChildren');
|
|
1243
|
+
const spy2 = sinon.spy(oc, 'triggerHideEvent');
|
|
1244
|
+
|
|
1245
|
+
oc.bottomEdgeClickHandler({ edge: query('.bottomEdge', $sumiao), node: $sumiao });
|
|
1246
|
+
|
|
1247
|
+
spy.should.have.been.calledWith($sumiao);
|
|
1248
|
+
spy2.should.have.been.called;
|
|
1249
|
+
});
|
|
1250
|
+
|
|
1251
|
+
it('bottomEdgeClickHandler() accepts wrapped native node payloads', function () {
|
|
1252
|
+
const spy = sinon.spy(oc, 'hideChildren');
|
|
1253
|
+
|
|
1254
|
+
oc.bottomEdgeClickHandler({
|
|
1255
|
+
originalEvent: {
|
|
1256
|
+
currentTarget: $sumiao
|
|
1257
|
+
}
|
|
1258
|
+
});
|
|
1259
|
+
|
|
1260
|
+
spy.should.have.been.calledWith($sumiao);
|
|
1261
|
+
spy.restore();
|
|
1262
|
+
});
|
|
1263
|
+
|
|
1264
|
+
it('hEdgeClickHandler() passes a native node to hideSiblings()', function () {
|
|
1265
|
+
const spy = sinon.spy(oc, 'hideSiblings');
|
|
1266
|
+
const spy2 = sinon.spy(oc, 'triggerHideEvent');
|
|
1267
|
+
|
|
1268
|
+
oc.hEdgeClickHandler({ edge: query('.leftEdge', $sumiao), node: $sumiao });
|
|
1269
|
+
|
|
1270
|
+
spy.should.have.been.calledWith($sumiao);
|
|
1271
|
+
spy2.should.have.been.called;
|
|
1272
|
+
});
|
|
1273
|
+
|
|
1274
|
+
it('hEdgeClickHandler() accepts wrapped native edge payloads', function () {
|
|
1275
|
+
const spy = sinon.spy(oc, 'hideSiblings');
|
|
1276
|
+
|
|
1277
|
+
oc.hEdgeClickHandler({
|
|
1278
|
+
originalEvent: {
|
|
1279
|
+
currentTarget: $sumiao,
|
|
1280
|
+
target: query('.leftEdge', $sumiao)
|
|
1281
|
+
}
|
|
1282
|
+
});
|
|
1283
|
+
|
|
1284
|
+
spy.should.have.been.calledWith($sumiao);
|
|
1285
|
+
spy.restore();
|
|
1286
|
+
});
|
|
1287
|
+
|
|
1288
|
+
it('hEdgeClickHandler() restores the collapsed parent after topEdgeClickHandler()', function () {
|
|
1289
|
+
oc.topEdgeClickHandler({ edge: query('.topEdge', $sumiao), node: $sumiao });
|
|
1290
|
+
triggerEvent($bomiao, 'transitionend');
|
|
1291
|
+
triggerEvent($laolao, 'transitionend');
|
|
1292
|
+
|
|
1293
|
+
oc.hEdgeClickHandler({ edge: query('.leftEdge', $sumiao), node: $sumiao });
|
|
1294
|
+
|
|
1295
|
+
closestElement($sumiao, '.hierarchy').classList.contains('isAncestorsCollapsed').should.equal(false);
|
|
1296
|
+
$laolao.classList.contains('hidden').should.equal(false);
|
|
1297
|
+
$laolao.classList.contains('slide-down').should.equal(false);
|
|
1298
|
+
$laolao.classList.contains('sliding').should.equal(true);
|
|
1299
|
+
});
|
|
1300
|
+
|
|
1301
|
+
it('startLoading() and endLoading() accept a native edge node', function () {
|
|
1302
|
+
$sumiao.dispatchEvent(new window.MouseEvent('mouseenter'));
|
|
1303
|
+
const edgeEl = query('.bottomEdge', $sumiao);
|
|
1304
|
+
|
|
1305
|
+
oc.startLoading(edgeEl).should.be.true;
|
|
1306
|
+
matchesSelector(edgeEl, '.hidden').should.be.true;
|
|
1307
|
+
queryAll('.spinner', edgeEl.parentElement).should.have.lengthOf(1);
|
|
1308
|
+
getState(oc.chart, 'inAjax').should.be.true;
|
|
1309
|
+
|
|
1310
|
+
oc.endLoading(edgeEl);
|
|
1311
|
+
matchesSelector(edgeEl, '.hidden').should.be.false;
|
|
1312
|
+
queryAll('.spinner', edgeEl.parentElement).should.have.lengthOf(0);
|
|
1313
|
+
getState(oc.chart, 'inAjax').should.be.false;
|
|
1314
|
+
});
|
|
1315
|
+
|
|
1316
|
+
it('startLoading() and endLoading() toggle native export buttons', function () {
|
|
1317
|
+
$sumiao.dispatchEvent(new window.MouseEvent('mouseenter'));
|
|
1318
|
+
const edgeEl = query('.bottomEdge', $sumiao);
|
|
1319
|
+
const exportButtonEl = document.createElement('button');
|
|
1320
|
+
|
|
1321
|
+
exportButtonEl.className = 'oc-export-btn';
|
|
1322
|
+
document.body.appendChild(exportButtonEl);
|
|
1323
|
+
|
|
1324
|
+
oc.startLoading(edgeEl);
|
|
1325
|
+
exportButtonEl.disabled.should.equal(true);
|
|
1326
|
+
|
|
1327
|
+
oc.endLoading(edgeEl);
|
|
1328
|
+
exportButtonEl.disabled.should.equal(false);
|
|
1329
|
+
|
|
1330
|
+
exportButtonEl.remove();
|
|
1331
|
+
});
|
|
1332
|
+
|
|
1333
|
+
it('stopAjax() accepts a native node level element', function () {
|
|
1334
|
+
const nodeLevelEl = oc.getChildren($sumiao)[0].closest('.nodes');
|
|
1335
|
+
const spinnerEl = document.createElement('i');
|
|
1336
|
+
|
|
1337
|
+
spinnerEl.className = 'spinner';
|
|
1338
|
+
nodeLevelEl.appendChild(spinnerEl);
|
|
1339
|
+
setState(oc.chart, 'inAjax', true);
|
|
1340
|
+
|
|
1341
|
+
oc.stopAjax(nodeLevelEl);
|
|
1342
|
+
|
|
1343
|
+
getState(oc.chart, 'inAjax').should.be.false;
|
|
1344
|
+
spinnerEl.remove();
|
|
1345
|
+
});
|
|
1346
|
+
|
|
1347
|
+
it('backToLooseHandler() and backToCompactHandler() toggle compact mode classes', function () {
|
|
1348
|
+
const compactNodeEl = createElementFromHtml('<div class="node compact"><i class="backToCompactSymbol hidden"></i><i class="backToLooseSymbol"></i></div>');
|
|
1349
|
+
|
|
1350
|
+
$container.appendChild(compactNodeEl);
|
|
1351
|
+
|
|
1352
|
+
oc.backToLooseHandler({ compactNode: compactNodeEl });
|
|
1353
|
+
matchesSelector(compactNodeEl, '.looseMode').should.be.true;
|
|
1354
|
+
matchesSelector(query('.backToLooseSymbol', compactNodeEl), '.hidden').should.be.true;
|
|
1355
|
+
matchesSelector(query('.backToCompactSymbol', compactNodeEl), '.hidden').should.be.false;
|
|
1356
|
+
|
|
1357
|
+
oc.backToCompactHandler({ compactNode: compactNodeEl });
|
|
1358
|
+
matchesSelector(compactNodeEl, '.looseMode').should.be.false;
|
|
1359
|
+
matchesSelector(query('.backToCompactSymbol', compactNodeEl), '.hidden').should.be.true;
|
|
1360
|
+
matchesSelector(query('.backToLooseSymbol', compactNodeEl), '.hidden').should.be.false;
|
|
1361
|
+
});
|
|
1362
|
+
|
|
1363
|
+
it('backToLooseHandler() and backToCompactHandler() accept wrapped native compact-node payloads', function () {
|
|
1364
|
+
const compactNodeEl = createElementFromHtml('<div class="node compact"><i class="backToCompactSymbol hidden"></i><i class="backToLooseSymbol"></i></div>');
|
|
1365
|
+
|
|
1366
|
+
$container.appendChild(compactNodeEl);
|
|
1367
|
+
|
|
1368
|
+
oc.backToLooseHandler({
|
|
1369
|
+
originalEvent: {
|
|
1370
|
+
currentTarget: compactNodeEl
|
|
1371
|
+
}
|
|
1372
|
+
});
|
|
1373
|
+
matchesSelector(compactNodeEl, '.looseMode').should.be.true;
|
|
1374
|
+
|
|
1375
|
+
oc.backToCompactHandler({
|
|
1376
|
+
originalEvent: {
|
|
1377
|
+
currentTarget: compactNodeEl
|
|
1378
|
+
}
|
|
1379
|
+
});
|
|
1380
|
+
matchesSelector(compactNodeEl, '.looseMode').should.be.false;
|
|
1381
|
+
});
|
|
1382
|
+
|
|
1383
|
+
it('toggleVNodes() expands vertical descendants from a native toggle button payload', function () {
|
|
1384
|
+
const spy = sinon.spy(oc, 'repaint');
|
|
1385
|
+
const toggleHostEl = createElementFromHtml('<div class="node"><i class="toggleBtn"></i></div>');
|
|
1386
|
+
const descWrapperEl = createElementFromHtml('<ul class="nodes hidden"><li class="hierarchy"><div class="node slide-up">child</div></li></ul>');
|
|
1387
|
+
let childNodeEl;
|
|
1388
|
+
|
|
1389
|
+
$container.appendChild(toggleHostEl);
|
|
1390
|
+
$container.appendChild(descWrapperEl);
|
|
1391
|
+
childNodeEl = query('.node', descWrapperEl);
|
|
1392
|
+
|
|
1393
|
+
oc.toggleVNodes({ toggleButton: query('.toggleBtn', toggleHostEl) });
|
|
1394
|
+
|
|
1395
|
+
spy.should.have.been.calledWith(childNodeEl);
|
|
1396
|
+
matchesSelector(descWrapperEl, '.hidden').should.be.false;
|
|
1397
|
+
matchesSelector(childNodeEl, '.sliding').should.be.true;
|
|
1398
|
+
matchesSelector(childNodeEl, '.slide-up').should.be.false;
|
|
1399
|
+
});
|
|
1400
|
+
|
|
1401
|
+
it('toggleVNodes() accepts a wrapped native toggle button payload', function () {
|
|
1402
|
+
const toggleHostEl = createElementFromHtml('<div class="node"><i class="toggleBtn"></i></div>');
|
|
1403
|
+
const descWrapperEl = createElementFromHtml('<ul class="nodes hidden"><li class="hierarchy"><div class="node slide-up">child</div></li></ul>');
|
|
1404
|
+
|
|
1405
|
+
$container.appendChild(toggleHostEl);
|
|
1406
|
+
$container.appendChild(descWrapperEl);
|
|
1407
|
+
|
|
1408
|
+
oc.toggleVNodes({
|
|
1409
|
+
originalEvent: {
|
|
1410
|
+
target: query('.toggleBtn', toggleHostEl)
|
|
1411
|
+
}
|
|
1412
|
+
});
|
|
1413
|
+
|
|
1414
|
+
matchesSelector(descWrapperEl, '.hidden').should.be.false;
|
|
1415
|
+
});
|
|
1416
|
+
|
|
1417
|
+
it('toggleVNodes() collapses vertical descendants from a native toggle button payload', function () {
|
|
1418
|
+
const toggleHostEl = createElementFromHtml('<div class="node"><i class="toggleBtn"></i></div>');
|
|
1419
|
+
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>');
|
|
1420
|
+
let nestedToggleBtnEl;
|
|
1421
|
+
let childNodeEl;
|
|
1422
|
+
|
|
1423
|
+
$container.appendChild(toggleHostEl);
|
|
1424
|
+
$container.appendChild(descWrapperEl);
|
|
1425
|
+
nestedToggleBtnEl = query('.node .toggleBtn', descWrapperEl);
|
|
1426
|
+
childNodeEl = query('.node', descWrapperEl);
|
|
1427
|
+
|
|
1428
|
+
oc.toggleVNodes({ toggleButton: query('.toggleBtn', toggleHostEl) });
|
|
1429
|
+
|
|
1430
|
+
matchesSelector(childNodeEl, '.sliding.slide-up').should.be.true;
|
|
1431
|
+
nestedToggleBtnEl.classList.contains('oci-plus-square').should.be.false;
|
|
1432
|
+
nestedToggleBtnEl.classList.contains('oci-minus-square').should.be.false;
|
|
1433
|
+
});
|
|
1434
|
+
|
|
1435
|
+
it('expandVNodesEnd() accepts direct vNodes payloads', function () {
|
|
1436
|
+
const descWrapperEl = createElementFromHtml('<ul class="nodes"><li class="hierarchy"><div class="node sliding">child</div></li></ul>');
|
|
1437
|
+
const childNodeEl = query('.node', descWrapperEl);
|
|
1438
|
+
|
|
1439
|
+
$container.appendChild(descWrapperEl);
|
|
1440
|
+
|
|
1441
|
+
oc.expandVNodesEnd({ vNodes: [childNodeEl] });
|
|
1442
|
+
|
|
1443
|
+
childNodeEl.classList.contains('sliding').should.equal(false);
|
|
1444
|
+
});
|
|
1445
|
+
|
|
1446
|
+
it('expandVNodesEnd() accepts wrapped native vNodes payloads', function () {
|
|
1447
|
+
const descWrapperEl = createElementFromHtml('<ul class="nodes"><li class="hierarchy"><div class="node sliding">child</div></li></ul>');
|
|
1448
|
+
const childNodeEl = query('.node', descWrapperEl);
|
|
1449
|
+
|
|
1450
|
+
$container.appendChild(descWrapperEl);
|
|
1451
|
+
|
|
1452
|
+
oc.expandVNodesEnd({
|
|
1453
|
+
originalEvent: {
|
|
1454
|
+
vNodes: [childNodeEl]
|
|
1455
|
+
}
|
|
1456
|
+
});
|
|
1457
|
+
|
|
1458
|
+
childNodeEl.classList.contains('sliding').should.equal(false);
|
|
1459
|
+
});
|
|
1460
|
+
|
|
1461
|
+
it('collapseVNodesEnd() accepts direct vNodes payloads', function () {
|
|
1462
|
+
const descWrapperEl = createElementFromHtml('<ul class="nodes"><li class="hierarchy"><div class="node sliding">child</div></li></ul>');
|
|
1463
|
+
const childNodeEl = query('.node', descWrapperEl);
|
|
1464
|
+
|
|
1465
|
+
$container.appendChild(descWrapperEl);
|
|
1466
|
+
|
|
1467
|
+
oc.collapseVNodesEnd({ vNodes: [childNodeEl] });
|
|
1468
|
+
|
|
1469
|
+
childNodeEl.classList.contains('sliding').should.equal(false);
|
|
1470
|
+
descWrapperEl.classList.contains('hidden').should.equal(true);
|
|
1471
|
+
});
|
|
1472
|
+
|
|
1473
|
+
it('collapseVNodesEnd() accepts wrapped native vNodes payloads', function () {
|
|
1474
|
+
const descWrapperEl = createElementFromHtml('<ul class="nodes"><li class="hierarchy"><div class="node sliding">child</div></li></ul>');
|
|
1475
|
+
const childNodeEl = query('.node', descWrapperEl);
|
|
1476
|
+
|
|
1477
|
+
$container.appendChild(descWrapperEl);
|
|
1478
|
+
|
|
1479
|
+
oc.collapseVNodesEnd({
|
|
1480
|
+
originalEvent: {
|
|
1481
|
+
vNodes: [childNodeEl]
|
|
1482
|
+
}
|
|
1483
|
+
});
|
|
1484
|
+
|
|
1485
|
+
childNodeEl.classList.contains('sliding').should.equal(false);
|
|
1486
|
+
descWrapperEl.classList.contains('hidden').should.equal(true);
|
|
1487
|
+
});
|
|
1488
|
+
|
|
1489
|
+
it('filterAllowedDropNodes() accepts a native dragged node', function () {
|
|
1490
|
+
oc.filterAllowedDropNodes($heihei);
|
|
1491
|
+
|
|
1492
|
+
getState(oc.chart, 'dragged').should.equal($heihei);
|
|
1493
|
+
$laolao.classList.contains('allowedDrop').should.be.true;
|
|
1494
|
+
queryAll('.allowedDrop', oc.chart).length.should.be.above(0);
|
|
1495
|
+
});
|
|
1496
|
+
|
|
1497
|
+
it('filterAllowedDropNodes() passes native node arguments to dropCriteria', function () {
|
|
1498
|
+
const dropCriteria = sinon.stub().returns(true);
|
|
1499
|
+
|
|
1500
|
+
oc.options.dropCriteria = dropCriteria;
|
|
1501
|
+
|
|
1502
|
+
oc.filterAllowedDropNodes($heihei);
|
|
1503
|
+
|
|
1504
|
+
dropCriteria.should.have.been.called;
|
|
1505
|
+
dropCriteria.firstCall.args[0].should.equal($heihei);
|
|
1506
|
+
dropCriteria.firstCall.args[1].should.equal($sumiao);
|
|
1507
|
+
dropCriteria.firstCall.args[2].should.have.property('nodeType', 1);
|
|
1508
|
+
});
|
|
1509
|
+
|
|
1510
|
+
it('dragstartHandler() passes a native dragged node payload to filterAllowedDropNodes()', function () {
|
|
1511
|
+
const spy = sinon.spy(oc, 'filterAllowedDropNodes');
|
|
1512
|
+
const dataTransfer = { setData: sinon.spy() };
|
|
1513
|
+
|
|
1514
|
+
oc.dragstartHandler({ draggedNode: $heihei, originalEvent: { dataTransfer: dataTransfer } });
|
|
1515
|
+
|
|
1516
|
+
dataTransfer.setData.should.have.been.called;
|
|
1517
|
+
spy.should.have.been.calledWith($heihei);
|
|
1518
|
+
});
|
|
1519
|
+
|
|
1520
|
+
it('dragstartHandler() accepts a wrapped native dragged node payload', function () {
|
|
1521
|
+
const spy = sinon.spy(oc, 'filterAllowedDropNodes');
|
|
1522
|
+
const dataTransfer = { setData: sinon.spy() };
|
|
1523
|
+
|
|
1524
|
+
oc.dragstartHandler({
|
|
1525
|
+
originalEvent: {
|
|
1526
|
+
target: $heihei,
|
|
1527
|
+
dataTransfer: dataTransfer
|
|
1528
|
+
}
|
|
1529
|
+
});
|
|
1530
|
+
|
|
1531
|
+
dataTransfer.setData.should.have.been.called;
|
|
1532
|
+
spy.should.have.been.calledWith($heihei);
|
|
1533
|
+
spy.restore();
|
|
1534
|
+
});
|
|
1535
|
+
|
|
1536
|
+
it('createGhostNode() accepts a native source node payload and creates a ghost image', function () {
|
|
1537
|
+
const setDragImageSpy = sinon.spy();
|
|
1538
|
+
const sourceNodeEl = $heihei;
|
|
1539
|
+
|
|
1540
|
+
oc.chart.style.transform = 'matrix(1, 0, 0, 1, 10, 20)';
|
|
1541
|
+
sourceNodeEl.getBoundingClientRect = function () {
|
|
1542
|
+
return { width: 120, height: 40, left: 10, top: 20 };
|
|
1543
|
+
};
|
|
1544
|
+
|
|
1545
|
+
oc.createGhostNode({
|
|
1546
|
+
sourceNode: sourceNodeEl,
|
|
1547
|
+
originalEvent: {
|
|
1548
|
+
offsetX: 5,
|
|
1549
|
+
offsetY: 6,
|
|
1550
|
+
dataTransfer: { setDragImage: setDragImageSpy }
|
|
1551
|
+
}
|
|
1552
|
+
});
|
|
1553
|
+
|
|
1554
|
+
const ghostNodeEl = oc.chart.querySelector('.ghost-node');
|
|
1555
|
+
should.exist(ghostNodeEl);
|
|
1556
|
+
ghostNodeEl.getAttribute('width').should.equal('120');
|
|
1557
|
+
ghostNodeEl.getAttribute('height').should.equal('40');
|
|
1558
|
+
setDragImageSpy.should.have.been.calledOnce;
|
|
1559
|
+
setDragImageSpy.firstCall.args[0].should.equal(ghostNodeEl);
|
|
1560
|
+
});
|
|
1561
|
+
|
|
1562
|
+
it('createGhostNode() accepts a wrapped native source node payload', function () {
|
|
1563
|
+
const setDragImageSpy = sinon.spy();
|
|
1564
|
+
const sourceNodeEl = $heihei;
|
|
1565
|
+
|
|
1566
|
+
oc.chart.style.transform = 'matrix(1, 0, 0, 1, 10, 20)';
|
|
1567
|
+
sourceNodeEl.getBoundingClientRect = function () {
|
|
1568
|
+
return { width: 120, height: 40, left: 10, top: 20 };
|
|
1569
|
+
};
|
|
1570
|
+
|
|
1571
|
+
oc.createGhostNode({
|
|
1572
|
+
originalEvent: {
|
|
1573
|
+
target: sourceNodeEl,
|
|
1574
|
+
offsetX: 5,
|
|
1575
|
+
offsetY: 6,
|
|
1576
|
+
dataTransfer: { setDragImage: setDragImageSpy }
|
|
1577
|
+
}
|
|
1578
|
+
});
|
|
1579
|
+
|
|
1580
|
+
should.exist(oc.chart.querySelector('.ghost-node'));
|
|
1581
|
+
setDragImageSpy.should.have.been.calledOnce;
|
|
1582
|
+
});
|
|
1583
|
+
|
|
1584
|
+
it('dragoverHandler() accepts a native drop zone payload', function () {
|
|
1585
|
+
const disallowedEvent = {
|
|
1586
|
+
dropZone: $bomiao,
|
|
1587
|
+
originalEvent: { dataTransfer: { dropEffect: 'move' } },
|
|
1588
|
+
preventDefault: sinon.spy()
|
|
1589
|
+
};
|
|
1590
|
+
disallowedEvent.originalEvent.preventDefault = disallowedEvent.preventDefault;
|
|
1591
|
+
const allowedEvent = {
|
|
1592
|
+
dropZone: addClasses($hongmiao, 'allowedDrop'),
|
|
1593
|
+
originalEvent: { dataTransfer: { dropEffect: 'move' } },
|
|
1594
|
+
preventDefault: sinon.spy()
|
|
1595
|
+
};
|
|
1596
|
+
allowedEvent.originalEvent.preventDefault = allowedEvent.preventDefault;
|
|
1597
|
+
|
|
1598
|
+
oc.dragoverHandler(disallowedEvent);
|
|
1599
|
+
oc.dragoverHandler(allowedEvent);
|
|
1600
|
+
|
|
1601
|
+
disallowedEvent.originalEvent.dataTransfer.dropEffect.should.equal('none');
|
|
1602
|
+
disallowedEvent.preventDefault.should.not.have.been.called;
|
|
1603
|
+
allowedEvent.preventDefault.should.have.been.calledOnce;
|
|
1604
|
+
});
|
|
1605
|
+
|
|
1606
|
+
it('dragoverHandler() accepts wrapped native drop-zone payloads', function () {
|
|
1607
|
+
const wrappedEvent = {
|
|
1608
|
+
originalEvent: {
|
|
1609
|
+
currentTarget: addClasses($hongmiao, 'allowedDrop'),
|
|
1610
|
+
dataTransfer: { dropEffect: 'move' },
|
|
1611
|
+
preventDefault: sinon.spy()
|
|
1612
|
+
}
|
|
1613
|
+
};
|
|
1614
|
+
|
|
1615
|
+
oc.dragoverHandler(wrappedEvent);
|
|
1616
|
+
|
|
1617
|
+
wrappedEvent.originalEvent.preventDefault.should.have.been.calledOnce;
|
|
1618
|
+
});
|
|
1619
|
+
|
|
1620
|
+
it('dragendHandler() removes allowedDrop from all nodes', function () {
|
|
1621
|
+
addClasses($bomiao, 'allowedDrop');
|
|
1622
|
+
addClasses($hongmiao, 'allowedDrop');
|
|
1623
|
+
|
|
1624
|
+
oc.dragendHandler({});
|
|
1625
|
+
|
|
1626
|
+
queryAll('.allowedDrop', oc.chart).should.have.lengthOf(0);
|
|
1627
|
+
});
|
|
1628
|
+
|
|
1629
|
+
it('dropHandler() accepts a native drop zone for non-node drags', async function () {
|
|
1630
|
+
const spy = sinon.spy();
|
|
1631
|
+
const foreignEl = createElementFromHtml('<div class="foreign-item"></div>');
|
|
1632
|
+
|
|
1633
|
+
oc.chart.addEventListener('otherdropped.orgchart', spy);
|
|
1634
|
+
setState(oc.chart, 'dragged', foreignEl);
|
|
1635
|
+
|
|
1636
|
+
await oc.dropHandler({ dropZone: $bomiao });
|
|
1637
|
+
|
|
1638
|
+
spy.should.have.been.calledOnce;
|
|
1639
|
+
spy.firstCall.args[0].type.should.equal('otherdropped.orgchart');
|
|
1640
|
+
spy.firstCall.args[0].detail.dropZone.should.equal($bomiao);
|
|
1641
|
+
});
|
|
1642
|
+
|
|
1643
|
+
it('dropHandler() accepts a wrapped native drop zone for non-node drags', async function () {
|
|
1644
|
+
const spy = sinon.spy();
|
|
1645
|
+
const foreignEl = createElementFromHtml('<div class="foreign-item"></div>');
|
|
1646
|
+
|
|
1647
|
+
oc.chart.addEventListener('otherdropped.orgchart', spy);
|
|
1648
|
+
setState(oc.chart, 'dragged', foreignEl);
|
|
1649
|
+
|
|
1650
|
+
await oc.dropHandler({
|
|
1651
|
+
originalEvent: {
|
|
1652
|
+
currentTarget: $bomiao
|
|
1653
|
+
}
|
|
1654
|
+
});
|
|
1655
|
+
|
|
1656
|
+
spy.should.have.been.calledOnce;
|
|
1657
|
+
spy.firstCall.args[0].detail.dropZone.should.equal($bomiao);
|
|
1658
|
+
});
|
|
1659
|
+
|
|
1660
|
+
it('dropHandler() accepts a native drop zone for node drags', async function () {
|
|
1661
|
+
const originalJSONDigger = global.JSONDigger;
|
|
1662
|
+
|
|
1663
|
+
global.JSONDigger = function () {
|
|
1664
|
+
return {
|
|
1665
|
+
findOneNode: function () {
|
|
1666
|
+
return null;
|
|
1667
|
+
}
|
|
1668
|
+
};
|
|
1669
|
+
};
|
|
1670
|
+
setState(oc.chart, 'dragged', $bomiao);
|
|
1671
|
+
addClasses($hongmiao, 'allowedDrop');
|
|
1672
|
+
|
|
1673
|
+
await oc.dropHandler({ dropZone: $hongmiao });
|
|
1674
|
+
|
|
1675
|
+
queryAll('#n2', firstSibling($hongmiao, '.nodes')).should.lengthOf(1);
|
|
1676
|
+
childElements(firstSibling($laolao, '.nodes'), '.hierarchy').should.lengthOf(2);
|
|
1677
|
+
global.JSONDigger = originalJSONDigger;
|
|
1678
|
+
});
|
|
1679
|
+
|
|
1680
|
+
it('dropHandler() keeps nodedrop payloads as native nodes', async function () {
|
|
1681
|
+
const originalJSONDigger = global.JSONDigger;
|
|
1682
|
+
const spy = sinon.spy();
|
|
1683
|
+
|
|
1684
|
+
global.JSONDigger = function () {
|
|
1685
|
+
return {
|
|
1686
|
+
findOneNode: function () {
|
|
1687
|
+
return null;
|
|
1688
|
+
}
|
|
1689
|
+
};
|
|
1690
|
+
};
|
|
1691
|
+
oc.chart.addEventListener('nodedrop.orgchart', spy);
|
|
1692
|
+
setState(oc.chart, 'dragged', $bomiao);
|
|
1693
|
+
addClasses($hongmiao, 'allowedDrop');
|
|
1694
|
+
|
|
1695
|
+
await oc.dropHandler({ dropZone: $hongmiao });
|
|
1696
|
+
|
|
1697
|
+
spy.should.have.been.calledOnce;
|
|
1698
|
+
spy.firstCall.args[0].type.should.equal('nodedrop.orgchart');
|
|
1699
|
+
spy.firstCall.args[0].detail.draggedNode.should.equal($bomiao);
|
|
1700
|
+
spy.firstCall.args[0].detail.dragZone.should.equal($laolao);
|
|
1701
|
+
spy.firstCall.args[0].detail.dropZone.should.equal($hongmiao);
|
|
1702
|
+
global.JSONDigger = originalJSONDigger;
|
|
1703
|
+
});
|
|
1704
|
+
|
|
1705
|
+
it('dropHandler() removes source child container when dragged node was the only child', async function () {
|
|
1706
|
+
const originalJSONDigger = global.JSONDigger;
|
|
1707
|
+
|
|
1708
|
+
global.JSONDigger = function () {
|
|
1709
|
+
return {
|
|
1710
|
+
findOneNode: function () {
|
|
1711
|
+
return null;
|
|
1712
|
+
}
|
|
1713
|
+
};
|
|
1714
|
+
};
|
|
1715
|
+
setState(oc.chart, 'dragged', $dandan);
|
|
1716
|
+
addClasses($hongmiao, 'allowedDrop');
|
|
1717
|
+
|
|
1718
|
+
await oc.dropHandler({ dropZone: $hongmiao });
|
|
1719
|
+
|
|
1720
|
+
queryAll('#n8', firstSibling($hongmiao, '.nodes')).should.lengthOf(1);
|
|
1721
|
+
siblingElements($tiehua, '.nodes').should.lengthOf(0);
|
|
1722
|
+
childElements($tiehua, '.bottomEdge, .parentNodeSymbol').should.lengthOf(0);
|
|
1723
|
+
global.JSONDigger = originalJSONDigger;
|
|
1724
|
+
});
|
|
1725
|
+
|
|
1726
|
+
it('touchmoveHandler() passes a native dragged node payload to filterAllowedDropNodes()', function () {
|
|
1727
|
+
const spy = sinon.spy(oc, 'filterAllowedDropNodes');
|
|
1728
|
+
const createDragImageStub = sinon.stub(oc, 'createDragImage').returns(document.createElement('div'));
|
|
1729
|
+
const moveDragImageStub = sinon.stub(oc, 'moveDragImage');
|
|
1730
|
+
const originalElementFromPoint = document.elementFromPoint;
|
|
1731
|
+
|
|
1732
|
+
document.elementFromPoint = function () {
|
|
1733
|
+
return $bomiao;
|
|
1734
|
+
};
|
|
1735
|
+
|
|
1736
|
+
oc.touchHandled = true;
|
|
1737
|
+
oc.touchMoved = false;
|
|
1738
|
+
oc.touchmoveHandler({
|
|
1739
|
+
draggedNode: $heihei,
|
|
1740
|
+
touches: [{ clientX: 0, clientY: 0 }],
|
|
1741
|
+
preventDefault: function () {}
|
|
1742
|
+
});
|
|
1743
|
+
|
|
1744
|
+
spy.should.have.been.calledWith($heihei);
|
|
1745
|
+
createDragImageStub.should.have.been.called;
|
|
1746
|
+
moveDragImageStub.should.have.been.called;
|
|
1747
|
+
oc.touchTargetNode.should.equal($bomiao);
|
|
1748
|
+
|
|
1749
|
+
document.elementFromPoint = originalElementFromPoint;
|
|
1750
|
+
moveDragImageStub.restore();
|
|
1751
|
+
createDragImageStub.restore();
|
|
1752
|
+
});
|
|
1753
|
+
|
|
1754
|
+
it('touchmoveHandler() accepts wrapped native touch payloads', function () {
|
|
1755
|
+
const spy = sinon.spy(oc, 'filterAllowedDropNodes');
|
|
1756
|
+
const createDragImageStub = sinon.stub(oc, 'createDragImage').returns(document.createElement('div'));
|
|
1757
|
+
const moveDragImageStub = sinon.stub(oc, 'moveDragImage');
|
|
1758
|
+
const originalElementFromPoint = document.elementFromPoint;
|
|
1759
|
+
|
|
1760
|
+
document.elementFromPoint = function () {
|
|
1761
|
+
return $bomiao;
|
|
1762
|
+
};
|
|
1763
|
+
|
|
1764
|
+
oc.touchHandled = true;
|
|
1765
|
+
oc.touchMoved = false;
|
|
1766
|
+
oc.touchmoveHandler({
|
|
1767
|
+
originalEvent: {
|
|
1768
|
+
currentTarget: $heihei,
|
|
1769
|
+
touches: [{ clientX: 0, clientY: 0 }],
|
|
1770
|
+
preventDefault: function () {}
|
|
1771
|
+
}
|
|
1772
|
+
});
|
|
1773
|
+
|
|
1774
|
+
spy.should.have.been.calledWith($heihei);
|
|
1775
|
+
createDragImageStub.should.have.been.called;
|
|
1776
|
+
moveDragImageStub.should.have.been.called;
|
|
1777
|
+
oc.touchTargetNode.should.equal($bomiao);
|
|
1778
|
+
|
|
1779
|
+
document.elementFromPoint = originalElementFromPoint;
|
|
1780
|
+
moveDragImageStub.restore();
|
|
1781
|
+
createDragImageStub.restore();
|
|
1782
|
+
spy.restore();
|
|
1783
|
+
});
|
|
1784
|
+
|
|
1785
|
+
it('touchstartHandler() accepts a wrapped native touch payload', function () {
|
|
1786
|
+
const preventDefaultSpy = sinon.spy();
|
|
1787
|
+
|
|
1788
|
+
oc.touchHandled = false;
|
|
1789
|
+
oc.touchMoved = true;
|
|
1790
|
+
|
|
1791
|
+
oc.touchstartHandler({
|
|
1792
|
+
originalEvent: {
|
|
1793
|
+
touches: [{ clientX: 0, clientY: 0 }],
|
|
1794
|
+
preventDefault: preventDefaultSpy
|
|
1795
|
+
}
|
|
1796
|
+
});
|
|
1797
|
+
|
|
1798
|
+
oc.touchHandled.should.equal(true);
|
|
1799
|
+
oc.touchMoved.should.equal(false);
|
|
1800
|
+
preventDefaultSpy.should.have.been.calledOnce;
|
|
1801
|
+
});
|
|
1802
|
+
|
|
1803
|
+
it('getTouchPoint() accepts a wrapped native touch payload', function () {
|
|
1804
|
+
const touchPoint = oc.getTouchPoint({
|
|
1805
|
+
originalEvent: {
|
|
1806
|
+
touches: [{ clientX: 12, clientY: 34 }]
|
|
1807
|
+
}
|
|
1808
|
+
});
|
|
1809
|
+
|
|
1810
|
+
touchPoint.x.should.equal(12);
|
|
1811
|
+
touchPoint.y.should.equal(34);
|
|
1812
|
+
});
|
|
1813
|
+
|
|
1814
|
+
it('touchendHandler() passes a native drop zone to dropHandler() after touch drag', function () {
|
|
1815
|
+
const destroyDragImageStub = sinon.stub(oc, 'destroyDragImage');
|
|
1816
|
+
const dropHandlerStub = sinon.stub(oc, 'dropHandler');
|
|
1817
|
+
const dragendHandlerStub = sinon.stub(oc, 'dragendHandler');
|
|
1818
|
+
|
|
1819
|
+
oc.touchHandled = true;
|
|
1820
|
+
oc.touchMoved = true;
|
|
1821
|
+
oc.touchTargetNode = $bomiao;
|
|
1822
|
+
|
|
1823
|
+
oc.touchendHandler({});
|
|
1824
|
+
|
|
1825
|
+
destroyDragImageStub.should.have.been.calledOnce;
|
|
1826
|
+
dropHandlerStub.should.have.been.calledOnce;
|
|
1827
|
+
dropHandlerStub.firstCall.args[0].dropZone.should.equal($bomiao);
|
|
1828
|
+
dragendHandlerStub.should.have.been.calledOnce;
|
|
1829
|
+
should.equal(oc.touchTargetNode, null);
|
|
1830
|
+
oc.touchHandled.should.equal(false);
|
|
1831
|
+
|
|
1832
|
+
dragendHandlerStub.restore();
|
|
1833
|
+
dropHandlerStub.restore();
|
|
1834
|
+
destroyDragImageStub.restore();
|
|
1835
|
+
});
|
|
1836
|
+
|
|
1837
|
+
it('touchendHandler() dispatches a native click when touch did not move', function () {
|
|
1838
|
+
const destroyDragImageStub = sinon.stub(oc, 'destroyDragImage');
|
|
1839
|
+
const clickSpy = sinon.spy();
|
|
1840
|
+
const targetEl = document.createElement('div');
|
|
1841
|
+
|
|
1842
|
+
targetEl.addEventListener('click', clickSpy);
|
|
1843
|
+
oc.touchHandled = true;
|
|
1844
|
+
oc.touchMoved = false;
|
|
1845
|
+
|
|
1846
|
+
oc.touchendHandler({
|
|
1847
|
+
target: targetEl,
|
|
1848
|
+
changedTouches: [{ screenX: 1, screenY: 2, clientX: 3, clientY: 4 }],
|
|
1849
|
+
ctrlKey: false,
|
|
1850
|
+
altKey: false,
|
|
1851
|
+
shiftKey: false,
|
|
1852
|
+
metaKey: false
|
|
1853
|
+
});
|
|
1854
|
+
|
|
1855
|
+
destroyDragImageStub.should.have.been.calledOnce;
|
|
1856
|
+
clickSpy.should.have.been.calledOnce;
|
|
1857
|
+
clickSpy.firstCall.args[0].type.should.equal('click');
|
|
1858
|
+
clickSpy.firstCall.args[0].clientX.should.equal(3);
|
|
1859
|
+
clickSpy.firstCall.args[0].clientY.should.equal(4);
|
|
1860
|
+
oc.touchHandled.should.equal(false);
|
|
1861
|
+
|
|
1862
|
+
destroyDragImageStub.restore();
|
|
1863
|
+
});
|
|
1864
|
+
|
|
1865
|
+
it('touchendHandler() accepts wrapped native touchend payloads', function () {
|
|
1866
|
+
const destroyDragImageStub = sinon.stub(oc, 'destroyDragImage');
|
|
1867
|
+
const clickSpy = sinon.spy();
|
|
1868
|
+
const targetEl = document.createElement('div');
|
|
1869
|
+
|
|
1870
|
+
targetEl.addEventListener('click', clickSpy);
|
|
1871
|
+
oc.touchHandled = true;
|
|
1872
|
+
oc.touchMoved = false;
|
|
1873
|
+
|
|
1874
|
+
oc.touchendHandler({
|
|
1875
|
+
originalEvent: {
|
|
1876
|
+
target: targetEl,
|
|
1877
|
+
changedTouches: [{ screenX: 1, screenY: 2, clientX: 3, clientY: 4 }],
|
|
1878
|
+
ctrlKey: false,
|
|
1879
|
+
altKey: false,
|
|
1880
|
+
shiftKey: false,
|
|
1881
|
+
metaKey: false
|
|
1882
|
+
}
|
|
1883
|
+
});
|
|
1884
|
+
|
|
1885
|
+
destroyDragImageStub.should.have.been.calledOnce;
|
|
1886
|
+
clickSpy.should.have.been.calledOnce;
|
|
1887
|
+
oc.touchHandled.should.equal(false);
|
|
1888
|
+
|
|
1889
|
+
destroyDragImageStub.restore();
|
|
1890
|
+
});
|
|
1891
|
+
|
|
1892
|
+
it('getUpperLevel() and getLowerLevel() accept native nodes', function () {
|
|
1893
|
+
oc.getUpperLevel($laolao).should.equal(1);
|
|
1894
|
+
oc.getUpperLevel($dandan).should.equal(4);
|
|
1895
|
+
oc.getLowerLevel($laolao).should.equal(4);
|
|
1896
|
+
oc.getLowerLevel($dandan).should.equal(1);
|
|
1897
|
+
});
|
|
1898
|
+
|
|
1899
|
+
it('getLevelOrderNodes() accepts a native root node', function () {
|
|
1900
|
+
const levels = oc.getLevelOrderNodes($laolao);
|
|
1901
|
+
|
|
1902
|
+
levels.should.have.lengthOf(4);
|
|
1903
|
+
levels[0][0].should.equal($laolao);
|
|
1904
|
+
levels[1].map(function (nodeEl) { return nodeEl.id; }).should.deep.equal(['n2', 'n3', 'n4']);
|
|
1905
|
+
levels[2].map(function (nodeEl) { return nodeEl.id; }).should.deep.equal(['n5', 'n6', 'n7']);
|
|
1906
|
+
levels[3].map(function (nodeEl) { return nodeEl.id; }).should.deep.equal(['n8', 'n9', 'n10']);
|
|
1907
|
+
});
|
|
1908
|
+
|
|
1909
|
+
it('isInAction() tracks node interaction independently of arrow classes', function () {
|
|
1910
|
+
const nodeEl = $sumiao;
|
|
1911
|
+
|
|
1912
|
+
oc.isInAction(nodeEl).should.equal(false);
|
|
1913
|
+
nodeEl.dispatchEvent(new window.MouseEvent('mouseenter'));
|
|
1914
|
+
oc.isInAction(nodeEl).should.equal(true);
|
|
1915
|
+
|
|
1916
|
+
nodeEl.querySelector('.topEdge').className = 'edge topEdge';
|
|
1917
|
+
oc.isInAction(nodeEl).should.equal(true);
|
|
1918
|
+
nodeEl.dispatchEvent(new window.MouseEvent('mouseleave'));
|
|
1919
|
+
oc.isInAction(nodeEl).should.equal(false);
|
|
1920
|
+
});
|
|
1921
|
+
|
|
1922
|
+
it('switchHorizontalArrow() accepts a native node and toggles edge classes from native siblings', function () {
|
|
1923
|
+
const nodeEl = $sumiao;
|
|
1924
|
+
nodeEl.dispatchEvent(new window.MouseEvent('mouseenter'));
|
|
1925
|
+
const leftEdgeEl = nodeEl.querySelector('.leftEdge');
|
|
1926
|
+
const rightEdgeEl = nodeEl.querySelector('.rightEdge');
|
|
1927
|
+
|
|
1928
|
+
oc.switchHorizontalArrow(nodeEl);
|
|
1929
|
+
leftEdgeEl.classList.contains(oc.options.icons.expandToRight).should.equal(true);
|
|
1930
|
+
leftEdgeEl.classList.contains(oc.options.icons.collapseToLeft).should.equal(false);
|
|
1931
|
+
rightEdgeEl.classList.contains(oc.options.icons.collapseToLeft).should.equal(true);
|
|
1932
|
+
rightEdgeEl.classList.contains(oc.options.icons.expandToRight).should.equal(false);
|
|
1933
|
+
|
|
1934
|
+
siblingElements(closestElement($sumiao, '.hierarchy')).forEach(function (siblingEl) {
|
|
1935
|
+
addClasses(siblingEl, 'hidden');
|
|
1936
|
+
});
|
|
1937
|
+
oc.switchHorizontalArrow(nodeEl);
|
|
1938
|
+
|
|
1939
|
+
leftEdgeEl.classList.contains(oc.options.icons.expandToRight).should.equal(false);
|
|
1940
|
+
leftEdgeEl.classList.contains(oc.options.icons.collapseToLeft).should.equal(true);
|
|
1941
|
+
rightEdgeEl.classList.contains(oc.options.icons.collapseToLeft).should.equal(false);
|
|
1942
|
+
rightEdgeEl.classList.contains(oc.options.icons.expandToRight).should.equal(true);
|
|
1943
|
+
});
|
|
1944
|
+
|
|
1945
|
+
it('switchVerticalArrow() accepts a native edge element and toggles vertical arrow classes', function () {
|
|
1946
|
+
$sumiao.dispatchEvent(new window.MouseEvent('mouseenter'));
|
|
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, touches: [{ clientX: 0, clientY: 0 }, { clientX: 3, clientY: 4 }] });
|
|
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', 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', level: 1 });
|
|
2301
|
+
hierarchyEl.appendChild(nodeEl);
|
|
2302
|
+
|
|
2303
|
+
verticalChart.buildInferiorNodes(hierarchyEl, nodeEl, {
|
|
2304
|
+
collapsed: true,
|
|
2305
|
+
children: [{ id: 'n12', name: 'Child' }]
|
|
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', 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' }]
|
|
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', outsider: false },
|
|
2343
|
+
{
|
|
2344
|
+
id: 'n12',
|
|
2345
|
+
name: 'Spouse B',
|
|
2346
|
+
outsider: true,
|
|
2347
|
+
children: [[{ id: 'n13', name: 'Child' }]]
|
|
2348
|
+
}
|
|
2349
|
+
]]);
|
|
2350
|
+
|
|
2351
|
+
wrapperEl = hierarchyEl.firstElementChild;
|
|
2352
|
+
|
|
2353
|
+
should.exist(wrapperEl);
|
|
2354
|
+
wrapperEl.classList.contains('couple').should.equal(true);
|
|
2355
|
+
Array.from(wrapperEl.children).filter(function (childEl) {
|
|
2356
|
+
return childEl.classList && childEl.classList.contains('node');
|
|
2357
|
+
}).length.should.equal(2);
|
|
2358
|
+
wrapperEl.querySelector('#n12').should.not.equal(null);
|
|
2359
|
+
wrapperEl.querySelector('.nodes').should.not.equal(null);
|
|
2360
|
+
});
|
|
2361
|
+
|
|
2362
|
+
it('addAncestors() wraps the original root content into a different hierarchy from the new ancestor', function () {
|
|
2363
|
+
let ancestorNodeEl;
|
|
2364
|
+
let originalRootNodeEl;
|
|
2365
|
+
|
|
2366
|
+
oc.addAncestors({ id: 'n0', name: 'Lao Ye' }, 'n0');
|
|
2367
|
+
|
|
2368
|
+
ancestorNodeEl = document.getElementById('n0');
|
|
2369
|
+
originalRootNodeEl = document.getElementById('n1');
|
|
2370
|
+
|
|
2371
|
+
should.exist(ancestorNodeEl);
|
|
2372
|
+
should.exist(originalRootNodeEl);
|
|
2373
|
+
originalRootNodeEl.closest('.hierarchy').should.not.equal(ancestorNodeEl.closest('.hierarchy'));
|
|
2374
|
+
});
|
|
2375
|
+
|
|
2376
|
+
it('addDescendants() accepts a native parent element and appends descendant hierarchy nodes', function () {
|
|
2377
|
+
oc.addDescendants([{ id: 'n11', name: 'Li Xin' }], $bomiao);
|
|
2378
|
+
|
|
2379
|
+
should.exist($bomiao.nextElementSibling);
|
|
2380
|
+
matchesSelector($bomiao.nextElementSibling, '.nodes').should.be.true;
|
|
2381
|
+
childElements($bomiao.nextElementSibling, '.hierarchy').should.have.lengthOf(1);
|
|
2382
|
+
queryAll('#n11', $bomiao.nextElementSibling).should.have.lengthOf(1);
|
|
2383
|
+
});
|
|
2384
|
+
|
|
2385
|
+
it('showDropZones() accepts a native dragged node', function () {
|
|
2386
|
+
oc.showDropZones($heihei);
|
|
2387
|
+
|
|
2388
|
+
getState(oc.chart, 'dragged').should.equal($heihei);
|
|
2389
|
+
queryAll('.allowedDrop', oc.chart).length.should.equal(queryAll('.node', oc.chart).length);
|
|
2390
|
+
});
|
|
2391
|
+
|
|
2392
|
+
it('hideDropZones() clears all allowedDrop classes', function () {
|
|
2393
|
+
oc.showDropZones($heihei);
|
|
2394
|
+
|
|
2395
|
+
oc.hideDropZones();
|
|
2396
|
+
|
|
2397
|
+
queryAll('.allowedDrop', oc.chart).should.have.lengthOf(0);
|
|
2398
|
+
});
|
|
2399
|
+
|
|
2400
|
+
it('processExternalDrop() accepts native drop and dragged nodes', function () {
|
|
2401
|
+
const dropSpy = sinon.spy();
|
|
2402
|
+
|
|
2403
|
+
$bomiao.addEventListener('drop', dropSpy);
|
|
2404
|
+
|
|
2405
|
+
oc.processExternalDrop($bomiao, $heihei);
|
|
2406
|
+
|
|
2407
|
+
getState(oc.chart, 'dragged').should.equal($heihei);
|
|
2408
|
+
dropSpy.should.have.been.calledOnce;
|
|
2409
|
+
dropSpy.firstCall.args[0].type.should.equal('drop');
|
|
2410
|
+
});
|
|
2411
|
+
|
|
2412
|
+
it('exportPNG() creates and reuses a native download anchor', function () {
|
|
2413
|
+
const originalNavigator = window.navigator;
|
|
2414
|
+
const originalClick = window.HTMLAnchorElement.prototype.click;
|
|
2415
|
+
const originalWebkitAppearance = document.documentElement.style.WebkitAppearance;
|
|
2416
|
+
const clickSpy = sinon.spy();
|
|
2417
|
+
const fakeCanvas = {
|
|
2418
|
+
toDataURL: function () {
|
|
2419
|
+
return 'data:image/png;base64,fake';
|
|
2420
|
+
}
|
|
2421
|
+
};
|
|
2422
|
+
|
|
2423
|
+
Object.defineProperty(window, 'navigator', {
|
|
2424
|
+
configurable: true,
|
|
2425
|
+
value: {
|
|
2426
|
+
appName: 'Netscape',
|
|
2427
|
+
appVersion: 'Chrome'
|
|
2428
|
+
}
|
|
2429
|
+
});
|
|
2430
|
+
document.documentElement.style.WebkitAppearance = 'none';
|
|
2431
|
+
window.HTMLAnchorElement.prototype.click = clickSpy;
|
|
2432
|
+
|
|
2433
|
+
oc.exportPNG(fakeCanvas, 'UnitExportPng');
|
|
2434
|
+
oc.exportPNG(fakeCanvas, 'UnitExportPng2');
|
|
2435
|
+
|
|
2436
|
+
queryAll('.download-btn', $container).should.have.lengthOf(1);
|
|
2437
|
+
query('.download-btn', $container).getAttribute('download').should.equal('UnitExportPng2.png');
|
|
2438
|
+
query('.download-btn', $container).getAttribute('href').should.equal('data:image/png;base64,fake');
|
|
2439
|
+
clickSpy.callCount.should.equal(2);
|
|
2440
|
+
|
|
2441
|
+
Object.defineProperty(window, 'navigator', {
|
|
2442
|
+
configurable: true,
|
|
2443
|
+
value: originalNavigator
|
|
2444
|
+
});
|
|
2445
|
+
document.documentElement.style.WebkitAppearance = originalWebkitAppearance;
|
|
2446
|
+
window.HTMLAnchorElement.prototype.click = originalClick;
|
|
2447
|
+
});
|
|
2448
|
+
|
|
2449
|
+
it('export() passes the visible chart element to html2canvas and exports png by default', function (done) {
|
|
2450
|
+
const originalHtml2canvas = global.html2canvas;
|
|
2451
|
+
const originalWindowHtml2canvas = window.html2canvas;
|
|
2452
|
+
const exportPNGStub = sinon.stub(oc, 'exportPNG');
|
|
2453
|
+
const fakeCanvas = {
|
|
2454
|
+
toDataURL: function () {
|
|
2455
|
+
return 'data:image/png;base64,fake';
|
|
2456
|
+
}
|
|
2457
|
+
};
|
|
2458
|
+
|
|
2459
|
+
global.html2canvas = function (element, options) {
|
|
2460
|
+
try {
|
|
2461
|
+
element.should.equal(oc.chart);
|
|
2462
|
+
options.width.should.equal(oc.chart.clientWidth);
|
|
2463
|
+
options.height.should.equal(oc.chart.clientHeight);
|
|
2464
|
+
options.scale.should.equal(2);
|
|
2465
|
+
options.useCORS.should.equal(true);
|
|
2466
|
+
} catch (error) {
|
|
2467
|
+
done(error);
|
|
2468
|
+
return {
|
|
2469
|
+
then: function () {}
|
|
2470
|
+
};
|
|
2471
|
+
}
|
|
2472
|
+
|
|
2473
|
+
return {
|
|
2474
|
+
then: function (resolve) {
|
|
2475
|
+
resolve(fakeCanvas);
|
|
2476
|
+
return {
|
|
2477
|
+
then: function () {}
|
|
2478
|
+
};
|
|
2479
|
+
}
|
|
2480
|
+
};
|
|
2481
|
+
};
|
|
2482
|
+
|
|
2483
|
+
window.html2canvas = global.html2canvas;
|
|
2484
|
+
|
|
2485
|
+
oc.export('UnitExport');
|
|
2486
|
+
|
|
2487
|
+
setTimeout(function () {
|
|
2488
|
+
try {
|
|
2489
|
+
exportPNGStub.should.have.been.calledOnce;
|
|
2490
|
+
exportPNGStub.firstCall.args[0].should.equal(fakeCanvas);
|
|
2491
|
+
exportPNGStub.firstCall.args[1].should.equal('UnitExport');
|
|
2492
|
+
$container.classList.contains('canvasContainer').should.be.false;
|
|
2493
|
+
query('.mask', $container).classList.contains('hidden').should.be.true;
|
|
2494
|
+
global.html2canvas = originalHtml2canvas;
|
|
2495
|
+
window.html2canvas = originalWindowHtml2canvas;
|
|
2496
|
+
exportPNGStub.restore();
|
|
2497
|
+
done();
|
|
2498
|
+
} catch (error) {
|
|
2499
|
+
global.html2canvas = originalHtml2canvas;
|
|
2500
|
+
window.html2canvas = originalWindowHtml2canvas;
|
|
2501
|
+
exportPNGStub.restore();
|
|
2502
|
+
done(error);
|
|
2503
|
+
}
|
|
2504
|
+
}, 0);
|
|
2505
|
+
});
|
|
2506
|
+
|
|
2507
|
+
it('export() returns false when the chart container already has a spinner', function () {
|
|
2508
|
+
const html2canvasStub = sinon.stub(global, 'html2canvas');
|
|
2509
|
+
const spinnerEl = document.createElement('i');
|
|
2510
|
+
|
|
2511
|
+
spinnerEl.className = 'spinner';
|
|
2512
|
+
$container.appendChild(spinnerEl);
|
|
2513
|
+
|
|
2514
|
+
oc.export('BlockedExport').should.equal(false);
|
|
2515
|
+
html2canvasStub.should.not.have.been.called;
|
|
2516
|
+
|
|
2517
|
+
spinnerEl.remove();
|
|
2518
|
+
html2canvasStub.restore();
|
|
2519
|
+
});
|
|
2520
|
+
|
|
2521
|
+
it('export() routes pdf exports to exportPDF()', function (done) {
|
|
2522
|
+
const originalHtml2canvas = global.html2canvas;
|
|
2523
|
+
const originalWindowHtml2canvas = window.html2canvas;
|
|
2524
|
+
const exportPDFStub = sinon.stub(oc, 'exportPDF');
|
|
2525
|
+
const fakeCanvas = {
|
|
2526
|
+
toDataURL: function () {
|
|
2527
|
+
return 'data:image/png;base64,fake';
|
|
2528
|
+
}
|
|
2529
|
+
};
|
|
2530
|
+
|
|
2531
|
+
global.html2canvas = function () {
|
|
2532
|
+
return {
|
|
2533
|
+
then: function (resolve) {
|
|
2534
|
+
resolve(fakeCanvas);
|
|
2535
|
+
return {
|
|
2536
|
+
then: function () {}
|
|
2537
|
+
};
|
|
2538
|
+
}
|
|
2539
|
+
};
|
|
2540
|
+
};
|
|
2541
|
+
|
|
2542
|
+
window.html2canvas = global.html2canvas;
|
|
2543
|
+
|
|
2544
|
+
oc.export('UnitExportPdf', 'pdf');
|
|
2545
|
+
|
|
2546
|
+
setTimeout(function () {
|
|
2547
|
+
try {
|
|
2548
|
+
exportPDFStub.should.have.been.calledOnce;
|
|
2549
|
+
exportPDFStub.firstCall.args[0].should.equal(fakeCanvas);
|
|
2550
|
+
exportPDFStub.firstCall.args[1].should.equal('UnitExportPdf');
|
|
2551
|
+
global.html2canvas = originalHtml2canvas;
|
|
2552
|
+
window.html2canvas = originalWindowHtml2canvas;
|
|
2553
|
+
exportPDFStub.restore();
|
|
2554
|
+
done();
|
|
2555
|
+
} catch (error) {
|
|
2556
|
+
global.html2canvas = originalHtml2canvas;
|
|
2557
|
+
window.html2canvas = originalWindowHtml2canvas;
|
|
2558
|
+
exportPDFStub.restore();
|
|
2559
|
+
done(error);
|
|
2560
|
+
}
|
|
2561
|
+
}, 0);
|
|
2562
|
+
});
|
|
2563
|
+
});
|