mirror of
https://github.com/koalyptus/TableFilter.git
synced 2024-06-15 20:25:07 +02:00
Compare commits
781 commits
Author | SHA1 | Date | |
---|---|---|---|
7afe45f1e6 | |||
6e01e45dfb | |||
12c30629af | |||
3e763efac9 | |||
825b915ae8 | |||
8e48bf2943 | |||
be7a5e585f | |||
c44bef22a2 | |||
6dcebbf67e | |||
44cb6f9124 | |||
571c31e8da | |||
8633891fdb | |||
8eddc6f35c | |||
577fb0b90a | |||
88a5bfe425 | |||
cac2900444 | |||
5dad4dae8e | |||
134851525c | |||
9a66748bb8 | |||
c52004421f | |||
f53b392c59 | |||
c496b0916d | |||
25b89b19e7 | |||
8b4a05be02 | |||
1c4961a25b | |||
40daf54768 | |||
c43debc7ac | |||
3ac2603e47 | |||
185c119342 | |||
80c9b3d734 | |||
e8605e5e19 | |||
bd95afb3eb | |||
c16f885951 | |||
6be9ad491f | |||
447a3119aa | |||
2025aa4010 | |||
bdc03755e8 | |||
2dceed888e | |||
982769a020 | |||
4318826ead | |||
66b8fa9d94 | |||
79cea3e27f | |||
7af493da27 | |||
90c3b7f937 | |||
85dce5847a | |||
65863b635a | |||
3c001f52e2 | |||
e3957977b6 | |||
8923c4db94 | |||
c7d1a25467 | |||
ebdd817199 | |||
27365e25d4 | |||
2e960867ab | |||
3d35d53005 | |||
02bc5e3ae1 | |||
09c1f8ff52 | |||
6b339f7bd7 | |||
a1efe26a85 | |||
64e6c6597f | |||
9363a7a661 | |||
41e220efa9 | |||
64d3808a2b | |||
eb15788965 | |||
fede2f6e86 | |||
9738c8ed91 | |||
b285d01b54 | |||
37eed72f2c | |||
71103cd04b | |||
42a347550b | |||
bed04b5b9b | |||
43fc68df31 | |||
d116525f73 | |||
d7ff36514d | |||
0d0abf3206 | |||
4cd004e423 | |||
459829a214 | |||
b8c0c1bc3f | |||
5686e8a470 | |||
b04d4f55ed | |||
3004963058 | |||
3454187be6 | |||
1dac7736b1 | |||
2c7ad88346 | |||
6e41c4a8c6 | |||
859f6b1eeb | |||
7204c4b546 | |||
f29b59fdbd | |||
6cc887e806 | |||
f7ad9741ca | |||
323a80d1d7 | |||
fc46f0b4ae | |||
0471570985 | |||
20243b641f | |||
99722cbdb0 | |||
64cc6825c5 | |||
bcb541fcad | |||
1c3c1bbb0a | |||
bba009c505 | |||
48659ec1d5 | |||
1d32dcea7d | |||
0e1c617b06 | |||
5c705fe591 | |||
3c501e3aef | |||
78ae09c861 | |||
2e1af5efb3 | |||
da270df5d6 | |||
8a8419bf02 | |||
a6c24c7885 | |||
ed2fef999a | |||
47c66d71bb | |||
f99f850c4d | |||
10c06b5100 | |||
1cc810c341 | |||
c707978e19 | |||
32b541239e | |||
2963962250 | |||
bbec44cc15 | |||
352a700fb2 | |||
fae4ec9e07 | |||
226f18a6f6 | |||
1d58191127 | |||
1559c74fd9 | |||
2cd30b1bfb | |||
cd5e5589a4 | |||
5499093810 | |||
df54ddda33 | |||
80ebc0aa8c | |||
a5fa336a08 | |||
36d4f85f6c | |||
e886a6f1a8 | |||
7204746e5f | |||
ecd33d0631 | |||
f97394fc32 | |||
eef0ab3bbd | |||
c48b48f924 | |||
d699d02914 | |||
09b3f7875d | |||
9c54974338 | |||
b89a52fb77 | |||
ef46fd4295 | |||
8d8c8ae74c | |||
fafa983dac | |||
a19c5a106f | |||
1e391233dc | |||
aade342976 | |||
0443442916 | |||
ed4979331c | |||
0e1a1ff3d1 | |||
e71b3a5c93 | |||
a22b009c57 | |||
f6a9a058c9 | |||
f7c231b99f | |||
6f4e5a91ab | |||
f405a45d79 | |||
fbe43b1db4 | |||
e13201733d | |||
002c46297e | |||
017337b2e2 | |||
51679ad61b | |||
bc34e8b187 | |||
58e90cb766 | |||
3243fad4da | |||
ea2a8be8b6 | |||
5e1fe901b7 | |||
c001e90617 | |||
a446c0afc0 | |||
ff88f6c7d7 | |||
d46265eb57 | |||
3057b1949c | |||
bca2cee175 | |||
077eb3fe87 | |||
90e4367951 | |||
589b356bc6 | |||
7664e054e5 | |||
2dcad20d0c | |||
86369ff116 | |||
f1bdd8997f | |||
eefbf3fe41 | |||
0b455e2ec4 | |||
de6745821f | |||
f79234ea7e | |||
8bcf731d3c | |||
5247493035 | |||
69a1fd3ee9 | |||
9c80252935 | |||
c22f9981e6 | |||
04012e5a97 | |||
02997076d4 | |||
9117097750 | |||
e3f9851848 | |||
f1febe1688 | |||
cf9a566e92 | |||
34e8b4099b | |||
495b64ecf0 | |||
0a69a99dc5 | |||
2d9671e10d | |||
0f380c03da | |||
df85babf34 | |||
131280c1a3 | |||
372473227c | |||
cb7fc0d4fa | |||
c3b5ef529c | |||
89b1814c2d | |||
9a1202c0b5 | |||
95475b022d | |||
8b1d3a6e23 | |||
6b2fbd1eef | |||
8d1dc88f6a | |||
34c56e5765 | |||
87ee312fc5 | |||
df0221d5e7 | |||
528d587a80 | |||
b8bdff83aa | |||
d40244b7e5 | |||
ec7799b57b | |||
fa28abbee8 | |||
e06dfbdc35 | |||
64f56c22a4 | |||
ecfa6c64ad | |||
37f6db7025 | |||
bfa440b265 | |||
bf9cbd0a69 | |||
967ae801b4 | |||
066c5fee56 | |||
807c191a01 | |||
9382a07c7b | |||
8b09b6feab | |||
d733766621 | |||
ceba24d727 | |||
c25cae1679 | |||
04342ac316 | |||
0ad57767f8 | |||
fd56dabea8 | |||
0b11de4f90 | |||
bbd0ce06ce | |||
500344c64a | |||
5845f8c52d | |||
d232f64fa5 | |||
53a77d1b97 | |||
44ce01be4b | |||
1f17364a00 | |||
a437dad841 | |||
99b34c07b4 | |||
ff977281c7 | |||
bf667cdd6f | |||
94d6d59593 | |||
1fc5fa5f8a | |||
34d35a3495 | |||
9750b07e06 | |||
bfe6b6dc2c | |||
67b1d4b65e | |||
c7482bec2d | |||
b38bc836ee | |||
79d06ff09e | |||
bd6afe484c | |||
6560392771 | |||
599717ae14 | |||
e96273e95f | |||
dcc0a43258 | |||
31ece0ff81 | |||
db0c95e197 | |||
2945c27ae9 | |||
786bb519b0 | |||
db1ecaec42 | |||
3f74756d58 | |||
dca79c8391 | |||
dd6de7f219 | |||
4e222fd98c | |||
e45c7ce863 | |||
b45815cfc7 | |||
481c7c3970 | |||
6b47928c92 | |||
259a88d0c5 | |||
91ec79d226 | |||
6630a87263 | |||
4d4d1f4212 | |||
7631b51f3d | |||
5bde707a0c | |||
2cea817247 | |||
68acd1fcb7 | |||
4d424d1d7e | |||
50fda2a900 | |||
335f97a9de | |||
a7e0f235a3 | |||
d6a79e14fc | |||
7e780f3463 | |||
439f183d95 | |||
10b80612fe | |||
72327b84cc | |||
ba5323ab3b | |||
a9c0fd9c2f | |||
e6049975ee | |||
62a55c8d95 | |||
5d4def11fc | |||
13eb677b8e | |||
d48bbeaab5 | |||
6fec4947c4 | |||
d3634bce5f | |||
6813debb6e | |||
b14667a345 | |||
2f825a25b4 | |||
cca223c4d4 | |||
09243a9bdb | |||
24e0f3d184 | |||
d70cf23624 | |||
2d963e782f | |||
c100f0f63f | |||
875fdc2603 | |||
4bdf873ec8 | |||
d1875f19f2 | |||
5254983778 | |||
7e13d59d0f | |||
a66402e139 | |||
8cb8f74fa3 | |||
c5775ae8aa | |||
a10d3a2830 | |||
2e089a1823 | |||
3231da9760 | |||
7533499c40 | |||
80cf351eab | |||
d790156373 | |||
70d791f41c | |||
f1f28b51cb | |||
8a94f2ffd2 | |||
a0f9f28397 | |||
71292db999 | |||
42a40a295b | |||
7a90cb5b13 | |||
7eecd95122 | |||
a45217bc9f | |||
d14a0a359a | |||
e09bab000b | |||
efffa40248 | |||
50afb94340 | |||
d35ea7cb26 | |||
52705e56f7 | |||
b34e5696f3 | |||
606cc00393 | |||
c728209c92 | |||
2e3bdda8bc | |||
7bc7b16cfc | |||
c5bc7cbb33 | |||
ec6d0779a1 | |||
bcbfe5251f | |||
453ff1c59c | |||
948055da09 | |||
f534a8b23f | |||
6c23ae883f | |||
55e4d6b511 | |||
2d5f7401f9 | |||
00143a686b | |||
46f7028580 | |||
313336ab5f | |||
89851eae3b | |||
e49538c442 | |||
cb0aa73a6d | |||
9b89b78f38 | |||
1a32ef216b | |||
bcf7189bbc | |||
9a55c86e5f | |||
c710fa3585 | |||
a5164f4ba5 | |||
0babe0249e | |||
ca4f0f2afa | |||
00150bc9e1 | |||
46b21b4a20 | |||
89b0cf843a | |||
946f600260 | |||
0cd8fb2aa3 | |||
ad8c86c599 | |||
bf1bdc5a0e | |||
ed01c6e201 | |||
b4905f7703 | |||
2cc28e8072 | |||
521d02c374 | |||
fe51fdecb8 | |||
bfa23c3b6e | |||
2abd81906b | |||
f1e046e331 | |||
ea8ca2a125 | |||
6bc6c8a8eb | |||
c0520dd4bb | |||
3d7945b09c | |||
84c964bf13 | |||
c7d6de72f7 | |||
81f31a3106 | |||
3995dee394 | |||
7540169fcd | |||
4bff89b70c | |||
c8df8992b3 | |||
4889b29cda | |||
b3101a8871 | |||
bf2f2bd747 | |||
b08b517fa7 | |||
f2c5edbfb8 | |||
ca6ced712a | |||
0d95699fa6 | |||
4378141d7d | |||
0631fd2ef7 | |||
7cbb38d9ba | |||
edd2494899 | |||
49eb4b7bd6 | |||
5d4627277a | |||
907ccd5e4a | |||
c26e6d3c4b | |||
e1106f23a8 | |||
7909cde78b | |||
bc416e0e39 | |||
934ba4add0 | |||
73fc78e9e3 | |||
c1000b7684 | |||
a34009f1e9 | |||
51e27c4a2f | |||
2fee4d95f2 | |||
5b6919ba39 | |||
974bb3cc77 | |||
1a1560d636 | |||
2d3f67d504 | |||
81c593382a | |||
62cab3ac2c | |||
4ac92a3e73 | |||
da8977433d | |||
cde2e8a326 | |||
7b03e23f3c | |||
dc3d40b12c | |||
48674c3b31 | |||
a92acfa615 | |||
be1bdf72cd | |||
b6d9bddc6f | |||
025717f61c | |||
e09d30c2cd | |||
39bbe6a19a | |||
2f7b650f5b | |||
85092bbd1c | |||
3bed943a42 | |||
2452a0bd9e | |||
98aca44cb9 | |||
33ed3cc194 | |||
2da8a56659 | |||
71d5cd7a49 | |||
05c2d6b666 | |||
50f4a0014b | |||
07eebbd528 | |||
9ccc4dbfd4 | |||
9d184df49a | |||
d664ebb780 | |||
0226300af8 | |||
1e8e4a6467 | |||
0ec96ed520 | |||
11d01b1661 | |||
2d0219b54d | |||
317d795974 | |||
f2f853c517 | |||
9468602f3d | |||
cc0932f5f7 | |||
f97ff3a52d | |||
8575d0ea68 | |||
d274876976 | |||
a9737da2f6 | |||
62964c2478 | |||
71e7012ba0 | |||
4a3fbbb736 | |||
ee128f9d80 | |||
9b29d1632e | |||
1946d75125 | |||
83ff0aab79 | |||
8dbc307a39 | |||
c7eefc8ddc | |||
0e2d17714d | |||
650959237b | |||
4a10876a96 | |||
d5ef7afa1e | |||
4cf9a4081d | |||
c1e26349ef | |||
16b2997a71 | |||
ab273644e5 | |||
731909a267 | |||
7f75e23b1b | |||
55eadd72eb | |||
4855c9064b | |||
032bdd53b0 | |||
f73aa02733 | |||
029f2c35e8 | |||
52a514088b | |||
c7756d8d58 | |||
054423f10d | |||
cccc4b71cf | |||
db2bb7de18 | |||
740cce0551 | |||
f6a93f7f00 | |||
b6db436bca | |||
158c8835f9 | |||
7a2bc50a56 | |||
74cea36219 | |||
2deeb5d57a | |||
619c272469 | |||
7862bc68d0 | |||
e2e8331a08 | |||
3134ee804b | |||
1c930a0184 | |||
51f188e63f | |||
2ca11374a0 | |||
79367df924 | |||
fe384896d5 | |||
f8c5d081d4 | |||
3ff774d78f | |||
33ae62cab7 | |||
8be5990a02 | |||
88d31090b4 | |||
fbfa2fdf96 | |||
f447199905 | |||
be67034e02 | |||
a01c914f0a | |||
c288fe44ce | |||
dc05239d57 | |||
42fb561866 | |||
95c8206eb7 | |||
26beced5c7 | |||
cf7a53354d | |||
653b1ce006 | |||
d69f60aced | |||
949f21f446 | |||
722c420dc6 | |||
590dd8316c | |||
376102c801 | |||
a243c96dd3 | |||
631f6bdb5c | |||
fc089f1b73 | |||
dfa93b378b | |||
0affe2c187 | |||
8231252f34 | |||
75faca6e8d | |||
4a6ae393a5 | |||
0e669bcc45 | |||
08fb37b982 | |||
bde954e570 | |||
78f6df704b | |||
7cf9be1342 | |||
86a650ff6d | |||
13adb6fb3a | |||
f2d54839c3 | |||
9abc9802bd | |||
82a03d428c | |||
0b5160b45d | |||
fca1fcf23c | |||
e311aa36f1 | |||
9b54c10bc6 | |||
eb62703e50 | |||
81062452e2 | |||
6e72912c90 | |||
52999f000e | |||
6999b0c7f9 | |||
e205a6b15a | |||
fbeb52bda2 | |||
465b216e01 | |||
ff622ea585 | |||
6a0179681b | |||
68adc86cbc | |||
e661005ff8 | |||
a861cff760 | |||
12e4052a9f | |||
e9441fe1d5 | |||
175a23934f | |||
a757bd02fa | |||
b03ec21a28 | |||
5f66df7e6a | |||
5a10841f84 | |||
2ef37ed58d | |||
828a42f938 | |||
4428f7b48b | |||
e855fc5bbd | |||
a7f0f442d8 | |||
2a424e7f6f | |||
50f537fbfc | |||
7ba78c94ae | |||
763fbcc86e | |||
3abca0ef22 | |||
7888a8ee24 | |||
abec798b27 | |||
eb9ac51b5a | |||
d86601e1a1 | |||
fd48f8c3ec | |||
fa28d6ce17 | |||
4250fda098 | |||
4f9e3dee01 | |||
e05f0b2c73 | |||
7c7a5fc1b7 | |||
a54abc6ea1 | |||
e4ed4d5567 | |||
29c4c107bc | |||
0b242aadc7 | |||
44a39e7e1f | |||
e82640c7da | |||
f89bf8859b | |||
6b5c432ce7 | |||
409a3bc6eb | |||
d406a09a9e | |||
36b045c6d2 | |||
59902adcf5 | |||
41842eede4 | |||
62c7cb1918 | |||
d23f6f4cc8 | |||
80f1fc3371 | |||
ea87137a82 | |||
aa8df36e28 | |||
0947a87d6c | |||
72c47a9b0d | |||
f0c9a800a5 | |||
ad5405e699 | |||
cc5c8b9ed5 | |||
04d8fd3d14 | |||
fb0a6a0a01 | |||
78059d1bf8 | |||
3352765fed | |||
f96166be48 | |||
3a878c9e90 | |||
7b8c3c7412 | |||
9f6751533e | |||
82e9b27598 | |||
237fff1351 | |||
e00c560c80 | |||
407e772fdb | |||
645437b5e3 | |||
7f6221cd8e | |||
d9c770855a | |||
70a7d6540c | |||
acf6678619 | |||
f2242c4e57 | |||
8fb7c76e2d | |||
72e78fd4bc | |||
2f1e065571 | |||
761c3730ed | |||
cdf7b926ba | |||
d3addb09c4 | |||
471203b0a6 | |||
7cac5b105e | |||
e8c3f27d93 | |||
97d2ed0d64 | |||
7278aab649 | |||
e33e634d0d | |||
92af5d8842 | |||
140f949190 | |||
c5d043f85b | |||
06cea02484 | |||
287b7413e3 | |||
3c330ac4f0 | |||
51bc126c8d | |||
edcd166cd8 | |||
aaead0e5ca | |||
990ef45e45 | |||
9ae607d802 | |||
3c07d8dcc4 | |||
bb8b8a9d50 | |||
08303e93ca | |||
01bdad6368 | |||
8145ef116f | |||
ab9ff96684 | |||
9858ac84c1 | |||
c6b876d7f9 | |||
05f1c62ad0 | |||
bf631efd24 | |||
f86e73b374 | |||
7cd85bbd34 | |||
38424bfdca | |||
9dde61e7a0 | |||
5fc1c78d1b | |||
2cbfc0b1ec | |||
5043378c2c | |||
92e743a67e | |||
9262e7fd13 | |||
5adfa8a1be | |||
0d64d5aa00 | |||
11e15f0482 | |||
07355d7442 | |||
e8392b8fa5 | |||
bfcf221a91 | |||
c29cbda581 | |||
5294a31e30 | |||
ed7ead95d5 | |||
aee6063410 | |||
45e78777e9 | |||
1de6a6288c | |||
4b7af32eb1 | |||
955c49a2c1 | |||
eeb5afe97b | |||
f5d818c91a | |||
0a38e422b8 | |||
f059faecbc | |||
195918f088 | |||
022e52e31c | |||
b249399b1d | |||
132d46fed5 | |||
49e16a3631 | |||
06c3b3f025 | |||
39e4340dee | |||
cb3a633807 | |||
b0bc11007f | |||
7781bcfe4b | |||
308ea2ce25 | |||
d66c7906c0 | |||
a0bf340378 | |||
1b8bb8a9ea | |||
25101b278a | |||
5c4c8c0fe9 | |||
7a861eabee | |||
b8f549a432 | |||
5a82498d60 | |||
890d004c3c | |||
c7c20cdacf | |||
3f2bc41176 | |||
70779f192c | |||
6fc121a314 | |||
29960cada8 | |||
6dc1c9e53b | |||
5b7b1527d5 | |||
6bfccca291 | |||
39c8933a3f | |||
5411843f9f | |||
88b0dc5215 | |||
2a8571d940 | |||
9882a99417 | |||
2f8fb874d8 | |||
5f229311f0 | |||
4a88f6cc56 | |||
151ec256fa | |||
37c90ed12b | |||
c21863c71a | |||
508fc8fd1c | |||
9f6b3160fc | |||
650de1d7e3 | |||
68ebfcd537 | |||
4cc870b1bb | |||
a15fb5719e | |||
6926ef3b9a | |||
76a61d5a01 | |||
f24c5da431 | |||
b9ab9582a8 | |||
f9426c9ed0 | |||
067cce1d7b | |||
b03445ea46 | |||
9d7f49dda9 | |||
dfd78be5b3 | |||
f0e2ec6a8a | |||
06ed30de3b | |||
5cfc6c573b | |||
ec940d428a | |||
4f593cb2d3 | |||
611fc1ba24 | |||
4f7249bfa4 | |||
8f8e468278 | |||
23916b753a | |||
e8ba629217 | |||
ef2c2917db | |||
6daed0f4a8 | |||
8624920e2c | |||
e303cccd2a | |||
88c4f2d8d0 | |||
41feee7a22 | |||
c0101f45b5 | |||
c49eb2e50f | |||
238af84a97 | |||
87d166c4a4 | |||
d05a3c4dc0 | |||
a2ccc2668a | |||
e93df29cc0 | |||
aafe5da783 | |||
35174fb849 | |||
1905d89a75 | |||
d566d6a315 | |||
08529d0d59 | |||
ce946b9aed | |||
f7aa5cd65c | |||
d9c0fd6d0b | |||
41db8d67df | |||
7a5985ba8f | |||
574e2c3761 | |||
90b5e3cdca | |||
b062d44b87 | |||
ca1c801d64 | |||
c3a6c61739 | |||
5a496f228a |
14
.esdoc.json
Normal file
14
.esdoc.json
Normal file
|
@ -0,0 +1,14 @@
|
|||
{
|
||||
"source": "src",
|
||||
"destination": "docs/docs",
|
||||
"plugins": [{
|
||||
"name": "esdoc-standard-plugin",
|
||||
"option": {
|
||||
"lint": {"enable": false},
|
||||
"accessor": {
|
||||
"access": ["public", "protected"],
|
||||
"autoPrivate": true
|
||||
}
|
||||
}
|
||||
}]
|
||||
}
|
11
.eslintrc
11
.eslintrc
|
@ -1,18 +1,20 @@
|
|||
{
|
||||
"parser": "babel-eslint",
|
||||
"parserOptions": {
|
||||
"sourceType": "module"
|
||||
"sourceType": "module",
|
||||
"ecmaFeatures": { "modules": true }
|
||||
},
|
||||
"rules": {
|
||||
"max-len": [2, 80, 2, {"ignoreUrls": true}],
|
||||
"indent": [2, 4, {"SwitchCase": 1}],
|
||||
"semi": ["error", "always"],
|
||||
"no-trailing-spaces": 2,
|
||||
"no-multi-spaces": 2,
|
||||
"array-bracket-spacing": 2,
|
||||
"keyword-spacing": ["error", { "after": true, "before": true }],
|
||||
"max-depth": [2, 7],
|
||||
"max-statements": [2, 144],
|
||||
"complexity": [2, 78],
|
||||
"max-statements": [2, 133],
|
||||
"complexity": [2, 45],
|
||||
"no-unused-vars": 2,
|
||||
"no-eval": 2,
|
||||
"no-underscore-dangle": 0,
|
||||
|
@ -24,9 +26,6 @@
|
|||
"new-cap": 2,
|
||||
"radix": [2, "always"]
|
||||
},
|
||||
"ecmaFeatures": {
|
||||
"modules": true
|
||||
},
|
||||
"env": {
|
||||
"es6": true,
|
||||
"browser": true,
|
||||
|
|
38
.github/ISSUE_TEMPLATE/bug_report.md
vendored
Normal file
38
.github/ISSUE_TEMPLATE/bug_report.md
vendored
Normal file
|
@ -0,0 +1,38 @@
|
|||
---
|
||||
name: Bug report
|
||||
about: Create a report to help us improve
|
||||
title: ''
|
||||
labels: bug
|
||||
assignees: ''
|
||||
|
||||
---
|
||||
|
||||
**Describe the bug**
|
||||
A clear and concise description of what the bug is.
|
||||
|
||||
**Reproduction steps:**
|
||||
Steps to reproduce the behavior:
|
||||
1. [First Step]
|
||||
2. [Second Step]
|
||||
3. [Other Steps...]
|
||||
|
||||
**Expected behavior**
|
||||
A clear and concise description of what you expected to happen.
|
||||
|
||||
**Observed behavior:**
|
||||
A clear and concise description of observed behavior.
|
||||
|
||||
**Screenshots**
|
||||
If applicable, add screenshots to help explain your problem.
|
||||
![Screenshots and GIFs which follow reproduction steps to demonstrate the problem](url)
|
||||
|
||||
**TableFilter version:** [Enter TableFilter version here]
|
||||
**Browser and version:** [Enter Browser name and version here]
|
||||
**OS and version:** [Enter OS name and version here]
|
||||
**Device:** [e.g. iPhone6]
|
||||
|
||||
**Additional information/context:**
|
||||
Add any other context about the problem here.
|
||||
|
||||
* Problem started happening recently, didn't happen in an older version of TableFilter: [Yes/No] if yes [version here]
|
||||
* Problem can be reliably reproduced, doesn't happen randomly: [Yes/No]
|
36
.github/ISSUE_TEMPLATE/feature_request.md
vendored
Normal file
36
.github/ISSUE_TEMPLATE/feature_request.md
vendored
Normal file
|
@ -0,0 +1,36 @@
|
|||
---
|
||||
name: Feature request
|
||||
about: Suggest an idea for this project
|
||||
title: ''
|
||||
labels: ''
|
||||
assignees: ''
|
||||
|
||||
---
|
||||
|
||||
**Enhancement/feature description**
|
||||
[A clear and concise description of what the problem is. Ex. I'm always frustrated when ...]
|
||||
|
||||
**Steps which explain the enhancement/feature**
|
||||
1. [First Step]
|
||||
2. [Second Step]
|
||||
3. [Other Steps...]
|
||||
|
||||
**Current and suggested behavior**
|
||||
[Describe current and suggested behavior here]
|
||||
|
||||
**Why would the enhancement be useful to most users**
|
||||
[Explain why the enhancement would be useful to most users]
|
||||
|
||||
**Screenshots and GIFs**
|
||||
![Screenshots and GIFs which demonstrate the steps or part of TableFilter the enhancement suggestion is related to](url)
|
||||
|
||||
**Additional context**
|
||||
[Add any other context or screenshots about the feature request here.]
|
||||
|
||||
**Describe alternatives you've considered**
|
||||
A clear and concise description of any alternative solutions or features you've considered.
|
||||
|
||||
**TableFilter Version:** [Enter TableFilter version here]
|
||||
**Browser and version:** [Enter Browser name and version here]
|
||||
**OS and version:** [Enter OS name and version here]
|
||||
**Device:** [e.g. iPhone6]
|
17
.github/ISSUE_TEMPLATE/support.md
vendored
Normal file
17
.github/ISSUE_TEMPLATE/support.md
vendored
Normal file
|
@ -0,0 +1,17 @@
|
|||
---
|
||||
name: Support
|
||||
about: I need support with TableFilter
|
||||
title: ''
|
||||
labels: ''
|
||||
assignees: ''
|
||||
|
||||
---
|
||||
|
||||
For usage and support questions, please check out resources below, you might find an answer:
|
||||
|
||||
- https://www.tablefilter.com/
|
||||
- https://www.tablefilter.com/docs/
|
||||
- https://www.tablefilter.com/examples.html
|
||||
- https://github.com/koalyptus/TableFilter/wiki/
|
||||
- https://github.com/koalyptus/TableFilter/issues?q=is%3Aissue+is%3Aclosed
|
||||
- https://codepen.io/koalyptus/pens/public/
|
49
.travis.yml
49
.travis.yml
|
@ -1,16 +1,53 @@
|
|||
language: node_js
|
||||
node_js:
|
||||
- '6.3.0'
|
||||
- '8.9.4'
|
||||
before_script:
|
||||
- npm install grunt-cli -g
|
||||
- npm install codecov -g
|
||||
- npm install grunt-cli -g
|
||||
- npm install codecov -g
|
||||
script:
|
||||
- npm test
|
||||
- npm run codecov
|
||||
- npm run deploy
|
||||
- npm test
|
||||
- npm run codecov
|
||||
- npm run build:all
|
||||
branches:
|
||||
only:
|
||||
- master
|
||||
- /^greenkeeper/.*$/
|
||||
before_deploy:
|
||||
- git config --global user.email "maxgug@hotmail.com"
|
||||
- git config --global user.name "koalyptus"
|
||||
- export GIT_TAG=$(git describe --tags --abbrev=0)
|
||||
- echo -n $GIT_TAG
|
||||
- export NEW_GIT_TAG=$(node -p -e "require('./package.json').version")
|
||||
- echo -n $NEW_GIT_TAG
|
||||
- |
|
||||
if [ $GIT_TAG != $NEW_GIT_TAG ]; then
|
||||
git tag $NEW_GIT_TAG -am "Generated tag from TravisCI build $TRAVIS_BUILD_NUMBER"
|
||||
fi
|
||||
deploy:
|
||||
- provider: releases
|
||||
on:
|
||||
branch: master
|
||||
api_key: $GITHUB_OAUTH_ACCESS_TOKEN
|
||||
skip_cleanup: true
|
||||
name: $NEW_GIT_TAG
|
||||
- provider: s3
|
||||
on:
|
||||
branch: master
|
||||
access_key_id: $AWS_ACCESS_KEY_ID
|
||||
secret_access_key: $AWS_SECRET_ACCESS_KEY
|
||||
region: $AWS_DEFAULT_REGION
|
||||
bucket: www.tablefilter.com
|
||||
skip_cleanup: true
|
||||
local_dir: dist
|
||||
- provider: s3
|
||||
on:
|
||||
branch: master
|
||||
access_key_id: $AWS_ACCESS_KEY_ID
|
||||
secret_access_key: $AWS_SECRET_ACCESS_KEY
|
||||
region: $AWS_DEFAULT_REGION
|
||||
bucket: www.tablefilter.com
|
||||
skip_cleanup: true
|
||||
local_dir: docs
|
||||
env:
|
||||
global:
|
||||
- secure: A1G8GvJkV0rjy7XCTVdOpTHy3xaoSZZAbMWhI+ikrqBqd8mRz+sB71FhRusouTcYdsT5VfF9Io2doS8LKAeP0TNC34Pp0uvjtsvarzn8a/oNEOuqR3Ub0ws2bmbZIZc+wOpgErKOj1H1QSJAUpd6ZjIuEAbOVXlhGBJz3zUCmcpRDh32CpFKC62oFWeGlvttxPciLLzBfKgkVKEGhPtdGP/xCHL1MCQptYVHZiXwWsaIQ5wHFO6KCVlRrPgdfOL+Yce3mT02iXH6ZjW6U6zA6vYQVQZVD873AkU5RmirYblW+jW1wdvu4UXI71lSH6Z3uXRVnrw1b0TsLVTjP9ZUbCtkTHtLbxYzeDjEukxKoCjpAppIhOtaNIxrdA8oKJAabQYp5X+QK6lkosy0zdT5u2B1+g8unZhsf0y//7lgLUe04iQ7sc1Q6AHiiEGtByaXg4BHNW53bUfKgNnbV4+IbXf8rz5wWOxL2/yWAU/GoiszjqRQfajAXCpSf6SyMjXjhhvQdeFn+Cz6FwdtaxH+tOIY0Hq9Gqy1xrLIkv/httd3O+AbhLrU1c/M0MwlFQue7GeJb7ZyF3KsK7bXvoz2dEqvzHd98NZXiQEqFXCIs77uVh4eZMoYrbEyrkOAgkUZNQYhHh9fuvfynJ/zgUvyA0v3GUvBebq3ybYKD/vqX7s=
|
||||
|
|
|
@ -116,15 +116,13 @@ In general, we follow the "fork-and-pull" Git workflow.
|
|||
3. **Commit** changes to your own branch
|
||||
- 3.1. **Add** unit tests covering your change in the `test` folder
|
||||
- 3.2. **Run** the tests with the `npm run eslint test` command
|
||||
- 3.3. **Ensure** build is working with `npm run build-all` command
|
||||
- 3.3. **Ensure** build is working with `npm run dist` command
|
||||
4. **Push** your work back up to your fork
|
||||
5. Submit a **Pull request** so that we can review your changes
|
||||
|
||||
NOTE: Be sure to merge the latest from "upstream" before making a pull request!
|
||||
|
||||
## Donations
|
||||
To support this project simply locate the `Donate` button in the [project's
|
||||
website](http://koalyptus.github.io/TableFilter/)
|
||||
which points to PayPal.
|
||||
Thanks to all those who supported this project in the past and to those who will
|
||||
Support this project by donating [here](http://www.tablefilter.com/donate.html).
|
||||
Thanks to all those who supported this project in the past and those who will
|
||||
in the future!
|
||||
|
|
254
Gruntfile.js
254
Gruntfile.js
|
@ -1,38 +1,19 @@
|
|||
module.exports = function (grunt) {
|
||||
var webpackConfig = require('./webpack.config.js');
|
||||
var webpackDevConfig = require('./webpack.dev.config.js');
|
||||
var webpackTestConfig = require('./webpack.test.config.js');
|
||||
var fs = require('fs');
|
||||
var path = require('path');
|
||||
var testDir = 'test';
|
||||
var testHost = 'http://localhost:8000/';
|
||||
var pkg = grunt.file.readJSON('package.json');
|
||||
var repo = 'github.com/koalyptus/TableFilter';
|
||||
var styleDirDist = 'dist/tablefilter/style/';
|
||||
|
||||
grunt.initConfig({
|
||||
|
||||
eslint: {
|
||||
options: {
|
||||
configFile: '.eslintrc'
|
||||
},
|
||||
target: [
|
||||
'Gruntfile.js',
|
||||
'webpack.config.js',
|
||||
'webpack.dev.config.js',
|
||||
'webpack.test.config.js',
|
||||
'src/**/*.js',
|
||||
'test/*.js'
|
||||
]
|
||||
},
|
||||
|
||||
qunit: {
|
||||
options: {
|
||||
'--web-security': 'no',
|
||||
coverage: {
|
||||
disposeCollector: true,
|
||||
src: ['dist/tablefilter/*.js'],
|
||||
instrumentedFiles: 'temp/',
|
||||
instrumentedFiles: 'report/temp/',
|
||||
htmlReport: 'report/coverage',
|
||||
coberturaReport: 'report/',
|
||||
lcovReport: 'report/',
|
||||
|
@ -126,24 +107,6 @@ module.exports = function (grunt) {
|
|||
|
||||
clean: ['demos/starter.html'],
|
||||
|
||||
'webpack-dev-server': {
|
||||
options: {
|
||||
webpack: webpackDevConfig,
|
||||
publicPath: '/dist/'
|
||||
},
|
||||
start: {
|
||||
webpack: {
|
||||
devtool: 'eval'
|
||||
}
|
||||
}
|
||||
},
|
||||
|
||||
webpack: {
|
||||
build: webpackConfig,
|
||||
dev: webpackDevConfig,
|
||||
test: webpackTestConfig
|
||||
},
|
||||
|
||||
watch: {
|
||||
app: {
|
||||
files: ['src/**/*', 'static/style/**/*'],
|
||||
|
@ -161,168 +124,49 @@ module.exports = function (grunt) {
|
|||
}
|
||||
},
|
||||
|
||||
babel: {
|
||||
options: {
|
||||
sourceMap: true,
|
||||
modules: 'amd',
|
||||
compact: false,
|
||||
presets: ['es2015']
|
||||
// temporary shell commands while decommissioning grunt
|
||||
shell: {
|
||||
eslint: {
|
||||
command: 'npm run lint'
|
||||
},
|
||||
dist: {
|
||||
files: [{
|
||||
expand: true,
|
||||
cwd: 'src',
|
||||
src: ['**/*.js'],
|
||||
dest: 'dist/tablefilter'
|
||||
}]
|
||||
}
|
||||
},
|
||||
|
||||
esdoc: {
|
||||
dist: {
|
||||
options: {
|
||||
source: 'src',
|
||||
destination: 'docs/docs',
|
||||
title: pkg.name + ' v' + pkg.version
|
||||
}
|
||||
}
|
||||
},
|
||||
|
||||
stylus: {
|
||||
compile: {
|
||||
options: {
|
||||
banner: '/** \n' +
|
||||
' *\t ' + pkg.name + ' v' + pkg.version +
|
||||
' by ' + pkg.author.name + ' \n' +
|
||||
' *\t build date: ' + new Date().toISOString() + ' \n' +
|
||||
' *\t MIT License \n' +
|
||||
' */ \n'
|
||||
},
|
||||
files: [
|
||||
{
|
||||
src: ['static/style/*.styl'],
|
||||
dest: styleDirDist + 'tablefilter.css'
|
||||
}, {
|
||||
src: ['static/style/extensions/colsVisibility.styl'],
|
||||
dest: styleDirDist + 'colsVisibility.css'
|
||||
}, {
|
||||
src: ['static/style/extensions/filtersVisibility.styl'],
|
||||
dest: styleDirDist + 'filtersVisibility.css'
|
||||
}, {
|
||||
src: ['static/style/themes/default/*.styl'],
|
||||
dest: styleDirDist + 'themes/default/default.css'
|
||||
}, {
|
||||
src: ['static/style/themes/mytheme/*.styl'],
|
||||
dest: styleDirDist + 'themes/mytheme/mytheme.css'
|
||||
}, {
|
||||
src: ['static/style/themes/skyblue/*.styl'],
|
||||
dest: styleDirDist + 'themes/skyblue/skyblue.css'
|
||||
}, {
|
||||
src: ['static/style/themes/transparent/*.styl'],
|
||||
dest:
|
||||
styleDirDist + 'themes/transparent/transparent.css'
|
||||
}
|
||||
]
|
||||
}
|
||||
},
|
||||
|
||||
'gh-pages': {
|
||||
options: {
|
||||
branch: 'gh-pages',
|
||||
add: true
|
||||
esdoc: {
|
||||
command: 'npm run esdoc'
|
||||
},
|
||||
'publish-lib': {
|
||||
options: {
|
||||
base: 'dist',
|
||||
repo: 'https://' + repo,
|
||||
message: 'publish TableFilter lib to gh-pages (cli)'
|
||||
},
|
||||
src: ['**/*']
|
||||
build: {
|
||||
command: 'npm run build'
|
||||
},
|
||||
'publish-readme': {
|
||||
options: {
|
||||
base: './',
|
||||
repo: 'https://' + repo,
|
||||
message: 'publish README and LICENSE to gh-pages (cli)'
|
||||
},
|
||||
src: ['README.md', 'LICENSE']
|
||||
dev: {
|
||||
command: 'npm run dev'
|
||||
},
|
||||
'publish-docs': {
|
||||
options: {
|
||||
base: 'docs',
|
||||
repo: 'https://' + repo,
|
||||
message: 'publish Docs to gh-pages (cli)'
|
||||
},
|
||||
src: ['**/*']
|
||||
test: {
|
||||
command: 'npm run build:test'
|
||||
},
|
||||
'deploy-lib': {
|
||||
options: {
|
||||
user: {
|
||||
name: 'koalyptus'
|
||||
},
|
||||
base: 'dist',
|
||||
repo: 'https://' + process.env.GH_TOKEN + '@' + repo,
|
||||
message: 'publish TableFilter to gh-pages (auto)' +
|
||||
getDeployMessage(),
|
||||
silent: true
|
||||
},
|
||||
src: ['**/*']
|
||||
},
|
||||
'deploy-readme': {
|
||||
options: {
|
||||
user: {
|
||||
name: 'koalyptus'
|
||||
},
|
||||
base: './',
|
||||
repo: 'https://' + process.env.GH_TOKEN + '@' + repo,
|
||||
message: 'publish README to gh-pages (auto)' +
|
||||
getDeployMessage(),
|
||||
silent: true
|
||||
},
|
||||
src: ['README.md', 'LICENSE']
|
||||
},
|
||||
'deploy-docs': {
|
||||
options: {
|
||||
user: {
|
||||
name: 'koalyptus'
|
||||
},
|
||||
base: 'docs',
|
||||
repo: 'https://' + process.env.GH_TOKEN + '@' + repo,
|
||||
message: 'publish Docs to gh-pages (auto)' +
|
||||
getDeployMessage(),
|
||||
silent: true
|
||||
},
|
||||
src: ['**/*']
|
||||
'build-css': {
|
||||
command: 'npm run build:css'
|
||||
}
|
||||
}
|
||||
|
||||
});
|
||||
|
||||
grunt.loadNpmTasks('grunt-eslint');
|
||||
grunt.loadNpmTasks('grunt-contrib-copy');
|
||||
grunt.loadNpmTasks('grunt-contrib-clean');
|
||||
grunt.loadNpmTasks('grunt-contrib-watch');
|
||||
grunt.loadNpmTasks('grunt-string-replace');
|
||||
grunt.loadNpmTasks('grunt-contrib-connect');
|
||||
grunt.loadNpmTasks('grunt-webpack');
|
||||
grunt.loadNpmTasks('grunt-babel');
|
||||
grunt.loadNpmTasks('grunt-esdoc');
|
||||
grunt.loadNpmTasks('grunt-shell');
|
||||
grunt.loadNpmTasks('grunt-qunit-istanbul');
|
||||
grunt.loadNpmTasks('grunt-contrib-stylus');
|
||||
grunt.loadNpmTasks('grunt-gh-pages');
|
||||
|
||||
grunt.registerTask('eslint', ['shell:eslint']);
|
||||
grunt.registerTask('esdoc', ['shell:esdoc']);
|
||||
|
||||
grunt.registerTask('default', ['test', 'build', 'build-demos']);
|
||||
|
||||
// Development server
|
||||
grunt.registerTask('server', ['webpack-dev-server:start']);
|
||||
|
||||
// Dev dev/build/watch cycle
|
||||
grunt.registerTask('dev',
|
||||
['eslint', 'webpack:dev', 'copy:dist', 'stylus:compile', 'watch:app']);
|
||||
['eslint', 'shell:dev', 'copy:dist', 'shell:build-css', 'watch:app']);
|
||||
|
||||
// Production build
|
||||
grunt.registerTask('build',
|
||||
['eslint', 'webpack:build', 'copy:dist', 'stylus:compile']);
|
||||
['eslint', 'shell:build', 'copy:dist', 'shell:build-css']);
|
||||
|
||||
// Build demos
|
||||
grunt.registerTask('dev-demos', ['build-demos', 'watch:templates']);
|
||||
|
@ -331,23 +175,14 @@ module.exports = function (grunt) {
|
|||
|
||||
// Build tests
|
||||
grunt.registerTask('build-test',
|
||||
['eslint', 'webpack:test', 'copy:dist', 'stylus:compile']);
|
||||
|
||||
// Transpile with Babel
|
||||
grunt.registerTask('dev-modules', ['babel', 'copy:dist']);
|
||||
['eslint', 'shell:test', 'copy:dist', 'shell:build-css']);
|
||||
|
||||
// Tests with coverage
|
||||
grunt.registerTask('test', ['build-test', 'connect', 'qunit:all']);
|
||||
|
||||
// Publish to gh-pages
|
||||
grunt.registerTask('publish', 'Publish from CLI', [
|
||||
'build', 'build-demos', 'esdoc', 'gh-pages:publish-lib',
|
||||
'gh-pages:publish-readme', 'gh-pages:publish-docs'
|
||||
]);
|
||||
|
||||
// Deploy to gh-pages
|
||||
grunt.registerTask('deploy', 'Publish from Travis', [
|
||||
'build', 'esdoc', 'check-deploy'
|
||||
// Build all for deployment from travis
|
||||
grunt.registerTask('build-all', 'Prepare for deployment', [
|
||||
'build', 'build-demos', 'esdoc'
|
||||
]);
|
||||
|
||||
// Custom task running QUnit tests for specified files.
|
||||
|
@ -414,43 +249,4 @@ module.exports = function (grunt) {
|
|||
|
||||
return getFiles(testDir, host);
|
||||
}
|
||||
|
||||
grunt.registerTask('check-deploy', function () {
|
||||
var env = process.env;
|
||||
// need this
|
||||
this.requires(['build', 'esdoc']);
|
||||
|
||||
// only deploy under these conditions
|
||||
if (env.TRAVIS === 'true' &&
|
||||
env.TRAVIS_SECURE_ENV_VARS === 'true' &&
|
||||
env.TRAVIS_PULL_REQUEST === 'false') {
|
||||
grunt.log.writeln('executing deployment');
|
||||
// queue deploy
|
||||
grunt.task.run([
|
||||
'gh-pages:deploy-lib',
|
||||
'gh-pages:deploy-readme',
|
||||
'gh-pages:deploy-docs'
|
||||
]);
|
||||
} else {
|
||||
grunt.log.writeln('skipped deployment');
|
||||
}
|
||||
});
|
||||
|
||||
// Get a formatted commit message to review changes from the commit log
|
||||
// github will turn some of these into clickable links
|
||||
function getDeployMessage() {
|
||||
var ret = '\n\n';
|
||||
var env = process.env;
|
||||
if (env.TRAVIS !== 'true') {
|
||||
ret += 'missing env vars for travis-ci';
|
||||
return ret;
|
||||
}
|
||||
ret += 'branch: ' + env.TRAVIS_BRANCH + '\n';
|
||||
ret += 'SHA: ' + env.TRAVIS_COMMIT + '\n';
|
||||
ret += 'range SHA: ' + env.TRAVIS_COMMIT_RANGE + '\n';
|
||||
ret += 'build id: ' + env.TRAVIS_BUILD_ID + '\n';
|
||||
ret += 'build number: ' + env.TRAVIS_BUILD_NUMBER + '\n';
|
||||
return ret;
|
||||
}
|
||||
|
||||
};
|
||||
|
|
24
PULL_REQUEST_TEMPLATE.md
Normal file
24
PULL_REQUEST_TEMPLATE.md
Normal file
|
@ -0,0 +1,24 @@
|
|||
# Description
|
||||
|
||||
Please include a summary of the change and which issue is fixed. Please also include relevant motivation and context.
|
||||
Fixes # (issue)
|
||||
|
||||
## Type of change
|
||||
|
||||
Please delete options that are not relevant.
|
||||
|
||||
- [ ] Bug fix (non-breaking change which fixes an issue)
|
||||
- [ ] New feature (non-breaking change which adds functionality)
|
||||
- [ ] Breaking change (fix or feature that would cause existing functionality to not work as expected)
|
||||
- [ ] This change requires a documentation update
|
||||
- [ ] Development tool configuration change
|
||||
|
||||
# Checklist:
|
||||
|
||||
- [ ] My code follows the style guidelines of this project
|
||||
- [ ] I have performed a self-review of my own code
|
||||
- [ ] I have commented my code, particularly in hard-to-understand areas
|
||||
- [ ] I have made corresponding changes to the documentation
|
||||
- [ ] My changes do not lower current test coverage
|
||||
- [ ] I have added tests that prove my fix is effective or that my feature works
|
||||
- [ ] New and existing unit tests pass locally with my changes
|
57
README.md
57
README.md
|
@ -1,6 +1,8 @@
|
|||
[![Build Status](https://api.travis-ci.org/koalyptus/TableFilter.svg?branch=master)](https://travis-ci.org/koalyptus/TableFilter)
|
||||
[![Document](http://koalyptus.github.io/TableFilter/docs/badge.svg)](https://koalyptus.github.io/TableFilter/docs/source)
|
||||
[![Document](https://www.tablefilter.com/docs/badge.svg)](https://www.tablefilter.com/docs/source.html)
|
||||
[![codecov](https://codecov.io/gh/koalyptus/TableFilter/branch/master/graph/badge.svg)](https://codecov.io/gh/koalyptus/TableFilter)
|
||||
[![Greenkeeper badge](https://badges.greenkeeper.io/koalyptus/TableFilter.svg)](https://greenkeeper.io/)
|
||||
[![Donate](https://img.shields.io/badge/donate-%24-green.svg)](https://www.tablefilter.com/donate.html)
|
||||
|
||||
# TableFilter
|
||||
|
||||
|
@ -22,7 +24,7 @@ users to filter and limit the data displayed within a long table. By default, th
|
|||
* Attach to an existing HTML table
|
||||
* Integration with any server-side technology as this is a pure client-side
|
||||
solution
|
||||
* Exhaustive documentation and poweful API
|
||||
* Exhaustive documentation and powerful API
|
||||
|
||||
## Getting started
|
||||
* Clone the repo using Git:
|
||||
|
@ -32,23 +34,40 @@ git clone https://github.com/koalyptus/TableFilter.git
|
|||
|
||||
* You can [download](https://github.com/koalyptus/TableFilter/archive/master.zip) this repository.
|
||||
|
||||
* Alternatively, install TableFilter files in your npm enabled project using:
|
||||
* TableFilter is available on [npm repository](https://www.npmjs.com/package/tablefilter), you can install it from the command line using the following command:
|
||||
```shell
|
||||
npm install tablefilter --save-dev
|
||||
```
|
||||
```
|
||||
* or get the future features from the ``next`` release channel:
|
||||
```shell
|
||||
npm install tablefilter@next --save-dev
|
||||
```
|
||||
* If you don't use `npm`, you can also
|
||||
[access these files on unpkg](https://unpkg.com/tablefilter/), download them
|
||||
or point your package manager to them.
|
||||
* Alternatively you can also [access these files from unpkg CDN](https://unpkg.com/tablefilter/), download them or point your package manager to them.
|
||||
|
||||
## Setup
|
||||
### Using modules
|
||||
Require `TableFilter`:
|
||||
```javascript
|
||||
// ES2015 modules
|
||||
import TableFilter from 'tablefilter';
|
||||
|
||||
// CommonJS or AMD modules
|
||||
var TableFilter = require('tablefilter');
|
||||
```
|
||||
|
||||
### Using distribution scripts
|
||||
If you are not using a module system, you can reference the distribution scripts directly in your html pages:
|
||||
```html
|
||||
<script src="path_to/node_modules/tablefilter/dist/tablefilter/tablefilter.js"></script>
|
||||
```
|
||||
|
||||
### Placing manually the distribution scripts in your project
|
||||
Copy the ``tablefilter`` directory under ``dist`` and place it at desired location in your project. Then include the main js file in your page:
|
||||
```shell
|
||||
<script src="path/to/my/scripts/tablefilter/tablefilter.js"></script>
|
||||
```
|
||||
|
||||
### Usage
|
||||
Place the following snippet just under the HTML table and always define a ``base_path`` property in the configuration object to reflect the path to the script
|
||||
```shell
|
||||
<script>
|
||||
|
@ -62,11 +81,11 @@ If the ``base_path`` property is not specified, it will default to ``/tablefilte
|
|||
```shell
|
||||
your-page.html
|
||||
|— tablefilter
|
||||
```
|
||||
```
|
||||
|
||||
## Development
|
||||
This project requires node.js and Grunt to be installed:
|
||||
- install [node.js](https://nodejs.org/)
|
||||
- install [node.js](https://nodejs.org/) v8.9.4 or higher
|
||||
- install [Grunt](http://gruntjs.com/getting-started) from the command line using npm (comes with node.js):
|
||||
```shell
|
||||
npm install -g grunt-cli
|
||||
|
@ -77,24 +96,24 @@ Start by installing any dependencies.
|
|||
```shell
|
||||
npm install
|
||||
```
|
||||
Use
|
||||
Use
|
||||
```shell
|
||||
npm run dev
|
||||
```
|
||||
```
|
||||
command to launch a build / watch cycle and start the local
|
||||
sever on port ``8080``.
|
||||
|
||||
Use
|
||||
Use
|
||||
```shell
|
||||
npm run build
|
||||
```
|
||||
```
|
||||
command to generate a production build.
|
||||
|
||||
The
|
||||
The
|
||||
```shell
|
||||
npm run dist
|
||||
```
|
||||
command will create a production build, run the tests and finally generate
|
||||
```
|
||||
command will create a production build, run the tests and finally generate
|
||||
the demos:
|
||||
|
||||
To run all the tests and generate the coverage report:
|
||||
|
@ -115,7 +134,7 @@ to view the coverage report(s), open the `index.html` under the
|
|||
[online](https://codecov.io/gh/koalyptus/TableFilter).
|
||||
|
||||
## Demos
|
||||
Check out the online [examples](http://koalyptus.github.io/TableFilter/examples)
|
||||
Check out the online [examples](http://www.tablefilter.com/examples.html)
|
||||
or generate the demos locally:
|
||||
```shell
|
||||
npm run build:demos
|
||||
|
@ -132,7 +151,7 @@ http://localhost:8080/demos/
|
|||
## Documentation
|
||||
Find exhaustive documentation on the configuration options in the [WIKI](https://github.com/koalyptus/TableFilter/wiki) section.
|
||||
|
||||
Autogenerated documentation of the ES6 modules is available on the website: [docs](http://koalyptus.github.io/TableFilter/docs)
|
||||
Autogenerated documentation of the ES6 modules is available on the website: [docs](http://www.tablefilter.com/docs)
|
||||
|
||||
If you previously used the HTML Table Filter Generator plugin, verify the configuration
|
||||
options you are using are still supported: [Obsolete](https://github.com/koalyptus/TableFilter/wiki/Obsolete)
|
||||
|
@ -143,7 +162,7 @@ npm run esdoc
|
|||
```
|
||||
|
||||
## Support
|
||||
* GitHub for reporting bugs and feature requests.
|
||||
* GitHub for [reporting bugs](https://github.com/koalyptus/TableFilter/blob/master/CONTRIBUTING.md#reporting-bugs) and [feature requests](https://github.com/koalyptus/TableFilter/blob/master/CONTRIBUTING.md#suggesting-enhancements-and-features).
|
||||
|
||||
## License
|
||||
[MIT](LICENSE)
|
||||
|
|
6
dist/starter.html
vendored
6
dist/starter.html
vendored
|
@ -1,10 +1,10 @@
|
|||
<!DOCTYPE html>
|
||||
<html lang="en">
|
||||
<head>
|
||||
<title>tablefilter v0.4.40 - Starter</title>
|
||||
<title>tablefilter v0.7.3 - Starter</title>
|
||||
</head>
|
||||
<body>
|
||||
<h1>tablefilter v0.4.40</h1>
|
||||
<h1>tablefilter v0.7.3</h1>
|
||||
|
||||
|
||||
|
||||
|
@ -479,7 +479,7 @@
|
|||
},
|
||||
col_widths: [
|
||||
'150px', '100px', '100px',
|
||||
'70px', '70px', '70px',
|
||||
'100px', '100px', '100px',
|
||||
'70px', '60px', '60px'
|
||||
],
|
||||
extensions:[{ name: 'sort' }]
|
||||
|
|
7
dist/tablefilter/style/colsVisibility.css
vendored
7
dist/tablefilter/style/colsVisibility.css
vendored
|
@ -1,6 +1 @@
|
|||
/**
|
||||
* tablefilter v0.4.40 by Max Guglielmi
|
||||
* build date: 2017-02-11T12:40:33.756Z
|
||||
* MIT License
|
||||
*/
|
||||
span.colVisSpan{text-align:left;}span.colVisSpan a.colVis{display:inline-block;padding:7px 5px 0;font-size:inherit;font-weight:inherit;vertical-align:top}div.colVisCont{position:relative;background:#fff;-webkit-box-shadow:3px 3px 2px #888;-moz-box-shadow:3px 3px 2px #888;box-shadow:3px 3px 2px #888;position:absolute;display:none;border:1px solid #ccc;height:auto;width:250px;background-color:#fff;margin:35px 0 0 -100px;z-index:10000;padding:10px 10px 10px 10px;text-align:left;font-size:12px;}div.colVisCont:after,div.colVisCont:before{bottom:100%;left:50%;border:solid transparent;content:" ";height:0;width:0;position:absolute;pointer-events:none}div.colVisCont:after{border-color:rgba(255,255,255,0);border-bottom-color:#fff;border-width:10px;margin-left:-10px}div.colVisCont:before{border-color:rgba(255,255,255,0);border-bottom-color:#ccc;border-width:12px;margin-left:-12px}div.colVisCont p{margin:6px auto 6px auto}div.colVisCont a.colVis{display:initial;font-weight:inherit}ul.cols_checklist{padding:0;margin:0;list-style:none;}ul.cols_checklist label{display:block}ul.cols_checklist input{vertical-align:middle;margin:2px 5px 2px 1px}li.cols_checklist_item{padding:4px;margin:0;}li.cols_checklist_item:hover{background-color:#335ea8;color:#fff}.cols_checklist_slc_item{background-color:#335ea8;color:#fff}
|
||||
span.colVisSpan{text-align:left;}span.colVisSpan a.colVis{display:inline-block;padding:7px 5px 0;font-size:inherit;font-weight:inherit;vertical-align:top}div.colVisCont{position:relative;background:#fff;-webkit-box-shadow:3px 3px 2px #888;-moz-box-shadow:3px 3px 2px #888;box-shadow:3px 3px 2px #888;position:absolute;display:none;border:1px solid #ccc;height:auto;width:250px;background-color:#fff;margin:35px 0 0 -100px;z-index:10000;padding:10px 10px 10px 10px;text-align:left;font-size:inherit;}div.colVisCont:after,div.colVisCont:before{bottom:100%;left:50%;border:solid transparent;content:" ";height:0;width:0;position:absolute;pointer-events:none}div.colVisCont:after{border-color:rgba(255,255,255,0);border-bottom-color:#fff;border-width:10px;margin-left:-10px}div.colVisCont:before{border-color:rgba(255,255,255,0);border-bottom-color:#ccc;border-width:12px;margin-left:-12px}div.colVisCont p{margin:6px auto 6px auto}div.colVisCont a.colVis{display:initial;font-weight:inherit}ul.cols_checklist{padding:0;margin:0;list-style-type:none;}ul.cols_checklist label{display:block}ul.cols_checklist input{vertical-align:middle;margin:2px 5px 2px 1px}li.cols_checklist_item{padding:4px;margin:0;}li.cols_checklist_item:hover{background-color:#335ea8;color:#fff}.cols_checklist_slc_item{background-color:#335ea8;color:#fff}
|
5
dist/tablefilter/style/filtersVisibility.css
vendored
5
dist/tablefilter/style/filtersVisibility.css
vendored
|
@ -1,6 +1 @@
|
|||
/**
|
||||
* tablefilter v0.4.40 by Max Guglielmi
|
||||
* build date: 2017-02-11T12:40:33.756Z
|
||||
* MIT License
|
||||
*/
|
||||
span.expClpFlt a.btnExpClpFlt{width:35px;height:35px;display:inline-block;}span.expClpFlt a.btnExpClpFlt:hover{background-color:#f4f4f4}span.expClpFlt img{padding:8px 11px 11px 11px}
|
24
dist/tablefilter/style/tablefilter.css
vendored
24
dist/tablefilter/style/tablefilter.css
vendored
File diff suppressed because one or more lines are too long
|
@ -1,6 +1 @@
|
|||
/**
|
||||
* tablefilter v0.4.40 by Max Guglielmi
|
||||
* build date: 2017-02-11T12:40:33.756Z
|
||||
* MIT License
|
||||
*/
|
||||
table.TF{border-left:1px solid #ccc;border-top:none;border-right:none;border-bottom:none;}table.TF th{background:#ebecee url("images/bg_th.jpg") left top repeat-x;border-bottom:1px solid #d0d0d0;border-right:1px solid #d0d0d0;border-left:1px solid #fff;border-top:1px solid #fff;color:#333}table.TF td{border-bottom:1px dotted #999;padding:5px}.fltrow{background-color:#ebecee !important;}.fltrow th,.fltrow td{border-bottom:1px dotted #666 !important;padding:1px 3px 1px 3px !important}.flt,select.flt,select.flt_multi,.flt_s,.single_flt,.div_checklist{border:1px solid #999 !important}input.flt{width:99% !important}.inf{height:$min-height;background:#d7d7d7 url("images/bg_infDiv.jpg") 0 0 repeat-x !important}input.reset{background:transparent url("images/btn_eraser.gif") center center no-repeat !important}.helpBtn:hover{background-color:transparent}.nextPage{background:transparent url("images/btn_next_page.gif") center center no-repeat !important;}.nextPage:hover{background:transparent url("images/btn_over_next_page.gif") center center no-repeat !important}.previousPage{background:transparent url("images/btn_previous_page.gif") center center no-repeat !important;}.previousPage:hover{background:transparent url("images/btn_over_previous_page.gif") center center no-repeat !important}.firstPage{background:transparent url("images/btn_first_page.gif") center center no-repeat !important;}.firstPage:hover{background:transparent url("images/btn_over_first_page.gif") center center no-repeat !important}.lastPage{background:transparent url("images/btn_last_page.gif") center center no-repeat !important;}.lastPage:hover{background:transparent url("images/btn_over_last_page.gif") center center no-repeat !important}div.grd_Cont{background-color:#ebecee !important;border:1px solid #ccc !important;padding:0 !important;}div.grd_Cont .even{background-color:#fff}div.grd_Cont .odd{background-color:#d5d5d5}div.grd_headTblCont{background-color:#ebecee !important;border-bottom:none !important;}div.grd_headTblCont table{border-right:none !important}div.grd_tblCont table th,div.grd_headTblCont table th,div.grd_headTblCont table td{background:#ebecee url("images/bg_th.jpg") left top repeat-x !important;border-bottom:1px solid #d0d0d0 !important;border-right:1px solid #d0d0d0 !important;border-left:1px solid #fff !important;border-top:1px solid #fff !important}div.grd_tblCont table td{border-bottom:1px solid #999 !important}.grd_inf{background:#d7d7d7 url("images/bg_infDiv.jpg") 0 0 repeat-x !important;border-top:1px solid #d0d0d0 !important}.loader{border:1px solid #999}.defaultLoader{width:32px;height:32px;background:transparent url("images/img_loading.gif") 0 0 no-repeat !important}.even{background-color:#fff}.odd{background-color:#d5d5d5}span.expClpFlt a.btnExpClpFlt:hover{background-color:transparent !important}.activeHeader{background:#999 !important}
|
|
@ -1,6 +1 @@
|
|||
/**
|
||||
* tablefilter v0.4.40 by Max Guglielmi
|
||||
* build date: 2017-02-11T12:40:33.756Z
|
||||
* MIT License
|
||||
*/
|
||||
table.TF{border-left:1px dotted #81963b;border-top:none;border-right:0;border-bottom:none;}table.TF th{background:#39424b url("images/bg_headers.jpg") left top repeat-x;border-bottom:0;border-right:1px dotted #d0d0d0;border-left:0;border-top:0;color:#fff}table.TF td{border-bottom:1px dotted #81963b;border-right:1px dotted #81963b;padding:5px}.fltrow{background-color:#81963b !important;}.fltrow th,.fltrow td{border-bottom:1px dotted #39424b !important;border-right:1px dotted #fff !important;border-left:0 !important;border-top:0 !important;padding:1px 3px 1px 3px !important}.flt,select.flt,select.flt_multi,.flt_s,.single_flt,.div_checklist{border:1px solid #687830 !important}input.flt{width:99% !important}.inf{background:#d8d8d8;height:$min-height}input.reset{width:53px;background:transparent url("images/btn_filter.png") center center no-repeat !important}.helpBtn:hover{background-color:transparent}.nextPage{background:transparent url("images/btn_next_page.gif") center center no-repeat !important}.previousPage{background:transparent url("images/btn_previous_page.gif") center center no-repeat !important}.firstPage{background:transparent url("images/btn_first_page.gif") center center no-repeat !important}.lastPage{background:transparent url("images/btn_last_page.gif") center center no-repeat !important}div.grd_Cont{background:#81963b url("images/bg_headers.jpg") left top repeat-x !important;border:1px solid #ccc !important;padding:0 1px 1px 1px !important;}div.grd_Cont .even{background-color:#bccd83}div.grd_Cont .odd{background-color:#fff}div.grd_headTblCont{background-color:#ebecee !important;border-bottom:none !important}div.grd_tblCont table{border-right:none !important;}div.grd_tblCont table td{border-bottom:1px dotted #81963b;border-right:1px dotted #81963b}div.grd_tblCont table th,div.grd_headTblCont table th{background:transparent url("images/bg_headers.jpg") 0 0 repeat-x !important;border-bottom:0 !important;border-right:1px dotted #d0d0d0 !important;border-left:0 !important;border-top:0 !important;padding:0 4px 0 4px !important;color:#fff !important;height:35px !important}div.grd_headTblCont table td{border-bottom:1px dotted #39424b !important;border-right:1px dotted #fff !important;border-left:0 !important;border-top:0 !important;background-color:#81963b !important;padding:1px 3px 1px 3px !important}.grd_inf{background-color:#d8d8d8;border-top:1px solid #d0d0d0 !important}.loader{border:0 !important;background:#81963b !important}.defaultLoader{width:32px;height:32px;background:transparent url("images/img_loading.gif") 0 0 no-repeat !important}.even{background-color:#bccd83}.odd{background-color:#fff}span.expClpFlt a.btnExpClpFlt:hover{background-color:transparent !important}.activeHeader{background:#81963b !important}
|
|
@ -1,6 +1 @@
|
|||
/**
|
||||
* tablefilter v0.4.40 by Max Guglielmi
|
||||
* build date: 2017-02-11T12:40:33.756Z
|
||||
* MIT License
|
||||
*/
|
||||
table.TF{padding:0;color:#000;border-right:1px solid #a4bed4;border-top:1px solid #a4bed4;border-left:1px solid #a4bed4;border-bottom:0;}table.TF th{margin:0;color:inherit;background:#d1e5fe url("images/bg_skyblue.gif") 0 0 repeat-x;border-color:#fdfdfd #a4bed4 #a4bed4 #fdfdfd;border-width:1px;border-style:solid}table.TF td{margin:0;padding:5px;color:inherit;border-bottom:1px solid #a4bed4;border-left:0;border-top:0;border-right:0}.fltrow{background-color:#d1e5fe !important;}.fltrow th,.fltrow td{padding:1px 3px 1px 3px !important}.flt,select.flt,select.flt_multi,.flt_s,.single_flt,.div_checklist{border:1px solid #a4bed4 !important}input.flt{width:99% !important}.inf{background-color:#e3efff !important;border:1px solid #a4bed4;height:$min-height;color:#004a6f}div.tot,div.status{border-right:0 !important}.helpBtn:hover{background-color:transparent}input.reset{background:transparent url("images/icn_clear_filters.png") center center no-repeat !important}.nextPage{background:transparent url("images/btn_next_page.gif") center center no-repeat !important;border:1px solid transparent !important;}.nextPage:hover{background:#ffe4ab url("images/btn_next_page.gif") center center no-repeat !important;border:1px solid #ffb552 !important}.previousPage{background:transparent url("images/btn_prev_page.gif") center center no-repeat !important;border:1px solid transparent !important;}.previousPage:hover{background:#ffe4ab url("images/btn_prev_page.gif") center center no-repeat !important;border:1px solid #ffb552 !important}.firstPage{background:transparent url("images/btn_first_page.gif") center center no-repeat !important;border:1px solid transparent !important;}.firstPage:hover{background:#ffe4ab url("images/btn_first_page.gif") center center no-repeat !important;border:1px solid #ffb552 !important}.lastPage{background:transparent url("images/btn_last_page.gif") center center no-repeat !important;border:1px solid transparent !important;}.lastPage:hover{background:#ffe4ab url("images/btn_last_page.gif") center center no-repeat !important;border:1px solid #ffb552 !important}.activeHeader{background:#ffe4ab !important;border:1px solid #ffb552 !important;color:inherit !important}div.grd_Cont{background-color:#d9eaed !important;border:1px solid #9cc !important;padding:0 !important;}div.grd_Cont .even{background-color:#fff}div.grd_Cont .odd{background-color:#e3efff}div.grd_headTblCont{background-color:#d9eaed !important;border-bottom:none !important}div.grd_tblCont table{border-right:none !important}div.grd_tblCont table th,div.grd_headTblCont table th,div.grd_headTblCont table td{background:#d9eaed url("images/bg_skyblue.gif") left top repeat-x;border-bottom:1px solid #a4bed4;border-right:1px solid #a4bed4 !important;border-left:1px solid #fff !important;border-top:1px solid #fff !important}div.grd_tblCont table td{border-bottom:1px solid #a4bed4 !important;border-right:0 !important;border-left:0 !important;border-top:0 !important}.grd_inf{background-color:#cce2fe;color:#004a6f;border-top:1px solid #9cc !important;}.grd_inf a{text-decoration:none;font-weight:bold}.loader{background-color:#2d8eef;border:1px solid #cce2fe;border-radius:5px}.even{background-color:#fff}.odd{background-color:#e3efff}span.expClpFlt a.btnExpClpFlt:hover{background-color:transparent !important}.ezActiveRow{background-color:#ffdc61 !important;color:inherit}.ezSelectedRow{background-color:#ffe4ab !important;color:inherit}.ezActiveCell{background-color:#fff !important;color:#000 !important;font-weight:bold}.ezETSelectedCell{background-color:#fff !important;font-weight:bold;color:#000 !important}
|
|
@ -1,6 +1 @@
|
|||
/**
|
||||
* tablefilter v0.4.40 by Max Guglielmi
|
||||
* build date: 2017-02-11T12:40:33.756Z
|
||||
* MIT License
|
||||
*/
|
||||
table.TF{padding:0;color:inherit;border-right:1px solid transparent;border-top:1px solid transparent;border-left:1px solid transparent;border-bottom:0;}table.TF th{margin:0;color:inherit;background-color:transparent;border-color:transparent;border-width:1px;border-style:solid;}table.TF th:last-child{border-right:1px solid transparent}table.TF td{margin:0;padding:5px;color:inherit;border-bottom:1px solid transparent;border-left:0;border-top:0;border-right:0}.fltrow{background-color:transparent;}.fltrow th,.fltrow td{padding:1px 3px 1px 3px;border-bottom:1px solid transparent !important;}.fltrow th:last-child,.fltrow td:last-child{border-right:1px solid transparent}.flt,select.flt,select.flt_multi,.flt_s,.single_flt,.div_checklist{border:1px solid #a4bed4}input.flt{width:99% !important}.inf{background-color:transparent;border:1px solid transparent;height:$min-height;color:inherit}div.tot,div.status{border-right:0 !important}.helpBtn:hover{background-color:transparent}input.reset{background:transparent url("images/icn_clear_filters.png") center center no-repeat !important}.nextPage{background:transparent url("images/btn_next_page.gif") center center no-repeat !important;border:1px solid transparent !important;}.nextPage:hover{background:#f7f7f7 url("images/btn_next_page.gif") center center no-repeat !important;border:1px solid #f7f7f7 !important}.previousPage{background:transparent url("images/btn_prev_page.gif") center center no-repeat !important;border:1px solid transparent !important;}.previousPage:hover{background:#f7f7f7 url("images/btn_prev_page.gif") center center no-repeat !important;border:1px solid #f7f7f7 !important}.firstPage{background:transparent url("images/btn_first_page.gif") center center no-repeat !important;border:1px solid transparent !important;}.firstPage:hover{background:#f7f7f7 url("images/btn_first_page.gif") center center no-repeat !important;border:1px solid #f7f7f7 !important}.lastPage{background:transparent url("images/btn_last_page.gif") center center no-repeat !important;border:1px solid transparent !important;}.lastPage:hover{background:#f7f7f7 url("images/btn_last_page.gif") center center no-repeat !important;border:1px solid #f7f7f7 !important}.activeHeader{background:#f7f7f7 !important;border:1px solid transparent;color:inherit !important}div.grd_Cont{-webkit-box-shadow:0 0 0 0 rgba(50,50,50,0.75);-moz-box-shadow:0 0 0 0 rgba(50,50,50,0.75);box-shadow:0 0 0 0 rgba(50,50,50,0.75);background-color:transparent;border:1px solid transparent;padding:0 !important;}div.grd_Cont .even{background-color:transparent}div.grd_Cont .odd{background-color:#f7f7f7}div.grd_headTblCont{background-color:transparent;border-bottom:none !important}div.grd_tblCont table{border-right:none !important}div.grd_tblCont table th,div.grd_headTblCont table th,div.grd_headTblCont table td{background:transparent;border-bottom:1px solid transparent;border-right:1px solid transparent !important;border-left:1px solid transparent;border-top:1px solid transparent}div.grd_tblCont table td{border-bottom:1px solid transparent;border-right:0 !important;border-left:0 !important;border-top:0 !important}.grd_inf{background-color:transparent;color:inherit;border-top:1px solid transparent;}.grd_inf a{text-decoration:none;font-weight:bold}.loader{background-color:#f7f7f7;border:1px solid #f7f7f7;border-radius:5px;color:#000;text-shadow:none}.even{background-color:transparent}.odd{background-color:#f7f7f7}span.expClpFlt a.btnExpClpFlt:hover{background-color:transparent !important}.ezActiveRow{background-color:#ccc !important;color:inherit}.ezSelectedRow{background-color:#ccc !important;color:inherit}.ezActiveCell{background-color:transparent;color:inherit;font-weight:bold}.ezETSelectedCell{background-color:transparent;font-weight:bold;color:inherit}
|
15
dist/tablefilter/tablefilter.js
vendored
15
dist/tablefilter/tablefilter.js
vendored
File diff suppressed because one or more lines are too long
1
dist/tablefilter/tablefilter.js.map
vendored
1
dist/tablefilter/tablefilter.js.map
vendored
File diff suppressed because one or more lines are too long
File diff suppressed because one or more lines are too long
File diff suppressed because one or more lines are too long
1
dist/tablefilter/tf-1-2aa33b10e0e549020c12.js
vendored
Normal file
1
dist/tablefilter/tf-1-2aa33b10e0e549020c12.js
vendored
Normal file
File diff suppressed because one or more lines are too long
12319
package-lock.json
generated
Normal file
12319
package-lock.json
generated
Normal file
File diff suppressed because it is too large
Load diff
62
package.json
62
package.json
|
@ -1,6 +1,6 @@
|
|||
{
|
||||
"name": "tablefilter",
|
||||
"version": "0.4.40",
|
||||
"version": "0.7.3",
|
||||
"description": "A Javascript library making HTML tables filterable and a bit more",
|
||||
"license": "MIT",
|
||||
"author": {
|
||||
|
@ -22,54 +22,58 @@
|
|||
"pagination"
|
||||
],
|
||||
"scripts": {
|
||||
"dev": "grunt dev",
|
||||
"build": "grunt build",
|
||||
"lint": "eslint src/**/*.js test/*.js *.js",
|
||||
"dev": "webpack --colors --config webpack.dev.config.js",
|
||||
"build": "webpack --colors --config webpack.config.js",
|
||||
"build:css": "stylus -c static/style/tablefilter.styl -o dist/tablefilter/style && stylus -c static/style/extensions -o dist/tablefilter/style && stylus -c static/style/themes/default -o dist/tablefilter/style/themes/default && stylus -c static/style/themes/mytheme -o dist/tablefilter/style/themes/mytheme && stylus -c static/style/themes/skyblue -o dist/tablefilter/style/themes/skyblue && stylus -c static/style/themes/transparent -o dist/tablefilter/style/themes/transparent",
|
||||
"build:demos": "grunt build-demos",
|
||||
"server": "grunt server",
|
||||
"eslint": "grunt eslint",
|
||||
"build:test": "webpack --colors --config webpack.test.config.js",
|
||||
"server": "webpack-dev-server --colors --hot --config ./webpack.dev.config.js",
|
||||
"test": "grunt test",
|
||||
"codecov": "./node_modules/.bin/codecov",
|
||||
"esdoc": "grunt esdoc",
|
||||
"esdoc": "esdoc",
|
||||
"dist": "grunt",
|
||||
"deploy": "grunt deploy",
|
||||
"build:all": "grunt build-all",
|
||||
"start": "npm run server"
|
||||
},
|
||||
"publishConfig": {
|
||||
"tag": "next"
|
||||
},
|
||||
"devDependencies": {
|
||||
"babel-core": "^6.22.1",
|
||||
"babel-eslint": "7.1.1",
|
||||
"babel-loader": "^6.2.9",
|
||||
"babel-plugin-transform-es2015-classes": "^6.22.0",
|
||||
"babel-preset-es2015": "^6.22.0",
|
||||
"clean-webpack-plugin": "^0.1.15",
|
||||
"codecov": "1.0.1",
|
||||
"@babel/core": "7.10.0",
|
||||
"@babel/preset-env": "7.10.0",
|
||||
"babel-eslint": "10.1.0",
|
||||
"babel-loader": "^8.0.2",
|
||||
"babel-preset-env": "1.7.0",
|
||||
"clean-webpack-plugin": "^3.0.0",
|
||||
"codecov": "3.7.1",
|
||||
"diacritics": "1.3.0",
|
||||
"esdoc": "1.1.0",
|
||||
"esdoc-standard-plugin": "1.0.0",
|
||||
"eslint": "6.5.0",
|
||||
"format-number": "3.0.0",
|
||||
"grunt": "^1.0.1",
|
||||
"grunt-babel": "^6.0.0",
|
||||
"grunt-cli": "1.2.0",
|
||||
"grunt-contrib-clean": "^1.0.0",
|
||||
"grunt-contrib-connect": "^1.0.2",
|
||||
"grunt-cli": "1.3.2",
|
||||
"grunt-contrib-clean": "^2.0.0",
|
||||
"grunt-contrib-connect": "^2.0.0",
|
||||
"grunt-contrib-copy": "^1.0.0",
|
||||
"grunt-contrib-stylus": "^1.2.0",
|
||||
"grunt-contrib-watch": "^1.0.0",
|
||||
"grunt-esdoc": "^0.0.4",
|
||||
"grunt-eslint": "19.0.0",
|
||||
"grunt-gh-pages": "^2.0.0",
|
||||
"grunt-qunit-istanbul": "1.0.0",
|
||||
"grunt-qunit-istanbul": "1.1.0",
|
||||
"grunt-shell": "3.0.0",
|
||||
"grunt-string-replace": "^1.3.1",
|
||||
"grunt-webpack": "^2.0.1",
|
||||
"isparta-loader": "2.0.0",
|
||||
"script-loader": "^0.7.0",
|
||||
"string-replace-webpack-plugin": "^0.0.5",
|
||||
"sugar-date": "2.0.4",
|
||||
"webpack": "^2.2.1",
|
||||
"webpack-dev-server": "^2.3.0"
|
||||
"string-replace-webpack-plugin": "^0.1.3",
|
||||
"stylus": "^0.54.5",
|
||||
"sugar-date": "2.0.6",
|
||||
"uglifyjs-webpack-plugin": "2.2.0",
|
||||
"webpack": "^4.38.0",
|
||||
"webpack-cli": "^3.0.8",
|
||||
"webpack-dev-server": "^3.1.11"
|
||||
},
|
||||
"dependencies": {},
|
||||
"bugs": {
|
||||
"url": "https://github.com/koalyptus/TableFilter/issues"
|
||||
},
|
||||
"homepage": "http://koalyptus.github.io/TableFilter"
|
||||
"homepage": "https://www.tablefilter.com"
|
||||
}
|
||||
|
|
|
@ -19,4 +19,4 @@ export const has = (arr, val, caseSensitive) => {
|
|||
}
|
||||
}
|
||||
return false;
|
||||
}
|
||||
};
|
||||
|
|
29
src/dom.js
29
src/dom.js
|
@ -18,7 +18,7 @@ export const getText = (node) => {
|
|||
return trim(node.innerText);
|
||||
}
|
||||
return trim(node.textContent);
|
||||
}
|
||||
};
|
||||
|
||||
/**
|
||||
* Returns the first text node contained in the supplied node
|
||||
|
@ -32,11 +32,11 @@ export const getFirstTextNode = (node) => {
|
|||
return n.data;
|
||||
}
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
/**
|
||||
* Creates an html element with given collection of attributes
|
||||
* @param {String} tag a string of the html tag to create
|
||||
* @param {String} tag html tag name
|
||||
* @param {Array} an undetermined number of arrays containing the with 2
|
||||
* items, the attribute name and its value ['id','myId']
|
||||
* @return {Object} created element
|
||||
|
@ -55,9 +55,8 @@ export const createElm = (...args) => {
|
|||
el.setAttribute(arg[0], arg[1]);
|
||||
}
|
||||
}
|
||||
|
||||
return el;
|
||||
}
|
||||
};
|
||||
|
||||
/**
|
||||
* Removes passed node from DOM
|
||||
|
@ -88,7 +87,7 @@ export const hasClass = (ele, cls) => {
|
|||
return ele.classList.contains(cls);
|
||||
}
|
||||
return ele.className.match(new RegExp('(\\s|^)' + cls + '(\\s|$)'));
|
||||
}
|
||||
};
|
||||
|
||||
/**
|
||||
* Adds the specified class to the passed element
|
||||
|
@ -111,7 +110,7 @@ export const addClass = (ele, cls) => {
|
|||
else if (!hasClass(ele, cls)) {
|
||||
ele.className += ' ' + cls;
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
/**
|
||||
* Removes the specified class to the passed element
|
||||
|
@ -129,7 +128,7 @@ export const removeClass = (ele, cls) => {
|
|||
}
|
||||
let reg = new RegExp('(\\s|^)' + cls + '(\\s|$)', 'g');
|
||||
ele.className = ele.className.replace(reg, '');
|
||||
}
|
||||
};
|
||||
|
||||
/**
|
||||
* Creates and returns an option element
|
||||
|
@ -141,27 +140,29 @@ export const removeClass = (ele, cls) => {
|
|||
export const createOpt = (text, value, isSel) => {
|
||||
let isSelected = isSel ? true : false;
|
||||
let opt = isSelected ?
|
||||
createElm('option', ['value', value], ['selected', 'true']) :
|
||||
createElm('option', ['value', value]);
|
||||
createElm('option', ['value', value], ['selected', 'true']) :
|
||||
createElm('option', ['value', value]);
|
||||
opt.appendChild(createText(text));
|
||||
return opt;
|
||||
}
|
||||
};
|
||||
|
||||
/**
|
||||
* Creates and returns a checklist item
|
||||
* @param {String} id index of check item
|
||||
* @param {String} chkValue check item value
|
||||
* @param {String} labelText check item label text
|
||||
* @param {Array} extraAttr array containing attribute name and its value
|
||||
* @return {Object} li DOM element
|
||||
*/
|
||||
export const createCheckItem = (id, chkValue, labelText) => {
|
||||
export const createCheckItem = (id, chkValue, labelText, extraAttr = []) => {
|
||||
let li = createElm('li');
|
||||
let label = createElm('label', ['for', id]);
|
||||
let check = createElm('input',
|
||||
['id', id],
|
||||
['name', id],
|
||||
['type', 'checkbox'],
|
||||
['value', chkValue]
|
||||
['value', chkValue],
|
||||
extraAttr
|
||||
);
|
||||
label.appendChild(check);
|
||||
label.appendChild(createText(labelText));
|
||||
|
@ -169,7 +170,7 @@ export const createCheckItem = (id, chkValue, labelText) => {
|
|||
li.label = label;
|
||||
li.check = check;
|
||||
return li;
|
||||
}
|
||||
};
|
||||
|
||||
/**
|
||||
* Returns the element matching the supplied Id
|
||||
|
|
23
src/event.js
23
src/event.js
|
@ -99,3 +99,26 @@ export const keyCode = (evt) => {
|
|||
return evt.charCode ? evt.charCode :
|
||||
(evt.keyCode ? evt.keyCode : (evt.which ? evt.which : 0));
|
||||
};
|
||||
|
||||
/**
|
||||
* Check code of pressed key is one of the expected key codes
|
||||
*
|
||||
* @param {Event} evt key event
|
||||
* @param {Array} keyCodes list of keycodes to check
|
||||
*/
|
||||
export const isKeyPressed = (evt, keyCodes = []) => {
|
||||
return keyCodes.indexOf(keyCode(evt)) !== -1;
|
||||
};
|
||||
|
||||
/**
|
||||
* Bind passed function to passed scope
|
||||
* @param {Function} fn function
|
||||
* @param {Object} scope object instance
|
||||
*/
|
||||
export function bound(fn, scope) {
|
||||
let boundFnName = `${fn.name}_bound`;
|
||||
if (!scope[boundFnName]) {
|
||||
scope[boundFnName] = fn.bind(scope);
|
||||
}
|
||||
return scope[boundFnName];
|
||||
}
|
||||
|
|
|
@ -1,6 +1,7 @@
|
|||
import {Feature} from '../../feature';
|
||||
import {tag} from '../../dom';
|
||||
import {INPUT} from '../../const';
|
||||
import {defaultsStr} from '../../settings';
|
||||
import {root} from '../../root';
|
||||
|
||||
const INSTANTIATION_ERROR = `Failed to instantiate EditTable object.
|
||||
|
@ -20,19 +21,19 @@ export default class AdapterEzEditTable extends Feature {
|
|||
* @param {Object} cfg Configuration options for ezEditTable library
|
||||
*/
|
||||
constructor(tf, cfg) {
|
||||
super(tf, cfg.name);
|
||||
super(tf, AdapterEzEditTable);
|
||||
|
||||
/**
|
||||
* Module description
|
||||
* @type {String}
|
||||
*/
|
||||
this.desc = cfg.description || 'ezEditTable adapter';
|
||||
this.desc = defaultsStr(cfg.description, 'ezEditTable adapter');
|
||||
|
||||
/**
|
||||
* Filename of ezEditTable library
|
||||
* @type {String}
|
||||
*/
|
||||
this.filename = cfg.filename || 'ezEditTable.js';
|
||||
this.filename = defaultsStr(cfg.filename, 'ezEditTable.js');
|
||||
|
||||
/**
|
||||
* Path to ezEditTable library
|
||||
|
@ -50,13 +51,15 @@ export default class AdapterEzEditTable extends Feature {
|
|||
* Path to ezEditTable stylesheet
|
||||
* @type {String}
|
||||
*/
|
||||
this.stylesheet = cfg.stylesheet || this.vendorPath + 'ezEditTable.css';
|
||||
this.stylesheet = defaultsStr(cfg.stylesheet,
|
||||
this.vendorPath + 'ezEditTable.css');
|
||||
|
||||
/**
|
||||
* Name of ezEditTable stylesheet
|
||||
* @type {String}
|
||||
*/
|
||||
this.stylesheetName = cfg.stylesheet_name || 'ezEditTableCss';
|
||||
this.stylesheetName = defaultsStr(cfg.stylesheet_name,
|
||||
'ezEditTableCss');
|
||||
|
||||
// Enable the ezEditTable's scroll into view behaviour if grid layout on
|
||||
cfg.scroll_into_view = cfg.scroll_into_view === false ?
|
||||
|
@ -117,7 +120,7 @@ export default class AdapterEzEditTable extends Feature {
|
|||
//start row for EditTable constructor needs to be calculated
|
||||
let startRow,
|
||||
cfg = this.cfg,
|
||||
thead = tag(tf.tbl, 'thead');
|
||||
thead = tag(tf.dom(), 'thead');
|
||||
|
||||
//if thead exists and startRow not specified, startRow is calculated
|
||||
//automatically by EditTable
|
||||
|
@ -158,7 +161,7 @@ export default class AdapterEzEditTable extends Feature {
|
|||
et.ClearSelections();
|
||||
/* eslint-enable */
|
||||
let cellIndex = selectedElm.cellIndex,
|
||||
row = tf.tbl.rows[nextRowIndex];
|
||||
row = tf.dom().rows[nextRowIndex];
|
||||
if (et.defaultSelection === 'both') {
|
||||
/* eslint-disable */
|
||||
slc.SelectRowByIndex(nextRowIndex);
|
||||
|
@ -172,7 +175,7 @@ export default class AdapterEzEditTable extends Feature {
|
|||
}
|
||||
//Table is filtered
|
||||
if (tf.validRowsIndex.length !== tf.getRowsNb()) {
|
||||
let r = tf.tbl.rows[nextRowIndex];
|
||||
let r = tf.dom().rows[nextRowIndex];
|
||||
if (r) {
|
||||
r.scrollIntoView(false);
|
||||
}
|
||||
|
@ -208,7 +211,7 @@ export default class AdapterEzEditTable extends Feature {
|
|||
paging = tf.feature('paging'),
|
||||
//pgup/pgdown keys
|
||||
d = keyCode === 34 || keyCode === 33 ?
|
||||
(paging && paging.pagingLength || et.nbRowsPerPage) :
|
||||
(paging && paging.pageLength || et.nbRowsPerPage) :
|
||||
1;
|
||||
|
||||
//If next row is not valid, next valid filtered row needs to be
|
||||
|
@ -278,11 +281,11 @@ export default class AdapterEzEditTable extends Feature {
|
|||
if (tf.feature('paging').nbPages > 1) {
|
||||
let paging = tf.feature('paging');
|
||||
//page length is re-assigned in case it has changed
|
||||
et.nbRowsPerPage = paging.pagingLength;
|
||||
et.nbRowsPerPage = paging.pageLength;
|
||||
let validIndexes = tf.validRowsIndex,
|
||||
validIdxLen = validIndexes.length,
|
||||
pagingEndRow = parseInt(paging.startPagingRow, 10) +
|
||||
parseInt(paging.pagingLength, 10);
|
||||
parseInt(paging.pageLength, 10);
|
||||
let rowIndex = row.rowIndex;
|
||||
|
||||
if ((rowIndex === validIndexes[validIdxLen - 1]) &&
|
||||
|
@ -502,3 +505,5 @@ export default class AdapterEzEditTable extends Feature {
|
|||
this.initialized = false;
|
||||
}
|
||||
}
|
||||
|
||||
AdapterEzEditTable.meta = {altName: 'advancedGrid'};
|
||||
|
|
|
@ -1,7 +1,11 @@
|
|||
import {Feature} from '../../feature';
|
||||
import {createText, elm} from '../../dom';
|
||||
import {isArray, isFn, isUndef, isEmpty, EMPTY_FN} from '../../types';
|
||||
import {isArray, isEmpty, EMPTY_FN} from '../../types';
|
||||
import {numSortAsc} from '../../sort';
|
||||
import {FORMATTED_NUMBER} from '../../const';
|
||||
import formatNumber from 'format-number';
|
||||
import {defaultsFn, defaultsArr} from '../../settings';
|
||||
import {bound} from '../../event';
|
||||
|
||||
const EVENTS = [
|
||||
'after-filtering',
|
||||
|
@ -29,21 +33,19 @@ export default class ColOps extends Feature {
|
|||
* @param {Object} opts Configuration object
|
||||
*/
|
||||
constructor(tf, opts) {
|
||||
super(tf, opts.name);
|
||||
super(tf, ColOps);
|
||||
|
||||
/**
|
||||
* Callback fired before columns operations start
|
||||
* @type {Function}
|
||||
*/
|
||||
this.onBeforeOperation = isFn(opts.on_before_operation) ?
|
||||
opts.on_before_operation : EMPTY_FN;
|
||||
this.onBeforeOperation = defaultsFn(opts.on_before_operation, EMPTY_FN);
|
||||
|
||||
/**
|
||||
* Callback fired after columns operations are completed
|
||||
* @type {Function}
|
||||
*/
|
||||
this.onAfterOperation = isFn(opts.on_after_operation) ?
|
||||
opts.on_after_operation : EMPTY_FN;
|
||||
this.onAfterOperation = defaultsFn(opts.on_after_operation, EMPTY_FN);
|
||||
|
||||
/**
|
||||
* Configuration options
|
||||
|
@ -55,46 +57,53 @@ export default class ColOps extends Feature {
|
|||
* List of DOM element IDs containing column's calculation result
|
||||
* @type {Array}
|
||||
*/
|
||||
this.labelIds = opts.id || [];
|
||||
this.labelIds = defaultsArr(opts.id, []);
|
||||
|
||||
/**
|
||||
* List of columns' indexes for calculations
|
||||
* @type {Array}
|
||||
*/
|
||||
this.colIndexes = opts.col || [];
|
||||
this.colIndexes = defaultsArr(opts.col, []);
|
||||
|
||||
/**
|
||||
* List of operations - possible values: 'sum', 'mean', 'min', 'max',
|
||||
* 'median', 'q1', 'q3'
|
||||
* @type {Array}
|
||||
*/
|
||||
this.operations = opts.operation || [];
|
||||
this.operations = defaultsArr(opts.operation, []);
|
||||
|
||||
/**
|
||||
* List of write methods used to write the result - possible values:
|
||||
* 'innerHTML', 'setValue', 'createTextNode'
|
||||
* @type {Array}
|
||||
*/
|
||||
this.outputTypes = opts.write_method || [];
|
||||
this.outputTypes = defaultsArr(opts.write_method, []);
|
||||
|
||||
/**
|
||||
* List of format objects used for formatting the result -
|
||||
* refer to https://github.com/componitable/format-number to check
|
||||
* configuration options
|
||||
* @type {Array}
|
||||
*/
|
||||
this.formatResults = defaultsArr(opts.format_result, []);
|
||||
|
||||
/**
|
||||
* List of row indexes displaying the results
|
||||
* @type {Array}
|
||||
*/
|
||||
this.totRowIndexes = opts.tot_row_index || [];
|
||||
this.totRowIndexes = defaultsArr(opts.tot_row_index, []);
|
||||
|
||||
/**
|
||||
* List of row indexes excluded from calculations
|
||||
* @type {Array}
|
||||
*/
|
||||
this.excludeRows = opts.exclude_row || [];
|
||||
this.excludeRows = defaultsArr(opts.exclude_row, []);
|
||||
|
||||
/**
|
||||
* List of decimal precision for calculation results
|
||||
* @type {Array}
|
||||
*/
|
||||
this.decimalPrecisions = isUndef(opts.decimal_precision) ?
|
||||
2 : opts.decimal_precision;
|
||||
this.decimalPrecisions = defaultsArr(opts.decimal_precision, 2);
|
||||
|
||||
this.enable();
|
||||
}
|
||||
|
@ -107,7 +116,7 @@ export default class ColOps extends Feature {
|
|||
return;
|
||||
}
|
||||
// subscribe to events
|
||||
this.emitter.on(EVENTS, () => this.calcAll());
|
||||
this.emitter.on(EVENTS, bound(this.calcAll, this));
|
||||
|
||||
this.calcAll();
|
||||
|
||||
|
@ -140,13 +149,9 @@ export default class ColOps extends Feature {
|
|||
this.onBeforeOperation(tf, this);
|
||||
this.emitter.emit('before-column-operation', tf, this);
|
||||
|
||||
let colIndexes = this.colIndexes,
|
||||
colOperations = this.operations,
|
||||
outputTypes = this.outputTypes,
|
||||
totRowIndexes = this.totRowIndexes,
|
||||
excludeRows = this.excludeRows,
|
||||
decimalPrecisions = isUndef(this.decimalPrecisions) ?
|
||||
2 : this.decimalPrecisions;
|
||||
let { colIndexes, operations: colOperations, outputTypes,
|
||||
totRowIndexes, excludeRows, formatResults,
|
||||
decimalPrecisions } = this;
|
||||
|
||||
//nuovella: determine unique list of columns to operate on
|
||||
let uIndexes = [];
|
||||
|
@ -157,7 +162,7 @@ export default class ColOps extends Feature {
|
|||
});
|
||||
|
||||
let nbCols = uIndexes.length,
|
||||
rows = tf.tbl.rows,
|
||||
rows = tf.dom().rows,
|
||||
colValues = [];
|
||||
|
||||
for (let u = 0; u < nbCols; u++) {
|
||||
|
@ -165,7 +170,7 @@ export default class ColOps extends Feature {
|
|||
//use uIndexes because we only want to pass through this loop
|
||||
//once for each column get the values in this unique column
|
||||
colValues.push(
|
||||
tf.getFilteredDataCol(uIndexes[u], false, true, excludeRows)
|
||||
tf.getVisibleColumnData(uIndexes[u], false, excludeRows)
|
||||
);
|
||||
|
||||
let curValues = colValues[u];
|
||||
|
@ -176,6 +181,7 @@ export default class ColOps extends Feature {
|
|||
precisions = [],
|
||||
labels = [],
|
||||
writeType,
|
||||
formatResult = [],
|
||||
idx = 0;
|
||||
|
||||
for (let k = 0; k < colIndexes.length; k++) {
|
||||
|
@ -186,6 +192,8 @@ export default class ColOps extends Feature {
|
|||
precisions[idx] = decimalPrecisions[k];
|
||||
labels[idx] = this.labelIds[k];
|
||||
writeType = isArray(outputTypes) ? outputTypes[k] : null;
|
||||
formatResult[idx] =
|
||||
this.configureFormat(uIndexes[u], formatResults[k]);
|
||||
idx++;
|
||||
}
|
||||
|
||||
|
@ -219,7 +227,8 @@ export default class ColOps extends Feature {
|
|||
result,
|
||||
labels[i],
|
||||
writeType,
|
||||
precisions[i]
|
||||
precisions[i],
|
||||
formatResult[i]
|
||||
);
|
||||
|
||||
}//for i
|
||||
|
@ -245,8 +254,8 @@ export default class ColOps extends Feature {
|
|||
*/
|
||||
columnCalc(colIndex, operation = SUM, precision) {
|
||||
let excludeRows = this.excludeRows || [];
|
||||
let colValues =
|
||||
this.tf.getFilteredDataCol(colIndex, false, true, excludeRows);
|
||||
let colValues = tf.getVisibleColumnData(colIndex, false, excludeRows);
|
||||
|
||||
return Number(this.calc(colValues, operation, precision));
|
||||
}
|
||||
|
||||
|
@ -402,7 +411,8 @@ export default class ColOps extends Feature {
|
|||
* @param {Number} [precision=2] Applied decimal precision
|
||||
* @private
|
||||
*/
|
||||
writeResult(result = 0, label, writeType = 'innerhtml', precision = 2) {
|
||||
writeResult(result = 0, label, writeType = 'innerhtml',
|
||||
precision = 2, format = {}) {
|
||||
let labelElm = elm(label);
|
||||
|
||||
if (!labelElm) {
|
||||
|
@ -412,6 +422,8 @@ export default class ColOps extends Feature {
|
|||
result = result.toFixed(precision);
|
||||
if (isNaN(result) || !isFinite(result)) {
|
||||
result = '';
|
||||
} else {
|
||||
result = formatNumber(format)(result);
|
||||
}
|
||||
|
||||
switch (writeType.toLowerCase()) {
|
||||
|
@ -429,13 +441,38 @@ export default class ColOps extends Feature {
|
|||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Configure the format options used to format the operation result based
|
||||
* on column type.
|
||||
* @param {Number} colIndex Column index
|
||||
* @param {Object} [format={}] Format object
|
||||
* @returns {Object}
|
||||
* @private
|
||||
*/
|
||||
configureFormat(colIndex, format = {}) {
|
||||
let tf = this.tf;
|
||||
if (tf.hasType(colIndex, [FORMATTED_NUMBER])) {
|
||||
let colType = tf.colTypes[colIndex];
|
||||
if (colType.decimal && !format.decimal) {
|
||||
format.decimal = colType.decimal;
|
||||
}
|
||||
if (colType.thousands && !format.integerSeparator) {
|
||||
format.integerSeparator = colType.thousands;
|
||||
}
|
||||
} else {
|
||||
format.decimal = format.decimal || '';
|
||||
format.integerSeparator = format.integerSeparator || '';
|
||||
}
|
||||
return format;
|
||||
}
|
||||
|
||||
/** Remove extension */
|
||||
destroy() {
|
||||
if (!this.initialized) {
|
||||
return;
|
||||
}
|
||||
// unsubscribe to events
|
||||
this.emitter.off(EVENTS, () => this.calcAll());
|
||||
this.emitter.off(EVENTS, bound(this.calcAll, this));
|
||||
|
||||
this.initialized = false;
|
||||
}
|
||||
|
|
|
@ -1,11 +1,16 @@
|
|||
import {Feature} from '../../feature';
|
||||
import {
|
||||
addClass, removeClass, createCheckItem, createElm, elm, removeElm,
|
||||
getText
|
||||
getText, tag
|
||||
} from '../../dom';
|
||||
import {isFn, EMPTY_FN} from '../../types';
|
||||
import {isUndef, EMPTY_FN, isNull} from '../../types';
|
||||
import {addEvt, targetEvt, removeEvt} from '../../event';
|
||||
import {root} from '../../root';
|
||||
import {NONE} from '../../const';
|
||||
import {
|
||||
defaultsBool, defaultsStr, defaultsFn, defaultsNb, defaultsArr
|
||||
} from '../../settings';
|
||||
import {RIGHT} from '../../modules/toolbar';
|
||||
|
||||
/**
|
||||
* Columns Visibility extension
|
||||
|
@ -18,7 +23,7 @@ export default class ColsVisibility extends Feature {
|
|||
* @param {Object} Configuration object
|
||||
*/
|
||||
constructor(tf, f) {
|
||||
super(tf, f.name);
|
||||
super(tf, ColsVisibility);
|
||||
|
||||
// Configuration object
|
||||
let cfg = this.config;
|
||||
|
@ -33,7 +38,7 @@ export default class ColsVisibility extends Feature {
|
|||
* Module description
|
||||
* @type {String}
|
||||
*/
|
||||
this.desc = f.description || 'Columns visibility manager';
|
||||
this.desc = defaultsStr(f.description, 'Columns visibility manager');
|
||||
|
||||
/**
|
||||
* show/hide columns container element
|
||||
|
@ -57,13 +62,13 @@ export default class ColsVisibility extends Feature {
|
|||
* Enable tick to hide a column, defaults to true
|
||||
* @type {Boolean}
|
||||
*/
|
||||
this.tickToHide = f.tick_to_hide === false ? false : true;
|
||||
this.tickToHide = defaultsBool(f.tick_to_hide, true);
|
||||
|
||||
/**
|
||||
* Enable columns manager UI, defaults to true
|
||||
* @type {Boolean}
|
||||
*/
|
||||
this.manager = f.manager === false ? false : true;
|
||||
this.manager = defaultsBool(f.manager, true);
|
||||
|
||||
/**
|
||||
* Headers HTML table reference only if headers are external
|
||||
|
@ -75,112 +80,115 @@ export default class ColsVisibility extends Feature {
|
|||
* Headers row index only if headers are external
|
||||
* @type {Number}
|
||||
*/
|
||||
this.headersIndex = f.headers_index || 1;
|
||||
this.headersIndex = defaultsNb(f.headers_index, 1);
|
||||
|
||||
/**
|
||||
* ID of main container element
|
||||
* @type {String}
|
||||
*/
|
||||
this.contElTgtId = f.container_target_id || null;
|
||||
this.contElTgtId = defaultsStr(f.container_target_id, null);
|
||||
|
||||
/**
|
||||
* Alternative text for column headers in column manager UI
|
||||
* @type {Array}
|
||||
*/
|
||||
this.headersText = f.headers_text || null;
|
||||
this.headersText = defaultsArr(f.headers_text, []);
|
||||
|
||||
/**
|
||||
* ID of button's container element
|
||||
* @type {String}
|
||||
*/
|
||||
this.btnTgtId = f.btn_target_id || null;
|
||||
this.btnTgtId = defaultsStr(f.btn_target_id, null);
|
||||
|
||||
/**
|
||||
* Button's text, defaults to Columns▼
|
||||
* @type {String}
|
||||
*/
|
||||
this.btnText = f.btn_text || 'Columns▼';
|
||||
this.btnText = defaultsStr(f.btn_text, 'Columns▼');
|
||||
|
||||
/**
|
||||
* Button's inner HTML
|
||||
* @type {String}
|
||||
*/
|
||||
this.btnHtml = f.btn_html || null;
|
||||
this.btnHtml = defaultsStr(f.btn_html, null);
|
||||
|
||||
/**
|
||||
* Css class for button
|
||||
* @type {String}
|
||||
*/
|
||||
this.btnCssClass = f.btn_css_class || 'colVis';
|
||||
this.btnCssClass = defaultsStr(f.btn_css_class, 'colVis');
|
||||
|
||||
/**
|
||||
* Columns manager UI close link text, defaults to 'Close'
|
||||
* @type {String}
|
||||
*/
|
||||
this.btnCloseText = f.btn_close_text || 'Close';
|
||||
this.btnCloseText = defaultsStr(f.btn_close_text, 'Close');
|
||||
|
||||
/**
|
||||
* Columns manager UI close link HTML
|
||||
* @type {String}
|
||||
*/
|
||||
this.btnCloseHtml = f.btn_close_html || null;
|
||||
this.btnCloseHtml = defaultsStr(f.btn_close_html, null);
|
||||
|
||||
/**
|
||||
* Css for columns manager UI close link
|
||||
* @type {String}
|
||||
*/
|
||||
this.btnCloseCssClass = f.btn_close_css_class || this.btnCssClass;
|
||||
this.btnCloseCssClass = defaultsStr(f.btn_close_css_class,
|
||||
this.btnCssClass);
|
||||
|
||||
/**
|
||||
* Extension's stylesheet filename
|
||||
* @type {String}
|
||||
*/
|
||||
this.stylesheet = f.stylesheet || 'colsVisibility.css';
|
||||
this.stylesheet = defaultsStr(f.stylesheet, 'colsVisibility.css');
|
||||
|
||||
/**
|
||||
* Css for columns manager UI span
|
||||
* @type {String}
|
||||
*/
|
||||
this.spanCssClass = f.span_css_class || 'colVisSpan';
|
||||
this.spanCssClass = defaultsStr(f.span_css_class, 'colVisSpan');
|
||||
|
||||
/**
|
||||
* Css for columns manager UI main container
|
||||
* @type {String}
|
||||
*/
|
||||
this.contCssClass = f.cont_css_class || 'colVisCont';
|
||||
this.contCssClass = defaultsStr(f.cont_css_class, 'colVisCont');
|
||||
|
||||
/**
|
||||
* Css for columns manager UI checklist (ul)
|
||||
* @type {String}
|
||||
*/
|
||||
this.listCssClass = cfg.list_css_class || 'cols_checklist';
|
||||
this.listCssClass = defaultsStr(cfg.list_css_class, 'cols_checklist');
|
||||
|
||||
/**
|
||||
* Css for columns manager UI checklist item (li)
|
||||
* @type {String}
|
||||
*/
|
||||
this.listItemCssClass = cfg.checklist_item_css_class ||
|
||||
'cols_checklist_item';
|
||||
this.listItemCssClass = defaultsStr(cfg.checklist_item_css_class,
|
||||
'cols_checklist_item');
|
||||
|
||||
/**
|
||||
* Css for columns manager UI checklist item selected state (li)
|
||||
* @type {String}
|
||||
*/
|
||||
this.listSlcItemCssClass = cfg.checklist_selected_item_css_class ||
|
||||
'cols_checklist_slc_item';
|
||||
this.listSlcItemCssClass = defaultsStr(
|
||||
cfg.checklist_selected_item_css_class,
|
||||
'cols_checklist_slc_item'
|
||||
);
|
||||
|
||||
/**
|
||||
* Text preceding the columns list, defaults to 'Hide' or 'Show'
|
||||
* depending on tick mode (tick_to_hide option)
|
||||
* @type {String}
|
||||
*/
|
||||
this.text = f.text || (this.tickToHide ? 'Hide: ' : 'Show: ');
|
||||
this.text = defaultsStr(f.text, this.tickToHide ? 'Hide: ' : 'Show: ');
|
||||
|
||||
/**
|
||||
* List of columns indexes to be hidden at initialization
|
||||
* @type {Array}
|
||||
*/
|
||||
this.atStart = f.at_start || [];
|
||||
this.atStart = defaultsArr(f.at_start, []);
|
||||
|
||||
/**
|
||||
* Enable hover behaviour on columns manager button/link
|
||||
|
@ -198,7 +206,13 @@ export default class ColsVisibility extends Feature {
|
|||
* Text for select all option, defaults to 'Select all:'
|
||||
* @type {String}
|
||||
*/
|
||||
this.tickAllText = f.tick_all_text || 'Select all:';
|
||||
this.tickAllText = defaultsStr(f.tick_all_text, 'Select all:');
|
||||
|
||||
/**
|
||||
* Default position in toolbar ('left'|'center'|'right')
|
||||
* @type {String}
|
||||
*/
|
||||
this.toolbarPosition = defaultsStr(f.toolbar_position, RIGHT);
|
||||
|
||||
/**
|
||||
* List of indexes of hidden columns
|
||||
|
@ -216,73 +230,66 @@ export default class ColsVisibility extends Feature {
|
|||
* Callback fired when the extension is initialized
|
||||
* @type {Function}
|
||||
*/
|
||||
this.onLoaded = isFn(f.on_loaded) ? f.on_loaded : EMPTY_FN;
|
||||
this.onLoaded = defaultsFn(f.on_loaded, EMPTY_FN);
|
||||
|
||||
/**
|
||||
* Callback fired before the columns manager is opened
|
||||
* @type {Function}
|
||||
*/
|
||||
this.onBeforeOpen = isFn(f.on_before_open) ?
|
||||
f.on_before_open : EMPTY_FN;
|
||||
this.onBeforeOpen = defaultsFn(f.on_before_open, EMPTY_FN);
|
||||
|
||||
/**
|
||||
* Callback fired after the columns manager is opened
|
||||
* @type {Function}
|
||||
*/
|
||||
this.onAfterOpen = isFn(f.on_after_open) ? f.on_after_open : EMPTY_FN;
|
||||
this.onAfterOpen = defaultsFn(f.on_after_open, EMPTY_FN);
|
||||
|
||||
/**
|
||||
* Callback fired before the columns manager is closed
|
||||
* @type {Function}
|
||||
*/
|
||||
this.onBeforeClose = isFn(f.on_before_close) ?
|
||||
f.on_before_close : EMPTY_FN;
|
||||
this.onBeforeClose = defaultsFn(f.on_before_close, EMPTY_FN);
|
||||
|
||||
/**
|
||||
* Callback fired after the columns manager is closed
|
||||
* @type {Function}
|
||||
*/
|
||||
this.onAfterClose = isFn(f.on_after_close) ?
|
||||
f.on_after_close : EMPTY_FN;
|
||||
this.onAfterClose = defaultsFn(f.on_after_close, EMPTY_FN);
|
||||
|
||||
/**
|
||||
* Callback fired before a column is hidden
|
||||
* @type {Function}
|
||||
*/
|
||||
this.onBeforeColHidden = isFn(f.on_before_col_hidden) ?
|
||||
f.on_before_col_hidden : EMPTY_FN;
|
||||
this.onBeforeColHidden = defaultsFn(f.on_before_col_hidden, EMPTY_FN);
|
||||
|
||||
/**
|
||||
* Callback fired after a column is hidden
|
||||
* @type {Function}
|
||||
*/
|
||||
this.onAfterColHidden = isFn(f.on_after_col_hidden) ?
|
||||
f.on_after_col_hidden : EMPTY_FN;
|
||||
this.onAfterColHidden = defaultsFn(f.on_after_col_hidden, EMPTY_FN);
|
||||
|
||||
/**
|
||||
* Callback fired before a column is displayed
|
||||
* @type {Function}
|
||||
*/
|
||||
this.onBeforeColDisplayed = isFn(f.on_before_col_displayed) ?
|
||||
f.on_before_col_displayed : EMPTY_FN;
|
||||
this.onBeforeColDisplayed = defaultsFn(f.on_before_col_displayed,
|
||||
EMPTY_FN);
|
||||
|
||||
/**
|
||||
* Callback fired after a column is displayed
|
||||
* @type {Function}
|
||||
*/
|
||||
this.onAfterColDisplayed = isFn(f.on_after_col_displayed) ?
|
||||
f.on_after_col_displayed : EMPTY_FN;
|
||||
this.onAfterColDisplayed = defaultsFn(f.on_after_col_displayed,
|
||||
EMPTY_FN);
|
||||
|
||||
//Grid layout support
|
||||
if (tf.gridLayout) {
|
||||
this.headersTbl = tf.feature('gridLayout').headTbl; //headers table
|
||||
this.headersIndex = 0; //headers index
|
||||
this.onAfterColDisplayed = function () { };
|
||||
this.onAfterColHidden = function () { };
|
||||
}
|
||||
|
||||
//Loads extension stylesheet
|
||||
tf.import(f.name + 'Style', tf.stylePath + this.stylesheet, null,
|
||||
tf.import(f.name + 'Style', tf.getStylePath() + this.stylesheet, null,
|
||||
'link');
|
||||
|
||||
this.enable();
|
||||
|
@ -324,7 +331,7 @@ export default class ColsVisibility extends Feature {
|
|||
}
|
||||
|
||||
this.contEl.style.display = contDisplay === 'inline' ?
|
||||
'none' : 'inline';
|
||||
NONE : 'inline';
|
||||
|
||||
if (contDisplay !== 'inline') {
|
||||
this.onAfterOpen(this);
|
||||
|
@ -369,6 +376,9 @@ export default class ColsVisibility extends Feature {
|
|||
return;
|
||||
}
|
||||
|
||||
this.emitter.emit('initializing-extension', this,
|
||||
!isNull(this.btnTgtId));
|
||||
|
||||
this.emitter.on(['hide-column'],
|
||||
(tf, colIndex) => this.hideCol(colIndex));
|
||||
|
||||
|
@ -381,6 +391,7 @@ export default class ColsVisibility extends Feature {
|
|||
this.boundMouseup = this.onMouseup.bind(this);
|
||||
|
||||
this.emitter.emit('columns-visibility-initialized', this.tf, this);
|
||||
this.emitter.emit('extension-initialized', this);
|
||||
|
||||
// Hide columns at start at very end of initialization, do not move
|
||||
// as order is important
|
||||
|
@ -398,11 +409,10 @@ export default class ColsVisibility extends Feature {
|
|||
let span = createElm('span');
|
||||
span.className = this.spanCssClass;
|
||||
|
||||
//Container element (rdiv or custom element)
|
||||
if (!this.btnTgtId) {
|
||||
tf.setToolbar();
|
||||
}
|
||||
let targetEl = !this.btnTgtId ? tf.rDiv : elm(this.btnTgtId);
|
||||
// Container element (rdiv or custom element)
|
||||
let targetEl = !this.btnTgtId ?
|
||||
tf.feature('toolbar').container(this.toolbarPosition) :
|
||||
elm(this.btnTgtId);
|
||||
|
||||
if (!this.btnTgtId) {
|
||||
let firstChild = targetEl.firstChild;
|
||||
|
@ -423,7 +433,7 @@ export default class ColsVisibility extends Feature {
|
|||
} else {
|
||||
addEvt(btn, 'mouseover', (evt) => this.toggle(evt));
|
||||
}
|
||||
} else { //Custom html
|
||||
} else { // Custom html
|
||||
span.innerHTML = this.btnHtml;
|
||||
let colVisEl = span.firstChild;
|
||||
if (!this.enableHover) {
|
||||
|
@ -459,7 +469,7 @@ export default class ColsVisibility extends Feature {
|
|||
let ul = createElm('ul');
|
||||
ul.className = this.listCssClass;
|
||||
|
||||
let tbl = this.headersTbl ? this.headersTbl : tf.tbl;
|
||||
let tbl = this.headersTbl || tf.dom();
|
||||
let headerIndex = this.headersTbl ?
|
||||
this.headersIndex : tf.getHeadersRowIndex();
|
||||
let headerRow = tbl.rows[headerIndex];
|
||||
|
@ -485,8 +495,7 @@ export default class ColsVisibility extends Feature {
|
|||
|
||||
for (let i = 0; i < headerRow.cells.length; i++) {
|
||||
let cell = headerRow.cells[i];
|
||||
let cellText = this.headersText && this.headersText[i] ?
|
||||
this.headersText[i] : this._getHeaderText(cell);
|
||||
let cellText = this.headersText[i] || this._getHeaderText(cell);
|
||||
let liElm = createCheckItem('col_' + i + '_' + tf.id, cellText,
|
||||
cellText);
|
||||
addClass(liElm, this.listItemCssClass);
|
||||
|
@ -535,18 +544,17 @@ export default class ColsVisibility extends Feature {
|
|||
*/
|
||||
setHidden(colIndex, hide) {
|
||||
let tf = this.tf;
|
||||
let tbl = tf.tbl;
|
||||
let tbl = tf.dom();
|
||||
|
||||
if (hide) {
|
||||
this.onBeforeColHidden(this, colIndex);
|
||||
}
|
||||
if (!hide) {
|
||||
} else {
|
||||
this.onBeforeColDisplayed(this, colIndex);
|
||||
}
|
||||
|
||||
this._hideCells(tbl, colIndex, hide);
|
||||
this._hideElements(tbl, colIndex, hide);
|
||||
if (this.headersTbl) {
|
||||
this._hideCells(this.headersTbl, colIndex, hide);
|
||||
this._hideElements(this.headersTbl, colIndex, hide);
|
||||
}
|
||||
|
||||
let hiddenCols = this.hiddenCols;
|
||||
|
@ -561,46 +569,11 @@ export default class ColsVisibility extends Feature {
|
|||
}
|
||||
}
|
||||
|
||||
let gridLayout;
|
||||
let headTbl;
|
||||
let gridColElms;
|
||||
if (hide) {
|
||||
//This event is fired just after a column is displayed for
|
||||
//grid_layout support
|
||||
//TODO: grid layout module should be responsible for those
|
||||
//calculations
|
||||
if (tf.gridLayout) {
|
||||
gridLayout = tf.feature('gridLayout');
|
||||
headTbl = gridLayout.headTbl;
|
||||
gridColElms = gridLayout.colElms;
|
||||
let hiddenWidth = parseInt(
|
||||
gridColElms[colIndex].style.width, 10);
|
||||
|
||||
let headTblW = parseInt(headTbl.style.width, 10);
|
||||
headTbl.style.width = headTblW - hiddenWidth + 'px';
|
||||
tbl.style.width = headTbl.style.width;
|
||||
}
|
||||
|
||||
this.onAfterColHidden(this, colIndex);
|
||||
this.emitter.emit('column-hidden', tf, this, colIndex,
|
||||
this.hiddenCols);
|
||||
}
|
||||
|
||||
if (!hide) {
|
||||
//This event is fired just after a column is displayed for
|
||||
//grid_layout support
|
||||
//TODO: grid layout module should be responsible for those
|
||||
//calculations
|
||||
if (tf.gridLayout) {
|
||||
gridLayout = tf.feature('gridLayout');
|
||||
headTbl = gridLayout.headTbl;
|
||||
gridColElms = gridLayout.colElms;
|
||||
let width = parseInt(gridColElms[colIndex].style.width, 10);
|
||||
headTbl.style.width =
|
||||
(parseInt(headTbl.style.width, 10) + width) + 'px';
|
||||
tf.tbl.style.width = headTbl.style.width;
|
||||
}
|
||||
|
||||
} else {
|
||||
this.onAfterColDisplayed(this, colIndex);
|
||||
this.emitter.emit('column-shown', tf, this, colIndex,
|
||||
this.hiddenCols);
|
||||
|
@ -612,7 +585,7 @@ export default class ColsVisibility extends Feature {
|
|||
* @param {Number} colIndex Column index
|
||||
*/
|
||||
showCol(colIndex) {
|
||||
if (colIndex === undefined || !this.isColHidden(colIndex)) {
|
||||
if (isUndef(colIndex) || !this.isColHidden(colIndex)) {
|
||||
return;
|
||||
}
|
||||
if (this.manager && this.contEl) {
|
||||
|
@ -630,7 +603,7 @@ export default class ColsVisibility extends Feature {
|
|||
* @param {Number} colIndex Column index
|
||||
*/
|
||||
hideCol(colIndex) {
|
||||
if (colIndex === undefined || this.isColHidden(colIndex)) {
|
||||
if (isUndef(colIndex) || this.isColHidden(colIndex)) {
|
||||
return;
|
||||
}
|
||||
if (this.manager && this.contEl) {
|
||||
|
@ -659,7 +632,7 @@ export default class ColsVisibility extends Feature {
|
|||
* @param {Number} colIndex Column index
|
||||
*/
|
||||
toggleCol(colIndex) {
|
||||
if (colIndex === undefined || this.isColHidden(colIndex)) {
|
||||
if (isUndef(colIndex) || this.isColHidden(colIndex)) {
|
||||
this.showCol(colIndex);
|
||||
} else {
|
||||
this.hideCol(colIndex);
|
||||
|
@ -721,16 +694,29 @@ export default class ColsVisibility extends Feature {
|
|||
return '';
|
||||
}
|
||||
|
||||
_hideCells(tbl, colIndex, hide) {
|
||||
_hideElements(tbl, colIdx, hide) {
|
||||
this._hideCells(tbl, colIdx, hide);
|
||||
this._hideCol(tbl, colIdx, hide);
|
||||
}
|
||||
|
||||
_hideCells(tbl, colIdx, hide) {
|
||||
for (let i = 0; i < tbl.rows.length; i++) {
|
||||
let row = tbl.rows[i];
|
||||
let cell = row.cells[colIndex];
|
||||
let cell = row.cells[colIdx];
|
||||
if (cell) {
|
||||
cell.style.display = hide ? 'none' : '';
|
||||
cell.style.display = hide ? NONE : '';
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
_hideCol(tbl, colIdx, hide) {
|
||||
let colElms = tag(tbl, 'col');
|
||||
if (colElms.length === 0) {
|
||||
return;
|
||||
}
|
||||
colElms[colIdx].style.display = hide ? NONE : '';
|
||||
}
|
||||
|
||||
_hideAtStart() {
|
||||
this.atStart.forEach((colIdx) => {
|
||||
this.hideCol(colIdx);
|
||||
|
|
|
@ -1,7 +1,11 @@
|
|||
import {Feature} from '../../feature';
|
||||
import {createElm, removeElm, elm} from '../../dom';
|
||||
import {isFn, isUndef, EMPTY_FN} from '../../types';
|
||||
import {EMPTY_FN, isNull} from '../../types';
|
||||
import {addEvt} from '../../event';
|
||||
import {
|
||||
defaultsBool, defaultsStr, defaultsFn, defaultsNb,
|
||||
} from '../../settings';
|
||||
import {RIGHT} from '../../modules/toolbar';
|
||||
|
||||
/**
|
||||
* Filters Visibility extension
|
||||
|
@ -14,7 +18,7 @@ export default class FiltersVisibility extends Feature {
|
|||
* @param {Object} Configuration object
|
||||
*/
|
||||
constructor(tf, f) {
|
||||
super(tf, f.name);
|
||||
super(tf, FiltersVisibility);
|
||||
|
||||
/**
|
||||
* Module name
|
||||
|
@ -26,25 +30,26 @@ export default class FiltersVisibility extends Feature {
|
|||
* Module description
|
||||
* @type {String}
|
||||
*/
|
||||
this.desc = f.description || 'Filters row visibility manager';
|
||||
this.desc = defaultsStr(f.description,
|
||||
'Filters row visibility manager');
|
||||
|
||||
/**
|
||||
* Extension's stylesheet filename
|
||||
* @type {String}
|
||||
*/
|
||||
this.stylesheet = f.stylesheet || 'filtersVisibility.css';
|
||||
this.stylesheet = defaultsStr(f.stylesheet , 'filtersVisibility.css');
|
||||
|
||||
/**
|
||||
* Expand icon filename
|
||||
* @type {String}
|
||||
*/
|
||||
this.icnExpand = f.expand_icon_name || 'icn_exp.png';
|
||||
this.icnExpand = defaultsStr(f.expand_icon_name, 'icn_exp.png');
|
||||
|
||||
/**
|
||||
* Collapse icon filename
|
||||
* @type {String}
|
||||
*/
|
||||
this.icnCollapse = f.collapse_icon_name || 'icn_clp.png';
|
||||
this.icnCollapse = defaultsStr(f.collapse_icon_name, 'icn_clp.png');
|
||||
|
||||
/**
|
||||
* Main container element
|
||||
|
@ -88,13 +93,13 @@ export default class FiltersVisibility extends Feature {
|
|||
* Enable expand/collapse icon, defaults to true
|
||||
* @type {Boolean}
|
||||
*/
|
||||
this.enableIcon = f.enable_icon === false ? false : true;
|
||||
this.enableIcon = defaultsBool(f.enable_icon, true);
|
||||
|
||||
/**
|
||||
* Custom text for button
|
||||
* @type {String}
|
||||
*/
|
||||
this.btnText = f.btn_text || '';
|
||||
this.btnText = defaultsStr(f.btn_text, '');
|
||||
|
||||
/**
|
||||
* Collapse button HTML
|
||||
|
@ -116,62 +121,65 @@ export default class FiltersVisibility extends Feature {
|
|||
* Button's custom HTML
|
||||
* @type {String}
|
||||
*/
|
||||
this.btnHtml = f.btn_html || null;
|
||||
this.btnHtml = defaultsStr(f.btn_html, null);
|
||||
|
||||
/**
|
||||
* Css class for expand/collapse filters button
|
||||
* @type {String}
|
||||
*/
|
||||
this.btnCssClass = f.btn_css_class || 'btnExpClpFlt';
|
||||
this.btnCssClass = defaultsStr(f.btn_css_class, 'btnExpClpFlt');
|
||||
|
||||
/**
|
||||
* Css class for main container
|
||||
* @type {String}
|
||||
*/
|
||||
this.contCssClass = f.cont_css_class || 'expClpFlt';
|
||||
this.contCssClass = defaultsStr(f.cont_css_class, 'expClpFlt');
|
||||
|
||||
/**
|
||||
* Filters row index
|
||||
* @type {Number}
|
||||
*/
|
||||
this.filtersRowIndex = !isUndef(f.filters_row_index) ?
|
||||
f.filters_row_index : tf.getFiltersRowIndex();
|
||||
this.filtersRowIndex = defaultsNb(f.filters_row_index,
|
||||
tf.getFiltersRowIndex());
|
||||
|
||||
/**
|
||||
* Make filters visible at initialization, defaults to true
|
||||
* @type {Boolean}
|
||||
*/
|
||||
this.visibleAtStart = !isUndef(f.visible_at_start) ?
|
||||
Boolean(f.visible_at_start) : true;
|
||||
this.visibleAtStart = defaultsNb(f.visible_at_start, true);
|
||||
|
||||
/**
|
||||
* Default position in toolbar ('left'|'center'|'right')
|
||||
* @type {String}
|
||||
*/
|
||||
this.toolbarPosition = defaultsStr(f.toolbar_position, RIGHT);
|
||||
|
||||
/**
|
||||
* Callback fired before filters row is shown
|
||||
* @type {Function}
|
||||
*/
|
||||
this.onBeforeShow = isFn(f.on_before_show) ?
|
||||
f.on_before_show : EMPTY_FN;
|
||||
this.onBeforeShow = defaultsFn(f.on_before_show, EMPTY_FN);
|
||||
|
||||
/**
|
||||
* Callback fired after filters row is shown
|
||||
* @type {Function}
|
||||
*/
|
||||
this.onAfterShow = isFn(f.on_after_show) ? f.on_after_show : EMPTY_FN;
|
||||
this.onAfterShow = defaultsFn(f.on_after_show, EMPTY_FN);
|
||||
|
||||
/**
|
||||
* Callback fired before filters row is hidden
|
||||
* @type {Function}
|
||||
*/
|
||||
this.onBeforeHide = isFn(f.on_before_hide) ?
|
||||
f.on_before_hide : EMPTY_FN;
|
||||
this.onBeforeHide = defaultsFn(f.on_before_hide, EMPTY_FN);
|
||||
|
||||
/**
|
||||
* Callback fired after filters row is hidden
|
||||
* @type {Function}
|
||||
*/
|
||||
this.onAfterHide = isFn(f.on_after_hide) ? f.on_after_hide : EMPTY_FN;
|
||||
this.onAfterHide = defaultsFn(f.on_after_hide, EMPTY_FN);
|
||||
|
||||
//Import extension's stylesheet
|
||||
tf.import(f.name + 'Style', tf.stylePath + this.stylesheet, null,
|
||||
tf.import(f.name + 'Style', tf.getStylePath() + this.stylesheet, null,
|
||||
'link');
|
||||
|
||||
this.enable();
|
||||
|
@ -185,15 +193,17 @@ export default class FiltersVisibility extends Feature {
|
|||
return;
|
||||
}
|
||||
|
||||
this.emitter.emit('initializing-extension', this,
|
||||
!isNull(this.targetId));
|
||||
|
||||
this.buildUI();
|
||||
|
||||
/**
|
||||
* @inherited
|
||||
*/
|
||||
/** @inherited */
|
||||
this.initialized = true;
|
||||
|
||||
this.emitter.on(['show-filters'], (tf, visible) => this.show(visible));
|
||||
this.emitter.emit('filters-visibility-initialized', this.tf, this);
|
||||
this.emitter.emit('extension-initialized', this);
|
||||
}
|
||||
|
||||
/**
|
||||
|
@ -204,11 +214,10 @@ export default class FiltersVisibility extends Feature {
|
|||
let span = createElm('span');
|
||||
span.className = this.contCssClass;
|
||||
|
||||
//Container element (rdiv or custom element)
|
||||
if (!this.targetId) {
|
||||
tf.setToolbar();
|
||||
}
|
||||
let targetEl = !this.targetId ? tf.rDiv : elm(this.targetId);
|
||||
// Container element (rdiv or custom element)
|
||||
let targetEl = !this.targetId ?
|
||||
tf.feature('toolbar').container(this.toolbarPosition) :
|
||||
elm(this.targetId);
|
||||
|
||||
if (!this.targetId) {
|
||||
let firstChild = targetEl.firstChild;
|
||||
|
@ -224,7 +233,7 @@ export default class FiltersVisibility extends Feature {
|
|||
btn.title = this.btnText || this.defaultText;
|
||||
btn.innerHTML = this.collapseBtnHtml;
|
||||
span.appendChild(btn);
|
||||
} else { //Custom html
|
||||
} else { // Custom html
|
||||
span.innerHTML = this.btnHtml;
|
||||
btn = span.firstChild;
|
||||
}
|
||||
|
@ -244,7 +253,7 @@ export default class FiltersVisibility extends Feature {
|
|||
*/
|
||||
toggle() {
|
||||
let tf = this.tf;
|
||||
let tbl = tf.gridLayout ? tf.feature('gridLayout').headTbl : tf.tbl;
|
||||
let tbl = tf.gridLayout ? tf.feature('gridLayout').headTbl : tf.dom();
|
||||
let fltRow = tbl.rows[this.filtersRowIndex];
|
||||
let isDisplayed = fltRow.style.display === '';
|
||||
|
||||
|
@ -258,7 +267,7 @@ export default class FiltersVisibility extends Feature {
|
|||
*/
|
||||
show(visible = true) {
|
||||
let tf = this.tf;
|
||||
let tbl = tf.gridLayout ? tf.feature('gridLayout').headTbl : tf.tbl;
|
||||
let tbl = tf.gridLayout ? tf.feature('gridLayout').headTbl : tf.dom();
|
||||
let fltRow = tbl.rows[this.filtersRowIndex];
|
||||
|
||||
if (visible) {
|
||||
|
|
|
@ -1,12 +1,13 @@
|
|||
import {Feature} from '../../feature';
|
||||
import {isArray, isFn, isUndef, isObj, EMPTY_FN} from '../../types';
|
||||
import {createElm, elm, getText, tag} from '../../dom';
|
||||
import {addEvt} from '../../event';
|
||||
import {isUndef, isObj, EMPTY_FN} from '../../types';
|
||||
import {createElm, elm, tag} from '../../dom';
|
||||
import {addEvt, bound} from '../../event';
|
||||
import {parse as parseNb} from '../../number';
|
||||
import {
|
||||
NONE, CELL_TAG, HEADER_TAG, STRING, NUMBER, DATE, FORMATTED_NUMBER,
|
||||
IP_ADDRESS
|
||||
} from '../../const';
|
||||
import {defaultsStr, defaultsFn, defaultsArr} from '../../settings';
|
||||
|
||||
/**
|
||||
* SortableTable Adapter module
|
||||
|
@ -19,7 +20,7 @@ export default class AdapterSortableTable extends Feature {
|
|||
* @param {Object} opts Configuration object
|
||||
*/
|
||||
constructor(tf, opts) {
|
||||
super(tf, opts.name);
|
||||
super(tf, AdapterSortableTable);
|
||||
|
||||
/**
|
||||
* Module name
|
||||
|
@ -31,7 +32,7 @@ export default class AdapterSortableTable extends Feature {
|
|||
* Module description
|
||||
* @type {String}
|
||||
*/
|
||||
this.desc = opts.description || 'Sortable table';
|
||||
this.desc = defaultsStr(opts.description, 'Sortable table');
|
||||
|
||||
/**
|
||||
* Indicate whether table previously sorted
|
||||
|
@ -44,15 +45,14 @@ export default class AdapterSortableTable extends Feature {
|
|||
* List of sort type per column basis
|
||||
* @type {Array}
|
||||
*/
|
||||
this.sortTypes = isArray(opts.types) ? opts.types : tf.colTypes;
|
||||
this.sortTypes = defaultsArr(opts.types, tf.colTypes);
|
||||
|
||||
/**
|
||||
* Column to be sorted at initialization, ie:
|
||||
* sort_col_at_start: [1, true]
|
||||
* @type {Array}
|
||||
*/
|
||||
this.sortColAtStart = isArray(opts.sort_col_at_start) ?
|
||||
opts.sort_col_at_start : null;
|
||||
this.sortColAtStart = defaultsArr(opts.sort_col_at_start, null);
|
||||
|
||||
/**
|
||||
* Enable asynchronous sort, if triggers are external
|
||||
|
@ -64,7 +64,7 @@ export default class AdapterSortableTable extends Feature {
|
|||
* List of element IDs triggering sort on a per column basis
|
||||
* @type {Array}
|
||||
*/
|
||||
this.triggerIds = isArray(opts.trigger_ids) ? opts.trigger_ids : [];
|
||||
this.triggerIds = defaultsArr(opts.trigger_ids, []);
|
||||
|
||||
// edit .sort-arrow.descending / .sort-arrow.ascending in
|
||||
// tablefilter.css to reflect any path change
|
||||
|
@ -72,58 +72,57 @@ export default class AdapterSortableTable extends Feature {
|
|||
* Path to images
|
||||
* @type {String}
|
||||
*/
|
||||
this.imgPath = opts.images_path || tf.themesPath;
|
||||
this.imgPath = defaultsStr(opts.images_path, tf.themesPath);
|
||||
|
||||
/**
|
||||
* Blank image file name
|
||||
* @type {String}
|
||||
*/
|
||||
this.imgBlank = opts.image_blank || 'blank.png';
|
||||
this.imgBlank = defaultsStr(opts.image_blank, 'blank.png');
|
||||
|
||||
/**
|
||||
* Css class for sort indicator image
|
||||
* @type {String}
|
||||
*/
|
||||
this.imgClassName = opts.image_class_name || 'sort-arrow';
|
||||
this.imgClassName = defaultsStr(opts.image_class_name, 'sort-arrow');
|
||||
|
||||
/**
|
||||
* Css class for ascending sort indicator image
|
||||
* @type {String}
|
||||
*/
|
||||
this.imgAscClassName = opts.image_asc_class_name || 'ascending';
|
||||
this.imgAscClassName = defaultsStr(opts.image_asc_class_name,
|
||||
'ascending');
|
||||
|
||||
/**
|
||||
* Css class for descending sort indicator image
|
||||
* @type {String}
|
||||
*/
|
||||
this.imgDescClassName = opts.image_desc_class_name || 'descending';
|
||||
this.imgDescClassName = defaultsStr(opts.image_desc_class_name,
|
||||
'descending');
|
||||
|
||||
/**
|
||||
* Cell attribute key storing custom value used for sorting
|
||||
* @type {String}
|
||||
*/
|
||||
this.customKey = opts.custom_key || 'data-tf-sortKey';
|
||||
this.customKey = defaultsStr(opts.custom_key, 'data-tf-sortKey');
|
||||
|
||||
/**
|
||||
* Callback fired when sort extension is instanciated
|
||||
* @type {Function}
|
||||
*/
|
||||
this.onSortLoaded = isFn(opts.on_sort_loaded) ?
|
||||
opts.on_sort_loaded : EMPTY_FN;
|
||||
this.onSortLoaded = defaultsFn(opts.on_sort_loaded, EMPTY_FN);
|
||||
|
||||
/**
|
||||
* Callback fired before a table column is sorted
|
||||
* @type {Function}
|
||||
*/
|
||||
this.onBeforeSort = isFn(opts.on_before_sort) ?
|
||||
opts.on_before_sort : EMPTY_FN;
|
||||
this.onBeforeSort = defaultsFn(opts.on_before_sort, EMPTY_FN);
|
||||
|
||||
/**
|
||||
* Callback fired after a table column is sorted
|
||||
* @type {Function}
|
||||
*/
|
||||
this.onAfterSort = isFn(opts.on_after_sort) ?
|
||||
opts.on_after_sort : EMPTY_FN;
|
||||
this.onAfterSort = defaultsFn(opts.on_after_sort, EMPTY_FN);
|
||||
|
||||
/**
|
||||
* SortableTable instance
|
||||
|
@ -190,8 +189,7 @@ export default class AdapterSortableTable extends Feature {
|
|||
this.stt.sort(sortColAtStart[0], sortColAtStart[1]);
|
||||
}
|
||||
|
||||
this.emitter.on(['sort'],
|
||||
(tf, colIdx, desc) => this.sortByColumnIndex(colIdx, desc));
|
||||
this.emitter.on(['sort'], bound(this.sortByColumnIndexHandler, this));
|
||||
|
||||
/** @inherited */
|
||||
this.initialized = true;
|
||||
|
@ -208,6 +206,11 @@ export default class AdapterSortableTable extends Feature {
|
|||
this.stt.sort(colIdx, desc);
|
||||
}
|
||||
|
||||
/** @private */
|
||||
sortByColumnIndexHandler(tf, colIdx, desc) {
|
||||
this.sortByColumnIndex(colIdx, desc);
|
||||
}
|
||||
|
||||
/**
|
||||
* Set SortableTable overrides for TableFilter integration
|
||||
*/
|
||||
|
@ -358,17 +361,17 @@ export default class AdapterSortableTable extends Feature {
|
|||
/**
|
||||
* Overrides getInnerText in order to avoid Firefox unexpected sorting
|
||||
* behaviour with untrimmed text elements
|
||||
* @param {Object} oNode DOM element
|
||||
* @param {Object} cell DOM element
|
||||
* @return {String} DOM element inner text
|
||||
*/
|
||||
SortableTable.getInnerText = function (oNode) {
|
||||
if (!oNode) {
|
||||
SortableTable.getInnerText = function (cell) {
|
||||
if (!cell) {
|
||||
return;
|
||||
}
|
||||
if (oNode.getAttribute(adpt.customKey)) {
|
||||
return oNode.getAttribute(adpt.customKey);
|
||||
if (cell.getAttribute(adpt.customKey)) {
|
||||
return cell.getAttribute(adpt.customKey);
|
||||
} else {
|
||||
return getText(oNode);
|
||||
return tf.getCellValue(cell);
|
||||
}
|
||||
};
|
||||
}
|
||||
|
@ -378,8 +381,8 @@ export default class AdapterSortableTable extends Feature {
|
|||
*/
|
||||
addSortType(...args) {
|
||||
// Extract the arguments
|
||||
let [id, caster, sorter] = args;
|
||||
SortableTable.prototype.addSortType(id, caster, sorter);
|
||||
let [id, caster, sorter, getRowValue] = args;
|
||||
SortableTable.prototype.addSortType(id, caster, sorter, getRowValue);
|
||||
}
|
||||
|
||||
/**
|
||||
|
@ -391,7 +394,7 @@ export default class AdapterSortableTable extends Feature {
|
|||
sortTypes = this.sortTypes,
|
||||
_sortTypes = [];
|
||||
|
||||
for (let i = 0; i < tf.nbCells; i++) {
|
||||
tf.eachCol((i) => {
|
||||
let colType;
|
||||
if (sortTypes[i]) {
|
||||
colType = sortTypes[i];
|
||||
|
@ -421,7 +424,7 @@ export default class AdapterSortableTable extends Feature {
|
|||
colType = STRING;
|
||||
}
|
||||
_sortTypes.push(colType);
|
||||
}
|
||||
});
|
||||
|
||||
//Public TF method to add sort type
|
||||
|
||||
|
@ -430,7 +433,7 @@ export default class AdapterSortableTable extends Feature {
|
|||
this.addSortType(STRING);
|
||||
this.addSortType(IP_ADDRESS, ipAddress, sortIP);
|
||||
|
||||
this.stt = new SortableTable(tf.tbl, _sortTypes);
|
||||
this.stt = new SortableTable(tf.dom(), _sortTypes);
|
||||
|
||||
/*** external table headers adapter ***/
|
||||
if (this.asyncSort && this.triggerIds.length > 0) {
|
||||
|
@ -487,8 +490,7 @@ export default class AdapterSortableTable extends Feature {
|
|||
return;
|
||||
}
|
||||
let tf = this.tf;
|
||||
this.emitter.off(['sort'],
|
||||
(tf, colIdx, desc) => this.sortByColumnIndex(colIdx, desc));
|
||||
this.emitter.off(['sort'], bound(this.sortByColumnIndexHandler, this));
|
||||
this.sorted = false;
|
||||
this.stt.destroy();
|
||||
|
||||
|
@ -506,9 +508,12 @@ export default class AdapterSortableTable extends Feature {
|
|||
|
||||
}
|
||||
|
||||
AdapterSortableTable.meta = {altName: 'sort'};
|
||||
|
||||
//Converters
|
||||
function ipAddress(value) {
|
||||
let vals = value.split('.');
|
||||
// eslint-disable-next-line no-unused-vars
|
||||
for (let x in vals) {
|
||||
let val = vals[x];
|
||||
while (3 > val.length) {
|
||||
|
|
|
@ -1,5 +1,6 @@
|
|||
import {toCamelCase} from './string';
|
||||
|
||||
const NOTIMPLEMENTED = 'Not implemented.';
|
||||
const NOT_IMPLEMENTED = 'Not implemented.';
|
||||
|
||||
/**
|
||||
* Base class defining the interface of a TableFilter feature
|
||||
|
@ -8,9 +9,11 @@ export class Feature {
|
|||
/**
|
||||
* Creates an instance of Feature
|
||||
* @param {Object} tf TableFilter instance
|
||||
* @param {String} feature Feature name known by TableFilter
|
||||
* @param {Class} feature Feature class for TableFilter registration
|
||||
*/
|
||||
constructor(tf, feature) {
|
||||
constructor(tf, cls) {
|
||||
cls.meta = cls.meta || {};
|
||||
|
||||
/**
|
||||
* TableFilter instance
|
||||
* @type {TableFilter}
|
||||
|
@ -18,16 +21,18 @@ export class Feature {
|
|||
this.tf = tf;
|
||||
|
||||
/**
|
||||
* Feature name
|
||||
* Feature name is the camelised class name as per TableFilter's
|
||||
* convention
|
||||
* @type {String}
|
||||
*/
|
||||
this.feature = feature;
|
||||
this.feature = cls.meta.altName || cls.meta.name
|
||||
|| toCamelCase(cls.name);
|
||||
|
||||
/**
|
||||
* TableFilter feature setting
|
||||
* @type {Boolean}
|
||||
*/
|
||||
this.enabled = tf[feature];
|
||||
this.enabled = tf[this.feature];
|
||||
|
||||
/**
|
||||
* TableFilter configuration
|
||||
|
@ -55,7 +60,7 @@ export class Feature {
|
|||
* Initialize the feature
|
||||
*/
|
||||
init() {
|
||||
throw new Error(NOTIMPLEMENTED);
|
||||
throw new Error(NOT_IMPLEMENTED);
|
||||
}
|
||||
|
||||
/**
|
||||
|
@ -70,7 +75,7 @@ export class Feature {
|
|||
* Destroy the feature
|
||||
*/
|
||||
destroy() {
|
||||
throw new Error(NOTIMPLEMENTED);
|
||||
throw new Error(NOT_IMPLEMENTED);
|
||||
}
|
||||
|
||||
/**
|
||||
|
@ -92,6 +97,6 @@ export class Feature {
|
|||
* @returns {Boolean}
|
||||
*/
|
||||
isEnabled() {
|
||||
return this.enabled;
|
||||
return this.enabled === true;
|
||||
}
|
||||
}
|
||||
|
|
|
@ -1,5 +1,7 @@
|
|||
import {Feature} from '../feature';
|
||||
import {addClass, removeClass} from '../dom';
|
||||
import {defaultsStr} from '../settings';
|
||||
import {bound} from '../event';
|
||||
|
||||
/**
|
||||
* Rows with alternating background color for improved readability
|
||||
|
@ -12,20 +14,21 @@ export class AlternateRows extends Feature {
|
|||
* @param {Object} tf TableFilter instance
|
||||
*/
|
||||
constructor(tf) {
|
||||
super(tf, 'alternateRows');
|
||||
super(tf, AlternateRows);
|
||||
|
||||
let config = this.config;
|
||||
|
||||
/**
|
||||
* Css class for even rows (default: 'even')
|
||||
* @type {String}
|
||||
*/
|
||||
this.evenCss = config.even_row_css_class || 'even';
|
||||
this.evenCss = defaultsStr(config.even_row_css_class, 'even');
|
||||
|
||||
/**
|
||||
* Css class for odd rows (default: 'odd')
|
||||
* @type {String}
|
||||
*/
|
||||
this.oddCss = config.odd_row_css_class || 'odd';
|
||||
this.oddCss = defaultsStr(config.odd_row_css_class, 'odd');
|
||||
}
|
||||
|
||||
/**
|
||||
|
@ -40,10 +43,9 @@ export class AlternateRows extends Feature {
|
|||
|
||||
// Subscribe to events
|
||||
this.emitter.on(['row-processed', 'row-paged'],
|
||||
(tf, rowIndex, arrIndex, isValid) =>
|
||||
this.processRow(rowIndex, arrIndex, isValid));
|
||||
this.emitter.on(['column-sorted'], () => this.processAll());
|
||||
this.emitter.on(['rows-changed'], () => this.processAll());
|
||||
bound(this.processRowHandler, this));
|
||||
this.emitter.on(['column-sorted', 'rows-changed'],
|
||||
bound(this.processAll, this));
|
||||
|
||||
/** @inherited */
|
||||
this.initialized = true;
|
||||
|
@ -94,7 +96,7 @@ export class AlternateRows extends Feature {
|
|||
if (!this.isEnabled() || isNaN(rowIdx)) {
|
||||
return;
|
||||
}
|
||||
let rows = this.tf.tbl.rows;
|
||||
let rows = this.tf.dom().rows;
|
||||
let i = isNaN(idx) ? rowIdx : idx;
|
||||
this.removeRowBg(rowIdx);
|
||||
|
||||
|
@ -110,11 +112,16 @@ export class AlternateRows extends Feature {
|
|||
if (isNaN(idx)) {
|
||||
return;
|
||||
}
|
||||
let rows = this.tf.tbl.rows;
|
||||
let rows = this.tf.dom().rows;
|
||||
removeClass(rows[idx], this.oddCss);
|
||||
removeClass(rows[idx], this.evenCss);
|
||||
}
|
||||
|
||||
/** @private */
|
||||
processRowHandler(tf, rowIndex, arrIndex, isValid) {
|
||||
this.processRow(rowIndex, arrIndex, isValid);
|
||||
}
|
||||
|
||||
/**
|
||||
* Removes all alternating backgrounds
|
||||
*/
|
||||
|
@ -122,17 +129,15 @@ export class AlternateRows extends Feature {
|
|||
if (!this.initialized) {
|
||||
return;
|
||||
}
|
||||
let nbRows = this.tf.getRowsNb(true);
|
||||
for (let i = 0; i < nbRows; i++) {
|
||||
this.removeRowBg(i);
|
||||
}
|
||||
|
||||
let eachRow = this.tf.eachRow(0);
|
||||
eachRow((row, i) => this.removeRowBg(i));
|
||||
|
||||
// Unsubscribe to events
|
||||
this.emitter.off(['row-processed', 'row-paged'],
|
||||
(tf, rowIndex, arrIndex, isValid) =>
|
||||
this.processRow(rowIndex, arrIndex, isValid));
|
||||
this.emitter.off(['column-sorted'], () => this.processAll());
|
||||
this.emitter.off(['rows-changed'], () => this.processAll());
|
||||
bound(this.processRowHandler, this));
|
||||
this.emitter.off(['column-sorted', 'rows-changed'],
|
||||
bound(this.processAll, this));
|
||||
|
||||
this.initialized = false;
|
||||
}
|
||||
|
|
160
src/modules/baseDropdown.js
Normal file
160
src/modules/baseDropdown.js
Normal file
|
@ -0,0 +1,160 @@
|
|||
import {Feature} from '../feature';
|
||||
import {
|
||||
ignoreCase, numSortAsc, numSortDesc,
|
||||
dateSortAsc, dateSortDesc, sortNumberStr, sortDateStr
|
||||
} from '../sort';
|
||||
import {isArray, isObj, isEmpty} from '../types';
|
||||
import {NUMBER, FORMATTED_NUMBER, DATE} from '../const';
|
||||
|
||||
/**
|
||||
* Base class for Dropdown and CheckList UI components
|
||||
* @export
|
||||
* @class BaseDropdown
|
||||
* @extends {Feature}
|
||||
*/
|
||||
export class BaseDropdown extends Feature {
|
||||
|
||||
/**
|
||||
* Creates an instance of BaseDropdown
|
||||
* @param {TableFilter} tf
|
||||
*/
|
||||
constructor(tf, cls) {
|
||||
super(tf, cls);
|
||||
|
||||
let f = this.config;
|
||||
|
||||
/**
|
||||
* Filter options custom sorter on a column basis
|
||||
* @type {Object}
|
||||
*/
|
||||
this.customSorter = isObj(f.filter_options_sorter) &&
|
||||
isArray(f.filter_options_sorter.col) &&
|
||||
isArray(f.filter_options_sorter.comparer) ?
|
||||
f.filter_options_sorter :
|
||||
null;
|
||||
|
||||
// TODO: move here all properties shared by Dropdown and CheckList
|
||||
|
||||
/**
|
||||
* Has custom options
|
||||
* @type {Boolean}
|
||||
* @private
|
||||
*/
|
||||
this.isCustom = false;
|
||||
|
||||
/**
|
||||
* List of options values
|
||||
* @type {Array}
|
||||
* @private
|
||||
*/
|
||||
this.opts = [];
|
||||
|
||||
/**
|
||||
* List of options texts for custom values
|
||||
* @type {Array}
|
||||
* @private
|
||||
*/
|
||||
this.optsTxt = [];
|
||||
|
||||
/**
|
||||
* List of options to be excluded from the checklist filter
|
||||
* @type {Array}
|
||||
* @private
|
||||
*/
|
||||
this.excludedOpts = [];
|
||||
}
|
||||
|
||||
/**
|
||||
* Sort passed options based on the type of the specified column
|
||||
* @param {Number} colIndex Column index
|
||||
* @param {Array} [options=[]] Collection of values
|
||||
* @return {Array} Sorted values
|
||||
* @private
|
||||
*/
|
||||
sortOptions(colIndex, options = []) {
|
||||
let {tf} = this;
|
||||
|
||||
if (tf.isCustomOptions(colIndex) || !tf.sortSlc ||
|
||||
(isArray(tf.sortSlc) && tf.sortSlc.indexOf(colIndex) === -1)) {
|
||||
return options;
|
||||
}
|
||||
|
||||
let { caseSensitive, sortFilterOptionsDesc } = tf;
|
||||
let isSortDesc = sortFilterOptionsDesc.indexOf(colIndex) !== -1;
|
||||
let compareFn;
|
||||
|
||||
if (this.customSorter &&
|
||||
this.customSorter.col.indexOf(colIndex) !== -1) {
|
||||
var idx = this.customSorter.col.indexOf(colIndex);
|
||||
compareFn = this.customSorter.comparer[idx];
|
||||
}
|
||||
else if (tf.hasType(colIndex, [NUMBER, FORMATTED_NUMBER])) {
|
||||
let decimal = tf.getDecimal(colIndex);
|
||||
let comparer = isSortDesc ? numSortDesc : numSortAsc;
|
||||
compareFn = sortNumberStr(comparer, decimal);
|
||||
}
|
||||
else if (tf.hasType(colIndex, [DATE])) {
|
||||
let locale = tf.feature('dateType').getLocale(colIndex);
|
||||
let comparer = isSortDesc ? dateSortDesc : dateSortAsc;
|
||||
compareFn = sortDateStr(comparer, locale);
|
||||
} else { // string
|
||||
compareFn = caseSensitive ? undefined : ignoreCase;
|
||||
if (isSortDesc) {
|
||||
return options.sort(compareFn).reverse();
|
||||
}
|
||||
}
|
||||
|
||||
return options.sort(compareFn);
|
||||
}
|
||||
|
||||
/**
|
||||
* Regenerate filters of specified columns and maintain selection if any
|
||||
* @param {Array} colIndexes Collection of column indexes
|
||||
* @private
|
||||
*/
|
||||
refreshFilters(colIndexes) {
|
||||
colIndexes.forEach((colIdx) => {
|
||||
let values = this.getValues(colIdx);
|
||||
this.build(colIdx, this.tf.linkedFilters);
|
||||
this.selectOptions(colIdx, values);
|
||||
});
|
||||
}
|
||||
|
||||
/**
|
||||
* Check passed row contains a valid linked value
|
||||
* @param {Number} rowIdx Row index
|
||||
* @param {Number} activeFilterIdx Current active filter index
|
||||
* @returns {Boolean}
|
||||
*/
|
||||
isValidLinkedValue(rowIdx, activeFilterIdx) {
|
||||
let tf = this.tf;
|
||||
|
||||
if (tf.disableExcludedOptions) {
|
||||
return true;
|
||||
}
|
||||
|
||||
if (tf.paging) {
|
||||
if (!isEmpty(activeFilterIdx) && tf.isRowValid(rowIdx)) {
|
||||
return true;
|
||||
}
|
||||
} else {
|
||||
if (tf.isRowDisplayed(rowIdx)) {
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
/**
|
||||
* Refresh linked filters to offer only selected options
|
||||
*/
|
||||
linkFilters() {
|
||||
let tf = this.tf;
|
||||
if (!tf.linkedFilters || !tf.activeFilterId) {
|
||||
return;
|
||||
}
|
||||
|
||||
this.refreshAll();
|
||||
}
|
||||
}
|
|
@ -1,29 +1,28 @@
|
|||
import {Feature} from '../feature';
|
||||
import {BaseDropdown} from './baseDropdown';
|
||||
import {
|
||||
addClass, createCheckItem, createText, createElm, elm, getText,
|
||||
removeClass, tag
|
||||
addClass, createCheckItem, createText, createElm, elm, removeClass, tag
|
||||
} from '../dom';
|
||||
import {has} from '../array';
|
||||
import {matchCase, trim, rgxEsc} from '../string';
|
||||
import {ignoreCase, numSortAsc, numSortDesc} from '../sort';
|
||||
import {addEvt, removeEvt, targetEvt} from '../event';
|
||||
import {isEmpty} from '../types';
|
||||
import {CHECKLIST, NONE} from '../const';
|
||||
|
||||
const SORT_ERROR = 'Filter options for column {0} cannot be sorted in ' +
|
||||
'{1} manner.';
|
||||
import {defaultsStr, defaultsBool} from '../settings';
|
||||
|
||||
/**
|
||||
* Checklist filter UI component
|
||||
* @export
|
||||
* @class CheckList
|
||||
* @extends {BaseDropdown}
|
||||
*/
|
||||
export class CheckList extends Feature {
|
||||
export class CheckList extends BaseDropdown {
|
||||
|
||||
/**
|
||||
* Creates an instance of CheckList
|
||||
* @param {TableFilter} tf TableFilter instance
|
||||
*/
|
||||
constructor(tf) {
|
||||
super(tf, 'checkList');
|
||||
super(tf, CheckList);
|
||||
|
||||
let f = this.config;
|
||||
|
||||
|
@ -37,48 +36,57 @@ export class CheckList extends Feature {
|
|||
* Css class for the container of the checklist filter (div)
|
||||
* @type {String}
|
||||
*/
|
||||
this.containerCssClass = f.div_checklist_css_class || 'div_checklist';
|
||||
this.containerCssClass = defaultsStr(f.div_checklist_css_class,
|
||||
'div_checklist');
|
||||
|
||||
/**
|
||||
* Css class for the checklist filter element (ul)
|
||||
* @type {String}
|
||||
*/
|
||||
this.filterCssClass = f.checklist_css_class || 'flt_checklist';
|
||||
this.filterCssClass = defaultsStr(f.checklist_css_class,
|
||||
'flt_checklist');
|
||||
|
||||
/**
|
||||
* Css class for the item of a checklist (li)
|
||||
* @type {String}
|
||||
*/
|
||||
this.itemCssClass = f.checklist_item_css_class || 'flt_checklist_item';
|
||||
this.itemCssClass = defaultsStr(f.checklist_item_css_class,
|
||||
'flt_checklist_item');
|
||||
|
||||
/**
|
||||
* Css class for a selected item of a checklist (li)
|
||||
* @type {String}
|
||||
*/
|
||||
this.selectedItemCssClass =
|
||||
f.checklist_selected_item_css_class || 'flt_checklist_slc_item';
|
||||
this.selectedItemCssClass = defaultsStr(
|
||||
f.checklist_selected_item_css_class,
|
||||
'flt_checklist_slc_item'
|
||||
);
|
||||
|
||||
/**
|
||||
* Text placed in the filter's container when load filter on demand
|
||||
* feature is enabled
|
||||
* @type {String}
|
||||
*/
|
||||
this.activateText =
|
||||
f.activate_checklist_text || 'Click to load filter data';
|
||||
this.activateText = defaultsStr(
|
||||
f.activate_checklist_text,
|
||||
'Click to load filter data'
|
||||
);
|
||||
|
||||
/**
|
||||
* Css class for a disabled item of a checklist (li)
|
||||
* @type {String}
|
||||
*/
|
||||
this.disabledItemCssClass = f.checklist_item_disabled_css_class ||
|
||||
'flt_checklist_item_disabled';
|
||||
this.disabledItemCssClass = defaultsStr(
|
||||
f.checklist_item_disabled_css_class,
|
||||
'flt_checklist_item_disabled'
|
||||
);
|
||||
|
||||
/**
|
||||
* Enable the reset filter option as first item
|
||||
* @type {Boolean}
|
||||
*/
|
||||
this.enableResetOption = f.enable_checklist_reset_filter === false ?
|
||||
false : true;
|
||||
this.enableResetOption = defaultsBool(f.enable_checklist_reset_filter,
|
||||
true);
|
||||
|
||||
/**
|
||||
* Prefix for container element ID
|
||||
|
@ -86,34 +94,6 @@ export class CheckList extends Feature {
|
|||
* @private
|
||||
*/
|
||||
this.prfx = 'chkdiv_';
|
||||
|
||||
/**
|
||||
* Has custom options
|
||||
* @type {Boolean}
|
||||
* @private
|
||||
*/
|
||||
this.isCustom = false;
|
||||
|
||||
/**
|
||||
* List of options values
|
||||
* @type {Array}
|
||||
* @private
|
||||
*/
|
||||
this.opts = [];
|
||||
|
||||
/**
|
||||
* List of options texts for custom values
|
||||
* @type {Array}
|
||||
* @private
|
||||
*/
|
||||
this.optsTxt = [];
|
||||
|
||||
/**
|
||||
* List of options to be excluded from the checklist filter
|
||||
* @type {Array}
|
||||
* @private
|
||||
*/
|
||||
this.excludedOpts = [];
|
||||
}
|
||||
|
||||
/**
|
||||
|
@ -126,7 +106,7 @@ export class CheckList extends Feature {
|
|||
let tf = this.tf;
|
||||
|
||||
this.emitter.emit('filter-focus', tf, elm);
|
||||
this.setCheckListValues(elm);
|
||||
this.setItemOption(elm);
|
||||
tf.filter();
|
||||
}
|
||||
|
||||
|
@ -149,13 +129,8 @@ export class CheckList extends Feature {
|
|||
* Refresh all checklist filters
|
||||
*/
|
||||
refreshAll() {
|
||||
let tf = this.tf;
|
||||
let fltsIdxs = tf.getFiltersByType(CHECKLIST, true);
|
||||
fltsIdxs.forEach((colIdx) => {
|
||||
let values = this.getValues(colIdx);
|
||||
this.build(colIdx, tf.linkedFilters);
|
||||
this.selectOptions(colIdx, values);
|
||||
});
|
||||
let colIdxs = this.tf.getFiltersByType(CHECKLIST, true);
|
||||
this.refreshFilters(colIdxs);
|
||||
}
|
||||
|
||||
/**
|
||||
|
@ -167,7 +142,7 @@ export class CheckList extends Feature {
|
|||
init(colIndex, isExternal, container) {
|
||||
let tf = this.tf;
|
||||
let externalFltTgtId = isExternal ?
|
||||
tf.externalFltTgtIds[colIndex] : null;
|
||||
tf.externalFltIds[colIndex] : null;
|
||||
|
||||
let divCont = createElm('div',
|
||||
['id', `${this.prfx}${colIndex}_${tf.id}`],
|
||||
|
@ -203,6 +178,8 @@ export class CheckList extends Feature {
|
|||
|
||||
this.emitter.on(['rows-changed'], () => this.refreshAll());
|
||||
|
||||
this.emitter.on(['after-filtering'], () => this.linkFilters());
|
||||
|
||||
/** @inherited */
|
||||
this.initialized = true;
|
||||
}
|
||||
|
@ -214,11 +191,13 @@ export class CheckList extends Feature {
|
|||
*/
|
||||
build(colIndex, isLinked = false) {
|
||||
let tf = this.tf;
|
||||
colIndex = parseInt(colIndex, 10);
|
||||
colIndex = Number(colIndex);
|
||||
|
||||
this.emitter.emit('before-populating-filter', tf, colIndex);
|
||||
|
||||
/** @inherited */
|
||||
this.opts = [];
|
||||
/** @inherited */
|
||||
this.optsTxt = [];
|
||||
|
||||
let flt = this.containers[colIndex];
|
||||
|
@ -227,71 +206,10 @@ export class CheckList extends Feature {
|
|||
['colIndex', colIndex]);
|
||||
ul.className = this.filterCssClass;
|
||||
|
||||
let rows = tf.tbl.rows;
|
||||
let nbRows = tf.getRowsNb(true);
|
||||
let caseSensitive = tf.caseSensitive;
|
||||
/** @inherited */
|
||||
this.isCustom = tf.isCustomOptions(colIndex);
|
||||
|
||||
let activeIdx;
|
||||
let activeFilterId = tf.getActiveFilterId();
|
||||
if (isLinked && activeFilterId) {
|
||||
activeIdx = tf.getColumnIndexFromFilterId(activeFilterId);
|
||||
}
|
||||
|
||||
let filteredDataCol = [];
|
||||
if (isLinked && tf.disableExcludedOptions) {
|
||||
this.excludedOpts = [];
|
||||
}
|
||||
|
||||
flt.innerHTML = '';
|
||||
|
||||
for (let k = tf.refRow; k < nbRows; k++) {
|
||||
// always visible rows don't need to appear on selects as always
|
||||
// valid
|
||||
if (tf.hasVisibleRows && tf.visibleRows.indexOf(k) !== -1) {
|
||||
continue;
|
||||
}
|
||||
|
||||
let cells = rows[k].cells;
|
||||
let ncells = cells.length;
|
||||
|
||||
// checks if row has exact cell #
|
||||
if (ncells !== tf.nbCells || this.isCustom) {
|
||||
continue;
|
||||
}
|
||||
|
||||
// this loop retrieves cell data
|
||||
for (let j = 0; j < ncells; j++) {
|
||||
if (colIndex !== j) {
|
||||
continue;
|
||||
}
|
||||
if (isLinked && !tf.disableExcludedOptions &&
|
||||
(!tf.paging && !tf.isRowDisplayed(k)) ||
|
||||
(tf.paging && activeIdx && !tf.isRowValid(k))) {
|
||||
continue;
|
||||
}
|
||||
|
||||
let cellValue = tf.getCellValue(cells[j]);
|
||||
//Vary Peter's patch
|
||||
let cellString = matchCase(cellValue, caseSensitive);
|
||||
// checks if celldata is already in array
|
||||
if (!has(this.opts, cellString, caseSensitive)) {
|
||||
this.opts.push(cellValue);
|
||||
}
|
||||
let filteredCol = filteredDataCol[j];
|
||||
if (isLinked && tf.disableExcludedOptions) {
|
||||
if (!filteredCol) {
|
||||
filteredCol = tf.getFilteredDataCol(j);
|
||||
}
|
||||
if (!has(filteredCol, cellString, caseSensitive) &&
|
||||
!has(this.excludedOpts, cellString,
|
||||
caseSensitive)) {
|
||||
this.excludedOpts.push(cellValue);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
//Retrieves custom values
|
||||
if (this.isCustom) {
|
||||
let customValues = tf.getCustomOptions(colIndex);
|
||||
|
@ -299,48 +217,64 @@ export class CheckList extends Feature {
|
|||
this.optsTxt = customValues[1];
|
||||
}
|
||||
|
||||
if (tf.sortSlc && !this.isCustom) {
|
||||
if (!caseSensitive) {
|
||||
this.opts.sort(ignoreCase);
|
||||
if (this.excludedOpts) {
|
||||
this.excludedOpts.sort(ignoreCase);
|
||||
let activeIdx;
|
||||
let activeFilterId = tf.getActiveFilterId();
|
||||
|
||||
if (isLinked && activeFilterId) {
|
||||
activeIdx = tf.getColumnIndexFromFilterId(activeFilterId);
|
||||
}
|
||||
|
||||
let filteredDataCol = [];
|
||||
if (isLinked && tf.disableExcludedOptions) {
|
||||
/** @inherited */
|
||||
this.excludedOpts = [];
|
||||
}
|
||||
|
||||
flt.innerHTML = '';
|
||||
|
||||
let eachRow = tf.eachRow();
|
||||
eachRow(
|
||||
(row) => {
|
||||
let cellValue = tf.getCellValue(row.cells[colIndex]);
|
||||
//Vary Peter's patch
|
||||
let cellString = matchCase(cellValue, caseSensitive);
|
||||
// checks if celldata is already in array
|
||||
if (!has(this.opts, cellString, caseSensitive)) {
|
||||
this.opts.push(cellValue);
|
||||
}
|
||||
} else {
|
||||
this.opts.sort();
|
||||
if (this.excludedOpts) {
|
||||
this.excludedOpts.sort();
|
||||
let filteredCol = filteredDataCol[colIndex];
|
||||
if (isLinked && tf.disableExcludedOptions) {
|
||||
if (!filteredCol) {
|
||||
filteredCol = tf.getVisibleColumnValues(colIndex);
|
||||
}
|
||||
if (!has(filteredCol, cellString, caseSensitive) &&
|
||||
!has(this.excludedOpts, cellString, caseSensitive)) {
|
||||
this.excludedOpts.push(cellValue);
|
||||
}
|
||||
}
|
||||
},
|
||||
// continue conditions function
|
||||
(row, k) => {
|
||||
// excluded rows don't need to appear on selects as always valid
|
||||
if (tf.excludeRows.indexOf(k) !== -1) {
|
||||
return true;
|
||||
}
|
||||
|
||||
// checks if row has expected number of cells
|
||||
if (row.cells.length !== tf.nbCells || this.isCustom) {
|
||||
return true;
|
||||
}
|
||||
|
||||
if (isLinked && !this.isValidLinkedValue(k, activeIdx)) {
|
||||
return true;
|
||||
}
|
||||
}
|
||||
}
|
||||
//asc sort
|
||||
if (tf.sortNumAsc.indexOf(colIndex) !== -1) {
|
||||
try {
|
||||
this.opts.sort(numSortAsc);
|
||||
if (this.excludedOpts) {
|
||||
this.excludedOpts.sort(numSortAsc);
|
||||
}
|
||||
if (this.isCustom) {
|
||||
this.optsTxt.sort(numSortAsc);
|
||||
}
|
||||
} catch (e) {
|
||||
throw new Error(SORT_ERROR.replace('{0}', colIndex)
|
||||
.replace('{1}', 'ascending'));
|
||||
}//in case there are alphanumeric values
|
||||
}
|
||||
//desc sort
|
||||
if (tf.sortNumDesc.indexOf(colIndex) !== -1) {
|
||||
try {
|
||||
this.opts.sort(numSortDesc);
|
||||
if (this.excludedOpts) {
|
||||
this.excludedOpts.sort(numSortDesc);
|
||||
}
|
||||
if (this.isCustom) {
|
||||
this.optsTxt.sort(numSortDesc);
|
||||
}
|
||||
} catch (e) {
|
||||
throw new Error(SORT_ERROR.replace('{0}', colIndex)
|
||||
.replace('{1}', 'descending'));
|
||||
}//in case there are alphanumeric values
|
||||
);
|
||||
|
||||
//sort options
|
||||
this.opts = this.sortOptions(colIndex, this.opts);
|
||||
if (this.excludedOpts) {
|
||||
this.excludedOpts = this.sortOptions(colIndex, this.excludedOpts);
|
||||
}
|
||||
|
||||
this.addChecks(colIndex, ul);
|
||||
|
@ -368,7 +302,9 @@ export class CheckList extends Feature {
|
|||
let val = this.opts[y]; //item value
|
||||
let lbl = this.isCustom ? this.optsTxt[y] : val; //item text
|
||||
let fltId = tf.fltIds[colIndex];
|
||||
let li = createCheckItem(`${fltId}_${(y + chkCt)}`, val, lbl);
|
||||
let lblIdx = y + chkCt;
|
||||
let li = createCheckItem(`${fltId}_${lblIdx}`, val, lbl,
|
||||
['data-idx', lblIdx]);
|
||||
li.className = this.itemCssClass;
|
||||
|
||||
if (tf.linkedFilters && tf.disableExcludedOptions &&
|
||||
|
@ -400,7 +336,7 @@ export class CheckList extends Feature {
|
|||
let chkCt = 1;
|
||||
let fltId = tf.fltIds[colIndex];
|
||||
let li0 = createCheckItem(`${fltId}_0`, '',
|
||||
tf.getClearFilterText(colIndex));
|
||||
tf.getClearFilterText(colIndex), ['data-idx', 0]);
|
||||
li0.className = this.itemCssClass;
|
||||
ul.appendChild(li0);
|
||||
|
||||
|
@ -412,7 +348,7 @@ export class CheckList extends Feature {
|
|||
|
||||
if (tf.enableEmptyOption) {
|
||||
let li1 = createCheckItem(`${fltId}_1`, tf.emOperator,
|
||||
tf.emptyText);
|
||||
tf.emptyText, ['data-idx', 1]);
|
||||
li1.className = this.itemCssClass;
|
||||
ul.appendChild(li1);
|
||||
addEvt(li1.check, 'click', evt => this.optionClick(evt));
|
||||
|
@ -421,7 +357,7 @@ export class CheckList extends Feature {
|
|||
|
||||
if (tf.enableNonEmptyOption) {
|
||||
let li2 = createCheckItem(`${fltId}_2`, tf.nmOperator,
|
||||
tf.nonEmptyText);
|
||||
tf.nonEmptyText, ['data-idx', 2]);
|
||||
li2.className = this.itemCssClass;
|
||||
ul.appendChild(li2);
|
||||
addEvt(li2.check, 'click', evt => this.optionClick(evt));
|
||||
|
@ -431,81 +367,73 @@ export class CheckList extends Feature {
|
|||
}
|
||||
|
||||
/**
|
||||
* Store checked options in DOM element attribute
|
||||
* Set/unset value of passed item option in filter's DOM element attribute
|
||||
* @param {Object} o checklist option DOM element
|
||||
* @private
|
||||
*/
|
||||
setCheckListValues(o) {
|
||||
setItemOption(o) {
|
||||
if (!o) {
|
||||
return;
|
||||
}
|
||||
|
||||
let tf = this.tf;
|
||||
let chkValue = o.value; //checked item value
|
||||
// TODO: provide helper to extract column index, ugly!
|
||||
let chkIndex = parseInt(o.id.split('_')[2], 10);
|
||||
let chkIndex = o.dataset.idx;
|
||||
let colIdx = tf.getColumnIndexFromFilterId(o.id);
|
||||
let itemTag = 'LI';
|
||||
|
||||
let n = tf.getFilterElement(parseInt(colIdx, 10));
|
||||
let li = n.childNodes[chkIndex];
|
||||
let colIndex = n.getAttribute('colIndex');
|
||||
let fltValue = n.getAttribute('value'); //filter value (ul tag)
|
||||
let fltIndexes = n.getAttribute('indexes'); //selected items (ul tag)
|
||||
let items = n.childNodes;
|
||||
let li = items[chkIndex];
|
||||
//selected values (ul tag)
|
||||
let slcValues = n.getAttribute('value') || '';
|
||||
//selected items indexes (ul tag)
|
||||
let slcIndexes = n.getAttribute('indexes') || '';
|
||||
|
||||
if (o.checked) {
|
||||
//show all item
|
||||
if (chkValue === '') {
|
||||
if ((fltIndexes && fltIndexes !== '')) {
|
||||
//items indexes
|
||||
let indSplit = fltIndexes.split(tf.separator);
|
||||
//checked items loop
|
||||
for (let u = 0; u < indSplit.length; u++) {
|
||||
//checked item
|
||||
let cChk = elm(tf.fltIds[colIndex] + '_' +
|
||||
indSplit[u]);
|
||||
if (cChk) {
|
||||
cChk.checked = false;
|
||||
removeClass(n.childNodes[indSplit[u]],
|
||||
this.selectedItemCssClass);
|
||||
}
|
||||
//items indexes
|
||||
let indexes = slcIndexes.split(tf.separator);
|
||||
indexes.forEach(idx => {
|
||||
idx = Number(idx);
|
||||
let li = items[idx];
|
||||
let chx = tag(li, 'input')[0];
|
||||
if (chx && idx > 0) {
|
||||
chx.checked = false;
|
||||
removeClass(li, this.selectedItemCssClass);
|
||||
}
|
||||
}
|
||||
});
|
||||
|
||||
n.setAttribute('value', '');
|
||||
n.setAttribute('indexes', '');
|
||||
|
||||
} else {
|
||||
fltValue = (fltValue) ? fltValue : '';
|
||||
chkValue = trim(fltValue + ' ' + chkValue + ' ' +
|
||||
tf.orOperator);
|
||||
chkIndex = fltIndexes + chkIndex + tf.separator;
|
||||
n.setAttribute('value', chkValue);
|
||||
n.setAttribute('indexes', chkIndex);
|
||||
//1st option unchecked
|
||||
if (elm(tf.fltIds[colIndex] + '_0')) {
|
||||
elm(tf.fltIds[colIndex] + '_0').checked = false;
|
||||
let indexes = slcIndexes + chkIndex + tf.separator;
|
||||
let values =
|
||||
trim(slcValues + ' ' + chkValue + ' ' + tf.orOperator);
|
||||
|
||||
n.setAttribute('value', values);
|
||||
n.setAttribute('indexes', indexes);
|
||||
|
||||
//uncheck first option
|
||||
let chx0 = tag(items[0], 'input')[0];
|
||||
if (chx0) {
|
||||
chx0.checked = false;
|
||||
}
|
||||
}
|
||||
|
||||
if (li.nodeName === itemTag) {
|
||||
removeClass(n.childNodes[0], this.selectedItemCssClass);
|
||||
addClass(li, this.selectedItemCssClass);
|
||||
}
|
||||
removeClass(items[0], this.selectedItemCssClass);
|
||||
addClass(li, this.selectedItemCssClass);
|
||||
} else { //removes values and indexes
|
||||
if (chkValue !== '') {
|
||||
let replaceValue = new RegExp(
|
||||
rgxEsc(chkValue + ' ' + tf.orOperator));
|
||||
fltValue = fltValue.replace(replaceValue, '');
|
||||
n.setAttribute('value', trim(fltValue));
|
||||
let replaceValue =
|
||||
new RegExp(rgxEsc(chkValue + ' ' + tf.orOperator));
|
||||
let values = slcValues.replace(replaceValue, '');
|
||||
let replaceIndex = new RegExp(rgxEsc(chkIndex + tf.separator));
|
||||
let indexes = slcIndexes.replace(replaceIndex, '');
|
||||
|
||||
let replaceIndex = new RegExp(
|
||||
rgxEsc(chkIndex + tf.separator));
|
||||
fltIndexes = fltIndexes.replace(replaceIndex, '');
|
||||
n.setAttribute('indexes', fltIndexes);
|
||||
}
|
||||
if (li.nodeName === itemTag) {
|
||||
removeClass(li, this.selectedItemCssClass);
|
||||
}
|
||||
n.setAttribute('value', trim(values));
|
||||
n.setAttribute('indexes', indexes);
|
||||
|
||||
removeClass(li, this.selectedItemCssClass);
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -517,39 +445,36 @@ export class CheckList extends Feature {
|
|||
selectOptions(colIndex, values = []) {
|
||||
let tf = this.tf;
|
||||
let flt = tf.getFilterElement(colIndex);
|
||||
if (tf.getFilterType(colIndex) !== CHECKLIST || !flt ||
|
||||
values.length === 0) {
|
||||
if (!flt || values.length === 0) {
|
||||
return;
|
||||
}
|
||||
|
||||
let lisNb = tag(flt, 'li').length;
|
||||
let lis = tag(flt, 'li');
|
||||
|
||||
flt.setAttribute('value', '');
|
||||
flt.setAttribute('indexes', '');
|
||||
|
||||
for (let k = 0; k < lisNb; k++) {
|
||||
let li = tag(flt, 'li')[k];
|
||||
let lbl = tag(li, 'label')[0];
|
||||
[].forEach.call(lis, (li) => {
|
||||
let chk = tag(li, 'input')[0];
|
||||
let lblTxt = matchCase(getText(lbl), tf.caseSensitive);
|
||||
let chkVal = matchCase(chk.value, tf.caseSensitive);
|
||||
|
||||
if (lblTxt !== '' && has(values, lblTxt, tf.caseSensitive)) {
|
||||
if (chkVal !== '' && has(values, chkVal, tf.caseSensitive)) {
|
||||
chk.checked = true;
|
||||
} else {
|
||||
// Check non-empty-text or empty-text option
|
||||
if (values.indexOf(tf.nmOperator) !== -1 &&
|
||||
lblTxt === matchCase(tf.nonEmptyText, tf.caseSensitive)) {
|
||||
chkVal === matchCase(tf.nonEmptyText, tf.caseSensitive)) {
|
||||
chk.checked = true;
|
||||
}
|
||||
else if (values.indexOf(tf.emOperator) !== -1 &&
|
||||
lblTxt === matchCase(tf.emptyText, tf.caseSensitive)) {
|
||||
chkVal === matchCase(tf.emptyText, tf.caseSensitive)) {
|
||||
chk.checked = true;
|
||||
} else {
|
||||
chk.checked = false;
|
||||
}
|
||||
}
|
||||
this.setCheckListValues(chk);
|
||||
}
|
||||
this.setItemOption(chk);
|
||||
});
|
||||
}
|
||||
|
||||
/**
|
||||
|
@ -560,9 +485,12 @@ export class CheckList extends Feature {
|
|||
getValues(colIndex) {
|
||||
let tf = this.tf;
|
||||
let flt = tf.getFilterElement(colIndex);
|
||||
if (!flt) {
|
||||
return [];
|
||||
}
|
||||
|
||||
let fltAttr = flt.getAttribute('value');
|
||||
let values = isEmpty(fltAttr) ? '' : fltAttr;
|
||||
|
||||
//removes last operator ||
|
||||
values = values.substr(0, values.length - 3);
|
||||
//turn || separated values into array
|
||||
|
@ -584,6 +512,7 @@ export class CheckList extends Feature {
|
|||
(tf, colIndex, values) => this.selectOptions(colIndex, values)
|
||||
);
|
||||
this.emitter.off(['rows-changed'], () => this.refreshAll());
|
||||
this.emitter.off(['after-filtering'], () => this.linkFilters());
|
||||
|
||||
this.initialized = false;
|
||||
}
|
||||
|
|
|
@ -1,6 +1,9 @@
|
|||
import {Feature} from '../feature';
|
||||
import {createElm, createText, elm, removeElm} from '../dom';
|
||||
import {addEvt} from '../event';
|
||||
import {defaultsStr} from '../settings';
|
||||
import {isNull} from '../types';
|
||||
import {RIGHT} from './toolbar';
|
||||
|
||||
/**
|
||||
* Clear button UI component
|
||||
|
@ -12,15 +15,48 @@ export class ClearButton extends Feature {
|
|||
* @param {TableFilter} tf TableFilter instance
|
||||
*/
|
||||
constructor(tf) {
|
||||
super(tf, 'btnReset');
|
||||
super(tf, ClearButton);
|
||||
|
||||
let f = this.config;
|
||||
let f = this.config.btn_reset || {};
|
||||
|
||||
/**
|
||||
* Container element ID
|
||||
* @type {String}
|
||||
*/
|
||||
this.targetId = f.btn_reset_target_id || null;
|
||||
this.targetId = defaultsStr(f.target_id, null);
|
||||
|
||||
/**
|
||||
* Text for the clear button
|
||||
* @type {String}
|
||||
*/
|
||||
this.text = defaultsStr(f.text, null);
|
||||
|
||||
/**
|
||||
* Css class for reset button
|
||||
* @type {String}
|
||||
*/
|
||||
this.cssClass = defaultsStr(f.css_class, 'reset');
|
||||
|
||||
/**
|
||||
* Tooltip text for the clear button
|
||||
* @type {String}
|
||||
*/
|
||||
this.tooltip = f.tooltip || 'Clear filters';
|
||||
|
||||
/**
|
||||
* Custom Html string for the clear button
|
||||
* @type {String}
|
||||
*/
|
||||
this.html = defaultsStr(f.html,
|
||||
(!tf.enableIcons || this.text ? null :
|
||||
'<input type="button" value="" class="' + this.cssClass +
|
||||
'" ' + 'title="' + this.tooltip + '" />'));
|
||||
|
||||
/**
|
||||
* Default position in toolbar ('left'|'center'|'right')
|
||||
* @type {String}
|
||||
*/
|
||||
this.toolbarPosition = defaultsStr(f.toolbar_position, RIGHT);
|
||||
|
||||
/**
|
||||
* Clear button container element
|
||||
|
@ -35,33 +71,6 @@ export class ClearButton extends Feature {
|
|||
* @private
|
||||
*/
|
||||
this.element = null;
|
||||
|
||||
/**
|
||||
* Text for the clear button
|
||||
* @type {String}
|
||||
*/
|
||||
this.text = f.btn_reset_text || 'Reset';
|
||||
|
||||
/**
|
||||
* Css class for reset button
|
||||
* @type {String}
|
||||
*/
|
||||
this.cssClass = f.btn_reset_css_class || 'reset';
|
||||
|
||||
/**
|
||||
* Tooltip text for the clear button
|
||||
* @type {String}
|
||||
*/
|
||||
this.tooltip = f.btn_reset_tooltip || 'Clear filters';
|
||||
|
||||
/**
|
||||
* Custom Html string for the clear button
|
||||
* @type {String}
|
||||
*/
|
||||
this.html = f.btn_reset_html ||
|
||||
(!tf.enableIcons ? null :
|
||||
'<input type="button" value="" class="' + this.cssClass +
|
||||
'" ' + 'title="' + this.tooltip + '" />');
|
||||
}
|
||||
|
||||
/**
|
||||
|
@ -85,13 +94,13 @@ export class ClearButton extends Feature {
|
|||
return;
|
||||
}
|
||||
|
||||
this.emitter.emit('initializing-feature', this, !isNull(this.targetId));
|
||||
|
||||
let cont = createElm('span');
|
||||
|
||||
// reset button is added to defined element
|
||||
if (!this.targetId) {
|
||||
tf.setToolbar();
|
||||
}
|
||||
let targetEl = !this.targetId ? tf.rDiv : elm(this.targetId);
|
||||
let targetEl = !this.targetId ?
|
||||
tf.feature('toolbar').container(this.toolbarPosition) :
|
||||
elm(this.targetId);
|
||||
targetEl.appendChild(cont);
|
||||
|
||||
if (!this.html) {
|
||||
|
@ -110,6 +119,8 @@ export class ClearButton extends Feature {
|
|||
|
||||
/** @inherited */
|
||||
this.initialized = true;
|
||||
|
||||
this.emitter.emit('feature-initialized', this);
|
||||
}
|
||||
|
||||
/**
|
||||
|
@ -126,3 +137,6 @@ export class ClearButton extends Feature {
|
|||
this.initialized = false;
|
||||
}
|
||||
}
|
||||
|
||||
// TODO: remove as soon as feature name is fixed
|
||||
ClearButton.meta = {altName: 'btnReset'};
|
||||
|
|
|
@ -17,7 +17,7 @@ export class DateType extends Feature {
|
|||
* @param {TableFilter} tf TableFilter instance
|
||||
*/
|
||||
constructor(tf) {
|
||||
super(tf, 'dateType');
|
||||
super(tf, DateType);
|
||||
|
||||
/**
|
||||
* Global locale
|
||||
|
@ -94,6 +94,16 @@ export class DateType extends Feature {
|
|||
return isObj(colType) ? colType : {};
|
||||
}
|
||||
|
||||
/**
|
||||
* Return the locale code for supplied column index as per configuration
|
||||
* or global setting
|
||||
* @param {Number} colIndex Column index
|
||||
* @returns {String} Locale code (ie: 'en-us')
|
||||
*/
|
||||
getLocale(colIndex) {
|
||||
return this.getOptions(colIndex).locale || this.locale;
|
||||
}
|
||||
|
||||
/**
|
||||
* Add date time format(s) to a locale as specified by the passed
|
||||
* collection of column types, ie:
|
||||
|
|
|
@ -1,25 +1,25 @@
|
|||
import {Feature} from '../feature';
|
||||
import {BaseDropdown} from './baseDropdown';
|
||||
import {createElm, createOpt, elm} from '../dom';
|
||||
import {has} from '../array';
|
||||
import {matchCase} from '../string';
|
||||
import {ignoreCase, numSortAsc, numSortDesc} from '../sort';
|
||||
import {addEvt, targetEvt} from '../event';
|
||||
import {SELECT, MULTIPLE, NONE} from '../const';
|
||||
|
||||
const SORT_ERROR = 'Filter options for column {0} cannot be sorted in ' +
|
||||
'{1} manner.';
|
||||
import {defaultsStr, defaultsBool} from '../settings';
|
||||
|
||||
/**
|
||||
* Dropdown filter UI component
|
||||
* @export
|
||||
* @class Dropdown
|
||||
* @extends {BaseDropdown}
|
||||
*/
|
||||
export class Dropdown extends Feature {
|
||||
export class Dropdown extends BaseDropdown {
|
||||
|
||||
/**
|
||||
* Creates an instance of Dropdown
|
||||
* @param {TableFilter} tf TableFilter instance
|
||||
*/
|
||||
constructor(tf) {
|
||||
super(tf, 'dropdown');
|
||||
super(tf, Dropdown);
|
||||
|
||||
// Configuration object
|
||||
let f = this.config;
|
||||
|
@ -28,41 +28,21 @@ export class Dropdown extends Feature {
|
|||
* Enable the reset filter option as first item
|
||||
* @type {Boolean}
|
||||
*/
|
||||
this.enableSlcResetFilter = f.enable_slc_reset_filter === false ?
|
||||
false : true;
|
||||
this.enableSlcResetFilter =
|
||||
defaultsBool(f.enable_slc_reset_filter, true);
|
||||
|
||||
/**
|
||||
* Non empty option text
|
||||
* @type {String}
|
||||
*/
|
||||
this.nonEmptyText = f.non_empty_text || '(Non empty)';
|
||||
this.nonEmptyText = defaultsStr(f.non_empty_text, '(Non empty)');
|
||||
|
||||
/**
|
||||
* Tooltip text appearing on multiple select
|
||||
* @type {String}
|
||||
*/
|
||||
this.multipleSlcTooltip = f.multiple_slc_tooltip ||
|
||||
'Use Ctrl/Cmd key for multiple selections';
|
||||
|
||||
/**
|
||||
* Indicates drop-down has custom options
|
||||
* @private
|
||||
*/
|
||||
this.isCustom = null;
|
||||
|
||||
/**
|
||||
* List of options values
|
||||
* @type {Array}
|
||||
* @private
|
||||
*/
|
||||
this.opts = null;
|
||||
|
||||
/**
|
||||
* List of options texts for custom values
|
||||
* @type {Array}
|
||||
* @private
|
||||
*/
|
||||
this.optsTxt = null;
|
||||
this.multipleSlcTooltip = defaultsStr(f.multiple_slc_tooltip,
|
||||
'Use Ctrl/Cmd key for multiple selections');
|
||||
}
|
||||
|
||||
|
||||
|
@ -96,15 +76,10 @@ export class Dropdown extends Feature {
|
|||
* Refresh all drop-down filters
|
||||
*/
|
||||
refreshAll() {
|
||||
let tf = this.tf;
|
||||
let selectFlts = tf.getFiltersByType(SELECT, true);
|
||||
let multipleFlts = tf.getFiltersByType(MULTIPLE, true);
|
||||
let flts = selectFlts.concat(multipleFlts);
|
||||
flts.forEach((colIdx) => {
|
||||
let values = this.getValues(colIdx);
|
||||
this.build(colIdx, tf.linkedFilters);
|
||||
this.selectOptions(colIdx, values);
|
||||
});
|
||||
let selectFlts = this.tf.getFiltersByType(SELECT, true);
|
||||
let multipleFlts = this.tf.getFiltersByType(MULTIPLE, true);
|
||||
let colIdxs = selectFlts.concat(multipleFlts);
|
||||
this.refreshFilters(colIdxs);
|
||||
}
|
||||
|
||||
/**
|
||||
|
@ -117,7 +92,7 @@ export class Dropdown extends Feature {
|
|||
let tf = this.tf;
|
||||
let col = tf.getFilterType(colIndex);
|
||||
let externalFltTgtId = isExternal ?
|
||||
tf.externalFltTgtIds[colIndex] : null;
|
||||
tf.externalFltIds[colIndex] : null;
|
||||
|
||||
let slc = createElm(SELECT,
|
||||
['id', tf.buildFilterId(colIndex)],
|
||||
|
@ -162,6 +137,8 @@ export class Dropdown extends Feature {
|
|||
);
|
||||
this.emitter.on(['rows-changed'], () => this.refreshAll());
|
||||
|
||||
this.emitter.on(['after-filtering'], () => this.linkFilters());
|
||||
|
||||
/** @inherited */
|
||||
this.initialized = true;
|
||||
}
|
||||
|
@ -173,21 +150,28 @@ export class Dropdown extends Feature {
|
|||
*/
|
||||
build(colIndex, isLinked = false) {
|
||||
let tf = this.tf;
|
||||
colIndex = parseInt(colIndex, 10);
|
||||
colIndex = Number(colIndex);
|
||||
|
||||
this.emitter.emit('before-populating-filter', tf, colIndex);
|
||||
|
||||
/** @inherited */
|
||||
this.opts = [];
|
||||
/** @inherited */
|
||||
this.optsTxt = [];
|
||||
|
||||
let slcId = tf.fltIds[colIndex];
|
||||
let slc = elm(slcId);
|
||||
let rows = tf.tbl.rows;
|
||||
let nbRows = tf.getRowsNb(true);
|
||||
let slc = tf.getFilterElement(colIndex);
|
||||
|
||||
//custom select test
|
||||
/** @inherited */
|
||||
this.isCustom = tf.isCustomOptions(colIndex);
|
||||
|
||||
//Retrieves custom values
|
||||
if (this.isCustom) {
|
||||
let customValues = tf.getCustomOptions(colIndex);
|
||||
this.opts = customValues[0];
|
||||
this.optsTxt = customValues[1];
|
||||
}
|
||||
|
||||
//custom selects text
|
||||
let activeIdx;
|
||||
let activeFilterId = tf.getActiveFilterId();
|
||||
|
@ -202,35 +186,12 @@ export class Dropdown extends Feature {
|
|||
filteredDataCol = [];
|
||||
}
|
||||
|
||||
for (let k = tf.refRow; k < nbRows; k++) {
|
||||
// always visible rows don't need to appear on selects as always
|
||||
// valid
|
||||
if (tf.hasVisibleRows && tf.visibleRows.indexOf(k) !== -1) {
|
||||
continue;
|
||||
}
|
||||
|
||||
let cell = rows[k].cells,
|
||||
nchilds = cell.length;
|
||||
|
||||
// checks if row has exact cell #
|
||||
if (nchilds !== tf.nbCells || this.isCustom) {
|
||||
continue;
|
||||
}
|
||||
|
||||
// this loop retrieves cell data
|
||||
for (let j = 0; j < nchilds; j++) {
|
||||
if (colIndex !== j) {
|
||||
continue;
|
||||
}
|
||||
if (isLinked && !tf.disableExcludedOptions &&
|
||||
(!tf.paging && !tf.isRowDisplayed(k)) ||
|
||||
(tf.paging && activeIdx && !tf.isRowValid(k))) {
|
||||
continue;
|
||||
}
|
||||
|
||||
let cellValue = tf.getCellValue(cell[j]),
|
||||
//Vary Peter's patch
|
||||
cellString = matchCase(cellValue, tf.caseSensitive);
|
||||
let eachRow = tf.eachRow();
|
||||
eachRow(
|
||||
(row) => {
|
||||
let cellValue = tf.getCellValue(row.cells[colIndex]);
|
||||
//Vary Peter's patch
|
||||
let cellString = matchCase(cellValue, tf.caseSensitive);
|
||||
|
||||
// checks if celldata is already in array
|
||||
if (!has(this.opts, cellString, tf.caseSensitive)) {
|
||||
|
@ -238,66 +199,38 @@ export class Dropdown extends Feature {
|
|||
}
|
||||
|
||||
if (isLinked && tf.disableExcludedOptions) {
|
||||
let filteredCol = filteredDataCol[j];
|
||||
let filteredCol = filteredDataCol[colIndex];
|
||||
if (!filteredCol) {
|
||||
filteredCol = tf.getFilteredDataCol(j);
|
||||
filteredCol = tf.getVisibleColumnValues(colIndex);
|
||||
}
|
||||
if (!has(filteredCol, cellString, tf.caseSensitive) &&
|
||||
!has(excludedOpts, cellString, tf.caseSensitive)) {
|
||||
excludedOpts.push(cellValue);
|
||||
}
|
||||
}
|
||||
}//for j
|
||||
}//for k
|
||||
|
||||
//Retrieves custom values
|
||||
if (this.isCustom) {
|
||||
let customValues = tf.getCustomOptions(colIndex);
|
||||
this.opts = customValues[0];
|
||||
this.optsTxt = customValues[1];
|
||||
}
|
||||
|
||||
if (tf.sortSlc && !this.isCustom) {
|
||||
if (!tf.caseSensitive) {
|
||||
this.opts.sort(ignoreCase);
|
||||
if (excludedOpts) {
|
||||
excludedOpts.sort(ignoreCase);
|
||||
},
|
||||
// continue conditions function
|
||||
(row, k) => {
|
||||
// excluded rows don't need to appear on selects as always valid
|
||||
if (tf.excludeRows.indexOf(k) !== -1) {
|
||||
return true;
|
||||
}
|
||||
|
||||
// checks if row has expected number of cells
|
||||
if (row.cells.length !== tf.nbCells || this.isCustom) {
|
||||
return true;
|
||||
}
|
||||
|
||||
if (isLinked && !this.isValidLinkedValue(k, activeIdx)) {
|
||||
return true;
|
||||
}
|
||||
} else {
|
||||
this.opts.sort();
|
||||
if (excludedOpts) { excludedOpts.sort(); }
|
||||
}
|
||||
}
|
||||
);
|
||||
|
||||
//asc sort
|
||||
if (tf.sortNumAsc.indexOf(colIndex) !== -1) {
|
||||
try {
|
||||
this.opts.sort(numSortAsc);
|
||||
if (excludedOpts) {
|
||||
excludedOpts.sort(numSortAsc);
|
||||
}
|
||||
if (this.isCustom) {
|
||||
this.optsTxt.sort(numSortAsc);
|
||||
}
|
||||
} catch (e) {
|
||||
throw new Error(SORT_ERROR.replace('{0}', colIndex)
|
||||
.replace('{1}', 'ascending'));
|
||||
}//in case there are alphanumeric values
|
||||
}
|
||||
//desc sort
|
||||
if (tf.sortNumDesc.indexOf(colIndex) !== -1) {
|
||||
try {
|
||||
this.opts.sort(numSortDesc);
|
||||
if (excludedOpts) {
|
||||
excludedOpts.sort(numSortDesc);
|
||||
}
|
||||
if (this.isCustom) {
|
||||
this.optsTxt.sort(numSortDesc);
|
||||
}
|
||||
} catch (e) {
|
||||
throw new Error(SORT_ERROR.replace('{0}', colIndex)
|
||||
.replace('{1}', 'ascending'));
|
||||
}//in case there are alphanumeric values
|
||||
//sort options
|
||||
this.opts = this.sortOptions(colIndex, this.opts);
|
||||
if (excludedOpts) {
|
||||
excludedOpts = this.sortOptions(colIndex, excludedOpts);
|
||||
}
|
||||
|
||||
//populates drop-down
|
||||
|
@ -437,6 +370,7 @@ export class Dropdown extends Feature {
|
|||
(tf, colIndex, values) => this.selectOptions(colIndex, values)
|
||||
);
|
||||
this.emitter.off(['rows-changed'], () => this.refreshAll());
|
||||
this.emitter.off(['after-filtering'], () => this.linkFilters());
|
||||
this.initialized = false;
|
||||
}
|
||||
}
|
||||
|
|
|
@ -3,6 +3,9 @@ import {createElm, removeElm, elm, tag} from '../dom';
|
|||
import {addEvt, targetEvt} from '../event';
|
||||
import {contains} from '../string';
|
||||
import {NONE} from '../const';
|
||||
import {
|
||||
defaultsBool, defaultsStr, defaultsNb, defaultsArr
|
||||
} from '../settings';
|
||||
|
||||
/**
|
||||
* Grid layout, table with fixed headers
|
||||
|
@ -14,77 +17,76 @@ export class GridLayout extends Feature {
|
|||
* @param {TableFilter} tf TableFilter instance
|
||||
*/
|
||||
constructor(tf) {
|
||||
super(tf, 'gridLayout');
|
||||
super(tf, GridLayout);
|
||||
|
||||
let f = this.config;
|
||||
let f = this.config.grid_layout || {};
|
||||
|
||||
/**
|
||||
* Grid-layout container width as CSS string
|
||||
* @type {String}
|
||||
*/
|
||||
this.width = f.grid_width || null;
|
||||
this.width = defaultsStr(f.width, null);
|
||||
|
||||
/**
|
||||
* Grid-layout container height as CSS string
|
||||
* @type {String}
|
||||
*/
|
||||
this.height = f.grid_height || null;
|
||||
this.height = defaultsStr(f.height, null);
|
||||
|
||||
/**
|
||||
* Css class for main container element
|
||||
* @type {String}
|
||||
*/
|
||||
this.mainContCssClass = f.grid_cont_css_class || 'grd_Cont';
|
||||
this.mainContCssClass = defaultsStr(f.cont_css_class, 'grd_Cont');
|
||||
|
||||
/**
|
||||
* Css class for body table container element
|
||||
* @type {String}
|
||||
*/
|
||||
this.contCssClass = f.grid_tbl_cont_css_class || 'grd_tblCont';
|
||||
this.contCssClass = defaultsStr(f.tbl_cont_css_class, 'grd_tblCont');
|
||||
|
||||
/**
|
||||
* Css class for headers table container element
|
||||
* @type {String}
|
||||
*/
|
||||
this.headContCssClass = f.grid_tblHead_cont_css_class ||
|
||||
'grd_headTblCont';
|
||||
this.headContCssClass = defaultsStr(f.tbl_head_css_class,
|
||||
'grd_headTblCont');
|
||||
|
||||
/**
|
||||
* Css class for toolbar container element (rows counter, paging etc.)
|
||||
* @type {String}
|
||||
*/
|
||||
this.infDivCssClass = f.grid_inf_grid_css_class || 'grd_inf';
|
||||
this.infDivCssClass = defaultsStr(f.inf_grid_css_class, 'grd_inf');
|
||||
|
||||
/**
|
||||
* Index of the headers row, default: 0
|
||||
* @type {Number}
|
||||
*/
|
||||
this.headRowIndex = f.grid_headers_row_index || 0;
|
||||
this.headRowIndex = defaultsNb(f.headers_row_index, 0);
|
||||
|
||||
/**
|
||||
* Collection of the header row indexes to be moved into headers table
|
||||
* @type {Array}
|
||||
*/
|
||||
this.headRows = f.grid_headers_rows || [0];
|
||||
this.headRows = defaultsArr(f.headers_rows, [0]);
|
||||
|
||||
/**
|
||||
* Enable or disable column filters generation, default: true
|
||||
* @type {Boolean}
|
||||
*/
|
||||
this.enableFilters = f.grid_enable_default_filters === false ?
|
||||
false : true;
|
||||
this.filters = defaultsBool(f.filters, true);
|
||||
|
||||
/**
|
||||
* Enable or disable column headers, default: false
|
||||
* @type {Boolean}
|
||||
*/
|
||||
this.noHeaders = Boolean(f.grid_no_headers);
|
||||
this.noHeaders = Boolean(f.no_headers);
|
||||
|
||||
/**
|
||||
* Grid-layout default column widht as CSS string
|
||||
* @type {String}
|
||||
*/
|
||||
this.defaultColWidth = f.grid_default_col_width || '100px';
|
||||
this.defaultColWidth = defaultsStr(f.default_col_width, '100px');
|
||||
|
||||
/**
|
||||
* List of column elements
|
||||
|
@ -112,14 +114,14 @@ export class GridLayout extends Feature {
|
|||
* @type {String}
|
||||
* @private
|
||||
*/
|
||||
this.sourceTblHtml = tf.tbl.outerHTML;
|
||||
this.sourceTblHtml = tf.dom().outerHTML;
|
||||
|
||||
/**
|
||||
* Indicates if working table has column elements
|
||||
* @type {Boolean}
|
||||
* @private
|
||||
*/
|
||||
this.tblHasColTag = tag(tf.tbl, 'col').length > 0 ? true : false;
|
||||
this.tblHasColTag = tag(tf.dom(), 'col').length > 0 ? true : false;
|
||||
|
||||
/**
|
||||
* Main container element
|
||||
|
@ -146,7 +148,7 @@ export class GridLayout extends Feature {
|
|||
this.headTbl = null;
|
||||
|
||||
// filters flag at TF level
|
||||
tf.fltGrid = this.enableFilters;
|
||||
tf.fltGrid = this.filters;
|
||||
}
|
||||
|
||||
/**
|
||||
|
@ -155,7 +157,7 @@ export class GridLayout extends Feature {
|
|||
*/
|
||||
init() {
|
||||
let tf = this.tf;
|
||||
let tbl = tf.tbl;
|
||||
let tbl = tf.dom();
|
||||
|
||||
if (this.initialized) {
|
||||
return;
|
||||
|
@ -167,9 +169,6 @@ export class GridLayout extends Feature {
|
|||
// Assign default column widths
|
||||
this.setDefaultColWidths();
|
||||
|
||||
// Initial table width
|
||||
let tblW = this.initialTableWidth();
|
||||
|
||||
//Main container: it will contain all the elements
|
||||
this.tblMainCont = this.createContainer(
|
||||
'div', this.mainContCssClass);
|
||||
|
@ -190,6 +189,7 @@ export class GridLayout extends Feature {
|
|||
|
||||
//In case table width is expressed in %
|
||||
if (tbl.style.width === '') {
|
||||
let tblW = this.initialTableWidth();
|
||||
tbl.style.width = (contains('%', tblW) ?
|
||||
tbl.clientWidth : tblW) + 'px';
|
||||
}
|
||||
|
@ -200,7 +200,6 @@ export class GridLayout extends Feature {
|
|||
//Headers table container: div wrapping headers table
|
||||
this.headTblCont = this.createContainer(
|
||||
'div', this.headContCssClass);
|
||||
this.setConfigWidth(this.headTblCont);
|
||||
|
||||
//Headers table
|
||||
this.headTbl = createElm('table');
|
||||
|
@ -233,22 +232,16 @@ export class GridLayout extends Feature {
|
|||
tbl.removeChild(thead[0]);
|
||||
}
|
||||
|
||||
//Headers table style
|
||||
// ensure table layout is always set even if already set in css
|
||||
// definitions, potentially with custom css class this could be lost
|
||||
this.headTbl.style.tableLayout = 'fixed';
|
||||
tbl.style.tableLayout = 'fixed';
|
||||
this.headTbl.cellPadding = tbl.cellPadding;
|
||||
this.headTbl.cellSpacing = tbl.cellSpacing;
|
||||
// this.headTbl.style.width = tbl.style.width;
|
||||
|
||||
//content table without headers needs col widths to be reset
|
||||
tf.setColWidths(this.headTbl);
|
||||
|
||||
//Headers container width
|
||||
// this.headTblCont.style.width = this.tblCont.clientWidth+'px';
|
||||
|
||||
tbl.style.width = '';
|
||||
//
|
||||
this.headTbl.style.width = tbl.clientWidth + 'px';
|
||||
this.headTbl.style.width = tbl.style.width;
|
||||
//
|
||||
|
||||
//scroll synchronisation
|
||||
|
@ -288,10 +281,6 @@ export class GridLayout extends Feature {
|
|||
filtersRow.style.display = NONE;
|
||||
}
|
||||
|
||||
if (tbl.clientWidth !== this.headTbl.clientWidth) {
|
||||
tbl.style.width = this.headTbl.clientWidth + 'px';
|
||||
}
|
||||
|
||||
/** @inherited */
|
||||
this.initialized = true;
|
||||
}
|
||||
|
@ -305,7 +294,6 @@ export class GridLayout extends Feature {
|
|||
tf.refRow = 0;
|
||||
tf.headersRow = 0;
|
||||
tf.filtersRowIndex = 1;
|
||||
tf.isExternalFlt = true;
|
||||
}
|
||||
|
||||
/**
|
||||
|
@ -314,12 +302,13 @@ export class GridLayout extends Feature {
|
|||
*/
|
||||
setDefaultColWidths() {
|
||||
let tf = this.tf;
|
||||
if (tf.hasColWidths) {
|
||||
if (tf.colWidths.length > 0) {
|
||||
return;
|
||||
}
|
||||
for (let k = 0, len = tf.getCellsNb(); k < len; k++) {
|
||||
|
||||
tf.eachCol((k) => {
|
||||
let colW;
|
||||
let cell = tf.tbl.rows[tf.getHeadersRowIndex()].cells[k];
|
||||
let cell = tf.dom().rows[tf.getHeadersRowIndex()].cells[k];
|
||||
if (cell.width !== '') {
|
||||
colW = cell.width;
|
||||
} else if (cell.style.width !== '') {
|
||||
|
@ -328,8 +317,8 @@ export class GridLayout extends Feature {
|
|||
colW = this.defaultColWidth;
|
||||
}
|
||||
tf.colWidths[k] = colW;
|
||||
}
|
||||
tf.hasColWidths = true;
|
||||
});
|
||||
|
||||
tf.setColWidths();
|
||||
}
|
||||
|
||||
|
@ -339,7 +328,7 @@ export class GridLayout extends Feature {
|
|||
* @private
|
||||
*/
|
||||
initialTableWidth() {
|
||||
let tbl = this.tf.tbl;
|
||||
let tbl = this.tf.dom();
|
||||
let width; //initial table width
|
||||
|
||||
if (tbl.width !== '') {
|
||||
|
@ -374,14 +363,14 @@ export class GridLayout extends Feature {
|
|||
createFiltersRow() {
|
||||
let tf = this.tf;
|
||||
let filtersRow = createElm('tr');
|
||||
if (this.enableFilters && tf.fltGrid) {
|
||||
tf.externalFltTgtIds = [];
|
||||
for (let j = 0; j < tf.getCellsNb(); j++) {
|
||||
if (this.filters && tf.fltGrid) {
|
||||
tf.externalFltIds = [];
|
||||
tf.eachCol((j) => {
|
||||
let fltTdId = `${tf.prfxFlt + j + this.prfxGridFltTd + tf.id}`;
|
||||
let cl = createElm(tf.fltCellTag, ['id', fltTdId]);
|
||||
filtersRow.appendChild(cl);
|
||||
tf.externalFltTgtIds[j] = fltTdId;
|
||||
}
|
||||
tf.externalFltIds[j] = fltTdId;
|
||||
});
|
||||
}
|
||||
return filtersRow;
|
||||
}
|
||||
|
@ -392,15 +381,15 @@ export class GridLayout extends Feature {
|
|||
*/
|
||||
setColumnElements() {
|
||||
let tf = this.tf;
|
||||
let cols = tag(tf.tbl, 'col');
|
||||
let cols = tag(tf.dom(), 'col');
|
||||
this.tblHasColTag = cols.length > 0;
|
||||
|
||||
for (let k = (tf.nbCells - 1); k >= 0; k--) {
|
||||
for (let k = (tf.getCellsNb() - 1); k >= 0; k--) {
|
||||
let col;
|
||||
|
||||
if (!this.tblHasColTag) {
|
||||
col = createElm('col');
|
||||
tf.tbl.insertBefore(col, tf.tbl.firstChild);
|
||||
tf.dom().insertBefore(col, tf.dom().firstChild);
|
||||
} else {
|
||||
col = cols[k];
|
||||
}
|
||||
|
@ -423,7 +412,7 @@ export class GridLayout extends Feature {
|
|||
} else {
|
||||
// Headers row are moved from content table to headers table
|
||||
for (let i = 0; i < this.headRows.length; i++) {
|
||||
let row = this.tf.tbl.rows[this.headRows[i]];
|
||||
let row = this.tf.dom().rows[this.headRows[i]];
|
||||
tableHead.appendChild(row);
|
||||
}
|
||||
}
|
||||
|
@ -454,7 +443,7 @@ export class GridLayout extends Feature {
|
|||
getSortTriggerIds(row) {
|
||||
let tf = this.tf;
|
||||
let sortTriggers = [];
|
||||
for (let n = 0; n < tf.getCellsNb(); n++) {
|
||||
tf.eachCol((n) => {
|
||||
let c = row.cells[n];
|
||||
let thId = c.getAttribute('id');
|
||||
if (!thId || thId === '') {
|
||||
|
@ -462,7 +451,7 @@ export class GridLayout extends Feature {
|
|||
c.setAttribute('id', thId);
|
||||
}
|
||||
sortTriggers.push(thId);
|
||||
}
|
||||
});
|
||||
return sortTriggers;
|
||||
}
|
||||
|
||||
|
@ -471,7 +460,7 @@ export class GridLayout extends Feature {
|
|||
*/
|
||||
destroy() {
|
||||
let tf = this.tf;
|
||||
let tbl = tf.tbl;
|
||||
let tbl = tf.dom();
|
||||
|
||||
if (!this.initialized) {
|
||||
return;
|
||||
|
|
|
@ -86,7 +86,7 @@ export class Hash {
|
|||
}
|
||||
|
||||
/**
|
||||
* Converts a URL hash into a state JSON object
|
||||
* Converts a URL hash into a JSON object
|
||||
*
|
||||
* @param {String} hash URL hash fragment
|
||||
* @returns {Object} JSON object
|
||||
|
|
|
@ -3,10 +3,13 @@ import {createElm, createText, elm, removeElm} from '../dom';
|
|||
import {addEvt, targetEvt, removeEvt} from '../event';
|
||||
import {NONE} from '../const';
|
||||
import {root} from '../root';
|
||||
import {isEmpty, isNull} from '../types';
|
||||
import {defaultsStr, defaultsNb} from '../settings';
|
||||
import {RIGHT} from './toolbar';
|
||||
|
||||
const WIKI_URL = 'https://github.com/koalyptus/TableFilter/wiki/' +
|
||||
'4.-Filter-operators';
|
||||
const WEBSITE_URL = 'http://koalyptus.github.io/TableFilter/';
|
||||
const WEBSITE_URL = 'https://www.tablefilter.com/';
|
||||
|
||||
/**
|
||||
* Help UI component
|
||||
|
@ -18,29 +21,27 @@ export class Help extends Feature {
|
|||
* @param {TableFilter} tf TableFilter instance
|
||||
*/
|
||||
constructor(tf) {
|
||||
super(tf, 'help');
|
||||
super(tf, Help);
|
||||
|
||||
let f = this.config;
|
||||
let f = this.config.help_instructions || {};
|
||||
|
||||
/**
|
||||
* ID of main custom container element
|
||||
* @type {String}
|
||||
*/
|
||||
this.tgtId = f.help_instructions_target_id || null;
|
||||
this.tgtId = defaultsStr(f.target_id, null);
|
||||
|
||||
/**
|
||||
* ID of custom container element for instructions
|
||||
* @type {String}
|
||||
*/
|
||||
this.contTgtId = f.help_instructions_container_target_id ||
|
||||
null;
|
||||
this.contTgtId = defaultsStr(f.container_target_id, null);
|
||||
|
||||
/**
|
||||
* Instructions text (accepts HTML)
|
||||
* @type {String}
|
||||
*/
|
||||
this.instrText = f.help_instructions_text ?
|
||||
f.help_instructions_text :
|
||||
this.instrText = !isEmpty(f.text) ? f.text :
|
||||
'Use the filters above each column to filter and limit table ' +
|
||||
'data. Advanced searches can be performed by using the following ' +
|
||||
'operators: <br /><b><</b>, <b><=</b>, <b>></b>, ' +
|
||||
|
@ -53,32 +54,31 @@ export class Help extends Feature {
|
|||
* Instructions HTML
|
||||
* @type {String}
|
||||
*/
|
||||
this.instrHtml = f.help_instructions_html || null;
|
||||
this.instrHtml = defaultsStr(f.html, null);
|
||||
|
||||
/**
|
||||
* Help button text ('?')
|
||||
* @type {String}
|
||||
*/
|
||||
this.btnText = f.help_instructions_btn_text || '?';
|
||||
this.btnText = defaultsStr(f.btn_text, '?');
|
||||
|
||||
/**
|
||||
* Custom help button HTML
|
||||
* @type {String}
|
||||
*/
|
||||
this.btnHtml = f.help_instructions_btn_html || null;
|
||||
this.btnHtml = defaultsStr(f.btn_html, null);
|
||||
|
||||
/**
|
||||
* Css class for help button
|
||||
* @type {String}
|
||||
*/
|
||||
this.btnCssClass = f.help_instructions_btn_css_class || 'helpBtn';
|
||||
this.btnCssClass = defaultsStr(f.btn_css_class, 'helpBtn');
|
||||
|
||||
/**
|
||||
* Css class for help container element
|
||||
* @type {String}
|
||||
*/
|
||||
this.contCssClass = f.help_instructions_container_css_class ||
|
||||
'helpCont';
|
||||
this.contCssClass = defaultsStr(f.container_css_class, 'helpCont');
|
||||
|
||||
/**
|
||||
* Button DOM element
|
||||
|
@ -92,6 +92,15 @@ export class Help extends Feature {
|
|||
*/
|
||||
this.cont = null;
|
||||
|
||||
/**
|
||||
* Adjust container left position when table's horizontal scroll is
|
||||
* on, typically when `responsive` option is enabled.
|
||||
* @type {Number}
|
||||
* @defaultValue 25
|
||||
*/
|
||||
this.contAdjustLeftPosition =
|
||||
defaultsNb(f.container_adjust_left_position, 25);
|
||||
|
||||
/**
|
||||
* Bound mouseup wrapper
|
||||
* @private
|
||||
|
@ -109,6 +118,12 @@ export class Help extends Feature {
|
|||
'<div align="center" style="margin-top:8px;">' +
|
||||
'<a href="javascript:void(0);" class="close">Close</a></div></div>';
|
||||
|
||||
/**
|
||||
* Default position in toolbar ('left'|'center'|'right')
|
||||
* @type {String}
|
||||
*/
|
||||
this.toolbarPosition = defaultsStr(f.toolbar_position, RIGHT);
|
||||
|
||||
this.emitter.on(['init-help'], () => this.init());
|
||||
}
|
||||
|
||||
|
@ -138,6 +153,8 @@ export class Help extends Feature {
|
|||
return;
|
||||
}
|
||||
|
||||
this.emitter.emit('initializing-feature', this, !isNull(this.tgtId));
|
||||
|
||||
let tf = this.tf;
|
||||
|
||||
let btn = createElm('span');
|
||||
|
@ -146,10 +163,9 @@ export class Help extends Feature {
|
|||
this.boundMouseup = this.onMouseup.bind(this);
|
||||
|
||||
//help button is added to defined element
|
||||
if (!this.tgtId) {
|
||||
tf.setToolbar();
|
||||
}
|
||||
let targetEl = !this.tgtId ? tf.rDiv : elm(this.tgtId);
|
||||
let targetEl = !this.tgtId ?
|
||||
tf.feature('toolbar').container(this.toolbarPosition) :
|
||||
elm(this.tgtId);
|
||||
targetEl.appendChild(btn);
|
||||
|
||||
let divContainer = !this.contTgtId ? btn : elm(this.contTgtId);
|
||||
|
@ -187,15 +203,17 @@ export class Help extends Feature {
|
|||
this.btn = btn;
|
||||
/** @inherited */
|
||||
this.initialized = true;
|
||||
|
||||
this.emitter.emit('feature-initialized', this);
|
||||
}
|
||||
|
||||
/**
|
||||
* Toggle help pop-up
|
||||
*/
|
||||
toggle() {
|
||||
// check only if explicitily set to false as in this case undefined
|
||||
// check only if explicitily disabled as in this case undefined
|
||||
// signifies the help feature is enabled by default
|
||||
if (this.enabled === false) {
|
||||
if (!this.isEnabled()) {
|
||||
return;
|
||||
}
|
||||
|
||||
|
@ -205,9 +223,21 @@ export class Help extends Feature {
|
|||
let divDisplay = this.cont.style.display;
|
||||
if (divDisplay === '' || divDisplay === NONE) {
|
||||
this.cont.style.display = 'inline';
|
||||
|
||||
// if table element has an horizontal scrollbar adjust container
|
||||
// left position accordingly
|
||||
if (this.tf.dom().scrollLeft > 0) {
|
||||
this.cont.style.left = `${
|
||||
this.btn.offsetLeft
|
||||
- this.tf.dom().scrollLeft
|
||||
+ this.contAdjustLeftPosition
|
||||
}px`;
|
||||
}
|
||||
|
||||
addEvt(root, 'mouseup', this.boundMouseup);
|
||||
} else {
|
||||
this.cont.style.display = NONE;
|
||||
this.cont.style.left = '';
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -225,8 +255,10 @@ export class Help extends Feature {
|
|||
this.cont = null;
|
||||
|
||||
this.boundMouseup = null;
|
||||
|
||||
this.initialized = false;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
// TODO: remove as soon as feature name is fixed
|
||||
Help.meta = {alwaysInstantiate: true};
|
||||
|
|
|
@ -1,6 +1,7 @@
|
|||
import {createText, createElm, getText} from '../dom';
|
||||
import {isArray} from '../types';
|
||||
import {isNull} from '../types';
|
||||
import {rgxEsc} from '../string';
|
||||
import {defaultsStr} from '../settings';
|
||||
|
||||
/**
|
||||
* Highlight matched keywords upon filtering
|
||||
|
@ -21,7 +22,7 @@ export class HighlightKeyword {
|
|||
* Css class for highlighted term
|
||||
* @type {String}
|
||||
*/
|
||||
this.highlightCssClass = f.highlight_css_class || 'keyword';
|
||||
this.highlightCssClass = defaultsStr(f.highlight_css_class, 'keyword');
|
||||
|
||||
/**
|
||||
* TableFilter instance
|
||||
|
@ -99,12 +100,13 @@ export class HighlightKeyword {
|
|||
* @param {String} cssClass Css class to remove
|
||||
*/
|
||||
unhighlight(term, cssClass) {
|
||||
let highlightedNodes = this.tf.tbl.querySelectorAll(`.${cssClass}`);
|
||||
let highlightedNodes = this.tf.dom().querySelectorAll(`.${cssClass}`);
|
||||
for (let i = 0; i < highlightedNodes.length; i++) {
|
||||
let n = highlightedNodes[i];
|
||||
let nodeVal = getText(n);
|
||||
|
||||
if (nodeVal.toLowerCase().indexOf(term.toLowerCase()) !== -1) {
|
||||
if (isNull(term) ||
|
||||
nodeVal.toLowerCase().indexOf(term.toLowerCase()) !== -1) {
|
||||
let parentNode = n.parentNode;
|
||||
parentNode.replaceChild(createText(nodeVal), n);
|
||||
parentNode.normalize();
|
||||
|
@ -119,15 +121,8 @@ export class HighlightKeyword {
|
|||
if (!this.tf.highlightKeywords) {
|
||||
return;
|
||||
}
|
||||
// iterate filters values to unhighlight all values
|
||||
this.tf.getFiltersValue().forEach((val) => {
|
||||
if (isArray(val)) {
|
||||
val.forEach((item) =>
|
||||
this.unhighlight(item, this.highlightCssClass));
|
||||
} else {
|
||||
this.unhighlight(val, this.highlightCssClass);
|
||||
}
|
||||
});
|
||||
|
||||
this.unhighlight(null, this.highlightCssClass);
|
||||
}
|
||||
|
||||
/** Remove feature */
|
||||
|
@ -177,3 +172,9 @@ export class HighlightKeyword {
|
|||
this.highlight(cell, term, this.highlightCssClass);
|
||||
}
|
||||
}
|
||||
|
||||
// TODO: remove as soon as feature name is fixed
|
||||
HighlightKeyword.meta = {
|
||||
name: 'highlightKeyword',
|
||||
altName: 'highlightKeywords'
|
||||
};
|
||||
|
|
|
@ -1,10 +1,11 @@
|
|||
import {Feature} from '../feature';
|
||||
import {createElm, createText, elm, removeElm} from '../dom';
|
||||
import {isFn, EMPTY_FN} from '../types';
|
||||
import {EMPTY_FN} from '../types';
|
||||
import {root} from '../root';
|
||||
import {NONE} from '../const';
|
||||
import {defaultsStr, defaultsFn} from '../settings';
|
||||
|
||||
const EVENTS = [
|
||||
const BEFORE_ACTION_EVENTS = [
|
||||
'before-filtering',
|
||||
'before-populating-filter',
|
||||
'before-page-change',
|
||||
|
@ -16,6 +17,18 @@ const EVENTS = [
|
|||
'before-loading-themes'
|
||||
];
|
||||
|
||||
const AFTER_ACTION_EVENTS = [
|
||||
'after-filtering',
|
||||
'after-populating-filter',
|
||||
'after-page-change',
|
||||
'after-clearing-filters',
|
||||
'after-page-length-change',
|
||||
'after-reset-page',
|
||||
'after-reset-page-length',
|
||||
'after-loading-extensions',
|
||||
'after-loading-themes'
|
||||
];
|
||||
|
||||
/**
|
||||
* Activity indicator
|
||||
*
|
||||
|
@ -31,15 +44,15 @@ export class Loader extends Feature {
|
|||
* @param {TableFilter} tf TableFilter instance
|
||||
*/
|
||||
constructor(tf) {
|
||||
super(tf, 'loader');
|
||||
super(tf, Loader);
|
||||
|
||||
let f = this.config;
|
||||
let f = this.config.loader || {};
|
||||
|
||||
/**
|
||||
* ID of custom container element
|
||||
* @type {String}
|
||||
*/
|
||||
this.targetId = f.loader_target_id || null;
|
||||
this.targetId = defaultsStr(f.target_id, null);
|
||||
|
||||
/**
|
||||
* Loader container DOM element
|
||||
|
@ -51,19 +64,19 @@ export class Loader extends Feature {
|
|||
* Text displayed when indicator is visible
|
||||
* @type {String}
|
||||
*/
|
||||
this.text = f.loader_text || 'Loading...';
|
||||
this.text = defaultsStr(f.text, 'Loading...');
|
||||
|
||||
/**
|
||||
* Custom HTML injected in Loader's container element
|
||||
* @type {String}
|
||||
*/
|
||||
this.html = f.loader_html || null;
|
||||
this.html = defaultsStr(f.html, null);
|
||||
|
||||
/**
|
||||
* Css class for Loader's container element
|
||||
* @type {String}
|
||||
*/
|
||||
this.cssClass = f.loader_css_class || 'loader';
|
||||
this.cssClass = defaultsStr(f.css_class, 'loader');
|
||||
|
||||
/**
|
||||
* Close delay in milliseconds
|
||||
|
@ -75,14 +88,13 @@ export class Loader extends Feature {
|
|||
* Callback fired when loader is displayed
|
||||
* @type {Function}
|
||||
*/
|
||||
this.onShow = isFn(f.on_show_loader) ?
|
||||
f.on_show_loader : EMPTY_FN;
|
||||
this.onShow = defaultsFn(f.on_show_loader, EMPTY_FN);
|
||||
|
||||
/**
|
||||
* Callback fired when loader is closed
|
||||
* @type {Function}
|
||||
*/
|
||||
this.onHide = isFn(f.on_hide_loader) ? f.on_hide_loader : EMPTY_FN;
|
||||
this.onHide = defaultsFn(f.on_hide_loader, EMPTY_FN);
|
||||
}
|
||||
|
||||
/**
|
||||
|
@ -100,9 +112,9 @@ export class Loader extends Feature {
|
|||
containerDiv.className = this.cssClass;
|
||||
|
||||
let targetEl = !this.targetId ?
|
||||
tf.tbl.parentNode : elm(this.targetId);
|
||||
tf.dom().parentNode : elm(this.targetId);
|
||||
if (!this.targetId) {
|
||||
targetEl.insertBefore(containerDiv, tf.tbl);
|
||||
targetEl.insertBefore(containerDiv, tf.dom());
|
||||
} else {
|
||||
targetEl.appendChild(containerDiv);
|
||||
}
|
||||
|
@ -116,12 +128,10 @@ export class Loader extends Feature {
|
|||
this.show(NONE);
|
||||
|
||||
// Subscribe to events
|
||||
emitter.on(EVENTS, () => this.show(''));
|
||||
emitter.on(EVENTS, () => this.show(NONE));
|
||||
emitter.on(BEFORE_ACTION_EVENTS, () => this.show(''));
|
||||
emitter.on(AFTER_ACTION_EVENTS, () => this.show(NONE));
|
||||
|
||||
/**
|
||||
* @inherited
|
||||
*/
|
||||
/** @inherited */
|
||||
this.initialized = true;
|
||||
}
|
||||
|
||||
|
@ -134,7 +144,7 @@ export class Loader extends Feature {
|
|||
return;
|
||||
}
|
||||
|
||||
let displayLoader = () => {
|
||||
function displayLoader() {
|
||||
if (!this.cont) {
|
||||
return;
|
||||
}
|
||||
|
@ -148,7 +158,7 @@ export class Loader extends Feature {
|
|||
};
|
||||
|
||||
let t = p === NONE ? this.closeDelay : 1;
|
||||
root.setTimeout(displayLoader, t);
|
||||
root.setTimeout(displayLoader.bind(this), t);
|
||||
}
|
||||
|
||||
/**
|
||||
|
@ -165,8 +175,8 @@ export class Loader extends Feature {
|
|||
this.cont = null;
|
||||
|
||||
// Unsubscribe to events
|
||||
emitter.off(EVENTS, () => this.show(''));
|
||||
emitter.off(EVENTS, () => this.show(NONE));
|
||||
emitter.off(BEFORE_ACTION_EVENTS, () => this.show(''));
|
||||
emitter.off(AFTER_ACTION_EVENTS, () => this.show(NONE));
|
||||
|
||||
this.initialized = false;
|
||||
}
|
||||
|
|
146
src/modules/markActiveColumns.js
Normal file
146
src/modules/markActiveColumns.js
Normal file
|
@ -0,0 +1,146 @@
|
|||
import {Feature} from '../feature';
|
||||
import {addClass, removeClass, hasClass} from '../dom';
|
||||
import {EMPTY_FN} from '../types';
|
||||
import {defaultsStr, defaultsFn} from '../settings';
|
||||
|
||||
/**
|
||||
* Visual indicator for filtered columns
|
||||
* @export
|
||||
* @class MarkActiveColumns
|
||||
* @extends {Feature}
|
||||
*/
|
||||
export class MarkActiveColumns extends Feature {
|
||||
|
||||
/**
|
||||
* Create an instance of MarkActiveColumns
|
||||
* @param {TableFilter} tf TableFilter instance
|
||||
*/
|
||||
constructor(tf) {
|
||||
super(tf, MarkActiveColumns);
|
||||
|
||||
let config = this.config.mark_active_columns || {};
|
||||
|
||||
/**
|
||||
* Css class for filtered (active) columns
|
||||
* @type {String}
|
||||
*/
|
||||
this.headerCssClass = defaultsStr(config.header_css_class,
|
||||
'activeHeader');
|
||||
|
||||
/**
|
||||
* Css class for filtered (active) column cells
|
||||
* @type {String}
|
||||
*/
|
||||
this.cellCssClass = defaultsStr(config.cell_css_class,
|
||||
'activeCell');
|
||||
|
||||
/**
|
||||
* Enable/disable column highlighting
|
||||
* @type {Boolean}
|
||||
*/
|
||||
this.highlightColumn = Boolean(config.highlight_column);
|
||||
|
||||
/**
|
||||
* Callback fired before a column is marked as filtered
|
||||
* @type {Function}
|
||||
*/
|
||||
this.onBeforeActiveColumn = defaultsFn(config.on_before_active_column,
|
||||
EMPTY_FN);
|
||||
|
||||
/**
|
||||
* Callback fired after a column is marked as filtered
|
||||
* @type {Function}
|
||||
*/
|
||||
this.onAfterActiveColumn = defaultsFn(config.on_after_active_column,
|
||||
EMPTY_FN);
|
||||
}
|
||||
|
||||
/**
|
||||
* Initialise MarkActiveColumns instance
|
||||
*/
|
||||
init() {
|
||||
if (this.initialized) {
|
||||
return;
|
||||
}
|
||||
|
||||
this.emitter.on(['before-filtering'], () => this.clearActiveColumns());
|
||||
this.emitter.on(
|
||||
['cell-processed'],
|
||||
(tf, colIndex) => this.markActiveColumn(colIndex)
|
||||
);
|
||||
|
||||
/** @inherited */
|
||||
this.initialized = true;
|
||||
}
|
||||
|
||||
/**
|
||||
* Clear filtered columns visual indicator (background color)
|
||||
*/
|
||||
clearActiveColumns() {
|
||||
let tf = this.tf;
|
||||
tf.eachCol((idx) => {
|
||||
removeClass(tf.getHeaderElement(idx), this.headerCssClass);
|
||||
|
||||
if (this.highlightColumn) {
|
||||
this.eachColumnCell(idx,
|
||||
(cell) => removeClass(cell, this.cellCssClass));
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
/**
|
||||
* Mark currently filtered column
|
||||
* @param {Number} colIndex Column index
|
||||
*/
|
||||
markActiveColumn(colIndex) {
|
||||
let tf = this.tf;
|
||||
let header = tf.getHeaderElement(colIndex);
|
||||
if (hasClass(header, this.headerCssClass)) {
|
||||
return;
|
||||
}
|
||||
|
||||
this.onBeforeActiveColumn(this, colIndex);
|
||||
|
||||
addClass(header, this.headerCssClass);
|
||||
|
||||
if (this.highlightColumn) {
|
||||
this.eachColumnCell(colIndex,
|
||||
(cell) => addClass(cell, this.cellCssClass));
|
||||
}
|
||||
|
||||
this.onAfterActiveColumn(this, colIndex);
|
||||
}
|
||||
|
||||
/**
|
||||
* Column cells iterator
|
||||
* TODO: make public and move into TableFilter if used elsewhere
|
||||
* @param {Number} colIndex
|
||||
* @param {Function} fn
|
||||
* @param {DOMElement} tbl
|
||||
* @private
|
||||
*/
|
||||
eachColumnCell(colIndex, fn = EMPTY_FN, tbl = this.tf.dom()) {
|
||||
// TODO: remove [].forEach when polyfill for PhanthomJs is available
|
||||
[].forEach.call(
|
||||
tbl.querySelectorAll(`tbody td:nth-child(${colIndex + 1})`), fn);
|
||||
}
|
||||
|
||||
/**
|
||||
* Remove feature
|
||||
*/
|
||||
destroy() {
|
||||
if (!this.initialized) {
|
||||
return;
|
||||
}
|
||||
|
||||
this.clearActiveColumns();
|
||||
this.emitter.off(['before-filtering'], () => this.clearActiveColumns());
|
||||
this.emitter.off(
|
||||
['cell-processed'],
|
||||
(tf, colIndex) => this.markActiveColumn(colIndex)
|
||||
);
|
||||
|
||||
/** @inherited */
|
||||
this.initialized = false;
|
||||
}
|
||||
}
|
|
@ -1,7 +1,8 @@
|
|||
import {Feature} from '../feature';
|
||||
import {createElm, elm, removeElm} from '../dom';
|
||||
import {isEmpty, isFn, EMPTY_FN} from '../types';
|
||||
import {isEmpty, EMPTY_FN} from '../types';
|
||||
import {NONE} from '../const';
|
||||
import {defaultsStr, defaultsFn} from '../settings';
|
||||
|
||||
/**
|
||||
* UI when filtering yields no matches
|
||||
|
@ -16,28 +17,28 @@ export class NoResults extends Feature {
|
|||
* @param {TableFilter} tf TableFilter instance
|
||||
*/
|
||||
constructor(tf) {
|
||||
super(tf, 'noResults');
|
||||
super(tf, NoResults);
|
||||
|
||||
//configuration object
|
||||
let f = this.config.no_results_message;
|
||||
let f = this.config.no_results_message || {};
|
||||
|
||||
/**
|
||||
* Text (accepts HTML)
|
||||
* @type {String}
|
||||
*/
|
||||
this.content = f.content || 'No results';
|
||||
this.content = defaultsStr(f.content, 'No results');
|
||||
|
||||
/**
|
||||
* Custom container DOM element
|
||||
* @type {DOMElement}
|
||||
*/
|
||||
this.customContainer = f.custom_container || null;
|
||||
this.customContainer = defaultsStr(f.custom_container, null);
|
||||
|
||||
/**
|
||||
* ID of custom container element
|
||||
* @type {String}
|
||||
*/
|
||||
this.customContainerId = f.custom_container_id || null;
|
||||
this.customContainerId = defaultsStr(f.custom_container_id, null);
|
||||
|
||||
/**
|
||||
* Indicates if UI is contained in a external element
|
||||
|
@ -51,7 +52,7 @@ export class NoResults extends Feature {
|
|||
* Css class assigned to container element
|
||||
* @type {String}
|
||||
*/
|
||||
this.cssClass = f.css_class || 'no-results';
|
||||
this.cssClass = defaultsStr(f.css_class, 'no-results');
|
||||
|
||||
/**
|
||||
* Stores container DOM element
|
||||
|
@ -63,29 +64,25 @@ export class NoResults extends Feature {
|
|||
* Callback fired before the message is displayed
|
||||
* @type {Function}
|
||||
*/
|
||||
this.onBeforeShow = isFn(f.on_before_show_msg) ?
|
||||
f.on_before_show_msg : EMPTY_FN;
|
||||
this.onBeforeShow = defaultsFn(f.on_before_show_msg, EMPTY_FN);
|
||||
|
||||
/**
|
||||
* Callback fired after the message is displayed
|
||||
* @type {Function}
|
||||
*/
|
||||
this.onAfterShow = isFn(f.on_after_show_msg) ?
|
||||
f.on_after_show_msg : EMPTY_FN;
|
||||
this.onAfterShow = defaultsFn(f.on_after_show_msg, EMPTY_FN);
|
||||
|
||||
/**
|
||||
* Callback fired before the message is hidden
|
||||
* @type {Function}
|
||||
*/
|
||||
this.onBeforeHide = isFn(f.on_before_hide_msg) ?
|
||||
f.on_before_hide_msg : EMPTY_FN;
|
||||
this.onBeforeHide = defaultsFn(f.on_before_hide_msg, EMPTY_FN);
|
||||
|
||||
/**
|
||||
* Callback fired after the message is hidden
|
||||
* @type {Function}
|
||||
*/
|
||||
this.onAfterHide = isFn(f.on_after_hide_msg) ?
|
||||
f.on_after_hide_msg : EMPTY_FN;
|
||||
this.onAfterHide = defaultsFn(f.on_after_hide_msg, EMPTY_FN);
|
||||
}
|
||||
|
||||
/**
|
||||
|
@ -97,7 +94,7 @@ export class NoResults extends Feature {
|
|||
}
|
||||
let tf = this.tf;
|
||||
let target = this.customContainer || elm(this.customContainerId) ||
|
||||
tf.tbl;
|
||||
tf.dom();
|
||||
|
||||
//container
|
||||
let cont = createElm('div');
|
||||
|
@ -113,14 +110,13 @@ export class NoResults extends Feature {
|
|||
this.cont = cont;
|
||||
|
||||
// subscribe to after-filtering event
|
||||
this.emitter.on(['after-filtering'], () => this.toggle());
|
||||
this.emitter.on(
|
||||
['initialized', 'after-filtering'],
|
||||
() => this.toggle()
|
||||
);
|
||||
|
||||
/**
|
||||
* @inherited
|
||||
*/
|
||||
/** @inherited */
|
||||
this.initialized = true;
|
||||
|
||||
this.hide();
|
||||
}
|
||||
|
||||
/**
|
||||
|
@ -174,16 +170,15 @@ export class NoResults extends Feature {
|
|||
let tf = this.tf;
|
||||
if (tf.gridLayout) {
|
||||
let gridLayout = tf.feature('gridLayout');
|
||||
this.cont.style.width = gridLayout.tblCont.clientWidth + 'px';
|
||||
this.cont.style.width = gridLayout.headTbl.clientWidth + 'px';
|
||||
} else {
|
||||
this.cont.style.width = (tf.tbl.tHead ? tf.tbl.tHead.clientWidth :
|
||||
tf.tbl.tBodies[0].clientWidth) + 'px';
|
||||
this.cont.style.width = (tf.dom().tHead ?
|
||||
tf.dom().tHead.clientWidth :
|
||||
tf.dom().tBodies[0].clientWidth) + 'px';
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Remove feature
|
||||
*/
|
||||
/** Remove feature */
|
||||
destroy() {
|
||||
if (!this.initialized) {
|
||||
return;
|
||||
|
|
|
@ -1,8 +1,12 @@
|
|||
import {Feature} from '../feature';
|
||||
import {createElm, createOpt, createText, elm, removeElm} from '../dom';
|
||||
import {isArray, isFn, isNull, EMPTY_FN} from '../types';
|
||||
import {addEvt, keyCode, removeEvt} from '../event';
|
||||
import {isArray, isNull, EMPTY_FN} from '../types';
|
||||
import {addEvt, removeEvt, isKeyPressed, bound} from '../event';
|
||||
import {INPUT, SELECT, NONE, ENTER_KEY} from '../const';
|
||||
import {
|
||||
defaultsStr, defaultsNb, defaultsBool, defaultsArr, defaultsFn
|
||||
} from '../settings';
|
||||
import {CENTER, RIGHT} from './toolbar';
|
||||
|
||||
/**
|
||||
* Paging UI component
|
||||
|
@ -17,65 +21,65 @@ export class Paging extends Feature {
|
|||
* @param {TableFilter} tf TableFilter instance
|
||||
*/
|
||||
constructor(tf) {
|
||||
super(tf, 'paging');
|
||||
super(tf, Paging);
|
||||
|
||||
// Configuration object
|
||||
var f = this.config;
|
||||
let f = this.config.paging || {};
|
||||
|
||||
/**
|
||||
* Css class for the paging buttons (previous, next, etc.)
|
||||
* @type {String}
|
||||
*/
|
||||
this.btnPageCssClass = f.paging_btn_css_class || 'pgInp';
|
||||
this.btnCssClass = defaultsStr(f.btn_css_class, 'pgInp');
|
||||
|
||||
/**
|
||||
/**
|
||||
* Main select DOM element
|
||||
* @type {DOMElement}
|
||||
*/
|
||||
this.pagingSlc = null;
|
||||
this.pageSlc = null;
|
||||
|
||||
/**
|
||||
* Results per page select DOM element
|
||||
* @type {DOMElement}
|
||||
*/
|
||||
this.resultsPerPageSlc = null;
|
||||
this.pageLengthSlc = null;
|
||||
|
||||
/**
|
||||
* ID of custom container element
|
||||
* @type {String}
|
||||
*/
|
||||
this.pagingTgtId = f.paging_target_id || null;
|
||||
this.tgtId = defaultsStr(f.target_id, null);
|
||||
|
||||
/**
|
||||
* Number of rows contained in a page
|
||||
* @type {Number}
|
||||
*/
|
||||
this.pagingLength = !isNaN(f.paging_length) ? f.paging_length : 10;
|
||||
this.pageLength = defaultsNb(f.length, 10);
|
||||
|
||||
/**
|
||||
* ID of custom container element for the results per page selector
|
||||
* @type {String}
|
||||
*/
|
||||
this.resultsPerPageTgtId = f.results_per_page_target_id || null;
|
||||
this.pageLengthTgtId = defaultsStr(f.results_per_page_target_id, null);
|
||||
|
||||
/**
|
||||
* Css class for the paging select element
|
||||
* @type {String}
|
||||
*/
|
||||
this.pgSlcCssClass = f.paging_slc_css_class || 'pgSlc';
|
||||
this.pgSlcCssClass = defaultsStr(f.slc_css_class, 'pgSlc');
|
||||
|
||||
/**
|
||||
* Css class for the paging input element
|
||||
* @type {String}
|
||||
*/
|
||||
this.pgInpCssClass = f.paging_inp_css_class || 'pgNbInp';
|
||||
this.pgInpCssClass = defaultsStr(f.inp_css_class, 'pgNbInp');
|
||||
|
||||
/**
|
||||
* Label and values for the results per page select, example of usage:
|
||||
* ['Records: ', [10,25,50,100]]
|
||||
* @type {Array}
|
||||
*/
|
||||
this.resultsPerPage = f.results_per_page || null;
|
||||
this.resultsPerPage = defaultsArr(f.results_per_page, null);
|
||||
|
||||
/**
|
||||
* Determines if results per page is configured
|
||||
|
@ -87,13 +91,14 @@ export class Paging extends Feature {
|
|||
* Css class for the results per page select
|
||||
* @type {String}
|
||||
*/
|
||||
this.resultsSlcCssClass = f.results_slc_css_class || 'rspg';
|
||||
this.resultsSlcCssClass = defaultsStr(f.results_slc_css_class, 'rspg');
|
||||
|
||||
/**
|
||||
* Css class for the label preceding results per page select
|
||||
* @type {String}
|
||||
*/
|
||||
this.resultsSpanCssClass = f.results_span_css_class || 'rspgSpan';
|
||||
this.resultsSpanCssClass = defaultsStr(f.results_span_css_class,
|
||||
'rspgSpan');
|
||||
|
||||
/**
|
||||
* Index of the first row of current page
|
||||
|
@ -120,105 +125,109 @@ export class Paging extends Feature {
|
|||
* Next page button text
|
||||
* @type {String}
|
||||
*/
|
||||
this.btnNextPageText = f.btn_next_page_text || '>';
|
||||
this.btnNextPageText = defaultsStr(f.btn_next_page_text, '>');
|
||||
|
||||
/**
|
||||
* Previous page button text
|
||||
* @type {String}
|
||||
*/
|
||||
this.btnPrevPageText = f.btn_prev_page_text || '<';
|
||||
this.btnPrevPageText = defaultsStr(f.btn_prev_page_text, '<');
|
||||
|
||||
/**
|
||||
* Last page button text
|
||||
* @type {String}
|
||||
*/
|
||||
this.btnLastPageText = f.btn_last_page_text || '>|';
|
||||
this.btnLastPageText = defaultsStr(f.btn_last_page_text, '>|');
|
||||
|
||||
/**
|
||||
* First page button text
|
||||
* @type {String}
|
||||
*/
|
||||
this.btnFirstPageText = f.btn_first_page_text || '|<';
|
||||
this.btnFirstPageText = defaultsStr(f.btn_first_page_text, '|<');
|
||||
|
||||
/**
|
||||
* Next page button HTML
|
||||
* @type {String}
|
||||
*/
|
||||
this.btnNextPageHtml = f.btn_next_page_html ||
|
||||
this.btnNextPageHtml = defaultsStr(f.btn_next_page_html,
|
||||
(!tf.enableIcons ? null :
|
||||
'<input type="button" value="" class="' + this.btnPageCssClass +
|
||||
' nextPage" title="Next page" />');
|
||||
'<input type="button" value="" class="' + this.btnCssClass +
|
||||
' nextPage" title="Next page" />'));
|
||||
|
||||
/**
|
||||
* Previous page button HTML
|
||||
* @type {String}
|
||||
*/
|
||||
this.btnPrevPageHtml = f.btn_prev_page_html ||
|
||||
this.btnPrevPageHtml = defaultsStr(f.btn_prev_page_html,
|
||||
(!tf.enableIcons ? null :
|
||||
'<input type="button" value="" class="' + this.btnPageCssClass +
|
||||
' previousPage" title="Previous page" />');
|
||||
'<input type="button" value="" class="' + this.btnCssClass +
|
||||
' previousPage" title="Previous page" />'));
|
||||
|
||||
/**
|
||||
* First page button HTML
|
||||
* @type {String}
|
||||
*/
|
||||
this.btnFirstPageHtml = f.btn_first_page_html ||
|
||||
this.btnFirstPageHtml = defaultsStr(f.btn_first_page_html,
|
||||
(!tf.enableIcons ? null :
|
||||
'<input type="button" value="" class="' + this.btnPageCssClass +
|
||||
' firstPage" title="First page" />');
|
||||
'<input type="button" value="" class="' + this.btnCssClass +
|
||||
' firstPage" title="First page" />'));
|
||||
|
||||
/**
|
||||
* Last page button HTML
|
||||
* @type {String}
|
||||
*/
|
||||
this.btnLastPageHtml = f.btn_last_page_html ||
|
||||
this.btnLastPageHtml = defaultsStr(f.btn_last_page_html,
|
||||
(!tf.enableIcons ? null :
|
||||
'<input type="button" value="" class="' + this.btnPageCssClass +
|
||||
' lastPage" title="Last page" />');
|
||||
'<input type="button" value="" class="' + this.btnCssClass +
|
||||
' lastPage" title="Last page" />'));
|
||||
|
||||
/**
|
||||
* Text preceeding page selector drop-down
|
||||
* @type {String}
|
||||
*/
|
||||
this.pageText = f.page_text || ' Page ';
|
||||
this.pageText = defaultsStr(f.page_text, ' Page ');
|
||||
|
||||
/**
|
||||
* Text after page selector drop-down
|
||||
* @type {String}
|
||||
*/
|
||||
this.ofText = f.of_text || ' of ';
|
||||
this.ofText = defaultsStr(f.of_text, ' of ');
|
||||
|
||||
/**
|
||||
* Css class for the span containing total number of pages
|
||||
* @type {String}
|
||||
*/
|
||||
this.nbPgSpanCssClass = f.nb_pages_css_class || 'nbpg';
|
||||
this.nbPgSpanCssClass = defaultsStr(f.nb_pages_css_class, 'nbpg');
|
||||
|
||||
/**
|
||||
* Determines if paging buttons are enabled (default: true)
|
||||
* @type {Boolean}
|
||||
*/
|
||||
this.hasPagingBtns = f.paging_btns === false ? false : true;
|
||||
this.hasBtns = defaultsBool(f.btns, true);
|
||||
|
||||
/**
|
||||
* Defines page selector type, two possible values: 'select', 'input'
|
||||
* @type {String}
|
||||
*/
|
||||
this.pageSelectorType = f.page_selector_type || SELECT;
|
||||
this.pageSelectorType = defaultsStr(f.page_selector_type, SELECT);
|
||||
|
||||
/**
|
||||
* Default position in toolbar ('left'|'center'|'right')
|
||||
* @type {String}
|
||||
*/
|
||||
this.toolbarPosition = defaultsStr(f.toolbar_position, CENTER);
|
||||
|
||||
/**
|
||||
* Callback fired before the page is changed
|
||||
* @type {Function}
|
||||
*/
|
||||
this.onBeforeChangePage = isFn(f.on_before_change_page) ?
|
||||
f.on_before_change_page : EMPTY_FN;
|
||||
this.onBeforeChangePage = defaultsFn(f.on_before_change_page, EMPTY_FN);
|
||||
|
||||
/**
|
||||
* Callback fired after the page is changed
|
||||
* @type {Function}
|
||||
*/
|
||||
this.onAfterChangePage = isFn(f.on_after_change_page) ?
|
||||
f.on_after_change_page : EMPTY_FN;
|
||||
this.onAfterChangePage = defaultsFn(f.on_after_change_page, EMPTY_FN);
|
||||
|
||||
/**
|
||||
* Label preciding results per page select
|
||||
|
@ -269,12 +278,12 @@ export class Paging extends Feature {
|
|||
*/
|
||||
this.pgAfter = null;
|
||||
|
||||
var start_row = tf.refRow;
|
||||
var nrows = tf.getRowsNb(true);
|
||||
let startRow = tf.refRow;
|
||||
let nrows = tf.getRowsNb(true);
|
||||
//calculates page nb
|
||||
this.nbPages = Math.ceil((nrows - start_row) / this.pagingLength);
|
||||
this.nbPages = Math.ceil((nrows - startRow) / this.pageLength);
|
||||
|
||||
var o = this;
|
||||
let o = this;
|
||||
/**
|
||||
* Paging DOM events handlers
|
||||
* @type {String}
|
||||
|
@ -283,21 +292,21 @@ export class Paging extends Feature {
|
|||
this.evt = {
|
||||
slcIndex() {
|
||||
return (o.pageSelectorType === SELECT) ?
|
||||
o.pagingSlc.options.selectedIndex :
|
||||
parseInt(o.pagingSlc.value, 10) - 1;
|
||||
o.pageSlc.options.selectedIndex :
|
||||
parseInt(o.pageSlc.value, 10) - 1;
|
||||
},
|
||||
nbOpts() {
|
||||
return (o.pageSelectorType === SELECT) ?
|
||||
parseInt(o.pagingSlc.options.length, 10) - 1 :
|
||||
parseInt(o.pageSlc.options.length, 10) - 1 :
|
||||
(o.nbPages - 1);
|
||||
},
|
||||
next() {
|
||||
var nextIndex = o.evt.slcIndex() < o.evt.nbOpts() ?
|
||||
let nextIndex = o.evt.slcIndex() < o.evt.nbOpts() ?
|
||||
o.evt.slcIndex() + 1 : 0;
|
||||
o.changePage(nextIndex);
|
||||
},
|
||||
prev() {
|
||||
var prevIndex = o.evt.slcIndex() > 0 ?
|
||||
let prevIndex = o.evt.slcIndex() > 0 ?
|
||||
o.evt.slcIndex() - 1 : o.evt.nbOpts();
|
||||
o.changePage(prevIndex);
|
||||
},
|
||||
|
@ -308,8 +317,7 @@ export class Paging extends Feature {
|
|||
o.changePage(0);
|
||||
},
|
||||
_detectKey(e) {
|
||||
var key = keyCode(e);
|
||||
if (key === ENTER_KEY) {
|
||||
if (isKeyPressed(e, [ENTER_KEY])) {
|
||||
if (tf.sorted) {
|
||||
tf.filter();
|
||||
o.changePage(o.evt.slcIndex());
|
||||
|
@ -331,27 +339,29 @@ export class Paging extends Feature {
|
|||
* Initialize DOM elements
|
||||
*/
|
||||
init() {
|
||||
var slcPages;
|
||||
var tf = this.tf;
|
||||
var evt = this.evt;
|
||||
let slcPages;
|
||||
let tf = this.tf;
|
||||
let evt = this.evt;
|
||||
|
||||
if (this.initialized) {
|
||||
return;
|
||||
}
|
||||
|
||||
this.emitter.emit('initializing-feature', this, !isNull(this.tgtId));
|
||||
|
||||
// Check resultsPerPage is in expected format and initialise the
|
||||
// results per page component
|
||||
if (this.hasResultsPerPage) {
|
||||
if (this.resultsPerPage.length < 2) {
|
||||
this.hasResultsPerPage = false;
|
||||
} else {
|
||||
this.pagingLength = this.resultsPerPage[1][0];
|
||||
this.pageLength = this.resultsPerPage[1][0];
|
||||
this.setResultsPerPage();
|
||||
}
|
||||
}
|
||||
|
||||
evt.slcPagesChange = (event) => {
|
||||
var slc = event.target;
|
||||
let slc = event.target;
|
||||
this.changePage(slc.selectedIndex);
|
||||
};
|
||||
|
||||
|
@ -370,20 +380,20 @@ export class Paging extends Feature {
|
|||
}
|
||||
|
||||
// btns containers
|
||||
var btnNextSpan = createElm('span');
|
||||
var btnPrevSpan = createElm('span');
|
||||
var btnLastSpan = createElm('span');
|
||||
var btnFirstSpan = createElm('span');
|
||||
let btnNextSpan = createElm('span');
|
||||
let btnPrevSpan = createElm('span');
|
||||
let btnLastSpan = createElm('span');
|
||||
let btnFirstSpan = createElm('span');
|
||||
|
||||
if (this.hasPagingBtns) {
|
||||
if (this.hasBtns) {
|
||||
// Next button
|
||||
if (!this.btnNextPageHtml) {
|
||||
var btnNext = createElm(INPUT,
|
||||
let btnNext = createElm(INPUT,
|
||||
['type', 'button'],
|
||||
['value', this.btnNextPageText],
|
||||
['title', 'Next']
|
||||
);
|
||||
btnNext.className = this.btnPageCssClass;
|
||||
btnNext.className = this.btnCssClass;
|
||||
addEvt(btnNext, 'click', evt.next);
|
||||
btnNextSpan.appendChild(btnNext);
|
||||
} else {
|
||||
|
@ -392,12 +402,12 @@ export class Paging extends Feature {
|
|||
}
|
||||
// Previous button
|
||||
if (!this.btnPrevPageHtml) {
|
||||
var btnPrev = createElm(INPUT,
|
||||
let btnPrev = createElm(INPUT,
|
||||
['type', 'button'],
|
||||
['value', this.btnPrevPageText],
|
||||
['title', 'Previous']
|
||||
);
|
||||
btnPrev.className = this.btnPageCssClass;
|
||||
btnPrev.className = this.btnCssClass;
|
||||
addEvt(btnPrev, 'click', evt.prev);
|
||||
btnPrevSpan.appendChild(btnPrev);
|
||||
} else {
|
||||
|
@ -406,12 +416,12 @@ export class Paging extends Feature {
|
|||
}
|
||||
// Last button
|
||||
if (!this.btnLastPageHtml) {
|
||||
var btnLast = createElm(INPUT,
|
||||
let btnLast = createElm(INPUT,
|
||||
['type', 'button'],
|
||||
['value', this.btnLastPageText],
|
||||
['title', 'Last']
|
||||
);
|
||||
btnLast.className = this.btnPageCssClass;
|
||||
btnLast.className = this.btnCssClass;
|
||||
addEvt(btnLast, 'click', evt.last);
|
||||
btnLastSpan.appendChild(btnLast);
|
||||
} else {
|
||||
|
@ -420,12 +430,12 @@ export class Paging extends Feature {
|
|||
}
|
||||
// First button
|
||||
if (!this.btnFirstPageHtml) {
|
||||
var btnFirst = createElm(INPUT,
|
||||
let btnFirst = createElm(INPUT,
|
||||
['type', 'button'],
|
||||
['value', this.btnFirstPageText],
|
||||
['title', 'First']
|
||||
);
|
||||
btnFirst.className = this.btnPageCssClass;
|
||||
btnFirst.className = this.btnCssClass;
|
||||
addEvt(btnFirst, 'click', evt.first);
|
||||
btnFirstSpan.appendChild(btnFirst);
|
||||
} else {
|
||||
|
@ -435,23 +445,22 @@ export class Paging extends Feature {
|
|||
}
|
||||
|
||||
// paging elements (buttons+drop-down list) are added to defined element
|
||||
if (!this.pagingTgtId) {
|
||||
tf.setToolbar();
|
||||
}
|
||||
var targetEl = !this.pagingTgtId ? tf.mDiv : elm(this.pagingTgtId);
|
||||
let targetEl = !this.tgtId ?
|
||||
tf.feature('toolbar').container(this.toolbarPosition) :
|
||||
elm(this.tgtId);
|
||||
targetEl.appendChild(btnFirstSpan);
|
||||
targetEl.appendChild(btnPrevSpan);
|
||||
|
||||
var pgBeforeSpan = createElm('span');
|
||||
let pgBeforeSpan = createElm('span');
|
||||
pgBeforeSpan.appendChild(createText(this.pageText));
|
||||
pgBeforeSpan.className = this.nbPgSpanCssClass;
|
||||
targetEl.appendChild(pgBeforeSpan);
|
||||
targetEl.appendChild(slcPages);
|
||||
var pgAfterSpan = createElm('span');
|
||||
let pgAfterSpan = createElm('span');
|
||||
pgAfterSpan.appendChild(createText(this.ofText));
|
||||
pgAfterSpan.className = this.nbPgSpanCssClass;
|
||||
targetEl.appendChild(pgAfterSpan);
|
||||
var pgSpan = createElm('span');
|
||||
let pgSpan = createElm('span');
|
||||
pgSpan.className = this.nbPgSpanCssClass;
|
||||
pgSpan.appendChild(createText(' ' + this.nbPages + ' '));
|
||||
targetEl.appendChild(pgSpan);
|
||||
|
@ -465,7 +474,7 @@ export class Paging extends Feature {
|
|||
this.pgCont = pgSpan;
|
||||
this.pgBefore = pgBeforeSpan;
|
||||
this.pgAfter = pgAfterSpan;
|
||||
this.pagingSlc = slcPages;
|
||||
this.pageSlc = slcPages;
|
||||
|
||||
this.setPagingInfo();
|
||||
|
||||
|
@ -474,14 +483,15 @@ export class Paging extends Feature {
|
|||
this.setPagingInfo(tf.validRowsIndex);
|
||||
}
|
||||
|
||||
this.emitter.on(['after-filtering'], () => this.resetPagingInfo());
|
||||
this.emitter.on(['change-page'],
|
||||
(tf, pageNumber) => this.setPage(pageNumber));
|
||||
this.emitter.on(['after-filtering'], bound(this.resetPagingInfo, this));
|
||||
this.emitter.on(['change-page'], bound(this.changePageHandler, this));
|
||||
this.emitter.on(['change-page-results'],
|
||||
(tf, pageLength) => this.changeResultsPerPage(pageLength));
|
||||
bound(this.changePageResultsHandler, this));
|
||||
|
||||
/** @inherited */
|
||||
this.initialized = true;
|
||||
|
||||
this.emitter.emit('feature-initialized', this);
|
||||
}
|
||||
|
||||
/**
|
||||
|
@ -489,15 +499,11 @@ export class Paging extends Feature {
|
|||
* @param {Boolean} filterTable Execute filtering once paging instanciated
|
||||
*/
|
||||
reset(filterTable = false) {
|
||||
var tf = this.tf;
|
||||
if (this.isEnabled()) {
|
||||
return;
|
||||
}
|
||||
this.enable();
|
||||
this.init();
|
||||
|
||||
if (filterTable) {
|
||||
tf.filter();
|
||||
this.tf.filter();
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -516,36 +522,38 @@ export class Paging extends Feature {
|
|||
* @param {Array} validRows Collection of valid rows
|
||||
*/
|
||||
setPagingInfo(validRows) {
|
||||
var tf = this.tf;
|
||||
var mdiv = !this.pagingTgtId ? tf.mDiv : elm(this.pagingTgtId);
|
||||
let tf = this.tf;
|
||||
let cont = !this.tgtId ?
|
||||
tf.feature('toolbar').container(this.toolbarPosition) :
|
||||
elm(this.tgtId);
|
||||
|
||||
//store valid rows indexes
|
||||
tf.validRowsIndex = validRows || tf.getValidRows(true);
|
||||
|
||||
//calculate nb of pages
|
||||
this.nbPages = Math.ceil(tf.validRowsIndex.length / this.pagingLength);
|
||||
this.nbPages = Math.ceil(tf.validRowsIndex.length / this.pageLength);
|
||||
//refresh page nb span
|
||||
this.pgCont.innerHTML = this.nbPages;
|
||||
//select clearing shortcut
|
||||
if (this.pageSelectorType === SELECT) {
|
||||
this.pagingSlc.innerHTML = '';
|
||||
this.pageSlc.innerHTML = '';
|
||||
}
|
||||
|
||||
if (this.nbPages > 0) {
|
||||
mdiv.style.visibility = 'visible';
|
||||
cont.style.visibility = 'visible';
|
||||
if (this.pageSelectorType === SELECT) {
|
||||
for (var z = 0; z < this.nbPages; z++) {
|
||||
var opt = createOpt(z + 1, z * this.pagingLength, false);
|
||||
this.pagingSlc.options[z] = opt;
|
||||
for (let z = 0; z < this.nbPages; z++) {
|
||||
let opt = createOpt(z + 1, z * this.pageLength, false);
|
||||
this.pageSlc.options[z] = opt;
|
||||
}
|
||||
} else {
|
||||
//input type
|
||||
this.pagingSlc.value = this.currentPageNb;
|
||||
this.pageSlc.value = this.currentPageNb;
|
||||
}
|
||||
|
||||
} else {
|
||||
/*** if no results paging select and buttons are hidden ***/
|
||||
mdiv.style.visibility = 'hidden';
|
||||
cont.style.visibility = 'hidden';
|
||||
}
|
||||
this.groupByPage(tf.validRowsIndex);
|
||||
}
|
||||
|
@ -555,10 +563,10 @@ export class Paging extends Feature {
|
|||
* @param {Array} validRows Collection of valid rows
|
||||
*/
|
||||
groupByPage(validRows) {
|
||||
var tf = this.tf;
|
||||
var rows = tf.tbl.rows;
|
||||
var startPagingRow = parseInt(this.startPagingRow, 10);
|
||||
var endPagingRow = startPagingRow + parseInt(this.pagingLength, 10);
|
||||
let tf = this.tf;
|
||||
let rows = tf.dom().rows;
|
||||
let startPagingRow = parseInt(this.startPagingRow, 10);
|
||||
let endPagingRow = startPagingRow + parseInt(this.pageLength, 10);
|
||||
|
||||
//store valid rows indexes
|
||||
if (validRows) {
|
||||
|
@ -566,11 +574,11 @@ export class Paging extends Feature {
|
|||
}
|
||||
|
||||
//this loop shows valid rows of current page
|
||||
for (var h = 0, len = tf.getValidRowsNb(true); h < len; h++) {
|
||||
var validRowIdx = tf.validRowsIndex[h];
|
||||
var r = rows[validRowIdx];
|
||||
var isRowValid = r.getAttribute('validRow');
|
||||
var rowDisplayed = false;
|
||||
for (let h = 0, len = tf.getValidRowsNb(true); h < len; h++) {
|
||||
let validRowIdx = tf.validRowsIndex[h];
|
||||
let r = rows[validRowIdx];
|
||||
let isRowValid = r.getAttribute('validRow');
|
||||
let rowDisplayed = false;
|
||||
|
||||
if (h >= startPagingRow && h < endPagingRow) {
|
||||
if (isNull(isRowValid) || Boolean(isRowValid === 'true')) {
|
||||
|
@ -601,11 +609,11 @@ export class Paging extends Feature {
|
|||
* 'previous', 'last', 'first' or page number as per param
|
||||
*/
|
||||
setPage(cmd) {
|
||||
var tf = this.tf;
|
||||
let tf = this.tf;
|
||||
if (!tf.isInitialized() || !this.isEnabled()) {
|
||||
return;
|
||||
}
|
||||
var btnEvt = this.evt,
|
||||
let btnEvt = this.evt,
|
||||
cmdtype = typeof cmd;
|
||||
if (cmdtype === 'string') {
|
||||
switch (cmd.toLowerCase()) {
|
||||
|
@ -635,10 +643,10 @@ export class Paging extends Feature {
|
|||
* Generates UI elements for the number of results per page drop-down
|
||||
*/
|
||||
setResultsPerPage() {
|
||||
var tf = this.tf;
|
||||
var evt = this.evt;
|
||||
let tf = this.tf;
|
||||
let evt = this.evt;
|
||||
|
||||
if (this.resultsPerPageSlc || !this.resultsPerPage) {
|
||||
if (this.pageLengthSlc || !this.resultsPerPage) {
|
||||
return;
|
||||
}
|
||||
|
||||
|
@ -647,22 +655,20 @@ export class Paging extends Feature {
|
|||
ev.target.blur();
|
||||
};
|
||||
|
||||
var slcR = createElm(SELECT);
|
||||
let slcR = createElm(SELECT);
|
||||
slcR.className = this.resultsSlcCssClass;
|
||||
var slcRText = this.resultsPerPage[0],
|
||||
let slcRText = this.resultsPerPage[0],
|
||||
slcROpts = this.resultsPerPage[1];
|
||||
var slcRSpan = createElm('span');
|
||||
let slcRSpan = createElm('span');
|
||||
slcRSpan.className = this.resultsSpanCssClass;
|
||||
|
||||
// results per page select is added to external element
|
||||
if (!this.resultsPerPageTgtId) {
|
||||
tf.setToolbar();
|
||||
}
|
||||
var targetEl = !this.resultsPerPageTgtId ?
|
||||
tf.rDiv : elm(this.resultsPerPageTgtId);
|
||||
let targetEl = !this.pageLengthTgtId ?
|
||||
tf.feature('toolbar').container(RIGHT) :
|
||||
elm(this.pageLengthTgtId);
|
||||
slcRSpan.appendChild(createText(slcRText));
|
||||
|
||||
var help = tf.feature('help');
|
||||
let help = tf.feature('help');
|
||||
if (help && help.btn) {
|
||||
help.btn.parentNode.insertBefore(slcRSpan, help.btn);
|
||||
help.btn.parentNode.insertBefore(slcR, help.btn);
|
||||
|
@ -671,31 +677,31 @@ export class Paging extends Feature {
|
|||
targetEl.appendChild(slcR);
|
||||
}
|
||||
|
||||
for (var r = 0; r < slcROpts.length; r++) {
|
||||
var currOpt = new Option(slcROpts[r], slcROpts[r], false, false);
|
||||
for (let r = 0; r < slcROpts.length; r++) {
|
||||
let currOpt = new Option(slcROpts[r], slcROpts[r], false, false);
|
||||
slcR.options[r] = currOpt;
|
||||
}
|
||||
addEvt(slcR, 'change', evt.slcResultsChange);
|
||||
this.slcResultsTxt = slcRSpan;
|
||||
this.resultsPerPageSlc = slcR;
|
||||
this.pageLengthSlc = slcR;
|
||||
}
|
||||
|
||||
/**
|
||||
* Remove number of results per page UI elements
|
||||
*/
|
||||
removeResultsPerPage() {
|
||||
var tf = this.tf;
|
||||
if (!tf.isInitialized() || !this.resultsPerPageSlc ||
|
||||
let tf = this.tf;
|
||||
if (!tf.isInitialized() || !this.pageLengthSlc ||
|
||||
!this.resultsPerPage) {
|
||||
return;
|
||||
}
|
||||
if (this.resultsPerPageSlc) {
|
||||
removeElm(this.resultsPerPageSlc);
|
||||
if (this.pageLengthSlc) {
|
||||
removeElm(this.pageLengthSlc);
|
||||
}
|
||||
if (this.slcResultsTxt) {
|
||||
removeElm(this.slcResultsTxt);
|
||||
}
|
||||
this.resultsPerPageSlc = null;
|
||||
this.pageLengthSlc = null;
|
||||
this.slcResultsTxt = null;
|
||||
}
|
||||
|
||||
|
@ -704,7 +710,7 @@ export class Paging extends Feature {
|
|||
* @param {Number} index Index of the page (0-n)
|
||||
*/
|
||||
changePage(index) {
|
||||
var tf = this.tf;
|
||||
let tf = this.tf;
|
||||
|
||||
if (!this.isEnabled()) {
|
||||
return;
|
||||
|
@ -714,20 +720,20 @@ export class Paging extends Feature {
|
|||
|
||||
if (index === null) {
|
||||
index = this.pageSelectorType === SELECT ?
|
||||
this.pagingSlc.options.selectedIndex : this.pagingSlc.value - 1;
|
||||
this.pageSlc.options.selectedIndex : this.pageSlc.value - 1;
|
||||
}
|
||||
if (index >= 0 && index <= (this.nbPages - 1)) {
|
||||
this.onBeforeChangePage(this, (index + 1));
|
||||
|
||||
this.currentPageNb = parseInt(index, 10) + 1;
|
||||
if (this.pageSelectorType === SELECT) {
|
||||
this.pagingSlc.options[index].selected = true;
|
||||
this.pageSlc.options[index].selected = true;
|
||||
} else {
|
||||
this.pagingSlc.value = this.currentPageNb;
|
||||
this.pageSlc.value = this.currentPageNb;
|
||||
}
|
||||
|
||||
this.startPagingRow = (this.pageSelectorType === SELECT) ?
|
||||
this.pagingSlc.value : (index * this.pagingLength);
|
||||
this.pageSlc.value : (index * this.pageLength);
|
||||
|
||||
this.groupByPage();
|
||||
|
||||
|
@ -746,7 +752,7 @@ export class Paging extends Feature {
|
|||
return;
|
||||
}
|
||||
|
||||
this.resultsPerPageSlc.value = val;
|
||||
this.pageLengthSlc.value = val;
|
||||
this.onChangeResultsPerPage();
|
||||
}
|
||||
|
||||
|
@ -754,49 +760,51 @@ export class Paging extends Feature {
|
|||
* Change rows according to page results drop-down
|
||||
*/
|
||||
onChangeResultsPerPage() {
|
||||
var tf = this.tf;
|
||||
let tf = this.tf;
|
||||
|
||||
if (!this.isEnabled()) {
|
||||
if (!this.isEnabled() || tf.getValidRowsNb() === 0) {
|
||||
return;
|
||||
}
|
||||
|
||||
this.emitter.emit('before-page-length-change', tf);
|
||||
let {
|
||||
pageLengthSlc: slcR, pageSelectorType, pageSlc, emitter
|
||||
} = this;
|
||||
|
||||
var slcR = this.resultsPerPageSlc;
|
||||
var slcIndex = slcR.selectedIndex;
|
||||
var slcPagesSelIndex = (this.pageSelectorType === SELECT) ?
|
||||
this.pagingSlc.selectedIndex :
|
||||
parseInt(this.pagingSlc.value - 1, 10);
|
||||
this.pagingLength = parseInt(slcR.options[slcIndex].value, 10);
|
||||
this.startPagingRow = this.pagingLength * slcPagesSelIndex;
|
||||
emitter.emit('before-page-length-change', tf);
|
||||
|
||||
if (!isNaN(this.pagingLength)) {
|
||||
let slcIndex = slcR.selectedIndex;
|
||||
let slcPagesSelIndex = (pageSelectorType === SELECT) ?
|
||||
pageSlc.selectedIndex : parseInt(pageSlc.value - 1, 10);
|
||||
this.pageLength = parseInt(slcR.options[slcIndex].value, 10);
|
||||
this.startPagingRow = this.pageLength * slcPagesSelIndex;
|
||||
|
||||
if (!isNaN(this.pageLength)) {
|
||||
if (this.startPagingRow >= tf.nbFilterableRows) {
|
||||
this.startPagingRow = (tf.nbFilterableRows - this.pagingLength);
|
||||
this.startPagingRow = (tf.nbFilterableRows - this.pageLength);
|
||||
}
|
||||
this.setPagingInfo();
|
||||
|
||||
if (this.pageSelectorType === SELECT) {
|
||||
var slcIdx =
|
||||
(this.pagingSlc.options.length - 1 <= slcPagesSelIndex) ?
|
||||
(this.pagingSlc.options.length - 1) : slcPagesSelIndex;
|
||||
this.pagingSlc.options[slcIdx].selected = true;
|
||||
if (pageSelectorType === SELECT) {
|
||||
let slcIdx = (pageSlc.options.length - 1 <= slcPagesSelIndex) ?
|
||||
(pageSlc.options.length - 1) :
|
||||
slcPagesSelIndex;
|
||||
pageSlc.options[slcIdx].selected = true;
|
||||
}
|
||||
}
|
||||
|
||||
this.emitter.emit('after-page-length-change', tf, this.pagingLength);
|
||||
emitter.emit('after-page-length-change', tf, this.pageLength);
|
||||
}
|
||||
|
||||
/**
|
||||
* Re-set page nb at page re-load
|
||||
*/
|
||||
resetPage() {
|
||||
var tf = this.tf;
|
||||
let tf = this.tf;
|
||||
if (!this.isEnabled()) {
|
||||
return;
|
||||
}
|
||||
this.emitter.emit('before-reset-page', tf);
|
||||
var pgNb = tf.feature('store').getPageNb();
|
||||
let pgNb = tf.feature('store').getPageNb();
|
||||
if (pgNb !== '') {
|
||||
this.changePage((pgNb - 1));
|
||||
}
|
||||
|
@ -807,20 +815,30 @@ export class Paging extends Feature {
|
|||
* Re-set page length value at page re-load
|
||||
*/
|
||||
resetPageLength() {
|
||||
var tf = this.tf;
|
||||
let tf = this.tf;
|
||||
if (!this.isEnabled()) {
|
||||
return;
|
||||
}
|
||||
this.emitter.emit('before-reset-page-length', tf);
|
||||
var pglenIndex = tf.feature('store').getPageLength();
|
||||
let pglenIndex = tf.feature('store').getPageLength();
|
||||
|
||||
if (pglenIndex !== '') {
|
||||
this.resultsPerPageSlc.options[pglenIndex].selected = true;
|
||||
this.pageLengthSlc.options[pglenIndex].selected = true;
|
||||
this.changeResultsPerPage();
|
||||
}
|
||||
this.emitter.emit('after-reset-page-length', tf, pglenIndex);
|
||||
}
|
||||
|
||||
/** @private */
|
||||
changePageHandler(tf, pageNumber) {
|
||||
this.setPage(pageNumber);
|
||||
}
|
||||
|
||||
/** @private */
|
||||
changePageResultsHandler(tf, pageLength) {
|
||||
this.changeResultsPerPage(pageLength);
|
||||
}
|
||||
|
||||
/**
|
||||
* Remove paging feature
|
||||
*/
|
||||
|
@ -829,16 +847,16 @@ export class Paging extends Feature {
|
|||
return;
|
||||
}
|
||||
|
||||
var evt = this.evt;
|
||||
let evt = this.evt;
|
||||
|
||||
if (this.pagingSlc) {
|
||||
if (this.pageSlc) {
|
||||
if (this.pageSelectorType === SELECT) {
|
||||
removeEvt(this.pagingSlc, 'change', evt.slcPagesChange);
|
||||
removeEvt(this.pageSlc, 'change', evt.slcPagesChange);
|
||||
}
|
||||
else if (this.pageSelectorType === INPUT) {
|
||||
removeEvt(this.pagingSlc, 'keypress', evt._detectKey);
|
||||
removeEvt(this.pageSlc, 'keypress', evt._detectKey);
|
||||
}
|
||||
removeElm(this.pagingSlc);
|
||||
removeElm(this.pageSlc);
|
||||
}
|
||||
|
||||
if (this.btnNextCont) {
|
||||
|
@ -884,15 +902,15 @@ export class Paging extends Feature {
|
|||
this.removeResultsPerPage();
|
||||
}
|
||||
|
||||
this.emitter.off(['after-filtering'], () => this.resetPagingInfo());
|
||||
this.emitter.off(['change-page'],
|
||||
(tf, pageNumber) => this.setPage(pageNumber));
|
||||
this.emitter.off(['after-filtering'],
|
||||
bound(this.resetPagingInfo, this));
|
||||
this.emitter.off(['change-page'], bound(this.changePageHandler, this));
|
||||
this.emitter.off(['change-page-results'],
|
||||
(tf, pageLength) => this.changeResultsPerPage(pageLength));
|
||||
bound(this.changePageResultsHandler, this));
|
||||
|
||||
this.pagingSlc = null;
|
||||
this.pageSlc = null;
|
||||
this.nbPages = 0;
|
||||
this.disable();
|
||||
|
||||
this.initialized = false;
|
||||
}
|
||||
}
|
||||
|
|
|
@ -1,9 +1,10 @@
|
|||
import {Feature} from '../feature';
|
||||
import {isFn, isUndef, EMPTY_FN} from '../types';
|
||||
import {isUndef, EMPTY_FN} from '../types';
|
||||
import {createElm, removeElm} from '../dom';
|
||||
import {addEvt, cancelEvt, stopEvt, targetEvt, removeEvt} from '../event';
|
||||
import {INPUT, NONE, CHECKLIST, MULTIPLE} from '../const';
|
||||
import {root} from '../root';
|
||||
import {defaultsStr, defaultsBool, defaultsArr, defaultsFn} from '../settings';
|
||||
|
||||
/**
|
||||
* Pop-up filter component
|
||||
|
@ -18,84 +19,81 @@ export class PopupFilter extends Feature {
|
|||
* @param {TableFilter} tf TableFilter instance
|
||||
*/
|
||||
constructor(tf) {
|
||||
super(tf, 'popupFilters');
|
||||
super(tf, PopupFilter);
|
||||
|
||||
// Configuration object
|
||||
let f = this.config;
|
||||
|
||||
// Enable external filters
|
||||
tf.isExternalFlt = true;
|
||||
tf.externalFltTgtIds = [];
|
||||
let f = this.config.popup_filters || {};
|
||||
|
||||
/**
|
||||
* Close active popup filter upon filtering, enabled by default
|
||||
* @type {Boolean}
|
||||
*/
|
||||
this.closeOnFiltering = f.popup_filters_close_on_filtering === false ?
|
||||
false : true;
|
||||
this.closeOnFiltering = defaultsBool(f.close_on_filtering, true);
|
||||
|
||||
/**
|
||||
* Filter icon path
|
||||
* @type {String}
|
||||
*/
|
||||
this.iconPath = f.popup_filters_image ||
|
||||
tf.themesPath + 'icn_filter.gif';
|
||||
this.iconPath = defaultsStr(f.image, tf.themesPath + 'icn_filter.gif');
|
||||
|
||||
/**
|
||||
* Active filter icon path
|
||||
* @type {string}
|
||||
*/
|
||||
this.activeIconPath = f.popup_filters_image_active ||
|
||||
tf.themesPath + 'icn_filterActive.gif';
|
||||
this.activeIconPath = defaultsStr(f.image_active,
|
||||
tf.themesPath + 'icn_filterActive.gif');
|
||||
|
||||
/**
|
||||
* HTML for the filter icon
|
||||
* @type {string}
|
||||
*/
|
||||
this.iconHtml = f.popup_filters_image_html ||
|
||||
'<img src="' + this.iconPath + '" alt="Column filter" />';
|
||||
this.iconHtml = defaultsStr(f.image_html,
|
||||
'<img src="' + this.iconPath + '" alt="Column filter" />');
|
||||
|
||||
/**
|
||||
* Css class assigned to the popup container element
|
||||
* @type {String}
|
||||
*/
|
||||
this.placeholderCssClass = defaultsStr(f.placeholder_css_class,
|
||||
'popUpPlaceholder');
|
||||
|
||||
/**
|
||||
* Css class assigned to filter container element
|
||||
* @type {String}
|
||||
*/
|
||||
this.containerCssClass = f.popup_div_css_class || 'popUpFilter';
|
||||
this.containerCssClass = defaultsStr(f.div_css_class, 'popUpFilter');
|
||||
|
||||
/**
|
||||
* Ensure filter's container element width matches column width, enabled
|
||||
* by default
|
||||
* @type {Boolean}
|
||||
*/
|
||||
this.adjustToContainer =
|
||||
f.popup_filters_adjust_to_container === false ? false : true;
|
||||
this.adjustToContainer = defaultsBool(f.adjust_to_container, true);
|
||||
|
||||
/**
|
||||
* Callback fired before a popup filter is opened
|
||||
* @type {Function}
|
||||
*/
|
||||
this.onBeforeOpen = isFn(f.on_before_popup_filter_open) ?
|
||||
f.on_before_popup_filter_open : EMPTY_FN;
|
||||
this.onBeforeOpen = defaultsFn(f.on_before_popup_filter_open, EMPTY_FN);
|
||||
|
||||
/**
|
||||
* Callback fired after a popup filter is opened
|
||||
* @type {Function}
|
||||
*/
|
||||
this.onAfterOpen = isFn(f.on_after_popup_filter_open) ?
|
||||
f.on_after_popup_filter_open : EMPTY_FN;
|
||||
this.onAfterOpen = defaultsFn(f.on_after_popup_filter_open, EMPTY_FN);
|
||||
|
||||
/**
|
||||
* Callback fired before a popup filter is closed
|
||||
* @type {Function}
|
||||
*/
|
||||
this.onBeforeClose = isFn(f.on_before_popup_filter_close) ?
|
||||
f.on_before_popup_filter_close : EMPTY_FN;
|
||||
this.onBeforeClose = defaultsFn(f.on_before_popup_filter_close,
|
||||
EMPTY_FN);
|
||||
|
||||
/**
|
||||
* Callback fired after a popup filter is closed
|
||||
* @type {Function}
|
||||
*/
|
||||
this.onAfterClose = isFn(f.on_after_popup_filter_close) ?
|
||||
f.on_after_popup_filter_close : EMPTY_FN;
|
||||
this.onAfterClose = defaultsFn(f.on_after_popup_filter_close, EMPTY_FN);
|
||||
|
||||
/**
|
||||
* Collection of filters spans
|
||||
|
@ -123,7 +121,7 @@ export class PopupFilter extends Feature {
|
|||
* @type {Array}
|
||||
* @private
|
||||
*/
|
||||
this.fltElms = this.filtersCache || [];
|
||||
this.fltElms = defaultsArr(this.filtersCache, []);
|
||||
|
||||
/**
|
||||
* Prefix for pop-up filter container ID
|
||||
|
@ -198,6 +196,12 @@ export class PopupFilter extends Feature {
|
|||
|
||||
let tf = this.tf;
|
||||
|
||||
// Enable external filters
|
||||
tf.externalFltIds = [''];
|
||||
|
||||
// Override filters row index supplied by configuration
|
||||
tf.filtersRowIndex = 0;
|
||||
|
||||
// Override headers row index if no grouped headers
|
||||
// TODO: Because of the filters row generation, headers row index needs
|
||||
// adjusting: prevent useless row generation
|
||||
|
@ -246,18 +250,19 @@ export class PopupFilter extends Feature {
|
|||
// adjusting: prevent useless row generation
|
||||
tf.headersRow++;
|
||||
|
||||
for (let i = 0; i < tf.nbCells; i++) {
|
||||
if (tf.getFilterType(i) === NONE) {
|
||||
continue;
|
||||
}
|
||||
let icon = createElm('span', ['ci', i]);
|
||||
icon.innerHTML = this.iconHtml;
|
||||
let header = tf.getHeaderElement(i);
|
||||
header.appendChild(icon);
|
||||
addEvt(icon, 'click', (evt) => this.onClick(evt));
|
||||
this.fltSpans[i] = icon;
|
||||
this.fltIcons[i] = icon.firstChild;
|
||||
}
|
||||
tf.eachCol(
|
||||
(i) => {
|
||||
let icon = createElm('span', ['ci', i]);
|
||||
icon.innerHTML = this.iconHtml;
|
||||
let header = tf.getHeaderElement(i);
|
||||
header.appendChild(icon);
|
||||
addEvt(icon, 'click', (evt) => this.onClick(evt));
|
||||
this.fltSpans[i] = icon;
|
||||
this.fltIcons[i] = icon.firstChild;
|
||||
},
|
||||
// continue condition function
|
||||
(i) => tf.getFilterType(i) === NONE
|
||||
);
|
||||
}
|
||||
|
||||
/**
|
||||
|
@ -277,12 +282,14 @@ export class PopupFilter extends Feature {
|
|||
build(colIndex, div) {
|
||||
let tf = this.tf;
|
||||
let contId = `${this.prfxDiv}${tf.id}_${colIndex}`;
|
||||
let cont = div || createElm('div', ['id', contId]);
|
||||
cont.className = this.containerCssClass;
|
||||
tf.externalFltTgtIds.push(cont.id);
|
||||
let placeholder = createElm('div', ['class', this.placeholderCssClass]);
|
||||
let cont = div ||
|
||||
createElm('div', ['id', contId], ['class', this.containerCssClass]);
|
||||
tf.externalFltIds[colIndex] = cont.id;
|
||||
placeholder.appendChild(cont);
|
||||
|
||||
let header = tf.getHeaderElement(colIndex);
|
||||
header.insertBefore(cont, header.firstChild);
|
||||
header.insertBefore(placeholder, header.firstChild);
|
||||
addEvt(cont, 'click', (evt) => stopEvt(evt));
|
||||
this.fltElms[colIndex] = cont;
|
||||
}
|
||||
|
@ -364,7 +371,7 @@ export class PopupFilter extends Feature {
|
|||
if (i === exceptIdx) {
|
||||
continue;
|
||||
}
|
||||
let fltType = tf.getFilterType(i);
|
||||
let fltType = this.tf.getFilterType(i);
|
||||
let isMultipleFilter =
|
||||
(fltType === CHECKLIST || fltType === MULTIPLE);
|
||||
|
||||
|
@ -408,6 +415,7 @@ export class PopupFilter extends Feature {
|
|||
this.filtersCache = [];
|
||||
for (let i = 0; i < this.fltElms.length; i++) {
|
||||
let container = this.fltElms[i],
|
||||
placeholder = container.parentNode,
|
||||
icon = this.fltSpans[i],
|
||||
iconImg = this.fltIcons[i];
|
||||
if (container) {
|
||||
|
@ -415,6 +423,10 @@ export class PopupFilter extends Feature {
|
|||
this.filtersCache[i] = container;
|
||||
}
|
||||
container = null;
|
||||
if (placeholder) {
|
||||
removeElm(placeholder);
|
||||
}
|
||||
placeholder = null;
|
||||
if (icon) {
|
||||
removeElm(icon);
|
||||
}
|
||||
|
@ -429,7 +441,7 @@ export class PopupFilter extends Feature {
|
|||
this.fltIcons = [];
|
||||
|
||||
// TODO: expose an API to handle external filter IDs
|
||||
tf.externalFltTgtIds = [];
|
||||
this.tf.externalFltIds = [];
|
||||
|
||||
// unsubscribe to events
|
||||
this.emitter.off(['before-filtering'], () => this.setIconsState());
|
||||
|
@ -444,3 +456,6 @@ export class PopupFilter extends Feature {
|
|||
}
|
||||
|
||||
}
|
||||
|
||||
// TODO: remove as soon as feature name is fixed
|
||||
PopupFilter.meta = {altName: 'popupFilters'};
|
||||
|
|
|
@ -1,6 +1,8 @@
|
|||
import {Feature} from '../feature';
|
||||
import {createElm, createText, elm, removeElm} from '../dom';
|
||||
import {isFn, EMPTY_FN} from '../types';
|
||||
import {EMPTY_FN, isNull} from '../types';
|
||||
import {defaultsStr, defaultsFn} from '../settings';
|
||||
import {LEFT} from './toolbar';
|
||||
|
||||
/**
|
||||
* Rows counter UI component
|
||||
|
@ -15,16 +17,16 @@ export class RowsCounter extends Feature {
|
|||
* @param {TableFilter} tf TableFilter instance
|
||||
*/
|
||||
constructor(tf) {
|
||||
super(tf, 'rowsCounter');
|
||||
super(tf, RowsCounter);
|
||||
|
||||
// TableFilter configuration
|
||||
let f = this.config;
|
||||
let f = this.config.rows_counter || {};
|
||||
|
||||
/**
|
||||
* ID of custom container element
|
||||
* @type {String}
|
||||
*/
|
||||
this.targetId = f.rows_counter_target_id || null;
|
||||
this.targetId = defaultsStr(f.target_id, null);
|
||||
|
||||
/**
|
||||
* Container DOM element
|
||||
|
@ -44,14 +46,14 @@ export class RowsCounter extends Feature {
|
|||
* Text preceding the total number of rows
|
||||
* @type {String}
|
||||
*/
|
||||
this.text = f.rows_counter_text || 'Rows: ';
|
||||
this.text = defaultsStr(f.text, 'Rows: ');
|
||||
|
||||
/**
|
||||
* Separator symbol appearing between the first and last visible rows of
|
||||
* current page when paging is enabled. ie: Rows: 31-40 / 70
|
||||
* @type {String}
|
||||
*/
|
||||
this.fromToTextSeparator = f.from_to_text_separator || '-';
|
||||
this.fromToTextSeparator = defaultsStr(f.separator, '-');
|
||||
|
||||
/**
|
||||
* Separator symbol appearing between the first and last visible rows of
|
||||
|
@ -59,27 +61,33 @@ export class RowsCounter extends Feature {
|
|||
* enabled. ie: Rows: 31-40 / 70
|
||||
* @type {String}
|
||||
*/
|
||||
this.overText = f.over_text || ' / ';
|
||||
this.overText = defaultsStr(f.over_text, ' / ');
|
||||
|
||||
/**
|
||||
* Css class for container element
|
||||
* @type {String}
|
||||
*/
|
||||
this.cssClass = f.tot_rows_css_class || 'tot';
|
||||
this.cssClass = defaultsStr(f.css_class, 'tot');
|
||||
|
||||
/**
|
||||
* Default position in toolbar ('left'|'center'|'right')
|
||||
* @type {String}
|
||||
*/
|
||||
this.toolbarPosition = defaultsStr(f.toolbar_position, LEFT);
|
||||
|
||||
/**
|
||||
* Callback fired before the counter is refreshed
|
||||
* @type {Function}
|
||||
*/
|
||||
this.onBeforeRefreshCounter = isFn(f.on_before_refresh_counter) ?
|
||||
f.on_before_refresh_counter : EMPTY_FN;
|
||||
this.onBeforeRefreshCounter = defaultsFn(f.on_before_refresh_counter,
|
||||
EMPTY_FN);
|
||||
|
||||
/**
|
||||
* Callback fired after the counter is refreshed
|
||||
* @type {Function}
|
||||
*/
|
||||
this.onAfterRefreshCounter = isFn(f.on_after_refresh_counter) ?
|
||||
f.on_after_refresh_counter : EMPTY_FN;
|
||||
this.onAfterRefreshCounter = defaultsFn(f.on_after_refresh_counter,
|
||||
EMPTY_FN);
|
||||
}
|
||||
|
||||
/**
|
||||
|
@ -90,6 +98,8 @@ export class RowsCounter extends Feature {
|
|||
return;
|
||||
}
|
||||
|
||||
this.emitter.emit('initializing-feature', this, !isNull(this.targetId));
|
||||
|
||||
let tf = this.tf;
|
||||
|
||||
//rows counter container
|
||||
|
@ -101,18 +111,16 @@ export class RowsCounter extends Feature {
|
|||
countText.appendChild(createText(this.text));
|
||||
|
||||
// counter is added to defined element
|
||||
if (!this.targetId) {
|
||||
tf.setToolbar();
|
||||
}
|
||||
let targetEl = !this.targetId ? tf.lDiv : elm(this.targetId);
|
||||
let targetEl = !this.targetId ?
|
||||
tf.feature('toolbar').container(this.toolbarPosition) :
|
||||
elm(this.targetId);
|
||||
|
||||
//default container: 'lDiv'
|
||||
if (!this.targetId) {
|
||||
countDiv.appendChild(countText);
|
||||
countDiv.appendChild(countSpan);
|
||||
targetEl.appendChild(countDiv);
|
||||
}
|
||||
else {
|
||||
} else {
|
||||
//custom container, no need to append statusDiv
|
||||
targetEl.appendChild(countText);
|
||||
targetEl.appendChild(countSpan);
|
||||
|
@ -128,12 +136,13 @@ export class RowsCounter extends Feature {
|
|||
/** @inherited */
|
||||
this.initialized = true;
|
||||
this.refresh();
|
||||
|
||||
this.emitter.emit('feature-initialized', this);
|
||||
}
|
||||
|
||||
/**
|
||||
* Refreshes the rows counter
|
||||
* @param {Number} p Optional parameter the total number of rows to display
|
||||
* @returns
|
||||
*/
|
||||
refresh(p) {
|
||||
if (!this.initialized || !this.isEnabled()) {
|
||||
|
@ -154,16 +163,17 @@ export class RowsCounter extends Feature {
|
|||
} else {
|
||||
let paging = tf.feature('paging');
|
||||
if (paging) {
|
||||
let nbValidRows = tf.getValidRowsNb();
|
||||
//paging start row
|
||||
let pagingStartRow = parseInt(paging.startPagingRow, 10) +
|
||||
((tf.getValidRowsNb() > 0) ? 1 : 0);
|
||||
((nbValidRows > 0) ? 1 : 0);
|
||||
let pagingEndRow =
|
||||
(pagingStartRow + paging.pagingLength) - 1 <=
|
||||
tf.getValidRowsNb() ?
|
||||
pagingStartRow + paging.pagingLength - 1 :
|
||||
tf.getValidRowsNb();
|
||||
(pagingStartRow + paging.pageLength) - 1 <=
|
||||
nbValidRows ?
|
||||
pagingStartRow + paging.pageLength - 1 :
|
||||
nbValidRows;
|
||||
totTxt = pagingStartRow + this.fromToTextSeparator +
|
||||
pagingEndRow + this.overText + tf.getValidRowsNb();
|
||||
pagingEndRow + this.overText + nbValidRows;
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -3,6 +3,7 @@ import {Hash} from './hash';
|
|||
import {Storage} from './storage';
|
||||
import {isEmpty} from '../string';
|
||||
import {isArray, isNull, isString, isUndef} from '../types';
|
||||
import {defaultsBool, defaultsNb} from '../settings';
|
||||
|
||||
/**
|
||||
* Features state object persistable with localStorage, cookie or URL hash
|
||||
|
@ -18,9 +19,9 @@ export class State extends Feature {
|
|||
* @param {TableFilter} tf TableFilter instance
|
||||
*/
|
||||
constructor(tf) {
|
||||
super(tf, 'state');
|
||||
super(tf, State);
|
||||
|
||||
let cfg = this.config.state;
|
||||
let cfg = this.config.state || {};
|
||||
|
||||
/**
|
||||
* Determines whether state is persisted with URL hash
|
||||
|
@ -47,7 +48,7 @@ export class State extends Feature {
|
|||
* Persist filters values, enabled by default
|
||||
* @type {Boolean}
|
||||
*/
|
||||
this.persistFilters = cfg.filters === false ? false : true;
|
||||
this.persistFilters = defaultsBool(cfg.filters, true);
|
||||
|
||||
/**
|
||||
* Persist current page number when paging is enabled
|
||||
|
@ -83,8 +84,8 @@ export class State extends Feature {
|
|||
* Cookie duration in hours
|
||||
* @type {Boolean}
|
||||
*/
|
||||
this.cookieDuration = !isNaN(cfg.cookie_duration) ?
|
||||
parseInt(cfg.cookie_duration, 10) : 87600;
|
||||
this.cookieDuration = defaultsNb(parseInt(cfg.cookie_duration, 10),
|
||||
87600);
|
||||
|
||||
/**
|
||||
* Enable Storage if localStorage or cookie is required
|
||||
|
@ -212,9 +213,7 @@ export class State extends Feature {
|
|||
this.storage.init();
|
||||
}
|
||||
|
||||
/**
|
||||
* @inherited
|
||||
*/
|
||||
/** @inherited */
|
||||
this.initialized = true;
|
||||
}
|
||||
|
||||
|
@ -366,6 +365,7 @@ export class State extends Feature {
|
|||
*/
|
||||
override(state) {
|
||||
this.state = state;
|
||||
this.emitter.emit('state-changed', this.tf, state);
|
||||
}
|
||||
|
||||
/**
|
||||
|
@ -421,6 +421,10 @@ export class State extends Feature {
|
|||
let state = this.state;
|
||||
let tf = this.tf;
|
||||
|
||||
// clear all filters
|
||||
// TODO: use tf.clearFilters() once it allows to not filter the table
|
||||
tf.eachCol((colIdx) => tf.setFilterValue(colIdx, ''));
|
||||
|
||||
Object.keys(state).forEach((key) => {
|
||||
if (key.indexOf(this.prfxCol) !== -1) {
|
||||
let colIdx = parseInt(key.replace(this.prfxCol, ''), 10);
|
||||
|
|
|
@ -1,7 +1,9 @@
|
|||
import {Feature} from '../feature';
|
||||
import {root} from '../root';
|
||||
import {createElm, createText, elm, removeElm} from '../dom';
|
||||
import {isFn, EMPTY_FN} from '../types';
|
||||
import {EMPTY_FN, isNull} from '../types';
|
||||
import {defaultsStr, defaultsFn} from '../settings';
|
||||
import {LEFT} from './toolbar';
|
||||
|
||||
const EVENTS = [
|
||||
'after-filtering',
|
||||
|
@ -28,16 +30,16 @@ export class StatusBar extends Feature {
|
|||
* @param {TableFilter} tf TableFilter instance
|
||||
*/
|
||||
constructor(tf) {
|
||||
super(tf, 'statusBar');
|
||||
super(tf, StatusBar);
|
||||
|
||||
// Configuration object
|
||||
let f = this.config;
|
||||
let f = this.config.status_bar || {};
|
||||
|
||||
/**
|
||||
* ID of custom container element
|
||||
* @type {String}
|
||||
*/
|
||||
this.targetId = f.status_bar_target_id || null;
|
||||
this.targetId = defaultsStr(f.target_id, null);
|
||||
|
||||
/**
|
||||
* Container DOM element
|
||||
|
@ -64,13 +66,13 @@ export class StatusBar extends Feature {
|
|||
* Text preceding status message
|
||||
* @type {String}
|
||||
*/
|
||||
this.text = f.status_bar_text || '';
|
||||
this.text = defaultsStr(f.text, '');
|
||||
|
||||
/**
|
||||
* Css class for container element
|
||||
* @type {String}
|
||||
*/
|
||||
this.cssClass = f.status_bar_css_class || 'status';
|
||||
this.cssClass = defaultsStr(f.css_class, 'status');
|
||||
|
||||
/**
|
||||
* Message visibility duration in milliseconds
|
||||
|
@ -83,85 +85,91 @@ export class StatusBar extends Feature {
|
|||
* Callback fired before the message is displayed
|
||||
* @type {Function}
|
||||
*/
|
||||
this.onBeforeShowMsg = isFn(f.on_before_show_msg) ?
|
||||
f.on_before_show_msg : EMPTY_FN;
|
||||
this.onBeforeShowMsg = defaultsFn(f.on_before_show_msg, EMPTY_FN);
|
||||
|
||||
/**
|
||||
* Callback fired after the message is displayed
|
||||
* @type {Function}
|
||||
*/
|
||||
this.onAfterShowMsg = isFn(f.on_after_show_msg) ?
|
||||
f.on_after_show_msg : EMPTY_FN;
|
||||
this.onAfterShowMsg = defaultsFn(f.on_after_show_msg, EMPTY_FN);
|
||||
|
||||
/**
|
||||
* Message appearing upon filtering
|
||||
* @type {String}
|
||||
*/
|
||||
this.msgFilter = f.msg_filter || 'Filtering data...';
|
||||
this.msgFilter = defaultsStr(f.msg_filter, 'Filtering data...');
|
||||
|
||||
/**
|
||||
* Message appearing when a drop-down filter is populated
|
||||
* @type {String}
|
||||
*/
|
||||
this.msgPopulate = f.msg_populate || 'Populating filter...';
|
||||
this.msgPopulate = defaultsStr(f.msg_populate, 'Populating filter...');
|
||||
|
||||
/**
|
||||
* Message appearing when a checklist filter is populated
|
||||
* @type {String}
|
||||
*/
|
||||
this.msgPopulateCheckList = f.msg_populate_checklist ||
|
||||
'Populating list...';
|
||||
this.msgPopulateCheckList = defaultsStr(f.msg_populate_checklist,
|
||||
'Populating list...');
|
||||
|
||||
/**
|
||||
* Message appearing when a pagination page is changed
|
||||
* @type {String}
|
||||
*/
|
||||
this.msgChangePage = f.msg_change_page || 'Collecting paging data...';
|
||||
this.msgChangePage = defaultsStr(f.msg_change_page,
|
||||
'Collecting paging data...');
|
||||
|
||||
/**
|
||||
* Message appearing when filters are cleared
|
||||
* @type {String}
|
||||
*/
|
||||
this.msgClear = f.msg_clear || 'Clearing filters...';
|
||||
this.msgClear = defaultsStr(f.msg_clear, 'Clearing filters...');
|
||||
|
||||
/**
|
||||
* Message appearing when the page length is changed
|
||||
* @type {String}
|
||||
*/
|
||||
this.msgChangeResults = f.msg_change_results ||
|
||||
'Changing results per page...';
|
||||
this.msgChangeResults = defaultsStr(f.msg_change_results,
|
||||
'Changing results per page...');
|
||||
|
||||
/**
|
||||
* Message appearing when the page is re-set
|
||||
* @type {String}
|
||||
*/
|
||||
this.msgResetPage = f.msg_reset_page || 'Re-setting page...';
|
||||
this.msgResetPage = defaultsStr(f.msg_reset_page, 'Re-setting page...');
|
||||
|
||||
/**
|
||||
* Message appearing when the page length is re-set
|
||||
* @type {String}
|
||||
*/
|
||||
this.msgResetPageLength = f.msg_reset_page_length ||
|
||||
'Re-setting page length...';
|
||||
this.msgResetPageLength = defaultsStr(f.msg_reset_page_length,
|
||||
'Re-setting page length...');
|
||||
|
||||
/**
|
||||
* Message appearing upon column sorting
|
||||
* @type {String}
|
||||
*/
|
||||
this.msgSort = f.msg_sort || 'Sorting data...';
|
||||
this.msgSort = defaultsStr(f.msg_sort, 'Sorting data...');
|
||||
|
||||
/**
|
||||
* Message appearing when extensions are loading
|
||||
* @type {String}
|
||||
*/
|
||||
this.msgLoadExtensions = f.msg_load_extensions ||
|
||||
'Loading extensions...';
|
||||
this.msgLoadExtensions = defaultsStr(f.msg_load_extensions,
|
||||
'Loading extensions...');
|
||||
|
||||
/**
|
||||
* Message appearing when themes are loading
|
||||
* @type {String}
|
||||
*/
|
||||
this.msgLoadThemes = f.msg_load_themes || 'Loading theme(s)...';
|
||||
this.msgLoadThemes = defaultsStr(f.msg_load_themes,
|
||||
'Loading theme(s)...');
|
||||
|
||||
/**
|
||||
* Default position in toolbar ('left'|'center'|'right')
|
||||
* @type {String}
|
||||
*/
|
||||
this.toolbarPosition = defaultsStr(f.toolbar_position, LEFT);
|
||||
}
|
||||
|
||||
/**
|
||||
|
@ -175,23 +183,24 @@ export class StatusBar extends Feature {
|
|||
let tf = this.tf;
|
||||
let emitter = this.emitter;
|
||||
|
||||
//status bar container
|
||||
emitter.emit('initializing-feature', this, !isNull(this.targetId));
|
||||
|
||||
// status bar container
|
||||
let statusDiv = createElm('div');
|
||||
statusDiv.className = this.cssClass;
|
||||
|
||||
//status bar label
|
||||
// status bar label
|
||||
let statusSpan = createElm('span');
|
||||
//preceding text
|
||||
// preceding text
|
||||
let statusSpanText = createElm('span');
|
||||
statusSpanText.appendChild(createText(this.text));
|
||||
|
||||
// target element container
|
||||
if (!this.targetId) {
|
||||
tf.setToolbar();
|
||||
}
|
||||
let targetEl = (!this.targetId) ? tf.lDiv : elm(this.targetId);
|
||||
let targetEl = (!this.targetId) ?
|
||||
tf.feature('toolbar').container(this.toolbarPosition) :
|
||||
elm(this.targetId);
|
||||
|
||||
//default container: 'lDiv'
|
||||
// default container
|
||||
if (!this.targetId) {
|
||||
statusDiv.appendChild(statusSpanText);
|
||||
statusDiv.appendChild(statusSpan);
|
||||
|
@ -206,7 +215,7 @@ export class StatusBar extends Feature {
|
|||
this.msgContainer = statusSpan;
|
||||
this.labelContainer = statusSpanText;
|
||||
|
||||
// Subscribe to events
|
||||
// subscribe to events
|
||||
emitter.on(['before-filtering'], () => this.message(this.msgFilter));
|
||||
emitter.on(['before-populating-filter'],
|
||||
() => this.message(this.msgPopulate));
|
||||
|
@ -227,10 +236,10 @@ export class StatusBar extends Feature {
|
|||
|
||||
emitter.on(EVENTS, () => this.message(''));
|
||||
|
||||
/**
|
||||
* @inherited
|
||||
*/
|
||||
/** @inherited */
|
||||
this.initialized = true;
|
||||
|
||||
emitter.emit('feature-initialized', this);
|
||||
}
|
||||
|
||||
/**
|
||||
|
|
|
@ -1,4 +1,3 @@
|
|||
|
||||
import Cookie from '../cookie';
|
||||
import {root} from '../root';
|
||||
|
||||
|
|
224
src/modules/toolbar.js
Normal file
224
src/modules/toolbar.js
Normal file
|
@ -0,0 +1,224 @@
|
|||
import {Feature} from '../feature';
|
||||
import {createElm, removeElm, elm, tag} from '../dom';
|
||||
import {defaultsStr} from '../settings';
|
||||
import {isUndef} from '../types';
|
||||
|
||||
const EVENTS = [
|
||||
'initializing-feature',
|
||||
'initializing-extension'
|
||||
];
|
||||
|
||||
/** Left position in toolbar */
|
||||
export const LEFT = 'left';
|
||||
/** Right position in toolbar */
|
||||
export const RIGHT = 'right';
|
||||
/** Center position in toolbar */
|
||||
export const CENTER = 'center';
|
||||
|
||||
/**
|
||||
* Toolbar UI component
|
||||
* @export
|
||||
* @class Toolbar
|
||||
* @extends {Feature}
|
||||
*/
|
||||
export class Toolbar extends Feature {
|
||||
|
||||
/**
|
||||
* Create an instance of Toolbar
|
||||
* @param {TableFilter} tf TableFilter instance
|
||||
* @memberof Toolbar
|
||||
*/
|
||||
constructor(tf) {
|
||||
super(tf, Toolbar);
|
||||
|
||||
// Configuration object
|
||||
let f = this.config.toolbar || {};
|
||||
|
||||
/**
|
||||
* Css class for toolbar's container DOM element
|
||||
* @type {String}
|
||||
*/
|
||||
this.contCssClass = defaultsStr(f.container_css_class, 'inf');
|
||||
|
||||
/**
|
||||
* Css class for left-side inner container DOM element
|
||||
* @type {String}
|
||||
*/
|
||||
this.lContCssClass = defaultsStr(f.left_cont_css_class, 'ldiv');
|
||||
|
||||
/**
|
||||
* Css class for right-side inner container DOM element
|
||||
* @type {String}
|
||||
*/
|
||||
this.rContCssClass = defaultsStr(f.right_cont_css_class, 'rdiv');
|
||||
|
||||
/**
|
||||
* Css class for middle inner container DOM element
|
||||
* @type {String}
|
||||
*/
|
||||
this.cContCssClass = defaultsStr(f.center_cont_css_class, 'mdiv');
|
||||
|
||||
/**
|
||||
* Toolbar's custom container ID
|
||||
* @type {String}
|
||||
*/
|
||||
this.tgtId = defaultsStr(f.target_id, null);
|
||||
|
||||
/**
|
||||
* Toolbar's container DOM element
|
||||
* @type {DOMElement}
|
||||
* @private
|
||||
*/
|
||||
this.cont = null;
|
||||
|
||||
/**
|
||||
* Left-side inner container DOM element (rows counter in toolbar)
|
||||
* @type {DOMElement}
|
||||
* @private
|
||||
*/
|
||||
this.lCont = null;
|
||||
|
||||
/**
|
||||
* Right-side inner container DOM element (reset button,
|
||||
* page length selector in toolbar)
|
||||
* @type {DOMElement}
|
||||
* @private
|
||||
*/
|
||||
this.rCont = null;
|
||||
|
||||
/**
|
||||
* Middle inner container DOM element (paging elements in toolbar)
|
||||
* @type {DOMElement}
|
||||
* @private
|
||||
*/
|
||||
this.cCont = null;
|
||||
|
||||
/**
|
||||
* Container elements inside toolbar
|
||||
* @private
|
||||
*/
|
||||
this.innerCont = {
|
||||
left: null,
|
||||
center: null,
|
||||
right: null
|
||||
};
|
||||
|
||||
this.emitter.on(EVENTS,
|
||||
(feature, isExternal) => this.init(isExternal));
|
||||
|
||||
/** @inherited */
|
||||
this.enabled = true;
|
||||
}
|
||||
|
||||
/**
|
||||
* Initialize toolbar components
|
||||
* @param {Boolean} isExternal initialize only if component belongs
|
||||
* to toolbar
|
||||
*/
|
||||
init(isExternal) {
|
||||
if (this.initialized || isExternal) {
|
||||
return;
|
||||
}
|
||||
|
||||
let tf = this.tf;
|
||||
|
||||
// default container
|
||||
let container = createElm('div');
|
||||
container.className = this.contCssClass;
|
||||
|
||||
// custom container
|
||||
if (this.tgtId) {
|
||||
elm(this.tgtId).appendChild(container);
|
||||
}
|
||||
// grid-layout
|
||||
else if (tf.gridLayout) {
|
||||
let gridLayout = tf.Mod.gridLayout;
|
||||
gridLayout.tblMainCont.appendChild(container);
|
||||
container.className = gridLayout.infDivCssClass;
|
||||
}
|
||||
// default location: just above the table
|
||||
else {
|
||||
let cont = createElm('caption');
|
||||
cont.appendChild(container);
|
||||
tf.dom().insertBefore(cont, tf.dom().firstChild);
|
||||
}
|
||||
this.cont = container;
|
||||
|
||||
// left container
|
||||
this.lCont = this.createContainer(container, this.lContCssClass);
|
||||
|
||||
// right container
|
||||
this.rCont = this.createContainer(container, this.rContCssClass);
|
||||
|
||||
// middle container
|
||||
this.cCont = this.createContainer(container, this.cContCssClass);
|
||||
|
||||
this.innerCont = {
|
||||
left: this.lCont,
|
||||
center: this.cCont,
|
||||
right: this.rCont
|
||||
};
|
||||
|
||||
/** @inherited */
|
||||
this.initialized = true;
|
||||
|
||||
// emit help initialisation only if undefined
|
||||
if (isUndef(tf.help)) {
|
||||
// explicitily enable help to initialise feature by
|
||||
// default, only if setting is undefined
|
||||
tf.Mod.help.enable();
|
||||
this.emitter.emit('init-help', tf);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Return the container based on requested position inside the toolbar
|
||||
* @param {String} [position=RIGHT] 3 possible positions: 'left', 'center',
|
||||
* 'right'
|
||||
* @param {DOMElement} el optional DOM element to be inserter in container
|
||||
* @returns {DOMElement}
|
||||
*/
|
||||
container(position = RIGHT, el) {
|
||||
let cont = this.innerCont[position];
|
||||
if (el) {
|
||||
cont.appendChild(el);
|
||||
}
|
||||
return cont;
|
||||
}
|
||||
|
||||
/**
|
||||
* Create DOM element inside passed container
|
||||
* @param {DOMElement} container
|
||||
* @param {String} css
|
||||
* @private
|
||||
*/
|
||||
createContainer(container, css) {
|
||||
let div = createElm('div', ['class', css]);
|
||||
container.appendChild(div);
|
||||
return div;
|
||||
}
|
||||
|
||||
/**
|
||||
* Destroy Toolbar instance
|
||||
*/
|
||||
destroy() {
|
||||
if (!this.initialized) {
|
||||
return;
|
||||
}
|
||||
|
||||
let tf = this.tf;
|
||||
|
||||
removeElm(this.cont);
|
||||
this.cont = null;
|
||||
|
||||
let tbl = tf.dom();
|
||||
let captions = tag(tbl, 'caption');
|
||||
[].forEach.call(captions, (el) => removeElm(el));
|
||||
|
||||
/** @inherited */
|
||||
this.initialized = false;
|
||||
}
|
||||
}
|
||||
|
||||
// TODO: remove as soon as feature name is fixed
|
||||
Toolbar.meta = {alwaysInstantiate: true};
|
|
@ -19,11 +19,14 @@ export const parse = (value, decimal = '.') => {
|
|||
let regex = new RegExp('[^0-9-' + decimal + ']', ['g']);
|
||||
let unformatted = parseFloat(
|
||||
('' + value)
|
||||
.replace(/\((.*)\)/, '-$1') // replace bracketed values with negatives
|
||||
.replace(regex, '') // strip out any cruft
|
||||
.replace(decimal, '.') // make sure decimal point is standard
|
||||
// replace bracketed values with negatives
|
||||
.replace(/\((.*)\)/, '-$1')
|
||||
// strip out any cruft
|
||||
.replace(regex, '')
|
||||
// make sure decimal point is standard
|
||||
.replace(decimal, '.')
|
||||
);
|
||||
|
||||
// This will fail silently
|
||||
return !isNaN(unformatted) ? unformatted : 0;
|
||||
}
|
||||
};
|
||||
|
|
53
src/settings.js
Normal file
53
src/settings.js
Normal file
|
@ -0,0 +1,53 @@
|
|||
import {isBoolean, isString, isFn, isArray} from './types';
|
||||
|
||||
/** Configuration settings helpers */
|
||||
|
||||
/**
|
||||
* If passed value is not of boolean type return the default value
|
||||
* otherwise return the value itself
|
||||
* @param {Boolean|Any} value
|
||||
* @param {Boolean} default value
|
||||
* @return {Boolean|Any}
|
||||
*/
|
||||
export const defaultsBool =
|
||||
(val, defaultVal) => isBoolean(val) ? val : defaultVal;
|
||||
|
||||
/**
|
||||
* If passed value is not of string type return the default value
|
||||
* otherwise return the value itself
|
||||
* @param {String|Any} value
|
||||
* @param {String} default value
|
||||
* @return {String|Any}
|
||||
*/
|
||||
export const defaultsStr =
|
||||
(val, defaultVal) => isString(val) ? val : defaultVal;
|
||||
|
||||
/**
|
||||
* If passed value is not of number type return the default value
|
||||
* otherwise return the value itself
|
||||
* @param {Number|Any} value
|
||||
* @param {Number} default value
|
||||
* @return {Number|Any}
|
||||
*/
|
||||
export const defaultsNb =
|
||||
(val, defaultVal) => isNaN(val) ? defaultVal : val;
|
||||
|
||||
/**
|
||||
* If passed value is not of array type return the default value
|
||||
* otherwise return the value itself
|
||||
* @param {Array|Any} value
|
||||
* @param {Array} default value
|
||||
* @return {Array|Any}
|
||||
*/
|
||||
export const defaultsArr =
|
||||
(val, defaultVal) => isArray(val) ? val : defaultVal;
|
||||
|
||||
/**
|
||||
* If passed value is not of function type return the default value
|
||||
* otherwise return the value itself
|
||||
* @param {Function|Any} value
|
||||
* @param {Function} default value
|
||||
* @return {Function|Any}
|
||||
*/
|
||||
export const defaultsFn =
|
||||
(val, defaultVal) => isFn(val) ? val : defaultVal;
|
67
src/sort.js
67
src/sort.js
|
@ -1,6 +1,7 @@
|
|||
/**
|
||||
* Sorting utilities
|
||||
*/
|
||||
import {parse as parseNb} from './number';
|
||||
import {Date as SugarDate} from 'sugar-date';
|
||||
|
||||
/** Sorting utilities */
|
||||
|
||||
/**
|
||||
* Case insensitive compare function for passed strings
|
||||
|
@ -13,21 +14,69 @@
|
|||
export const ignoreCase = (a, b) => {
|
||||
let x = a.toLowerCase();
|
||||
let y = b.toLowerCase();
|
||||
return ((x < y) ? -1 : ((x > y) ? 1 : 0));
|
||||
}
|
||||
return x < y ? -1 : (x > y ? 1 : 0);
|
||||
};
|
||||
|
||||
/**
|
||||
* Sorts passed numbers in a ascending manner
|
||||
* Compare function for sorting passed numbers in ascending manner
|
||||
* @param {Number} First number
|
||||
* @param {Number} Second number
|
||||
* @param {Number} Negative, zero or positive number
|
||||
* @return {Number} Negative, zero or positive number
|
||||
*/
|
||||
export const numSortAsc = (a, b) => (a - b);
|
||||
|
||||
/**
|
||||
* Sorts passed numbers in a descending manner
|
||||
* Compare function for sorting passed numbers in descending manner
|
||||
* @param {Number} First number
|
||||
* @param {Number} Second number
|
||||
* @param {Number} Negative, zero or positive number
|
||||
* @return {Number} Negative, zero or positive number
|
||||
*/
|
||||
export const numSortDesc = (a, b) => (b - a);
|
||||
|
||||
/**
|
||||
* Compare function for sorting passed dates in ascending manner according to
|
||||
* the corresponding UTC numeric value (returned by getTime)
|
||||
* @param {Date} First date object
|
||||
* @param {Date} Second date object
|
||||
* @return {Number} Negative, zero or positive number
|
||||
*/
|
||||
export const dateSortAsc = (date1, date2) => date1.getTime() - date2.getTime();
|
||||
|
||||
/**
|
||||
* Compare function for sorting passed dates in descending manner according to
|
||||
* the corresponding UTC numeric value (returned by getTime)
|
||||
* @param {Date} First date object
|
||||
* @param {Date} Second date object
|
||||
* @return {Number} Negative, zero or positive number
|
||||
*/
|
||||
export const dateSortDesc = (date1, date2) => date2.getTime() - date1.getTime();
|
||||
|
||||
/**
|
||||
* Curried compare function for sorting passed formatted numbers in desired
|
||||
* fashion according to supplied compare function and decimal separator
|
||||
* @param {Function} Compare function
|
||||
* @param {String} [decimal=','] Decimal separator
|
||||
* @return {Function} Compare function receiving parsed numeric arguments
|
||||
*/
|
||||
export const sortNumberStr = (compareFn, decimal = ',') => {
|
||||
return (numStr1, numStr2) => {
|
||||
let num1 = parseNb(numStr1, decimal);
|
||||
let num2 = parseNb(numStr2, decimal);
|
||||
return compareFn(num1, num2);
|
||||
};
|
||||
};
|
||||
|
||||
/**
|
||||
* Curried compare function for sorting passed formatted dates in desired
|
||||
* fashion according to supplied compare function and locale
|
||||
* @param {Function} Compare function
|
||||
* @param {String} [locale='en-us'] Locale code
|
||||
* @return {Function} Compare function receiving parsed date arguments
|
||||
*/
|
||||
export const sortDateStr = (compareFn, locale = 'en-us') => {
|
||||
return (dateStr1, dateStr2) => {
|
||||
let date1 = SugarDate.create(dateStr1, locale);
|
||||
let date2 = SugarDate.create(dateStr2, locale);
|
||||
return compareFn(date1, date2);
|
||||
};
|
||||
};
|
||||
|
|
|
@ -14,7 +14,7 @@ export const trim = (text) => {
|
|||
return text.trim();
|
||||
}
|
||||
return text.replace(/^\s*|\s*$/g, '');
|
||||
}
|
||||
};
|
||||
|
||||
/**
|
||||
* Checks if passed string is empty
|
||||
|
@ -32,7 +32,7 @@ export const rgxEsc = (text) => {
|
|||
let chars = /[-\/\\^$*+?.()|[\]{}]/g;
|
||||
let escMatch = '\\$&';
|
||||
return String(text).replace(chars, escMatch);
|
||||
}
|
||||
};
|
||||
|
||||
/**
|
||||
* Returns passed string as lowercase if caseSensitive flag set false. By
|
||||
|
@ -45,7 +45,7 @@ export const matchCase = (text, caseSensitive = false) => {
|
|||
return text.toLowerCase();
|
||||
}
|
||||
return text;
|
||||
}
|
||||
};
|
||||
|
||||
/**
|
||||
* Checks if passed data contains the searched term
|
||||
|
@ -73,4 +73,40 @@ export const contains = (term, data, exactMatch = false, caseSensitive = false,
|
|||
regexp = new RegExp(rgxEsc(term), modifier);
|
||||
}
|
||||
return regexp.test(data);
|
||||
}
|
||||
};
|
||||
|
||||
/**
|
||||
* Camelize a string, cutting the string by multiple separators like
|
||||
* hyphens, underscores and spaces.
|
||||
* @param {String} text text to camelize
|
||||
* @return {String} camelized text
|
||||
*/
|
||||
export const toCamelCase = (text = '') => {
|
||||
return text.replace(/^([A-Z])|[\s-_]+(\w)/g, (match, p1, p2) => {
|
||||
if (p2) {
|
||||
return p2.toUpperCase();
|
||||
}
|
||||
return p1.toLowerCase();
|
||||
});
|
||||
};
|
||||
|
||||
/**
|
||||
* Generate a string in the format of a UUID (Universally Unique IDentifier).
|
||||
* NOTE: This format of 8 chars, followed by 3 groups of 4 chars, followed by 12
|
||||
* chars is known as a UUID and is defined in RFC4122 and is a standard for
|
||||
* generating unique IDs. This function DOES NOT implement this standard.
|
||||
* It simply outputs a string that looks similar. The standard is found here:
|
||||
* https://www.ietf.org/rfc/rfc4122.txt
|
||||
* source: https://gist.github.com/gordonbrander/2230317
|
||||
* @return {String}
|
||||
*/
|
||||
export const uuid = () => {
|
||||
const chr4 = () => Math.random().toString(16).slice(-4);
|
||||
|
||||
return chr4() + chr4()
|
||||
+ '-' + chr4()
|
||||
+ '-' + chr4()
|
||||
+ '-' + chr4()
|
||||
+ '-' + chr4()
|
||||
+ chr4() + chr4();
|
||||
};
|
||||
|
|
1830
src/tablefilter.js
1830
src/tablefilter.js
File diff suppressed because it is too large
Load diff
10
src/types.js
10
src/types.js
|
@ -37,7 +37,7 @@ export const isArray =
|
|||
|
||||
/**
|
||||
* Check passed argument is a string
|
||||
* @param {String} obj objue
|
||||
* @param {String} obj obj
|
||||
* @returns {Boolean}
|
||||
*/
|
||||
export const isString =
|
||||
|
@ -51,6 +51,14 @@ export const isString =
|
|||
export const isNumber =
|
||||
(obj) => Object.prototype.toString.call(obj) === '[object Number]';
|
||||
|
||||
/**
|
||||
* Check passed argument is a boolean
|
||||
* @param {Boolean} obj
|
||||
* @returns {Boolean}
|
||||
*/
|
||||
export const isBoolean =
|
||||
(obj) => Object.prototype.toString.call(obj) === '[object Boolean]';
|
||||
|
||||
/**
|
||||
* Check passed argument is undefined
|
||||
* @param {Any} obj
|
||||
|
|
File diff suppressed because it is too large
Load diff
|
@ -5,3 +5,6 @@
|
|||
.activeHeader
|
||||
background-color #66AFE9 !important
|
||||
color #fff !important
|
||||
|
||||
.activeCell
|
||||
background-color rgba(0,0,0,0.075)
|
||||
|
|
|
@ -34,7 +34,7 @@ div.colVisCont
|
|||
z-index 10000
|
||||
padding 10px 10px 10px 10px
|
||||
text-align left
|
||||
font-size 12px
|
||||
font-size inherit
|
||||
|
||||
p
|
||||
margin 6px auto 6px auto
|
||||
|
@ -47,7 +47,7 @@ div.colVisCont
|
|||
ul.cols_checklist
|
||||
padding 0
|
||||
margin 0
|
||||
list-style none
|
||||
list-style-type none
|
||||
|
||||
label
|
||||
display block
|
||||
|
|
|
@ -11,7 +11,7 @@ $item-font-color = #fff
|
|||
.div_checklist
|
||||
width 100%
|
||||
height 90px
|
||||
line-height 24px
|
||||
line-height 30px
|
||||
border 1px solid $filter-border-color
|
||||
overflow auto
|
||||
text-align left
|
||||
|
@ -27,19 +27,20 @@ $item-font-color = #fff
|
|||
li.flt_checklist_item
|
||||
padding 1px !important
|
||||
margin 0 !important
|
||||
font-size 10px !important
|
||||
font-size inherit
|
||||
border-bottom 1px solid $filter-border-color !important
|
||||
|
||||
&:hover
|
||||
background-color $item-bg-color !important
|
||||
color $item-font-color !important;
|
||||
color $item-font-color !important
|
||||
|
||||
label
|
||||
display block !important;
|
||||
display block !important
|
||||
font-weight inherit !important
|
||||
|
||||
input
|
||||
vertical-align middle !important;
|
||||
margin 2px 5px 2px 1px !important;
|
||||
vertical-align middle !important
|
||||
margin 2px 5px 3px 1px !important
|
||||
|
||||
// disabled checklist item
|
||||
.flt_checklist_item_disabled
|
||||
|
|
|
@ -43,6 +43,7 @@
|
|||
// input and select filter type
|
||||
.flt
|
||||
font-family inherit
|
||||
font-size inherit
|
||||
display block
|
||||
color $filter-font-color
|
||||
background-color $filter-bg-color
|
||||
|
@ -64,6 +65,7 @@
|
|||
// multiple select type filter
|
||||
select.flt_multi
|
||||
font-family inherit
|
||||
font-size inherit
|
||||
color $filter-font-color
|
||||
background-color $filter-bg-color
|
||||
border 1px solid $filter-border-color
|
||||
|
@ -92,7 +94,7 @@ select.flt_multi
|
|||
box-sizing initial
|
||||
display initial
|
||||
|
||||
// Pop-up filters elements
|
||||
// pop-up filters elements
|
||||
div.popUpFilter
|
||||
arrow(top, 10px white, 2px $th-bg-color)
|
||||
box-shadow(3px 3px 2px #888)
|
||||
|
@ -103,3 +105,7 @@ div.popUpFilter
|
|||
background-color $th-bg-color
|
||||
border 1px solid $filter-row-bg-color
|
||||
padding 0
|
||||
|
||||
// pop-up container
|
||||
.popUpPlaceholder
|
||||
position relative
|
||||
|
|
|
@ -11,7 +11,6 @@ div.grd_Cont
|
|||
width 800px
|
||||
height auto
|
||||
overflow hidden
|
||||
padding 3px 3px 3px 3px
|
||||
background-color $grid-layout-bg-color
|
||||
border 1px solid $grid-layout-border-color
|
||||
|
||||
|
@ -50,8 +49,9 @@ div.grd_tblCont
|
|||
|
||||
// headers' table container
|
||||
div.grd_headTblCont
|
||||
display block
|
||||
margin-right 20px
|
||||
height auto
|
||||
width 800px
|
||||
overflow hidden
|
||||
border-bottom 1px solid $grid-layout-border-color
|
||||
background-color $grid-layout-bg-color
|
||||
|
@ -63,10 +63,6 @@ div.grd_headTblCont table
|
|||
table-layout fixed
|
||||
box-sizing initial
|
||||
|
||||
div.grd_tblCont table
|
||||
border-right 1px solid $grid-layout-border-color
|
||||
box-sizing initial
|
||||
|
||||
// headers
|
||||
div.grd_tblCont table th
|
||||
div.grd_headTblCont table th
|
||||
|
|
|
@ -32,6 +32,7 @@ div.helpCont
|
|||
color #333
|
||||
background #fff
|
||||
text-align left
|
||||
z-index 1000
|
||||
|
||||
a
|
||||
color #cc0000
|
||||
|
|
7
static/style/mixins/empty-content.styl
Normal file
7
static/style/mixins/empty-content.styl
Normal file
|
@ -0,0 +1,7 @@
|
|||
/**
|
||||
* Empty content mixin
|
||||
*/
|
||||
|
||||
empty-content()
|
||||
&:empty:after
|
||||
content "\00A0"
|
|
@ -14,3 +14,8 @@ input.reset
|
|||
|
||||
&:hover
|
||||
background-color $toolbar-hover-color
|
||||
|
||||
a.reset
|
||||
font-weight normal !important
|
||||
line-height $min-height
|
||||
padding 5px 5px
|
||||
|
|
|
@ -26,11 +26,19 @@ table.TF
|
|||
margin 0
|
||||
padding $padding
|
||||
border-bottom 1px solid $td-border-color
|
||||
text-overflow ellipsis
|
||||
|
||||
// responsiveness
|
||||
// responsive
|
||||
&.resp
|
||||
display block
|
||||
overflow-x auto
|
||||
overflow-y hidden
|
||||
|
||||
.sort-arrow
|
||||
position initial
|
||||
|
||||
// stick headers
|
||||
&.sticky
|
||||
th
|
||||
position sticky
|
||||
top -1px
|
||||
|
|
18
static/style/tablefilter.styl
Normal file
18
static/style/tablefilter.styl
Normal file
|
@ -0,0 +1,18 @@
|
|||
/** Main stylesheet */
|
||||
@import 'active-header'
|
||||
@import 'alternating-rows'
|
||||
@import 'ezedittable'
|
||||
@import 'filter-checklist'
|
||||
@import 'filters'
|
||||
@import 'grid-layout'
|
||||
@import 'help'
|
||||
@import 'keyword'
|
||||
@import 'loader'
|
||||
@import 'noresults'
|
||||
@import 'paging'
|
||||
@import 'reset-button'
|
||||
@import 'rows-counter'
|
||||
@import 'sort'
|
||||
@import 'status-bar'
|
||||
@import 'table'
|
||||
@import 'toolbar'
|
|
@ -3,12 +3,14 @@
|
|||
*/
|
||||
|
||||
@import 'config'
|
||||
@import 'mixins/empty-content'
|
||||
|
||||
// left, middle and right divs container (toolbar)
|
||||
.inf
|
||||
clear both
|
||||
width auto
|
||||
height $min-height
|
||||
min-width 400px
|
||||
background-color $toolbar-bg-color
|
||||
font-size $toolbar-font-size
|
||||
margin 0
|
||||
|
@ -32,25 +34,25 @@
|
|||
|
||||
// left div
|
||||
.ldiv
|
||||
empty-content()
|
||||
float left
|
||||
width 30%
|
||||
// height 100%
|
||||
position inherit
|
||||
text-align left
|
||||
|
||||
// middle div
|
||||
.mdiv
|
||||
empty-content()
|
||||
float left
|
||||
width 38%
|
||||
// height 100%
|
||||
position inherit
|
||||
text-align center
|
||||
padding 0
|
||||
|
||||
// right div
|
||||
.rdiv
|
||||
empty-content()
|
||||
float right
|
||||
width 30%
|
||||
// height 100%
|
||||
position inherit
|
||||
text-align right
|
||||
|
|
|
@ -49,8 +49,9 @@
|
|||
<script data-config>
|
||||
var filtersConfig = {
|
||||
base_path: '../dist/tablefilter/',
|
||||
grid_layout: true,
|
||||
grid_width: '900px',
|
||||
grid_layout: {
|
||||
width: '900px'
|
||||
},
|
||||
alternate_rows: true,
|
||||
btn_reset: true,
|
||||
rows_counter: true,
|
||||
|
|
|
@ -19,15 +19,18 @@
|
|||
<script data-config>
|
||||
var filtersConfig = {
|
||||
base_path: '../dist/tablefilter/',
|
||||
auto_filter: true,
|
||||
auto_filter_delay: 750, //milliseconds
|
||||
auto_filter: {
|
||||
delay: 750 // milliseconds
|
||||
},
|
||||
filters_row_index: 1,
|
||||
state: true,
|
||||
alternate_rows: true,
|
||||
rows_counter: true,
|
||||
rows_counter_text: 'Rows: ',
|
||||
rows_counter: {
|
||||
text: 'Rows: '
|
||||
},
|
||||
btn_reset: true,
|
||||
status_bar: true,
|
||||
sticky_headers: true,
|
||||
msg_filter: 'Filtering...'
|
||||
};
|
||||
|
||||
|
|
|
@ -39,8 +39,9 @@ var tfConfig = {
|
|||
},
|
||||
alternate_rows: true,
|
||||
rows_counter: true,
|
||||
btn_reset: true,
|
||||
btn_reset_text: 'Clear',
|
||||
btn_reset: {
|
||||
text: 'Clear'
|
||||
},
|
||||
status_bar: true,
|
||||
col_1: 'select',
|
||||
col_2: 'select',
|
||||
|
|
|
@ -32,40 +32,6 @@ var id = function (id){
|
|||
var table = id('demo-tot');
|
||||
var totRowIndex = table.getElementsByTagName('tr').length;
|
||||
|
||||
function addCommas(nStr){
|
||||
nStr += '';
|
||||
var x = nStr.split('.');
|
||||
var x1 = x[0];
|
||||
var x2 = x.length > 1 ? '.' + x[1] : '';
|
||||
var rgx = /(\d+)(\d{3})/;
|
||||
while (rgx.test(x1)) {
|
||||
x1 = x1.replace(rgx, '$1' + ',' + '$2');
|
||||
}
|
||||
return x1 + x2;
|
||||
}
|
||||
|
||||
function addDots(nStr){
|
||||
nStr += '';
|
||||
var x = nStr.split('.');
|
||||
var x1 = x[0];
|
||||
var x2 = x.length > 1 ? ',' + x[1] : '';
|
||||
var rgx = /(\d+)(\d{3})/;
|
||||
while (rgx.test(x1)) {
|
||||
x1 = x1.replace(rgx, '$1' + '.' + '$2');
|
||||
}
|
||||
return x1 + x2;
|
||||
}
|
||||
|
||||
function formatTotals(){
|
||||
var tot1 = id('sum1').innerHTML;
|
||||
tot1 = addDots(tot1);
|
||||
id('sum1').innerHTML = tot1;
|
||||
|
||||
var tot2 = id('sum2').innerHTML;
|
||||
tot2 = addCommas(tot2);
|
||||
id('sum2').innerHTML = tot2;
|
||||
}
|
||||
|
||||
/* EXAMPLE 1
|
||||
*********************** */
|
||||
var tfConfig = {
|
||||
|
@ -107,7 +73,10 @@ var tfConfig = {
|
|||
exclude_row: [totRowIndex],
|
||||
decimal_precision: [2, 2],
|
||||
tot_row_index: [totRowIndex],
|
||||
on_after_operation: formatTotals
|
||||
format_result: [
|
||||
{ prefix: '€ ' },
|
||||
{ prefix: '$ ' }
|
||||
]
|
||||
}
|
||||
]
|
||||
};
|
||||
|
|
|
@ -23,9 +23,10 @@
|
|||
btn_reset: true,
|
||||
loader: true,
|
||||
status_bar: true,
|
||||
mark_active_columns: true,
|
||||
mark_active_columns: {
|
||||
highlight_column: true
|
||||
},
|
||||
no_results_message: true,
|
||||
responsive: true,
|
||||
custom_options: {
|
||||
cols:[3],
|
||||
texts: [
|
||||
|
@ -46,8 +47,8 @@
|
|||
},
|
||||
col_widths: [
|
||||
'150px', '100px', '100px',
|
||||
'70px', '70px', '70px',
|
||||
'70px', '60px', '60px'
|
||||
'90px', '90px', '90px',
|
||||
'90px', '70px', '70px'
|
||||
],
|
||||
extensions:[{ name: 'sort' }]
|
||||
};
|
||||
|
|
|
@ -82,8 +82,9 @@
|
|||
var tfConfig = {
|
||||
base_path: '../dist/tablefilter/',
|
||||
alternate_rows: true,
|
||||
rows_counter: true,
|
||||
rows_counter_text: "Displayed rows: ",
|
||||
rows_counter: {
|
||||
text: 'Displayed rows: '
|
||||
},
|
||||
loader: true,
|
||||
status: true,
|
||||
status_bar: true,
|
||||
|
@ -105,8 +106,7 @@ var tfConfig = {
|
|||
col_8: "none",
|
||||
|
||||
/* external filters */
|
||||
external_flt_grid: true,
|
||||
external_flt_grid_ids: [
|
||||
external_flt_ids: [
|
||||
'slcCountry',
|
||||
'slcCode',
|
||||
'slcYear',
|
||||
|
|
|
@ -26,8 +26,9 @@ var tfConfig = {
|
|||
'string', 'string', 'string',
|
||||
'number', 'string', 'string', 'date'
|
||||
],
|
||||
rows_counter: true,
|
||||
rows_counter_text: 'Books: ',
|
||||
rows_counter: {
|
||||
text: 'Books: '
|
||||
},
|
||||
alternate_rows: true,
|
||||
btn_reset: true,
|
||||
|
||||
|
@ -36,22 +37,23 @@ var tfConfig = {
|
|||
col_4: 'select',
|
||||
col_5: 'select',
|
||||
|
||||
/* custom_cell_data delegate used for filtering
|
||||
images in a column */
|
||||
custom_cell_data_cols: [0, 4],
|
||||
custom_cell_data: function(o, cell, colIndex){
|
||||
if(colIndex === 0){
|
||||
var img = cell.getElementsByTagName('img')[0];
|
||||
if(!img){
|
||||
return '';
|
||||
}
|
||||
return img.alt;
|
||||
} else if(colIndex === 4){
|
||||
var chk = cell.getElementsByTagName('input')[0];
|
||||
if(chk.checked){
|
||||
return 'yes';
|
||||
} else {
|
||||
return 'no';
|
||||
/* cell parser for filtering images in a column */
|
||||
cell_parser: {
|
||||
cols: [0, 4],
|
||||
parse: function(o, cell, colIndex){
|
||||
if(colIndex === 0){
|
||||
var img = cell.getElementsByTagName('img')[0];
|
||||
if(!img){
|
||||
return '';
|
||||
}
|
||||
return img.alt;
|
||||
} else if(colIndex === 4){
|
||||
var chk = cell.getElementsByTagName('input')[0];
|
||||
if(chk.checked){
|
||||
return 'yes';
|
||||
} else {
|
||||
return 'no';
|
||||
}
|
||||
}
|
||||
}
|
||||
},
|
||||
|
|
|
@ -22,7 +22,7 @@ var tfConfig = {
|
|||
col_2: 'checklist',
|
||||
col_widths: [
|
||||
'75px', '200px', '200px',
|
||||
'100px', '75px', ''
|
||||
'100px', '75px', '400px'
|
||||
],
|
||||
paging: true,
|
||||
alternate_rows: true,
|
||||
|
|
|
@ -22,6 +22,9 @@
|
|||
loader: true,
|
||||
status_bar: true,
|
||||
no_results_message: true,
|
||||
mark_active_columns: {
|
||||
highlight_column: true
|
||||
},
|
||||
col_1: 'select',
|
||||
col_2: 'select',
|
||||
col_widths: [
|
||||
|
|
|
@ -58,8 +58,9 @@ var tfConfig = {
|
|||
rows_counter: true,
|
||||
btn_reset: true,
|
||||
status_bar: true,
|
||||
paging: true,
|
||||
paging_length: 15,
|
||||
paging: {
|
||||
length: 15
|
||||
},
|
||||
enable_empty_option: true,
|
||||
enable_non_empty_option: true,
|
||||
enable_default_theme: true,
|
||||
|
|
|
@ -20,14 +20,15 @@ var tfConfig = {
|
|||
base_path: '../dist/tablefilter/',
|
||||
col_widths: [
|
||||
'150px', '100px', '100px',
|
||||
'70px', '70px', '70px',
|
||||
'70px', '60px', '60px'
|
||||
'100px', '100px', '100px',
|
||||
'90px', '90px', '90px'
|
||||
],
|
||||
alternate_rows: true,
|
||||
rows_counter: true,
|
||||
btn_reset: true,
|
||||
status_bar: true,
|
||||
load_filters_on_demand: true,
|
||||
sticky_headers: true,
|
||||
col_0: 'multiple',
|
||||
col_1: 'select',
|
||||
col_2: 'checklist'
|
||||
|
|
|
@ -30,8 +30,9 @@
|
|||
<script data-config>
|
||||
var filtersConfig = {
|
||||
base_path: '../dist/tablefilter/',
|
||||
paging: true,
|
||||
results_per_page: ['Records: ', [10,25,50,100]],
|
||||
paging: {
|
||||
results_per_page: ['Records: ', [10, 25, 50, 100]]
|
||||
},
|
||||
state: {
|
||||
types: ['local_storage'],
|
||||
filters: true,
|
||||
|
@ -39,15 +40,21 @@
|
|||
page_length: true,
|
||||
sort: true
|
||||
},
|
||||
responsive: true,
|
||||
help_instructions: {
|
||||
container_adjust_left_position: 30
|
||||
},
|
||||
alternate_rows: true,
|
||||
btn_reset: true,
|
||||
rows_counter: true,
|
||||
loader: true,
|
||||
loader_html: '<div id="lblMsg"></div>',
|
||||
loader_css_class: 'myLoader',
|
||||
status_bar: true,
|
||||
status_bar_target_id: 'lblMsg',
|
||||
status_bar_css_class: 'myStatus',
|
||||
loader: {
|
||||
html: '<div id="lblMsg"></div>',
|
||||
css_class: 'myLoader'
|
||||
},
|
||||
status_bar: {
|
||||
target_id: 'lblMsg',
|
||||
css_class: 'myStatus'
|
||||
},
|
||||
no_results_message: true,
|
||||
col_0: 'select',
|
||||
col_1: 'select',
|
||||
|
|
|
@ -1,69 +0,0 @@
|
|||
<!DOCTYPE html>
|
||||
<html lang="en">
|
||||
<head>
|
||||
<title>{NAME} v{VERSION} - Development workflow with RequireJs</title>
|
||||
<!-- @import partials/style.html -->
|
||||
</head>
|
||||
<body>
|
||||
<h1>{NAME} v{VERSION}</h1>
|
||||
<h2>Development workflow with RequireJs</h2>
|
||||
<p>
|
||||
To take advantage of the RequireJs development workflow use the
|
||||
<code>grunt dev-modules</code> command.
|
||||
</p>
|
||||
<p>
|
||||
If you use extensions, you will need to specify the extensions path as per
|
||||
configuration example. Sorting feature also requires the third-party
|
||||
<code>../libs/sortabletable</code> dependency to be imported.
|
||||
</p>
|
||||
|
||||
<!-- @import partials/pre.html -->
|
||||
|
||||
<!-- @import partials/countries-by-continent.html -->
|
||||
|
||||
<script src="//cdnjs.cloudflare.com/ajax/libs/require.js/2.1.17/require.min.js"></script>
|
||||
<script data-config>
|
||||
requirejs(
|
||||
['../dist/tablefilter/tablefilter', '../libs/sortabletable'],
|
||||
function(mod){
|
||||
var TableFilter = mod.TableFilter;
|
||||
var tfConfig = {
|
||||
base_path: '../dist/tablefilter/',
|
||||
col_1: 'multiple',
|
||||
col_2: 'checklist',
|
||||
alternate_rows: true,
|
||||
rows_counter: true,
|
||||
enable_default_theme: true,
|
||||
col_widths: [
|
||||
'70px', '170px', '170px',
|
||||
'110px', '90px', '250px'
|
||||
],
|
||||
extensions:[
|
||||
{
|
||||
name: 'sort',
|
||||
path: '../dist/tablefilter/extensions/sort/',
|
||||
types: [
|
||||
'number', 'string', 'string',
|
||||
'US', 'none', 'string'
|
||||
]
|
||||
},
|
||||
{
|
||||
name: 'colsVisibility',
|
||||
path: '../dist/tablefilter/extensions/colsVisibility/'
|
||||
},
|
||||
{
|
||||
name: 'filtersVisibility',
|
||||
path: '../dist/tablefilter/extensions/filtersVisibility/'
|
||||
}
|
||||
]
|
||||
};
|
||||
|
||||
tf = new TableFilter('demo', tfConfig);
|
||||
tf.init();
|
||||
}
|
||||
);
|
||||
</script>
|
||||
|
||||
<!-- @import partials/pre-inline-script.html -->
|
||||
</body>
|
||||
</html>
|
|
@ -43,7 +43,7 @@
|
|||
},
|
||||
col_widths: [
|
||||
'150px', '100px', '100px',
|
||||
'70px', '70px', '70px',
|
||||
'100px', '100px', '100px',
|
||||
'70px', '60px', '60px'
|
||||
],
|
||||
extensions:[{ name: 'sort' }]
|
||||
|
|
|
@ -35,28 +35,33 @@ var tfConfig = {
|
|||
'string', 'string', 'number',
|
||||
'string', 'string', 'date'
|
||||
],
|
||||
rows_counter: true,
|
||||
rows_counter_text: 'Books: ',
|
||||
rows_counter: {
|
||||
text: 'Books: '
|
||||
},
|
||||
alternate_rows: true,
|
||||
btn_reset: true,
|
||||
mark_active_columns: true,
|
||||
mark_active_columns: {
|
||||
highlight_column: true
|
||||
},
|
||||
|
||||
/* Filter types*/
|
||||
col_3: 'select',
|
||||
col_4: 'select',
|
||||
|
||||
/* delegate for filtering 'In store' column */
|
||||
custom_cell_data_cols: [3],
|
||||
custom_cell_data: function(o, cell, colIndex){
|
||||
if(colIndex === 3){
|
||||
var chk = cell.getElementsByTagName('input')[0];
|
||||
if(!chk){
|
||||
return '';
|
||||
}
|
||||
if(chk.checked){
|
||||
return 'yes';
|
||||
} else {
|
||||
return 'no';
|
||||
/* cell parser for 'In store' column */
|
||||
cell_parser: {
|
||||
cols: [3],
|
||||
parse: function(o, cell, colIndex){
|
||||
if(colIndex === 3){
|
||||
var chk = cell.getElementsByTagName('input')[0];
|
||||
if(!chk){
|
||||
return '';
|
||||
}
|
||||
if(chk.checked){
|
||||
return 'yes';
|
||||
} else {
|
||||
return 'no';
|
||||
}
|
||||
}
|
||||
}
|
||||
},
|
||||
|
|
|
@ -6,12 +6,72 @@
|
|||
mark_active_columns: true
|
||||
});
|
||||
tf.init();
|
||||
var markActiveColumns = tf.feature('markActiveColumns');
|
||||
|
||||
module('Sanity checks');
|
||||
test('Active columns', function() {
|
||||
deepEqual(tf instanceof TableFilter, true, 'TableFilter instanciated');
|
||||
notEqual(markActiveColumns, null, 'markActiveColumns instanciated');
|
||||
deepEqual(tf.markActiveColumns, true, 'markActiveColumns property');
|
||||
equal(markActiveColumns.emitter.events['before-filtering'].length, 1,
|
||||
'subscribed to `before-filtering` event');
|
||||
equal(markActiveColumns.emitter.events['cell-processed'].length, 1,
|
||||
'subscribed to `cell-processed` event');
|
||||
});
|
||||
|
||||
module('Feature interface');
|
||||
test('Properties', function() {
|
||||
deepEqual(markActiveColumns.tf instanceof TableFilter, true,
|
||||
'TableFilter instance');
|
||||
deepEqual(markActiveColumns.feature, 'markActiveColumns',
|
||||
'Feature name');
|
||||
deepEqual(markActiveColumns.enabled, true, 'Feature enabled');
|
||||
deepEqual(markActiveColumns.initialized, true, 'Feature initialized');
|
||||
deepEqual(typeof markActiveColumns.emitter, 'object',
|
||||
'Feature has emitter instance');
|
||||
deepEqual(typeof markActiveColumns.config, 'object',
|
||||
'TF configuration object');
|
||||
deepEqual(typeof markActiveColumns.init, 'function',
|
||||
'Feature init method');
|
||||
deepEqual(typeof markActiveColumns.destroy, 'function',
|
||||
'Feature destroy method');
|
||||
deepEqual(typeof markActiveColumns.reset, 'function',
|
||||
'Feature reset method');
|
||||
deepEqual(typeof markActiveColumns.enable, 'function',
|
||||
'Feature enable method');
|
||||
deepEqual(typeof markActiveColumns.disable, 'function',
|
||||
'Feature enable method');
|
||||
deepEqual(typeof markActiveColumns.isEnabled, 'function',
|
||||
'Feature enable method');
|
||||
});
|
||||
test('Can destroy', function() {
|
||||
markActiveColumns.destroy();
|
||||
deepEqual(markActiveColumns.initialized, false, 'not initialised');
|
||||
});
|
||||
test('Can reset', function() {
|
||||
markActiveColumns.reset();
|
||||
deepEqual(markActiveColumns.enabled, true, 'enabled');
|
||||
});
|
||||
test('Can disable', function() {
|
||||
markActiveColumns.disable();
|
||||
deepEqual(markActiveColumns.enabled, false, 'disabled');
|
||||
});
|
||||
test('Can enable', function() {
|
||||
markActiveColumns.enable();
|
||||
deepEqual(markActiveColumns.enabled, true, 'enabled');
|
||||
});
|
||||
test('Can init', function() {
|
||||
markActiveColumns.destroy();
|
||||
markActiveColumns.enable();
|
||||
markActiveColumns.init();
|
||||
deepEqual(markActiveColumns.enabled, true, 'enabled');
|
||||
});
|
||||
test('Can check is enabled', function() {
|
||||
markActiveColumns.isEnabled();
|
||||
deepEqual(markActiveColumns.enabled, true, 'enabled');
|
||||
});
|
||||
|
||||
module('Behaviour');
|
||||
test('Active columns', function() {
|
||||
tf.setFilterValue(1, 'Bri');
|
||||
tf.setFilterValue(3, '>2');
|
||||
|
@ -28,6 +88,59 @@
|
|||
'Active filter indicator');
|
||||
});
|
||||
|
||||
test('can highlight column cells', function() {
|
||||
// setup
|
||||
tf.clearFilters();
|
||||
var markActiveColumns = tf.feature('markActiveColumns');
|
||||
markActiveColumns.highlightColumn = true;
|
||||
|
||||
// act
|
||||
tf.setFilterValue(3, '>2');
|
||||
tf.filter();
|
||||
|
||||
// assert
|
||||
deepEqual(tf.dom().rows[6].cells[3].className,
|
||||
markActiveColumns.cellCssClass, 'cell has expected css class');
|
||||
deepEqual(
|
||||
tf.dom()
|
||||
.querySelectorAll('.' + markActiveColumns.cellCssClass).length,
|
||||
7,
|
||||
'number of highlighted column cells'
|
||||
);
|
||||
});
|
||||
|
||||
test('can unhighlight column cells', function() {
|
||||
// act
|
||||
tf.clearFilters();
|
||||
|
||||
// assert
|
||||
deepEqual(
|
||||
tf.dom()
|
||||
.querySelectorAll('.' + markActiveColumns.cellCssClass).length,
|
||||
0,
|
||||
'number of highlighted column cells'
|
||||
);
|
||||
|
||||
markActiveColumns.highlightColumn = false;
|
||||
});
|
||||
|
||||
test('cannot initialiase if already initialised', function() {
|
||||
// setup
|
||||
var hit = 0;
|
||||
var emitterOn = markActiveColumns.emitter.on;
|
||||
markActiveColumns.emitter.on = function() {
|
||||
hit++;
|
||||
};
|
||||
|
||||
// act
|
||||
markActiveColumns.init();
|
||||
|
||||
// assert
|
||||
deepEqual(hit, 0, 'init exited');
|
||||
|
||||
markActiveColumns.emitter.on = emitterOn;
|
||||
});
|
||||
|
||||
test('Active columns with paging', function() {
|
||||
tf.destroy();
|
||||
tf = null;
|
||||
|
@ -76,8 +189,130 @@
|
|||
header3.className.indexOf('activeHeader') !== -1,
|
||||
true,
|
||||
'Active filter indicator');
|
||||
});
|
||||
|
||||
test('Cannot destroy if not initialised', function() {
|
||||
// setup
|
||||
var clearActiveColumns = markActiveColumns.clearActiveColumns;
|
||||
var hit = 0;
|
||||
markActiveColumns.clearActiveColumns = function() { hit++; };
|
||||
markActiveColumns.initialized = false;
|
||||
|
||||
// act
|
||||
markActiveColumns.destroy();
|
||||
|
||||
// assert
|
||||
deepEqual(hit, 0, 'clearActiveColumns not called');
|
||||
|
||||
markActiveColumns.clearActiveColumns = clearActiveColumns;
|
||||
});
|
||||
|
||||
module('Callbacks');
|
||||
test('Can trigger onBeforeActiveColumn callback', function() {
|
||||
// setup
|
||||
var colIndex;
|
||||
markActiveColumns.onBeforeActiveColumn = function(feature, colIdx) {
|
||||
colIndex = colIdx;
|
||||
};
|
||||
|
||||
// act
|
||||
markActiveColumns.markActiveColumn(2);
|
||||
|
||||
// assert
|
||||
deepEqual(colIndex, 2,
|
||||
'expected column index passed to onBeforeActiveColumn');
|
||||
});
|
||||
|
||||
test('Can trigger onAfterActiveColumn callback', function() {
|
||||
// setup
|
||||
var colIndex;
|
||||
markActiveColumns.onAfterActiveColumn = function(feature, colIdx) {
|
||||
colIndex = colIdx;
|
||||
};
|
||||
|
||||
// act
|
||||
markActiveColumns.markActiveColumn(3);
|
||||
|
||||
// assert
|
||||
deepEqual(colIndex, 3,
|
||||
'expected column index passed to onAfterActiveColumn');
|
||||
});
|
||||
|
||||
module('mark_active_columns as configuration object');
|
||||
test('Sanity checks', function() {
|
||||
tf.destroy();
|
||||
var hit = 0;
|
||||
tf = new TableFilter('demo', {
|
||||
base_path: '../dist/tablefilter/',
|
||||
mark_active_columns: {
|
||||
header_css_class: 'myCssClass',
|
||||
on_before_active_column: function(feature, colIndex) {
|
||||
hit = colIndex;
|
||||
},
|
||||
on_after_active_column: function(feature, colIndex) {
|
||||
hit = colIndex;
|
||||
}
|
||||
}
|
||||
});
|
||||
tf.init();
|
||||
var markActiveColumns = tf.feature('markActiveColumns');
|
||||
|
||||
deepEqual(tf instanceof TableFilter, true, 'TableFilter instanciated');
|
||||
notEqual(markActiveColumns, null, 'markActiveColumns instanciated');
|
||||
deepEqual(tf.markActiveColumns, true, 'markActiveColumns property');
|
||||
|
||||
test('Custom header CSS class', function() {
|
||||
// setup
|
||||
tf.setFilterValue(1, 'Bri');
|
||||
tf.setFilterValue(3, '>2');
|
||||
var header1 = tf.getHeaderElement(1);
|
||||
var header3 = tf.getHeaderElement(3);
|
||||
|
||||
// act
|
||||
tf.filter();
|
||||
|
||||
// assert
|
||||
deepEqual(
|
||||
header1.className.indexOf('myCssClass') !== -1,
|
||||
true,
|
||||
'Active filter indicator');
|
||||
deepEqual(
|
||||
header3.className.indexOf('myCssClass') !== -1,
|
||||
true,
|
||||
'Active filter indicator');
|
||||
});
|
||||
|
||||
test('on_before_active_column callback', function() {
|
||||
// setup
|
||||
tf.clearFilters();
|
||||
tf.setFilterValue(1, 'Bri');
|
||||
|
||||
// act
|
||||
tf.filter();
|
||||
|
||||
// assert
|
||||
deepEqual(hit, 1,
|
||||
'expected column index passed to on_before_active_column');
|
||||
});
|
||||
|
||||
test('on_after_active_column callback', function() {
|
||||
// setup
|
||||
tf.clearFilters();
|
||||
tf.setFilterValue(3, '>2');
|
||||
|
||||
// act
|
||||
tf.filter();
|
||||
|
||||
// assert
|
||||
deepEqual(hit, 3,
|
||||
'expected column index passed to on_after_active_column');
|
||||
});
|
||||
|
||||
module('Tear-down');
|
||||
test('can destroy', function() {
|
||||
tf.destroy();
|
||||
deepEqual(tf.isInitialized(), false, 'Filters removed');
|
||||
});
|
||||
});
|
||||
|
||||
})(window, TableFilter);
|
||||
|
|
|
@ -4,7 +4,7 @@ var tf = new TableFilter('demo', {
|
|||
alternate_rows: true
|
||||
});
|
||||
tf.init();
|
||||
var tbl = tf.tbl;
|
||||
var tbl = tf.dom();
|
||||
var altRows = tf.feature('alternateRows');
|
||||
|
||||
module('Sanity checks');
|
||||
|
@ -91,8 +91,8 @@ test('Clear filters', function() {
|
|||
tf.clearFilters();
|
||||
tf.filter();
|
||||
|
||||
deepEqual(tbl.querySelectorAll('tr.odd').length, 3, 'Odd bgs removed');
|
||||
deepEqual(tbl.querySelectorAll('tr.even').length, 4, 'Even bg removed');
|
||||
deepEqual(tbl.querySelectorAll('tr.odd').length, 4, 'Odd bgs removed');
|
||||
deepEqual(tbl.querySelectorAll('tr.even').length, 3, 'Even bg removed');
|
||||
});
|
||||
|
||||
test('Set background on a row', function() {
|
||||
|
@ -110,7 +110,7 @@ test('Cannot init if initialised', function() {
|
|||
// setup
|
||||
var processAll = altRows.processAll;
|
||||
var hit = 0;
|
||||
altRows.processAll = function() { hit++ };
|
||||
altRows.processAll = function() { hit++; };
|
||||
altRows.initialized = true;
|
||||
|
||||
// act
|
||||
|
@ -126,7 +126,7 @@ test('Cannot processAll if not enabled', function() {
|
|||
// setup
|
||||
var setRowBg = altRows.setRowBg;
|
||||
var hit = 0;
|
||||
altRows.setRowBg = function() { hit++ };
|
||||
altRows.setRowBg = function() { hit++; };
|
||||
altRows.enabled = false;
|
||||
|
||||
// act
|
||||
|
@ -142,7 +142,7 @@ test('Cannot setRowBg if not enabled', function() {
|
|||
// setup
|
||||
var removeRowBg = altRows.removeRowBg;
|
||||
var hit = 0;
|
||||
altRows.removeRowBg = function() { hit++ };
|
||||
altRows.removeRowBg = function() { hit++; };
|
||||
altRows.enabled = false;
|
||||
|
||||
// act
|
||||
|
@ -171,7 +171,7 @@ test('Cannot destroy if not initialised', function() {
|
|||
// setup
|
||||
var getRowsNb = altRows.tf.getRowsNb;
|
||||
var hit = 0;
|
||||
altRows.tf.getRowsNb = function() { hit++ };
|
||||
altRows.tf.getRowsNb = function() { hit++; };
|
||||
altRows.initialized = false;
|
||||
|
||||
// act
|
||||
|
@ -242,42 +242,6 @@ test('Can handle `row-paged` event', function() {
|
|||
altRows.processRow = processRow;
|
||||
});
|
||||
|
||||
test('Can handle `column-sorted` event', function() {
|
||||
// setup
|
||||
var processAll = altRows.processAll;
|
||||
var hit = 0;
|
||||
altRows.processAll = function() {
|
||||
hit++;
|
||||
};
|
||||
|
||||
// act
|
||||
altRows.init();
|
||||
tf.emitter.emit('column-sorted');
|
||||
|
||||
// assert
|
||||
deepEqual(hit, 1, 'processAll called');
|
||||
|
||||
altRows.processAll = processAll;
|
||||
});
|
||||
|
||||
test('Can handle `rows-changed` event', function() {
|
||||
// setup
|
||||
var processAll = altRows.processAll;
|
||||
var hit = 0;
|
||||
altRows.processAll = function() {
|
||||
hit++;
|
||||
};
|
||||
|
||||
// act
|
||||
altRows.init();
|
||||
tf.emitter.emit('rows-changed');
|
||||
|
||||
// assert
|
||||
deepEqual(hit, 1, 'processAll called');
|
||||
|
||||
altRows.processAll = processAll;
|
||||
});
|
||||
|
||||
module('Grid layout');
|
||||
test('Grid layout: initialising alternating rows', function() {
|
||||
tf.destroy();
|
||||
|
@ -288,13 +252,13 @@ test('Grid layout: initialising alternating rows', function() {
|
|||
alternate_rows: true
|
||||
});
|
||||
tf.init();
|
||||
tbl = tf.tbl;
|
||||
tbl = tf.dom();
|
||||
altRows = tf.feature('alternateRows');
|
||||
|
||||
deepEqual(
|
||||
tbl.querySelectorAll('tr.odd').length, 4, 'Expected bg for odd rows');
|
||||
tbl.querySelectorAll('tr.odd').length, 4, 'Expected bg for odd rows');
|
||||
deepEqual(
|
||||
tbl.querySelectorAll('tr.even').length, 3, 'Expected bg for even rows');
|
||||
tbl.querySelectorAll('tr.even').length, 3, 'Expected bg for even rows');
|
||||
});
|
||||
|
||||
test('Grid layout: filter column', function() {
|
||||
|
@ -309,8 +273,8 @@ test('Grid layout: clear filters', function() {
|
|||
tf.clearFilters();
|
||||
tf.filter();
|
||||
|
||||
deepEqual(tbl.querySelectorAll('tr.odd').length, 3, 'Odd bgs removed');
|
||||
deepEqual(tbl.querySelectorAll('tr.even').length, 4, 'Even bg removed');
|
||||
deepEqual(tbl.querySelectorAll('tr.odd').length, 4, 'Odd bgs removed');
|
||||
deepEqual(tbl.querySelectorAll('tr.even').length, 3, 'Even bg removed');
|
||||
});
|
||||
|
||||
test('Grid layout: set background on a row', function() {
|
||||
|
@ -352,7 +316,7 @@ test('Sort: alternating rows with column sorted at start', function() {
|
|||
deepEqual(altRows.oddCss, 'odd', 'Expected odd css class');
|
||||
|
||||
function checkAlternateRows(tf) {
|
||||
tbl = tf.tbl;
|
||||
tbl = tf.dom();
|
||||
altRows = tf.feature('alternateRows');
|
||||
|
||||
test('Alternate rows with sort column at start option', function() {
|
||||
|
|
|
@ -1,115 +0,0 @@
|
|||
(function(win, TableFilter){
|
||||
var tf = new TableFilter('demo', {
|
||||
base_path: '../dist/tablefilter/',
|
||||
rows_always_visible: [4, 9]
|
||||
});
|
||||
tf.init();
|
||||
|
||||
module('Sanity checks');
|
||||
test('Always visible rows', function() {
|
||||
deepEqual(tf instanceof TableFilter, true, 'TableFilter type');
|
||||
deepEqual(tf.hasVisibleRows, true, 'Contains always visible rows');
|
||||
});
|
||||
|
||||
module('Behaviour');
|
||||
test('for filtered table', function() {
|
||||
tf.setFilterValue(0, 'Hello');
|
||||
tf.filter();
|
||||
var alwaysVisibleRow1 = tf.tbl.rows[4];
|
||||
var alwaysVisibleRow2 = tf.tbl.rows[9];
|
||||
deepEqual(
|
||||
tf.getRowDisplay(alwaysVisibleRow1),
|
||||
'',
|
||||
'Row display for alwaysVisibleRow1'
|
||||
);
|
||||
deepEqual(
|
||||
tf.getRowDisplay(alwaysVisibleRow2),
|
||||
'',
|
||||
'Row display for alwaysVisibleRow2'
|
||||
);
|
||||
});
|
||||
|
||||
test('after filters are cleared', function() {
|
||||
tf.clearFilters();
|
||||
var alwaysVisibleRow1 = tf.tbl.rows[4];
|
||||
var alwaysVisibleRow2 = tf.tbl.rows[9];
|
||||
deepEqual(
|
||||
tf.getRowDisplay(alwaysVisibleRow1),
|
||||
'',
|
||||
'Row display for alwaysVisibleRow1'
|
||||
);
|
||||
deepEqual(
|
||||
tf.getRowDisplay(alwaysVisibleRow2),
|
||||
'',
|
||||
'Row display for alwaysVisibleRow2'
|
||||
);
|
||||
|
||||
testPaging();
|
||||
});
|
||||
|
||||
function testPaging(){
|
||||
tf.destroy();
|
||||
tf = new TableFilter('demo', {
|
||||
base_path: '../dist/tablefilter/',
|
||||
rows_always_visible: [4, 9],
|
||||
paging: true,
|
||||
paging_length: 2
|
||||
});
|
||||
tf.init();
|
||||
var paging = tf.feature('paging');
|
||||
|
||||
module('Behaviour with paging');
|
||||
test('for filtered table', function() {
|
||||
tf.setFilterValue(0, 'Hello');
|
||||
tf.filter();
|
||||
var alwaysVisibleRow1 = tf.tbl.rows[4];
|
||||
var alwaysVisibleRow2 = tf.tbl.rows[9];
|
||||
deepEqual(
|
||||
tf.getRowDisplay(alwaysVisibleRow1),
|
||||
'',
|
||||
'Row display for alwaysVisibleRow1'
|
||||
);
|
||||
deepEqual(
|
||||
tf.getRowDisplay(alwaysVisibleRow2),
|
||||
'',
|
||||
'Row display for alwaysVisibleRow2'
|
||||
);
|
||||
});
|
||||
|
||||
test('after filters are cleared', function() {
|
||||
tf.clearFilters();
|
||||
var alwaysVisibleRow1 = tf.tbl.rows[4];
|
||||
var alwaysVisibleRow2 = tf.tbl.rows[9];
|
||||
deepEqual(
|
||||
tf.getRowDisplay(alwaysVisibleRow1),
|
||||
'none',
|
||||
'Row display for alwaysVisibleRow1'
|
||||
);
|
||||
deepEqual(
|
||||
tf.getRowDisplay(alwaysVisibleRow2),
|
||||
'none',
|
||||
'Row display for alwaysVisibleRow2'
|
||||
);
|
||||
});
|
||||
|
||||
|
||||
test('after changing pagination page', function() {
|
||||
paging.setPage(2);
|
||||
var alwaysVisibleRow1 = tf.tbl.rows[4];
|
||||
var alwaysVisibleRow2 = tf.tbl.rows[9];
|
||||
deepEqual(
|
||||
tf.getRowDisplay(alwaysVisibleRow1),
|
||||
'',
|
||||
'Row display for alwaysVisibleRow1'
|
||||
);
|
||||
deepEqual(
|
||||
tf.getRowDisplay(alwaysVisibleRow2),
|
||||
'none',
|
||||
'Row display for alwaysVisibleRow2'
|
||||
);
|
||||
|
||||
tf.destroy();
|
||||
});
|
||||
}
|
||||
|
||||
})(window, TableFilter);
|
235
test/test-api.js
235
test/test-api.js
|
@ -14,6 +14,14 @@ var tf1 = new TableFilter('demo1', {
|
|||
on_loaded: colsVisibilityTests
|
||||
}]
|
||||
});
|
||||
|
||||
tf1.registerExtension(
|
||||
{
|
||||
init: function() {},
|
||||
destroy: function() {}
|
||||
},
|
||||
'myExtension'
|
||||
);
|
||||
tf1.init();
|
||||
|
||||
module('Sanity checks');
|
||||
|
@ -28,6 +36,7 @@ test('TableFilter object', function() {
|
|||
deepEqual(tf.getFilterId(0), 'flt0_demo', 'Filter DOM element id');
|
||||
deepEqual(tf.getStartRowIndex(), 2, 'Start of filterable rows');
|
||||
deepEqual(tf.getLastRowIndex(), 8, 'Last row index');
|
||||
deepEqual(tf.dom().nodeName, 'TABLE', 'Working DOM element type');
|
||||
deepEqual(
|
||||
tf.getHeadersText(),
|
||||
[
|
||||
|
@ -42,7 +51,7 @@ test('TableFilter object', function() {
|
|||
);
|
||||
deepEqual(tf.getValidRowsNb(), 0, 'Number of valid rows before filtering');
|
||||
deepEqual(
|
||||
tf.getCellData(tf.tbl.rows[3].cells[2]),
|
||||
tf.getCellData(tf.dom().rows[3].cells[2]),
|
||||
982,
|
||||
'getCellData returns typed value'
|
||||
);
|
||||
|
@ -128,6 +137,21 @@ test('Activate filter for a specified column', function() {
|
|||
deepEqual(tf.getActiveFilterId(), filterId, 'Filter active');
|
||||
});
|
||||
|
||||
test('Activate filter not called if colIndex not a number', function() {
|
||||
//set
|
||||
var originalSetActiveFilterId = tf.setActiveFilterId;
|
||||
var hit = 0;
|
||||
tf.setActiveFilterId = function() { hit++; };
|
||||
|
||||
//act
|
||||
tf.activateFilter(undefined);
|
||||
|
||||
//assert
|
||||
deepEqual(hit, 0, 'setActiveFilterId never called');
|
||||
|
||||
tf.setActiveFilterId = originalSetActiveFilterId;
|
||||
});
|
||||
|
||||
test('Clear filters', function() {
|
||||
tf.clearFilters();
|
||||
deepEqual(tf.getValidRowsNb(), 7, 'Filtered rows number');
|
||||
|
@ -140,6 +164,27 @@ test('Can get feature', function() {
|
|||
deepEqual(feature.feature, 'help', 'Feature name');
|
||||
});
|
||||
|
||||
test('can iterate columns', function() {
|
||||
// setup
|
||||
var counter = [];
|
||||
|
||||
// act
|
||||
tf.eachCol(
|
||||
function(idx) {
|
||||
counter.push(idx);
|
||||
},
|
||||
function(idx) {
|
||||
return idx === 2;
|
||||
},
|
||||
function(idx) {
|
||||
return idx === 4;
|
||||
}
|
||||
);
|
||||
|
||||
// assert
|
||||
deepEqual(counter, [0, 1, 3], 'column iterator conditions met');
|
||||
});
|
||||
|
||||
test('Get table data', function() {
|
||||
deepEqual(tf.getColValues(0),
|
||||
[
|
||||
|
@ -204,7 +249,7 @@ test('Get table data', function() {
|
|||
tf.setFilterValue(0, 'Adelaide');
|
||||
tf.filter();
|
||||
deepEqual(
|
||||
tf.getFilteredData(),
|
||||
tf.getFilteredValues(),
|
||||
[
|
||||
[6, ['Adelaide','Perth','2781','3.1','38']],
|
||||
[7, ['Adelaide','Alice Springs','1533','2','20.25']],
|
||||
|
@ -213,7 +258,7 @@ test('Get table data', function() {
|
|||
'Get filtered table data'
|
||||
);
|
||||
deepEqual(
|
||||
tf.getFilteredData(true),
|
||||
tf.getFilteredValues(true),
|
||||
[
|
||||
[1, ['From','Destination','Road Distance (km)',
|
||||
'By Air (hrs)','By Rail (hrs)']],
|
||||
|
@ -221,10 +266,10 @@ test('Get table data', function() {
|
|||
[7, ['Adelaide','Alice Springs','1533','2','20.25']],
|
||||
[8, ['Adelaide','Brisbane','2045','2.15','40']]
|
||||
],
|
||||
'Get filtered table data including columns headers'
|
||||
'Get filtered table values including columns headers'
|
||||
);
|
||||
deepEqual(
|
||||
tf.getFilteredData(false, false, true),
|
||||
tf.getFilteredData(),
|
||||
[
|
||||
[6, ['Adelaide','Perth',2781,3.1,38]],
|
||||
[7, ['Adelaide','Alice Springs',1533,2,20.25]],
|
||||
|
@ -247,6 +292,46 @@ test('Get table data', function() {
|
|||
[2781,1533,2045],
|
||||
'Get specified column filtered typed values'
|
||||
);
|
||||
deepEqual(
|
||||
tf.getFilteredColumnData(2),
|
||||
[2781,1533,2045],
|
||||
'Get filtered column data'
|
||||
);
|
||||
deepEqual(
|
||||
tf.getFilteredColumnData(2, true),
|
||||
['Road Distance (km)',2781,1533,2045],
|
||||
'Get filtered column data with headers'
|
||||
);
|
||||
deepEqual(
|
||||
tf.getVisibleColumnData(2),
|
||||
[2781,1533,2045],
|
||||
'Get visible column data'
|
||||
);
|
||||
deepEqual(
|
||||
tf.getVisibleColumnData(2, true),
|
||||
['Road Distance (km)',2781,1533,2045],
|
||||
'Get visible column data with headers'
|
||||
);
|
||||
deepEqual(
|
||||
tf.getFilteredColumnValues(2),
|
||||
['2781','1533','2045'],
|
||||
'Get filtered column data'
|
||||
);
|
||||
deepEqual(
|
||||
tf.getFilteredColumnValues(2, true),
|
||||
['Road Distance (km)','2781','1533','2045'],
|
||||
'Get filtered column data with headers'
|
||||
);
|
||||
deepEqual(
|
||||
tf.getVisibleColumnValues(2),
|
||||
['2781','1533','2045'],
|
||||
'Get visible column data'
|
||||
);
|
||||
deepEqual(
|
||||
tf.getVisibleColumnValues(2, true),
|
||||
['Road Distance (km)','2781','1533','2045'],
|
||||
'Get visible column data with headers'
|
||||
);
|
||||
tf.clearFilters();
|
||||
tf.filter();
|
||||
});
|
||||
|
@ -264,7 +349,8 @@ test('Test filter types', function() {
|
|||
base_path: '../dist/tablefilter/',
|
||||
col_0: 'select',
|
||||
col_1: 'multiple',
|
||||
col_2: 'checklist'
|
||||
col_2: 'checklist',
|
||||
col_types: ['string', 'string', 'number', 'number', 'number']
|
||||
});
|
||||
tf.init();
|
||||
|
||||
|
@ -338,17 +424,28 @@ test('Can select checklist options with array', function() {
|
|||
tf.setFilterValue(2, '');
|
||||
tf.setFilterValue(2, ['1412', '982']);
|
||||
|
||||
deepEqual(tf.getFilterValue(2), ['1412', '982'],
|
||||
deepEqual(tf.getFilterValue(2), ['982', '1412'],
|
||||
'Column 2 filter values');
|
||||
});
|
||||
|
||||
test('get and set filter value can handle out of range column index',
|
||||
function() {
|
||||
// act
|
||||
tf.setFilterValue(11, '');
|
||||
|
||||
// assert
|
||||
deepEqual(tf.getFilterValue(11), '',
|
||||
'return empty string for inexistent filter');
|
||||
});
|
||||
|
||||
module('TableFilter with pop-up filters');
|
||||
test('Sanity checks', function() {
|
||||
tf.destroy();
|
||||
tf = null;
|
||||
tf = new TableFilter('demo', {
|
||||
base_path: '../dist/tablefilter/',
|
||||
popup_filters: true
|
||||
popup_filters: true,
|
||||
col_types: ['string', 'string', 'number', 'number', 'number']
|
||||
});
|
||||
tf.init();
|
||||
|
||||
|
@ -396,7 +493,8 @@ test('Sanity checks', function() {
|
|||
grid_layout: true,
|
||||
col_0: 'select',
|
||||
col_1: 'multiple',
|
||||
col_2: 'checklist'
|
||||
col_2: 'checklist',
|
||||
col_types: ['string', 'string', 'number', 'number', 'number']
|
||||
});
|
||||
tf.init();
|
||||
|
||||
|
@ -456,6 +554,28 @@ test('Get table data', function() {
|
|||
],
|
||||
'Get specified column values including column header'
|
||||
);
|
||||
deepEqual(tf.getColumnValues(0),
|
||||
[
|
||||
'Sydney','Sydney','Sydney',
|
||||
'Sydney','Adelaide','Adelaide','Adelaide'
|
||||
],
|
||||
'Get specified column values'
|
||||
);
|
||||
deepEqual(tf.getColumnValues(0, true),
|
||||
[
|
||||
'From','Sydney','Sydney','Sydney',
|
||||
'Sydney','Adelaide','Adelaide','Adelaide'
|
||||
],
|
||||
'Get specified column values including column header'
|
||||
);
|
||||
deepEqual(tf.getColumnData(2),
|
||||
[1412, 982, 286, 872, 2781, 1533, 2045],
|
||||
'Get specified column data'
|
||||
);
|
||||
deepEqual(tf.getColumnData(2, true),
|
||||
['Road Distance (km)', 1412, 982, 286, 872, 2781, 1533, 2045],
|
||||
'Get specified column data including column header'
|
||||
);
|
||||
deepEqual(
|
||||
tf.getTableData(),
|
||||
[
|
||||
|
@ -467,22 +587,49 @@ test('Get table data', function() {
|
|||
[5, ['Adelaide','Alice Springs','1533','2','20.25']],
|
||||
[6, ['Adelaide','Brisbane','2045','2.15','40']]
|
||||
],
|
||||
'Get table values with getTableData()'
|
||||
);
|
||||
deepEqual(
|
||||
tf.getData(),
|
||||
[
|
||||
[0, ['Sydney','Adelaide',1412,1.4,25.3]],
|
||||
[1, ['Sydney','Brisbane',982,1.5,16]],
|
||||
[2, ['Sydney','Canberra',286,0.6,4.3]],
|
||||
[3, ['Sydney','Melbourne',872,1.1,10.5]],
|
||||
[4, ['Adelaide','Perth',2781,3.1,38]],
|
||||
[5, ['Adelaide','Alice Springs',1533,2,20.25]],
|
||||
[6, ['Adelaide','Brisbane',2045,2.15,40]]
|
||||
],
|
||||
'Get table data'
|
||||
);
|
||||
deepEqual(
|
||||
tf.getValues(),
|
||||
[
|
||||
[0, ['Sydney','Adelaide','1412','1.4','25.3']],
|
||||
[1, ['Sydney','Brisbane','982','1.5','16']],
|
||||
[2, ['Sydney','Canberra','286','.6','4.3']],
|
||||
[3, ['Sydney','Melbourne','872','1.1','10.5']],
|
||||
[4, ['Adelaide','Perth','2781','3.1','38']],
|
||||
[5, ['Adelaide','Alice Springs','1533','2','20.25']],
|
||||
[6, ['Adelaide','Brisbane','2045','2.15','40']]
|
||||
],
|
||||
'Get table values'
|
||||
);
|
||||
|
||||
tf.clearFilters();
|
||||
tf.setFilterValue(0, 'Adelaide');
|
||||
tf.filter();
|
||||
deepEqual(
|
||||
tf.getFilteredData(),
|
||||
tf.getFilteredValues(),
|
||||
[
|
||||
[4, ['Adelaide','Perth','2781','3.1','38']],
|
||||
[5, ['Adelaide','Alice Springs','1533','2','20.25']],
|
||||
[6, ['Adelaide','Brisbane','2045','2.15','40']]
|
||||
],
|
||||
'Get filtered table data'
|
||||
'Get filtered table values'
|
||||
);
|
||||
deepEqual(
|
||||
tf.getFilteredData(true),
|
||||
tf.getFilteredValues(true),
|
||||
[
|
||||
[0, ['From','Destination','Road Distance (km)',
|
||||
'By Air (hrs)','By Rail (hrs)']],
|
||||
|
@ -490,7 +637,7 @@ test('Get table data', function() {
|
|||
[5, ['Adelaide','Alice Springs','1533','2','20.25']],
|
||||
[6, ['Adelaide','Brisbane','2045','2.15','40']]
|
||||
],
|
||||
'Get filtered table data including columns headers'
|
||||
'Get filtered table values including columns headers'
|
||||
);
|
||||
deepEqual(
|
||||
tf.getFilteredDataCol(0),
|
||||
|
@ -502,6 +649,46 @@ test('Get table data', function() {
|
|||
['From','Adelaide','Adelaide','Adelaide'],
|
||||
'Get specified column filtered values including header'
|
||||
);
|
||||
deepEqual(
|
||||
tf.getFilteredColumnData(2),
|
||||
[2781,1533,2045],
|
||||
'Get filtered column data'
|
||||
);
|
||||
deepEqual(
|
||||
tf.getFilteredColumnData(2, true),
|
||||
['Road Distance (km)',2781,1533,2045],
|
||||
'Get filtered column data with headers'
|
||||
);
|
||||
deepEqual(
|
||||
tf.getVisibleColumnData(2),
|
||||
[2781,1533,2045],
|
||||
'Get visible column data'
|
||||
);
|
||||
deepEqual(
|
||||
tf.getVisibleColumnData(2, true),
|
||||
['Road Distance (km)',2781,1533,2045],
|
||||
'Get visible column data with headers'
|
||||
);
|
||||
deepEqual(
|
||||
tf.getFilteredColumnValues(2),
|
||||
['2781','1533','2045'],
|
||||
'Get filtered column data'
|
||||
);
|
||||
deepEqual(
|
||||
tf.getFilteredColumnValues(2, true),
|
||||
['Road Distance (km)','2781','1533','2045'],
|
||||
'Get filtered column data with headers'
|
||||
);
|
||||
deepEqual(
|
||||
tf.getVisibleColumnValues(2),
|
||||
['2781','1533','2045'],
|
||||
'Get visible column data'
|
||||
);
|
||||
deepEqual(
|
||||
tf.getVisibleColumnValues(2, true),
|
||||
['Road Distance (km)','2781','1533','2045'],
|
||||
'Get visible column data with headers'
|
||||
);
|
||||
tf.clearFilters();
|
||||
tf.filter();
|
||||
});
|
||||
|
@ -520,24 +707,24 @@ function colsVisibilityTests() { // issue 94
|
|||
tf1.filter();
|
||||
|
||||
deepEqual(
|
||||
tf1.getFilteredData(false, true),
|
||||
tf1.getFilteredValues(false, true),
|
||||
[
|
||||
[6, ['Adelaide','3.1','38']],
|
||||
[7, ['Adelaide','2','20.25']],
|
||||
[8, ['Adelaide','2.15','40']]
|
||||
],
|
||||
'Get filtered table data with excluded columns'
|
||||
'Get filtered table values with excluded columns'
|
||||
);
|
||||
|
||||
deepEqual(
|
||||
tf1.getFilteredData(true, true),
|
||||
tf1.getFilteredValues(true, true),
|
||||
[
|
||||
[1, ['From','By Air (hrs)','By Rail (hrs)']],
|
||||
[6, ['Adelaide','3.1','38']],
|
||||
[7, ['Adelaide','2','20.25']],
|
||||
[8, ['Adelaide','2.15','40']]
|
||||
],
|
||||
'Get filtered table data with headers and excluded columns'
|
||||
'Get filtered table values with headers and excluded columns'
|
||||
);
|
||||
|
||||
deepEqual(
|
||||
|
@ -586,6 +773,20 @@ function colsVisibilityTests() { // issue 94
|
|||
|
||||
});
|
||||
|
||||
test('Extension Sanity checks', function() {
|
||||
deepEqual(
|
||||
tf1.hasExtension('colsVisibility'),
|
||||
true,
|
||||
'ColsVisibility in extensions registry'
|
||||
);
|
||||
|
||||
deepEqual(
|
||||
tf1.hasExtension('myExtension'),
|
||||
true,
|
||||
'myExtension in extensions registry'
|
||||
);
|
||||
});
|
||||
|
||||
test('Destroy', function() {
|
||||
tf1.destroy();
|
||||
deepEqual(tf1.isInitialized(), false, 'Filters removed');
|
||||
|
|
|
@ -2,8 +2,9 @@
|
|||
|
||||
var tf = new TableFilter('demo', {
|
||||
base_path: '../dist/tablefilter/',
|
||||
auto_filter: true,
|
||||
auto_filter_delay: 1000
|
||||
auto_filter: {
|
||||
delay: 1000
|
||||
}
|
||||
});
|
||||
tf.init();
|
||||
window.tf = tf;
|
||||
|
@ -14,6 +15,18 @@
|
|||
deepEqual(tf.autoFilter, true, 'Auto filtering enabled');
|
||||
deepEqual(tf.autoFilterDelay, 1000, 'Expected filtering delay');
|
||||
});
|
||||
test('Blur input filter', function() {
|
||||
// setup
|
||||
var filter = tf.getFilterElement(0);
|
||||
filter.focus();
|
||||
|
||||
// act
|
||||
filter.blur();
|
||||
|
||||
// assert
|
||||
deepEqual(tf.isUserTyping, false, 'User not typing');
|
||||
deepEqual(tf.autoFilterTimer, null, 'Auto filter timer cleared');
|
||||
});
|
||||
|
||||
module('Remove feature');
|
||||
test('Auto filter feature disabled', function() {
|
||||
|
|
109
test/test-cell-parser.html
Normal file
109
test/test-cell-parser.html
Normal file
|
@ -0,0 +1,109 @@
|
|||
<!DOCTYPE html>
|
||||
<html>
|
||||
<head>
|
||||
<meta charset="utf-8">
|
||||
<title>TableFilter filter with cell parser</title>
|
||||
<link rel="stylesheet" href="libs/qunit/qunit.css">
|
||||
<script src="libs/qunit/qunit.js"></script>
|
||||
<script src="libs/polyfill.js"></script>
|
||||
</head>
|
||||
<body>
|
||||
<table id="demo">
|
||||
<thead>
|
||||
<tr>
|
||||
<th></th>
|
||||
<th>From</th>
|
||||
<th>Destination</th>
|
||||
<th>Road Distance (km)</th>
|
||||
<th>By Air (hrs)</th>
|
||||
<th>By Rail (hrs)</th>
|
||||
</tr>
|
||||
</thead>
|
||||
<tbody>
|
||||
<tr>
|
||||
<td>
|
||||
<input type="checkbox" disabled="disabled"
|
||||
value="" checked="checked">
|
||||
</td>
|
||||
<td><strong>Sydney</strong></td>
|
||||
<td>Adelaide</td>
|
||||
<td>1412</td>
|
||||
<td>1.4</td>
|
||||
<td>25.3</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td>
|
||||
<input type="checkbox" disabled="disabled"
|
||||
value="">
|
||||
</td>
|
||||
<td><strong>Sydney</strong></td>
|
||||
<td>Brisbane</td>
|
||||
<td>982</td>
|
||||
<td>1.5</td>
|
||||
<td>16</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td>
|
||||
<input type="checkbox" disabled="disabled"
|
||||
value="" checked="checked">
|
||||
</td>
|
||||
<td><strong>Sydney</strong></td>
|
||||
<td>Canberra</td>
|
||||
<td>286</td>
|
||||
<td>.6</td>
|
||||
<td>4.3</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td>
|
||||
<input type="checkbox" disabled="disabled"
|
||||
value="" checked="checked">
|
||||
</td>
|
||||
<td><strong>Sydney</strong></td>
|
||||
<td>Melbourne</td>
|
||||
<td>872</td>
|
||||
<td>1.1</td>
|
||||
<td>10.5</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td>
|
||||
<input type="checkbox" disabled="disabled"
|
||||
value="">
|
||||
</td>
|
||||
<td><strong>Adelaide</strong></td>
|
||||
<td>Perth</td>
|
||||
<td>2781</td>
|
||||
<td>3.1</td>
|
||||
<td>38</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td>
|
||||
<input type="checkbox" disabled="disabled"
|
||||
value="" checked="checked">
|
||||
</td>
|
||||
<td><strong>Adelaide</strong></td>
|
||||
<td>Alice Springs</td>
|
||||
<td>1533</td>
|
||||
<td>2</td>
|
||||
<td>20.25</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td>
|
||||
<input type="checkbox" disabled="disabled"
|
||||
value="">
|
||||
</td>
|
||||
<td><strong>Adelaide</strong></td>
|
||||
<td>Brisbane</td>
|
||||
<td>2045</td>
|
||||
<td>2.15</td>
|
||||
<td>40</td>
|
||||
</tr>
|
||||
</tbody>
|
||||
</table>
|
||||
|
||||
<script src="../dist/tablefilter/tablefilter.js"></script>
|
||||
<script src="test-cell-parser.js"></script>
|
||||
|
||||
<div id="qunit"></div>
|
||||
<div id="qunit-fixture"></div>
|
||||
</body>
|
||||
</html>
|
80
test/test-cell-parser.js
Normal file
80
test/test-cell-parser.js
Normal file
|
@ -0,0 +1,80 @@
|
|||
(function(win, TableFilter){
|
||||
|
||||
var tf = new TableFilter('demo', {
|
||||
base_path: '../dist/tablefilter/',
|
||||
col_0: 'select',
|
||||
cell_parser: {
|
||||
cols: [0],
|
||||
parse: function(tf, cell) {
|
||||
var chk = cell.getElementsByTagName('input')[0];
|
||||
if (chk.checked) {
|
||||
return 'yes';
|
||||
} else {
|
||||
return 'no';
|
||||
}
|
||||
}
|
||||
}
|
||||
});
|
||||
tf.init();
|
||||
|
||||
module('Sanity checks');
|
||||
test('Sanity checks', function() {
|
||||
deepEqual(tf instanceof TableFilter, true, 'TableFilter instanciated');
|
||||
deepEqual(tf.cellParser.cols.length, 1,
|
||||
'Columns implementing cell parser');
|
||||
deepEqual(typeof tf.cellParser.parse, 'function', 'Parse function');
|
||||
deepEqual(
|
||||
tf.getFilterElement(0).nodeName, 'SELECT', 'Expected filter type');
|
||||
});
|
||||
|
||||
module('Behaviour');
|
||||
test('Can filter with parsed value', function() {
|
||||
// setup
|
||||
tf.setFilterValue(0, 'yes');
|
||||
|
||||
// act
|
||||
tf.filter();
|
||||
|
||||
// assert
|
||||
deepEqual(tf.getValidRows(), [2, 4, 5, 7], 'Number of parsed values');
|
||||
});
|
||||
|
||||
test('Can parse with custom function', function() {
|
||||
// setup
|
||||
var cell = tf.dom().rows[3].cells[0];
|
||||
|
||||
// act
|
||||
var value = tf.getCellValue(cell);
|
||||
|
||||
// assert
|
||||
deepEqual(value, 'no', 'Value returned by custom cell parser');
|
||||
});
|
||||
|
||||
test('Should not parse with custom function if no columns defined',
|
||||
function() {
|
||||
// setup
|
||||
var initialCellParser = tf.cellParser;
|
||||
var hit = 0;
|
||||
var cell = tf.dom().rows[3].cells[0];
|
||||
|
||||
tf.cellParser.cols = [];
|
||||
tf.cellParser.parse = function() {
|
||||
hit++;
|
||||
};
|
||||
|
||||
// act
|
||||
tf.getCellValue(cell);
|
||||
|
||||
// assert
|
||||
deepEqual(hit, 0, 'Cell parser not invoked');
|
||||
|
||||
tf.cellParser = initialCellParser;
|
||||
}
|
||||
);
|
||||
|
||||
module('Tear-down');
|
||||
test('can destroy', function() {
|
||||
tf.destroy();
|
||||
deepEqual(tf.isInitialized(), false, 'Filters removed');
|
||||
});
|
||||
})(window, TableFilter);
|
|
@ -41,7 +41,7 @@ test('Can refresh all drop-down filters', function() {
|
|||
tf.clearFilters();
|
||||
var build = checkList.build;
|
||||
var hit = 0;
|
||||
checkList.build = function() { hit++ };
|
||||
checkList.build = function() { hit++; };
|
||||
|
||||
//act
|
||||
checkList.refreshAll();
|
||||
|
@ -100,18 +100,43 @@ test('Can sort options', function() {
|
|||
tf.destroy();
|
||||
tf = new TableFilter('demo', {
|
||||
base_path: '../dist/tablefilter/',
|
||||
col_0: 'checklist',
|
||||
col_1: 'checklist',
|
||||
col_2: 'checklist',
|
||||
col_3: 'checklist',
|
||||
col_4: 'checklist',
|
||||
sort_num_asc: [2, 3],
|
||||
sort_num_desc: [4]
|
||||
col_types: ['string', 'string', 'number', 'number', 'number'],
|
||||
sort_filter_options_asc: [0, 2, 3],
|
||||
sort_filter_options_desc: [1, 4]
|
||||
});
|
||||
tf.init();
|
||||
|
||||
var flt0 = id(tf.fltIds[0]);
|
||||
var flt1 = id(tf.fltIds[1]);
|
||||
var flt2 = id(tf.fltIds[2]);
|
||||
var flt3 = id(tf.fltIds[3]);
|
||||
var flt4 = id(tf.fltIds[4]);
|
||||
|
||||
deepEqual(
|
||||
flt0.getElementsByTagName('li')[1].firstChild.firstChild.value,
|
||||
'Adelaide',
|
||||
'First option value for column 0'
|
||||
);
|
||||
deepEqual(
|
||||
flt0.getElementsByTagName('li')[2].firstChild.firstChild.value,
|
||||
'Sydney',
|
||||
'Last option value for column 0'
|
||||
);
|
||||
deepEqual(
|
||||
flt1.getElementsByTagName('li')[1].firstChild.firstChild.value,
|
||||
'Perth',
|
||||
'First option value for column 1'
|
||||
);
|
||||
deepEqual(
|
||||
flt1.getElementsByTagName('li')[6].firstChild.firstChild.value,
|
||||
'Adelaide',
|
||||
'Last option value for column 1'
|
||||
);
|
||||
deepEqual(
|
||||
flt2.getElementsByTagName('li')[1].firstChild.firstChild.value,
|
||||
'286',
|
||||
|
@ -181,6 +206,55 @@ test('Can select empty and non-empty options', function() {
|
|||
'Filter 3 options values attribute');
|
||||
});
|
||||
|
||||
// issue 714, clear filter text
|
||||
module('Clear filter text');
|
||||
test('Can define clear filter text for each column', function() {
|
||||
tf.clearFilters();
|
||||
tf.destroy();
|
||||
tf = new TableFilter('demo', {
|
||||
base_path: '../dist/tablefilter/',
|
||||
col_2: 'checklist',
|
||||
col_3: 'checklist',
|
||||
col_4: 'checklist',
|
||||
clear_filter_text: [null, null, 'clear 2', 'clear 3', 'clear 4']
|
||||
});
|
||||
tf.init();
|
||||
|
||||
var flt2 = tf.getFilterElement(2).getElementsByTagName('li');
|
||||
var flt3 = tf.getFilterElement(3).getElementsByTagName('li');
|
||||
var flt4 = tf.getFilterElement(4).getElementsByTagName('li');
|
||||
|
||||
deepEqual(flt2[0].getElementsByTagName('label')[0].innerText,
|
||||
'clear 2', 'clear text filter 2');
|
||||
deepEqual(flt3[0].getElementsByTagName('label')[0].innerText,
|
||||
'clear 3', 'clear text filter 3');
|
||||
deepEqual(flt4[0].getElementsByTagName('label')[0].innerText,
|
||||
'clear 4', 'clear text filter 4');
|
||||
});
|
||||
test('Can define clear filter text globally', function() {
|
||||
tf.clearFilters();
|
||||
tf.destroy();
|
||||
tf = new TableFilter('demo', {
|
||||
base_path: '../dist/tablefilter/',
|
||||
col_2: 'checklist',
|
||||
col_3: 'checklist',
|
||||
col_4: 'checklist',
|
||||
clear_filter_text: 'reset'
|
||||
});
|
||||
tf.init();
|
||||
|
||||
var flt2 = tf.getFilterElement(2).getElementsByTagName('li');
|
||||
var flt3 = tf.getFilterElement(3).getElementsByTagName('li');
|
||||
var flt4 = tf.getFilterElement(4).getElementsByTagName('li');
|
||||
|
||||
deepEqual(flt2[0].getElementsByTagName('label')[0].innerText,
|
||||
'reset', 'clear text filter 2');
|
||||
deepEqual(flt3[0].getElementsByTagName('label')[0].innerText,
|
||||
'reset', 'clear text filter 3');
|
||||
deepEqual(flt4[0].getElementsByTagName('label')[0].innerText,
|
||||
'reset', 'clear text filter 4');
|
||||
});
|
||||
|
||||
module('Tear down');
|
||||
test('TableFilter removed', function() {
|
||||
tf.destroy();
|
||||
|
|
|
@ -8,6 +8,7 @@
|
|||
<script src="libs/polyfill.js"></script>
|
||||
</head>
|
||||
<body>
|
||||
<div id="external-container"></div>
|
||||
<table id="demo" cellpadding="0" cellspacing="0">
|
||||
<tbody>
|
||||
<tr>
|
||||
|
@ -75,4 +76,4 @@
|
|||
<div id="qunit"></div>
|
||||
<div id="qunit-fixture"></div>
|
||||
</body>
|
||||
</html>
|
||||
</html>
|
||||
|
|
|
@ -6,6 +6,7 @@ var tf = new TableFilter('demo', {
|
|||
tf.init();
|
||||
|
||||
var clearButton = tf.feature('clearButton');
|
||||
|
||||
module('Sanity checks');
|
||||
test('Clear button component', function() {
|
||||
deepEqual(typeof clearButton, 'object', 'ClearButton instanciated');
|
||||
|
@ -58,6 +59,61 @@ test('Can check is enabled', function() {
|
|||
deepEqual(clearButton.enabled, true, 'enabled');
|
||||
});
|
||||
|
||||
module('Behaviour');
|
||||
test('Cannot init if already initialised', function() {
|
||||
// setup
|
||||
clearButton.initialized = true;
|
||||
var emit = clearButton.emitter.emit;
|
||||
var hit = 0;
|
||||
clearButton.emitter.emit = function() {
|
||||
hit++;
|
||||
};
|
||||
|
||||
// act
|
||||
clearButton.init();
|
||||
|
||||
// assert
|
||||
deepEqual(hit, 0, 'does not initialise');
|
||||
|
||||
clearButton.emitter.emit = emit;
|
||||
});
|
||||
|
||||
test('onClick does nothing if not enabled', function() {
|
||||
// setup
|
||||
clearButton.disable();
|
||||
var clearFilters = clearButton.tf.clearFilters;
|
||||
var hit = 0;
|
||||
clearButton.tf.clearFilters = function() {
|
||||
hit++;
|
||||
};
|
||||
|
||||
// act
|
||||
clearButton.onClick();
|
||||
|
||||
// assert
|
||||
deepEqual(hit, 0, 'onClick does nothing');
|
||||
|
||||
clearButton.tf.clearFilters = clearFilters;
|
||||
});
|
||||
|
||||
test('onClick calls clearFilters if enabled', function() {
|
||||
// setup
|
||||
clearButton.enable();
|
||||
var clearFilters = clearButton.tf.clearFilters;
|
||||
var hit = 0;
|
||||
clearButton.tf.clearFilters = function() {
|
||||
hit++;
|
||||
};
|
||||
|
||||
// act
|
||||
clearButton.onClick();
|
||||
|
||||
// assert
|
||||
deepEqual(hit, 1, 'onClick calls clearFilters');
|
||||
|
||||
clearButton.tf.clearFilters = clearFilters;
|
||||
});
|
||||
|
||||
module('UI elements');
|
||||
test('ClearButton UI elements', function() {
|
||||
var container = clearButton.container;
|
||||
|
@ -73,7 +129,7 @@ test('Remove UI', function() {
|
|||
deepEqual(btnResetEl, null, 'Clear button is removed');
|
||||
});
|
||||
|
||||
test('Re-set UI', function() {
|
||||
test('Re-set UI with no icons and text button', function() {
|
||||
clearButton.destroy();
|
||||
tf.enableIcons = false;
|
||||
clearButton.html = null;
|
||||
|
@ -85,6 +141,40 @@ test('Re-set UI', function() {
|
|||
deepEqual(btnResetEl.innerText, 'Clear', 'Clear button text');
|
||||
});
|
||||
|
||||
test('Destroy and init with text button and icons enabled', function() {
|
||||
tf.destroy();
|
||||
tf = new TableFilter('demo', {
|
||||
base_path: '../dist/tablefilter/',
|
||||
btn_reset: {
|
||||
text: 'Clear all'
|
||||
}
|
||||
});
|
||||
tf.init();
|
||||
|
||||
clearButton = tf.feature('clearButton');
|
||||
|
||||
var btnResetEl = clearButton.element;
|
||||
deepEqual(btnResetEl.nodeName, 'A', 'Clear button tag changed');
|
||||
deepEqual(btnResetEl.innerText, 'Clear all', 'Clear button text');
|
||||
});
|
||||
|
||||
test('Destroy and init in external container', function() {
|
||||
tf.destroy();
|
||||
tf = new TableFilter('demo', {
|
||||
base_path: '../dist/tablefilter/',
|
||||
btn_reset: {
|
||||
target_id: 'external-container'
|
||||
}
|
||||
});
|
||||
tf.init();
|
||||
|
||||
clearButton = tf.feature('clearButton');
|
||||
|
||||
deepEqual(clearButton.element.nodeName, 'INPUT', 'Clear button tag');
|
||||
deepEqual(clearButton.container.parentNode.id, 'external-container',
|
||||
'container id');
|
||||
});
|
||||
|
||||
module('Tear-down');
|
||||
test('can destroy TableFilter DOM elements', function() {
|
||||
tf.destroy();
|
||||
|
|
|
@ -6,8 +6,9 @@ var totRowIndex = table.getElementsByTagName('tr').length;
|
|||
tf = new TableFilter('demo', {
|
||||
base_path: '../dist/tablefilter/',
|
||||
col_types: ['string', 'string', 'number', 'number', 'number'],
|
||||
paging: true,
|
||||
paging_length: 4,
|
||||
paging: {
|
||||
length: 4
|
||||
},
|
||||
rows_always_visible: [
|
||||
totRowIndex-6,
|
||||
totRowIndex-5,
|
||||
|
|
|
@ -140,6 +140,61 @@ test('Can make column calculations', function() {
|
|||
deepEqual(result2, 2781, 'columnCalc max');
|
||||
});
|
||||
|
||||
test('Can make column calculations with formated results', function() {
|
||||
// setup
|
||||
var colOps = tf.extension('colOps');
|
||||
colOps.formatResults[2] = { suffix: ' Km' };
|
||||
colOps.formatResults[4] = { suffix: ' Km' };
|
||||
colOps.formatResults[6] = { suffix: ' Km' };
|
||||
tf.colTypes[2] = { type: 'formatted-number', decimal: '.', thousands: ',' };
|
||||
|
||||
// act
|
||||
colOps.calcAll();
|
||||
|
||||
// assert
|
||||
deepEqual(id('mean1').innerHTML, '1,416 Km', 'Formatted mean result');
|
||||
deepEqual(id('min1').innerHTML, '286 Km', 'Formatted min result');
|
||||
deepEqual(id('max1').innerHTML, '2,781 Km', 'Formatted max result');
|
||||
|
||||
colOps.formatResults[2] = undefined;
|
||||
colOps.formatResults[4] = undefined;
|
||||
colOps.formatResults[6] = undefined;
|
||||
tf.colTypes[2] = undefined;
|
||||
});
|
||||
|
||||
test('Can configure result format', function() {
|
||||
// setup
|
||||
var colOps = tf.extension('colOps');
|
||||
var format = { prefix: '$', suffix: '/item' };
|
||||
|
||||
// act
|
||||
var format = colOps.configureFormat(2, format);
|
||||
|
||||
// assert
|
||||
deepEqual(format.prefix, '$', 'prefix');
|
||||
deepEqual(format.suffix, '/item', 'suffix');
|
||||
deepEqual(format.decimal, '', 'decimal separator');
|
||||
deepEqual(format.integerSeparator, '', 'thousands separator');
|
||||
});
|
||||
|
||||
test('Can configure result format for formatted number column', function() {
|
||||
// setup
|
||||
var colOps = tf.extension('colOps');
|
||||
var format = { prefix: '$', suffix: '/item' };
|
||||
tf.colTypes = [null, null, null, null, null];
|
||||
tf.colTypes[3] = { type: 'formatted-number', decimal: ',', thousands: '.' };
|
||||
|
||||
// act
|
||||
var format = colOps.configureFormat(3, format);
|
||||
|
||||
// assert
|
||||
deepEqual(format.prefix, '$', 'prefix');
|
||||
deepEqual(format.suffix, '/item', 'suffix');
|
||||
deepEqual(format.decimal, ',', 'decimal separator');
|
||||
deepEqual(format.integerSeparator, '.', 'thousands separator');
|
||||
tf.colTypes[3] = undefined;
|
||||
});
|
||||
|
||||
module('Tear-down');
|
||||
test('can destroy', function() {
|
||||
tf.destroy();
|
||||
|
|
|
@ -9,10 +9,12 @@
|
|||
|
||||
module('Sanity checks');
|
||||
test('Column widths', function() {
|
||||
var cols = tf.tbl.getElementsByTagName('col');
|
||||
var cols = tf.dom().getElementsByTagName('col');
|
||||
deepEqual(tf instanceof TableFilter, true, 'TableFilter instanciated');
|
||||
deepEqual(cols[1].style.width, '100px', 'Expected column width');
|
||||
deepEqual(cols[4].style.width, '', 'Expected column width');
|
||||
deepEqual(tf.dom().style.width, '645px', 'Table width set');
|
||||
deepEqual(tf.dom().style.tableLayout, 'fixed', 'Table layout fixed');
|
||||
});
|
||||
|
||||
test('Grid layout column widths', function() {
|
||||
|
@ -20,14 +22,19 @@
|
|||
tf = null;
|
||||
tf = new TableFilter('demo', {
|
||||
base_path: '../dist/tablefilter/',
|
||||
col_widths: ['150px', '100px', '175px', '120px', '200px'],
|
||||
grid_layout: true,
|
||||
sort: false
|
||||
col_widths: ['150px', '100px', '175px', '120px', null],
|
||||
grid_layout: true
|
||||
});
|
||||
tf.init();
|
||||
var cols = tf.feature('gridLayout').headTbl.getElementsByTagName('col');
|
||||
var gridLayout = tf.feature('gridLayout');
|
||||
var cols = gridLayout.headTbl.getElementsByTagName('col');
|
||||
deepEqual(cols[0].style.width, '150px', 'Expected column width');
|
||||
deepEqual(cols[4].style.width, '200px', 'Expected column width');
|
||||
deepEqual(cols[3].style.width, '120px', 'Expected column width');
|
||||
deepEqual(
|
||||
tf.dom().style.width === gridLayout.headTbl.style.width,
|
||||
true,
|
||||
'Content and headers table have same width'
|
||||
);
|
||||
});
|
||||
|
||||
})(window, TableFilter);
|
||||
|
|
Some files were not shown because too many files have changed in this diff Show more
Loading…
Reference in a new issue