jqtree 1.5.2 → 1.6.2
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/.eslintrc +1 -0
- package/.github/workflows/ci.yml +54 -0
- package/.github/workflows/codeql-analysis.yml +28 -0
- package/README.md +1 -1
- package/_config.yml +1 -1
- package/_entries/10_changelog.md +20 -0
- package/_entries/{36_showemptynode.md → 36_showemptyfolder.md} +5 -5
- package/_entries/38_start_dnd_delay.md +13 -0
- package/_entries/{38_tabindex.md → 39_tabindex.md} +0 -0
- package/_entries/{39_usecontextmenu.md → 40_usecontextmenu.md} +0 -0
- package/_entries/{40_functions.md → 41_functions.md} +0 -0
- package/_entries/{41_addparentnode.md → 42_addparentnode.md} +0 -0
- package/_entries/{42_addnodeafter.md → 43_addnodeafter.md} +0 -0
- package/_entries/{43_addnodebefore.md → 44_addnodebefore.md} +0 -0
- package/_entries/{44_appendnode.md → 45_appendnode.md} +0 -0
- package/_entries/{45_closenode.md → 46_closenode.md} +0 -0
- package/_entries/{46_destroy.md → 47_destroy.md} +0 -0
- package/_entries/{47_getnodebycallback.md → 48_getnodebycallback.md} +0 -0
- package/_entries/{48_getnodebyid.md → 49_getnodebyid.md} +0 -0
- package/_entries/{49_getnodebyhtmlelement.md → 50_getnodebyhtmlelement.md} +0 -0
- package/_entries/{50_getselectednode.md → 51_getselectednode.md} +0 -0
- package/_entries/{51_getstate.md → 52_getstate.md} +0 -0
- package/_entries/{52_gettree.md → 53_gettree.md} +0 -0
- package/_entries/{53_isdragging.md → 54_isdragging.md} +0 -0
- package/_entries/{54_loaddata.md → 55_loaddata.md} +0 -0
- package/_entries/{55_loaddatafromurl.md → 56_loaddatafromurl.md} +0 -0
- package/_entries/{56_movedown.md → 57_movedown.md} +0 -0
- package/_entries/{57_movenode.md → 58_movenode.md} +0 -0
- package/_entries/{58_moveup.md → 59_moveup.md} +0 -0
- package/_entries/{59_opennode.md → 60_opennode.md} +0 -0
- package/_entries/{60_prependnode.md → 61_prependnode.md} +0 -0
- package/_entries/62_refresh.md +12 -0
- package/_entries/{61_reload.md → 63_reload.md} +0 -0
- package/_entries/{62_removenode.md → 64_removenode.md} +0 -0
- package/_entries/{63_selectnode.md → 65_selectnode.md} +0 -0
- package/_entries/{64_scrolltonode.md → 66_scrolltonode.md} +0 -0
- package/_entries/{65_setoption.md → 67_setoption.md} +0 -0
- package/_entries/{66_setstate.md → 68_setstate.md} +0 -0
- package/_entries/{67_toggle.md → 69_toggle.md} +0 -0
- package/_entries/{68_tojson.md → 70_tojson.md} +0 -0
- package/_entries/{69_updatenode.md → 71_updatenode.md} +0 -0
- package/_entries/{70_events.md → 72_events.md} +0 -0
- package/_entries/{71_tree-click.md → 73_tree-click.md} +0 -0
- package/_entries/{72_tree-close.md → 74_tree-close.md} +0 -0
- package/_entries/{73_tree-contextmenu.md → 75_tree-contextmenu.md} +0 -0
- package/_entries/{74_tree-dblclick.md → 76_tree-dblclick.md} +0 -0
- package/_entries/{75_tree-init.md → 77_tree-init.md} +0 -0
- package/_entries/{76_tree-load-data.md → 78_tree-load-data.md} +0 -0
- package/_entries/{77_tree-loading-data.md → 79_tree-loading-data.md} +0 -0
- package/_entries/{78_tree-move.md → 80_tree-move.md} +0 -0
- package/_entries/{79_tree-refresh.md → 81_tree-refresh.md} +0 -0
- package/_entries/{80_tree-open.md → 82_tree-open.md} +0 -0
- package/_entries/{81_tree-select.md → 83_tree-select.md} +0 -0
- package/_entries/{82_multiple-selection.md → 84_multiple-selection.md} +0 -0
- package/_entries/{83_add-to-selection.md → 85_add-to-selection.md} +0 -0
- package/_entries/{84_get-selected-nodes.md → 86_get-selected-nodes.md} +0 -0
- package/_entries/{85_is-node-selected.md → 87_is-node-selected.md} +0 -0
- package/_entries/{86_remove-from-selection.md → 88_remove-from-selection.md} +0 -0
- package/_entries/{87_node-functions.md → 89_node-functions.md} +0 -0
- package/_entries/{88_children.md → 90_children.md} +0 -0
- package/_entries/{89_getdata.md → 91_getdata.md} +0 -0
- package/_entries/{90_getlevel.md → 92_getlevel.md} +0 -0
- package/_entries/{91_getnextnode.md → 93_getnextnode.md} +0 -0
- package/_entries/{92_getnextsibling.md → 94_getnextsibling.md} +0 -0
- package/_entries/{93_getpreviousnode.md → 95_getpreviousnode.md} +0 -0
- package/_entries/{94_getprevioussibling.md → 96_getprevioussibling.md} +0 -0
- package/_entries/{95_parent.md → 97_parent.md} +0 -0
- package/_examples/13_drag_outside.html +2 -1
- package/_examples/14_filter.html +113 -0
- package/_layouts/base.html +1 -23
- package/babel.config.json +11 -0
- package/babel.coverage.config.json +4 -0
- package/bower.json +1 -1
- package/jest-browser.config.js +0 -3
- package/jest-jsdom.config.js +1 -2
- package/jqtree.css +4 -1
- package/jqtree.postcss +3 -0
- package/lib/dataLoader.js +146 -98
- package/lib/dragAndDropHandler.js +668 -470
- package/lib/elementsRenderer.js +282 -197
- package/lib/jqtreeOptions.js +1 -2
- package/lib/keyHandler.js +134 -87
- package/lib/mouse.widget.js +288 -165
- package/lib/node.js +693 -505
- package/lib/nodeElement.js +329 -205
- package/lib/playwright/playwright.test.js +216 -189
- package/lib/playwright/testUtil.js +437 -192
- package/lib/playwright/visualRegression.js +183 -117
- package/lib/saveStateHandler.js +311 -204
- package/lib/scrollHandler.js +293 -199
- package/lib/selectNodeHandler.js +140 -105
- package/lib/simple.widget.js +184 -109
- package/lib/test/global.d.js +3 -0
- package/lib/test/jqTree/create.test.js +44 -40
- package/lib/test/jqTree/events.test.js +185 -138
- package/lib/test/jqTree/keyboard.test.js +216 -199
- package/lib/test/jqTree/loadOnDemand.test.js +233 -157
- package/lib/test/jqTree/methods.test.js +1269 -1000
- package/lib/test/jqTree/options.test.js +467 -398
- package/lib/test/node.test.js +1036 -873
- package/lib/test/nodeUtil.test.js +21 -20
- package/lib/test/support/exampleData.js +35 -23
- package/lib/test/support/jqTreeMatchers.js +72 -54
- package/lib/test/support/matchers.d.js +1 -0
- package/lib/test/support/setupTests.js +9 -3
- package/lib/test/support/testUtil.js +38 -15
- package/lib/test/support/treeStructure.js +41 -32
- package/lib/test/util.test.js +21 -20
- package/lib/tree.jquery.d.js +1 -0
- package/lib/tree.jquery.js +1264 -883
- package/lib/types.js +1 -2
- package/lib/typings.d.js +2 -0
- package/lib/util.js +21 -7
- package/lib/version.js +8 -3
- package/package.json +43 -36
- package/production +4 -4
- package/rollup.config.js +16 -11
- package/src/dataLoader.ts +6 -6
- package/src/dragAndDropHandler.ts +0 -4
- package/src/elementsRenderer.ts +4 -0
- package/src/jqtreeOptions.ts +33 -32
- package/src/mouse.widget.ts +58 -29
- package/src/node.ts +32 -46
- package/src/nodeElement.ts +17 -9
- package/src/playwright/.eslintrc +5 -0
- package/src/playwright/playwright.test.ts +30 -30
- package/src/playwright/testUtil.ts +36 -37
- package/src/saveStateHandler.ts +11 -6
- package/src/selectNodeHandler.ts +14 -21
- package/src/simple.widget.ts +1 -1
- package/src/test/.eslintrc +4 -0
- package/src/test/jqTree/create.test.ts +0 -1
- package/src/test/jqTree/events.test.ts +12 -13
- package/src/test/jqTree/keyboard.test.ts +0 -1
- package/src/test/jqTree/loadOnDemand.test.ts +46 -1
- package/src/test/jqTree/methods.test.ts +67 -18
- package/src/test/jqTree/options.test.ts +5 -6
- package/src/test/node.test.ts +2 -2
- package/src/test/support/jqTreeMatchers.ts +8 -9
- package/src/test/support/matchers.d.ts +2 -4
- package/src/test/support/setupTests.ts +2 -1
- package/src/tree.jquery.d.ts +19 -13
- package/src/tree.jquery.ts +63 -57
- package/src/version.ts +1 -1
- package/static/bower.json +3 -3
- package/static/bower_components/fontawesome/css/all.min.css +2 -2
- package/static/bower_components/fontawesome/webfonts/fa-brands-400.eot +0 -0
- package/static/bower_components/fontawesome/webfonts/fa-brands-400.svg +774 -627
- package/static/bower_components/fontawesome/webfonts/fa-brands-400.ttf +0 -0
- package/static/bower_components/fontawesome/webfonts/fa-brands-400.woff +0 -0
- package/static/bower_components/fontawesome/webfonts/fa-brands-400.woff2 +0 -0
- package/static/bower_components/fontawesome/webfonts/fa-regular-400.eot +0 -0
- package/static/bower_components/fontawesome/webfonts/fa-regular-400.svg +93 -95
- package/static/bower_components/fontawesome/webfonts/fa-regular-400.ttf +0 -0
- package/static/bower_components/fontawesome/webfonts/fa-regular-400.woff +0 -0
- package/static/bower_components/fontawesome/webfonts/fa-regular-400.woff2 +0 -0
- package/static/bower_components/fontawesome/webfonts/fa-solid-900.eot +0 -0
- package/static/bower_components/fontawesome/webfonts/fa-solid-900.svg +1164 -1074
- package/static/bower_components/fontawesome/webfonts/fa-solid-900.ttf +0 -0
- package/static/bower_components/fontawesome/webfonts/fa-solid-900.woff +0 -0
- package/static/bower_components/fontawesome/webfonts/fa-solid-900.woff2 +0 -0
- package/static/bower_components/jquery/dist/jquery.js +118 -109
- package/static/bower_components/jquery/dist/jquery.min.js +2 -2
- package/static/bower_components/jquery-mockjax/dist/jquery.mockjax.js +15 -9
- package/static/example.css +13 -0
- package/static/example.postcss +13 -0
- package/static/example_data.js +33 -36
- package/static/examples/filter.js +63 -0
- package/tree.jquery.debug.js +4809 -3305
- package/tree.jquery.debug.js.map +1 -1
- package/tree.jquery.js +3 -3
- package/tree.jquery.js.map +1 -1
- package/tsconfig.json +1 -0
- package/.travis.yml +0 -18
|
@@ -1,4 +1,3 @@
|
|
|
1
|
-
import * as $ from "jquery";
|
|
2
1
|
import getGiven from "givens";
|
|
3
2
|
import { screen } from "@testing-library/dom";
|
|
4
3
|
import { rest } from "msw";
|
|
@@ -106,6 +105,52 @@ context("when a node has load_on_demand in the data", () => {
|
|
|
106
105
|
}),
|
|
107
106
|
]);
|
|
108
107
|
});
|
|
108
|
+
|
|
109
|
+
context("when the node is selected and has the focus", () => {
|
|
110
|
+
beforeEach(() => {
|
|
111
|
+
given.$tree.tree("selectNode", given.node);
|
|
112
|
+
});
|
|
113
|
+
|
|
114
|
+
it("keeps the node selected and focused", async () => {
|
|
115
|
+
expect(given.node.element).toBeSelected();
|
|
116
|
+
expect(given.node.element).toBeFocused();
|
|
117
|
+
|
|
118
|
+
togglerLink(given.node.element).trigger("click");
|
|
119
|
+
await screen.findByText("loaded-on-demand");
|
|
120
|
+
|
|
121
|
+
expect(given.node.element).toBeSelected();
|
|
122
|
+
expect(given.node.element).toBeFocused();
|
|
123
|
+
});
|
|
124
|
+
});
|
|
125
|
+
|
|
126
|
+
context("when the node is not selected", () => {
|
|
127
|
+
it("doesn't select the node", async () => {
|
|
128
|
+
expect(given.node.element).not.toBeSelected();
|
|
129
|
+
|
|
130
|
+
togglerLink(given.node.element).trigger("click");
|
|
131
|
+
await screen.findByText("loaded-on-demand");
|
|
132
|
+
|
|
133
|
+
expect(given.node.element).not.toBeSelected();
|
|
134
|
+
});
|
|
135
|
+
});
|
|
136
|
+
|
|
137
|
+
context("when the node is selected and doesn't have the focus", () => {
|
|
138
|
+
beforeEach(() => {
|
|
139
|
+
given.$tree.tree("selectNode", given.node);
|
|
140
|
+
(document.activeElement as HTMLElement).blur();
|
|
141
|
+
});
|
|
142
|
+
|
|
143
|
+
it("keeps the node selected and not focused", async () => {
|
|
144
|
+
expect(given.node.element).toBeSelected();
|
|
145
|
+
expect(given.node.element).not.toBeFocused();
|
|
146
|
+
|
|
147
|
+
togglerLink(given.node.element).trigger("click");
|
|
148
|
+
await screen.findByText("loaded-on-demand");
|
|
149
|
+
|
|
150
|
+
expect(given.node.element).toBeSelected();
|
|
151
|
+
expect(given.node.element).not.toBeFocused();
|
|
152
|
+
});
|
|
153
|
+
});
|
|
109
154
|
});
|
|
110
155
|
|
|
111
156
|
context("with autoOpen is true", () => {
|
|
@@ -1,4 +1,3 @@
|
|
|
1
|
-
import * as $ from "jquery";
|
|
2
1
|
import getGiven from "givens";
|
|
3
2
|
import { screen } from "@testing-library/dom";
|
|
4
3
|
import { rest } from "msw";
|
|
@@ -312,15 +311,17 @@ describe("getNodeByHtmlElement", () => {
|
|
|
312
311
|
|
|
313
312
|
describe("getNodeById", () => {
|
|
314
313
|
interface Vars {
|
|
314
|
+
data: NodeData[];
|
|
315
315
|
$tree: JQuery<HTMLElement>;
|
|
316
316
|
}
|
|
317
317
|
|
|
318
318
|
const given = getGiven<Vars>();
|
|
319
|
+
given("data", () => exampleData);
|
|
319
320
|
given("$tree", () => $("#tree1"));
|
|
320
321
|
|
|
321
322
|
beforeEach(() => {
|
|
322
323
|
given.$tree.tree({
|
|
323
|
-
data:
|
|
324
|
+
data: given.data,
|
|
324
325
|
});
|
|
325
326
|
});
|
|
326
327
|
|
|
@@ -331,18 +332,40 @@ describe("getNodeById", () => {
|
|
|
331
332
|
});
|
|
332
333
|
|
|
333
334
|
context("with a string parameter", () => {
|
|
334
|
-
it("
|
|
335
|
-
expect(given.$tree.tree("getNodeById", "127")).
|
|
336
|
-
name: "node3",
|
|
337
|
-
});
|
|
335
|
+
it("doesn't return the node", () => {
|
|
336
|
+
expect(given.$tree.tree("getNodeById", "127")).toBeNull();
|
|
338
337
|
});
|
|
339
338
|
});
|
|
340
339
|
|
|
341
340
|
context("when the node doesn't exist", () => {
|
|
342
|
-
it("returns
|
|
341
|
+
it("returns null", () => {
|
|
343
342
|
expect(given.$tree.tree("getNodeById", 99999)).toBeNull();
|
|
344
343
|
});
|
|
345
344
|
});
|
|
345
|
+
|
|
346
|
+
context("when the data has string ids", () => {
|
|
347
|
+
given("data", () => [{ id: "123", name: "node1" }]);
|
|
348
|
+
|
|
349
|
+
context("with a string parameter", () => {
|
|
350
|
+
it("returns the node", () => {
|
|
351
|
+
expect(given.$tree.tree("getNodeById", "123")).toMatchObject({
|
|
352
|
+
name: "node1",
|
|
353
|
+
});
|
|
354
|
+
});
|
|
355
|
+
});
|
|
356
|
+
|
|
357
|
+
context("with a number parameter", () => {
|
|
358
|
+
it("doesn't return the node", () => {
|
|
359
|
+
expect(given.$tree.tree("getNodeById", 123)).toBeNull();
|
|
360
|
+
});
|
|
361
|
+
});
|
|
362
|
+
|
|
363
|
+
context("when the node doesn't exist", () => {
|
|
364
|
+
it("returns null", () => {
|
|
365
|
+
expect(given.$tree.tree("getNodeById", "abc")).toBeNull();
|
|
366
|
+
});
|
|
367
|
+
});
|
|
368
|
+
});
|
|
346
369
|
});
|
|
347
370
|
|
|
348
371
|
describe("getNodesByProperty", () => {
|
|
@@ -943,6 +966,38 @@ describe("prependNode", () => {
|
|
|
943
966
|
});
|
|
944
967
|
});
|
|
945
968
|
|
|
969
|
+
describe("refresh", () => {
|
|
970
|
+
interface Vars {
|
|
971
|
+
$tree: JQuery<HTMLElement>;
|
|
972
|
+
}
|
|
973
|
+
|
|
974
|
+
const given = getGiven<Vars>();
|
|
975
|
+
given("$tree", () => $("#tree1"));
|
|
976
|
+
|
|
977
|
+
beforeEach(() => {
|
|
978
|
+
given.$tree.tree({
|
|
979
|
+
data: exampleData,
|
|
980
|
+
});
|
|
981
|
+
});
|
|
982
|
+
|
|
983
|
+
it("rerenders the tree", () => {
|
|
984
|
+
const tree = given.$tree.tree("getTree");
|
|
985
|
+
tree.children[0].name = "node1a";
|
|
986
|
+
|
|
987
|
+
expect(given.$tree).toHaveTreeStructure([
|
|
988
|
+
expect.objectContaining({ name: "node1" }),
|
|
989
|
+
expect.objectContaining({ name: "node2" }),
|
|
990
|
+
]);
|
|
991
|
+
|
|
992
|
+
given.$tree.tree("refresh");
|
|
993
|
+
|
|
994
|
+
expect(given.$tree).toHaveTreeStructure([
|
|
995
|
+
expect.objectContaining({ name: "node1a" }),
|
|
996
|
+
expect.objectContaining({ name: "node2" }),
|
|
997
|
+
]);
|
|
998
|
+
});
|
|
999
|
+
});
|
|
1000
|
+
|
|
946
1001
|
describe("reload", () => {
|
|
947
1002
|
interface Vars {
|
|
948
1003
|
node1: INode;
|
|
@@ -991,7 +1046,7 @@ describe("reload", () => {
|
|
|
991
1046
|
|
|
992
1047
|
context("with a onFinished parameter", () => {
|
|
993
1048
|
it("calls onFinished", () =>
|
|
994
|
-
new Promise((resolve) => {
|
|
1049
|
+
new Promise<void>((resolve) => {
|
|
995
1050
|
const handleFinished = () => {
|
|
996
1051
|
expect(given.$tree).toHaveTreeStructure([
|
|
997
1052
|
expect.objectContaining({ name: "node1" }),
|
|
@@ -1125,7 +1180,7 @@ describe("selectNode", () => {
|
|
|
1125
1180
|
|
|
1126
1181
|
it("selects the node and deselects the previous node", () => {
|
|
1127
1182
|
expect(given.node1.element).toBeSelected();
|
|
1128
|
-
expect(given.node2.element).
|
|
1183
|
+
expect(given.node2.element).not.toBeSelected();
|
|
1129
1184
|
});
|
|
1130
1185
|
});
|
|
1131
1186
|
|
|
@@ -1146,7 +1201,7 @@ describe("selectNode", () => {
|
|
|
1146
1201
|
|
|
1147
1202
|
it("deselects the node", () => {
|
|
1148
1203
|
given.$tree.tree("selectNode", given.node1);
|
|
1149
|
-
expect(given.node1.element).
|
|
1204
|
+
expect(given.node1.element).not.toBeSelected();
|
|
1150
1205
|
});
|
|
1151
1206
|
});
|
|
1152
1207
|
|
|
@@ -1181,7 +1236,7 @@ describe("setOption", () => {
|
|
|
1181
1236
|
|
|
1182
1237
|
it("sets an option", () => {
|
|
1183
1238
|
given.$tree.tree("setOption", "selectable", true);
|
|
1184
|
-
titleSpan(given.node1.element).click
|
|
1239
|
+
titleSpan(given.node1.element).trigger("click");
|
|
1185
1240
|
expect(given.$tree.tree("getSelectedNode")).toMatchObject({
|
|
1186
1241
|
name: "node1",
|
|
1187
1242
|
});
|
|
@@ -1412,13 +1467,7 @@ describe("updateNode", () => {
|
|
|
1412
1467
|
});
|
|
1413
1468
|
|
|
1414
1469
|
it("keeps the focus on the node", () => {
|
|
1415
|
-
expect(
|
|
1416
|
-
expect(
|
|
1417
|
-
given.$tree.tree(
|
|
1418
|
-
"getNodeByHtmlElement",
|
|
1419
|
-
document.activeElement as HTMLElement
|
|
1420
|
-
)
|
|
1421
|
-
).not.toBeNil();
|
|
1470
|
+
expect(given.node.element).toBeFocused();
|
|
1422
1471
|
});
|
|
1423
1472
|
});
|
|
1424
1473
|
});
|
|
@@ -1,4 +1,3 @@
|
|
|
1
|
-
import * as $ from "jquery";
|
|
2
1
|
import getGiven from "givens";
|
|
3
2
|
import { screen } from "@testing-library/dom";
|
|
4
3
|
import { rest } from "msw";
|
|
@@ -364,7 +363,7 @@ describe("onLoadFailed", () => {
|
|
|
364
363
|
});
|
|
365
364
|
|
|
366
365
|
it("calls onLoadFailed", () =>
|
|
367
|
-
new Promise((done) => {
|
|
366
|
+
new Promise<void>((done) => {
|
|
368
367
|
given.$tree.tree({
|
|
369
368
|
dataUrl: "/tree/",
|
|
370
369
|
onLoadFailed: (jqXHR) => {
|
|
@@ -391,7 +390,7 @@ describe("rtl", () => {
|
|
|
391
390
|
});
|
|
392
391
|
|
|
393
392
|
it("has a different closed icon", () => {
|
|
394
|
-
expect(togglerLink(given.node1.element).text()).
|
|
393
|
+
expect(togglerLink(given.node1.element).text()).toBe("◀");
|
|
395
394
|
});
|
|
396
395
|
});
|
|
397
396
|
|
|
@@ -402,7 +401,7 @@ describe("rtl", () => {
|
|
|
402
401
|
});
|
|
403
402
|
|
|
404
403
|
it("has a different closed icon", () => {
|
|
405
|
-
expect(togglerLink(given.node1.element).text()).
|
|
404
|
+
expect(togglerLink(given.node1.element).text()).toBe("◀");
|
|
406
405
|
});
|
|
407
406
|
});
|
|
408
407
|
});
|
|
@@ -434,7 +433,7 @@ describe("saveState", () => {
|
|
|
434
433
|
given("saveState", () => true);
|
|
435
434
|
|
|
436
435
|
it("saves the state to local storage", () => {
|
|
437
|
-
expect(localStorage.getItem("tree")).
|
|
436
|
+
expect(localStorage.getItem("tree")).toBe(
|
|
438
437
|
'{"open_nodes":[123],"selected_node":[123]}'
|
|
439
438
|
);
|
|
440
439
|
});
|
|
@@ -444,7 +443,7 @@ describe("saveState", () => {
|
|
|
444
443
|
given("saveState", () => "my-state");
|
|
445
444
|
|
|
446
445
|
it("uses the string as a key", () => {
|
|
447
|
-
expect(localStorage.getItem("my-state")).
|
|
446
|
+
expect(localStorage.getItem("my-state")).toBe(
|
|
448
447
|
'{"open_nodes":[123],"selected_node":[123]}'
|
|
449
448
|
);
|
|
450
449
|
});
|
package/src/test/node.test.ts
CHANGED
|
@@ -855,13 +855,13 @@ describe("hasChildren", () => {
|
|
|
855
855
|
});
|
|
856
856
|
|
|
857
857
|
it("returns true", () => {
|
|
858
|
-
expect(given.node.hasChildren()).
|
|
858
|
+
expect(given.node.hasChildren()).toBe(true);
|
|
859
859
|
});
|
|
860
860
|
});
|
|
861
861
|
|
|
862
862
|
context("when a node doesn't have children", () => {
|
|
863
863
|
it("returns false", () => {
|
|
864
|
-
expect(given.node.hasChildren()).
|
|
864
|
+
expect(given.node.hasChildren()).toBe(false);
|
|
865
865
|
});
|
|
866
866
|
});
|
|
867
867
|
});
|
|
@@ -1,4 +1,5 @@
|
|
|
1
1
|
import treeStructure from "./treeStructure";
|
|
2
|
+
import { titleSpan } from "./testUtil";
|
|
2
3
|
|
|
3
4
|
const assertJqTreeFolder = ($el: JQuery<HTMLElement>) => {
|
|
4
5
|
/* istanbul ignore if */
|
|
@@ -8,15 +9,6 @@ const assertJqTreeFolder = ($el: JQuery<HTMLElement>) => {
|
|
|
8
9
|
};
|
|
9
10
|
|
|
10
11
|
expect.extend({
|
|
11
|
-
notToBeSelected(el: HTMLElement | JQuery<HTMLElement>) {
|
|
12
|
-
const $el = jQuery(el);
|
|
13
|
-
|
|
14
|
-
/* istanbul ignore next */
|
|
15
|
-
return {
|
|
16
|
-
message: () => "The node is selected",
|
|
17
|
-
pass: !$el.hasClass("jqtree-selected"),
|
|
18
|
-
};
|
|
19
|
-
},
|
|
20
12
|
toBeClosed(el: HTMLElement | JQuery<HTMLElement>) {
|
|
21
13
|
const $el = jQuery(el);
|
|
22
14
|
assertJqTreeFolder($el);
|
|
@@ -27,6 +19,13 @@ expect.extend({
|
|
|
27
19
|
pass: $el.hasClass("jqtree-closed"),
|
|
28
20
|
};
|
|
29
21
|
},
|
|
22
|
+
toBeFocused(el: HTMLElement | JQuery<HTMLElement>) {
|
|
23
|
+
/* istanbul ignore next */
|
|
24
|
+
return {
|
|
25
|
+
message: () => "The is node is not focused",
|
|
26
|
+
pass: document.activeElement === titleSpan(el)[0],
|
|
27
|
+
};
|
|
28
|
+
},
|
|
30
29
|
toBeOpen(el: HTMLElement | JQuery<HTMLElement>) {
|
|
31
30
|
const $el = jQuery(el);
|
|
32
31
|
assertJqTreeFolder($el);
|
|
@@ -22,12 +22,10 @@ declare namespace JQTreeMatchers {
|
|
|
22
22
|
declare namespace jest {
|
|
23
23
|
// eslint-disable-next-line @typescript-eslint/no-unused-vars
|
|
24
24
|
interface Matchers<R> {
|
|
25
|
-
notToBeSelected(): boolean;
|
|
26
25
|
toBeClosed(): boolean;
|
|
26
|
+
toBeFocused(): boolean;
|
|
27
27
|
toBeOpen(): boolean;
|
|
28
28
|
toBeSelected(): boolean;
|
|
29
|
-
toHaveTreeStructure(
|
|
30
|
-
treeStructure: JQTreeMatchers.TreeStructure
|
|
31
|
-
): boolean;
|
|
29
|
+
toHaveTreeStructure(treeStructure: any): boolean;
|
|
32
30
|
}
|
|
33
31
|
}
|
|
@@ -1,4 +1,5 @@
|
|
|
1
|
-
import
|
|
1
|
+
import jQuery from "jquery";
|
|
2
2
|
import "./jqTreeMatchers";
|
|
3
3
|
|
|
4
|
+
(window as any).$ = jQuery; // eslint-disable-line @typescript-eslint/no-unsafe-member-access
|
|
4
5
|
(window as any).jQuery = jQuery; // eslint-disable-line @typescript-eslint/no-unsafe-member-access
|
package/src/tree.jquery.d.ts
CHANGED
|
@@ -1,21 +1,26 @@
|
|
|
1
1
|
type NodeId = number | string;
|
|
2
2
|
|
|
3
|
-
|
|
4
|
-
|
|
3
|
+
interface NodeRecord {
|
|
4
|
+
[key: string]: unknown;
|
|
5
|
+
id?: NodeId;
|
|
6
|
+
children?: NodeData[];
|
|
7
|
+
}
|
|
8
|
+
|
|
9
|
+
type NodeData = string | NodeRecord;
|
|
5
10
|
|
|
6
11
|
type IterateCallback = (node: INode, level: number) => boolean;
|
|
7
12
|
|
|
8
|
-
|
|
9
|
-
|
|
10
|
-
|
|
11
|
-
|
|
12
|
-
|
|
13
|
-
|
|
14
|
-
|
|
13
|
+
interface INode {
|
|
14
|
+
id?: NodeId;
|
|
15
|
+
name: string;
|
|
16
|
+
children: INode[];
|
|
17
|
+
element: HTMLElement;
|
|
18
|
+
is_open: boolean;
|
|
19
|
+
parent: INode | null;
|
|
15
20
|
|
|
16
21
|
[key: string]: unknown;
|
|
17
22
|
|
|
18
|
-
|
|
23
|
+
iterate(callback: IterateCallback): void;
|
|
19
24
|
}
|
|
20
25
|
|
|
21
26
|
type DataUrlFunction = (node?: Node) => JQuery.AjaxSettings;
|
|
@@ -41,7 +46,7 @@ interface IJQTreeOptions {
|
|
|
41
46
|
buttonLeft?: boolean;
|
|
42
47
|
closedIcon?: string | Element;
|
|
43
48
|
data?: NodeData[];
|
|
44
|
-
dataFilter?: (data:
|
|
49
|
+
dataFilter?: (data: NodeData[]) => NodeData[];
|
|
45
50
|
dataUrl?: DataUrl;
|
|
46
51
|
dragAndDrop?: boolean;
|
|
47
52
|
nodeClass?: any;
|
|
@@ -63,6 +68,7 @@ interface IJQTreeOptions {
|
|
|
63
68
|
saveState?: boolean | string;
|
|
64
69
|
slide?: boolean;
|
|
65
70
|
showEmptyFolder?: boolean;
|
|
71
|
+
startDndDelay?: number;
|
|
66
72
|
tabIndex?: number;
|
|
67
73
|
useContextMenu?: boolean;
|
|
68
74
|
}
|
|
@@ -134,14 +140,14 @@ interface IJQTreePlugin {
|
|
|
134
140
|
onFinished?: (node: INode) => void
|
|
135
141
|
): JQuery;
|
|
136
142
|
(behavior: "prependNode", newNodeInfo: NodeData, parentNode?: INode): INode;
|
|
143
|
+
(behavior: "refresh"): JQuery;
|
|
137
144
|
(behavior: "reload", onFinished?: () => void): JQuery;
|
|
138
145
|
(behavior: "removeFromSelection", node: INode): JQuery;
|
|
139
146
|
(behavior: "removeNode", node: INode): JQuery;
|
|
140
147
|
(behavior: "scrollToNode", node: INode): JQuery;
|
|
141
148
|
(behavior: "selectNode", node: INode | null): JQuery;
|
|
142
|
-
(behavior: "setMouseDelay", delay: number): void;
|
|
143
149
|
(behavior: "setOption", option: string, value: unknown): JQuery;
|
|
144
|
-
(behavior: "setState", options:
|
|
150
|
+
(behavior: "setState", options: Record<string, unknown>): JQuery;
|
|
145
151
|
(behavior: "toggle", node: INode, slideParam?: boolean): JQuery;
|
|
146
152
|
(behavior: "toJson"): string;
|
|
147
153
|
(behavior: "updateNode", node: INode, data: NodeData): JQuery;
|
package/src/tree.jquery.ts
CHANGED
|
@@ -1,23 +1,19 @@
|
|
|
1
1
|
import __version__ from "./version";
|
|
2
|
-
import * as jQueryProxy from "jquery";
|
|
3
2
|
import { DragAndDropHandler } from "./dragAndDropHandler";
|
|
4
3
|
import ElementsRenderer from "./elementsRenderer";
|
|
5
4
|
import DataLoader, { HandleFinishedLoading } from "./dataLoader";
|
|
6
5
|
import KeyHandler from "./keyHandler";
|
|
7
6
|
import MouseWidget from "./mouse.widget";
|
|
8
7
|
import { PositionInfo } from "./types";
|
|
9
|
-
import SaveStateHandler from "./saveStateHandler";
|
|
8
|
+
import SaveStateHandler, { SavedState } from "./saveStateHandler";
|
|
10
9
|
import ScrollHandler from "./scrollHandler";
|
|
11
10
|
import SelectNodeHandler from "./selectNodeHandler";
|
|
12
11
|
import SimpleWidget from "./simple.widget";
|
|
13
|
-
import { Node,
|
|
12
|
+
import { Node, getPosition } from "./node";
|
|
14
13
|
import { isFunction } from "./util";
|
|
15
14
|
import { FolderElement, NodeElement, OnFinishOpenNode } from "./nodeElement";
|
|
16
15
|
import { JQTreeOptions } from "./jqtreeOptions";
|
|
17
16
|
|
|
18
|
-
// eslint-disable-next-line @typescript-eslint/no-unsafe-assignment, @typescript-eslint/no-unsafe-member-access
|
|
19
|
-
const jQuery: JQueryStatic = (<any>jQueryProxy).default || jQueryProxy;
|
|
20
|
-
|
|
21
17
|
interface ClickTarget {
|
|
22
18
|
node: Node;
|
|
23
19
|
type: "button" | "label";
|
|
@@ -34,45 +30,41 @@ const PARAM_IS_EMPTY = "Parameter is empty: ";
|
|
|
34
30
|
export class JqTreeWidget extends MouseWidget<JQTreeOptions> {
|
|
35
31
|
protected static defaults: JQTreeOptions = {
|
|
36
32
|
animationSpeed: "fast",
|
|
37
|
-
autoOpen: false, // true / false / int (open n levels starting at 0)
|
|
38
|
-
saveState: false, // true / false / string (cookie name)
|
|
39
|
-
dragAndDrop: false,
|
|
40
|
-
selectable: true,
|
|
41
|
-
useContextMenu: true,
|
|
42
|
-
onCanSelectNode: undefined,
|
|
43
|
-
onSetStateFromStorage: undefined,
|
|
44
|
-
onGetStateFromStorage: undefined,
|
|
45
|
-
onCreateLi: undefined,
|
|
46
|
-
onIsMoveHandle: undefined,
|
|
47
|
-
|
|
48
|
-
// Can this node be moved?
|
|
49
|
-
onCanMove: undefined,
|
|
50
|
-
|
|
51
|
-
// Can this node be moved to this position? function(moved_node, target_node, position)
|
|
52
|
-
onCanMoveTo: undefined,
|
|
53
|
-
onLoadFailed: undefined,
|
|
54
33
|
autoEscape: true,
|
|
55
|
-
|
|
56
|
-
|
|
34
|
+
autoOpen: false, // true / false / int (open n levels starting at 0)
|
|
35
|
+
buttonLeft: true,
|
|
57
36
|
// The symbol to use for a closed node - ► BLACK RIGHT-POINTING POINTER
|
|
58
37
|
// http://www.fileformat.info/info/unicode/char/25ba/index.htm
|
|
59
38
|
closedIcon: undefined,
|
|
60
|
-
|
|
61
|
-
// The symbol to use for an open node - ▼ BLACK DOWN-POINTING TRIANGLE
|
|
62
|
-
// http://www.fileformat.info/info/unicode/char/25bc/index.htm
|
|
63
|
-
openedIcon: "▼",
|
|
64
|
-
slide: true, // must display slide animation?
|
|
65
|
-
nodeClass: Node,
|
|
39
|
+
data: undefined,
|
|
66
40
|
dataFilter: undefined,
|
|
41
|
+
dataUrl: undefined,
|
|
42
|
+
dragAndDrop: false,
|
|
67
43
|
keyboardSupport: true,
|
|
68
|
-
|
|
69
|
-
|
|
44
|
+
nodeClass: Node,
|
|
45
|
+
onCanMove: undefined, // Can this node be moved?
|
|
46
|
+
onCanMoveTo: undefined, // Can this node be moved to this position? function(moved_node, target_node, position)
|
|
47
|
+
onCanSelectNode: undefined,
|
|
48
|
+
onCreateLi: undefined,
|
|
70
49
|
onDragMove: undefined,
|
|
71
50
|
onDragStop: undefined,
|
|
72
|
-
|
|
51
|
+
onGetStateFromStorage: undefined,
|
|
52
|
+
onIsMoveHandle: undefined,
|
|
53
|
+
onLoadFailed: undefined,
|
|
73
54
|
onLoading: undefined,
|
|
55
|
+
onSetStateFromStorage: undefined,
|
|
56
|
+
openedIcon: "▼",
|
|
57
|
+
openFolderDelay: 500, // The delay for opening a folder during drag and drop; the value is in milliseconds
|
|
58
|
+
// The symbol to use for an open node - ▼ BLACK DOWN-POINTING TRIANGLE
|
|
59
|
+
// http://www.fileformat.info/info/unicode/char/25bc/index.htm
|
|
60
|
+
rtl: undefined, // right-to-left support; true / false (default)
|
|
61
|
+
saveState: false, // true / false / string (cookie name)
|
|
62
|
+
selectable: true,
|
|
74
63
|
showEmptyFolder: false,
|
|
64
|
+
slide: true, // must display slide animation?
|
|
65
|
+
startDndDelay: 300, // The delay for starting dnd (in milliseconds)
|
|
75
66
|
tabIndex: 0,
|
|
67
|
+
useContextMenu: true,
|
|
76
68
|
};
|
|
77
69
|
|
|
78
70
|
public element: JQuery;
|
|
@@ -171,6 +163,11 @@ export class JqTreeWidget extends MouseWidget<JQTreeOptions> {
|
|
|
171
163
|
return this.element;
|
|
172
164
|
}
|
|
173
165
|
|
|
166
|
+
public refresh(): JQuery {
|
|
167
|
+
this._refreshElements(null);
|
|
168
|
+
return this.element;
|
|
169
|
+
}
|
|
170
|
+
|
|
174
171
|
public getNodeById(nodeId: NodeId): Node | null {
|
|
175
172
|
return this.tree.getNodeById(nodeId);
|
|
176
173
|
}
|
|
@@ -370,19 +367,12 @@ export class JqTreeWidget extends MouseWidget<JQTreeOptions> {
|
|
|
370
367
|
node.removeChildren();
|
|
371
368
|
|
|
372
369
|
if (data.children.length) {
|
|
373
|
-
node.loadFromData(data.children);
|
|
370
|
+
node.loadFromData(data.children as Node[]);
|
|
374
371
|
}
|
|
375
372
|
}
|
|
376
373
|
|
|
377
|
-
const mustSetFocus = this.selectNodeHandler.isFocusOnTree();
|
|
378
|
-
const mustSelect = this.isSelectedNodeInSubtree(node);
|
|
379
|
-
|
|
380
374
|
this._refreshElements(node);
|
|
381
375
|
|
|
382
|
-
if (mustSelect) {
|
|
383
|
-
this.selectCurrentNode(mustSetFocus);
|
|
384
|
-
}
|
|
385
|
-
|
|
386
376
|
return this.element;
|
|
387
377
|
}
|
|
388
378
|
|
|
@@ -490,7 +480,7 @@ export class JqTreeWidget extends MouseWidget<JQTreeOptions> {
|
|
|
490
480
|
}
|
|
491
481
|
|
|
492
482
|
public setOption(option: string, value: unknown): JQuery {
|
|
493
|
-
(this.options as Record<string, unknown>)[option] = value;
|
|
483
|
+
(this.options as unknown as Record<string, unknown>)[option] = value;
|
|
494
484
|
return this.element;
|
|
495
485
|
}
|
|
496
486
|
|
|
@@ -518,7 +508,7 @@ export class JqTreeWidget extends MouseWidget<JQTreeOptions> {
|
|
|
518
508
|
|
|
519
509
|
public _triggerEvent(
|
|
520
510
|
eventName: string,
|
|
521
|
-
values?:
|
|
511
|
+
values?: Record<string, unknown>
|
|
522
512
|
): JQuery.Event {
|
|
523
513
|
const event = jQuery.Event(eventName, values);
|
|
524
514
|
this.element.trigger(event);
|
|
@@ -532,7 +522,7 @@ export class JqTreeWidget extends MouseWidget<JQTreeOptions> {
|
|
|
532
522
|
): void {
|
|
533
523
|
const doOpenNode = (
|
|
534
524
|
_node: Node,
|
|
535
|
-
_slide:
|
|
525
|
+
_slide: boolean,
|
|
536
526
|
_onFinished: OnFinishOpenNode | null
|
|
537
527
|
): void => {
|
|
538
528
|
const folderElement = new FolderElement(_node, this);
|
|
@@ -568,8 +558,17 @@ export class JqTreeWidget extends MouseWidget<JQTreeOptions> {
|
|
|
568
558
|
from_node: redraw this subtree
|
|
569
559
|
*/
|
|
570
560
|
public _refreshElements(fromNode: Node | null): void {
|
|
561
|
+
const mustSetFocus = this.selectNodeHandler.isFocusOnTree();
|
|
562
|
+
const mustSelect = fromNode
|
|
563
|
+
? this.isSelectedNodeInSubtree(fromNode)
|
|
564
|
+
: false;
|
|
565
|
+
|
|
571
566
|
this.renderer.render(fromNode);
|
|
572
567
|
|
|
568
|
+
if (mustSelect) {
|
|
569
|
+
this.selectCurrentNode(mustSetFocus);
|
|
570
|
+
}
|
|
571
|
+
|
|
573
572
|
this._triggerEvent("tree.refresh");
|
|
574
573
|
}
|
|
575
574
|
|
|
@@ -604,7 +603,6 @@ export class JqTreeWidget extends MouseWidget<JQTreeOptions> {
|
|
|
604
603
|
super.init();
|
|
605
604
|
|
|
606
605
|
this.element = this.$el;
|
|
607
|
-
this.mouseDelay = 300;
|
|
608
606
|
this.isInitialized = false;
|
|
609
607
|
|
|
610
608
|
this.options.rtl = this.getRtlOption();
|
|
@@ -677,6 +675,10 @@ export class JqTreeWidget extends MouseWidget<JQTreeOptions> {
|
|
|
677
675
|
}
|
|
678
676
|
}
|
|
679
677
|
|
|
678
|
+
protected getMouseDelay(): number {
|
|
679
|
+
return this.options.startDndDelay ?? 0;
|
|
680
|
+
}
|
|
681
|
+
|
|
680
682
|
private initData(): void {
|
|
681
683
|
if (this.options.data) {
|
|
682
684
|
this.doLoadData(this.options.data, null);
|
|
@@ -738,7 +740,7 @@ export class JqTreeWidget extends MouseWidget<JQTreeOptions> {
|
|
|
738
740
|
}
|
|
739
741
|
}
|
|
740
742
|
|
|
741
|
-
private initTree(data:
|
|
743
|
+
private initTree(data: NodeData[]): void {
|
|
742
744
|
const doInit = (): void => {
|
|
743
745
|
if (!this.isInitialized) {
|
|
744
746
|
this.isInitialized = true;
|
|
@@ -785,9 +787,8 @@ export class JqTreeWidget extends MouseWidget<JQTreeOptions> {
|
|
|
785
787
|
if (!state) {
|
|
786
788
|
return [false, false];
|
|
787
789
|
} else {
|
|
788
|
-
const mustLoadOnDemand =
|
|
789
|
-
state
|
|
790
|
-
);
|
|
790
|
+
const mustLoadOnDemand =
|
|
791
|
+
this.saveStateHandler.setInitialState(state);
|
|
791
792
|
|
|
792
793
|
// return true: the state is restored
|
|
793
794
|
return [true, mustLoadOnDemand];
|
|
@@ -902,7 +903,9 @@ export class JqTreeWidget extends MouseWidget<JQTreeOptions> {
|
|
|
902
903
|
}
|
|
903
904
|
}
|
|
904
905
|
|
|
905
|
-
private handleClick = (
|
|
906
|
+
private handleClick = (
|
|
907
|
+
e: JQuery.ClickEvent<HTMLElement, any, HTMLElement, HTMLElement>
|
|
908
|
+
): void => {
|
|
906
909
|
const clickTarget = this.getClickTarget(e.target);
|
|
907
910
|
|
|
908
911
|
if (clickTarget) {
|
|
@@ -925,7 +928,9 @@ export class JqTreeWidget extends MouseWidget<JQTreeOptions> {
|
|
|
925
928
|
}
|
|
926
929
|
};
|
|
927
930
|
|
|
928
|
-
private handleDblclick = (
|
|
931
|
+
private handleDblclick = (
|
|
932
|
+
e: JQuery.DoubleClickEvent<HTMLElement, any, HTMLElement, HTMLElement>
|
|
933
|
+
): void => {
|
|
929
934
|
const clickTarget = this.getClickTarget(e.target);
|
|
930
935
|
|
|
931
936
|
if (clickTarget?.type === "label") {
|
|
@@ -975,7 +980,9 @@ export class JqTreeWidget extends MouseWidget<JQTreeOptions> {
|
|
|
975
980
|
}
|
|
976
981
|
}
|
|
977
982
|
|
|
978
|
-
private handleContextmenu = (
|
|
983
|
+
private handleContextmenu = (
|
|
984
|
+
e: JQuery.ContextMenuEvent<HTMLElement, any, HTMLElement, HTMLElement>
|
|
985
|
+
) => {
|
|
979
986
|
const $div = jQuery(e.target).closest("ul.jqtree-tree .jqtree-element");
|
|
980
987
|
if ($div.length) {
|
|
981
988
|
const node = this.getNode($div);
|
|
@@ -1130,15 +1137,14 @@ export class JqTreeWidget extends MouseWidget<JQTreeOptions> {
|
|
|
1130
1137
|
}
|
|
1131
1138
|
|
|
1132
1139
|
private deselectNodes(parentNode: Node): void {
|
|
1133
|
-
const selectedNodesUnderParent =
|
|
1134
|
-
parentNode
|
|
1135
|
-
);
|
|
1140
|
+
const selectedNodesUnderParent =
|
|
1141
|
+
this.selectNodeHandler.getSelectedNodesUnder(parentNode);
|
|
1136
1142
|
for (const n of selectedNodesUnderParent) {
|
|
1137
1143
|
this.selectNodeHandler.removeFromSelection(n);
|
|
1138
1144
|
}
|
|
1139
1145
|
}
|
|
1140
1146
|
|
|
1141
|
-
private loadSubtree(data:
|
|
1147
|
+
private loadSubtree(data: NodeData[], parentNode: Node): void {
|
|
1142
1148
|
parentNode.loadFromData(data);
|
|
1143
1149
|
|
|
1144
1150
|
parentNode.load_on_demand = false;
|
package/src/version.ts
CHANGED