aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--.github/workflows/release.yml8
-rw-r--r--Cargo.lock306
-rw-r--r--Cargo.toml16
-rw-r--r--src/api/web.rs2
-rw-r--r--src/static/scripts/bootstrap.bundle.js10
-rw-r--r--src/static/scripts/bootstrap.css81
-rw-r--r--src/static/scripts/datatables.css350
-rw-r--r--src/static/scripts/datatables.js11303
-rw-r--r--src/static/scripts/jquery-3.7.1.slim.js (renamed from src/static/scripts/jquery-3.7.0.slim.js)48
-rw-r--r--src/static/templates/admin/organizations.hbs2
-rw-r--r--src/static/templates/admin/users.hbs2
-rwxr-xr-xtools/global_domains.py14
12 files changed, 5005 insertions, 7137 deletions
diff --git a/.github/workflows/release.yml b/.github/workflows/release.yml
index 619295d1..8063827d 100644
--- a/.github/workflows/release.yml
+++ b/.github/workflows/release.yml
@@ -229,28 +229,28 @@ jobs:
# Upload artifacts to Github Actions
- name: "Upload amd64 artifact"
- uses: actions/upload-artifact@26f96dfa697d77e81fd5907df203aa23a56210a8 # v4.3.0
+ uses: actions/upload-artifact@5d5d22a31266ced268874388b861e4b58bb5c2f3 # v4.3.1
if: ${{ matrix.base_image == 'alpine' }}
with:
name: vaultwarden-${{ env.SOURCE_VERSION }}-linux-amd64
path: vaultwarden-amd64
- name: "Upload arm64 artifact"
- uses: actions/upload-artifact@26f96dfa697d77e81fd5907df203aa23a56210a8 # v4.3.0
+ uses: actions/upload-artifact@5d5d22a31266ced268874388b861e4b58bb5c2f3 # v4.3.1
if: ${{ matrix.base_image == 'alpine' }}
with:
name: vaultwarden-${{ env.SOURCE_VERSION }}-linux-arm64
path: vaultwarden-arm64
- name: "Upload armv7 artifact"
- uses: actions/upload-artifact@26f96dfa697d77e81fd5907df203aa23a56210a8 # v4.3.0
+ uses: actions/upload-artifact@5d5d22a31266ced268874388b861e4b58bb5c2f3 # v4.3.1
if: ${{ matrix.base_image == 'alpine' }}
with:
name: vaultwarden-${{ env.SOURCE_VERSION }}-linux-armv7
path: vaultwarden-armv7
- name: "Upload armv6 artifact"
- uses: actions/upload-artifact@26f96dfa697d77e81fd5907df203aa23a56210a8 # v4.3.0
+ uses: actions/upload-artifact@5d5d22a31266ced268874388b861e4b58bb5c2f3 # v4.3.1
if: ${{ matrix.base_image == 'alpine' }}
with:
name: vaultwarden-${{ env.SOURCE_VERSION }}-linux-armv6
diff --git a/Cargo.lock b/Cargo.lock
index 0d062e35..518d8f84 100644
--- a/Cargo.lock
+++ b/Cargo.lock
@@ -19,9 +19,9 @@ checksum = "f26201604c87b1e01bd3d98f8d5d9a8fcbb815e8cedb41ffccbeb4bf593a35fe"
[[package]]
name = "ahash"
-version = "0.8.7"
+version = "0.8.9"
source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "77c3a9648d43b9cd48db467b3f87fdd6e146bcc88ab0180006cef2179fe11d01"
+checksum = "d713b3834d76b85304d4d525563c1276e2e30dc97cc67bfb4585a4a29fc2c89f"
dependencies = [
"cfg-if",
"once_cell",
@@ -104,7 +104,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "f28243a43d821d11341ab73c80bed182dc015c514b951616cf79bd4af39af0c3"
dependencies = [
"concurrent-queue",
- "event-listener 5.0.0",
+ "event-listener 5.1.0",
"event-listener-strategy 0.5.0",
"futures-core",
"pin-project-lite",
@@ -185,7 +185,7 @@ dependencies = [
"futures-io",
"futures-lite 2.2.0",
"parking",
- "polling 3.4.0",
+ "polling 3.5.0",
"rustix 0.38.31",
"slab",
"tracing",
@@ -293,7 +293,7 @@ checksum = "16e62a023e7c117e27523144c5d2459f4397fcc3cab0085af8e2224f643a0193"
dependencies = [
"proc-macro2",
"quote",
- "syn 2.0.48",
+ "syn 2.0.50",
]
[[package]]
@@ -310,7 +310,7 @@ checksum = "c980ee35e870bd1a4d2c8294d4c04d0499e67bca1e4b5cefcc693c2fa00caea9"
dependencies = [
"proc-macro2",
"quote",
- "syn 2.0.48",
+ "syn 2.0.50",
]
[[package]]
@@ -461,15 +461,15 @@ dependencies = [
[[package]]
name = "bumpalo"
-version = "3.14.0"
+version = "3.15.3"
source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "7f30e7476521f6f8af1a1c4c0b8cc94f0bee37d91763d0ca2665f299b6cd8aec"
+checksum = "8ea184aa71bb362a1157c896979544cc23974e08fd265f29ea96b59f0b4a555b"
[[package]]
name = "bytemuck"
-version = "1.14.2"
+version = "1.14.3"
source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "ea31d69bda4949c1c1562c1e6f042a1caefac98cdc8a298260a2ff41c1e2d42b"
+checksum = "a2ef034f05691a48569bd920a96c81b9d91bbad1ab5ac7c4616c1f6ef36cb79f"
[[package]]
name = "byteorder"
@@ -521,12 +521,9 @@ checksum = "ade8366b8bd5ba243f0a58f036cc0ca8a2f069cff1a2351ef1cac6b083e16fc0"
[[package]]
name = "cc"
-version = "1.0.83"
+version = "1.0.86"
source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "f1174fb0b6ec23863f8b971027804a42614e347eafb0a95bf0b12cdae21fc4d0"
-dependencies = [
- "libc",
-]
+checksum = "7f9fa1897e4325be0d68d48df6aa1a71ac2ed4d27723887e7754192705350730"
[[package]]
name = "cfg-if"
@@ -536,22 +533,22 @@ checksum = "baf1de4339761588bc0619e3cbc0120ee582ebb74b53b4efbf79117bd2da40fd"
[[package]]
name = "chrono"
-version = "0.4.33"
+version = "0.4.34"
source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "9f13690e35a5e4ace198e7beea2895d29f3a9cc55015fcebe6336bd2010af9eb"
+checksum = "5bc015644b92d5890fab7489e49d21f879d5c990186827d42ec511919404f38b"
dependencies = [
"android-tzdata",
"iana-time-zone",
"num-traits",
"serde",
- "windows-targets 0.52.0",
+ "windows-targets 0.52.3",
]
[[package]]
name = "chrono-tz"
-version = "0.8.5"
+version = "0.8.6"
source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "91d7b79e99bfaa0d47da0687c43aa3b7381938a62ad3a6498599039321f660b7"
+checksum = "d59ae0466b83e838b81a54256c39d5d7c20b9d7daa10510a242d9b75abd5936e"
dependencies = [
"chrono",
"chrono-tz-build",
@@ -654,9 +651,9 @@ dependencies = [
[[package]]
name = "crc32fast"
-version = "1.3.2"
+version = "1.4.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "b540bd8bc810d3885c6ea91e2018302f68baba2129ab3e88f32389ee9370880d"
+checksum = "b3855a8a784b474f333699ef2bbca9db2c4a1f6d9088a90a2d25b1eb53111eaa"
dependencies = [
"cfg-if",
]
@@ -787,7 +784,7 @@ dependencies = [
"proc-macro2",
"proc-macro2-diagnostics",
"quote",
- "syn 2.0.48",
+ "syn 2.0.50",
]
[[package]]
@@ -823,7 +820,7 @@ dependencies = [
"diesel_table_macro_syntax",
"proc-macro2",
"quote",
- "syn 2.0.48",
+ "syn 2.0.50",
]
[[package]]
@@ -853,7 +850,7 @@ version = "0.1.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "fc5557efc453706fed5e4fa85006fe9817c224c3f480a34c7e5959fd700921c5"
dependencies = [
- "syn 2.0.48",
+ "syn 2.0.50",
]
[[package]]
@@ -875,9 +872,9 @@ checksum = "1aaf95b3e5c8f23aa320147307562d361db0ae0d51242340f558153b4eb2439b"
[[package]]
name = "either"
-version = "1.9.0"
+version = "1.10.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "a26ae43d7bcc3b814de94796a5e736d4029efb0ee900c12e2d54c993ad1a1e07"
+checksum = "11157ac094ffbdde99aa67b23417ebdd801842852b500e395a45a9c0aac03e4a"
[[package]]
name = "email-encoding"
@@ -916,7 +913,7 @@ dependencies = [
"heck",
"proc-macro2",
"quote",
- "syn 2.0.48",
+ "syn 2.0.50",
]
[[package]]
@@ -974,9 +971,9 @@ dependencies = [
[[package]]
name = "event-listener"
-version = "5.0.0"
+version = "5.1.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "b72557800024fabbaa2449dd4bf24e37b93702d457a4d4f2b0dd1f0f039f20c1"
+checksum = "b7ad6fd685ce13acd6d9541a30f6db6567a7a24c9ffd4ba2955d29e3f22c8b27"
dependencies = [
"concurrent-queue",
"parking",
@@ -999,7 +996,7 @@ version = "0.5.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "feedafcaa9b749175d5ac357452a9d41ea2911da598fde46ce1fe02c37751291"
dependencies = [
- "event-listener 5.0.0",
+ "event-listener 5.1.0",
"pin-project-lite",
]
@@ -1168,7 +1165,7 @@ checksum = "87750cf4b7a4c0625b1529e4c543c2182106e4dedc60a2a6455e00d212c489ac"
dependencies = [
"proc-macro2",
"quote",
- "syn 2.0.48",
+ "syn 2.0.50",
]
[[package]]
@@ -1185,9 +1182,9 @@ checksum = "38d84fa142264698cdce1a9f9172cf383a0c82de1bddcf3092901442c4097004"
[[package]]
name = "futures-timer"
-version = "3.0.2"
+version = "3.0.3"
source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "e64b03909df88034c26dc1547e8970b91f98bdb65165d6a4e9110d94263dbb2c"
+checksum = "f288b0a4f20f9a56b5d1da57e2227c661b7b16168e2f72365f57b63326e29b24"
[[package]]
name = "futures-util"
@@ -1269,9 +1266,9 @@ dependencies = [
[[package]]
name = "governor"
-version = "0.6.0"
+version = "0.6.3"
source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "821239e5672ff23e2a7060901fa622950bbd80b649cdaadd78d1c1767ed14eb4"
+checksum = "68a7f542ee6b35af73b06abc0dad1c1bae89964e4e253bc4b587b91c9637867b"
dependencies = [
"cfg-if",
"dashmap",
@@ -1280,9 +1277,11 @@ dependencies = [
"no-std-compat",
"nonzero_ext",
"parking_lot",
+ "portable-atomic",
"quanta",
"rand",
"smallvec",
+ "spinning_top",
]
[[package]]
@@ -1343,9 +1342,9 @@ checksum = "95505c38b4572b2d910cecb0281560f54b440a19336cbbcb27bf6ce6adc6f5a8"
[[package]]
name = "hermit-abi"
-version = "0.3.5"
+version = "0.3.6"
source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "d0c62115964e08cb8039170eb33c1d0e2388a256930279edca206fff675f82c3"
+checksum = "bd5256b483761cd23699d0da46cc6fd2ee3be420bbe6d020ae4a091e70b7e9fd"
[[package]]
name = "hmac"
@@ -1436,7 +1435,7 @@ dependencies = [
"httpdate",
"itoa",
"pin-project-lite",
- "socket2 0.5.5",
+ "socket2 0.5.6",
"tokio",
"tower-service",
"tracing",
@@ -1517,9 +1516,9 @@ dependencies = [
[[package]]
name = "indexmap"
-version = "2.2.2"
+version = "2.2.3"
source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "824b2ae422412366ba479e8111fd301f7b5faece8149317bb81925979a53f520"
+checksum = "233cf39063f058ea2caae4091bf4a3ef70a653afbc026f5c4a4135d114e3c177"
dependencies = [
"equivalent",
"hashbrown",
@@ -1558,7 +1557,7 @@ version = "0.3.2"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "b58db92f96b720de98181bbbe63c831e87005ab460c1bf306eb2622b4707997f"
dependencies = [
- "socket2 0.5.5",
+ "socket2 0.5.6",
"widestring",
"windows-sys 0.48.0",
"winreg",
@@ -1572,12 +1571,12 @@ checksum = "8f518f335dce6725a761382244631d86cf0ccb2863413590b31338feb467f9c3"
[[package]]
name = "is-terminal"
-version = "0.4.10"
+version = "0.4.12"
source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "0bad00257d07be169d870ab665980b06cdb366d792ad690bf2e76876dc503455"
+checksum = "f23ff5ef2b80d608d61efee834934d862cd92461afc0560dedf493e4c033738b"
dependencies = [
"hermit-abi",
- "rustix 0.38.31",
+ "libc",
"windows-sys 0.52.0",
]
@@ -1667,7 +1666,7 @@ dependencies = [
"percent-encoding",
"quoted_printable",
"serde",
- "socket2 0.5.5",
+ "socket2 0.5.6",
"tokio",
"tokio-native-tls",
"tracing",
@@ -1769,15 +1768,6 @@ dependencies = [
]
[[package]]
-name = "mach2"
-version = "0.4.2"
-source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "19b955cdeb2a02b9117f121ce63aa52d08ade45de53e48fe6a38b39c10f6f709"
-dependencies = [
- "libc",
-]
-
-[[package]]
name = "match_cfg"
version = "0.1.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
@@ -1965,7 +1955,7 @@ checksum = "ed3955f1a9c7c0c15e092f9c887db08b1fc683305fdf6eb6684f22555355e202"
dependencies = [
"proc-macro2",
"quote",
- "syn 2.0.48",
+ "syn 2.0.50",
]
[[package]]
@@ -1998,9 +1988,9 @@ dependencies = [
[[package]]
name = "num_threads"
-version = "0.1.6"
+version = "0.1.7"
source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "2819ce041d2ee131036f4fc9d6ae7ae125a3a40e97ba64d04fe799ad9dabbb44"
+checksum = "5c7398b9c8b70908f6371f47ed36737907c87c52af34c268fed0bf0ceb92ead9"
dependencies = [
"libc",
]
@@ -2022,9 +2012,9 @@ checksum = "3fdb12b2476b595f9358c5161aa467c2438859caa136dec86c26fdd2efe17b92"
[[package]]
name = "openssl"
-version = "0.10.63"
+version = "0.10.64"
source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "15c9d69dd87a29568d4d017cfe8ec518706046a05184e5aea92d0af890b803c8"
+checksum = "95a0481286a310808298130d22dd1fef0fa571e05a8f44ec801801e84b216b1f"
dependencies = [
"bitflags 2.4.2",
"cfg-if",
@@ -2043,7 +2033,7 @@ checksum = "a948666b637a0f465e8564c73e89d4dde00d72d4d473cc972f390fc3dcee7d9c"
dependencies = [
"proc-macro2",
"quote",
- "syn 2.0.48",
+ "syn 2.0.50",
]
[[package]]
@@ -2054,18 +2044,18 @@ checksum = "ff011a302c396a5197692431fc1948019154afc178baf7d8e37367442a4601cf"
[[package]]
name = "openssl-src"
-version = "300.2.2+3.2.1"
+version = "300.2.3+3.2.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "8bbfad0063610ac26ee79f7484739e2b07555a75c42453b89263830b5c8103bc"
+checksum = "5cff92b6f71555b61bb9315f7c64da3ca43d87531622120fea0195fc761b4843"
dependencies = [
"cc",
]
[[package]]
name = "openssl-sys"
-version = "0.9.99"
+version = "0.9.101"
source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "22e1bf214306098e4832460f797824c05d25aacdf896f64a985fb0fd992454ae"
+checksum = "dda2b0f344e78efc2facf7d195d098df0dd72151b26ab98da807afc26c198dff"
dependencies = [
"cc",
"libc",
@@ -2155,7 +2145,7 @@ dependencies = [
"proc-macro2",
"proc-macro2-diagnostics",
"quote",
- "syn 2.0.48",
+ "syn 2.0.50",
]
[[package]]
@@ -2205,7 +2195,7 @@ dependencies = [
"pest_meta",
"proc-macro2",
"quote",
- "syn 2.0.48",
+ "syn 2.0.50",
]
[[package]]
@@ -2288,9 +2278,9 @@ dependencies = [
[[package]]
name = "pkg-config"
-version = "0.3.29"
+version = "0.3.30"
source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "2900ede94e305130c13ddd391e0ab7cbaeb783945ae07a279c268cb05109c6cb"
+checksum = "d231b230927b5e4ad203db57bbcbee2802f6bce620b1e4a9024a07d94e2907ec"
[[package]]
name = "polling"
@@ -2310,9 +2300,9 @@ dependencies = [
[[package]]
name = "polling"
-version = "3.4.0"
+version = "3.5.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "30054e72317ab98eddd8561db0f6524df3367636884b7b21b703e4b280a84a14"
+checksum = "24f040dee2588b4963afb4e420540439d126f73fdacf4a9c486a96d840bac3c9"
dependencies = [
"cfg-if",
"concurrent-queue",
@@ -2323,6 +2313,12 @@ dependencies = [
]
[[package]]
+name = "portable-atomic"
+version = "1.6.0"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "7170ef9988bc169ba16dd36a7fa041e5c4cbeb6a35b76d4c03daded371eae7c0"
+
+[[package]]
name = "powerfmt"
version = "0.2.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
@@ -2360,7 +2356,7 @@ checksum = "af066a9c399a26e020ada66a034357a868728e72cd426f3adcd35f80d88d88c8"
dependencies = [
"proc-macro2",
"quote",
- "syn 2.0.48",
+ "syn 2.0.50",
"version_check",
"yansi",
]
@@ -2392,13 +2388,12 @@ dependencies = [
[[package]]
name = "quanta"
-version = "0.11.1"
+version = "0.12.2"
source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "a17e662a7a8291a865152364c20c7abc5e60486ab2001e8ec10b24862de0b9ab"
+checksum = "9ca0b7bac0b97248c40bb77288fc52029cf1459c0461ea1b05ee32ccf011de2c"
dependencies = [
"crossbeam-utils",
"libc",
- "mach2",
"once_cell",
"raw-cpuid",
"wasi",
@@ -2470,11 +2465,11 @@ dependencies = [
[[package]]
name = "raw-cpuid"
-version = "10.7.0"
+version = "11.0.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "6c297679cb867470fa8c9f67dbba74a78d78e3e98d7cf2b08d6d71540f797332"
+checksum = "9d86a7c4638d42c44551f4791a20e687dbb4c3de1f33c43dd71e355cd429def1"
dependencies = [
- "bitflags 1.3.2",
+ "bitflags 2.4.2",
]
[[package]]
@@ -2503,7 +2498,7 @@ checksum = "5fddb4f8d99b0a2ebafc65a87a69a7b9875e4b1ae1f00db265d300ef7f28bccc"
dependencies = [
"proc-macro2",
"quote",
- "syn 2.0.48",
+ "syn 2.0.50",
]
[[package]]
@@ -2620,16 +2615,17 @@ dependencies = [
[[package]]
name = "ring"
-version = "0.17.7"
+version = "0.17.8"
source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "688c63d65483050968b2a8937f7995f443e27041a0f7700aa59b0822aedebb74"
+checksum = "c17fa4cb658e3583423e915b9f3acc01cceaee1860e33d59ebae66adc3a2dc0d"
dependencies = [
"cc",
+ "cfg-if",
"getrandom",
"libc",
"spin",
"untrusted",
- "windows-sys 0.48.0",
+ "windows-sys 0.52.0",
]
[[package]]
@@ -2703,7 +2699,7 @@ dependencies = [
"proc-macro2",
"quote",
"rocket_http",
- "syn 2.0.48",
+ "syn 2.0.50",
"unicode-xid",
"version_check",
]
@@ -2841,9 +2837,9 @@ checksum = "7ffc183a10b4478d04cbbbfc96d0873219d962dd5accaff2ffbd4ceb7df837f4"
[[package]]
name = "ryu"
-version = "1.0.16"
+version = "1.0.17"
source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "f98d2aa92eebf49b69786be48e4477826b256916e84a57ff2a4f21923b48eb4c"
+checksum = "e86697c916019a8588c99b5fac3cead74ec0b4b819707a682fd4d23fa0ce1ba1"
[[package]]
name = "same-file"
@@ -2919,15 +2915,15 @@ dependencies = [
[[package]]
name = "semver"
-version = "1.0.21"
+version = "1.0.22"
source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "b97ed7a9823b74f99c7742f5336af7be5ecd3eeafcb1507d1fa93347b1d589b0"
+checksum = "92d43fe69e652f3df9bdc2b85b2854a0825b86e4fb76bc44d945137d053639ca"
[[package]]
name = "serde"
-version = "1.0.196"
+version = "1.0.197"
source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "870026e60fa08c69f064aa766c10f10b1d62db9ccd4d0abb206472bee0ce3b32"
+checksum = "3fb1c873e1b9b056a4dc4c0c198b24c3ffa059243875552b2bd0933b1aee4ce2"
dependencies = [
"serde_derive",
]
@@ -2944,20 +2940,20 @@ dependencies = [
[[package]]
name = "serde_derive"
-version = "1.0.196"
+version = "1.0.197"
source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "33c85360c95e7d137454dc81d9a4ed2b8efd8fbe19cee57357b32b9771fccb67"
+checksum = "7eb0b34b42edc17f6b7cac84a52a1c5f0e1bb2227e997ca9011ea3dd34e8610b"
dependencies = [
"proc-macro2",
"quote",
- "syn 2.0.48",
+ "syn 2.0.50",
]
[[package]]
name = "serde_json"
-version = "1.0.113"
+version = "1.0.114"
source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "69801b70b1c3dac963ecb03a364ba0ceda9cf60c71cfe475e99864759c8b8a79"
+checksum = "c5f09b1bd632ef549eaa9f60a1f8de742bdbc698e6cee2095fc84dde5f549ae0"
dependencies = [
"itoa",
"ryu",
@@ -3080,12 +3076,12 @@ dependencies = [
[[package]]
name = "socket2"
-version = "0.5.5"
+version = "0.5.6"
source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "7b5fac59a5cb5dd637972e5fca70daf0523c9067fcdc4842f053dae04a18f8e9"
+checksum = "05ffd9c0a93b7543e062e759284fcf5f5e3b098501104bfbdde4d404db792871"
dependencies = [
"libc",
- "windows-sys 0.48.0",
+ "windows-sys 0.52.0",
]
[[package]]
@@ -3095,6 +3091,15 @@ source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "6980e8d7511241f8acf4aebddbb1ff938df5eebe98691418c4468d0b72a96a67"
[[package]]
+name = "spinning_top"
+version = "0.3.0"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "d96d2d1d716fb500937168cc09353ffdc7a012be8475ac7308e1bdf0e3923300"
+dependencies = [
+ "lock_api",
+]
+
+[[package]]
name = "stable-pattern"
version = "0.1.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
@@ -3150,9 +3155,9 @@ dependencies = [
[[package]]
name = "syn"
-version = "2.0.48"
+version = "2.0.50"
source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "0f3531638e407dfc0814761abb7c00a5b54992b849452a0646b7f65c9f770f3f"
+checksum = "74f1bdc9872430ce9b75da68329d1c1746faf50ffac5f19e02b71e37ff881ffb"
dependencies = [
"proc-macro2",
"quote",
@@ -3213,29 +3218,29 @@ dependencies = [
[[package]]
name = "thiserror"
-version = "1.0.56"
+version = "1.0.57"
source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "d54378c645627613241d077a3a79db965db602882668f9136ac42af9ecb730ad"
+checksum = "1e45bcbe8ed29775f228095caf2cd67af7a4ccf756ebff23a306bf3e8b47b24b"
dependencies = [
"thiserror-impl",
]
[[package]]
name = "thiserror-impl"
-version = "1.0.56"
+version = "1.0.57"
source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "fa0faa943b50f3db30a20aa7e265dbc66076993efed8463e8de414e5d06d3471"
+checksum = "a953cb265bef375dae3de6663da4d3804eee9682ea80d8e2542529b73c531c81"
dependencies = [
"proc-macro2",
"quote",
- "syn 2.0.48",
+ "syn 2.0.50",
]
[[package]]
name = "thread_local"
-version = "1.1.7"
+version = "1.1.8"
source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "3fdd6f064ccff2d6567adcb3873ca630700f00b5ad3f060c25b5dcfd9a4ce152"
+checksum = "8b9ef9bad013ada3808854ceac7b46812a6465ba368859a37e2100283d2d719c"
dependencies = [
"cfg-if",
"once_cell",
@@ -3312,7 +3317,7 @@ dependencies = [
"parking_lot",
"pin-project-lite",
"signal-hook-registry",
- "socket2 0.5.5",
+ "socket2 0.5.6",
"tokio-macros",
"windows-sys 0.48.0",
]
@@ -3325,7 +3330,7 @@ checksum = "5b8a1e28f2deaa14e508979454cb3a223b10b938b45af148bc0986de36f1923b"
dependencies = [
"proc-macro2",
"quote",
- "syn 2.0.48",
+ "syn 2.0.50",
]
[[package]]
@@ -3418,7 +3423,7 @@ dependencies = [
"serde",
"serde_spanned",
"toml_datetime",
- "toml_edit 0.22.4",
+ "toml_edit 0.22.6",
]
[[package]]
@@ -3440,20 +3445,20 @@ dependencies = [
"serde",
"serde_spanned",
"toml_datetime",
- "winnow",
+ "winnow 0.5.40",
]
[[package]]
name = "toml_edit"
-version = "0.22.4"
+version = "0.22.6"
source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "0c9ffdf896f8daaabf9b66ba8e77ea1ed5ed0f72821b398aba62352e95062951"
+checksum = "2c1b5fd4128cc8d3e0cb74d4ed9a9cc7c7284becd4df68f5f940e1ad123606f6"
dependencies = [
"indexmap",
"serde",
"serde_spanned",
"toml_datetime",
- "winnow",
+ "winnow 0.6.2",
]
[[package]]
@@ -3494,7 +3499,7 @@ checksum = "34704c8d6ebcbc939824180af020566b01a7c01f80641264eba0999f6c2b6be7"
dependencies = [
"proc-macro2",
"quote",
- "syn 2.0.48",
+ "syn 2.0.50",
]
[[package]]
@@ -3652,9 +3657,9 @@ checksum = "3354b9ac3fae1ff6755cb6db53683adb661634f67557942dea4facebec0fee4b"
[[package]]
name = "unicode-normalization"
-version = "0.1.22"
+version = "0.1.23"
source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "5c5713f0fc4b5db668a2ac63cdb7bb4469d8c9fed047b1d0292cc7b0ce2ba921"
+checksum = "a56d1686db2308d901306f92a263857ef59ea39678a5458e7cb17f01415101f5"
dependencies = [
"tinyvec",
]
@@ -3836,7 +3841,7 @@ dependencies = [
"once_cell",
"proc-macro2",
"quote",
- "syn 2.0.48",
+ "syn 2.0.50",
"wasm-bindgen-shared",
]
@@ -3870,7 +3875,7 @@ checksum = "642f325be6301eb8107a83d12a8ac6c1e1c54345a7ef1a9261962dfefda09e66"
dependencies = [
"proc-macro2",
"quote",
- "syn 2.0.48",
+ "syn 2.0.50",
"wasm-bindgen-backend",
"wasm-bindgen-shared",
]
@@ -3988,7 +3993,7 @@ version = "0.52.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "33ab640c8d7e35bf8ba19b884ba838ceb4fba93a4e8c65a9059d08afcfc683d9"
dependencies = [
- "windows-targets 0.52.0",
+ "windows-targets 0.52.3",
]
[[package]]
@@ -4006,7 +4011,7 @@ version = "0.52.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "282be5f36a8ce781fad8c8ae18fa3f9beff57ec1b52cb3de0789201425d9a33d"
dependencies = [
- "windows-targets 0.52.0",
+ "windows-targets 0.52.3",
]
[[package]]
@@ -4026,17 +4031,17 @@ dependencies = [
[[package]]
name = "windows-targets"
-version = "0.52.0"
+version = "0.52.3"
source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "8a18201040b24831fbb9e4eb208f8892e1f50a37feb53cc7ff887feb8f50e7cd"
+checksum = "d380ba1dc7187569a8a9e91ed34b8ccfc33123bbacb8c0aed2d1ad7f3ef2dc5f"
dependencies = [
- "windows_aarch64_gnullvm 0.52.0",
- "windows_aarch64_msvc 0.52.0",
- "windows_i686_gnu 0.52.0",
- "windows_i686_msvc 0.52.0",
- "windows_x86_64_gnu 0.52.0",
- "windows_x86_64_gnullvm 0.52.0",
- "windows_x86_64_msvc 0.52.0",
+ "windows_aarch64_gnullvm 0.52.3",
+ "windows_aarch64_msvc 0.52.3",
+ "windows_i686_gnu 0.52.3",
+ "windows_i686_msvc 0.52.3",
+ "windows_x86_64_gnu 0.52.3",
+ "windows_x86_64_gnullvm 0.52.3",
+ "windows_x86_64_msvc 0.52.3",
]
[[package]]
@@ -4047,9 +4052,9 @@ checksum = "2b38e32f0abccf9987a4e3079dfb67dcd799fb61361e53e2882c3cbaf0d905d8"
[[package]]
name = "windows_aarch64_gnullvm"
-version = "0.52.0"
+version = "0.52.3"
source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "cb7764e35d4db8a7921e09562a0304bf2f93e0a51bfccee0bd0bb0b666b015ea"
+checksum = "68e5dcfb9413f53afd9c8f86e56a7b4d86d9a2fa26090ea2dc9e40fba56c6ec6"
[[package]]
name = "windows_aarch64_msvc"
@@ -4059,9 +4064,9 @@ checksum = "dc35310971f3b2dbbf3f0690a219f40e2d9afcf64f9ab7cc1be722937c26b4bc"
[[package]]
name = "windows_aarch64_msvc"
-version = "0.52.0"
+version = "0.52.3"
source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "bbaa0368d4f1d2aaefc55b6fcfee13f41544ddf36801e793edbbfd7d7df075ef"
+checksum = "8dab469ebbc45798319e69eebf92308e541ce46760b49b18c6b3fe5e8965b30f"
[[package]]
name = "windows_i686_gnu"
@@ -4071,9 +4076,9 @@ checksum = "a75915e7def60c94dcef72200b9a8e58e5091744960da64ec734a6c6e9b3743e"
[[package]]
name = "windows_i686_gnu"
-version = "0.52.0"
+version = "0.52.3"
source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "a28637cb1fa3560a16915793afb20081aba2c92ee8af57b4d5f28e4b3e7df313"
+checksum = "2a4e9b6a7cac734a8b4138a4e1044eac3404d8326b6c0f939276560687a033fb"
[[package]]
name = "windows_i686_msvc"
@@ -4083,9 +4088,9 @@ checksum = "8f55c233f70c4b27f66c523580f78f1004e8b5a8b659e05a4eb49d4166cca406"
[[package]]
name = "windows_i686_msvc"
-version = "0.52.0"
+version = "0.52.3"
source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "ffe5e8e31046ce6230cc7215707b816e339ff4d4d67c65dffa206fd0f7aa7b9a"
+checksum = "28b0ec9c422ca95ff34a78755cfa6ad4a51371da2a5ace67500cf7ca5f232c58"
[[package]]
name = "windows_x86_64_gnu"
@@ -4095,9 +4100,9 @@ checksum = "53d40abd2583d23e4718fddf1ebec84dbff8381c07cae67ff7768bbf19c6718e"
[[package]]
name = "windows_x86_64_gnu"
-version = "0.52.0"
+version = "0.52.3"
source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "3d6fa32db2bc4a2f5abeacf2b69f7992cd09dca97498da74a151a3132c26befd"
+checksum = "704131571ba93e89d7cd43482277d6632589b18ecf4468f591fbae0a8b101614"
[[package]]
name = "windows_x86_64_gnullvm"
@@ -4107,9 +4112,9 @@ checksum = "0b7b52767868a23d5bab768e390dc5f5c55825b6d30b86c844ff2dc7414044cc"
[[package]]
name = "windows_x86_64_gnullvm"
-version = "0.52.0"
+version = "0.52.3"
source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "1a657e1e9d3f514745a572a6846d3c7aa7dbe1658c056ed9c3344c4109a6949e"
+checksum = "42079295511643151e98d61c38c0acc444e52dd42ab456f7ccfd5152e8ecf21c"
[[package]]
name = "windows_x86_64_msvc"
@@ -4119,15 +4124,24 @@ checksum = "ed94fce61571a4006852b7389a063ab983c02eb1bb37b47f8272ce92d06d9538"
[[package]]
name = "windows_x86_64_msvc"
-version = "0.52.0"
+version = "0.52.3"
source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "dff9641d1cd4be8d1a070daf9e3773c5f67e78b4d9d42263020c057706765c04"
+checksum = "0770833d60a970638e989b3fa9fd2bb1aaadcf88963d1659fd7d9990196ed2d6"
[[package]]
name = "winnow"
-version = "0.5.39"
+version = "0.5.40"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "f593a95398737aeed53e489c785df13f3618e41dbcd6718c6addbf1395aa6876"
+dependencies = [
+ "memchr",
+]
+
+[[package]]
+name = "winnow"
+version = "0.6.2"
source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "5389a154b01683d28c77f8f68f49dea75f0a4da32557a58f68ee51ebba472d29"
+checksum = "7a4191c47f15cc3ec71fcb4913cb83d58def65dd3787610213c649283b5ce178"
dependencies = [
"memchr",
]
@@ -4184,5 +4198,5 @@ checksum = "9ce1b18ccd8e73a9321186f97e46f9f04b778851177567b1975109d26a08d2a6"
dependencies = [
"proc-macro2",
"quote",
- "syn 2.0.48",
+ "syn 2.0.50",
]
diff --git a/Cargo.toml b/Cargo.toml
index 93a6ef87..8eb905b0 100644
--- a/Cargo.toml
+++ b/Cargo.toml
@@ -71,8 +71,8 @@ futures = "0.3.30"
tokio = { version = "1.36.0", features = ["rt-multi-thread", "fs", "io-util", "parking_lot", "time", "signal"] }
# A generic serialization/deserialization framework
-serde = { version = "1.0.196", features = ["derive"] }
-serde_json = "1.0.113"
+serde = { version = "1.0.197", features = ["derive"] }
+serde_json = "1.0.114"
# A safe, extensible ORM and Query builder
diesel = { version = "2.1.4", features = ["chrono", "r2d2", "numeric"] }
@@ -84,14 +84,14 @@ libsqlite3-sys = { version = "0.27.0", features = ["bundled"], optional = true }
# Crypto-related libraries
rand = { version = "0.8.5", features = ["small_rng"] }
-ring = "0.17.7"
+ring = "0.17.8"
# UUID generation
uuid = { version = "1.7.0", features = ["v4"] }
# Date and time libraries
-chrono = { version = "0.4.33", features = ["clock", "serde"], default-features = false }
-chrono-tz = "0.8.5"
+chrono = { version = "0.4.34", features = ["clock", "serde"], default-features = false }
+chrono-tz = "0.8.6"
time = "0.3.34"
# Job scheduler
@@ -140,17 +140,17 @@ cookie = "0.17.0"
cookie_store = "0.20.0"
# Used by U2F, JWT and PostgreSQL
-openssl = "0.10.63"
+openssl = "0.10.64"
# CLI argument parsing
pico-args = "0.5.0"
# Macro ident concatenation
paste = "1.0.14"
-governor = "0.6.0"
+governor = "0.6.3"
# Check client versions for specific features.
-semver = "1.0.21"
+semver = "1.0.22"
# Allow overriding the default memory allocator
# Mainly used for the musl builds, since the default musl malloc is very slow
diff --git a/src/api/web.rs b/src/api/web.rs
index dad36a7f..3e66e735 100644
--- a/src/api/web.rs
+++ b/src/api/web.rs
@@ -174,7 +174,7 @@ pub fn static_files(filename: &str) -> Result<(ContentType, &'static [u8]), Erro
"datatables.js" => Ok((ContentType::JavaScript, include_bytes!("../static/scripts/datatables.js"))),
"datatables.css" => Ok((ContentType::CSS, include_bytes!("../static/scripts/datatables.css"))),
"jquery-3.7.0.slim.js" => {
- Ok((ContentType::JavaScript, include_bytes!("../static/scripts/jquery-3.7.0.slim.js")))
+ Ok((ContentType::JavaScript, include_bytes!("../static/scripts/jquery-3.7.1.slim.js")))
}
_ => err!(format!("Static file not found: {filename}")),
}
diff --git a/src/static/scripts/bootstrap.bundle.js b/src/static/scripts/bootstrap.bundle.js
index 3a02ceb3..491038c2 100644
--- a/src/static/scripts/bootstrap.bundle.js
+++ b/src/static/scripts/bootstrap.bundle.js
@@ -1,5 +1,5 @@
/*!
- * Bootstrap v5.3.1 (https://getbootstrap.com/)
+ * Bootstrap v5.3.2 (https://getbootstrap.com/)
* Copyright 2011-2023 The Bootstrap Authors (https://github.com/twbs/bootstrap/graphs/contributors)
* Licensed under MIT (https://github.com/twbs/bootstrap/blob/main/LICENSE)
*/
@@ -648,7 +648,7 @@
* Constants
*/
- const VERSION = '5.3.1';
+ const VERSION = '5.3.2';
/**
* Class definition
@@ -729,9 +729,9 @@
if (hrefAttribute.includes('#') && !hrefAttribute.startsWith('#')) {
hrefAttribute = `#${hrefAttribute.split('#')[1]}`;
}
- selector = hrefAttribute && hrefAttribute !== '#' ? hrefAttribute.trim() : null;
+ selector = hrefAttribute && hrefAttribute !== '#' ? parseSelector(hrefAttribute.trim()) : null;
}
- return parseSelector(selector);
+ return selector;
};
const SelectorEngine = {
find(selector, element = document.documentElement) {
@@ -5866,7 +5866,7 @@
const CLASS_DROPDOWN = 'dropdown';
const SELECTOR_DROPDOWN_TOGGLE = '.dropdown-toggle';
const SELECTOR_DROPDOWN_MENU = '.dropdown-menu';
- const NOT_SELECTOR_DROPDOWN_TOGGLE = ':not(.dropdown-toggle)';
+ const NOT_SELECTOR_DROPDOWN_TOGGLE = `:not(${SELECTOR_DROPDOWN_TOGGLE})`;
const SELECTOR_TAB_PANEL = '.list-group, .nav, [role="tablist"]';
const SELECTOR_OUTER = '.nav-item, .list-group-item';
const SELECTOR_INNER = `.nav-link${NOT_SELECTOR_DROPDOWN_TOGGLE}, .list-group-item${NOT_SELECTOR_DROPDOWN_TOGGLE}, [role="tab"]${NOT_SELECTOR_DROPDOWN_TOGGLE}`;
diff --git a/src/static/scripts/bootstrap.css b/src/static/scripts/bootstrap.css
index 11e83fa5..32ea6e9c 100644
--- a/src/static/scripts/bootstrap.css
+++ b/src/static/scripts/bootstrap.css
@@ -1,6 +1,6 @@
@charset "UTF-8";
/*!
- * Bootstrap v5.3.1 (https://getbootstrap.com/)
+ * Bootstrap v5.3.2 (https://getbootstrap.com/)
* Copyright 2011-2023 The Bootstrap Authors
* Licensed under MIT (https://github.com/twbs/bootstrap/blob/main/LICENSE)
*/
@@ -99,6 +99,7 @@
--bs-link-hover-color: #0a58ca;
--bs-link-hover-color-rgb: 10, 88, 202;
--bs-code-color: #d63384;
+ --bs-highlight-color: #212529;
--bs-highlight-bg: #fff3cd;
--bs-border-width: 1px;
--bs-border-style: solid;
@@ -170,6 +171,8 @@
--bs-link-color-rgb: 110, 168, 254;
--bs-link-hover-color-rgb: 139, 185, 254;
--bs-code-color: #e685b5;
+ --bs-highlight-color: #dee2e6;
+ --bs-highlight-bg: #664d03;
--bs-border-color: #495057;
--bs-border-color-translucent: rgba(255, 255, 255, 0.15);
--bs-form-valid-color: #75b798;
@@ -325,6 +328,7 @@ small, .small {
mark, .mark {
padding: 0.1875em;
+ color: var(--bs-highlight-color);
background-color: var(--bs-highlight-bg);
}
@@ -819,7 +823,7 @@ progress {
.row-cols-3 > * {
flex: 0 0 auto;
- width: 33.3333333333%;
+ width: 33.33333333%;
}
.row-cols-4 > * {
@@ -834,7 +838,7 @@ progress {
.row-cols-6 > * {
flex: 0 0 auto;
- width: 16.6666666667%;
+ width: 16.66666667%;
}
.col-auto {
@@ -1024,7 +1028,7 @@ progress {
}
.row-cols-sm-3 > * {
flex: 0 0 auto;
- width: 33.3333333333%;
+ width: 33.33333333%;
}
.row-cols-sm-4 > * {
flex: 0 0 auto;
@@ -1036,7 +1040,7 @@ progress {
}
.row-cols-sm-6 > * {
flex: 0 0 auto;
- width: 16.6666666667%;
+ width: 16.66666667%;
}
.col-sm-auto {
flex: 0 0 auto;
@@ -1193,7 +1197,7 @@ progress {
}
.row-cols-md-3 > * {
flex: 0 0 auto;
- width: 33.3333333333%;
+ width: 33.33333333%;
}
.row-cols-md-4 > * {
flex: 0 0 auto;
@@ -1205,7 +1209,7 @@ progress {
}
.row-cols-md-6 > * {
flex: 0 0 auto;
- width: 16.6666666667%;
+ width: 16.66666667%;
}
.col-md-auto {
flex: 0 0 auto;
@@ -1362,7 +1366,7 @@ progress {
}
.row-cols-lg-3 > * {
flex: 0 0 auto;
- width: 33.3333333333%;
+ width: 33.33333333%;
}
.row-cols-lg-4 > * {
flex: 0 0 auto;
@@ -1374,7 +1378,7 @@ progress {
}
.row-cols-lg-6 > * {
flex: 0 0 auto;
- width: 16.6666666667%;
+ width: 16.66666667%;
}
.col-lg-auto {
flex: 0 0 auto;
@@ -1531,7 +1535,7 @@ progress {
}
.row-cols-xl-3 > * {
flex: 0 0 auto;
- width: 33.3333333333%;
+ width: 33.33333333%;
}
.row-cols-xl-4 > * {
flex: 0 0 auto;
@@ -1543,7 +1547,7 @@ progress {
}
.row-cols-xl-6 > * {
flex: 0 0 auto;
- width: 16.6666666667%;
+ width: 16.66666667%;
}
.col-xl-auto {
flex: 0 0 auto;
@@ -1700,7 +1704,7 @@ progress {
}
.row-cols-xxl-3 > * {
flex: 0 0 auto;
- width: 33.3333333333%;
+ width: 33.33333333%;
}
.row-cols-xxl-4 > * {
flex: 0 0 auto;
@@ -1712,7 +1716,7 @@ progress {
}
.row-cols-xxl-6 > * {
flex: 0 0 auto;
- width: 16.6666666667%;
+ width: 16.66666667%;
}
.col-xxl-auto {
flex: 0 0 auto;
@@ -1856,16 +1860,16 @@ progress {
--bs-table-bg-type: initial;
--bs-table-color-state: initial;
--bs-table-bg-state: initial;
- --bs-table-color: var(--bs-body-color);
+ --bs-table-color: var(--bs-emphasis-color);
--bs-table-bg: var(--bs-body-bg);
--bs-table-border-color: var(--bs-border-color);
--bs-table-accent-bg: transparent;
- --bs-table-striped-color: var(--bs-body-color);
- --bs-table-striped-bg: rgba(0, 0, 0, 0.05);
- --bs-table-active-color: var(--bs-body-color);
- --bs-table-active-bg: rgba(0, 0, 0, 0.1);
- --bs-table-hover-color: var(--bs-body-color);
- --bs-table-hover-bg: rgba(0, 0, 0, 0.075);
+ --bs-table-striped-color: var(--bs-emphasis-color);
+ --bs-table-striped-bg: rgba(var(--bs-emphasis-color-rgb), 0.05);
+ --bs-table-active-color: var(--bs-emphasis-color);
+ --bs-table-active-bg: rgba(var(--bs-emphasis-color-rgb), 0.1);
+ --bs-table-hover-color: var(--bs-emphasis-color);
+ --bs-table-hover-bg: rgba(var(--bs-emphasis-color-rgb), 0.075);
width: 100%;
margin-bottom: 1rem;
vertical-align: top;
@@ -1934,7 +1938,7 @@ progress {
.table-primary {
--bs-table-color: #000;
--bs-table-bg: #cfe2ff;
- --bs-table-border-color: #bacbe6;
+ --bs-table-border-color: #a6b5cc;
--bs-table-striped-bg: #c5d7f2;
--bs-table-striped-color: #000;
--bs-table-active-bg: #bacbe6;
@@ -1948,7 +1952,7 @@ progress {
.table-secondary {
--bs-table-color: #000;
--bs-table-bg: #e2e3e5;
- --bs-table-border-color: #cbccce;
+ --bs-table-border-color: #b5b6b7;
--bs-table-striped-bg: #d7d8da;
--bs-table-striped-color: #000;
--bs-table-active-bg: #cbccce;
@@ -1962,7 +1966,7 @@ progress {
.table-success {
--bs-table-color: #000;
--bs-table-bg: #d1e7dd;
- --bs-table-border-color: #bcd0c7;
+ --bs-table-border-color: #a7b9b1;
--bs-table-striped-bg: #c7dbd2;
--bs-table-striped-color: #000;
--bs-table-active-bg: #bcd0c7;
@@ -1976,7 +1980,7 @@ progress {
.table-info {
--bs-table-color: #000;
--bs-table-bg: #cff4fc;
- --bs-table-border-color: #badce3;
+ --bs-table-border-color: #a6c3ca;
--bs-table-striped-bg: #c5e8ef;
--bs-table-striped-color: #000;
--bs-table-active-bg: #badce3;
@@ -1990,7 +1994,7 @@ progress {
.table-warning {
--bs-table-color: #000;
--bs-table-bg: #fff3cd;
- --bs-table-border-color: #e6dbb9;
+ --bs-table-border-color: #ccc2a4;
--bs-table-striped-bg: #f2e7c3;
--bs-table-striped-color: #000;
--bs-table-active-bg: #e6dbb9;
@@ -2004,7 +2008,7 @@ progress {
.table-danger {
--bs-table-color: #000;
--bs-table-bg: #f8d7da;
- --bs-table-border-color: #dfc2c4;
+ --bs-table-border-color: #c6acae;
--bs-table-striped-bg: #eccccf;
--bs-table-striped-color: #000;
--bs-table-active-bg: #dfc2c4;
@@ -2018,7 +2022,7 @@ progress {
.table-light {
--bs-table-color: #000;
--bs-table-bg: #f8f9fa;
- --bs-table-border-color: #dfe0e1;
+ --bs-table-border-color: #c6c7c8;
--bs-table-striped-bg: #ecedee;
--bs-table-striped-color: #000;
--bs-table-active-bg: #dfe0e1;
@@ -2032,7 +2036,7 @@ progress {
.table-dark {
--bs-table-color: #fff;
--bs-table-bg: #212529;
- --bs-table-border-color: #373b3e;
+ --bs-table-border-color: #4d5154;
--bs-table-striped-bg: #2c3034;
--bs-table-striped-color: #fff;
--bs-table-active-bg: #373b3e;
@@ -2388,6 +2392,7 @@ textarea.form-control-lg {
.form-check-input {
--bs-form-check-bg: var(--bs-body-bg);
+ flex-shrink: 0;
width: 1em;
height: 1em;
margin-top: 0.25em;
@@ -2544,7 +2549,7 @@ textarea.form-control-lg {
height: 0.5rem;
color: transparent;
cursor: pointer;
- background-color: var(--bs-tertiary-bg);
+ background-color: var(--bs-secondary-bg);
border-color: transparent;
border-radius: 1rem;
}
@@ -2573,7 +2578,7 @@ textarea.form-control-lg {
height: 0.5rem;
color: transparent;
cursor: pointer;
- background-color: var(--bs-tertiary-bg);
+ background-color: var(--bs-secondary-bg);
border-color: transparent;
border-radius: 1rem;
}
@@ -3431,7 +3436,7 @@ textarea.form-control-lg {
--bs-dropdown-inner-border-radius: calc(var(--bs-border-radius) - var(--bs-border-width));
--bs-dropdown-divider-bg: var(--bs-border-color-translucent);
--bs-dropdown-divider-margin-y: 0.5rem;
- --bs-dropdown-box-shadow: 0 0.5rem 1rem rgba(0, 0, 0, 0.15);
+ --bs-dropdown-box-shadow: var(--bs-box-shadow);
--bs-dropdown-link-color: var(--bs-body-color);
--bs-dropdown-link-hover-color: var(--bs-body-color);
--bs-dropdown-link-hover-bg: var(--bs-tertiary-bg);
@@ -5473,7 +5478,7 @@ textarea.form-control-lg {
--bs-modal-border-color: var(--bs-border-color-translucent);
--bs-modal-border-width: var(--bs-border-width);
--bs-modal-border-radius: var(--bs-border-radius-lg);
- --bs-modal-box-shadow: 0 0.125rem 0.25rem rgba(0, 0, 0, 0.075);
+ --bs-modal-box-shadow: var(--bs-box-shadow-sm);
--bs-modal-inner-border-radius: calc(var(--bs-border-radius-lg) - (var(--bs-border-width)));
--bs-modal-header-padding-x: 1rem;
--bs-modal-header-padding-y: 1rem;
@@ -5614,7 +5619,7 @@ textarea.form-control-lg {
@media (min-width: 576px) {
.modal {
--bs-modal-margin: 1.75rem;
- --bs-modal-box-shadow: 0 0.5rem 1rem rgba(0, 0, 0, 0.15);
+ --bs-modal-box-shadow: var(--bs-box-shadow);
}
.modal-dialog {
max-width: var(--bs-modal-width);
@@ -5866,7 +5871,7 @@ textarea.form-control-lg {
--bs-popover-border-color: var(--bs-border-color-translucent);
--bs-popover-border-radius: var(--bs-border-radius-lg);
--bs-popover-inner-border-radius: calc(var(--bs-border-radius-lg) - var(--bs-border-width));
- --bs-popover-box-shadow: 0 0.5rem 1rem rgba(0, 0, 0, 0.15);
+ --bs-popover-box-shadow: var(--bs-box-shadow);
--bs-popover-header-padding-x: 1rem;
--bs-popover-header-padding-y: 0.5rem;
--bs-popover-header-font-size: 1rem;
@@ -6301,7 +6306,7 @@ textarea.form-control-lg {
--bs-offcanvas-bg: var(--bs-body-bg);
--bs-offcanvas-border-width: var(--bs-border-width);
--bs-offcanvas-border-color: var(--bs-border-color-translucent);
- --bs-offcanvas-box-shadow: 0 0.125rem 0.25rem rgba(0, 0, 0, 0.075);
+ --bs-offcanvas-box-shadow: var(--bs-box-shadow-sm);
--bs-offcanvas-transition: transform 0.3s ease-in-out;
--bs-offcanvas-title-line-height: 1.5;
}
@@ -7380,15 +7385,15 @@ textarea.form-control-lg {
}
.shadow {
- box-shadow: 0 0.5rem 1rem rgba(0, 0, 0, 0.15) !important;
+ box-shadow: var(--bs-box-shadow) !important;
}
.shadow-sm {
- box-shadow: 0 0.125rem 0.25rem rgba(0, 0, 0, 0.075) !important;
+ box-shadow: var(--bs-box-shadow-sm) !important;
}
.shadow-lg {
- box-shadow: 0 1rem 3rem rgba(0, 0, 0, 0.175) !important;
+ box-shadow: var(--bs-box-shadow-lg) !important;
}
.shadow-none {
diff --git a/src/static/scripts/datatables.css b/src/static/scripts/datatables.css
index e3205479..4c93a7d5 100644
--- a/src/static/scripts/datatables.css
+++ b/src/static/scripts/datatables.css
@@ -4,10 +4,10 @@
*
* To rebuild or modify this file with the latest versions of the included
* software please visit:
- * https://datatables.net/download/#bs5/dt-1.13.6
+ * https://datatables.net/download/#bs5/dt-2.0.0
*
* Included libraries:
- * DataTables 1.13.6
+ * DataTables 2.0.0
*/
@charset "UTF-8";
@@ -30,76 +30,124 @@ table.dataTable td.dt-control {
}
table.dataTable td.dt-control:before {
display: inline-block;
- color: rgba(0, 0, 0, 0.5);
- content: "â–º";
+ box-sizing: border-box;
+ content: "";
+ border-top: 5px solid transparent;
+ border-left: 10px solid rgba(0, 0, 0, 0.5);
+ border-bottom: 5px solid transparent;
+ border-right: 0px solid transparent;
}
table.dataTable tr.dt-hasChild td.dt-control:before {
- content: "â–¼";
+ border-top: 10px solid rgba(0, 0, 0, 0.5);
+ border-left: 5px solid transparent;
+ border-bottom: 0px solid transparent;
+ border-right: 5px solid transparent;
}
-html.dark table.dataTable td.dt-control:before {
- color: rgba(255, 255, 255, 0.5);
+html.dark table.dataTable td.dt-control:before,
+:root[data-bs-theme=dark] table.dataTable td.dt-control:before {
+ border-left-color: rgba(255, 255, 255, 0.5);
}
-html.dark table.dataTable tr.dt-hasChild td.dt-control:before {
- color: rgba(255, 255, 255, 0.5);
+html.dark table.dataTable tr.dt-hasChild td.dt-control:before,
+:root[data-bs-theme=dark] table.dataTable tr.dt-hasChild td.dt-control:before {
+ border-top-color: rgba(255, 255, 255, 0.5);
+ border-left-color: transparent;
}
-table.dataTable thead > tr > th.sorting, table.dataTable thead > tr > th.sorting_asc, table.dataTable thead > tr > th.sorting_desc, table.dataTable thead > tr > th.sorting_asc_disabled, table.dataTable thead > tr > th.sorting_desc_disabled,
-table.dataTable thead > tr > td.sorting,
-table.dataTable thead > tr > td.sorting_asc,
-table.dataTable thead > tr > td.sorting_desc,
-table.dataTable thead > tr > td.sorting_asc_disabled,
-table.dataTable thead > tr > td.sorting_desc_disabled {
- cursor: pointer;
- position: relative;
- padding-right: 26px;
-}
-table.dataTable thead > tr > th.sorting:before, table.dataTable thead > tr > th.sorting:after, table.dataTable thead > tr > th.sorting_asc:before, table.dataTable thead > tr > th.sorting_asc:after, table.dataTable thead > tr > th.sorting_desc:before, table.dataTable thead > tr > th.sorting_desc:after, table.dataTable thead > tr > th.sorting_asc_disabled:before, table.dataTable thead > tr > th.sorting_asc_disabled:after, table.dataTable thead > tr > th.sorting_desc_disabled:before, table.dataTable thead > tr > th.sorting_desc_disabled:after,
-table.dataTable thead > tr > td.sorting:before,
-table.dataTable thead > tr > td.sorting:after,
-table.dataTable thead > tr > td.sorting_asc:before,
-table.dataTable thead > tr > td.sorting_asc:after,
-table.dataTable thead > tr > td.sorting_desc:before,
-table.dataTable thead > tr > td.sorting_desc:after,
-table.dataTable thead > tr > td.sorting_asc_disabled:before,
-table.dataTable thead > tr > td.sorting_asc_disabled:after,
-table.dataTable thead > tr > td.sorting_desc_disabled:before,
-table.dataTable thead > tr > td.sorting_desc_disabled:after {
+div.dt-scroll-body thead tr,
+div.dt-scroll-body tfoot tr {
+ height: 0;
+}
+div.dt-scroll-body thead tr th, div.dt-scroll-body thead tr td,
+div.dt-scroll-body tfoot tr th,
+div.dt-scroll-body tfoot tr td {
+ height: 0 !important;
+ padding-top: 0px !important;
+ padding-bottom: 0px !important;
+ border-top-width: 0px !important;
+ border-bottom-width: 0px !important;
+}
+div.dt-scroll-body thead tr th div.dt-scroll-sizing, div.dt-scroll-body thead tr td div.dt-scroll-sizing,
+div.dt-scroll-body tfoot tr th div.dt-scroll-sizing,
+div.dt-scroll-body tfoot tr td div.dt-scroll-sizing {
+ height: 0 !important;
+ overflow: hidden !important;
+}
+
+table.dataTable thead > tr > th:active,
+table.dataTable thead > tr > td:active {
+ outline: none;
+}
+table.dataTable thead > tr > th.dt-orderable-asc span.dt-column-order:before, table.dataTable thead > tr > th.dt-ordering-asc span.dt-column-order:before,
+table.dataTable thead > tr > td.dt-orderable-asc span.dt-column-order:before,
+table.dataTable thead > tr > td.dt-ordering-asc span.dt-column-order:before {
position: absolute;
display: block;
- opacity: 0.125;
- right: 10px;
- line-height: 9px;
- font-size: 0.8em;
-}
-table.dataTable thead > tr > th.sorting:before, table.dataTable thead > tr > th.sorting_asc:before, table.dataTable thead > tr > th.sorting_desc:before, table.dataTable thead > tr > th.sorting_asc_disabled:before, table.dataTable thead > tr > th.sorting_desc_disabled:before,
-table.dataTable thead > tr > td.sorting:before,
-table.dataTable thead > tr > td.sorting_asc:before,
-table.dataTable thead > tr > td.sorting_desc:before,
-table.dataTable thead > tr > td.sorting_asc_disabled:before,
-table.dataTable thead > tr > td.sorting_desc_disabled:before {
bottom: 50%;
content: "â–²";
content: "â–²"/"";
}
-table.dataTable thead > tr > th.sorting:after, table.dataTable thead > tr > th.sorting_asc:after, table.dataTable thead > tr > th.sorting_desc:after, table.dataTable thead > tr > th.sorting_asc_disabled:after, table.dataTable thead > tr > th.sorting_desc_disabled:after,
-table.dataTable thead > tr > td.sorting:after,
-table.dataTable thead > tr > td.sorting_asc:after,
-table.dataTable thead > tr > td.sorting_desc:after,
-table.dataTable thead > tr > td.sorting_asc_disabled:after,
-table.dataTable thead > tr > td.sorting_desc_disabled:after {
+table.dataTable thead > tr > th.dt-orderable-desc span.dt-column-order:after, table.dataTable thead > tr > th.dt-ordering-desc span.dt-column-order:after,
+table.dataTable thead > tr > td.dt-orderable-desc span.dt-column-order:after,
+table.dataTable thead > tr > td.dt-ordering-desc span.dt-column-order:after {
+ position: absolute;
+ display: block;
top: 50%;
content: "â–¼";
content: "â–¼"/"";
}
-table.dataTable thead > tr > th.sorting_asc:before, table.dataTable thead > tr > th.sorting_desc:after,
-table.dataTable thead > tr > td.sorting_asc:before,
-table.dataTable thead > tr > td.sorting_desc:after {
+table.dataTable thead > tr > th.dt-orderable-asc, table.dataTable thead > tr > th.dt-orderable-desc, table.dataTable thead > tr > th.dt-ordering-asc, table.dataTable thead > tr > th.dt-ordering-desc,
+table.dataTable thead > tr > td.dt-orderable-asc,
+table.dataTable thead > tr > td.dt-orderable-desc,
+table.dataTable thead > tr > td.dt-ordering-asc,
+table.dataTable thead > tr > td.dt-ordering-desc {
+ position: relative;
+ padding-right: 30px;
+}
+table.dataTable thead > tr > th.dt-orderable-asc span.dt-column-order, table.dataTable thead > tr > th.dt-orderable-desc span.dt-column-order, table.dataTable thead > tr > th.dt-ordering-asc span.dt-column-order, table.dataTable thead > tr > th.dt-ordering-desc span.dt-column-order,
+table.dataTable thead > tr > td.dt-orderable-asc span.dt-column-order,
+table.dataTable thead > tr > td.dt-orderable-desc span.dt-column-order,
+table.dataTable thead > tr > td.dt-ordering-asc span.dt-column-order,
+table.dataTable thead > tr > td.dt-ordering-desc span.dt-column-order {
+ position: absolute;
+ right: 12px;
+ top: 0;
+ bottom: 0;
+ width: 12px;
+}
+table.dataTable thead > tr > th.dt-orderable-asc span.dt-column-order:before, table.dataTable thead > tr > th.dt-orderable-asc span.dt-column-order:after, table.dataTable thead > tr > th.dt-orderable-desc span.dt-column-order:before, table.dataTable thead > tr > th.dt-orderable-desc span.dt-column-order:after, table.dataTable thead > tr > th.dt-ordering-asc span.dt-column-order:before, table.dataTable thead > tr > th.dt-ordering-asc span.dt-column-order:after, table.dataTable thead > tr > th.dt-ordering-desc span.dt-column-order:before, table.dataTable thead > tr > th.dt-ordering-desc span.dt-column-order:after,
+table.dataTable thead > tr > td.dt-orderable-asc span.dt-column-order:before,
+table.dataTable thead > tr > td.dt-orderable-asc span.dt-column-order:after,
+table.dataTable thead > tr > td.dt-orderable-desc span.dt-column-order:before,
+table.dataTable thead > tr > td.dt-orderable-desc span.dt-column-order:after,
+table.dataTable thead > tr > td.dt-ordering-asc span.dt-column-order:before,
+table.dataTable thead > tr > td.dt-ordering-asc span.dt-column-order:after,
+table.dataTable thead > tr > td.dt-ordering-desc span.dt-column-order:before,
+table.dataTable thead > tr > td.dt-ordering-desc span.dt-column-order:after {
+ left: 0;
+ opacity: 0.125;
+ line-height: 9px;
+ font-size: 0.8em;
+}
+table.dataTable thead > tr > th.dt-orderable-asc, table.dataTable thead > tr > th.dt-orderable-desc,
+table.dataTable thead > tr > td.dt-orderable-asc,
+table.dataTable thead > tr > td.dt-orderable-desc {
+ cursor: pointer;
+}
+table.dataTable thead > tr > th.dt-orderable-asc:hover, table.dataTable thead > tr > th.dt-orderable-desc:hover,
+table.dataTable thead > tr > td.dt-orderable-asc:hover,
+table.dataTable thead > tr > td.dt-orderable-desc:hover {
+ outline: 2px solid rgba(0, 0, 0, 0.05);
+ outline-offset: -2px;
+}
+table.dataTable thead > tr > th.dt-ordering-asc span.dt-column-order:before, table.dataTable thead > tr > th.dt-ordering-desc span.dt-column-order:after,
+table.dataTable thead > tr > td.dt-ordering-asc span.dt-column-order:before,
+table.dataTable thead > tr > td.dt-ordering-desc span.dt-column-order:after {
opacity: 0.6;
}
-table.dataTable thead > tr > th.sorting_desc_disabled:after, table.dataTable thead > tr > th.sorting_asc_disabled:before,
-table.dataTable thead > tr > td.sorting_desc_disabled:after,
-table.dataTable thead > tr > td.sorting_asc_disabled:before {
+table.dataTable thead > tr > th.sorting_desc_disabled span.dt-column-order:after, table.dataTable thead > tr > th.sorting_asc_disabled span.dt-column-order:before,
+table.dataTable thead > tr > td.sorting_desc_disabled span.dt-column-order:after,
+table.dataTable thead > tr > td.sorting_asc_disabled span.dt-column-order:before {
display: none;
}
table.dataTable thead > tr > th:active,
@@ -107,29 +155,39 @@ table.dataTable thead > tr > td:active {
outline: none;
}
-div.dataTables_scrollBody > table.dataTable > thead > tr > th:before, div.dataTables_scrollBody > table.dataTable > thead > tr > th:after,
-div.dataTables_scrollBody > table.dataTable > thead > tr > td:before,
-div.dataTables_scrollBody > table.dataTable > thead > tr > td:after {
- display: none;
+div.dt-scroll-body > table.dataTable > thead > tr > th,
+div.dt-scroll-body > table.dataTable > thead > tr > td {
+ overflow: hidden;
+}
+
+:root.dark table.dataTable thead > tr > th.dt-orderable-asc:hover, :root.dark table.dataTable thead > tr > th.dt-orderable-desc:hover,
+:root.dark table.dataTable thead > tr > td.dt-orderable-asc:hover,
+:root.dark table.dataTable thead > tr > td.dt-orderable-desc:hover,
+:root[data-bs-theme=dark] table.dataTable thead > tr > th.dt-orderable-asc:hover,
+:root[data-bs-theme=dark] table.dataTable thead > tr > th.dt-orderable-desc:hover,
+:root[data-bs-theme=dark] table.dataTable thead > tr > td.dt-orderable-asc:hover,
+:root[data-bs-theme=dark] table.dataTable thead > tr > td.dt-orderable-desc:hover {
+ outline: 2px solid rgba(255, 255, 255, 0.05);
}
-div.dataTables_processing {
+div.dt-processing {
position: absolute;
top: 50%;
left: 50%;
width: 200px;
margin-left: -100px;
- margin-top: -26px;
+ margin-top: -22px;
text-align: center;
padding: 2px;
+ z-index: 10;
}
-div.dataTables_processing > div:last-child {
+div.dt-processing > div:last-child {
position: relative;
width: 80px;
height: 15px;
margin: 1em auto;
}
-div.dataTables_processing > div:last-child > div {
+div.dt-processing > div:last-child > div {
position: absolute;
top: 0;
width: 13px;
@@ -139,19 +197,19 @@ div.dataTables_processing > div:last-child > div {
background: rgb(var(--dt-row-selected));
animation-timing-function: cubic-bezier(0, 1, 1, 0);
}
-div.dataTables_processing > div:last-child > div:nth-child(1) {
+div.dt-processing > div:last-child > div:nth-child(1) {
left: 8px;
animation: datatables-loader-1 0.6s infinite;
}
-div.dataTables_processing > div:last-child > div:nth-child(2) {
+div.dt-processing > div:last-child > div:nth-child(2) {
left: 8px;
animation: datatables-loader-2 0.6s infinite;
}
-div.dataTables_processing > div:last-child > div:nth-child(3) {
+div.dt-processing > div:last-child > div:nth-child(3) {
left: 32px;
animation: datatables-loader-2 0.6s infinite;
}
-div.dataTables_processing > div:last-child > div:nth-child(4) {
+div.dt-processing > div:last-child > div:nth-child(4) {
left: 56px;
animation: datatables-loader-3 0.6s infinite;
}
@@ -183,13 +241,16 @@ div.dataTables_processing > div:last-child > div:nth-child(4) {
table.dataTable.nowrap th, table.dataTable.nowrap td {
white-space: nowrap;
}
+table.dataTable th,
+table.dataTable td {
+ box-sizing: border-box;
+}
table.dataTable th.dt-left,
table.dataTable td.dt-left {
text-align: left;
}
table.dataTable th.dt-center,
-table.dataTable td.dt-center,
-table.dataTable td.dataTables_empty {
+table.dataTable td.dt-center {
text-align: center;
}
table.dataTable th.dt-right,
@@ -204,6 +265,16 @@ table.dataTable th.dt-nowrap,
table.dataTable td.dt-nowrap {
white-space: nowrap;
}
+table.dataTable th.dt-empty,
+table.dataTable td.dt-empty {
+ text-align: center;
+ vertical-align: top;
+}
+table.dataTable th.dt-type-numeric, table.dataTable th.dt-type-date,
+table.dataTable td.dt-type-numeric,
+table.dataTable td.dt-type-date {
+ text-align: right;
+}
table.dataTable thead th,
table.dataTable thead td,
table.dataTable tfoot th,
@@ -266,179 +337,150 @@ table.dataTable tbody td.dt-body-nowrap {
* ©2020 SpryMedia Ltd, all rights reserved.
* License: MIT datatables.net/license/mit
*/
-table.dataTable {
+table.table.dataTable {
clear: both;
- margin-top: 6px !important;
- margin-bottom: 6px !important;
- max-width: none !important;
- border-collapse: separate !important;
+ margin-bottom: 0;
+ max-width: none;
border-spacing: 0;
}
-table.dataTable td,
-table.dataTable th {
- -webkit-box-sizing: content-box;
- box-sizing: content-box;
-}
-table.dataTable td.dataTables_empty,
-table.dataTable th.dataTables_empty {
- text-align: center;
-}
-table.dataTable.nowrap th,
-table.dataTable.nowrap td {
- white-space: nowrap;
-}
-table.dataTable.table-striped > tbody > tr:nth-of-type(2n+1) > * {
+table.table.dataTable.table-striped > tbody > tr:nth-of-type(2n+1) > * {
box-shadow: none;
}
-table.dataTable > tbody > tr {
+table.table.dataTable > :not(caption) > * > * {
background-color: transparent;
}
-table.dataTable > tbody > tr.selected > * {
+table.table.dataTable > tbody > tr {
+ background-color: transparent;
+}
+table.table.dataTable > tbody > tr.selected > * {
box-shadow: inset 0 0 0 9999px rgb(13, 110, 253);
box-shadow: inset 0 0 0 9999px rgb(var(--dt-row-selected));
color: rgb(255, 255, 255);
color: rgb(var(--dt-row-selected-text));
}
-table.dataTable > tbody > tr.selected a {
+table.table.dataTable > tbody > tr.selected a {
color: rgb(9, 10, 11);
color: rgb(var(--dt-row-selected-link));
}
-table.dataTable.table-striped > tbody > tr.odd > * {
+table.table.dataTable.table-striped > tbody > tr:nth-of-type(2n+1) > * {
box-shadow: inset 0 0 0 9999px rgba(var(--dt-row-stripe), 0.05);
}
-table.dataTable.table-striped > tbody > tr.odd.selected > * {
+table.table.dataTable.table-striped > tbody > tr:nth-of-type(2n+1).selected > * {
box-shadow: inset 0 0 0 9999px rgba(13, 110, 253, 0.95);
box-shadow: inset 0 0 0 9999px rgba(var(--dt-row-selected), 0.95);
}
-table.dataTable.table-hover > tbody > tr:hover > * {
+table.table.dataTable.table-hover > tbody > tr:hover > * {
box-shadow: inset 0 0 0 9999px rgba(var(--dt-row-hover), 0.075);
}
-table.dataTable.table-hover > tbody > tr.selected:hover > * {
+table.table.dataTable.table-hover > tbody > tr.selected:hover > * {
box-shadow: inset 0 0 0 9999px rgba(13, 110, 253, 0.975);
box-shadow: inset 0 0 0 9999px rgba(var(--dt-row-selected), 0.975);
}
-div.dataTables_wrapper div.dataTables_length label {
+div.dt-container div.dt-length label {
font-weight: normal;
text-align: left;
white-space: nowrap;
}
-div.dataTables_wrapper div.dataTables_length select {
+div.dt-container div.dt-length select {
width: auto;
display: inline-block;
+ margin-right: 0.5em;
}
-div.dataTables_wrapper div.dataTables_filter {
+div.dt-container div.dt-search {
text-align: right;
}
-div.dataTables_wrapper div.dataTables_filter label {
+div.dt-container div.dt-search label {
font-weight: normal;
white-space: nowrap;
text-align: left;
}
-div.dataTables_wrapper div.dataTables_filter input {
+div.dt-container div.dt-search input {
margin-left: 0.5em;
display: inline-block;
width: auto;
}
-div.dataTables_wrapper div.dataTables_info {
+div.dt-container div.dt-info {
padding-top: 0.85em;
}
-div.dataTables_wrapper div.dataTables_paginate {
+div.dt-container div.dt-paging {
margin: 0;
- white-space: nowrap;
- text-align: right;
}
-div.dataTables_wrapper div.dataTables_paginate ul.pagination {
+div.dt-container div.dt-paging ul.pagination {
margin: 2px 0;
- white-space: nowrap;
- justify-content: flex-end;
+ flex-wrap: wrap;
}
-div.dataTables_wrapper div.dt-row {
+div.dt-container div.dt-row {
position: relative;
}
-div.dataTables_scrollHead table.dataTable {
+div.dt-scroll-head table.dataTable {
margin-bottom: 0 !important;
}
-div.dataTables_scrollBody > table {
+div.dt-scroll-body {
+ border-bottom-color: var(--bs-border-color);
+ border-bottom-width: var(--bs-border-width);
+ border-bottom-style: solid;
+}
+div.dt-scroll-body > table {
border-top: none;
margin-top: 0 !important;
margin-bottom: 0 !important;
}
-div.dataTables_scrollBody > table > thead .sorting:before,
-div.dataTables_scrollBody > table > thead .sorting_asc:before,
-div.dataTables_scrollBody > table > thead .sorting_desc:before,
-div.dataTables_scrollBody > table > thead .sorting:after,
-div.dataTables_scrollBody > table > thead .sorting_asc:after,
-div.dataTables_scrollBody > table > thead .sorting_desc:after {
- display: none;
+div.dt-scroll-body > table > tbody > tr:first-child {
+ border-top-width: 0;
}
-div.dataTables_scrollBody > table > tbody tr:first-child th,
-div.dataTables_scrollBody > table > tbody tr:first-child td {
- border-top: none;
+div.dt-scroll-body > table > thead > tr {
+ border-width: 0 !important;
+}
+div.dt-scroll-body > table > tbody > tr:last-child > * {
+ border-bottom: none;
}
-div.dataTables_scrollFoot > .dataTables_scrollFootInner {
+div.dt-scroll-foot > .dt-scroll-footInner {
box-sizing: content-box;
}
-div.dataTables_scrollFoot > .dataTables_scrollFootInner > table {
+div.dt-scroll-foot > .dt-scroll-footInner > table {
margin-top: 0 !important;
border-top: none;
}
+div.dt-scroll-foot > .dt-scroll-footInner > table > tfoot > tr:first-child {
+ border-top-width: 0 !important;
+}
@media screen and (max-width: 767px) {
- div.dataTables_wrapper div.dataTables_length,
- div.dataTables_wrapper div.dataTables_filter,
- div.dataTables_wrapper div.dataTables_info,
- div.dataTables_wrapper div.dataTables_paginate {
+ div.dt-container div.dt-length,
+ div.dt-container div.dt-search,
+ div.dt-container div.dt-info,
+ div.dt-container div.dt-paging {
text-align: center;
}
- div.dataTables_wrapper div.dataTables_paginate ul.pagination {
+ div.dt-container .row {
+ --bs-gutter-y: 0.5rem;
+ }
+ div.dt-container div.dt-paging ul.pagination {
justify-content: center !important;
}
}
table.dataTable.table-sm > thead > tr > th:not(.sorting_disabled) {
padding-right: 20px;
}
-
-table.table-bordered.dataTable {
- border-right-width: 0;
-}
-table.table-bordered.dataTable thead tr:first-child th,
-table.table-bordered.dataTable thead tr:first-child td {
- border-top-width: 1px;
-}
-table.table-bordered.dataTable th,
-table.table-bordered.dataTable td {
- border-left-width: 0;
-}
-table.table-bordered.dataTable th:first-child, table.table-bordered.dataTable th:first-child,
-table.table-bordered.dataTable td:first-child,
-table.table-bordered.dataTable td:first-child {
- border-left-width: 1px;
-}
-table.table-bordered.dataTable th:last-child, table.table-bordered.dataTable th:last-child,
-table.table-bordered.dataTable td:last-child,
-table.table-bordered.dataTable td:last-child {
- border-right-width: 1px;
-}
-table.table-bordered.dataTable th,
-table.table-bordered.dataTable td {
- border-bottom-width: 1px;
+table.dataTable.table-sm > thead > tr > th:not(.sorting_disabled):before, table.dataTable.table-sm > thead > tr > th:not(.sorting_disabled):after {
+ right: 5px;
}
-div.dataTables_scrollHead table.table-bordered {
+div.dt-scroll-head table.table-bordered {
border-bottom-width: 0;
}
-div.table-responsive > div.dataTables_wrapper > div.row {
+div.table-responsive > div.dt-container > div.row {
margin: 0;
}
-div.table-responsive > div.dataTables_wrapper > div.row > div[class^=col-]:first-child {
+div.table-responsive > div.dt-container > div.row > div[class^=col-]:first-child {
padding-left: 0;
}
-div.table-responsive > div.dataTables_wrapper > div.row > div[class^=col-]:last-child {
+div.table-responsive > div.dt-container > div.row > div[class^=col-]:last-child {
padding-right: 0;
}
diff --git a/src/static/scripts/datatables.js b/src/static/scripts/datatables.js
index 735ba65e..f67d3f28 100644
--- a/src/static/scripts/datatables.js
+++ b/src/static/scripts/datatables.js
@@ -4,37 +4,34 @@
*
* To rebuild or modify this file with the latest versions of the included
* software please visit:
- * https://datatables.net/download/#bs5/dt-1.13.6
+ * https://datatables.net/download/#bs5/dt-2.0.0
*
* Included libraries:
- * DataTables 1.13.6
+ * DataTables 2.0.0
*/
-/*! DataTables 1.13.6
- * ©2008-2023 SpryMedia Ltd - datatables.net/license
+/*! DataTables 2.0.0
+ * © SpryMedia Ltd - datatables.net/license
*/
/**
* @summary DataTables
* @description Paginate, search and order HTML tables
- * @version 1.13.6
+ * @version 2.0.0
* @author SpryMedia Ltd
* @contact www.datatables.net
* @copyright SpryMedia Ltd.
*
* This source file is free software, available under the following license:
- * MIT license - http://datatables.net/license
+ * MIT license - https://datatables.net/license
*
* This source file is distributed in the hope that it will be useful, but
* WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
* or FITNESS FOR A PARTICULAR PURPOSE. See the license files for details.
*
- * For details please refer to: http://www.datatables.net
+ * For details please refer to: https://www.datatables.net
*/
-/*jslint evil: true, undef: true, browser: true */
-/*globals $,require,jQuery,define,_selector_run,_selector_opts,_selector_first,_selector_row_indexes,_ext,_Api,_api_register,_api_registerPlural,_re_new_lines,_re_html,_re_formatted_numeric,_re_escape_regex,_empty,_intVal,_numToDecimal,_isNumber,_isHtml,_htmlNumeric,_pluck,_pluck_order,_range,_stripHtml,_unique,_fnBuildAjax,_fnAjaxUpdate,_fnAjaxParameters,_fnAjaxUpdateDraw,_fnAjaxDataSrc,_fnAddColumn,_fnColumnOptions,_fnAdjustColumnSizing,_fnVisibleToColumnIndex,_fnColumnIndexToVisible,_fnVisbleColumns,_fnGetColumns,_fnColumnTypes,_fnApplyColumnDefs,_fnHungarianMap,_fnCamelToHungarian,_fnLanguageCompat,_fnBrowserDetect,_fnAddData,_fnAddTr,_fnNodeToDataIndex,_fnNodeToColumnIndex,_fnGetCellData,_fnSetCellData,_fnSplitObjNotation,_fnGetObjectDataFn,_fnSetObjectDataFn,_fnGetDataMaster,_fnClearTable,_fnDeleteIndex,_fnInvalidate,_fnGetRowElements,_fnCreateTr,_fnBuildHead,_fnDrawHead,_fnDraw,_fnReDraw,_fnAddOptionsHtml,_fnDetectHeader,_fnGetUniqueThs,_fnFeatureHtmlFilter,_fnFilterComplete,_fnFilterCustom,_fnFilterColumn,_fnFilter,_fnFilterCreateSearch,_fnEscapeRegex,_fnFilterData,_fnFeatureHtmlInfo,_fnUpdateInfo,_fnInfoMacros,_fnInitialise,_fnInitComplete,_fnLengthChange,_fnFeatureHtmlLength,_fnFeatureHtmlPaginate,_fnPageChange,_fnFeatureHtmlProcessing,_fnProcessingDisplay,_fnFeatureHtmlTable,_fnScrollDraw,_fnApplyToChildren,_fnCalculateColumnWidths,_fnThrottle,_fnConvertToWidth,_fnGetWidestNode,_fnGetMaxLenString,_fnStringToCss,_fnSortFlatten,_fnSort,_fnSortAria,_fnSortListener,_fnSortAttachListener,_fnSortingClasses,_fnSortData,_fnSaveState,_fnLoadState,_fnSettingsFromNode,_fnLog,_fnMap,_fnBindAction,_fnCallbackReg,_fnCallbackFire,_fnLengthOverflow,_fnRenderer,_fnDataSource,_fnRowAttributes*/
-
(function( factory ) {
"use strict";
@@ -66,15 +63,14 @@
};
}
else {
- return factory( jq, window, window.document );
+ module.exports = factory( jq, window, window.document );
}
}
else {
// Browser
window.DataTable = factory( jQuery, window, document );
}
-}
-(function( $, window, document, undefined ) {
+}(function( $, window, document ) {
"use strict";
@@ -95,762 +91,6 @@
options = selector;
}
- /**
- * Perform a jQuery selector action on the table's TR elements (from the tbody) and
- * return the resulting jQuery object.
- * @param {string|node|jQuery} sSelector jQuery selector or node collection to act on
- * @param {object} [oOpts] Optional parameters for modifying the rows to be included
- * @param {string} [oOpts.filter=none] Select TR elements that meet the current filter
- * criterion ("applied") or all TR elements (i.e. no filter).
- * @param {string} [oOpts.order=current] Order of the TR elements in the processed array.
- * Can be either 'current', whereby the current sorting of the table is used, or
- * 'original' whereby the original order the data was read into the table is used.
- * @param {string} [oOpts.page=all] Limit the selection to the currently displayed page
- * ("current") or not ("all"). If 'current' is given, then order is assumed to be
- * 'current' and filter is 'applied', regardless of what they might be given as.
- * @returns {object} jQuery object, filtered by the given selector.
- * @dtopt API
- * @deprecated Since v1.10
- *
- * @example
- * $(document).ready(function() {
- * var oTable = $('#example').dataTable();
- *
- * // Highlight every second row
- * oTable.$('tr:odd').css('backgroundColor', 'blue');
- * } );
- *
- * @example
- * $(document).ready(function() {
- * var oTable = $('#example').dataTable();
- *
- * // Filter to rows with 'Webkit' in them, add a background colour and then
- * // remove the filter, thus highlighting the 'Webkit' rows only.
- * oTable.fnFilter('Webkit');
- * oTable.$('tr', {"search": "applied"}).css('backgroundColor', 'blue');
- * oTable.fnFilter('');
- * } );
- */
- this.$ = function ( sSelector, oOpts )
- {
- return this.api(true).$( sSelector, oOpts );
- };
-
-
- /**
- * Almost identical to $ in operation, but in this case returns the data for the matched
- * rows - as such, the jQuery selector used should match TR row nodes or TD/TH cell nodes
- * rather than any descendants, so the data can be obtained for the row/cell. If matching
- * rows are found, the data returned is the original data array/object that was used to
- * create the row (or a generated array if from a DOM source).
- *
- * This method is often useful in-combination with $ where both functions are given the
- * same parameters and the array indexes will match identically.
- * @param {string|node|jQuery} sSelector jQuery selector or node collection to act on
- * @param {object} [oOpts] Optional parameters for modifying the rows to be included
- * @param {string} [oOpts.filter=none] Select elements that meet the current filter
- * criterion ("applied") or all elements (i.e. no filter).
- * @param {string} [oOpts.order=current] Order of the data in the processed array.
- * Can be either 'current', whereby the current sorting of the table is used, or
- * 'original' whereby the original order the data was read into the table is used.
- * @param {string} [oOpts.page=all] Limit the selection to the currently displayed page
- * ("current") or not ("all"). If 'current' is given, then order is assumed to be
- * 'current' and filter is 'applied', regardless of what they might be given as.
- * @returns {array} Data for the matched elements. If any elements, as a result of the
- * selector, were not TR, TD or TH elements in the DataTable, they will have a null
- * entry in the array.
- * @dtopt API
- * @deprecated Since v1.10
- *
- * @example
- * $(document).ready(function() {
- * var oTable = $('#example').dataTable();
- *
- * // Get the data from the first row in the table
- * var data = oTable._('tr:first');
- *
- * // Do something useful with the data
- * alert( "First cell is: "+data[0] );
- * } );
- *
- * @example
- * $(document).ready(function() {
- * var oTable = $('#example').dataTable();
- *
- * // Filter to 'Webkit' and get all data for
- * oTable.fnFilter('Webkit');
- * var data = oTable._('tr', {"search": "applied"});
- *
- * // Do something with the data
- * alert( data.length+" rows matched the search" );
- * } );
- */
- this._ = function ( sSelector, oOpts )
- {
- return this.api(true).rows( sSelector, oOpts ).data();
- };
-
-
- /**
- * Create a DataTables Api instance, with the currently selected tables for
- * the Api's context.
- * @param {boolean} [traditional=false] Set the API instance's context to be
- * only the table referred to by the `DataTable.ext.iApiIndex` option, as was
- * used in the API presented by DataTables 1.9- (i.e. the traditional mode),
- * or if all tables captured in the jQuery object should be used.
- * @return {DataTables.Api}
- */
- this.api = function ( traditional )
- {
- return traditional ?
- new _Api(
- _fnSettingsFromNode( this[ _ext.iApiIndex ] )
- ) :
- new _Api( this );
- };
-
-
- /**
- * Add a single new row or multiple rows of data to the table. Please note
- * that this is suitable for client-side processing only - if you are using
- * server-side processing (i.e. "bServerSide": true), then to add data, you
- * must add it to the data source, i.e. the server-side, through an Ajax call.
- * @param {array|object} data The data to be added to the table. This can be:
- * <ul>
- * <li>1D array of data - add a single row with the data provided</li>
- * <li>2D array of arrays - add multiple rows in a single call</li>
- * <li>object - data object when using <i>mData</i></li>
- * <li>array of objects - multiple data objects when using <i>mData</i></li>
- * </ul>
- * @param {bool} [redraw=true] redraw the table or not
- * @returns {array} An array of integers, representing the list of indexes in
- * <i>aoData</i> ({@link DataTable.models.oSettings}) that have been added to
- * the table.
- * @dtopt API
- * @deprecated Since v1.10
- *
- * @example
- * // Global var for counter
- * var giCount = 2;
- *
- * $(document).ready(function() {
- * $('#example').dataTable();
- * } );
- *
- * function fnClickAddRow() {
- * $('#example').dataTable().fnAddData( [
- * giCount+".1",
- * giCount+".2",
- * giCount+".3",
- * giCount+".4" ]
- * );
- *
- * giCount++;
- * }
- */
- this.fnAddData = function( data, redraw )
- {
- var api = this.api( true );
-
- /* Check if we want to add multiple rows or not */
- var rows = Array.isArray(data) && ( Array.isArray(data[0]) || $.isPlainObject(data[0]) ) ?
- api.rows.add( data ) :
- api.row.add( data );
-
- if ( redraw === undefined || redraw ) {
- api.draw();
- }
-
- return rows.flatten().toArray();
- };
-
-
- /**
- * This function will make DataTables recalculate the column sizes, based on the data
- * contained in the table and the sizes applied to the columns (in the DOM, CSS or
- * through the sWidth parameter). This can be useful when the width of the table's
- * parent element changes (for example a window resize).
- * @param {boolean} [bRedraw=true] Redraw the table or not, you will typically want to
- * @dtopt API
- * @deprecated Since v1.10
- *
- * @example
- * $(document).ready(function() {
- * var oTable = $('#example').dataTable( {
- * "sScrollY": "200px",
- * "bPaginate": false
- * } );
- *
- * $(window).on('resize', function () {
- * oTable.fnAdjustColumnSizing();
- * } );
- * } );
- */
- this.fnAdjustColumnSizing = function ( bRedraw )
- {
- var api = this.api( true ).columns.adjust();
- var settings = api.settings()[0];
- var scroll = settings.oScroll;
-
- if ( bRedraw === undefined || bRedraw ) {
- api.draw( false );
- }
- else if ( scroll.sX !== "" || scroll.sY !== "" ) {
- /* If not redrawing, but scrolling, we want to apply the new column sizes anyway */
- _fnScrollDraw( settings );
- }
- };
-
-
- /**
- * Quickly and simply clear a table
- * @param {bool} [bRedraw=true] redraw the table or not
- * @dtopt API
- * @deprecated Since v1.10
- *
- * @example
- * $(document).ready(function() {
- * var oTable = $('#example').dataTable();
- *
- * // Immediately 'nuke' the current rows (perhaps waiting for an Ajax callback...)
- * oTable.fnClearTable();
- * } );
- */
- this.fnClearTable = function( bRedraw )
- {
- var api = this.api( true ).clear();
-
- if ( bRedraw === undefined || bRedraw ) {
- api.draw();
- }
- };
-
-
- /**
- * The exact opposite of 'opening' a row, this function will close any rows which
- * are currently 'open'.
- * @param {node} nTr the table row to 'close'
- * @returns {int} 0 on success, or 1 if failed (can't find the row)
- * @dtopt API
- * @deprecated Since v1.10
- *
- * @example
- * $(document).ready(function() {
- * var oTable;
- *
- * // 'open' an information row when a row is clicked on
- * $('#example tbody tr').click( function () {
- * if ( oTable.fnIsOpen(this) ) {
- * oTable.fnClose( this );
- * } else {
- * oTable.fnOpen( this, "Temporary row opened", "info_row" );
- * }
- * } );
- *
- * oTable = $('#example').dataTable();
- * } );
- */
- this.fnClose = function( nTr )
- {
- this.api( true ).row( nTr ).child.hide();
- };
-
-
- /**
- * Remove a row for the table
- * @param {mixed} target The index of the row from aoData to be deleted, or
- * the TR element you want to delete
- * @param {function|null} [callBack] Callback function
- * @param {bool} [redraw=true] Redraw the table or not
- * @returns {array} The row that was deleted
- * @dtopt API
- * @deprecated Since v1.10
- *
- * @example
- * $(document).ready(function() {
- * var oTable = $('#example').dataTable();
- *
- * // Immediately remove the first row
- * oTable.fnDeleteRow( 0 );
- * } );
- */
- this.fnDeleteRow = function( target, callback, redraw )
- {
- var api = this.api( true );
- var rows = api.rows( target );
- var settings = rows.settings()[0];
- var data = settings.aoData[ rows[0][0] ];
-
- rows.remove();
-
- if ( callback ) {
- callback.call( this, settings, data );
- }
-
- if ( redraw === undefined || redraw ) {
- api.draw();
- }
-
- return data;
- };
-
-
- /**
- * Restore the table to it's original state in the DOM by removing all of DataTables
- * enhancements, alterations to the DOM structure of the table and event listeners.
- * @param {boolean} [remove=false] Completely remove the table from the DOM
- * @dtopt API
- * @deprecated Since v1.10
- *
- * @example
- * $(document).ready(function() {
- * // This example is fairly pointless in reality, but shows how fnDestroy can be used
- * var oTable = $('#example').dataTable();
- * oTable.fnDestroy();
- * } );
- */
- this.fnDestroy = function ( remove )
- {
- this.api( true ).destroy( remove );
- };
-
-
- /**
- * Redraw the table
- * @param {bool} [complete=true] Re-filter and resort (if enabled) the table before the draw.
- * @dtopt API
- * @deprecated Since v1.10
- *
- * @example
- * $(document).ready(function() {
- * var oTable = $('#example').dataTable();
- *
- * // Re-draw the table - you wouldn't want to do it here, but it's an example :-)
- * oTable.fnDraw();
- * } );
- */
- this.fnDraw = function( complete )
- {
- // Note that this isn't an exact match to the old call to _fnDraw - it takes
- // into account the new data, but can hold position.
- this.api( true ).draw( complete );
- };
-
-
- /**
- * Filter the input based on data
- * @param {string} sInput String to filter the table on
- * @param {int|null} [iColumn] Column to limit filtering to
- * @param {bool} [bRegex=false] Treat as regular expression or not
- * @param {bool} [bSmart=true] Perform smart filtering or not
- * @param {bool} [bShowGlobal=true] Show the input global filter in it's input box(es)
- * @param {bool} [bCaseInsensitive=true] Do case-insensitive matching (true) or not (false)
- * @dtopt API
- * @deprecated Since v1.10
- *
- * @example
- * $(document).ready(function() {
- * var oTable = $('#example').dataTable();
- *
- * // Sometime later - filter...
- * oTable.fnFilter( 'test string' );
- * } );
- */
- this.fnFilter = function( sInput, iColumn, bRegex, bSmart, bShowGlobal, bCaseInsensitive )
- {
- var api = this.api( true );
-
- if ( iColumn === null || iColumn === undefined ) {
- api.search( sInput, bRegex, bSmart, bCaseInsensitive );
- }
- else {
- api.column( iColumn ).search( sInput, bRegex, bSmart, bCaseInsensitive );
- }
-
- api.draw();
- };
-
-
- /**
- * Get the data for the whole table, an individual row or an individual cell based on the
- * provided parameters.
- * @param {int|node} [src] A TR row node, TD/TH cell node or an integer. If given as
- * a TR node then the data source for the whole row will be returned. If given as a
- * TD/TH cell node then iCol will be automatically calculated and the data for the
- * cell returned. If given as an integer, then this is treated as the aoData internal
- * data index for the row (see fnGetPosition) and the data for that row used.
- * @param {int} [col] Optional column index that you want the data of.
- * @returns {array|object|string} If mRow is undefined, then the data for all rows is
- * returned. If mRow is defined, just data for that row, and is iCol is
- * defined, only data for the designated cell is returned.
- * @dtopt API
- * @deprecated Since v1.10
- *
- * @example
- * // Row data
- * $(document).ready(function() {
- * oTable = $('#example').dataTable();
- *
- * oTable.$('tr').click( function () {
- * var data = oTable.fnGetData( this );
- * // ... do something with the array / object of data for the row
- * } );
- * } );
- *
- * @example
- * // Individual cell data
- * $(document).ready(function() {
- * oTable = $('#example').dataTable();
- *
- * oTable.$('td').click( function () {
- * var sData = oTable.fnGetData( this );
- * alert( 'The cell clicked on had the value of '+sData );
- * } );
- * } );
- */
- this.fnGetData = function( src, col )
- {
- var api = this.api( true );
-
- if ( src !== undefined ) {
- var type = src.nodeName ? src.nodeName.toLowerCase() : '';
-
- return col !== undefined || type == 'td' || type == 'th' ?
- api.cell( src, col ).data() :
- api.row( src ).data() || null;
- }
-
- return api.data().toArray();
- };
-
-
- /**
- * Get an array of the TR nodes that are used in the table's body. Note that you will
- * typically want to use the '$' API method in preference to this as it is more
- * flexible.
- * @param {int} [iRow] Optional row index for the TR element you want
- * @returns {array|node} If iRow is undefined, returns an array of all TR elements
- * in the table's body, or iRow is defined, just the TR element requested.
- * @dtopt API
- * @deprecated Since v1.10
- *
- * @example
- * $(document).ready(function() {
- * var oTable = $('#example').dataTable();
- *
- * // Get the nodes from the table
- * var nNodes = oTable.fnGetNodes( );
- * } );
- */
- this.fnGetNodes = function( iRow )
- {
- var api = this.api( true );
-
- return iRow !== undefined ?
- api.row( iRow ).node() :
- api.rows().nodes().flatten().toArray();
- };
-
-
- /**
- * Get the array indexes of a particular cell from it's DOM element
- * and column index including hidden columns
- * @param {node} node this can either be a TR, TD or TH in the table's body
- * @returns {int} If nNode is given as a TR, then a single index is returned, or
- * if given as a cell, an array of [row index, column index (visible),
- * column index (all)] is given.
- * @dtopt API
- * @deprecated Since v1.10
- *
- * @example
- * $(document).ready(function() {
- * $('#example tbody td').click( function () {
- * // Get the position of the current data from the node
- * var aPos = oTable.fnGetPosition( this );
- *
- * // Get the data array for this row
- * var aData = oTable.fnGetData( aPos[0] );
- *
- * // Update the data array and return the value
- * aData[ aPos[1] ] = 'clicked';
- * this.innerHTML = 'clicked';
- * } );
- *
- * // Init DataTables
- * oTable = $('#example').dataTable();
- * } );
- */
- this.fnGetPosition = function( node )
- {
- var api = this.api( true );
- var nodeName = node.nodeName.toUpperCase();
-
- if ( nodeName == 'TR' ) {
- return api.row( node ).index();
- }
- else if ( nodeName == 'TD' || nodeName == 'TH' ) {
- var cell = api.cell( node ).index();
-
- return [
- cell.row,
- cell.columnVisible,
- cell.column
- ];
- }
- return null;
- };
-
-
- /**
- * Check to see if a row is 'open' or not.
- * @param {node} nTr the table row to check
- * @returns {boolean} true if the row is currently open, false otherwise
- * @dtopt API
- * @deprecated Since v1.10
- *
- * @example
- * $(document).ready(function() {
- * var oTable;
- *
- * // 'open' an information row when a row is clicked on
- * $('#example tbody tr').click( function () {
- * if ( oTable.fnIsOpen(this) ) {
- * oTable.fnClose( this );
- * } else {
- * oTable.fnOpen( this, "Temporary row opened", "info_row" );
- * }
- * } );
- *
- * oTable = $('#example').dataTable();
- * } );
- */
- this.fnIsOpen = function( nTr )
- {
- return this.api( true ).row( nTr ).child.isShown();
- };
-
-
- /**
- * This function will place a new row directly after a row which is currently
- * on display on the page, with the HTML contents that is passed into the
- * function. This can be used, for example, to ask for confirmation that a
- * particular record should be deleted.
- * @param {node} nTr The table row to 'open'
- * @param {string|node|jQuery} mHtml The HTML to put into the row
- * @param {string} sClass Class to give the new TD cell
- * @returns {node} The row opened. Note that if the table row passed in as the
- * first parameter, is not found in the table, this method will silently
- * return.
- * @dtopt API
- * @deprecated Since v1.10
- *
- * @example
- * $(document).ready(function() {
- * var oTable;
- *
- * // 'open' an information row when a row is clicked on
- * $('#example tbody tr').click( function () {
- * if ( oTable.fnIsOpen(this) ) {
- * oTable.fnClose( this );
- * } else {
- * oTable.fnOpen( this, "Temporary row opened", "info_row" );
- * }
- * } );
- *
- * oTable = $('#example').dataTable();
- * } );
- */
- this.fnOpen = function( nTr, mHtml, sClass )
- {
- return this.api( true )
- .row( nTr )
- .child( mHtml, sClass )
- .show()
- .child()[0];
- };
-
-
- /**
- * Change the pagination - provides the internal logic for pagination in a simple API
- * function. With this function you can have a DataTables table go to the next,
- * previous, first or last pages.
- * @param {string|int} mAction Paging action to take: "first", "previous", "next" or "last"
- * or page number to jump to (integer), note that page 0 is the first page.
- * @param {bool} [bRedraw=true] Redraw the table or not
- * @dtopt API
- * @deprecated Since v1.10
- *
- * @example
- * $(document).ready(function() {
- * var oTable = $('#example').dataTable();
- * oTable.fnPageChange( 'next' );
- * } );
- */
- this.fnPageChange = function ( mAction, bRedraw )
- {
- var api = this.api( true ).page( mAction );
-
- if ( bRedraw === undefined || bRedraw ) {
- api.draw(false);
- }
- };
-
-
- /**
- * Show a particular column
- * @param {int} iCol The column whose display should be changed
- * @param {bool} bShow Show (true) or hide (false) the column
- * @param {bool} [bRedraw=true] Redraw the table or not
- * @dtopt API
- * @deprecated Since v1.10
- *
- * @example
- * $(document).ready(function() {
- * var oTable = $('#example').dataTable();
- *
- * // Hide the second column after initialisation
- * oTable.fnSetColumnVis( 1, false );
- * } );
- */
- this.fnSetColumnVis = function ( iCol, bShow, bRedraw )
- {
- var api = this.api( true ).column( iCol ).visible( bShow );
-
- if ( bRedraw === undefined || bRedraw ) {
- api.columns.adjust().draw();
- }
- };
-
-
- /**
- * Get the settings for a particular table for external manipulation
- * @returns {object} DataTables settings object. See
- * {@link DataTable.models.oSettings}
- * @dtopt API
- * @deprecated Since v1.10
- *
- * @example
- * $(document).ready(function() {
- * var oTable = $('#example').dataTable();
- * var oSettings = oTable.fnSettings();
- *
- * // Show an example parameter from the settings
- * alert( oSettings._iDisplayStart );
- * } );
- */
- this.fnSettings = function()
- {
- return _fnSettingsFromNode( this[_ext.iApiIndex] );
- };
-
-
- /**
- * Sort the table by a particular column
- * @param {int} iCol the data index to sort on. Note that this will not match the
- * 'display index' if you have hidden data entries
- * @dtopt API
- * @deprecated Since v1.10
- *
- * @example
- * $(document).ready(function() {
- * var oTable = $('#example').dataTable();
- *
- * // Sort immediately with columns 0 and 1
- * oTable.fnSort( [ [0,'asc'], [1,'asc'] ] );
- * } );
- */
- this.fnSort = function( aaSort )
- {
- this.api( true ).order( aaSort ).draw();
- };
-
-
- /**
- * Attach a sort listener to an element for a given column
- * @param {node} nNode the element to attach the sort listener to
- * @param {int} iColumn the column that a click on this node will sort on
- * @param {function} [fnCallback] callback function when sort is run
- * @dtopt API
- * @deprecated Since v1.10
- *
- * @example
- * $(document).ready(function() {
- * var oTable = $('#example').dataTable();
- *
- * // Sort on column 1, when 'sorter' is clicked on
- * oTable.fnSortListener( document.getElementById('sorter'), 1 );
- * } );
- */
- this.fnSortListener = function( nNode, iColumn, fnCallback )
- {
- this.api( true ).order.listener( nNode, iColumn, fnCallback );
- };
-
-
- /**
- * Update a table cell or row - this method will accept either a single value to
- * update the cell with, an array of values with one element for each column or
- * an object in the same format as the original data source. The function is
- * self-referencing in order to make the multi column updates easier.
- * @param {object|array|string} mData Data to update the cell/row with
- * @param {node|int} mRow TR element you want to update or the aoData index
- * @param {int} [iColumn] The column to update, give as null or undefined to
- * update a whole row.
- * @param {bool} [bRedraw=true] Redraw the table or not
- * @param {bool} [bAction=true] Perform pre-draw actions or not
- * @returns {int} 0 on success, 1 on error
- * @dtopt API
- * @deprecated Since v1.10
- *
- * @example
- * $(document).ready(function() {
- * var oTable = $('#example').dataTable();
- * oTable.fnUpdate( 'Example update', 0, 0 ); // Single cell
- * oTable.fnUpdate( ['a', 'b', 'c', 'd', 'e'], $('tbody tr')[0] ); // Row
- * } );
- */
- this.fnUpdate = function( mData, mRow, iColumn, bRedraw, bAction )
- {
- var api = this.api( true );
-
- if ( iColumn === undefined || iColumn === null ) {
- api.row( mRow ).data( mData );
- }
- else {
- api.cell( mRow, iColumn ).data( mData );
- }
-
- if ( bAction === undefined || bAction ) {
- api.columns.adjust();
- }
-
- if ( bRedraw === undefined || bRedraw ) {
- api.draw();
- }
- return 0;
- };
-
-
- /**
- * Provide a common method for plug-ins to check the version of DataTables being used, in order
- * to ensure compatibility.
- * @param {string} sVersion Version string to check for, in the format "X.Y.Z". Note that the
- * formats "X" and "X.Y" are also acceptable.
- * @returns {boolean} true if this version of DataTables is greater or equal to the required
- * version, or false if this version of DataTales is not suitable
- * @method
- * @dtopt API
- * @deprecated Since v1.10
- *
- * @example
- * $(document).ready(function() {
- * var oTable = $('#example').dataTable();
- * alert( oTable.fnVersionCheck( '1.9.0' ) );
- * } );
- */
- this.fnVersionCheck = _ext.fnVersionCheck;
-
-
var _that = this;
var emptyInit = options === undefined;
var len = this.length;
@@ -859,14 +99,11 @@
options = {};
}
- this.oApi = this.internal = _ext.internal;
-
- // Extend with old style plug-in API methods
- for ( var fn in DataTable.ext.internal ) {
- if ( fn ) {
- this[fn] = _fnExternApiFunc(fn);
- }
- }
+ // Method to get DT API instance from jQuery object
+ this.api = function ()
+ {
+ return new _Api( this );
+ };
this.each(function() {
// For each initialisation we want to give it a clean initialisation
@@ -876,8 +113,8 @@
_fnExtend( o, options, true ) :
options;
- /*global oInit,_that,emptyInit*/
- var i=0, iLen, j, jLen, k, kLen;
+
+ var i=0, iLen;
var sId = this.getAttribute( 'id' );
var bInitHandedOff = false;
var defaults = DataTable.defaults;
@@ -891,6 +128,8 @@
return;
}
+ $(this).trigger( 'options.dt', oInit );
+
/* Backwards compatibility for the defaults */
_fnCompatOpts( defaults );
_fnCompatCols( defaults.column );
@@ -925,7 +164,7 @@
}
else if ( bDestroy )
{
- s.oInstance.fnDestroy();
+ new DataTable.Api(s).destroy();
break;
}
else
@@ -958,27 +197,35 @@
var oSettings = $.extend( true, {}, DataTable.models.oSettings, {
"sDestroyWidth": $this[0].style.width,
"sInstance": sId,
- "sTableId": sId
+ "sTableId": sId,
+ colgroup: $('<colgroup>').prependTo(this),
+ fastData: function (row, column, type) {
+ return _fnGetCellData(oSettings, row, column, type);
+ }
} );
oSettings.nTable = this;
- oSettings.oApi = _that.internal;
oSettings.oInit = oInit;
allSettings.push( oSettings );
+ // Make a single API instance available for internal handling
+ oSettings.api = new _Api( oSettings );
+
// Need to add the instance after the instance after the settings object has been added
// to the settings array, so we can self reference the table instance if more than one
oSettings.oInstance = (_that.length===1) ? _that : $this.dataTable();
// Backwards compatibility, before we apply all the defaults
_fnCompatOpts( oInit );
- _fnLanguageCompat( oInit.oLanguage );
// If the length menu is given, but the init display length is not, use the length menu
if ( oInit.aLengthMenu && ! oInit.iDisplayLength )
{
- oInit.iDisplayLength = Array.isArray( oInit.aLengthMenu[0] ) ?
- oInit.aLengthMenu[0][0] : oInit.aLengthMenu[0];
+ oInit.iDisplayLength = Array.isArray(oInit.aLengthMenu[0])
+ ? oInit.aLengthMenu[0][0]
+ : $.isPlainObject( oInit.aLengthMenu[0] )
+ ? oInit.aLengthMenu[0].value
+ : oInit.aLengthMenu[0];
}
// Apply the defaults and init options to make a single init object will all
@@ -1001,26 +248,24 @@
"bDeferRender"
] );
_fnMap( oSettings, oInit, [
- "asStripeClasses",
"ajax",
- "fnServerData",
"fnFormatNumber",
"sServerMethod",
"aaSorting",
"aaSortingFixed",
"aLengthMenu",
"sPaginationType",
- "sAjaxSource",
- "sAjaxDataProp",
"iStateDuration",
- "sDom",
"bSortCellsTop",
"iTabIndex",
+ "sDom",
"fnStateLoadCallback",
"fnStateSaveCallback",
"renderer",
"searchDelay",
"rowId",
+ "caption",
+ "layout",
[ "iCookieDuration", "iStateDuration" ], // backwards compat
[ "oSearch", "oPreviousSearch" ],
[ "aoSearchCols", "aoPreSearchCols" ],
@@ -1035,17 +280,16 @@
_fnMap( oSettings.oLanguage, oInit, "fnInfoCallback" );
/* Callback functions which are array driven */
- _fnCallbackReg( oSettings, 'aoDrawCallback', oInit.fnDrawCallback, 'user' );
- _fnCallbackReg( oSettings, 'aoServerParams', oInit.fnServerParams, 'user' );
- _fnCallbackReg( oSettings, 'aoStateSaveParams', oInit.fnStateSaveParams, 'user' );
- _fnCallbackReg( oSettings, 'aoStateLoadParams', oInit.fnStateLoadParams, 'user' );
- _fnCallbackReg( oSettings, 'aoStateLoaded', oInit.fnStateLoaded, 'user' );
- _fnCallbackReg( oSettings, 'aoRowCallback', oInit.fnRowCallback, 'user' );
- _fnCallbackReg( oSettings, 'aoRowCreatedCallback', oInit.fnCreatedRow, 'user' );
- _fnCallbackReg( oSettings, 'aoHeaderCallback', oInit.fnHeaderCallback, 'user' );
- _fnCallbackReg( oSettings, 'aoFooterCallback', oInit.fnFooterCallback, 'user' );
- _fnCallbackReg( oSettings, 'aoInitComplete', oInit.fnInitComplete, 'user' );
- _fnCallbackReg( oSettings, 'aoPreDrawCallback', oInit.fnPreDrawCallback, 'user' );
+ _fnCallbackReg( oSettings, 'aoDrawCallback', oInit.fnDrawCallback );
+ _fnCallbackReg( oSettings, 'aoStateSaveParams', oInit.fnStateSaveParams );
+ _fnCallbackReg( oSettings, 'aoStateLoadParams', oInit.fnStateLoadParams );
+ _fnCallbackReg( oSettings, 'aoStateLoaded', oInit.fnStateLoaded );
+ _fnCallbackReg( oSettings, 'aoRowCallback', oInit.fnRowCallback );
+ _fnCallbackReg( oSettings, 'aoRowCreatedCallback', oInit.fnCreatedRow );
+ _fnCallbackReg( oSettings, 'aoHeaderCallback', oInit.fnHeaderCallback );
+ _fnCallbackReg( oSettings, 'aoFooterCallback', oInit.fnFooterCallback );
+ _fnCallbackReg( oSettings, 'aoInitComplete', oInit.fnInitComplete );
+ _fnCallbackReg( oSettings, 'aoPreDrawCallback', oInit.fnPreDrawCallback );
oSettings.rowIdFn = _fnGetObjectDataFn( oInit.rowId );
@@ -1055,8 +299,11 @@
var oClasses = oSettings.oClasses;
$.extend( oClasses, DataTable.ext.classes, oInit.oClasses );
- $this.addClass( oClasses.sTable );
+ $this.addClass( oClasses.table );
+ if (! oSettings.oFeatures.bPaginate) {
+ oInit.iDisplayStart = 0;
+ }
if ( oSettings.iInitDisplayStart === undefined )
{
@@ -1065,14 +312,6 @@
oSettings._iDisplayStart = oInit.iDisplayStart;
}
- if ( oInit.iDeferLoading !== null )
- {
- oSettings.bDeferLoading = true;
- var tmp = Array.isArray( oInit.iDeferLoading );
- oSettings._iRecordsDisplay = tmp ? oInit.iDeferLoading[0] : oInit.iDeferLoading;
- oSettings._iRecordsTotal = tmp ? oInit.iDeferLoading[1] : oInit.iDeferLoading;
- }
-
/* Language definitions */
var oLanguage = oSettings.oLanguage;
$.extend( true, oLanguage, oInit.oLanguage );
@@ -1088,14 +327,16 @@
url: oLanguage.sUrl,
success: function ( json ) {
_fnCamelToHungarian( defaults.oLanguage, json );
- _fnLanguageCompat( json );
$.extend( true, oLanguage, json, oSettings.oInit.oLanguage );
_fnCallbackFire( oSettings, null, 'i18n', [oSettings]);
_fnInitialise( oSettings );
},
error: function () {
- // Error occurred loading language file, continue on as best we can
+ // Error occurred loading language file
+ _fnLog( oSettings, 0, 'i18n file loading error', 21 );
+
+ // continue on as best we can
_fnInitialise( oSettings );
}
} );
@@ -1106,67 +347,38 @@
}
/*
- * Stripes
- */
- if ( oInit.asStripeClasses === null )
- {
- oSettings.asStripeClasses =[
- oClasses.sStripeOdd,
- oClasses.sStripeEven
- ];
- }
-
- /* Remove row stripe classes if they are already on the table row */
- var stripeClasses = oSettings.asStripeClasses;
- var rowOne = $this.children('tbody').find('tr').eq(0);
- if ( $.inArray( true, $.map( stripeClasses, function(el, i) {
- return rowOne.hasClass(el);
- } ) ) !== -1 ) {
- $('tbody tr', this).removeClass( stripeClasses.join(' ') );
- oSettings.asDestroyStripes = stripeClasses.slice();
- }
-
- /*
* Columns
* See if we should load columns automatically or use defined ones
*/
- var anThs = [];
- var aoColumnsInit;
- var nThead = this.getElementsByTagName('thead');
- if ( nThead.length !== 0 )
- {
- _fnDetectHeader( oSettings.aoHeader, nThead[0] );
- anThs = _fnGetUniqueThs( oSettings );
- }
+ var columnsInit = [];
+ var thead = this.getElementsByTagName('thead');
+ var initHeaderLayout = _fnDetectHeader( oSettings, thead[0] );
- /* If not given a column array, generate one with nulls */
- if ( oInit.aoColumns === null )
- {
- aoColumnsInit = [];
- for ( i=0, iLen=anThs.length ; i<iLen ; i++ )
- {
- aoColumnsInit.push( null );
- }
+ // If we don't have a columns array, then generate one with nulls
+ if ( oInit.aoColumns ) {
+ columnsInit = oInit.aoColumns;
}
- else
- {
- aoColumnsInit = oInit.aoColumns;
+ else if ( initHeaderLayout.length ) {
+ for ( i=0, iLen=initHeaderLayout[0].length ; i<iLen ; i++ ) {
+ columnsInit.push( null );
+ }
}
- /* Add the columns */
- for ( i=0, iLen=aoColumnsInit.length ; i<iLen ; i++ )
- {
- _fnAddColumn( oSettings, anThs ? anThs[i] : null );
+ // Add the columns
+ for ( i=0, iLen=columnsInit.length ; i<iLen ; i++ ) {
+ _fnAddColumn( oSettings );
}
- /* Apply the column definitions */
- _fnApplyColumnDefs( oSettings, oInit.aoColumnDefs, aoColumnsInit, function (iCol, oDef) {
+ // Apply the column definitions
+ _fnApplyColumnDefs( oSettings, oInit.aoColumnDefs, columnsInit, initHeaderLayout, function (iCol, oDef) {
_fnColumnOptions( oSettings, iCol, oDef );
} );
/* HTML5 attribute detection - build an mData object automatically if the
* attributes are found
*/
+ var rowOne = $this.children('tbody').find('tr').eq(0);
+
if ( rowOne.length ) {
var a = function ( cell, name ) {
return cell.getAttribute( 'data-'+name ) !== null ? name : null;
@@ -1219,44 +431,39 @@
*/
_fnSortingClasses( oSettings );
- if ( features.bSort ) {
- _fnCallbackReg( oSettings, 'aoDrawCallback', function () {
- if ( oSettings.bSorted ) {
- var aSort = _fnSortFlatten( oSettings );
- var sortedColumns = {};
-
- $.each( aSort, function (i, val) {
- sortedColumns[ val.src ] = val.dir;
- } );
-
- _fnCallbackFire( oSettings, null, 'order', [oSettings, aSort, sortedColumns] );
- _fnSortAria( oSettings );
- }
- } );
- }
-
_fnCallbackReg( oSettings, 'aoDrawCallback', function () {
if ( oSettings.bSorted || _fnDataSource( oSettings ) === 'ssp' || features.bDeferRender ) {
_fnSortingClasses( oSettings );
}
- }, 'sc' );
+ } );
/*
* Final init
* Cache the header, body and footer as required, creating them if needed
*/
+ var caption = $this.children('caption');
- // Work around for Webkit bug 83867 - store the caption-side before removing from doc
- var captions = $this.children('caption').each( function () {
- this._captionSide = $(this).css('caption-side');
- } );
+ if ( oSettings.caption ) {
+ if ( caption.length === 0 ) {
+ caption = $('<caption/>').appendTo( $this );
+ }
+
+ caption.html( oSettings.caption );
+ }
+
+ // Store the caption side, so we can remove the element from the document
+ // when creating the element
+ if (caption.length) {
+ caption[0]._captionSide = caption.css('caption-side');
+ oSettings.captionNode = caption[0];
+ }
- var thead = $this.children('thead');
if ( thead.length === 0 ) {
thead = $('<thead/>').appendTo($this);
}
oSettings.nTHead = thead[0];
+ $('tr', thead).addClass(oClasses.thead.row);
var tbody = $this.children('tbody');
if ( tbody.length === 0 ) {
@@ -1265,31 +472,22 @@
oSettings.nTBody = tbody[0];
var tfoot = $this.children('tfoot');
- if ( tfoot.length === 0 && captions.length > 0 && (oSettings.oScroll.sX !== "" || oSettings.oScroll.sY !== "") ) {
+ if ( tfoot.length === 0 ) {
// If we are a scrolling table, and no footer has been given, then we need to create
// a tfoot element for the caption element to be appended to
tfoot = $('<tfoot/>').appendTo($this);
}
+ oSettings.nTFoot = tfoot[0];
+ $('tr', tfoot).addClass(oClasses.tfoot.row);
- if ( tfoot.length === 0 || tfoot.children().length === 0 ) {
- $this.addClass( oClasses.sNoFooter );
- }
- else if ( tfoot.length > 0 ) {
- oSettings.nTFoot = tfoot[0];
- _fnDetectHeader( oSettings.aoFooter, oSettings.nTFoot );
- }
-
- /* Check if there is data passing into the constructor */
+ // Check if there is data passing into the constructor
if ( oInit.aaData ) {
for ( i=0 ; i<oInit.aaData.length ; i++ ) {
_fnAddData( oSettings, oInit.aaData[ i ] );
}
}
- else if ( oSettings.bDeferLoading || _fnDataSource( oSettings ) == 'dom' ) {
- /* Grab the data from the page - only do this when deferred loading or no Ajax
- * source since there is no point in reading the DOM data if we are then going
- * to replace it with Ajax data
- */
+ else if ( _fnDataSource( oSettings ) == 'dom' ) {
+ // Grab the data from the page
_fnAddTr( oSettings, $(oSettings.nTBody).children('tr') );
}
@@ -1308,7 +506,7 @@
};
/* Must be done after everything which can be overridden by the state saving! */
- _fnCallbackReg( oSettings, 'aoDrawCallback', _fnSaveState, 'state_save' );
+ _fnCallbackReg( oSettings, 'aoDrawCallback', _fnSaveState );
if ( oInit.bStateSave )
{
@@ -1325,6 +523,569 @@
};
+
+ /**
+ * DataTables extensions
+ *
+ * This namespace acts as a collection area for plug-ins that can be used to
+ * extend DataTables capabilities. Indeed many of the build in methods
+ * use this method to provide their own capabilities (sorting methods for
+ * example).
+ *
+ * Note that this namespace is aliased to `jQuery.fn.dataTableExt` for legacy
+ * reasons
+ *
+ * @namespace
+ */
+ DataTable.ext = _ext = {
+ /**
+ * Buttons. For use with the Buttons extension for DataTables. This is
+ * defined here so other extensions can define buttons regardless of load
+ * order. It is _not_ used by DataTables core.
+ *
+ * @type object
+ * @default {}
+ */
+ buttons: {},
+
+
+ /**
+ * Element class names
+ *
+ * @type object
+ * @default {}
+ */
+ classes: {},
+
+
+ /**
+ * DataTables build type (expanded by the download builder)
+ *
+ * @type string
+ */
+ build:"bs5/dt-2.0.0",
+
+
+ /**
+ * Error reporting.
+ *
+ * How should DataTables report an error. Can take the value 'alert',
+ * 'throw', 'none' or a function.
+ *
+ * @type string|function
+ * @default alert
+ */
+ errMode: "alert",
+
+
+ /**
+ * Legacy so v1 plug-ins don't throw js errors on load
+ */
+ feature: [],
+
+ /**
+ * Feature plug-ins.
+ *
+ * This is an object of callbacks which provide the features for DataTables
+ * to be initialised via the `layout` option.
+ */
+ features: {},
+
+
+ /**
+ * Row searching.
+ *
+ * This method of searching is complimentary to the default type based
+ * searching, and a lot more comprehensive as it allows you complete control
+ * over the searching logic. Each element in this array is a function
+ * (parameters described below) that is called for every row in the table,
+ * and your logic decides if it should be included in the searching data set
+ * or not.
+ *
+ * Searching functions have the following input parameters:
+ *
+ * 1. `{object}` DataTables settings object: see
+ * {@link DataTable.models.oSettings}
+ * 2. `{array|object}` Data for the row to be processed (same as the
+ * original format that was passed in as the data source, or an array
+ * from a DOM data source
+ * 3. `{int}` Row index ({@link DataTable.models.oSettings.aoData}), which
+ * can be useful to retrieve the `TR` element if you need DOM interaction.
+ *
+ * And the following return is expected:
+ *
+ * * {boolean} Include the row in the searched result set (true) or not
+ * (false)
+ *
+ * Note that as with the main search ability in DataTables, technically this
+ * is "filtering", since it is subtractive. However, for consistency in
+ * naming we call it searching here.
+ *
+ * @type array
+ * @default []
+ *
+ * @example
+ * // The following example shows custom search being applied to the
+ * // fourth column (i.e. the data[3] index) based on two input values
+ * // from the end-user, matching the data in a certain range.
+ * $.fn.dataTable.ext.search.push(
+ * function( settings, data, dataIndex ) {
+ * var min = document.getElementById('min').value * 1;
+ * var max = document.getElementById('max').value * 1;
+ * var version = data[3] == "-" ? 0 : data[3]*1;
+ *
+ * if ( min == "" && max == "" ) {
+ * return true;
+ * }
+ * else if ( min == "" && version < max ) {
+ * return true;
+ * }
+ * else if ( min < version && "" == max ) {
+ * return true;
+ * }
+ * else if ( min < version && version < max ) {
+ * return true;
+ * }
+ * return false;
+ * }
+ * );
+ */
+ search: [],
+
+
+ /**
+ * Selector extensions
+ *
+ * The `selector` option can be used to extend the options available for the
+ * selector modifier options (`selector-modifier` object data type) that
+ * each of the three built in selector types offer (row, column and cell +
+ * their plural counterparts). For example the Select extension uses this
+ * mechanism to provide an option to select only rows, columns and cells
+ * that have been marked as selected by the end user (`{selected: true}`),
+ * which can be used in conjunction with the existing built in selector
+ * options.
+ *
+ * Each property is an array to which functions can be pushed. The functions
+ * take three attributes:
+ *
+ * * Settings object for the host table
+ * * Options object (`selector-modifier` object type)
+ * * Array of selected item indexes
+ *
+ * The return is an array of the resulting item indexes after the custom
+ * selector has been applied.
+ *
+ * @type object
+ */
+ selector: {
+ cell: [],
+ column: [],
+ row: []
+ },
+
+
+ /**
+ * Legacy configuration options. Enable and disable legacy options that
+ * are available in DataTables.
+ *
+ * @type object
+ */
+ legacy: {
+ /**
+ * Enable / disable DataTables 1.9 compatible server-side processing
+ * requests
+ *
+ * @type boolean
+ * @default null
+ */
+ ajax: null
+ },
+
+
+ /**
+ * Pagination plug-in methods.
+ *
+ * Each entry in this object is a function and defines which buttons should
+ * be shown by the pagination rendering method that is used for the table:
+ * {@link DataTable.ext.renderer.pageButton}. The renderer addresses how the
+ * buttons are displayed in the document, while the functions here tell it
+ * what buttons to display. This is done by returning an array of button
+ * descriptions (what each button will do).
+ *
+ * Pagination types (the four built in options and any additional plug-in
+ * options defined here) can be used through the `paginationType`
+ * initialisation parameter.
+ *
+ * The functions defined take two parameters:
+ *
+ * 1. `{int} page` The current page index
+ * 2. `{int} pages` The number of pages in the table
+ *
+ * Each function is expected to return an array where each element of the
+ * array can be one of:
+ *
+ * * `first` - Jump to first page when activated
+ * * `last` - Jump to last page when activated
+ * * `previous` - Show previous page when activated
+ * * `next` - Show next page when activated
+ * * `{int}` - Show page of the index given
+ * * `{array}` - A nested array containing the above elements to add a
+ * containing 'DIV' element (might be useful for styling).
+ *
+ * Note that DataTables v1.9- used this object slightly differently whereby
+ * an object with two functions would be defined for each plug-in. That
+ * ability is still supported by DataTables 1.10+ to provide backwards
+ * compatibility, but this option of use is now decremented and no longer
+ * documented in DataTables 1.10+.
+ *
+ * @type object
+ * @default {}
+ *
+ * @example
+ * // Show previous, next and current page buttons only
+ * $.fn.dataTableExt.oPagination.current = function ( page, pages ) {
+ * return [ 'previous', page, 'next' ];
+ * };
+ */
+ pager: {},
+
+
+ renderer: {
+ pageButton: {},
+ header: {}
+ },
+
+
+ /**
+ * Ordering plug-ins - custom data source
+ *
+ * The extension options for ordering of data available here is complimentary
+ * to the default type based ordering that DataTables typically uses. It
+ * allows much greater control over the the data that is being used to
+ * order a column, but is necessarily therefore more complex.
+ *
+ * This type of ordering is useful if you want to do ordering based on data
+ * live from the DOM (for example the contents of an 'input' element) rather
+ * than just the static string that DataTables knows of.
+ *
+ * The way these plug-ins work is that you create an array of the values you
+ * wish to be ordering for the column in question and then return that
+ * array. The data in the array much be in the index order of the rows in
+ * the table (not the currently ordering order!). Which order data gathering
+ * function is run here depends on the `dt-init columns.orderDataType`
+ * parameter that is used for the column (if any).
+ *
+ * The functions defined take two parameters:
+ *
+ * 1. `{object}` DataTables settings object: see
+ * {@link DataTable.models.oSettings}
+ * 2. `{int}` Target column index
+ *
+ * Each function is expected to return an array:
+ *
+ * * `{array}` Data for the column to be ordering upon
+ *
+ * @type array
+ *
+ * @example
+ * // Ordering using `input` node values
+ * $.fn.dataTable.ext.order['dom-text'] = function ( settings, col )
+ * {
+ * return this.api().column( col, {order:'index'} ).nodes().map( function ( td, i ) {
+ * return $('input', td).val();
+ * } );
+ * }
+ */
+ order: {},
+
+
+ /**
+ * Type based plug-ins.
+ *
+ * Each column in DataTables has a type assigned to it, either by automatic
+ * detection or by direct assignment using the `type` option for the column.
+ * The type of a column will effect how it is ordering and search (plug-ins
+ * can also make use of the column type if required).
+ *
+ * @namespace
+ */
+ type: {
+ /**
+ * Automatic column class assignment
+ */
+ className: {},
+
+ /**
+ * Type detection functions.
+ *
+ * The functions defined in this object are used to automatically detect
+ * a column's type, making initialisation of DataTables super easy, even
+ * when complex data is in the table.
+ *
+ * The functions defined take two parameters:
+ *
+ * 1. `{*}` Data from the column cell to be analysed
+ * 2. `{settings}` DataTables settings object. This can be used to
+ * perform context specific type detection - for example detection
+ * based on language settings such as using a comma for a decimal
+ * place. Generally speaking the options from the settings will not
+ * be required
+ *
+ * Each function is expected to return:
+ *
+ * * `{string|null}` Data type detected, or null if unknown (and thus
+ * pass it on to the other type detection functions.
+ *
+ * @type array
+ *
+ * @example
+ * // Currency type detection plug-in:
+ * $.fn.dataTable.ext.type.detect.push(
+ * function ( data, settings ) {
+ * // Check the numeric part
+ * if ( ! data.substring(1).match(/[0-9]/) ) {
+ * return null;
+ * }
+ *
+ * // Check prefixed by currency
+ * if ( data.charAt(0) == '$' || data.charAt(0) == '&pound;' ) {
+ * return 'currency';
+ * }
+ * return null;
+ * }
+ * );
+ */
+ detect: [],
+
+ /**
+ * Automatic renderer assignment
+ */
+ render: {},
+
+
+ /**
+ * Type based search formatting.
+ *
+ * The type based searching functions can be used to pre-format the
+ * data to be search on. For example, it can be used to strip HTML
+ * tags or to de-format telephone numbers for numeric only searching.
+ *
+ * Note that is a search is not defined for a column of a given type,
+ * no search formatting will be performed.
+ *
+ * Pre-processing of searching data plug-ins - When you assign the sType
+ * for a column (or have it automatically detected for you by DataTables
+ * or a type detection plug-in), you will typically be using this for
+ * custom sorting, but it can also be used to provide custom searching
+ * by allowing you to pre-processing the data and returning the data in
+ * the format that should be searched upon. This is done by adding
+ * functions this object with a parameter name which matches the sType
+ * for that target column. This is the corollary of <i>afnSortData</i>
+ * for searching data.
+ *
+ * The functions defined take a single parameter:
+ *
+ * 1. `{*}` Data from the column cell to be prepared for searching
+ *
+ * Each function is expected to return:
+ *
+ * * `{string|null}` Formatted string that will be used for the searching.
+ *
+ * @type object
+ * @default {}
+ *
+ * @example
+ * $.fn.dataTable.ext.type.search['title-numeric'] = function ( d ) {
+ * return d.replace(/\n/g," ").replace( /<.*?>/g, "" );
+ * }
+ */
+ search: {},
+
+
+ /**
+ * Type based ordering.
+ *
+ * The column type tells DataTables what ordering to apply to the table
+ * when a column is sorted upon. The order for each type that is defined,
+ * is defined by the functions available in this object.
+ *
+ * Each ordering option can be described by three properties added to
+ * this object:
+ *
+ * * `{type}-pre` - Pre-formatting function
+ * * `{type}-asc` - Ascending order function
+ * * `{type}-desc` - Descending order function
+ *
+ * All three can be used together, only `{type}-pre` or only
+ * `{type}-asc` and `{type}-desc` together. It is generally recommended
+ * that only `{type}-pre` is used, as this provides the optimal
+ * implementation in terms of speed, although the others are provided
+ * for compatibility with existing Javascript sort functions.
+ *
+ * `{type}-pre`: Functions defined take a single parameter:
+ *
+ * 1. `{*}` Data from the column cell to be prepared for ordering
+ *
+ * And return:
+ *
+ * * `{*}` Data to be sorted upon
+ *
+ * `{type}-asc` and `{type}-desc`: Functions are typical Javascript sort
+ * functions, taking two parameters:
+ *
+ * 1. `{*}` Data to compare to the second parameter
+ * 2. `{*}` Data to compare to the first parameter
+ *
+ * And returning:
+ *
+ * * `{*}` Ordering match: <0 if first parameter should be sorted lower
+ * than the second parameter, ===0 if the two parameters are equal and
+ * >0 if the first parameter should be sorted height than the second
+ * parameter.
+ *
+ * @type object
+ * @default {}
+ *
+ * @example
+ * // Numeric ordering of formatted numbers with a pre-formatter
+ * $.extend( $.fn.dataTable.ext.type.order, {
+ * "string-pre": function(x) {
+ * a = (a === "-" || a === "") ? 0 : a.replace( /[^\d\-\.]/g, "" );
+ * return parseFloat( a );
+ * }
+ * } );
+ *
+ * @example
+ * // Case-sensitive string ordering, with no pre-formatting method
+ * $.extend( $.fn.dataTable.ext.order, {
+ * "string-case-asc": function(x,y) {
+ * return ((x < y) ? -1 : ((x > y) ? 1 : 0));
+ * },
+ * "string-case-desc": function(x,y) {
+ * return ((x < y) ? 1 : ((x > y) ? -1 : 0));
+ * }
+ * } );
+ */
+ order: {}
+ },
+
+ /**
+ * Unique DataTables instance counter
+ *
+ * @type int
+ * @private
+ */
+ _unique: 0,
+
+
+ //
+ // Depreciated
+ // The following properties are retained for backwards compatibility only.
+ // The should not be used in new projects and will be removed in a future
+ // version
+ //
+
+ /**
+ * Version check function.
+ * @type function
+ * @depreciated Since 1.10
+ */
+ fnVersionCheck: DataTable.fnVersionCheck,
+
+
+ /**
+ * Index for what 'this' index API functions should use
+ * @type int
+ * @deprecated Since v1.10
+ */
+ iApiIndex: 0,
+
+
+ /**
+ * Software version
+ * @type string
+ * @deprecated Since v1.10
+ */
+ sVersion: DataTable.version
+ };
+
+
+ //
+ // Backwards compatibility. Alias to pre 1.10 Hungarian notation counter parts
+ //
+ $.extend( _ext, {
+ afnFiltering: _ext.search,
+ aTypes: _ext.type.detect,
+ ofnSearch: _ext.type.search,
+ oSort: _ext.type.order,
+ afnSortData: _ext.order,
+ aoFeatures: _ext.feature,
+ oStdClasses: _ext.classes,
+ oPagination: _ext.pager
+ } );
+
+
+ $.extend( DataTable.ext.classes, {
+ container: 'dt-container',
+ empty: {
+ row: 'dt-empty'
+ },
+ info: {
+ container: 'dt-info'
+ },
+ length: {
+ container: 'dt-length',
+ select: 'dt-input'
+ },
+ order: {
+ canAsc: 'dt-orderable-asc',
+ canDesc: 'dt-orderable-desc',
+ isAsc: 'dt-ordering-asc',
+ isDesc: 'dt-ordering-desc',
+ none: 'dt-orderable-none',
+ position: 'sorting_'
+ },
+ processing: {
+ container: 'dt-processing'
+ },
+ scrolling: {
+ body: 'dt-scroll-body',
+ container: 'dt-scroll',
+ footer: {
+ self: 'dt-scroll-foot',
+ inner: 'dt-scroll-footInner'
+ },
+ header: {
+ self: 'dt-scroll-head',
+ inner: 'dt-scroll-headInner'
+ }
+ },
+ search: {
+ container: 'dt-search',
+ input: 'dt-input'
+ },
+ table: 'dataTable',
+ tbody: {
+ cell: '',
+ row: ''
+ },
+ thead: {
+ cell: '',
+ row: ''
+ },
+ tfoot: {
+ cell: '',
+ row: ''
+ },
+ paging: {
+ active: 'current',
+ button: 'dt-paging-button',
+ container: 'dt-paging',
+ disabled: 'disabled'
+ }
+ } );
+
+
/*
* It is useful to have variables which are scoped locally so only the
* DataTables functions can access them and they don't leak into global space.
@@ -1338,7 +1099,6 @@
// Defined else where
// _selector_run
// _selector_opts
- // _selector_first
// _selector_row_indexes
var _ext; // DataTable.ext
@@ -1352,12 +1112,12 @@
// This is not strict ISO8601 - Date.parse() is quite lax, although
// implementations differ between browsers.
- var _re_date = /^\d{2,4}[\.\/\-]\d{1,2}[\.\/\-]\d{1,2}([T ]{1}\d{1,2}[:\.]\d{2}([\.:]\d{2})?)?$/;
+ var _re_date = /^\d{2,4}[./-]\d{1,2}[./-]\d{1,2}([T ]{1}\d{1,2}[:.]\d{2}([.:]\d{2})?)?$/;
// Escape regular expression special characters
var _re_escape_regex = new RegExp( '(\\' + [ '/', '.', '*', '+', '?', '|', '(', ')', '[', ']', '{', '}', '\\', '$', '^', '-' ].join('|\\') + ')', 'g' );
- // http://en.wikipedia.org/wiki/Foreign_exchange_market
+ // https://en.wikipedia.org/wiki/Foreign_exchange_market
// - \u20BD - Russian ruble.
// - \u20a9 - South Korean Won
// - \u20BA - Turkish Lira
@@ -1427,12 +1187,17 @@
return _empty( d ) || typeof d === 'string';
};
-
+ // Is a string a number surrounded by HTML?
var _htmlNumeric = function ( d, decimalPoint, formatted ) {
if ( _empty( d ) ) {
return true;
}
+ // input and select strings mean that this isn't just a number
+ if (typeof d === 'string' && d.match(/<(input|select)/i)) {
+ return null;
+ }
+
var html = _isHtml( d );
return ! html ?
null :
@@ -1485,7 +1250,9 @@
}
else {
for ( ; i<ien ; i++ ) {
- out.push( a[ order[i] ][ prop ] );
+ if ( a[ order[i] ] ) {
+ out.push( a[ order[i] ][ prop ] );
+ }
}
}
@@ -1528,13 +1295,44 @@
return out;
};
-
+ // Replaceable function in api.util
var _stripHtml = function ( d ) {
return d
.replace( _re_html, '' ) // Complete tags
.replace(/<script/i, ''); // Safety for incomplete script tag
};
+ // Replaceable function in api.util
+ var _escapeHtml = function ( d ) {
+ if (Array.isArray(d)) {
+ d = d.join(',');
+ }
+
+ return typeof d === 'string' ?
+ d
+ .replace(/&/g, '&amp;')
+ .replace(/</g, '&lt;')
+ .replace(/>/g, '&gt;')
+ .replace(/"/g, '&quot;') :
+ d;
+ };
+
+ // Remove diacritics from a string by decomposing it and then removing
+ // non-ascii characters
+ var _normalize = function (str, both) {
+ if (typeof str !== 'string') {
+ return str;
+ }
+
+ // It is faster to just run `normalize` than it is to check if
+ // we need to with a regex!
+ var res = str.normalize("NFD");
+
+ // Equally, here we check if a regex is needed or not
+ return res.length !== str.length
+ ? (both === true ? str + ' ' : '' ) + res.replace(/[\u0300-\u036f]/g, "")
+ : res;
+ }
/**
* Determine if all values in the array are unique. This means we can short
@@ -1574,13 +1372,17 @@
*/
var _unique = function ( src )
{
+ if (Array.from && Set) {
+ return Array.from(new Set(src));
+ }
+
if ( _areAllUnique( src ) ) {
return src.slice();
}
// A faster unique method is to use object keys to identify used values,
// but this doesn't work with arrays or objects, which we must also
- // consider. See jsperf.com/compare-array-unique-versions/4 for more
+ // consider. See jsperf.app/compare-array-unique-versions/4 for more
// information.
var
out = [],
@@ -1615,40 +1417,20 @@
else {
out.push(val);
}
-
+
return out;
}
- var _includes = function (search, start) {
- if (start === undefined) {
- start = 0;
+ // Similar to jQuery's addClass, but use classList.add
+ function _addClass(el, name) {
+ if (name) {
+ name.split(' ').forEach(function (n) {
+ if (n) {
+ // `add` does deduplication, so no need to check `contains`
+ el.classList.add(n);
+ }
+ });
}
-
- return this.indexOf(search, start) !== -1;
- };
-
- // Array.isArray polyfill.
- // https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Array/isArray
- if (! Array.isArray) {
- Array.isArray = function(arg) {
- return Object.prototype.toString.call(arg) === '[object Array]';
- };
- }
-
- if (! Array.prototype.includes) {
- Array.prototype.includes = _includes;
- }
-
- // .trim() polyfill
- // https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/String/trim
- if (!String.prototype.trim) {
- String.prototype.trim = function () {
- return this.replace(/^[\s\uFEFF\xA0]+|[\s\uFEFF\xA0]+$/g, '');
- };
- }
-
- if (! String.prototype.includes) {
- String.prototype.includes = _includes;
}
/**
@@ -1663,6 +1445,43 @@
*/
DataTable.util = {
/**
+ * Return a string with diacritic characters decomposed
+ * @param {*} mixed Function or string to normalize
+ * @param {*} both Return original string and the normalized string
+ * @returns String or undefined
+ */
+ diacritics: function (mixed, both) {
+ var type = typeof mixed;
+
+ if (type !== 'function') {
+ return _normalize(mixed, both);
+ }
+ _normalize = mixed;
+ },
+
+ /**
+ * Debounce a function
+ *
+ * @param {function} fn Function to be called
+ * @param {integer} freq Call frequency in mS
+ * @return {function} Wrapped function
+ */
+ debounce: function ( fn, timeout ) {
+ var timer;
+
+ return function () {
+ var that = this;
+ var args = arguments;
+
+ clearTimeout(timer);
+
+ timer = setTimeout( function () {
+ fn.apply(that, args);
+ }, timeout || 250 );
+ };
+ },
+
+ /**
* Throttle the calls to a function. Arguments and context are maintained
* for the throttled function.
*
@@ -1697,7 +1516,6 @@
};
},
-
/**
* Escape a string such that it can be used in a regular expression
*
@@ -1731,9 +1549,10 @@
source( data, 'set', val, meta );
};
}
- else if ( typeof source === 'string' && (source.indexOf('.') !== -1 ||
- source.indexOf('[') !== -1 || source.indexOf('(') !== -1) )
- {
+ else if (
+ typeof source === 'string' && (source.indexOf('.') !== -1 ||
+ source.indexOf('[') !== -1 || source.indexOf('(') !== -1)
+ ) {
// Like the get, we need to get data from a nested object
var setData = function (data, val, src) {
var a = _fnSplitObjNotation( src ), b;
@@ -1849,9 +1668,10 @@
return source( data, type, row, meta );
};
}
- else if ( typeof source === 'string' && (source.indexOf('.') !== -1 ||
- source.indexOf('[') !== -1 || source.indexOf('(') !== -1) )
- {
+ else if (
+ typeof source === 'string' && (source.indexOf('.') !== -1 ||
+ source.indexOf('[') !== -1 || source.indexOf('(') !== -1)
+ ) {
/* If there is a . in the source string then the data source is in a
* nested object so we loop over the data for each level to get the next
* level down. On each loop we test for undefined, and if found immediately
@@ -1926,11 +1746,39 @@
}
else {
// Array or flat object mapping
- return function (data, type) { // row and meta also passed, but not used
+ return function (data) { // row and meta also passed, but not used
return data[source];
};
}
- }
+ },
+
+ stripHtml: function (mixed) {
+ var type = typeof mixed;
+
+ if (type === 'function') {
+ _stripHtml = mixed;
+ return;
+ }
+ else if (type === 'string') {
+ return _stripHtml(mixed);
+ }
+ return mixed;
+ },
+
+ escapeHtml: function (mixed) {
+ var type = typeof mixed;
+
+ if (type === 'function') {
+ _escapeHtml = mixed;
+ return;
+ }
+ else if (type === 'string' || Array.isArray(mixed)) {
+ return _escapeHtml(mixed);
+ }
+ return mixed;
+ },
+
+ unique: _unique
};
@@ -1950,7 +1798,7 @@
newKey,
map = {};
- $.each( o, function (key, val) {
+ $.each( o, function (key) {
match = key.match(/^([^A-Z]+?)([A-Z])/);
if ( match && hungarian.indexOf(match[1]+' ') !== -1 )
@@ -1988,7 +1836,7 @@
var hungarianKey;
- $.each( user, function (key, val) {
+ $.each( user, function (key) {
hungarianKey = src._hungarianMap[ key ];
if ( hungarianKey !== undefined && (force || user[hungarianKey] === undefined) )
@@ -2011,57 +1859,6 @@
} );
}
-
- /**
- * Language compatibility - when certain options are given, and others aren't, we
- * need to duplicate the values over, in order to provide backwards compatibility
- * with older language files.
- * @param {object} oSettings dataTables settings object
- * @memberof DataTable#oApi
- */
- function _fnLanguageCompat( lang )
- {
- // Note the use of the Hungarian notation for the parameters in this method as
- // this is called after the mapping of camelCase to Hungarian
- var defaults = DataTable.defaults.oLanguage;
-
- // Default mapping
- var defaultDecimal = defaults.sDecimal;
- if ( defaultDecimal ) {
- _addNumericSort( defaultDecimal );
- }
-
- if ( lang ) {
- var zeroRecords = lang.sZeroRecords;
-
- // Backwards compatibility - if there is no sEmptyTable given, then use the same as
- // sZeroRecords - assuming that is given.
- if ( ! lang.sEmptyTable && zeroRecords &&
- defaults.sEmptyTable === "No data available in table" )
- {
- _fnMap( lang, lang, 'sZeroRecords', 'sEmptyTable' );
- }
-
- // Likewise with loading records
- if ( ! lang.sLoadingRecords && zeroRecords &&
- defaults.sLoadingRecords === "Loading..." )
- {
- _fnMap( lang, lang, 'sZeroRecords', 'sLoadingRecords' );
- }
-
- // Old parameter name of the thousands separator mapped onto the new
- if ( lang.sInfoThousands ) {
- lang.sThousands = lang.sInfoThousands;
- }
-
- var decimal = lang.sDecimal;
- if ( decimal && defaultDecimal !== decimal ) {
- _addNumericSort( decimal );
- }
- }
- }
-
-
/**
* Map one parameter onto another
* @param {object} o Object to map
@@ -2113,6 +1910,11 @@
}
}
}
+
+ // Enable search delay if server-side processing is enabled
+ if (init.serverSide && ! init.searchDelay) {
+ init.searchDelay = 400;
+ }
}
@@ -2156,7 +1958,7 @@
.css( {
position: 'fixed',
top: 0,
- left: $(window).scrollLeft()*-1, // allow for scrolling
+ left: -1 * window.pageXOffset, // allow for scrolling
height: 1,
width: 1,
overflow: 'hidden'
@@ -2183,31 +1985,13 @@
var outer = n.children();
var inner = outer.children();
- // Numbers below, in order, are:
- // inner.offsetWidth, inner.clientWidth, outer.offsetWidth, outer.clientWidth
- //
- // IE6 XP: 100 100 100 83
- // IE7 Vista: 100 100 100 83
- // IE 8+ Windows: 83 83 100 83
- // Evergreen Windows: 83 83 100 83
- // Evergreen Mac with scrollbars: 85 85 100 85
- // Evergreen Mac without scrollbars: 100 100 100 100
-
// Get scrollbar width
browser.barWidth = outer[0].offsetWidth - outer[0].clientWidth;
- // IE6/7 will oversize a width 100% element inside a scrolling element, to
- // include the width of the scrollbar, while other browsers ensure the inner
- // element is contained without forcing scrolling
- browser.bScrollOversize = inner[0].offsetWidth === 100 && outer[0].clientWidth !== 100;
-
// In rtl text layout, some browsers (most, but not all) will place the
// scrollbar on the left, rather than the right.
browser.bScrollbarLeft = Math.round( inner.offset().left ) !== 1;
- // IE8- don't provide height and width for getBoundingClientRect
- browser.bBounding = n[0].getBoundingClientRect().width ? true : false;
-
n.remove();
}
@@ -2215,58 +1999,22 @@
settings.oScroll.iBarWidth = DataTable.__browser.barWidth;
}
-
- /**
- * Array.prototype reduce[Right] method, used for browsers which don't support
- * JS 1.6. Done this way to reduce code size, since we iterate either way
- * @param {object} settings dataTables settings object
- * @memberof DataTable#oApi
- */
- function _fnReduce ( that, fn, init, start, end, inc )
- {
- var
- i = start,
- value,
- isSet = false;
-
- if ( init !== undefined ) {
- value = init;
- isSet = true;
- }
-
- while ( i !== end ) {
- if ( ! that.hasOwnProperty(i) ) {
- continue;
- }
-
- value = isSet ?
- fn( value, that[i], i, that ) :
- that[i];
-
- isSet = true;
- i += inc;
- }
-
- return value;
- }
-
/**
* Add a column to the list used for the table with default values
* @param {object} oSettings dataTables settings object
- * @param {node} nTh The th element for this column
* @memberof DataTable#oApi
*/
- function _fnAddColumn( oSettings, nTh )
+ function _fnAddColumn( oSettings )
{
// Add column to aoColumns array
var oDefaults = DataTable.defaults.column;
var iCol = oSettings.aoColumns.length;
var oCol = $.extend( {}, DataTable.models.oColumn, oDefaults, {
- "nTh": nTh ? nTh : document.createElement('th'),
- "sTitle": oDefaults.sTitle ? oDefaults.sTitle : nTh ? nTh.innerHTML : '',
"aDataSort": oDefaults.aDataSort ? oDefaults.aDataSort : [iCol],
"mData": oDefaults.mData ? oDefaults.mData : iCol,
- idx: iCol
+ idx: iCol,
+ searchFixed: {},
+ colEl: $('<col>')
} );
oSettings.aoColumns.push( oCol );
@@ -2275,9 +2023,6 @@
// with only some of the parameters defined, and also not give a default
var searchCols = oSettings.aoPreSearchCols;
searchCols[ iCol ] = $.extend( {}, DataTable.models.oSearch, searchCols[ iCol ] );
-
- // Use the default column options function to initialise classes etc
- _fnColumnOptions( oSettings, iCol, $(nTh).data() );
}
@@ -2291,21 +2036,6 @@
function _fnColumnOptions( oSettings, iCol, oOptions )
{
var oCol = oSettings.aoColumns[ iCol ];
- var oClasses = oSettings.oClasses;
- var th = $(oCol.nTh);
-
- // Try to get width information from the DOM. We can't get it from CSS
- // as we'd need to parse the CSS stylesheet. `width` option can override
- if ( ! oCol.sWidthOrig ) {
- // Width attribute
- oCol.sWidthOrig = th.attr('width') || null;
-
- // Style attribute
- var t = (th.attr('style') || '').match(/width:\s*(\d+[pxem%]+)/);
- if ( t ) {
- oCol.sWidthOrig = t[1];
- }
- }
/* User specified column options */
if ( oOptions !== undefined && oOptions !== null )
@@ -2326,16 +2056,13 @@
{
oCol._sManualType = oOptions.sType;
}
-
+
// `class` is a reserved word in Javascript, so we need to provide
// the ability to use a valid name for the camel case input
if ( oOptions.className && ! oOptions.sClass )
{
oOptions.sClass = oOptions.className;
}
- if ( oOptions.sClass ) {
- th.addClass( oOptions.sClass );
- }
var origClass = oCol.sClass;
@@ -2356,18 +2083,22 @@
oCol.aDataSort = [ oOptions.iDataSort ];
}
_fnMap( oCol, oOptions, "aDataSort" );
-
- // Fall back to the aria-label attribute on the table header if no ariaTitle is
- // provided.
- if (! oCol.ariaTitle) {
- oCol.ariaTitle = th.attr("aria-label");
- }
}
/* Cache the data get and set functions for speed */
var mDataSrc = oCol.mData;
var mData = _fnGetObjectDataFn( mDataSrc );
- var mRender = oCol.mRender ? _fnGetObjectDataFn( oCol.mRender ) : null;
+
+ // The `render` option can be given as an array to access the helper rendering methods.
+ // The first element is the rendering method to use, the rest are the parameters to pass
+ if ( oCol.mRender && Array.isArray( oCol.mRender ) ) {
+ var copy = oCol.mRender.slice();
+ var name = copy.shift();
+
+ oCol.mRender = DataTable.render[name].apply(window, copy);
+ }
+
+ oCol._render = oCol.mRender ? _fnGetObjectDataFn( oCol.mRender ) : null;
var attrTest = function( src ) {
return typeof src === 'string' && src.indexOf('@') !== -1;
@@ -2380,8 +2111,8 @@
oCol.fnGetData = function (rowData, type, meta) {
var innerData = mData( rowData, type, undefined, meta );
- return mRender && type ?
- mRender( innerData, type, rowData, meta ) :
+ return oCol._render && type ?
+ oCol._render( innerData, type, rowData, meta ) :
innerData;
};
oCol.fnSetData = function ( rowData, val, meta ) {
@@ -2398,31 +2129,6 @@
if ( !oSettings.oFeatures.bSort )
{
oCol.bSortable = false;
- th.addClass( oClasses.sSortableNone ); // Have to add class here as order event isn't called
- }
-
- /* Check that the class assignment is correct for sorting */
- var bAsc = $.inArray('asc', oCol.asSorting) !== -1;
- var bDesc = $.inArray('desc', oCol.asSorting) !== -1;
- if ( !oCol.bSortable || (!bAsc && !bDesc) )
- {
- oCol.sSortingClass = oClasses.sSortableNone;
- oCol.sSortingClassJUI = "";
- }
- else if ( bAsc && !bDesc )
- {
- oCol.sSortingClass = oClasses.sSortableAsc;
- oCol.sSortingClassJUI = oClasses.sSortJUIAscAllowed;
- }
- else if ( !bAsc && bDesc )
- {
- oCol.sSortingClass = oClasses.sSortableDesc;
- oCol.sSortingClassJUI = oClasses.sSortJUIDescAllowed;
- }
- else
- {
- oCol.sSortingClass = oClasses.sSortable;
- oCol.sSortingClassJUI = oClasses.sSortJUI;
}
}
@@ -2435,27 +2141,33 @@
*/
function _fnAdjustColumnSizing ( settings )
{
- /* Not interested in doing column width calculation if auto-width is disabled */
- if ( settings.oFeatures.bAutoWidth !== false )
- {
- var columns = settings.aoColumns;
-
- _fnCalculateColumnWidths( settings );
- for ( var i=0 , iLen=columns.length ; i<iLen ; i++ )
- {
- columns[i].nTh.style.width = columns[i].sWidth;
- }
- }
+ _fnCalculateColumnWidths( settings );
+ _fnColumnSizes( settings );
var scroll = settings.oScroll;
- if ( scroll.sY !== '' || scroll.sX !== '')
- {
+ if ( scroll.sY !== '' || scroll.sX !== '') {
_fnScrollDraw( settings );
}
_fnCallbackFire( settings, null, 'column-sizing', [settings] );
}
+ /**
+ * Apply column sizes
+ *
+ * @param {*} settings DataTables settings object
+ */
+ function _fnColumnSizes ( settings )
+ {
+ var cols = settings.aoColumns;
+
+ for (var i=0 ; i<cols.length ; i++) {
+ var width = _fnColumnsSumWidth(settings, [i], false, false);
+
+ cols[i].colEl.css('width', width);
+ }
+ }
+
/**
* Convert the index of a visible column to the index in the data array (take account
@@ -2486,7 +2198,7 @@
function _fnColumnIndexToVisible( oSettings, iMatch )
{
var aiVis = _fnGetColumns( oSettings, 'bVisible' );
- var iPos = $.inArray( iMatch, aiVis );
+ var iPos = aiVis.indexOf(iMatch);
return iPos !== -1 ? iPos : null;
}
@@ -2498,16 +2210,19 @@
* @returns {int} i the number of visible columns
* @memberof DataTable#oApi
*/
- function _fnVisbleColumns( oSettings )
+ function _fnVisbleColumns( settings )
{
+ var layout = settings.aoHeader;
+ var columns = settings.aoColumns;
var vis = 0;
- // No reduce in IE8, use a loop for now
- $.each( oSettings.aoColumns, function ( i, col ) {
- if ( col.bVisible && $(col.nTh).css('display') !== 'none' ) {
- vis++;
+ if ( layout.length ) {
+ for ( var i=0, ien=layout[0].length ; i<ien ; i++ ) {
+ if ( columns[i].bVisible && $(layout[0][i].cell).css('display') !== 'none' ) {
+ vis++;
+ }
}
- } );
+ }
return vis;
}
@@ -2525,7 +2240,7 @@
{
var a = [];
- $.map( oSettings.aoColumns, function(val, i) {
+ oSettings.aoColumns.map( function(val, i) {
if ( val[sParam] ) {
a.push( i );
}
@@ -2546,7 +2261,7 @@
var data = settings.aoData;
var types = DataTable.ext.type.detect;
var i, ien, j, jen, k, ken;
- var col, cell, detectedType, cache;
+ var col, detectedType, cache;
// For each column, spin over the
for ( i=0, ien=columns.length ; i<ien ; i++ ) {
@@ -2559,6 +2274,11 @@
else if ( ! col.sType ) {
for ( j=0, jen=types.length ; j<jen ; j++ ) {
for ( k=0, ken=data.length ; k<ken ; k++ ) {
+
+ if (! data[k]) {
+ continue;
+ }
+
// Use a cache array so we only need to get the type data
// from the formatter once (when using multiple detectors)
if ( cache[k] === undefined ) {
@@ -2572,7 +2292,7 @@
// exception for the last type which is `html`. We need to
// scan all rows since it is possible to mix string and HTML
// types
- if ( ! detectedType && j !== types.length-1 ) {
+ if ( ! detectedType && j !== types.length-2 ) {
break;
}
@@ -2597,9 +2317,61 @@
col.sType = 'string';
}
}
+
+ // Set class names for header / footer for auto type classes
+ var autoClass = _ext.type.className[col.sType];
+
+ if (autoClass) {
+ _columnAutoClass(settings.aoHeader, i, autoClass);
+ _columnAutoClass(settings.aoFooter, i, autoClass);
+ }
+
+ var renderer = _ext.type.render[col.sType];
+
+ // This can only happen once! There is no way to remover
+ // a renderer. After the first time the renderer has
+ // already been set so createTr will run the renderer itself.
+ if (renderer && ! col._render) {
+ col._render = DataTable.util.get(renderer);
+
+ _columnAutoRender(settings, i);
+ }
}
}
+ /**
+ * Apply an auto detected renderer to data which doesn't yet have
+ * a renderer
+ */
+ function _columnAutoRender(settings, colIdx) {
+ var data = settings.aoData;
+
+ for (var i=0 ; i<data.length ; i++) {
+ if (data[i].nTr) {
+ // We have to update the display here since there is no
+ // invalidation check for the data
+ var display = _fnGetCellData( settings, i, colIdx, 'display' );
+
+ data[i].displayData[colIdx] = display;
+ _fnWriteCell(data[i].anCells[colIdx], display);
+
+ // No need to update sort / filter data since it has
+ // been invalidated and will be re-read with the
+ // renderer now applied
+ }
+ }
+ }
+
+ /**
+ * Apply a class name to a column's header cells
+ */
+ function _columnAutoClass(container, colIdx, className) {
+ container.forEach(function (row) {
+ if (row[colIdx].unique) {
+ _addClass(row[colIdx].cell, className);
+ }
+ });
+ }
/**
* Take the column definitions and static columns arrays and calculate how
@@ -2608,15 +2380,24 @@
* @param {object} oSettings dataTables settings object
* @param {array} aoColDefs The aoColumnDefs array that is to be applied
* @param {array} aoCols The aoColumns array that defines columns individually
+ * @param {array} headerLayout Layout for header as it was loaded
* @param {function} fn Callback function - takes two parameters, the calculated
* column index and the definition for that column.
* @memberof DataTable#oApi
*/
- function _fnApplyColumnDefs( oSettings, aoColDefs, aoCols, fn )
+ function _fnApplyColumnDefs( oSettings, aoColDefs, aoCols, headerLayout, fn )
{
var i, iLen, j, jLen, k, kLen, def;
var columns = oSettings.aoColumns;
+ if ( aoCols ) {
+ for ( i=0, iLen=aoCols.length ; i<iLen ; i++ ) {
+ if (aoCols[i] && aoCols[i].name) {
+ columns[i].sName = aoCols[i].name;
+ }
+ }
+ }
+
// Column definitions with aTargets
if ( aoColDefs )
{
@@ -2639,31 +2420,47 @@
for ( j=0, jLen=aTargets.length ; j<jLen ; j++ )
{
- if ( typeof aTargets[j] === 'number' && aTargets[j] >= 0 )
+ var target = aTargets[j];
+
+ if ( typeof target === 'number' && target >= 0 )
{
/* Add columns that we don't yet know about */
- while( columns.length <= aTargets[j] )
+ while( columns.length <= target )
{
_fnAddColumn( oSettings );
}
/* Integer, basic index */
- fn( aTargets[j], def );
+ fn( target, def );
}
- else if ( typeof aTargets[j] === 'number' && aTargets[j] < 0 )
+ else if ( typeof target === 'number' && target < 0 )
{
/* Negative integer, right to left column counting */
- fn( columns.length+aTargets[j], def );
+ fn( columns.length+target, def );
}
- else if ( typeof aTargets[j] === 'string' )
+ else if ( typeof target === 'string' )
{
- /* Class name matching on TH element */
- for ( k=0, kLen=columns.length ; k<kLen ; k++ )
- {
- if ( aTargets[j] == "_all" ||
- $(columns[k].nTh).hasClass( aTargets[j] ) )
- {
- fn( k, def );
+ for ( k=0, kLen=columns.length ; k<kLen ; k++ ) {
+ if (target.indexOf(':name') !== -1) {
+ if (columns[k].sName === target.replace(':name', '')) {
+ fn( k, def );
+ }
+ }
+ else {
+ headerLayout.forEach(function (row) {
+ var cell = $(row[k].cell);
+
+ // Legacy support. Note that it means that we don't support
+ // an element name selector only, since they are treated as
+ // class names for 1.x compat.
+ if (target.match(/^[a-z][\w-]*$/i)) {
+ target = '.' + target;
+ }
+
+ if (target === '_all' || cell.is( target )) {
+ fn( k, def );
+ }
+ });
}
}
}
@@ -2672,65 +2469,124 @@
}
// Statically defined columns array
- if ( aoCols )
- {
- for ( i=0, iLen=aoCols.length ; i<iLen ; i++ )
- {
+ if ( aoCols ) {
+ for ( i=0, iLen=aoCols.length ; i<iLen ; i++ ) {
fn( i, aoCols[i] );
}
}
}
+
+ /**
+ * Get the width for a given set of columns
+ *
+ * @param {*} settings DataTables settings object
+ * @param {*} targets Columns - comma separated string or array of numbers
+ * @param {*} original Use the original width (true) or calculated (false)
+ * @param {*} incVisible Include visible columns (true) or not (false)
+ * @returns Combined CSS value
+ */
+ function _fnColumnsSumWidth( settings, targets, original, incVisible ) {
+ if ( ! Array.isArray( targets ) ) {
+ targets = _fnColumnsFromHeader( targets );
+ }
+
+ var sum = 0;
+ var unit;
+ var columns = settings.aoColumns;
+
+ for ( var i=0, ien=targets.length ; i<ien ; i++ ) {
+ var column = columns[ targets[i] ];
+ var definedWidth = original ?
+ column.sWidthOrig :
+ column.sWidth;
+
+ if ( ! incVisible && column.bVisible === false ) {
+ continue;
+ }
+
+ if ( definedWidth === null || definedWidth === undefined ) {
+ return null; // can't determine a defined width - browser defined
+ }
+ else if ( typeof definedWidth === 'number' ) {
+ unit = 'px';
+ sum += definedWidth;
+ }
+ else {
+ var matched = definedWidth.match(/([\d\.]+)([^\d]*)/);
+
+ if ( matched ) {
+ sum += matched[1] * 1;
+ unit = matched.length === 3 ?
+ matched[2] :
+ 'px';
+ }
+ }
+ }
+
+ return sum + unit;
+ }
+
+ function _fnColumnsFromHeader( cell )
+ {
+ var attr = $(cell).closest('[data-dt-column]').attr('data-dt-column');
+
+ if ( ! attr ) {
+ return [];
+ }
+
+ return attr.split(',').map( function (val) {
+ return val * 1;
+ } );
+ }
/**
* Add a data array to the table, creating DOM node etc. This is the parallel to
* _fnGatherData, but for adding rows from a Javascript source, rather than a
* DOM source.
- * @param {object} oSettings dataTables settings object
- * @param {array} aData data array to be added
- * @param {node} [nTr] TR element to add to the table - optional. If not given,
+ * @param {object} settings dataTables settings object
+ * @param {array} data data array to be added
+ * @param {node} [tr] TR element to add to the table - optional. If not given,
* DataTables will create a row automatically
- * @param {array} [anTds] Array of TD|TH elements for the row - must be given
+ * @param {array} [tds] Array of TD|TH elements for the row - must be given
* if nTr is.
* @returns {int} >=0 if successful (index of new aoData entry), -1 if failed
* @memberof DataTable#oApi
*/
- function _fnAddData ( oSettings, aDataIn, nTr, anTds )
+ function _fnAddData ( settings, dataIn, tr, tds )
{
/* Create the object for storing information about this new row */
- var iRow = oSettings.aoData.length;
- var oData = $.extend( true, {}, DataTable.models.oRow, {
- src: nTr ? 'dom' : 'data',
- idx: iRow
+ var rowIdx = settings.aoData.length;
+ var rowModel = $.extend( true, {}, DataTable.models.oRow, {
+ src: tr ? 'dom' : 'data',
+ idx: rowIdx
} );
- oData._aData = aDataIn;
- oSettings.aoData.push( oData );
+ rowModel._aData = dataIn;
+ settings.aoData.push( rowModel );
- /* Create the cells */
- var nTd, sThisType;
- var columns = oSettings.aoColumns;
+ var columns = settings.aoColumns;
- // Invalidate the column types as the new data needs to be revalidated
for ( var i=0, iLen=columns.length ; i<iLen ; i++ )
{
+ // Invalidate the column types as the new data needs to be revalidated
columns[i].sType = null;
}
/* Add to the display array */
- oSettings.aiDisplayMaster.push( iRow );
+ settings.aiDisplayMaster.push( rowIdx );
- var id = oSettings.rowIdFn( aDataIn );
+ var id = settings.rowIdFn( dataIn );
if ( id !== undefined ) {
- oSettings.aIds[ id ] = oData;
+ settings.aIds[ id ] = rowModel;
}
/* Create the DOM information, or register it if already present */
- if ( nTr || ! oSettings.oFeatures.bDeferRender )
+ if ( tr || ! settings.oFeatures.bDeferRender )
{
- _fnCreateTr( oSettings, iRow, nTr, anTds );
+ _fnCreateTr( settings, rowIdx, tr, tds );
}
- return iRow;
+ return rowIdx;
}
@@ -2761,33 +2617,6 @@
/**
- * Take a TR element and convert it to an index in aoData
- * @param {object} oSettings dataTables settings object
- * @param {node} n the TR element to find
- * @returns {int} index if the node is found, null if not
- * @memberof DataTable#oApi
- */
- function _fnNodeToDataIndex( oSettings, n )
- {
- return (n._DT_RowIndex!==undefined) ? n._DT_RowIndex : null;
- }
-
-
- /**
- * Take a TD element and convert it into a column data index (not the visible index)
- * @param {object} oSettings dataTables settings object
- * @param {int} iRow The row number the TD/TH can be found in
- * @param {node} n The TD/TH element to find
- * @returns {int} index if the node is found, -1 if not
- * @memberof DataTable#oApi
- */
- function _fnNodeToColumnIndex( oSettings, iRow, n )
- {
- return $.inArray( n, oSettings.aoData[ iRow ].anCells );
- }
-
-
- /**
* Get the data for a given cell from the internal cache, taking into account data mapping
* @param {object} settings dataTables settings object
* @param {int} rowIdx aoData row id
@@ -2815,6 +2644,11 @@
col: colIdx
} );
+ // Allow for a node being returned for non-display types
+ if (type !== 'display' && cellData && typeof cellData === 'object' && cellData.nodeName) {
+ cellData = cellData.innerHTML;
+ }
+
if ( cellData === undefined ) {
if ( settings.iDrawError != draw && defaultContent === null ) {
_fnLog( settings, 0, "Requested unknown parameter "+
@@ -2872,6 +2706,23 @@
} );
}
+ /**
+ * Write a value to a cell
+ * @param {*} td Cell
+ * @param {*} val Value
+ */
+ function _fnWriteCell(td, val)
+ {
+ if (val && typeof val === 'object' && val.nodeName) {
+ $(td)
+ .empty()
+ .append(val);
+ }
+ else {
+ td.innerHTML = val;
+ }
+ }
+
// Private variable that is used to match action syntax in the data property object
var __reArray = /\[.*?\]$/;
@@ -2884,7 +2735,9 @@
*/
function _fnSplitObjNotation( str )
{
- return $.map( str.match(/(\\.|[^\.])+/g) || [''], function ( s ) {
+ var parts = str.match(/(\\.|[^.])+/g) || [''];
+
+ return parts.map( function ( s ) {
return s.replace(/\\\./g, '.');
} );
}
@@ -2936,36 +2789,6 @@
}
- /**
- * Take an array of integers (index array) and remove a target integer (value - not
- * the key!)
- * @param {array} a Index array to target
- * @param {int} iTarget value to find
- * @memberof DataTable#oApi
- */
- function _fnDeleteIndex( a, iTarget, splice )
- {
- var iTargetIndex = -1;
-
- for ( var i=0, iLen=a.length ; i<iLen ; i++ )
- {
- if ( a[i] == iTarget )
- {
- iTargetIndex = i;
- }
- else if ( a[i] > iTarget )
- {
- a[i]--;
- }
- }
-
- if ( iTargetIndex != -1 && splice === undefined )
- {
- a.splice( iTargetIndex, 1 );
- }
- }
-
-
/**
* Mark cached data as invalid such that a re-read of the data will occur when
* the cached data is next requested. Also update from the data source object.
@@ -2986,16 +2809,11 @@
{
var row = settings.aoData[ rowIdx ];
var i, ien;
- var cellWrite = function ( cell, col ) {
- // This is very frustrating, but in IE if you just write directly
- // to innerHTML, and elements that are overwritten are GC'ed,
- // even if there is a reference to them elsewhere
- while ( cell.childNodes.length ) {
- cell.removeChild( cell.firstChild );
- }
- cell.innerHTML = _fnGetCellData( settings, rowIdx, col, 'display' );
- };
+ // Remove the cached data for the row
+ row._aSortData = null;
+ row._aFilterData = null;
+ row.displayData = null;
// Are we reading last data from DOM or the data object?
if ( src === 'dom' || ((! src || src === 'auto') && row.src === 'dom') ) {
@@ -3008,33 +2826,34 @@
else {
// Reading from data object, update the DOM
var cells = row.anCells;
+ var display = _fnGetRowDisplay(settings, rowIdx);
if ( cells ) {
if ( colIdx !== undefined ) {
- cellWrite( cells[colIdx], colIdx );
+ _fnWriteCell(cells[colIdx], display[colIdx]);
}
else {
for ( i=0, ien=cells.length ; i<ien ; i++ ) {
- cellWrite( cells[i], i );
+ _fnWriteCell(cells[i], display[i]);
}
}
}
}
- // For both row and cell invalidation, the cached data for sorting and
- // filtering is nulled out
- row._aSortData = null;
- row._aFilterData = null;
-
- // Invalidate the type for a specific column (if given) or all columns since
- // the data might have changed
+ // Column specific invalidation
var cols = settings.aoColumns;
if ( colIdx !== undefined ) {
+ // Type - the data might have changed
cols[ colIdx ].sType = null;
+
+ // Max length string. Its a fairly cheep recalculation, so not worth
+ // something more complicated
+ cols[ colIdx ].maxLenString = null;
}
else {
for ( i=0, ien=cols.length ; i<ien ; i++ ) {
cols[i].sType = null;
+ cols[i].maxLenString = null;
}
// Update DataTables special `DT_*` attributes for the row
@@ -3065,7 +2884,7 @@
var
tds = [],
td = row.firstChild,
- name, col, o, i=0, contents,
+ name, col, i=0, contents,
columns = settings.aoColumns,
objectRead = settings._rowReadObject;
@@ -3159,6 +2978,29 @@
cells: tds
};
}
+
+ /**
+ * Render and cache a row's display data for the columns, if required
+ * @returns
+ */
+ function _fnGetRowDisplay (settings, rowIdx) {
+ let rowModal = settings.aoData[rowIdx];
+ let columns = settings.aoColumns;
+
+ if (! rowModal.displayData) {
+ // Need to render and cache
+ rowModal.displayData = [];
+
+ for ( var colIdx=0, len=columns.length ; colIdx<len ; colIdx++ ) {
+ rowModal.displayData.push(
+ _fnGetCellData( settings, rowIdx, colIdx, 'display' )
+ );
+ }
+ }
+
+ return rowModal.displayData;
+ }
+
/**
* Create a new TR element (and it's TD children) for a row
* @param {object} oSettings dataTables settings object
@@ -3176,7 +3018,8 @@
rowData = row._aData,
cells = [],
nTr, nTd, oCol,
- i, iLen, create;
+ i, iLen, create,
+ trClass = oSettings.oClasses.tbody.row;
if ( row.nTr === null )
{
@@ -3185,6 +3028,8 @@
row.nTr = nTr;
row.anCells = cells;
+ _addClass(nTr, trClass);
+
/* Use a private property on the node to allow reserve mapping from the node
* to the aoData array for fast look up
*/
@@ -3211,18 +3056,18 @@
};
cells.push( nTd );
+
+ var display = _fnGetRowDisplay(oSettings, iRow);
// Need to create the HTML if new, or if a rendering function is defined
- if ( create || ((oCol.mRender || oCol.mData !== i) &&
- (!$.isPlainObject(oCol.mData) || oCol.mData._ !== i+'.display')
- )) {
- nTd.innerHTML = _fnGetCellData( oSettings, iRow, i, 'display' );
- }
-
- /* Add user defined class */
- if ( oCol.sClass )
- {
- nTd.className += ' '+oCol.sClass;
+ if (
+ create ||
+ (
+ (oCol.mRender || oCol.mData !== i) &&
+ (!$.isPlainObject(oCol.mData) || oCol.mData._ !== i+'.display')
+ )
+ ) {
+ _fnWriteCell(nTd, display[i]);
}
// Visibility - add or remove as required
@@ -3243,7 +3088,10 @@
}
}
- _fnCallbackFire( oSettings, 'aoRowCreatedCallback', null, [nTr, rowData, iRow, cells] );
+ _fnCallbackFire( oSettings, 'aoRowCreatedCallback', 'row-created', [nTr, rowData, iRow, cells] );
+ }
+ else {
+ _addClass(row.nTr, trClass);
}
}
@@ -3295,182 +3143,171 @@
* @param {object} oSettings dataTables settings object
* @memberof DataTable#oApi
*/
- function _fnBuildHead( oSettings )
+ function _fnBuildHead( settings, side )
{
- var i, ien, cell, row, column;
- var thead = oSettings.nTHead;
- var tfoot = oSettings.nTFoot;
- var createHeader = $('th, td', thead).length === 0;
- var classes = oSettings.oClasses;
- var columns = oSettings.aoColumns;
-
- if ( createHeader ) {
- row = $('<tr/>').appendTo( thead );
+ var classes = settings.oClasses;
+ var columns = settings.aoColumns;
+ var i, ien, row;
+ var target = side === 'header'
+ ? settings.nTHead
+ : settings.nTFoot;
+ var titleProp = side === 'header' ? 'sTitle' : side;
+
+ // Footer might be defined
+ if (! target) {
+ return;
}
- for ( i=0, ien=columns.length ; i<ien ; i++ ) {
- column = columns[i];
- cell = $( column.nTh ).addClass( column.sClass );
+ // If no cells yet and we have content for them, then create
+ if ( $('th, td', target).length === 0 && (side === 'header' || _pluck(settings.aoColumns, titleProp).join('')) ) {
+ row = $('<tr/>')
+ .appendTo( target );
- if ( createHeader ) {
- cell.appendTo( row );
+ for ( i=0, ien=columns.length ; i<ien ; i++ ) {
+ $('<th/>')
+ .html( columns[i][titleProp] || '' )
+ .appendTo( row );
}
+ }
- // 1.11 move into sorting
- if ( oSettings.oFeatures.bSort ) {
- cell.addClass( column.sSortingClass );
+ var detected = _fnDetectHeader( settings, target, true );
- if ( column.bSortable !== false ) {
- cell
- .attr( 'tabindex', oSettings.iTabIndex )
- .attr( 'aria-controls', oSettings.sTableId );
+ if (side === 'header') {
+ settings.aoHeader = detected;
+ }
+ else {
+ settings.aoFooter = detected;
+ }
- _fnSortAttachListener( oSettings, column.nTh, i );
- }
- }
+ // ARIA role for the rows
+ $(target).children('tr').attr('role', 'row');
- if ( column.sTitle != cell[0].innerHTML ) {
- cell.html( column.sTitle );
- }
+ // Every cell needs to be passed through the renderer
+ $(target).children('tr').children('th, td')
+ .each( function () {
+ _fnRenderer( settings, side )(
+ settings, $(this), classes
+ );
+ } );
+ }
- _fnRenderer( oSettings, 'header' )(
- oSettings, cell, column, classes
- );
+ /**
+ * Build a layout structure for a header or footer
+ *
+ * @param {*} settings DataTables settings
+ * @param {*} source Source layout array
+ * @param {*} incColumns What columns should be included
+ * @returns Layout array
+ */
+ function _fnHeaderLayout( settings, source, incColumns )
+ {
+ var row, column, cell;
+ var local = [];
+ var structure = [];
+ var columns = settings.aoColumns;
+ var columnCount = columns.length;
+ var rowspan, colspan;
+
+ if ( ! source ) {
+ return;
}
- if ( createHeader ) {
- _fnDetectHeader( oSettings.aoHeader, thead );
+ // Default is to work on only visible columns
+ if ( ! incColumns ) {
+ incColumns = _range(columnCount)
+ .filter(function (idx) {
+ return columns[idx].bVisible;
+ });
}
- /* Deal with the footer - add classes if required */
- $(thead).children('tr').children('th, td').addClass( classes.sHeaderTH );
- $(tfoot).children('tr').children('th, td').addClass( classes.sFooterTH );
+ // Make a copy of the master layout array, but with only the columns we want
+ for ( row=0 ; row<source.length ; row++ ) {
+ // Remove any columns we haven't selected
+ local[row] = source[row].slice().filter(function (cell, i) {
+ return incColumns.includes(i);
+ });
+
+ // Prep the structure array - it needs an element for each row
+ structure.push( [] );
+ }
- // Cache the footer cells. Note that we only take the cells from the first
- // row in the footer. If there is more than one row the user wants to
- // interact with, they need to use the table().foot() method. Note also this
- // allows cells to be used for multiple columns using colspan
- if ( tfoot !== null ) {
- var cells = oSettings.aoFooter[0];
+ for ( row=0 ; row<local.length ; row++ ) {
+ for ( column=0 ; column<local[row].length ; column++ ) {
+ rowspan = 1;
+ colspan = 1;
- for ( i=0, ien=cells.length ; i<ien ; i++ ) {
- column = columns[i];
+ // Check to see if there is already a cell (row/colspan) covering our target
+ // insert point. If there is, then there is nothing to do.
+ if ( structure[row][column] === undefined ) {
+ cell = local[row][column].cell;
- if (column) {
- column.nTf = cells[i].cell;
-
- if ( column.sClass ) {
- $(column.nTf).addClass( column.sClass );
+ // Expand for rowspan
+ while (
+ local[row+rowspan] !== undefined &&
+ local[row][column].cell == local[row+rowspan][column].cell
+ ) {
+ structure[row+rowspan][column] = null;
+ rowspan++;
}
- }
- else {
- _fnLog( oSettings, 0, 'Incorrect column count', 18 );
+
+ // And for colspan
+ while (
+ local[row][column+colspan] !== undefined &&
+ local[row][column].cell == local[row][column+colspan].cell
+ ) {
+ // Which also needs to go over rows
+ for ( var k=0 ; k<rowspan ; k++ ) {
+ structure[row+k][column+colspan] = null;
+ }
+
+ colspan++;
+ }
+
+ structure[row][column] = {
+ cell: cell,
+ colspan: colspan,
+ rowspan: rowspan,
+ title: $('span.dt-column-title', cell).html()
+ };
}
}
}
+
+ return structure;
}
/**
- * Draw the header (or footer) element based on the column visibility states. The
- * methodology here is to use the layout array from _fnDetectHeader, modified for
- * the instantaneous column visibility, to construct the new layout. The grid is
- * traversed over cell at a time in a rows x columns grid fashion, although each
- * cell insert can cover multiple elements in the grid - which is tracks using the
- * aApplied array. Cell inserts in the grid will only occur where there isn't
- * already a cell in that position.
- * @param {object} oSettings dataTables settings object
- * @param array {objects} aoSource Layout array from _fnDetectHeader
- * @param {boolean} [bIncludeHidden=false] If true then include the hidden columns in the calc,
+ * Draw the header (or footer) element based on the column visibility states.
+ *
+ * @param object oSettings dataTables settings object
+ * @param array aoSource Layout array from _fnDetectHeader
* @memberof DataTable#oApi
*/
- function _fnDrawHead( oSettings, aoSource, bIncludeHidden )
+ function _fnDrawHead( settings, source )
{
- var i, iLen, j, jLen, k, kLen, n, nLocalTr;
- var aoLocal = [];
- var aApplied = [];
- var iColumns = oSettings.aoColumns.length;
- var iRowspan, iColspan;
-
- if ( ! aoSource )
- {
- return;
- }
-
- if ( bIncludeHidden === undefined )
- {
- bIncludeHidden = false;
- }
-
- /* Make a copy of the master layout array, but without the visible columns in it */
- for ( i=0, iLen=aoSource.length ; i<iLen ; i++ )
- {
- aoLocal[i] = aoSource[i].slice();
- aoLocal[i].nTr = aoSource[i].nTr;
-
- /* Remove any columns which are currently hidden */
- for ( j=iColumns-1 ; j>=0 ; j-- )
- {
- if ( !oSettings.aoColumns[j].bVisible && !bIncludeHidden )
- {
- aoLocal[i].splice( j, 1 );
- }
- }
-
- /* Prep the applied array - it needs an element for each row */
- aApplied.push( [] );
- }
+ var layout = _fnHeaderLayout(settings, source);
+ var tr, n;
- for ( i=0, iLen=aoLocal.length ; i<iLen ; i++ )
- {
- nLocalTr = aoLocal[i].nTr;
+ for ( var row=0 ; row<source.length ; row++ ) {
+ tr = source[row].row;
- /* All cells are going to be replaced, so empty out the row */
- if ( nLocalTr )
- {
- while( (n = nLocalTr.firstChild) )
- {
- nLocalTr.removeChild( n );
+ // All cells are going to be replaced, so empty out the row
+ // Can't use $().empty() as that kills event handlers
+ if (tr) {
+ while( (n = tr.firstChild) ) {
+ tr.removeChild( n );
}
}
- for ( j=0, jLen=aoLocal[i].length ; j<jLen ; j++ )
- {
- iRowspan = 1;
- iColspan = 1;
+ for ( var column=0 ; column<layout[row].length ; column++ ) {
+ var point = layout[row][column];
- /* Check to see if there is already a cell (row/colspan) covering our target
- * insert point. If there is, then there is nothing to do.
- */
- if ( aApplied[i][j] === undefined )
- {
- nLocalTr.appendChild( aoLocal[i][j].cell );
- aApplied[i][j] = 1;
-
- /* Expand the cell to cover as many rows as needed */
- while ( aoLocal[i+iRowspan] !== undefined &&
- aoLocal[i][j].cell == aoLocal[i+iRowspan][j].cell )
- {
- aApplied[i+iRowspan][j] = 1;
- iRowspan++;
- }
-
- /* Expand the cell to cover as many columns as needed */
- while ( aoLocal[i][j+iColspan] !== undefined &&
- aoLocal[i][j].cell == aoLocal[i][j+iColspan].cell )
- {
- /* Must update the applied array over the rows for the columns */
- for ( k=0 ; k<iRowspan ; k++ )
- {
- aApplied[i+k][j+iColspan] = 1;
- }
- iColspan++;
- }
-
- /* Do the actual expansion in the DOM */
- $(aoLocal[i][j].cell)
- .attr('rowspan', iRowspan)
- .attr('colspan', iColspan);
+ if (point) {
+ $(point.cell)
+ .appendTo(tr)
+ .attr('rowspan', point.rowspan)
+ .attr('colspan', point.colspan);
}
}
}
@@ -3490,7 +3327,7 @@
/* Provide a pre-callback function which can be used to cancel the draw is false is returned */
var aPreDraw = _fnCallbackFire( oSettings, 'aoPreDrawCallback', 'preDraw', [oSettings] );
- if ( $.inArray( false, aPreDraw ) !== -1 )
+ if ( aPreDraw.indexOf(false) !== -1 )
{
_fnProcessingDisplay( oSettings, false );
return;
@@ -3498,29 +3335,27 @@
var anRows = [];
var iRowCount = 0;
- var asStripeClasses = oSettings.asStripeClasses;
- var iStripes = asStripeClasses.length;
- var oLang = oSettings.oLanguage;
var bServerSide = _fnDataSource( oSettings ) == 'ssp';
var aiDisplay = oSettings.aiDisplay;
var iDisplayStart = oSettings._iDisplayStart;
var iDisplayEnd = oSettings.fnDisplayEnd();
+ var columns = oSettings.aoColumns;
+ var body = $(oSettings.nTBody);
oSettings.bDrawing = true;
/* Server-side processing draw intercept */
- if ( oSettings.bDeferLoading )
- {
- oSettings.bDeferLoading = false;
- oSettings.iDraw++;
- _fnProcessingDisplay( oSettings, false );
- }
- else if ( !bServerSide )
+ if ( !bServerSide )
{
oSettings.iDraw++;
}
else if ( !oSettings.bDestroying && !ajaxComplete)
{
+ // Show loading message for server-side processing
+ if (oSettings.iDraw === 0) {
+ body.empty().append(_emptyRow(oSettings));
+ }
+
_fnAjaxUpdate( oSettings );
return;
}
@@ -3541,15 +3376,14 @@
var nRow = aoData.nTr;
- /* Remove the old striping classes and then add the new one */
- if ( iStripes !== 0 )
- {
- var sStripe = asStripeClasses[ iRowCount % iStripes ];
- if ( aoData._sRowStripe != sStripe )
- {
- $(nRow).removeClass( aoData._sRowStripe ).addClass( sStripe );
- aoData._sRowStripe = sStripe;
- }
+ // Add various classes as needed
+ for (var i=0 ; i<columns.length ; i++) {
+ var col = columns[i];
+ var td = aoData.anCells[i];
+
+ _addClass(td, _ext.type.className[col.sType]); // auto class
+ _addClass(td, col.sClass); // column class
+ _addClass(td, oSettings.oClasses.tbody.cell); // all cells
}
// Row callback functions - might want to manipulate the row
@@ -3564,23 +3398,7 @@
}
else
{
- /* Table is empty - create a row with an empty message in it */
- var sZero = oLang.sZeroRecords;
- if ( oSettings.iDraw == 1 && _fnDataSource( oSettings ) == 'ajax' )
- {
- sZero = oLang.sLoadingRecords;
- }
- else if ( oLang.sEmptyTable && oSettings.fnRecordsTotal() === 0 )
- {
- sZero = oLang.sEmptyTable;
- }
-
- anRows[ 0 ] = $( '<tr/>', { 'class': iStripes ? asStripeClasses[0] : '' } )
- .append( $('<td />', {
- 'valign': 'top',
- 'colSpan': _fnVisbleColumns( oSettings ),
- 'class': oSettings.oClasses.sRowEmpty
- } ).html( sZero ) )[0];
+ anRows[ 0 ] = _emptyRow(oSettings);
}
/* Header and footer callbacks */
@@ -3590,13 +3408,14 @@
_fnCallbackFire( oSettings, 'aoFooterCallback', 'footer', [ $(oSettings.nTFoot).children('tr')[0],
_fnGetDataMaster( oSettings ), iDisplayStart, iDisplayEnd, aiDisplay ] );
- var body = $(oSettings.nTBody);
-
body.children().detach();
body.append( $(anRows) );
+ // Empty table needs a specific class
+ $(oSettings.nTableWrapper).toggleClass('dt-empty-footer', $('tr', oSettings.nTFoot).length === 0);
+
/* Call all required callback functions for the end of a draw */
- _fnCallbackFire( oSettings, 'aoDrawCallback', 'draw', [oSettings] );
+ _fnCallbackFire( oSettings, 'aoDrawCallback', 'draw', [oSettings], true );
/* Draw is complete, sorting and filtering must be as well */
oSettings.bSorted = false;
@@ -3612,23 +3431,25 @@
* the paging is reset to the first page
* @memberof DataTable#oApi
*/
- function _fnReDraw( settings, holdPosition )
+ function _fnReDraw( settings, holdPosition, recompute )
{
var
features = settings.oFeatures,
sort = features.bSort,
filter = features.bFilter;
- if ( sort ) {
- _fnSort( settings );
- }
+ if (recompute === undefined || recompute === true) {
+ if ( sort ) {
+ _fnSort( settings );
+ }
- if ( filter ) {
- _fnFilterComplete( settings, settings.oPreviousSearch );
- }
- else {
- // No filtering, so we want to just use the display master
- settings.aiDisplay = settings.aiDisplayMaster.slice();
+ if ( filter ) {
+ _fnFilterComplete( settings, settings.oPreviousSearch );
+ }
+ else {
+ // No filtering, so we want to just use the display master
+ settings.aiDisplay = settings.aiDisplayMaster.slice();
+ }
}
if ( holdPosition !== true ) {
@@ -3645,155 +3466,318 @@
}
+ /*
+ * Table is empty - create a row with an empty message in it
+ */
+ function _emptyRow ( settings ) {
+ var oLang = settings.oLanguage;
+ var zero = oLang.sZeroRecords;
+ var dataSrc = _fnDataSource( settings );
+
+ if ( settings.iDraw <= 1 && (dataSrc === 'ajax' || dataSrc === 'ssp') )
+ {
+ zero = oLang.sLoadingRecords;
+ }
+ else if ( oLang.sEmptyTable && settings.fnRecordsTotal() === 0 )
+ {
+ zero = oLang.sEmptyTable;
+ }
+
+ return $( '<tr/>' )
+ .append( $('<td />', {
+ 'colSpan': _fnVisbleColumns( settings ),
+ 'class': settings.oClasses.empty.row
+ } ).html( zero ) )[0];
+ }
+
+
+ /**
+ * Convert a `layout` object given by a user to the object structure needed
+ * for the renderer. This is done twice, once for above and once for below
+ * the table. Ordering must also be considered.
+ *
+ * @param {*} settings DataTables settings object
+ * @param {*} layout Layout object to convert
+ * @param {string} side `top` or `bottom`
+ * @returns Converted array structure - one item for each row.
+ */
+ function _layoutArray ( settings, layout, side )
+ {
+ var groups = {};
+
+ // Combine into like groups (e.g. `top`, `top2`, etc)
+ $.each( layout, function ( pos, val ) {
+ if (val === null) {
+ return;
+ }
+
+ var splitPos = pos.replace(/([A-Z])/g, ' $1').split(' ');
+
+ if ( ! groups[ splitPos[0] ] ) {
+ groups[ splitPos[0] ] = {};
+ }
+
+ var align = splitPos.length === 1 ?
+ 'full' :
+ splitPos[1].toLowerCase();
+ var group = groups[ splitPos[0] ];
+
+ // Transform to an object with a contents property
+ if ( $.isPlainObject( val ) ) {
+ // Already a group from a previous pass
+ if (val.contents) {
+ group[ align ] = val;
+ }
+ else {
+ // For objects, each property becomes an entry in the contents
+ // array for this insert position
+ group[ align ] = {
+ contents: Object.keys(val).map(function (key) {
+ return {
+ feature: key,
+ opts: val[key]
+ };
+ })
+ };
+ }
+ }
+ else {
+ group[ align ] = {
+ contents: val
+ };
+ }
+
+ // And make contents an array
+ if ( ! Array.isArray( group[ align ].contents ) ) {
+ group[ align ].contents = [ group[ align ].contents ];
+ }
+ } );
+
+ var filtered = Object.keys(groups)
+ .map( function ( pos ) {
+ // Filter to only the side we need
+ if ( pos.indexOf(side) !== 0 ) {
+ return null;
+ }
+
+ return {
+ name: pos,
+ val: groups[pos]
+ };
+ } )
+ .filter( function (item) {
+ return item !== null;
+ });
+
+ // Order by item identifier
+ filtered.sort( function ( a, b ) {
+ var order1 = a.name.replace(/[^0-9]/g, '') * 1;
+ var order2 = b.name.replace(/[^0-9]/g, '') * 1;
+
+ return order2 - order1;
+ } );
+
+ if ( side === 'bottom' ) {
+ filtered.reverse();
+ }
+
+ // Split into rows
+ var rows = [];
+ for ( var i=0, ien=filtered.length ; i<ien ; i++ ) {
+ if ( filtered[i].val.full ) {
+ rows.push( { full: filtered[i].val.full } );
+ _layoutResolve( settings, rows[ rows.length - 1 ] );
+
+ delete filtered[i].val.full;
+ }
+
+ if ( Object.keys(filtered[i].val).length ) {
+ rows.push( filtered[i].val );
+ _layoutResolve( settings, rows[ rows.length - 1 ] );
+ }
+ }
+
+ return rows;
+ }
+
+
+ /**
+ * Convert the contents of a row's layout object to nodes that can be inserted
+ * into the document by a renderer. Execute functions, look up plug-ins, etc.
+ *
+ * @param {*} settings DataTables settings object
+ * @param {*} row Layout object for this row
+ */
+ function _layoutResolve( settings, row ) {
+ var getFeature = function (feature, opts) {
+ if ( ! _ext.features[ feature ] ) {
+ _fnLog( settings, 0, 'Unknown feature: '+ feature );
+ }
+
+ return _ext.features[ feature ].apply( this, [settings, opts] );
+ };
+
+ var resolve = function ( item ) {
+ var line = row[ item ].contents;
+
+ for ( var i=0, ien=line.length ; i<ien ; i++ ) {
+ if ( ! line[i] ) {
+ continue;
+ }
+ else if ( typeof line[i] === 'string' ) {
+ line[i] = getFeature( line[i], null );
+ }
+ else if ( $.isPlainObject(line[i]) ) {
+ // If it's an object, it just has feature and opts properties from
+ // the transform in _layoutArray
+ line[i] = getFeature(line[i].feature, line[i].opts);
+ }
+ else if ( typeof line[i].node === 'function' ) {
+ line[i] = line[i].node( settings );
+ }
+ else if ( typeof line[i] === 'function' ) {
+ var inst = line[i]( settings );
+
+ line[i] = typeof inst.node === 'function' ?
+ inst.node() :
+ inst;
+ }
+ }
+ };
+
+ $.each( row, function ( key ) {
+ resolve( key );
+ } );
+ }
+
+
/**
* Add the options to the page HTML for the table
- * @param {object} oSettings dataTables settings object
+ * @param {object} settings DataTables settings object
* @memberof DataTable#oApi
*/
- function _fnAddOptionsHtml ( oSettings )
+ function _fnAddOptionsHtml ( settings )
{
- var classes = oSettings.oClasses;
- var table = $(oSettings.nTable);
- var holding = $('<div/>').insertBefore( table ); // Holding element for speed
- var features = oSettings.oFeatures;
-
- // All DataTables are wrapped in a div
- var insert = $('<div/>', {
- id: oSettings.sTableId+'_wrapper',
- 'class': classes.sWrapper + (oSettings.nTFoot ? '' : ' '+classes.sNoFooter)
- } );
+ var classes = settings.oClasses;
+ var table = $(settings.nTable);
- oSettings.nHolding = holding[0];
- oSettings.nTableWrapper = insert[0];
- oSettings.nTableReinsertBefore = oSettings.nTable.nextSibling;
+ // Wrapper div around everything DataTables controls
+ var insert = $('<div/>')
+ .attr({
+ id: settings.sTableId+'_wrapper',
+ 'class': classes.container
+ })
+ .insertBefore(table);
- /* Loop over the user set positioning and place the elements as needed */
- var aDom = oSettings.sDom.split('');
- var featureNode, cOption, nNewNode, cNext, sAttr, j;
- for ( var i=0 ; i<aDom.length ; i++ )
- {
+ settings.nTableWrapper = insert[0];
+
+ var top = _layoutArray( settings, settings.layout, 'top' );
+ var bottom = _layoutArray( settings, settings.layout, 'bottom' );
+ var renderer = _fnRenderer( settings, 'layout' );
+
+ if (settings.sDom) {
+ // Legacy
+ _fnLayoutDom(settings, settings.sDom, insert);
+ }
+ else {
+ // Everything above - the renderer will actually insert the contents into the document
+ top.forEach(function (item) {
+ renderer( settings, insert, item );
+ });
+
+ // The table - always the center of attention
+ renderer( settings, insert, {
+ full: {
+ table: true,
+ contents: [ _fnFeatureHtmlTable(settings) ]
+ }
+ } );
+
+ // Everything below
+ bottom.forEach(function (item) {
+ renderer( settings, insert, item );
+ });
+ }
+
+ // Processing floats on top, so it isn't an inserted feature
+ _processingHtml( settings );
+ }
+
+ /**
+ * Draw the table with the legacy DOM property
+ * @param {*} settings DT settings object
+ * @param {*} dom DOM string
+ * @param {*} insert Insert point
+ */
+ function _fnLayoutDom( settings, dom, insert )
+ {
+ var parts = dom.match(/(".*?")|('.*?')|./g);
+ var featureNode, option, newNode, next, attr;
+
+ for ( var i=0 ; i<parts.length ; i++ ) {
featureNode = null;
- cOption = aDom[i];
+ option = parts[i];
- if ( cOption == '<' )
- {
- /* New container div */
- nNewNode = $('<div/>')[0];
+ if ( option == '<' ) {
+ // New container div
+ newNode = $('<div/>');
- /* Check to see if we should append an id and/or a class name to the container */
- cNext = aDom[i+1];
- if ( cNext == "'" || cNext == '"' )
- {
- sAttr = "";
- j = 2;
- while ( aDom[i+j] != cNext )
- {
- sAttr += aDom[i+j];
- j++;
- }
+ // Check to see if we should append an id and/or a class name to the container
+ next = parts[i+1];
- /* Replace jQuery UI constants @todo depreciated */
- if ( sAttr == "H" )
- {
- sAttr = classes.sJUIHeader;
- }
- else if ( sAttr == "F" )
- {
- sAttr = classes.sJUIFooter;
- }
+ if ( next[0] == "'" || next[0] == '"' ) {
+ attr = next.replace(/['"]/g, '');
+
+ var id = '', className;
/* The attribute can be in the format of "#id.class", "#id" or "class" This logic
* breaks the string into parts and applies them as needed
*/
- if ( sAttr.indexOf('.') != -1 )
- {
- var aSplit = sAttr.split('.');
- nNewNode.id = aSplit[0].substr(1, aSplit[0].length-1);
- nNewNode.className = aSplit[1];
+ if ( attr.indexOf('.') != -1 ) {
+ var split = attr.split('.');
+
+ id = split[0];
+ className = split[1];
}
- else if ( sAttr.charAt(0) == "#" )
- {
- nNewNode.id = sAttr.substr(1, sAttr.length-1);
+ else if ( attr[0] == "#" ) {
+ id = attr;
}
- else
- {
- nNewNode.className = sAttr;
+ else {
+ className = attr;
}
- i += j; /* Move along the position array */
+ newNode
+ .attr('id', id.substring(1))
+ .addClass(className);
+
+ i++; // Move along the position array
}
- insert.append( nNewNode );
- insert = $(nNewNode);
+ insert.append( newNode );
+ insert = newNode;
}
- else if ( cOption == '>' )
- {
- /* End container div */
+ else if ( option == '>' ) {
+ // End container div
insert = insert.parent();
}
- // @todo Move options into their own plugins?
- else if ( cOption == 'l' && features.bPaginate && features.bLengthChange )
- {
- /* Length */
- featureNode = _fnFeatureHtmlLength( oSettings );
- }
- else if ( cOption == 'f' && features.bFilter )
- {
- /* Filter */
- featureNode = _fnFeatureHtmlFilter( oSettings );
- }
- else if ( cOption == 'r' && features.bProcessing )
- {
- /* pRocessing */
- featureNode = _fnFeatureHtmlProcessing( oSettings );
- }
- else if ( cOption == 't' )
- {
- /* Table */
- featureNode = _fnFeatureHtmlTable( oSettings );
- }
- else if ( cOption == 'i' && features.bInfo )
- {
- /* Info */
- featureNode = _fnFeatureHtmlInfo( oSettings );
- }
- else if ( cOption == 'p' && features.bPaginate )
- {
- /* Pagination */
- featureNode = _fnFeatureHtmlPaginate( oSettings );
+ else if ( option == 't' ) {
+ // Table
+ featureNode = _fnFeatureHtmlTable( settings );
}
- else if ( DataTable.ext.feature.length !== 0 )
+ else
{
- /* Plug-in features */
- var aoFeatures = DataTable.ext.feature;
- for ( var k=0, kLen=aoFeatures.length ; k<kLen ; k++ )
- {
- if ( cOption == aoFeatures[k].cFeature )
- {
- featureNode = aoFeatures[k].fnInit( oSettings );
- break;
+ DataTable.ext.feature.forEach(function(feature) {
+ if ( option == feature.cFeature ) {
+ featureNode = feature.fnInit( settings );
}
- }
+ });
}
- /* Add to the 2D features array */
- if ( featureNode )
- {
- var aanFeatures = oSettings.aanFeatures;
-
- if ( ! aanFeatures[cOption] )
- {
- aanFeatures[cOption] = [];
- }
-
- aanFeatures[cOption].push( featureNode );
+ // Add to the display
+ if ( featureNode ) {
insert.append( featureNode );
}
}
-
- /* Built our DOM structure - replace the holding div with what we want */
- holding.replaceWith( insert );
- oSettings.nHolding = null;
}
@@ -3802,111 +3786,147 @@
* create a layout grid (array) of rows x columns, which contains a reference
* to the cell that that point in the grid (regardless of col/rowspan), such that
* any column / row could be removed and the new grid constructed
- * @param array {object} aLayout Array to store the calculated layout in
- * @param {node} nThead The header/footer element for the table
+ * @param {node} thead The header/footer element for the table
+ * @returns {array} Calculated layout array
* @memberof DataTable#oApi
*/
- function _fnDetectHeader ( aLayout, nThead )
+ function _fnDetectHeader ( settings, thead, write )
{
- var nTrs = $(nThead).children('tr');
- var nTr, nCell;
- var i, k, l, iLen, jLen, iColShifted, iColumn, iColspan, iRowspan;
- var bUnique;
- var fnShiftCol = function ( a, i, j ) {
+ var columns = settings.aoColumns;
+ var rows = $(thead).children('tr');
+ var row, cell;
+ var i, k, l, iLen, shifted, column, colspan, rowspan;
+ var isHeader = thead && thead.nodeName.toLowerCase() === 'thead';
+ var layout = [];
+ var unique;
+ var shift = function ( a, i, j ) {
var k = a[i];
- while ( k[j] ) {
+ while ( k[j] ) {
j++;
}
return j;
};
- aLayout.splice( 0, aLayout.length );
-
- /* We know how many rows there are in the layout - so prep it */
- for ( i=0, iLen=nTrs.length ; i<iLen ; i++ )
- {
- aLayout.push( [] );
+ // We know how many rows there are in the layout - so prep it
+ for ( i=0, iLen=rows.length ; i<iLen ; i++ ) {
+ layout.push( [] );
}
- /* Calculate a layout array */
- for ( i=0, iLen=nTrs.length ; i<iLen ; i++ )
- {
- nTr = nTrs[i];
- iColumn = 0;
-
- /* For every cell in the row... */
- nCell = nTr.firstChild;
- while ( nCell ) {
- if ( nCell.nodeName.toUpperCase() == "TD" ||
- nCell.nodeName.toUpperCase() == "TH" )
- {
- /* Get the col and rowspan attributes from the DOM and sanitise them */
- iColspan = nCell.getAttribute('colspan') * 1;
- iRowspan = nCell.getAttribute('rowspan') * 1;
- iColspan = (!iColspan || iColspan===0 || iColspan===1) ? 1 : iColspan;
- iRowspan = (!iRowspan || iRowspan===0 || iRowspan===1) ? 1 : iRowspan;
-
- /* There might be colspan cells already in this row, so shift our target
- * accordingly
- */
- iColShifted = fnShiftCol( aLayout, i, iColumn );
+ for ( i=0, iLen=rows.length ; i<iLen ; i++ ) {
+ row = rows[i];
+ column = 0;
- /* Cache calculation for unique columns */
- bUnique = iColspan === 1 ? true : false;
+ // For every cell in the row..
+ cell = row.firstChild;
+ while ( cell ) {
+ if (
+ cell.nodeName.toUpperCase() == 'TD' ||
+ cell.nodeName.toUpperCase() == 'TH'
+ ) {
+ var cols = [];
+
+ // Get the col and rowspan attributes from the DOM and sanitise them
+ colspan = cell.getAttribute('colspan') * 1;
+ rowspan = cell.getAttribute('rowspan') * 1;
+ colspan = (!colspan || colspan===0 || colspan===1) ? 1 : colspan;
+ rowspan = (!rowspan || rowspan===0 || rowspan===1) ? 1 : rowspan;
+
+ // There might be colspan cells already in this row, so shift our target
+ // accordingly
+ shifted = shift( layout, i, column );
+
+ // Cache calculation for unique columns
+ unique = colspan === 1 ?
+ true :
+ false;
+
+ // Perform header setup
+ if ( write ) {
+ if (unique) {
+ // Allow column options to be set from HTML attributes
+ _fnColumnOptions( settings, shifted, $(cell).data() );
+
+ // Get the width for the column. This can be defined from the
+ // width attribute, style attribute or `columns.width` option
+ var columnDef = columns[shifted];
+ var width = cell.getAttribute('width') || null;
+ var t = cell.style.width.match(/width:\s*(\d+[pxem%]+)/);
+ if ( t ) {
+ width = t[1];
+ }
- /* If there is col / rowspan, copy the information into the layout grid */
- for ( l=0 ; l<iColspan ; l++ )
- {
- for ( k=0 ; k<iRowspan ; k++ )
- {
- aLayout[i+k][iColShifted+l] = {
- "cell": nCell,
- "unique": bUnique
- };
- aLayout[i+k].nTr = nTr;
+ columnDef.sWidthOrig = columnDef.sWidth || width;
+
+ if (isHeader) {
+ // Column title handling - can be user set, or read from the DOM
+ // This happens before the render, so the original is still in place
+ if ( columnDef.sTitle !== null && ! columnDef.autoTitle ) {
+ cell.innerHTML = columnDef.sTitle;
+ }
+
+ if (! columnDef.sTitle && unique) {
+ columnDef.sTitle = cell.innerHTML.replace( /<.*?>/g, "" );
+ columnDef.autoTitle = true;
+ }
+ }
+ else {
+ // Footer specific operations
+ if (columnDef.footer) {
+ cell.innerHTML = columnDef.footer;
+ }
+ }
+
+ // Fall back to the aria-label attribute on the table header if no ariaTitle is
+ // provided.
+ if (! columnDef.ariaTitle) {
+ columnDef.ariaTitle = $(cell).attr("aria-label") || columnDef.sTitle;
+ }
+
+ // Column specific class names
+ if ( columnDef.className ) {
+ $(cell).addClass( columnDef.className );
+ }
+ }
+
+ // Wrap the column title so we can write to it in future
+ if ( $('span.dt-column-title', cell).length === 0) {
+ $('<span>')
+ .addClass('dt-column-title')
+ .append(cell.childNodes)
+ .appendTo(cell);
+ }
+
+ if ( isHeader && $('span.dt-column-order', cell).length === 0) {
+ $('<span>')
+ .addClass('dt-column-order')
+ .appendTo(cell);
}
}
- }
- nCell = nCell.nextSibling;
- }
- }
- }
+ // If there is col / rowspan, copy the information into the layout grid
+ for ( l=0 ; l<colspan ; l++ ) {
+ for ( k=0 ; k<rowspan ; k++ ) {
+ layout[i+k][shifted+l] = {
+ cell: cell,
+ unique: unique
+ };
- /**
- * Get an array of unique th elements, one for each column
- * @param {object} oSettings dataTables settings object
- * @param {node} nHeader automatically detect the layout from this node - optional
- * @param {array} aLayout thead/tfoot layout from _fnDetectHeader - optional
- * @returns array {node} aReturn list of unique th's
- * @memberof DataTable#oApi
- */
- function _fnGetUniqueThs ( oSettings, nHeader, aLayout )
- {
- var aReturn = [];
- if ( !aLayout )
- {
- aLayout = oSettings.aoHeader;
- if ( nHeader )
- {
- aLayout = [];
- _fnDetectHeader( aLayout, nHeader );
- }
- }
+ layout[i+k].row = row;
+ }
- for ( var i=0, iLen=aLayout.length ; i<iLen ; i++ )
- {
- for ( var j=0, jLen=aLayout[i].length ; j<jLen ; j++ )
- {
- if ( aLayout[i][j].unique &&
- (!aReturn[j] || !oSettings.bSortCellsTop) )
- {
- aReturn[j] = aLayout[i][j].cell;
+ cols.push( shifted+l );
+ }
+
+ // Assign an attribute so spanning cells can still be identified
+ // as belonging to a column
+ cell.setAttribute('data-dt-column', _unique(cols).join(','));
}
+
+ cell = cell.nextSibling;
}
}
- return aReturn;
+ return layout;
}
/**
@@ -3942,34 +3962,6 @@
*/
function _fnBuildAjax( oSettings, data, fn )
{
- // Compatibility with 1.9-, allow fnServerData and event to manipulate
- _fnCallbackFire( oSettings, 'aoServerParams', 'serverParams', [data] );
-
- // Convert to object based for 1.10+ if using the old array scheme which can
- // come from server-side processing or serverParams
- if ( data && Array.isArray(data) ) {
- var tmp = {};
- var rbracket = /(.*?)\[\]$/;
-
- $.each( data, function (key, val) {
- var match = val.name.match(rbracket);
-
- if ( match ) {
- // Support for arrays
- var name = match[0];
-
- if ( ! tmp[ name ] ) {
- tmp[ name ] = [];
- }
- tmp[ name ].push( val.value );
- }
- else {
- tmp[val.name] = val.value;
- }
- } );
- data = tmp;
- }
-
var ajaxData;
var ajax = oSettings.ajax;
var instance = oSettings.oInstance;
@@ -3990,7 +3982,7 @@
oSettings.json = json;
- _fnCallbackFire( oSettings, null, 'xhr', [oSettings, json, oSettings.jqXHR] );
+ _fnCallbackFire( oSettings, null, 'xhr', [oSettings, json, oSettings.jqXHR], true );
fn( json );
};
@@ -4013,15 +4005,18 @@
}
var baseAjax = {
+ "url": typeof ajax === 'string' ?
+ ajax :
+ '',
"data": data,
"success": callback,
"dataType": "json",
"cache": false,
"type": oSettings.sServerMethod,
- "error": function (xhr, error, thrown) {
- var ret = _fnCallbackFire( oSettings, null, 'xhr', [oSettings, null, oSettings.jqXHR] );
+ "error": function (xhr, error) {
+ var ret = _fnCallbackFire( oSettings, null, 'xhr', [oSettings, null, oSettings.jqXHR], true );
- if ( $.inArray( true, ret ) === -1 ) {
+ if ( ret.indexOf(true) === -1 ) {
if ( error == "parsererror" ) {
_fnLog( oSettings, 0, 'Invalid JSON response', 1 );
}
@@ -4034,43 +4029,33 @@
}
};
+ // If `ajax` option is an object, extend and override our default base
+ if ( $.isPlainObject( ajax ) ) {
+ $.extend( baseAjax, ajax )
+ }
+
// Store the data submitted for the API
oSettings.oAjaxData = data;
// Allow plug-ins and external processes to modify the data
- _fnCallbackFire( oSettings, null, 'preXhr', [oSettings, data] );
+ _fnCallbackFire( oSettings, null, 'preXhr', [oSettings, data, baseAjax], true );
- if ( oSettings.fnServerData )
- {
- // DataTables 1.9- compatibility
- oSettings.fnServerData.call( instance,
- oSettings.sAjaxSource,
- $.map( data, function (val, key) { // Need to convert back to 1.9 trad format
- return { name: key, value: val };
- } ),
- callback,
- oSettings
- );
- }
- else if ( oSettings.sAjaxSource || typeof ajax === 'string' )
- {
- // DataTables 1.9- compatibility
- oSettings.jqXHR = $.ajax( $.extend( baseAjax, {
- url: ajax || oSettings.sAjaxSource
- } ) );
- }
- else if ( typeof ajax === 'function' )
+ if ( typeof ajax === 'function' )
{
// Is a function - let the caller define what needs to be done
oSettings.jqXHR = ajax.call( instance, data, callback, oSettings );
}
- else
- {
+ else if (ajax.url === '') {
+ callback({});
+ }
+ else {
// Object to extend the base settings
- oSettings.jqXHR = $.ajax( $.extend( baseAjax, ajax ) );
+ oSettings.jqXHR = $.ajax( baseAjax );
// Restore for next time around
- ajax.data = ajaxData;
+ if ( ajaxData ) {
+ ajax.data = ajaxData;
+ }
}
}
@@ -4086,16 +4071,11 @@
settings.iDraw++;
_fnProcessingDisplay( settings, true );
- // Keep track of drawHold state to handle scrolling after the Ajax call
- var drawHold = settings._drawHold;
-
_fnBuildAjax(
settings,
_fnAjaxParameters( settings ),
function(json) {
- settings._drawHold = drawHold;
_fnAjaxUpdateDraw( settings, json );
- settings._drawHold = false;
}
);
}
@@ -4103,11 +4083,7 @@
/**
* Build up the parameters in an object needed for a server-side processing
- * request. Note that this is basically done twice, is different ways - a modern
- * method which is used by default in DataTables 1.10 which uses objects and
- * arrays, or the 1.9- method with is name / value pairs. 1.9 method is used if
- * the sAjaxSource option is used in the initialisation, or the legacyAjax
- * option is set.
+ * request.
* @param {object} oSettings dataTables settings object
* @returns {bool} block the table drawing or not
* @memberof DataTable#oApi
@@ -4116,96 +4092,57 @@
{
var
columns = settings.aoColumns,
- columnCount = columns.length,
features = settings.oFeatures,
preSearch = settings.oPreviousSearch,
preColSearch = settings.aoPreSearchCols,
- i, data = [], dataProp, column, columnSearch,
- sort = _fnSortFlatten( settings ),
- displayStart = settings._iDisplayStart,
- displayLength = features.bPaginate !== false ?
- settings._iDisplayLength :
- -1;
-
- var param = function ( name, value ) {
- data.push( { 'name': name, 'value': value } );
- };
+ colData = function ( idx, prop ) {
+ return typeof columns[idx][prop] === 'function' ?
+ 'function' :
+ columns[idx][prop];
+ };
- // DataTables 1.9- compatible method
- param( 'sEcho', settings.iDraw );
- param( 'iColumns', columnCount );
- param( 'sColumns', _pluck( columns, 'sName' ).join(',') );
- param( 'iDisplayStart', displayStart );
- param( 'iDisplayLength', displayLength );
-
- // DataTables 1.10+ method
- var d = {
- draw: settings.iDraw,
- columns: [],
- order: [],
- start: displayStart,
- length: displayLength,
- search: {
- value: preSearch.sSearch,
- regex: preSearch.bRegex
+ return {
+ draw: settings.iDraw,
+ columns: columns.map( function ( column, i ) {
+ return {
+ data: colData(i, 'mData'),
+ name: column.sName,
+ searchable: column.bSearchable,
+ orderable: column.bSortable,
+ search: {
+ value: preColSearch[i].search,
+ regex: preColSearch[i].regex,
+ fixed: Object.keys(column.searchFixed).map( function(name) {
+ return {
+ name: name,
+ term: column.searchFixed[name].toString()
+ }
+ })
+ }
+ };
+ } ),
+ order: _fnSortFlatten( settings ).map( function ( val ) {
+ return {
+ column: val.col,
+ dir: val.dir,
+ name: colData(val.col, 'sName')
+ };
+ } ),
+ start: settings._iDisplayStart,
+ length: features.bPaginate ?
+ settings._iDisplayLength :
+ -1,
+ search: {
+ value: preSearch.search,
+ regex: preSearch.regex,
+ fixed: Object.keys(settings.searchFixed).map( function(name) {
+ return {
+ name: name,
+ term: settings.searchFixed[name].toString()
+ }
+ })
}
};
-
- for ( i=0 ; i<columnCount ; i++ ) {
- column = columns[i];
- columnSearch = preColSearch[i];
- dataProp = typeof column.mData=="function" ? 'function' : column.mData ;
-
- d.columns.push( {
- data: dataProp,
- name: column.sName,
- searchable: column.bSearchable,
- orderable: column.bSortable,
- search: {
- value: columnSearch.sSearch,
- regex: columnSearch.bRegex
- }
- } );
-
- param( "mDataProp_"+i, dataProp );
-
- if ( features.bFilter ) {
- param( 'sSearch_'+i, columnSearch.sSearch );
- param( 'bRegex_'+i, columnSearch.bRegex );
- param( 'bSearchable_'+i, column.bSearchable );
- }
-
- if ( features.bSort ) {
- param( 'bSortable_'+i, column.bSortable );
- }
- }
-
- if ( features.bFilter ) {
- param( 'sSearch', preSearch.sSearch );
- param( 'bRegex', preSearch.bRegex );
- }
-
- if ( features.bSort ) {
- $.each( sort, function ( i, val ) {
- d.order.push( { column: val.col, dir: val.dir } );
-
- param( 'iSortCol_'+i, val.col );
- param( 'sSortDir_'+i, val.dir );
- } );
-
- param( 'iSortingCols', sort.length );
- }
-
- // If the legacy.ajax parameter is null, then we automatically decide which
- // form to use, based on sAjaxSource
- var legacy = DataTable.ext.legacy.ajax;
- if ( legacy === null ) {
- return settings.sAjaxSource ? data : d;
- }
-
- // Otherwise, if legacy has been specified then we use that to decide on the
- // form
- return legacy ? data : d;
}
@@ -4222,16 +4159,10 @@
*/
function _fnAjaxUpdateDraw ( settings, json )
{
- // v1.10 uses camelCase variables, while 1.9 uses Hungarian notation.
- // Support both
- var compat = function ( old, modern ) {
- return json[old] !== undefined ? json[old] : json[modern];
- };
-
- var data = _fnAjaxDataSrc( settings, json );
- var draw = compat( 'sEcho', 'draw' );
- var recordsTotal = compat( 'iTotalRecords', 'recordsTotal' );
- var recordsFiltered = compat( 'iTotalDisplayRecords', 'recordsFiltered' );
+ var data = _fnAjaxDataSrc(settings, json);
+ var draw = _fnAjaxDataSrcParam(settings, 'draw', json);
+ var recordsTotal = _fnAjaxDataSrcParam(settings, 'recordsTotal', json);
+ var recordsFiltered = _fnAjaxDataSrcParam(settings, 'recordsFiltered', json);
if ( draw !== undefined ) {
// Protect against out of sequence returns
@@ -4256,11 +4187,7 @@
settings.aiDisplay = settings.aiDisplayMaster.slice();
_fnDraw( settings, true );
-
- if ( ! settings._bInitComplete ) {
- _fnInitComplete( settings, json );
- }
-
+ _fnInitComplete( settings );
_fnProcessingDisplay( settings, false );
}
@@ -4269,188 +4196,144 @@
* Get the data from the JSON data source to use for drawing a table. Using
* `_fnGetObjectDataFn` allows the data to be sourced from a property of the
* source object, or from a processing function.
- * @param {object} oSettings dataTables settings object
+ * @param {object} settings dataTables settings object
* @param {object} json Data source object / array from the server
* @return {array} Array of data to use
*/
- function _fnAjaxDataSrc ( oSettings, json, write )
- {
- var dataSrc = $.isPlainObject( oSettings.ajax ) && oSettings.ajax.dataSrc !== undefined ?
- oSettings.ajax.dataSrc :
- oSettings.sAjaxDataProp; // Compatibility with 1.9-.
+ function _fnAjaxDataSrc ( settings, json, write )
+ {
+ var dataProp = 'data';
+
+ if ($.isPlainObject( settings.ajax ) && settings.ajax.dataSrc !== undefined) {
+ // Could in inside a `dataSrc` object, or not!
+ var dataSrc = settings.ajax.dataSrc;
+
+ // string, function and object are valid types
+ if (typeof dataSrc === 'string' || typeof dataSrc === 'function') {
+ dataProp = dataSrc;
+ }
+ else if (dataSrc.data !== undefined) {
+ dataProp = dataSrc.data;
+ }
+ }
if ( ! write ) {
- if ( dataSrc === 'data' ) {
+ if ( dataProp === 'data' ) {
// If the default, then we still want to support the old style, and safely ignore
// it if possible
- return json.aaData || json[dataSrc];
+ return json.aaData || json[dataProp];
}
- return dataSrc !== "" ?
- _fnGetObjectDataFn( dataSrc )( json ) :
+ return dataProp !== "" ?
+ _fnGetObjectDataFn( dataProp )( json ) :
json;
}
-
+
// set
- _fnSetObjectDataFn( dataSrc )( json, write );
+ _fnSetObjectDataFn( dataProp )( json, write );
}
/**
- * Generate the node required for filtering text
- * @returns {node} Filter control element
- * @param {object} oSettings dataTables settings object
- * @memberof DataTable#oApi
+ * Very similar to _fnAjaxDataSrc, but for the other SSP properties
+ * @param {*} settings DataTables settings object
+ * @param {*} param Target parameter
+ * @param {*} json JSON data
+ * @returns Resolved value
*/
- function _fnFeatureHtmlFilter ( settings )
- {
- var classes = settings.oClasses;
- var tableId = settings.sTableId;
- var language = settings.oLanguage;
- var previousSearch = settings.oPreviousSearch;
- var features = settings.aanFeatures;
- var input = '<input type="search" class="'+classes.sFilterInput+'"/>';
+ function _fnAjaxDataSrcParam (settings, param, json) {
+ var dataSrc = $.isPlainObject( settings.ajax )
+ ? settings.ajax.dataSrc
+ : null;
- var str = language.sSearch;
- str = str.match(/_INPUT_/) ?
- str.replace('_INPUT_', input) :
- str+input;
-
- var filter = $('<div/>', {
- 'id': ! features.f ? tableId+'_filter' : null,
- 'class': classes.sFilter
- } )
- .append( $('<label/>' ).append( str ) );
-
- var searchFn = function(event) {
- /* Update all other filter input elements for the new display */
- var n = features.f;
- var val = !this.value ? "" : this.value; // mental IE8 fix :-(
- if(previousSearch.return && event.key !== "Enter") {
- return;
- }
- /* Now do the filter */
- if ( val != previousSearch.sSearch ) {
- _fnFilterComplete( settings, {
- "sSearch": val,
- "bRegex": previousSearch.bRegex,
- "bSmart": previousSearch.bSmart ,
- "bCaseInsensitive": previousSearch.bCaseInsensitive,
- "return": previousSearch.return
- } );
-
- // Need to redraw, without resorting
- settings._iDisplayStart = 0;
- _fnDraw( settings );
- }
- };
-
- var searchDelay = settings.searchDelay !== null ?
- settings.searchDelay :
- _fnDataSource( settings ) === 'ssp' ?
- 400 :
- 0;
+ if (dataSrc && dataSrc[param]) {
+ // Get from custom location
+ return _fnGetObjectDataFn( dataSrc[param] )( json );
+ }
- var jqFilter = $('input', filter)
- .val( previousSearch.sSearch )
- .attr( 'placeholder', language.sSearchPlaceholder )
- .on(
- 'keyup.DT search.DT input.DT paste.DT cut.DT',
- searchDelay ?
- _fnThrottle( searchFn, searchDelay ) :
- searchFn
- )
- .on( 'mouseup.DT', function(e) {
- // Edge fix! Edge 17 does not trigger anything other than mouse events when clicking
- // on the clear icon (Edge bug 17584515). This is safe in other browsers as `searchFn`
- // checks the value to see if it has changed. In other browsers it won't have.
- setTimeout( function () {
- searchFn.call(jqFilter[0], e);
- }, 10);
- } )
- .on( 'keypress.DT', function(e) {
- /* Prevent form submission */
- if ( e.keyCode == 13 ) {
- return false;
- }
- } )
- .attr('aria-controls', tableId);
+ // else - Default behaviour
+ var old = '';
- // Update the input elements whenever the table is filtered
- $(settings.nTable).on( 'search.dt.DT', function ( ev, s ) {
- if ( settings === s ) {
- // IE9 throws an 'unknown error' if document.activeElement is used
- // inside an iframe or frame...
- try {
- if ( jqFilter[0] !== document.activeElement ) {
- jqFilter.val( previousSearch.sSearch );
- }
- }
- catch ( e ) {}
- }
- } );
+ // Legacy support
+ if (param === 'draw') {
+ old = 'sEcho';
+ }
+ else if (param === 'recordsTotal') {
+ old = 'iTotalRecords';
+ }
+ else if (param === 'recordsFiltered') {
+ old = 'iTotalDisplayRecords';
+ }
- return filter[0];
+ return json[old] !== undefined
+ ? json[old]
+ : json[param];
}
/**
* Filter the table using both the global filter and column based filtering
- * @param {object} oSettings dataTables settings object
- * @param {object} oSearch search information
- * @param {int} [iForce] force a research of the master array (1) or not (undefined or 0)
+ * @param {object} settings dataTables settings object
+ * @param {object} input search information
* @memberof DataTable#oApi
*/
- function _fnFilterComplete ( oSettings, oInput, iForce )
+ function _fnFilterComplete ( settings, input )
{
- var oPrevSearch = oSettings.oPreviousSearch;
- var aoPrevSearch = oSettings.aoPreSearchCols;
- var fnSaveFilter = function ( oFilter ) {
- /* Save the filtering values */
- oPrevSearch.sSearch = oFilter.sSearch;
- oPrevSearch.bRegex = oFilter.bRegex;
- oPrevSearch.bSmart = oFilter.bSmart;
- oPrevSearch.bCaseInsensitive = oFilter.bCaseInsensitive;
- oPrevSearch.return = oFilter.return;
- };
- var fnRegex = function ( o ) {
- // Backwards compatibility with the bEscapeRegex option
- return o.bEscapeRegex !== undefined ? !o.bEscapeRegex : o.bRegex;
- };
+ var columnsSearch = settings.aoPreSearchCols;
// Resolve any column types that are unknown due to addition or invalidation
// @todo As per sort - can this be moved into an event handler?
- _fnColumnTypes( oSettings );
+ _fnColumnTypes( settings );
- /* In server-side processing all filtering is done by the server, so no point hanging around here */
- if ( _fnDataSource( oSettings ) != 'ssp' )
+ // In server-side processing all filtering is done by the server, so no point hanging around here
+ if ( _fnDataSource( settings ) != 'ssp' )
{
- /* Global filter */
- _fnFilter( oSettings, oInput.sSearch, iForce, fnRegex(oInput), oInput.bSmart, oInput.bCaseInsensitive );
- fnSaveFilter( oInput );
+ // Check if any of the rows were invalidated
+ _fnFilterData( settings );
+
+ // Start from the full data set
+ settings.aiDisplay = settings.aiDisplayMaster.slice();
+
+ // Global filter first
+ _fnFilter( settings.aiDisplay, settings, input.search, input );
+
+ $.each(settings.searchFixed, function (name, term) {
+ _fnFilter(settings.aiDisplay, settings, term, {});
+ });
- /* Now do the individual column filter */
- for ( var i=0 ; i<aoPrevSearch.length ; i++ )
+ // Then individual column filters
+ for ( var i=0 ; i<columnsSearch.length ; i++ )
{
- _fnFilterColumn( oSettings, aoPrevSearch[i].sSearch, i, fnRegex(aoPrevSearch[i]),
- aoPrevSearch[i].bSmart, aoPrevSearch[i].bCaseInsensitive );
+ var col = columnsSearch[i];
+
+ _fnFilter(
+ settings.aiDisplay,
+ settings,
+ col.search,
+ col,
+ i
+ );
+
+ $.each(settings.aoColumns[i].searchFixed, function (name, term) {
+ _fnFilter(settings.aiDisplay, settings, term, {}, i);
+ });
}
- /* Custom filtering */
- _fnFilterCustom( oSettings );
- }
- else
- {
- fnSaveFilter( oInput );
+ // And finally global filtering
+ _fnFilterCustom( settings );
}
- /* Tell the draw function we have been filtering */
- oSettings.bFiltered = true;
- _fnCallbackFire( oSettings, null, 'search', [oSettings] );
+ // Tell the draw function we have been filtering
+ settings.bFiltered = true;
+
+ _fnCallbackFire( settings, null, 'search', [settings] );
}
/**
* Apply custom filtering functions
+ *
+ * This is legacy now that we have named functions, but it is widely used
+ * from 1.x, so it is not yet deprecated.
* @param {object} oSettings dataTables settings object
* @memberof DataTable#oApi
*/
@@ -4476,97 +4359,44 @@
// So the array reference doesn't break set the results into the
// existing array
displayRows.length = 0;
- $.merge( displayRows, rows );
- }
- }
-
-
- /**
- * Filter the table on a per-column basis
- * @param {object} oSettings dataTables settings object
- * @param {string} sInput string to filter on
- * @param {int} iColumn column to filter
- * @param {bool} bRegex treat search string as a regular expression or not
- * @param {bool} bSmart use smart filtering or not
- * @param {bool} bCaseInsensitive Do case insensitive matching or not
- * @memberof DataTable#oApi
- */
- function _fnFilterColumn ( settings, searchStr, colIdx, regex, smart, caseInsensitive )
- {
- if ( searchStr === '' ) {
- return;
+ displayRows.push.apply(displayRows, rows);
}
-
- var data;
- var out = [];
- var display = settings.aiDisplay;
- var rpSearch = _fnFilterCreateSearch( searchStr, regex, smart, caseInsensitive );
-
- for ( var i=0 ; i<display.length ; i++ ) {
- data = settings.aoData[ display[i] ]._aFilterData[ colIdx ];
-
- if ( rpSearch.test( data ) ) {
- out.push( display[i] );
- }
- }
-
- settings.aiDisplay = out;
}
/**
* Filter the data table based on user input and draw the table
- * @param {object} settings dataTables settings object
- * @param {string} input string to filter on
- * @param {int} force optional - force a research of the master array (1) or not (undefined or 0)
- * @param {bool} regex treat as a regular expression or not
- * @param {bool} smart perform smart filtering or not
- * @param {bool} caseInsensitive Do case insensitive matching or not
- * @memberof DataTable#oApi
*/
- function _fnFilter( settings, input, force, regex, smart, caseInsensitive )
+ function _fnFilter( searchRows, settings, input, options, column )
{
- var rpSearch = _fnFilterCreateSearch( input, regex, smart, caseInsensitive );
- var prevSearch = settings.oPreviousSearch.sSearch;
- var displayMaster = settings.aiDisplayMaster;
- var display, invalidated, i;
- var filtered = [];
-
- // Need to take account of custom filtering functions - always filter
- if ( DataTable.ext.search.length !== 0 ) {
- force = true;
+ if ( input === '' ) {
+ return;
}
- // Check if any of the rows were invalidated
- invalidated = _fnFilterData( settings );
+ var i = 0;
- // If the input is blank - we just want the full data set
- if ( input.length <= 0 ) {
- settings.aiDisplay = displayMaster.slice();
- }
- else {
- // New search - start from the master array
- if ( invalidated ||
- force ||
- regex ||
- prevSearch.length > input.length ||
- input.indexOf(prevSearch) !== 0 ||
- settings.bSorted // On resort, the display master needs to be
- // re-filtered since indexes will have changed
- ) {
- settings.aiDisplay = displayMaster.slice();
- }
+ // Search term can be a function, regex or string - if a string we apply our
+ // smart filtering regex (assuming the options require that)
+ var searchFunc = typeof input === 'function' ? input : null;
+ var rpSearch = input instanceof RegExp
+ ? input
+ : searchFunc
+ ? null
+ : _fnFilterCreateSearch( input, options );
- // Search the display array
- display = settings.aiDisplay;
+ // Then for each row, does the test pass. If not, lop the row from the array
+ while (i < searchRows.length) {
+ var row = settings.aoData[ searchRows[i] ];
+ var data = column === undefined
+ ? row._sFilterRow
+ : row._aFilterData[ column ];
- for ( i=0 ; i<display.length ; i++ ) {
- if ( rpSearch.test( settings.aoData[ display[i] ]._sFilterRow ) ) {
- filtered.push( display[i] );
- }
+ if ( (searchFunc && ! searchFunc(data, row._aData, searchRows[i], column)) || (rpSearch && ! rpSearch.test(data)) ) {
+ searchRows.splice(i, 1);
+ i--;
}
- settings.aiDisplay = filtered;
+ i++;
}
}
@@ -4580,37 +4410,89 @@
* @returns {RegExp} constructed object
* @memberof DataTable#oApi
*/
- function _fnFilterCreateSearch( search, regex, smart, caseInsensitive )
+ function _fnFilterCreateSearch( search, inOpts )
{
- search = regex ?
+ var not = [];
+ var options = $.extend({}, {
+ boundary: false,
+ caseInsensitive: true,
+ exact: false,
+ regex: false,
+ smart: true
+ }, inOpts);
+
+ if (typeof search !== 'string') {
+ search = search.toString();
+ }
+
+ if (options.exact) {
+ return new RegExp(
+ '^'+_fnEscapeRegex(search)+'$',
+ options.caseInsensitive ? 'i' : ''
+ );
+ }
+
+ search = options.regex ?
search :
_fnEscapeRegex( search );
- if ( smart ) {
+ if ( options.smart ) {
/* For smart filtering we want to allow the search to work regardless of
* word order. We also want double quoted text to be preserved, so word
- * order is important - a la google. So this is what we want to
- * generate:
+ * order is important - a la google. And a negative look around for
+ * finding rows which don't contain a given string.
+ *
+ * So this is the sort of thing we want to generate:
*
* ^(?=.*?\bone\b)(?=.*?\btwo three\b)(?=.*?\bfour\b).*$
*/
- var a = $.map( search.match( /["\u201C][^"\u201D]+["\u201D]|[^ ]+/g ) || [''], function ( word ) {
+ var parts = search.match( /!?["\u201C][^"\u201D]+["\u201D]|[^ ]+/g ) || [''];
+ var a = parts.map( function ( word ) {
+ var negative = false;
+ var m;
+
+ // Determine if it is a "does not include"
+ if ( word.charAt(0) === '!' ) {
+ negative = true;
+ word = word.substring(1);
+ }
+
+ // Strip the quotes from around matched phrases
if ( word.charAt(0) === '"' ) {
- var m = word.match( /^"(.*)"$/ );
+ m = word.match( /^"(.*)"$/ );
word = m ? m[1] : word;
}
else if ( word.charAt(0) === '\u201C' ) {
- var m = word.match( /^\u201C(.*)\u201D$/ );
+ // Smart quote match (iPhone users)
+ m = word.match( /^\u201C(.*)\u201D$/ );
word = m ? m[1] : word;
}
+ // For our "not" case, we need to modify the string that is
+ // allowed to match at the end of the expression.
+ if (negative) {
+ if (word.length > 1) {
+ not.push('(?!'+word+')');
+ }
+
+ word = '';
+ }
+
return word.replace('"', '');
} );
- search = '^(?=.*?'+a.join( ')(?=.*?' )+').*$';
+ var match = not.length
+ ? not.join('')
+ : '';
+
+ var boundary = options.boundary
+ ? '\\b'
+ : '';
+
+ search = '^(?=.*?'+boundary+a.join( ')(?=.*?'+boundary )+')('+match+'.)*$';
}
- return new RegExp( search, caseInsensitive ? 'i' : '' );
+ return new RegExp( search, options.caseInsensitive ? 'i' : '' );
}
@@ -4629,12 +4511,17 @@
function _fnFilterData ( settings )
{
var columns = settings.aoColumns;
+ var data = settings.aoData;
var column;
- var i, j, ien, jen, filterData, cellData, row;
+ var j, jen, filterData, cellData, row;
var wasInvalidated = false;
- for ( i=0, ien=settings.aoData.length ; i<ien ; i++ ) {
- row = settings.aoData[i];
+ for ( var rowIdx=0 ; rowIdx<data.length ; rowIdx++ ) {
+ if (! data[rowIdx]) {
+ continue;
+ }
+
+ row = data[rowIdx];
if ( ! row._aFilterData ) {
filterData = [];
@@ -4643,10 +4530,9 @@
column = columns[j];
if ( column.bSearchable ) {
- cellData = _fnGetCellData( settings, i, j, 'filter' );
+ cellData = _fnGetCellData( settings, rowIdx, j, 'filter' );
- // Search in DataTables 1.10 is string based. In 1.11 this
- // should be altered to also allow strict type checking.
+ // Search in DataTables is string based
if ( cellData === null ) {
cellData = '';
}
@@ -4662,7 +4548,7 @@
// If it looks like there is an HTML entity in the string,
// attempt to decode it so sorting works as expected. Note that
// we could use a single line of jQuery to do this, but the DOM
- // method used here is much faster http://jsperf.com/html-decode
+ // method used here is much faster https://jsperf.com/html-decode
if ( cellData.indexOf && cellData.indexOf('&') !== -1 ) {
__filter_div.innerHTML = cellData;
cellData = __filter_div_textContent ?
@@ -4688,152 +4574,13 @@
/**
- * Convert from the internal Hungarian notation to camelCase for external
- * interaction
- * @param {object} obj Object to convert
- * @returns {object} Inverted object
- * @memberof DataTable#oApi
- */
- function _fnSearchToCamel ( obj )
- {
- return {
- search: obj.sSearch,
- smart: obj.bSmart,
- regex: obj.bRegex,
- caseInsensitive: obj.bCaseInsensitive
- };
- }
-
-
-
- /**
- * Convert from camelCase notation to the internal Hungarian. We could use the
- * Hungarian convert function here, but this is cleaner
- * @param {object} obj Object to convert
- * @returns {object} Inverted object
- * @memberof DataTable#oApi
- */
- function _fnSearchToHung ( obj )
- {
- return {
- sSearch: obj.search,
- bSmart: obj.smart,
- bRegex: obj.regex,
- bCaseInsensitive: obj.caseInsensitive
- };
- }
-
- /**
- * Generate the node required for the info display
- * @param {object} oSettings dataTables settings object
- * @returns {node} Information element
- * @memberof DataTable#oApi
- */
- function _fnFeatureHtmlInfo ( settings )
- {
- var
- tid = settings.sTableId,
- nodes = settings.aanFeatures.i,
- n = $('<div/>', {
- 'class': settings.oClasses.sInfo,
- 'id': ! nodes ? tid+'_info' : null
- } );
-
- if ( ! nodes ) {
- // Update display on each draw
- settings.aoDrawCallback.push( {
- "fn": _fnUpdateInfo,
- "sName": "information"
- } );
-
- n
- .attr( 'role', 'status' )
- .attr( 'aria-live', 'polite' );
-
- // Table is described by our info div
- $(settings.nTable).attr( 'aria-describedby', tid+'_info' );
- }
-
- return n[0];
- }
-
-
- /**
- * Update the information elements in the display
- * @param {object} settings dataTables settings object
- * @memberof DataTable#oApi
- */
- function _fnUpdateInfo ( settings )
- {
- /* Show information about the table */
- var nodes = settings.aanFeatures.i;
- if ( nodes.length === 0 ) {
- return;
- }
-
- var
- lang = settings.oLanguage,
- start = settings._iDisplayStart+1,
- end = settings.fnDisplayEnd(),
- max = settings.fnRecordsTotal(),
- total = settings.fnRecordsDisplay(),
- out = total ?
- lang.sInfo :
- lang.sInfoEmpty;
-
- if ( total !== max ) {
- /* Record set after filtering */
- out += ' ' + lang.sInfoFiltered;
- }
-
- // Convert the macros
- out += lang.sInfoPostFix;
- out = _fnInfoMacros( settings, out );
-
- var callback = lang.fnInfoCallback;
- if ( callback !== null ) {
- out = callback.call( settings.oInstance,
- settings, start, end, max, total, out
- );
- }
-
- $(nodes).html( out );
- }
-
-
- function _fnInfoMacros ( settings, str )
- {
- // When infinite scrolling, we are always starting at 1. _iDisplayStart is used only
- // internally
- var
- formatter = settings.fnFormatNumber,
- start = settings._iDisplayStart+1,
- len = settings._iDisplayLength,
- vis = settings.fnRecordsDisplay(),
- all = len === -1;
-
- return str.
- replace(/_START_/g, formatter.call( settings, start ) ).
- replace(/_END_/g, formatter.call( settings, settings.fnDisplayEnd() ) ).
- replace(/_MAX_/g, formatter.call( settings, settings.fnRecordsTotal() ) ).
- replace(/_TOTAL_/g, formatter.call( settings, vis ) ).
- replace(/_PAGE_/g, formatter.call( settings, all ? 1 : Math.ceil( start / len ) ) ).
- replace(/_PAGES_/g, formatter.call( settings, all ? 1 : Math.ceil( vis / len ) ) );
- }
-
-
-
- /**
* Draw the table for the first time, adding all required features
* @param {object} settings dataTables settings object
* @memberof DataTable#oApi
*/
function _fnInitialise ( settings )
{
- var i, iLen, iAjaxStart=settings.iInitDisplayStart;
- var columns = settings.aoColumns, column;
- var features = settings.oFeatures;
- var deferLoading = settings.bDeferLoading; // value modified by the draw
+ var i, iAjaxStart=settings.iInitDisplayStart;
/* Ensure that the table data is fully initialised */
if ( ! settings.bInitialised ) {
@@ -4841,31 +4588,22 @@
return;
}
- /* Show the display HTML options */
- _fnAddOptionsHtml( settings );
-
/* Build and draw the header / footer for the table */
- _fnBuildHead( settings );
+ _fnBuildHead( settings, 'header' );
+ _fnBuildHead( settings, 'footer' );
_fnDrawHead( settings, settings.aoHeader );
_fnDrawHead( settings, settings.aoFooter );
- /* Okay to show that something is going on now */
- _fnProcessingDisplay( settings, true );
-
- /* Calculate sizes for columns */
- if ( features.bAutoWidth ) {
- _fnCalculateColumnWidths( settings );
- }
+ // Enable features
+ _fnAddOptionsHtml( settings );
+ _fnSortInit( settings );
- for ( i=0, iLen=columns.length ; i<iLen ; i++ ) {
- column = columns[i];
+ _colGroup( settings );
- if ( column.sWidth ) {
- column.nTh.style.width = _fnStringToCss( column.sWidth );
- }
- }
+ /* Okay to show that something is going on now */
+ _fnProcessingDisplay( settings, true );
- _fnCallbackFire( settings, null, 'preInit', [settings] );
+ _fnCallbackFire( settings, null, 'preInit', [settings], true );
// If there is default sorting required - let's do it. The sort function
// will do the drawing for us. Otherwise we draw the table regardless of the
@@ -4873,12 +4611,13 @@
// data (show 'loading' message possibly)
_fnReDraw( settings );
- // Server-side processing init complete is done by _fnAjaxUpdateDraw
var dataSrc = _fnDataSource( settings );
- if ( dataSrc != 'ssp' || deferLoading ) {
+
+ // Server-side processing init complete is done by _fnAjaxUpdateDraw
+ if ( dataSrc != 'ssp' ) {
// if there is an ajax source load the data
if ( dataSrc == 'ajax' ) {
- _fnBuildAjax( settings, [], function(json) {
+ _fnBuildAjax( settings, {}, function(json) {
var aData = _fnAjaxDataSrc( settings, json );
// Got the data - add it to the table
@@ -4892,14 +4631,13 @@
settings.iInitDisplayStart = iAjaxStart;
_fnReDraw( settings );
-
_fnProcessingDisplay( settings, false );
- _fnInitComplete( settings, json );
+ _fnInitComplete( settings );
}, settings );
}
else {
- _fnProcessingDisplay( settings, false );
_fnInitComplete( settings );
+ _fnProcessingDisplay( settings, false );
}
}
}
@@ -4907,26 +4645,27 @@
/**
* Draw the table for the first time, adding all required features
- * @param {object} oSettings dataTables settings object
- * @param {object} [json] JSON from the server that completed the table, if using Ajax source
- * with client-side processing (optional)
+ * @param {object} settings dataTables settings object
* @memberof DataTable#oApi
*/
- function _fnInitComplete ( settings, json )
+ function _fnInitComplete ( settings )
{
+ if (settings._bInitComplete) {
+ return;
+ }
+
+ var args = [settings, settings.json];
+
settings._bInitComplete = true;
- // When data was added after the initialisation (data or Ajax) we need to
- // calculate the column sizing
- if ( json || settings.oInit.aaData ) {
- _fnAdjustColumnSizing( settings );
- }
+ // Table is fully set up and we have data, so calculate the
+ // column widths
+ _fnAdjustColumnSizing( settings );
- _fnCallbackFire( settings, null, 'plugin-init', [settings, json] );
- _fnCallbackFire( settings, 'aoInitComplete', 'init', [settings, json] );
+ _fnCallbackFire( settings, null, 'plugin-init', args, true );
+ _fnCallbackFire( settings, 'aoInitComplete', 'init', args, true );
}
-
function _fnLengthChange ( settings, val )
{
var len = parseInt( val, 10 );
@@ -4938,131 +4677,6 @@
_fnCallbackFire( settings, null, 'length', [settings, len] );
}
-
- /**
- * Generate the node required for user display length changing
- * @param {object} settings dataTables settings object
- * @returns {node} Display length feature node
- * @memberof DataTable#oApi
- */
- function _fnFeatureHtmlLength ( settings )
- {
- var
- classes = settings.oClasses,
- tableId = settings.sTableId,
- menu = settings.aLengthMenu,
- d2 = Array.isArray( menu[0] ),
- lengths = d2 ? menu[0] : menu,
- language = d2 ? menu[1] : menu;
-
- var select = $('<select/>', {
- 'name': tableId+'_length',
- 'aria-controls': tableId,
- 'class': classes.sLengthSelect
- } );
-
- for ( var i=0, ien=lengths.length ; i<ien ; i++ ) {
- select[0][ i ] = new Option(
- typeof language[i] === 'number' ?
- settings.fnFormatNumber( language[i] ) :
- language[i],
- lengths[i]
- );
- }
-
- var div = $('<div><label/></div>').addClass( classes.sLength );
- if ( ! settings.aanFeatures.l ) {
- div[0].id = tableId+'_length';
- }
-
- div.children().append(
- settings.oLanguage.sLengthMenu.replace( '_MENU_', select[0].outerHTML )
- );
-
- // Can't use `select` variable as user might provide their own and the
- // reference is broken by the use of outerHTML
- $('select', div)
- .val( settings._iDisplayLength )
- .on( 'change.DT', function(e) {
- _fnLengthChange( settings, $(this).val() );
- _fnDraw( settings );
- } );
-
- // Update node value whenever anything changes the table's length
- $(settings.nTable).on( 'length.dt.DT', function (e, s, len) {
- if ( settings === s ) {
- $('select', div).val( len );
- }
- } );
-
- return div[0];
- }
-
-
-
- /* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *
- * Note that most of the paging logic is done in
- * DataTable.ext.pager
- */
-
- /**
- * Generate the node required for default pagination
- * @param {object} oSettings dataTables settings object
- * @returns {node} Pagination feature node
- * @memberof DataTable#oApi
- */
- function _fnFeatureHtmlPaginate ( settings )
- {
- var
- type = settings.sPaginationType,
- plugin = DataTable.ext.pager[ type ],
- modern = typeof plugin === 'function',
- redraw = function( settings ) {
- _fnDraw( settings );
- },
- node = $('<div/>').addClass( settings.oClasses.sPaging + type )[0],
- features = settings.aanFeatures;
-
- if ( ! modern ) {
- plugin.fnInit( settings, node, redraw );
- }
-
- /* Add a draw callback for the pagination on first instance, to update the paging display */
- if ( ! features.p )
- {
- node.id = settings.sTableId+'_paginate';
-
- settings.aoDrawCallback.push( {
- "fn": function( settings ) {
- if ( modern ) {
- var
- start = settings._iDisplayStart,
- len = settings._iDisplayLength,
- visRecords = settings.fnRecordsDisplay(),
- all = len === -1,
- page = all ? 0 : Math.ceil( start / len ),
- pages = all ? 1 : Math.ceil( visRecords / len ),
- buttons = plugin(page, pages),
- i, ien;
-
- for ( i=0, ien=features.p.length ; i<ien ; i++ ) {
- _fnRenderer( settings, 'pageButton' )(
- settings, features.p[i], i, buttons, page, pages
- );
- }
- }
- else {
- plugin.fnUpdate( settings, redraw );
- }
- },
- "sName": "pagination"
- } );
- }
-
- return node;
- }
-
-
/**
* Alter the display settings to change the page
* @param {object} settings DataTables settings object
@@ -5104,7 +4718,7 @@
if ( start < 0 )
{
- start = 0;
+ start = 0;
}
}
else if ( action == "next" )
@@ -5118,6 +4732,10 @@
{
start = Math.floor( (records-1) / len) * len;
}
+ else if ( action === 'ellipsis' )
+ {
+ return;
+ }
else
{
_fnLog( settings, 0, "Unknown paging action: "+action, 5 );
@@ -5126,57 +4744,50 @@
var changed = settings._iDisplayStart !== start;
settings._iDisplayStart = start;
- if ( changed ) {
- _fnCallbackFire( settings, null, 'page', [settings] );
+ _fnCallbackFire( settings, null, changed ? 'page' : 'page-nc', [settings] );
- if ( redraw ) {
- _fnDraw( settings );
- }
- }
- else {
- // No change event - paging was called, but no change
- _fnCallbackFire( settings, null, 'page-nc', [settings] );
+ if ( changed && redraw ) {
+ _fnDraw( settings );
}
return changed;
}
-
/**
* Generate the node required for the processing node
- * @param {object} settings dataTables settings object
- * @returns {node} Processing element
- * @memberof DataTable#oApi
+ * @param {object} settings DataTables settings object
*/
- function _fnFeatureHtmlProcessing ( settings )
+ function _processingHtml ( settings )
{
- return $('<div/>', {
- 'id': ! settings.aanFeatures.r ? settings.sTableId+'_processing' : null,
- 'class': settings.oClasses.sProcessing,
- 'role': 'status'
- } )
- .html( settings.oLanguage.sProcessing )
- .append('<div><div></div><div></div><div></div><div></div></div>')
- .insertBefore( settings.nTable )[0];
+ var table = settings.nTable;
+
+ if ( settings.oFeatures.bProcessing ) {
+ var n = $('<div/>', {
+ 'id': settings.sTableId + '_processing',
+ 'class': settings.oClasses.processing.container,
+ 'role': 'status'
+ } )
+ .html( settings.oLanguage.sProcessing )
+ .append('<div><div></div><div></div><div></div><div></div></div>')
+ .insertBefore( table );
+
+ $(table).on( 'processing.dt.DT', function (e, s, show) {
+ n.css( 'display', show ? 'block' : 'none' );
+ } );
+ }
}
/**
* Display or hide the processing indicator
- * @param {object} settings dataTables settings object
+ * @param {object} settings DataTables settings object
* @param {bool} show Show the processing indicator (true) or not (false)
- * @memberof DataTable#oApi
*/
function _fnProcessingDisplay ( settings, show )
{
- if ( settings.oFeatures.bProcessing ) {
- $(settings.aanFeatures.r).css( 'display', show ? 'block' : 'none' );
- }
-
_fnCallbackFire( settings, null, 'processing', [settings, show] );
}
-
/**
* Add any control elements for the table - specifically scrolling
* @param {object} settings dataTables settings object
@@ -5196,9 +4807,9 @@
var scrollX = scroll.sX;
var scrollY = scroll.sY;
- var classes = settings.oClasses;
- var caption = table.children('caption');
- var captionSide = caption.length ? caption[0]._captionSide : null;
+ var classes = settings.oClasses.scrolling;
+ var caption = settings.captionNode;
+ var captionSide = caption ? caption._captionSide : null;
var headerClone = $( table[0].cloneNode(false) );
var footerClone = $( table[0].cloneNode(false) );
var footer = table.children('tfoot');
@@ -5227,9 +4838,9 @@
* table - scroll foot table
* tfoot - tfoot
*/
- var scroller = $( _div, { 'class': classes.sScrollWrapper } )
+ var scroller = $( _div, { 'class': classes.container } )
.append(
- $(_div, { 'class': classes.sScrollHead } )
+ $(_div, { 'class': classes.header.self } )
.css( {
overflow: 'hidden',
position: 'relative',
@@ -5237,7 +4848,7 @@
width: scrollX ? size(scrollX) : '100%'
} )
.append(
- $(_div, { 'class': classes.sScrollHeadInner } )
+ $(_div, { 'class': classes.header.inner } )
.css( {
'box-sizing': 'content-box',
width: scroll.sXInner || '100%'
@@ -5254,7 +4865,7 @@
)
)
.append(
- $(_div, { 'class': classes.sScrollBody } )
+ $(_div, { 'class': classes.body } )
.css( {
position: 'relative',
overflow: 'auto',
@@ -5265,14 +4876,14 @@
if ( footer ) {
scroller.append(
- $(_div, { 'class': classes.sScrollFoot } )
+ $(_div, { 'class': classes.footer.self } )
.css( {
overflow: 'hidden',
border: 0,
width: scrollX ? size(scrollX) : '100%'
} )
.append(
- $(_div, { 'class': classes.sScrollFootInner } )
+ $(_div, { 'class': classes.footer.inner } )
.append(
footerClone
.removeAttr('id')
@@ -5292,17 +4903,26 @@
var scrollFoot = footer ? children[2] : null;
// When the body is scrolled, then we also want to scroll the headers
- if ( scrollX ) {
- $(scrollBody).on( 'scroll.DT', function (e) {
- var scrollLeft = this.scrollLeft;
+ $(scrollBody).on( 'scroll.DT', function () {
+ var scrollLeft = this.scrollLeft;
- scrollHead.scrollLeft = scrollLeft;
+ scrollHead.scrollLeft = scrollLeft;
- if ( footer ) {
- scrollFoot.scrollLeft = scrollLeft;
- }
- } );
- }
+ if ( footer ) {
+ scrollFoot.scrollLeft = scrollLeft;
+ }
+ } );
+
+ // When focus is put on the header cells, we might need to scroll the body
+ $('th, td', scrollHead).on('focus', function () {
+ var scrollLeft = scrollHead.scrollLeft;
+
+ scrollBody.scrollLeft = scrollLeft;
+
+ if ( footer ) {
+ scrollBody.scrollLeft = scrollLeft;
+ }
+ });
$(scrollBody).css('max-height', scrollY);
if (! scroll.bCollapse) {
@@ -5314,10 +4934,7 @@
settings.nScrollFoot = scrollFoot;
// On redraw - align columns
- settings.aoDrawCallback.push( {
- "fn": _fnScrollDraw,
- "sName": "scrolling"
- } );
+ settings.aoDrawCallback.push(_fnScrollDraw);
return scroller[0];
}
@@ -5331,8 +4948,8 @@
* Welcome to the most horrible function DataTables. The process that this
* function follows is basically:
* 1. Re-create the table inside the scrolling div
- * 2. Take live measurements from the DOM
- * 3. Apply the measurements to align the columns
+ * 2. Correct colgroup > col values if needed
+ * 3. Copy colgroup > col over to header and footer
* 4. Clean up
*
* @param {object} settings dataTables settings object
@@ -5344,43 +4961,20 @@
// to try and keep the minimised size as small as possible
var
scroll = settings.oScroll,
- scrollX = scroll.sX,
- scrollXInner = scroll.sXInner,
- scrollY = scroll.sY,
barWidth = scroll.iBarWidth,
divHeader = $(settings.nScrollHead),
- divHeaderStyle = divHeader[0].style,
divHeaderInner = divHeader.children('div'),
- divHeaderInnerStyle = divHeaderInner[0].style,
divHeaderTable = divHeaderInner.children('table'),
divBodyEl = settings.nScrollBody,
divBody = $(divBodyEl),
- divBodyStyle = divBodyEl.style,
divFooter = $(settings.nScrollFoot),
divFooterInner = divFooter.children('div'),
divFooterTable = divFooterInner.children('table'),
header = $(settings.nTHead),
table = $(settings.nTable),
- tableEl = table[0],
- tableStyle = tableEl.style,
- footer = settings.nTFoot ? $(settings.nTFoot) : null,
+ footer = settings.nTFoot && $('th, td', settings.nTFoot).length ? $(settings.nTFoot) : null,
browser = settings.oBrowser,
- ie67 = browser.bScrollOversize,
- dtHeaderCells = _pluck( settings.aoColumns, 'nTh' ),
- headerTrgEls, footerTrgEls,
- headerSrcEls, footerSrcEls,
- headerCopy, footerCopy,
- headerWidths=[], footerWidths=[],
- headerContent=[], footerContent=[],
- idx, correction, sanityWidth,
- zeroOut = function(nSizer) {
- var style = nSizer.style;
- style.paddingTop = "0";
- style.paddingBottom = "0";
- style.borderTopWidth = "0";
- style.borderBottomWidth = "0";
- style.height = 0;
- };
+ headerCopy, footerCopy;
// If the scrollbar visibility has changed from the last draw, we need to
// adjust the column sizes as the table width will have changed to account
@@ -5396,214 +4990,95 @@
settings.scrollBarVis = scrollBarVis;
}
- /*
- * 1. Re-create the table inside the scrolling div
- */
-
+ // 1. Re-create the table inside the scrolling div
// Remove the old minimised thead and tfoot elements in the inner table
table.children('thead, tfoot').remove();
- if ( footer ) {
- footerCopy = footer.clone().prependTo( table );
- footerTrgEls = footer.find('tr'); // the original tfoot is in its own table and must be sized
- footerSrcEls = footerCopy.find('tr');
- footerCopy.find('[id]').removeAttr('id');
- }
-
// Clone the current header and footer elements and then place it into the inner table
headerCopy = header.clone().prependTo( table );
- headerTrgEls = header.find('tr'); // original header is in its own table
- headerSrcEls = headerCopy.find('tr');
headerCopy.find('th, td').removeAttr('tabindex');
headerCopy.find('[id]').removeAttr('id');
-
- /*
- * 2. Take live measurements from the DOM - do not alter the DOM itself!
- */
-
- // Remove old sizing and apply the calculated column widths
- // Get the unique column headers in the newly created (cloned) header. We want to apply the
- // calculated sizes to this header
- if ( ! scrollX )
- {
- divBodyStyle.width = '100%';
- divHeader[0].style.width = '100%';
- }
-
- $.each( _fnGetUniqueThs( settings, headerCopy ), function ( i, el ) {
- idx = _fnVisibleToColumnIndex( settings, i );
- el.style.width = settings.aoColumns[idx].sWidth;
- } );
-
if ( footer ) {
- _fnApplyToChildren( function(n) {
- n.style.width = "";
- }, footerSrcEls );
- }
-
- // Size the table as a whole
- sanityWidth = table.outerWidth();
- if ( scrollX === "" ) {
- // No x scrolling
- tableStyle.width = "100%";
-
- // IE7 will make the width of the table when 100% include the scrollbar
- // - which is shouldn't. When there is a scrollbar we need to take this
- // into account.
- if ( ie67 && (table.find('tbody').height() > divBodyEl.offsetHeight ||
- divBody.css('overflow-y') == "scroll")
- ) {
- tableStyle.width = _fnStringToCss( table.outerWidth() - barWidth);
- }
-
- // Recalculate the sanity width
- sanityWidth = table.outerWidth();
- }
- else if ( scrollXInner !== "" ) {
- // legacy x scroll inner has been given - use it
- tableStyle.width = _fnStringToCss(scrollXInner);
-
- // Recalculate the sanity width
- sanityWidth = table.outerWidth();
+ footerCopy = footer.clone().prependTo( table );
+ footerCopy.find('[id]').removeAttr('id');
}
- // Hidden header should have zero height, so remove padding and borders. Then
- // set the width based on the real headers
-
- // Apply all styles in one pass
- _fnApplyToChildren( zeroOut, headerSrcEls );
-
- // Read all widths in next pass
- _fnApplyToChildren( function(nSizer) {
- var style = window.getComputedStyle ?
- window.getComputedStyle(nSizer).width :
- _fnStringToCss( $(nSizer).width() );
+ // 2. Correct colgroup > col values if needed
+ // It is possible that the cell sizes are smaller than the content, so we need to
+ // correct colgroup>col for such cases. This can happen if the auto width detection
+ // uses a cell which has a longer string, but isn't the widest! For example
+ // "Chief Executive Officer (CEO)" is the longest string in the demo, but
+ // "Systems Administrator" is actually the widest string since it doesn't collapse.
+ if (settings.aiDisplay.length) {
+ // Get the column sizes from the first row in the table
+ var colSizes = table.find('tbody tr').eq(0).find('th, td').map(function () {
+ return $(this).outerWidth();
+ });
- headerContent.push( nSizer.innerHTML );
- headerWidths.push( style );
- }, headerSrcEls );
+ // Check against what the colgroup > col is set to and correct if needed
+ $('col', settings.colgroup).each(function (i) {
+ var colWidth = this.style.width.replace('px', '');
- // Apply all widths in final pass
- _fnApplyToChildren( function(nToSize, i) {
- nToSize.style.width = headerWidths[i];
- }, headerTrgEls );
+ if (colWidth !== colSizes[i]) {
+ this.style.width = colSizes[i] + 'px';
+ }
+ });
+ }
- $(headerSrcEls).css('height', 0);
+ // 3. Copy the colgroup over to the header and footer
+ divHeaderTable
+ .find('colgroup')
+ .remove();
- /* Same again with the footer if we have one */
- if ( footer )
- {
- _fnApplyToChildren( zeroOut, footerSrcEls );
+ divHeaderTable.append(settings.colgroup.clone());
- _fnApplyToChildren( function(nSizer) {
- footerContent.push( nSizer.innerHTML );
- footerWidths.push( _fnStringToCss( $(nSizer).css('width') ) );
- }, footerSrcEls );
-
- _fnApplyToChildren( function(nToSize, i) {
- nToSize.style.width = footerWidths[i];
- }, footerTrgEls );
+ if ( footer ) {
+ divFooterTable
+ .find('colgroup')
+ .remove();
- $(footerSrcEls).height(0);
+ divFooterTable.append(settings.colgroup.clone());
}
-
- /*
- * 3. Apply the measurements
- */
-
// "Hide" the header and footer that we used for the sizing. We need to keep
// the content of the cell so that the width applied to the header and body
- // both match, but we want to hide it completely. We want to also fix their
- // width to what they currently are
- _fnApplyToChildren( function(nSizer, i) {
- nSizer.innerHTML = '<div class="dataTables_sizing">'+headerContent[i]+'</div>';
- nSizer.childNodes[0].style.height = "0";
- nSizer.childNodes[0].style.overflow = "hidden";
- nSizer.style.width = headerWidths[i];
- }, headerSrcEls );
-
- if ( footer )
- {
- _fnApplyToChildren( function(nSizer, i) {
- nSizer.innerHTML = '<div class="dataTables_sizing">'+footerContent[i]+'</div>';
- nSizer.childNodes[0].style.height = "0";
- nSizer.childNodes[0].style.overflow = "hidden";
- nSizer.style.width = footerWidths[i];
- }, footerSrcEls );
- }
-
- // Sanity check that the table is of a sensible width. If not then we are going to get
- // misalignment - try to prevent this by not allowing the table to shrink below its min width
- if ( Math.round(table.outerWidth()) < Math.round(sanityWidth) )
- {
- // The min width depends upon if we have a vertical scrollbar visible or not */
- correction = ((divBodyEl.scrollHeight > divBodyEl.offsetHeight ||
- divBody.css('overflow-y') == "scroll")) ?
- sanityWidth+barWidth :
- sanityWidth;
-
- // IE6/7 are a law unto themselves...
- if ( ie67 && (divBodyEl.scrollHeight >
- divBodyEl.offsetHeight || divBody.css('overflow-y') == "scroll")
- ) {
- tableStyle.width = _fnStringToCss( correction-barWidth );
- }
-
- // And give the user a warning that we've stopped the table getting too small
- if ( scrollX === "" || scrollXInner !== "" ) {
- _fnLog( settings, 1, 'Possible column misalignment', 6 );
- }
- }
- else
- {
- correction = '100%';
- }
-
- // Apply to the container elements
- divBodyStyle.width = _fnStringToCss( correction );
- divHeaderStyle.width = _fnStringToCss( correction );
+ // both match, but we want to hide it completely.
+ $('th, td', headerCopy).each(function () {
+ $(this).children().wrapAll('<div class="dt-scroll-sizing">');
+ });
if ( footer ) {
- settings.nScrollFoot.style.width = _fnStringToCss( correction );
- }
-
-
- /*
- * 4. Clean up
- */
- if ( ! scrollY ) {
- /* IE7< puts a vertical scrollbar in place (when it shouldn't be) due to subtracting
- * the scrollbar height from the visible display, rather than adding it on. We need to
- * set the height in order to sort this. Don't want to do it in any other browsers.
- */
- if ( ie67 ) {
- divBodyStyle.height = _fnStringToCss( tableEl.offsetHeight+barWidth );
- }
+ $('th, td', footerCopy).each(function () {
+ $(this).children().wrapAll('<div class="dt-scroll-sizing">');
+ });
}
- /* Finally set the width's of the header and footer tables */
- var iOuterWidth = table.outerWidth();
- divHeaderTable[0].style.width = _fnStringToCss( iOuterWidth );
- divHeaderInnerStyle.width = _fnStringToCss( iOuterWidth );
-
+ // 4. Clean up
// Figure out if there are scrollbar present - if so then we need a the header and footer to
// provide a bit more space to allow "overflow" scrolling (i.e. past the scrollbar)
- var bScrolling = table.height() > divBodyEl.clientHeight || divBody.css('overflow-y') == "scroll";
- var padding = 'padding' + (browser.bScrollbarLeft ? 'Left' : 'Right' );
- divHeaderInnerStyle[ padding ] = bScrolling ? barWidth+"px" : "0px";
+ var isScrolling = Math.floor(table.height()) > divBodyEl.clientHeight || divBody.css('overflow-y') == "scroll";
+ var paddingSide = 'padding' + (browser.bScrollbarLeft ? 'Left' : 'Right' );
+
+ // Set the width's of the header and footer tables
+ var outerWidth = table.outerWidth();
+
+ divHeaderTable.css('width', _fnStringToCss( outerWidth ));
+ divHeaderInner
+ .css('width', _fnStringToCss( outerWidth ))
+ .css(paddingSide, isScrolling ? barWidth+"px" : "0px");
if ( footer ) {
- divFooterTable[0].style.width = _fnStringToCss( iOuterWidth );
- divFooterInner[0].style.width = _fnStringToCss( iOuterWidth );
- divFooterInner[0].style[padding] = bScrolling ? barWidth+"px" : "0px";
+ divFooterTable.css('width', _fnStringToCss( outerWidth ));
+ divFooterInner
+ .css('width', _fnStringToCss( outerWidth ))
+ .css(paddingSide, isScrolling ? barWidth+"px" : "0px");
}
// Correct DOM ordering for colgroup - comes before the thead
- table.children('colgroup').insertBefore( table.children('thead') );
+ table.children('colgroup').prependTo(table);
- /* Adjust the position of the header in case we loose the y-scrollbar */
+ // Adjust the position of the header in case we loose the y-scrollbar
divBody.trigger('scroll');
// If sorting or filtering has occurred, jump the scrolling back to the top
@@ -5613,148 +5088,81 @@
}
}
-
-
/**
- * Apply a given function to the display child nodes of an element array (typically
- * TD children of TR rows
- * @param {function} fn Method to apply to the objects
- * @param array {nodes} an1 List of elements to look through for display children
- * @param array {nodes} an2 Another list (identical structure to the first) - optional
+ * Calculate the width of columns for the table
+ * @param {object} settings dataTables settings object
* @memberof DataTable#oApi
*/
- function _fnApplyToChildren( fn, an1, an2 )
+ function _fnCalculateColumnWidths ( settings )
{
- var index=0, i=0, iLen=an1.length;
- var nNode1, nNode2;
-
- while ( i < iLen ) {
- nNode1 = an1[i].firstChild;
- nNode2 = an2 ? an2[i].firstChild : null;
-
- while ( nNode1 ) {
- if ( nNode1.nodeType === 1 ) {
- if ( an2 ) {
- fn( nNode1, nNode2, index );
- }
- else {
- fn( nNode1, index );
- }
-
- index++;
- }
-
- nNode1 = nNode1.nextSibling;
- nNode2 = an2 ? nNode2.nextSibling : null;
- }
-
- i++;
+ // Not interested in doing column width calculation if auto-width is disabled
+ if (! settings.oFeatures.bAutoWidth) {
+ return;
}
- }
-
-
- var __re_html_remove = /<.*?>/g;
-
-
- /**
- * Calculate the width of columns for the table
- * @param {object} oSettings dataTables settings object
- * @memberof DataTable#oApi
- */
- function _fnCalculateColumnWidths ( oSettings )
- {
var
- table = oSettings.nTable,
- columns = oSettings.aoColumns,
- scroll = oSettings.oScroll,
+ table = settings.nTable,
+ columns = settings.aoColumns,
+ scroll = settings.oScroll,
scrollY = scroll.sY,
scrollX = scroll.sX,
scrollXInner = scroll.sXInner,
- columnCount = columns.length,
- visibleColumns = _fnGetColumns( oSettings, 'bVisible' ),
- headerCells = $('th', oSettings.nTHead),
+ visibleColumns = _fnGetColumns( settings, 'bVisible' ),
tableWidthAttr = table.getAttribute('width'), // from DOM element
tableContainer = table.parentNode,
- userInputs = false,
- i, column, columnIdx, width, outerWidth,
- browser = oSettings.oBrowser,
- ie67 = browser.bScrollOversize;
+ i, column, columnIdx;
var styleWidth = table.style.width;
if ( styleWidth && styleWidth.indexOf('%') !== -1 ) {
tableWidthAttr = styleWidth;
}
- /* Convert any user input sizes into pixel sizes */
- for ( i=0 ; i<visibleColumns.length ; i++ ) {
- column = columns[ visibleColumns[i] ];
+ // Let plug-ins know that we are doing a recalc, in case they have changed any of the
+ // visible columns their own way (e.g. Responsive uses display:none).
+ _fnCallbackFire(
+ settings,
+ null,
+ 'column-calc',
+ {visible: visibleColumns},
+ false
+ );
- if ( column.sWidth !== null ) {
- column.sWidth = _fnConvertToWidth( column.sWidthOrig, tableContainer );
+ // Construct a single row, worst case, table with the widest
+ // node in the data, assign any user defined widths, then insert it into
+ // the DOM and allow the browser to do all the hard work of calculating
+ // table widths
+ var tmpTable = $(table.cloneNode())
+ .css( 'visibility', 'hidden' )
+ .removeAttr( 'id' );
- userInputs = true;
- }
- }
+ // Clean up the table body
+ tmpTable.append('<tbody>')
+ var tr = $('<tr/>').appendTo( tmpTable.find('tbody') );
- /* If the number of columns in the DOM equals the number that we have to
- * process in DataTables, then we can use the offsets that are created by
- * the web- browser. No custom sizes can be set in order for this to happen,
- * nor scrolling used
- */
- if ( ie67 || ! userInputs && ! scrollX && ! scrollY &&
- columnCount == _fnVisbleColumns( oSettings ) &&
- columnCount == headerCells.length
- ) {
- for ( i=0 ; i<columnCount ; i++ ) {
- var colIdx = _fnVisibleToColumnIndex( oSettings, i );
+ // Clone the table header and footer - we can't use the header / footer
+ // from the cloned table, since if scrolling is active, the table's
+ // real header and footer are contained in different table tags
+ tmpTable
+ .append( $(settings.nTHead).clone() )
+ .append( $(settings.nTFoot).clone() );
- if ( colIdx !== null ) {
- columns[ colIdx ].sWidth = _fnStringToCss( headerCells.eq(i).width() );
- }
- }
- }
- else
- {
- // Otherwise construct a single row, worst case, table with the widest
- // node in the data, assign any user defined widths, then insert it into
- // the DOM and allow the browser to do all the hard work of calculating
- // table widths
- var tmpTable = $(table).clone() // don't use cloneNode - IE8 will remove events on the main table
- .css( 'visibility', 'hidden' )
- .removeAttr( 'id' );
-
- // Clean up the table body
- tmpTable.find('tbody tr').remove();
- var tr = $('<tr/>').appendTo( tmpTable.find('tbody') );
-
- // Clone the table header and footer - we can't use the header / footer
- // from the cloned table, since if scrolling is active, the table's
- // real header and footer are contained in different table tags
- tmpTable.find('thead, tfoot').remove();
- tmpTable
- .append( $(oSettings.nTHead).clone() )
- .append( $(oSettings.nTFoot).clone() );
-
- // Remove any assigned widths from the footer (from scrolling)
- tmpTable.find('tfoot th, tfoot td').css('width', '');
-
- // Apply custom sizing to the cloned header
- headerCells = _fnGetUniqueThs( oSettings, tmpTable.find('thead')[0] );
-
- for ( i=0 ; i<visibleColumns.length ; i++ ) {
- column = columns[ visibleColumns[i] ];
-
- headerCells[i].style.width = column.sWidthOrig !== null && column.sWidthOrig !== '' ?
- _fnStringToCss( column.sWidthOrig ) :
- '';
+ // Remove any assigned widths from the footer (from scrolling)
+ tmpTable.find('tfoot th, tfoot td').css('width', '');
+
+ // Apply custom sizing to the cloned header
+ tmpTable.find('thead th, thead td').each( function () {
+ // Get the `width` from the header layout
+ var width = _fnColumnsSumWidth( settings, this, true, false );
+
+ if ( width ) {
+ this.style.width = width;
// For scrollX we need to force the column width otherwise the
// browser will collapse it. If this width is smaller than the
// width the column requires, then it will have no effect
- if ( column.sWidthOrig && scrollX ) {
- $( headerCells[i] ).append( $('<div/>').css( {
- width: column.sWidthOrig,
+ if ( scrollX ) {
+ $( this ).append( $('<div/>').css( {
+ width: width,
margin: 0,
padding: 0,
border: 0,
@@ -5762,96 +5170,96 @@
} ) );
}
}
-
- // Find the widest cell for each column and put it into the table
- if ( oSettings.aoData.length ) {
- for ( i=0 ; i<visibleColumns.length ; i++ ) {
- columnIdx = visibleColumns[i];
- column = columns[ columnIdx ];
-
- $( _fnGetWidestNode( oSettings, columnIdx ) )
- .clone( false )
- .append( column.sContentPadding )
- .appendTo( tr );
- }
- }
-
- // Tidy the temporary table - remove name attributes so there aren't
- // duplicated in the dom (radio elements for example)
- $('[name]', tmpTable).removeAttr('name');
-
- // Table has been built, attach to the document so we can work with it.
- // A holding element is used, positioned at the top of the container
- // with minimal height, so it has no effect on if the container scrolls
- // or not. Otherwise it might trigger scrolling when it actually isn't
- // needed
- var holder = $('<div/>').css( scrollX || scrollY ?
- {
- position: 'absolute',
- top: 0,
- left: 0,
- height: 1,
- right: 0,
- overflow: 'hidden'
- } :
- {}
- )
- .append( tmpTable )
- .appendTo( tableContainer );
-
- // When scrolling (X or Y) we want to set the width of the table as
- // appropriate. However, when not scrolling leave the table width as it
- // is. This results in slightly different, but I think correct behaviour
- if ( scrollX && scrollXInner ) {
- tmpTable.width( scrollXInner );
+ else {
+ this.style.width = '';
}
- else if ( scrollX ) {
- tmpTable.css( 'width', 'auto' );
- tmpTable.removeAttr('width');
+ } );
- // If there is no width attribute or style, then allow the table to
- // collapse
- if ( tmpTable.width() < tableContainer.clientWidth && tableWidthAttr ) {
- tmpTable.width( tableContainer.clientWidth );
- }
- }
- else if ( scrollY ) {
+ // Find the widest piece of data for each column and put it into the table
+ for ( i=0 ; i<visibleColumns.length ; i++ ) {
+ columnIdx = visibleColumns[i];
+ column = columns[ columnIdx ];
+
+ var longest = _fnGetMaxLenString(settings, columnIdx);
+ var autoClass = _ext.type.className[column.sType];
+ var text = longest + column.sContentPadding;
+ var insert = longest.indexOf('<') === -1
+ ? document.createTextNode(text)
+ : text
+
+ $('<td/>')
+ .addClass(autoClass)
+ .addClass(column.sClass)
+ .append(insert)
+ .appendTo(tr);
+ }
+
+ // Tidy the temporary table - remove name attributes so there aren't
+ // duplicated in the dom (radio elements for example)
+ $('[name]', tmpTable).removeAttr('name');
+
+ // Table has been built, attach to the document so we can work with it.
+ // A holding element is used, positioned at the top of the container
+ // with minimal height, so it has no effect on if the container scrolls
+ // or not. Otherwise it might trigger scrolling when it actually isn't
+ // needed
+ var holder = $('<div/>').css( scrollX || scrollY ?
+ {
+ position: 'absolute',
+ top: 0,
+ left: 0,
+ height: 1,
+ right: 0,
+ overflow: 'hidden'
+ } :
+ {}
+ )
+ .append( tmpTable )
+ .appendTo( tableContainer );
+
+ // When scrolling (X or Y) we want to set the width of the table as
+ // appropriate. However, when not scrolling leave the table width as it
+ // is. This results in slightly different, but I think correct behaviour
+ if ( scrollX && scrollXInner ) {
+ tmpTable.width( scrollXInner );
+ }
+ else if ( scrollX ) {
+ tmpTable.css( 'width', 'auto' );
+ tmpTable.removeAttr('width');
+
+ // If there is no width attribute or style, then allow the table to
+ // collapse
+ if ( tmpTable.width() < tableContainer.clientWidth && tableWidthAttr ) {
tmpTable.width( tableContainer.clientWidth );
}
- else if ( tableWidthAttr ) {
- tmpTable.width( tableWidthAttr );
- }
+ }
+ else if ( scrollY ) {
+ tmpTable.width( tableContainer.clientWidth );
+ }
+ else if ( tableWidthAttr ) {
+ tmpTable.width( tableWidthAttr );
+ }
- // Get the width of each column in the constructed table - we need to
- // know the inner width (so it can be assigned to the other table's
- // cells) and the outer width so we can calculate the full width of the
- // table. This is safe since DataTables requires a unique cell for each
- // column, but if ever a header can span multiple columns, this will
- // need to be modified.
- var total = 0;
- for ( i=0 ; i<visibleColumns.length ; i++ ) {
- var cell = $(headerCells[i]);
- var border = cell.outerWidth() - cell.width();
+ // Get the width of each column in the constructed table
+ var total = 0;
+ var bodyCells = tmpTable.find('tbody tr').eq(0).children();
- // Use getBounding... where possible (not IE8-) because it can give
- // sub-pixel accuracy, which we then want to round up!
- var bounding = browser.bBounding ?
- Math.ceil( headerCells[i].getBoundingClientRect().width ) :
- cell.outerWidth();
+ for ( i=0 ; i<visibleColumns.length ; i++ ) {
+ // Use getBounding for sub-pixel accuracy, which we then want to round up!
+ var bounding = bodyCells[i].getBoundingClientRect().width;
- // Total is tracked to remove any sub-pixel errors as the outerWidth
- // of the table might not equal the total given here (IE!).
- total += bounding;
+ // Total is tracked to remove any sub-pixel errors as the outerWidth
+ // of the table might not equal the total given here
+ total += bounding;
- // Width for each column to use
- columns[ visibleColumns[i] ].sWidth = _fnStringToCss( bounding - border );
- }
+ // Width for each column to use
+ columns[ visibleColumns[i] ].sWidth = _fnStringToCss( bounding );
+ }
- table.style.width = _fnStringToCss( total );
+ table.style.width = _fnStringToCss( total );
- // Finished with the table - ditch it
- holder.remove();
- }
+ // Finished with the table - ditch it
+ holder.remove();
// If there is a width attr, we want to attach an event listener which
// allows the table sizing to automatically adjust when the window is
@@ -5861,80 +5269,19 @@
table.style.width = _fnStringToCss( tableWidthAttr );
}
- if ( (tableWidthAttr || scrollX) && ! oSettings._reszEvt ) {
+ if ( (tableWidthAttr || scrollX) && ! settings._reszEvt ) {
var bindResize = function () {
- $(window).on('resize.DT-'+oSettings.sInstance, _fnThrottle( function () {
- _fnAdjustColumnSizing( oSettings );
+ $(window).on('resize.DT-'+settings.sInstance, DataTable.util.throttle( function () {
+ if (! settings.bDestroying) {
+ _fnAdjustColumnSizing( settings );
+ }
} ) );
};
- // IE6/7 will crash if we bind a resize event handler on page load.
- // To be removed in 1.11 which drops IE6/7 support
- if ( ie67 ) {
- setTimeout( bindResize, 1000 );
- }
- else {
- bindResize();
- }
-
- oSettings._reszEvt = true;
- }
- }
-
-
- /**
- * Throttle the calls to a function. Arguments and context are maintained for
- * the throttled function
- * @param {function} fn Function to be called
- * @param {int} [freq=200] call frequency in mS
- * @returns {function} wrapped function
- * @memberof DataTable#oApi
- */
- var _fnThrottle = DataTable.util.throttle;
-
-
- /**
- * Convert a CSS unit width to pixels (e.g. 2em)
- * @param {string} width width to be converted
- * @param {node} parent parent to get the with for (required for relative widths) - optional
- * @returns {int} width in pixels
- * @memberof DataTable#oApi
- */
- function _fnConvertToWidth ( width, parent )
- {
- if ( ! width ) {
- return 0;
- }
-
- var n = $('<div/>')
- .css( 'width', _fnStringToCss( width ) )
- .appendTo( parent || document.body );
+ bindResize();
- var val = n[0].offsetWidth;
- n.remove();
-
- return val;
- }
-
-
- /**
- * Get the widest node
- * @param {object} settings dataTables settings object
- * @param {int} colIdx column of interest
- * @returns {node} widest table node
- * @memberof DataTable#oApi
- */
- function _fnGetWidestNode( settings, colIdx )
- {
- var idx = _fnGetMaxLenString( settings, colIdx );
- if ( idx < 0 ) {
- return null;
+ settings._reszEvt = true;
}
-
- var data = settings.aoData[ idx ];
- return ! data.nTr ? // Might not have been created when deferred rendering
- $('<td/>').html( _fnGetCellData( settings, idx, colIdx, 'display' ) )[0] :
- data.anCells[ colIdx ];
}
@@ -5942,25 +5289,45 @@
* Get the maximum strlen for each data column
* @param {object} settings dataTables settings object
* @param {int} colIdx column of interest
- * @returns {string} max string length for each column
+ * @returns {string} string of the max length
* @memberof DataTable#oApi
*/
function _fnGetMaxLenString( settings, colIdx )
{
- var s, max=-1, maxIdx = -1;
+ var column = settings.aoColumns[colIdx];
- for ( var i=0, ien=settings.aoData.length ; i<ien ; i++ ) {
- s = _fnGetCellData( settings, i, colIdx, 'display' )+'';
- s = s.replace( __re_html_remove, '' );
- s = s.replace( /&nbsp;/g, ' ' );
-
- if ( s.length > max ) {
- max = s.length;
- maxIdx = i;
+ if (! column.maxLenString) {
+ var s, max='', maxLen = -1;
+
+ for ( var i=0, ien=settings.aiDisplayMaster.length ; i<ien ; i++ ) {
+ var rowIdx = settings.aiDisplayMaster[i];
+ var data = _fnGetRowDisplay(settings, rowIdx)[colIdx];
+
+ var cellString = data && typeof data === 'object' && data.nodeType
+ ? data.innerHTML
+ : data+'';
+
+ // Remove id / name attributes from elements so they
+ // don't interfere with existing elements
+ cellString = cellString
+ .replace(/id=".*?"/g, '')
+ .replace(/name=".*?"/g, '');
+
+ s = _stripHtml(cellString)
+ .replace( /&nbsp;/g, ' ' );
+
+ if ( s.length > maxLen ) {
+ // We want the HTML in the string, but the length that
+ // is important is the stripped string
+ max = cellString;
+ maxLen = s.length;
+ }
}
+
+ column.maxLenString = max;
}
- return maxIdx;
+ return column.maxLenString;
}
@@ -5988,68 +5355,198 @@
s;
}
+ /**
+ * Re-insert the `col` elements for current visibility
+ *
+ * @param {*} settings DT settings
+ */
+ function _colGroup( settings ) {
+ var cols = settings.aoColumns;
+
+ settings.colgroup.empty();
+
+ for (i=0 ; i<cols.length ; i++) {
+ if (cols[i].bVisible) {
+ settings.colgroup.append(cols[i].colEl);
+ }
+ }
+ }
+
+
+ function _fnSortInit( settings ) {
+ var target = settings.nTHead;
+ var headerRows = target.querySelectorAll('tr');
+ var legacyTop = settings.bSortCellsTop;
+ var notSelector = ':not([data-dt-order="disable"]):not([data-dt-order="icon-only"])';
+
+ // Legacy support for `orderCellsTop`
+ if (legacyTop === true) {
+ target = headerRows[0];
+ }
+ else if (legacyTop === false) {
+ target = headerRows[ headerRows.length - 1 ];
+ }
+
+ _fnSortAttachListener(
+ settings,
+ target,
+ target === settings.nTHead
+ ? 'tr'+notSelector+' th'+notSelector+', tr'+notSelector+' td'+notSelector
+ : 'th'+notSelector+', td'+notSelector
+ );
+
+ // Need to resolve the user input array into our internal structure
+ var order = [];
+ _fnSortResolve( settings, order, settings.aaSorting );
+
+ settings.aaSorting = order;
+ }
+
+
+ function _fnSortAttachListener(settings, node, selector, column, callback) {
+ _fnBindAction( node, selector, function (e) {
+ var columns = column === undefined
+ ? _fnColumnsFromHeader( e.target )
+ : [column];
+
+ if ( columns.length ) {
+ _fnProcessingDisplay( settings, true );
+
+ // Allow the processing display to show
+ setTimeout( function () {
+ for ( var i=0, ien=columns.length ; i<ien ; i++ ) {
+ var append = e.shiftKey || i > 0;
+
+ _fnSortAdd( settings, columns[i], append );
+ }
+
+ _fnSort( settings );
+ _fnSortDisplay( settings );
+ _fnReDraw( settings, false, false );
+ _fnProcessingDisplay( settings, false );
+
+ if (callback) {
+ callback();
+ }
+ }, 0);
+ }
+ } );
+ }
+
+ /**
+ * Sort the display array to match the master's order
+ * @param {*} settings
+ */
+ function _fnSortDisplay(settings) {
+ var display = settings.aiDisplay;
+ var master = settings.aiDisplayMaster;
+
+ display.sort(function(a, b){
+ return master.indexOf(a) - master.indexOf(b);
+ });
+ }
+
+
+ function _fnSortResolve (settings, nestedSort, sort) {
+ var push = function ( a ) {
+ if ($.isPlainObject(a)) {
+ if (a.idx !== undefined) {
+ // Index based ordering
+ nestedSort.push([a.idx, a.dir]);
+ }
+ else if (a.name) {
+ // Name based ordering
+ var cols = _pluck( settings.aoColumns, 'sName');
+ var idx = cols.indexOf(a.name);
+
+ if (idx !== -1) {
+ nestedSort.push([idx, a.dir]);
+ }
+ }
+ }
+ else {
+ // Plain column index and direction pair
+ nestedSort.push(a);
+ }
+ };
+
+ if ( $.isPlainObject(sort) ) {
+ // Object
+ push(sort);
+ }
+ else if ( sort.length && typeof sort[0] === 'number' ) {
+ // 1D array
+ push(sort);
+ }
+ else if ( sort.length ) {
+ // 2D array
+ for (var z=0; z<sort.length; z++) {
+ push(sort[z]); // Object or array
+ }
+ }
+ }
function _fnSortFlatten ( settings )
{
var
- i, iLen, k, kLen,
+ i, k, kLen,
aSort = [],
- aiOrig = [],
+ extSort = DataTable.ext.type.order,
aoColumns = settings.aoColumns,
aDataSort, iCol, sType, srcCol,
fixed = settings.aaSortingFixed,
fixedObj = $.isPlainObject( fixed ),
- nestedSort = [],
- add = function ( a ) {
- if ( a.length && ! Array.isArray( a[0] ) ) {
- // 1D array
- nestedSort.push( a );
- }
- else {
- // 2D array
- $.merge( nestedSort, a );
- }
- };
+ nestedSort = [];
+
+ if ( ! settings.oFeatures.bSort ) {
+ return aSort;
+ }
// Build the sort array, with pre-fix and post-fix options if they have been
// specified
if ( Array.isArray( fixed ) ) {
- add( fixed );
+ _fnSortResolve( settings, nestedSort, fixed );
}
if ( fixedObj && fixed.pre ) {
- add( fixed.pre );
+ _fnSortResolve( settings, nestedSort, fixed.pre );
}
- add( settings.aaSorting );
+ _fnSortResolve( settings, nestedSort, settings.aaSorting );
if (fixedObj && fixed.post ) {
- add( fixed.post );
+ _fnSortResolve( settings, nestedSort, fixed.post );
}
for ( i=0 ; i<nestedSort.length ; i++ )
{
srcCol = nestedSort[i][0];
- aDataSort = aoColumns[ srcCol ].aDataSort;
- for ( k=0, kLen=aDataSort.length ; k<kLen ; k++ )
- {
- iCol = aDataSort[k];
- sType = aoColumns[ iCol ].sType || 'string';
+ if ( aoColumns[ srcCol ] ) {
+ aDataSort = aoColumns[ srcCol ].aDataSort;
- if ( nestedSort[i]._idx === undefined ) {
- nestedSort[i]._idx = $.inArray( nestedSort[i][1], aoColumns[iCol].asSorting );
- }
+ for ( k=0, kLen=aDataSort.length ; k<kLen ; k++ )
+ {
+ iCol = aDataSort[k];
+ sType = aoColumns[ iCol ].sType || 'string';
- aSort.push( {
- src: srcCol,
- col: iCol,
- dir: nestedSort[i][1],
- index: nestedSort[i]._idx,
- type: sType,
- formatter: DataTable.ext.type.order[ sType+"-pre" ]
- } );
+ if ( nestedSort[i]._idx === undefined ) {
+ nestedSort[i]._idx = aoColumns[iCol].asSorting.indexOf(nestedSort[i][1]);
+ }
+
+ if ( nestedSort[i][1] ) {
+ aSort.push( {
+ src: srcCol,
+ col: iCol,
+ dir: nestedSort[i][1],
+ index: nestedSort[i]._idx,
+ type: sType,
+ formatter: extSort[ sType+"-pre" ],
+ sorter: extSort[ sType+"-"+nestedSort[i][1] ]
+ } );
+ }
+ }
}
}
@@ -6060,19 +5557,14 @@
* Change the order of the table
* @param {object} oSettings dataTables settings object
* @memberof DataTable#oApi
- * @todo This really needs split up!
*/
- function _fnSort ( oSettings )
+ function _fnSort ( oSettings, col, dir )
{
var
- i, ien, iLen, j, jLen, k, kLen,
- sDataType, nTh,
+ i, ien, iLen,
aiOrig = [],
- oExtSort = DataTable.ext.type.order,
+ extSort = DataTable.ext.type.order,
aoData = oSettings.aoData,
- aoColumns = oSettings.aoColumns,
- aDataSort, data, iCol, sType, oSort,
- formatters = 0,
sortCol,
displayMaster = oSettings.aiDisplayMaster,
aSort;
@@ -6082,16 +5574,28 @@
// data is going to be used in the table?
_fnColumnTypes( oSettings );
- aSort = _fnSortFlatten( oSettings );
+ // Allow a specific column to be sorted, which will _not_ alter the display
+ // master
+ if (col !== undefined) {
+ var srcCol = oSettings.aoColumns[col];
+ aSort = [{
+ src: col,
+ col: col,
+ dir: dir,
+ index: 0,
+ type: srcCol.sType,
+ formatter: extSort[ srcCol.sType+"-pre" ],
+ sorter: extSort[ srcCol.sType+"-"+dir ]
+ }];
+ displayMaster = displayMaster.slice();
+ }
+ else {
+ aSort = _fnSortFlatten( oSettings );
+ }
for ( i=0, ien=aSort.length ; i<ien ; i++ ) {
sortCol = aSort[i];
- // Track if we can use the fast sort algorithm
- if ( sortCol.formatter ) {
- formatters++;
- }
-
// Load the data needed for the sort, for each cell
_fnSortData( oSettings, sortCol.col );
}
@@ -6099,137 +5603,88 @@
/* No sorting required if server-side or no sorting array */
if ( _fnDataSource( oSettings ) != 'ssp' && aSort.length !== 0 )
{
- // Create a value - key array of the current row positions such that we can use their
- // current position during the sort, if values match, in order to perform stable sorting
+ // Reset the initial positions on each pass so we get a stable sort
for ( i=0, iLen=displayMaster.length ; i<iLen ; i++ ) {
- aiOrig[ displayMaster[i] ] = i;
+ aiOrig[ i ] = i;
+ }
+
+ // If the first sort is desc, then reverse the array to preserve original
+ // order, just in reverse
+ if (aSort.length && aSort[0].dir === 'desc') {
+ aiOrig.reverse();
}
/* Do the sort - here we want multi-column sorting based on a given data source (column)
* and sorting function (from oSort) in a certain direction. It's reasonably complex to
* follow on it's own, but this is what we want (example two column sorting):
* fnLocalSorting = function(a,b){
- * var iTest;
- * iTest = oSort['string-asc']('data11', 'data12');
- * if (iTest !== 0)
- * return iTest;
- * iTest = oSort['numeric-desc']('data21', 'data22');
- * if (iTest !== 0)
- * return iTest;
+ * var test;
+ * test = oSort['string-asc']('data11', 'data12');
+ * if (test !== 0)
+ * return test;
+ * test = oSort['numeric-desc']('data21', 'data22');
+ * if (test !== 0)
+ * return test;
* return oSort['numeric-asc']( aiOrig[a], aiOrig[b] );
* }
* Basically we have a test for each sorting column, if the data in that column is equal,
* test the next column. If all columns match, then we use a numeric sort on the row
* positions in the original data array to provide a stable sort.
- *
- * Note - I know it seems excessive to have two sorting methods, but the first is around
- * 15% faster, so the second is only maintained for backwards compatibility with sorting
- * methods which do not have a pre-sort formatting function.
*/
- if ( formatters === aSort.length ) {
- // All sort types have formatting functions
- displayMaster.sort( function ( a, b ) {
- var
- x, y, k, test, sort,
- len=aSort.length,
- dataA = aoData[a]._aSortData,
- dataB = aoData[b]._aSortData;
+ displayMaster.sort( function ( a, b ) {
+ var
+ x, y, k, test, sort,
+ len=aSort.length,
+ dataA = aoData[a]._aSortData,
+ dataB = aoData[b]._aSortData;
- for ( k=0 ; k<len ; k++ ) {
- sort = aSort[k];
+ for ( k=0 ; k<len ; k++ ) {
+ sort = aSort[k];
- x = dataA[ sort.col ];
- y = dataB[ sort.col ];
+ // Data, which may have already been through a `-pre` function
+ x = dataA[ sort.col ];
+ y = dataB[ sort.col ];
+
+ if (sort.sorter) {
+ // If there is a custom sorter (`-asc` or `-desc`) for this
+ // data type, use it
+ test = sort.sorter(x, y);
- test = x<y ? -1 : x>y ? 1 : 0;
if ( test !== 0 ) {
- return sort.dir === 'asc' ? test : -test;
+ return test;
}
}
+ else {
+ // Otherwise, use generic sorting
+ test = x<y ? -1 : x>y ? 1 : 0;
- x = aiOrig[a];
- y = aiOrig[b];
- return x<y ? -1 : x>y ? 1 : 0;
- } );
- }
- else {
- // Depreciated - remove in 1.11 (providing a plug-in option)
- // Not all sort types have formatting methods, so we have to call their sorting
- // methods.
- displayMaster.sort( function ( a, b ) {
- var
- x, y, k, l, test, sort, fn,
- len=aSort.length,
- dataA = aoData[a]._aSortData,
- dataB = aoData[b]._aSortData;
-
- for ( k=0 ; k<len ; k++ ) {
- sort = aSort[k];
-
- x = dataA[ sort.col ];
- y = dataB[ sort.col ];
-
- fn = oExtSort[ sort.type+"-"+sort.dir ] || oExtSort[ "string-"+sort.dir ];
- test = fn( x, y );
if ( test !== 0 ) {
- return test;
+ return sort.dir === 'asc' ? test : -test;
}
}
+ }
- x = aiOrig[a];
- y = aiOrig[b];
- return x<y ? -1 : x>y ? 1 : 0;
- } );
- }
- }
-
- /* Tell the draw function that we have sorted the data */
- oSettings.bSorted = true;
- }
-
-
- function _fnSortAria ( settings )
- {
- var label;
- var nextSort;
- var columns = settings.aoColumns;
- var aSort = _fnSortFlatten( settings );
- var oAria = settings.oLanguage.oAria;
-
- // ARIA attributes - need to loop all columns, to update all (removing old
- // attributes as needed)
- for ( var i=0, iLen=columns.length ; i<iLen ; i++ )
- {
- var col = columns[i];
- var asSorting = col.asSorting;
- var sTitle = col.ariaTitle || col.sTitle.replace( /<.*?>/g, "" );
- var th = col.nTh;
-
- // IE7 is throwing an error when setting these properties with jQuery's
- // attr() and removeAttr() methods...
- th.removeAttribute('aria-sort');
+ x = aiOrig[a];
+ y = aiOrig[b];
- /* In ARIA only the first sorting column can be marked as sorting - no multi-sort option */
- if ( col.bSortable ) {
- if ( aSort.length > 0 && aSort[0].col == i ) {
- th.setAttribute('aria-sort', aSort[0].dir=="asc" ? "ascending" : "descending" );
- nextSort = asSorting[ aSort[0].index+1 ] || asSorting[0];
- }
- else {
- nextSort = asSorting[0];
- }
+ return x<y ? -1 : x>y ? 1 : 0;
+ } );
+ }
+ else if ( aSort.length === 0 ) {
+ // Apply index order
+ displayMaster.sort(function (x, y) {
+ return x<y ? -1 : x>y ? 1 : 0;
+ });
+ }
- label = sTitle + ( nextSort === "asc" ?
- oAria.sSortAscending :
- oAria.sSortDescending
- );
- }
- else {
- label = sTitle;
- }
+ if (col === undefined) {
+ // Tell the draw function that we have sorted the data
+ oSettings.bSorted = true;
- th.setAttribute('aria-label', label);
+ _fnCallbackFire( oSettings, null, 'order', [oSettings, aSort] );
}
+
+ return displayMaster;
}
@@ -6243,7 +5698,7 @@
* @param {function} [callback] callback function
* @memberof DataTable#oApi
*/
- function _fnSortListener ( settings, colIdx, append, callback )
+ function _fnSortAdd ( settings, colIdx, append )
{
var col = settings.aoColumns[ colIdx ];
var sorting = settings.aaSorting;
@@ -6252,7 +5707,7 @@
var next = function ( a, overflow ) {
var idx = a._idx;
if ( idx === undefined ) {
- idx = $.inArray( a[1], asSorting );
+ idx = asSorting.indexOf(a[1]);
}
return idx+1 < asSorting.length ?
@@ -6262,6 +5717,10 @@
0;
};
+ if ( ! col.bSortable ) {
+ return;
+ }
+
// Convert to 2D array if needed
if ( typeof sorting[0] === 'number' ) {
sorting = settings.aaSorting = [ sorting ];
@@ -6270,7 +5729,7 @@
// If appending the sort then we are multi-column sorting
if ( append && settings.oFeatures.bSortMulti ) {
// Are we already doing some kind of sort on this column?
- var sortIdx = $.inArray( colIdx, _pluck(sorting, '0') );
+ var sortIdx = _pluck(sorting, '0').indexOf(colIdx);
if ( sortIdx !== -1 ) {
// Yes, modify the sort
@@ -6308,54 +5767,6 @@
sorting.push( [ colIdx, asSorting[0] ] );
sorting[0]._idx = 0;
}
-
- // Run the sort by calling a full redraw
- _fnReDraw( settings );
-
- // callback used for async user interaction
- if ( typeof callback == 'function' ) {
- callback( settings );
- }
- }
-
-
- /**
- * Attach a sort handler (click) to a node
- * @param {object} settings dataTables settings object
- * @param {node} attachTo node to attach the handler to
- * @param {int} colIdx column sorting index
- * @param {function} [callback] callback function
- * @memberof DataTable#oApi
- */
- function _fnSortAttachListener ( settings, attachTo, colIdx, callback )
- {
- var col = settings.aoColumns[ colIdx ];
-
- _fnBindAction( attachTo, {}, function (e) {
- /* If the column is not sortable - don't to anything */
- if ( col.bSortable === false ) {
- return;
- }
-
- // If processing is enabled use a timeout to allow the processing
- // display to be shown - otherwise to it synchronously
- if ( settings.oFeatures.bProcessing ) {
- _fnProcessingDisplay( settings, true );
-
- setTimeout( function() {
- _fnSortListener( settings, colIdx, e.shiftKey, callback );
-
- // In server-side processing, the draw callback will remove the
- // processing display
- if ( _fnDataSource( settings ) !== 'ssp' ) {
- _fnProcessingDisplay( settings, false );
- }
- }, 0 );
- }
- else {
- _fnSortListener( settings, colIdx, e.shiftKey, callback );
- }
- } );
}
@@ -6368,7 +5779,7 @@
function _fnSortingClasses( settings )
{
var oldSort = settings.aLastSort;
- var sortClass = settings.oClasses.sSortColumn;
+ var sortClass = settings.oClasses.order.position;
var sort = _fnSortFlatten( settings );
var features = settings.oFeatures;
var i, ien, colIdx;
@@ -6398,48 +5809,54 @@
// Get the data to sort a column, be it from cache, fresh (populating the
// cache), or from a sort formatter
- function _fnSortData( settings, idx )
+ function _fnSortData( settings, colIdx )
{
// Custom sorting function - provided by the sort data type
- var column = settings.aoColumns[ idx ];
+ var column = settings.aoColumns[ colIdx ];
var customSort = DataTable.ext.order[ column.sSortDataType ];
var customData;
if ( customSort ) {
- customData = customSort.call( settings.oInstance, settings, idx,
- _fnColumnIndexToVisible( settings, idx )
+ customData = customSort.call( settings.oInstance, settings, colIdx,
+ _fnColumnIndexToVisible( settings, colIdx )
);
}
// Use / populate cache
var row, cellData;
var formatter = DataTable.ext.type.order[ column.sType+"-pre" ];
+ var data = settings.aoData;
+
+ for ( var rowIdx=0 ; rowIdx<data.length ; rowIdx++ ) {
+ // Sparse array
+ if (! data[rowIdx]) {
+ continue;
+ }
- for ( var i=0, ien=settings.aoData.length ; i<ien ; i++ ) {
- row = settings.aoData[i];
+ row = data[rowIdx];
if ( ! row._aSortData ) {
row._aSortData = [];
}
- if ( ! row._aSortData[idx] || customSort ) {
+ if ( ! row._aSortData[colIdx] || customSort ) {
cellData = customSort ?
- customData[i] : // If there was a custom sort function, use data from there
- _fnGetCellData( settings, i, idx, 'sort' );
+ customData[rowIdx] : // If there was a custom sort function, use data from there
+ _fnGetCellData( settings, rowIdx, colIdx, 'sort' );
- row._aSortData[ idx ] = formatter ?
- formatter( cellData ) :
+ row._aSortData[ colIdx ] = formatter ?
+ formatter( cellData, settings ) :
cellData;
}
}
}
-
/**
- * Save the state of a table
- * @param {object} oSettings dataTables settings object
- * @memberof DataTable#oApi
+ * State information for a table
+ *
+ * @param {*} settings
+ * @returns State object
*/
function _fnSaveState ( settings )
{
@@ -6453,11 +5870,11 @@
start: settings._iDisplayStart,
length: settings._iDisplayLength,
order: $.extend( true, [], settings.aaSorting ),
- search: _fnSearchToCamel( settings.oPreviousSearch ),
- columns: $.map( settings.aoColumns, function ( col, i ) {
+ search: $.extend({}, settings.oPreviousSearch),
+ columns: settings.aoColumns.map( function ( col, i ) {
return {
visible: col.bVisible,
- search: _fnSearchToCamel( settings.aoPreSearchCols[i] )
+ search: $.extend({}, settings.aoPreSearchCols[i])
};
} )
};
@@ -6479,7 +5896,7 @@
* @param {function} callback Callback to execute when the state has been loaded
* @memberof DataTable#oApi
*/
- function _fnLoadState ( settings, oInit, callback )
+ function _fnLoadState ( settings, init, callback )
{
if ( ! settings.oFeatures.bStateSave ) {
callback();
@@ -6515,18 +5932,18 @@
return;
}
- // Allow custom and plug-in manipulation functions to alter the saved data set and
- // cancelling of loading by returning false
- var abStateLoad = _fnCallbackFire( settings, 'aoStateLoadParams', 'stateLoadParams', [settings, s] );
- if ( $.inArray( false, abStateLoad ) !== -1 ) {
+ // Reject old data
+ var duration = settings.iStateDuration;
+ if ( duration > 0 && s.time < +new Date() - (duration*1000) ) {
settings._bLoadingState = false;
callback();
return;
}
- // Reject old data
- var duration = settings.iStateDuration;
- if ( duration > 0 && s.time < +new Date() - (duration*1000) ) {
+ // Allow custom and plug-in manipulation functions to alter the saved data set and
+ // cancelling of loading by returning false
+ var abStateLoad = _fnCallbackFire( settings, 'aoStateLoadParams', 'stateLoadParams', [settings, s] );
+ if ( abStateLoad.indexOf(false) !== -1 ) {
settings._bLoadingState = false;
callback();
return;
@@ -6542,6 +5959,10 @@
// Store the saved state so it might be accessed at any time
settings.oLoadedState = $.extend( true, {}, s );
+ // This is needed for ColReorder, which has to happen first to allow all
+ // the stored indexes to be usable. It is not publicly documented.
+ _fnCallbackFire( settings, null, 'stateLoadInit', [settings, s], true );
+
// Page Length
if ( s.length !== undefined ) {
// If already initialised just set the value directly so that the select element is also updated
@@ -6578,7 +5999,7 @@
// Search
if ( s.search !== undefined ) {
- $.extend( settings.oPreviousSearch, _fnSearchToHung( s.search ) );
+ $.extend( settings.oPreviousSearch, s.search );
}
// Columns
@@ -6600,7 +6021,7 @@
// Search
if ( col.search !== undefined ) {
- $.extend( settings.aoPreSearchCols[i], _fnSearchToHung( col.search ) );
+ $.extend( settings.aoPreSearchCols[i], col.search );
}
}
@@ -6613,26 +6034,8 @@
settings._bLoadingState = false;
_fnCallbackFire( settings, 'aoStateLoaded', 'stateLoaded', [settings, s] );
callback();
- };
-
-
- /**
- * Return the settings object for a particular table
- * @param {node} table table we are using as a dataTable
- * @returns {object} Settings object - or null if not found
- * @memberof DataTable#oApi
- */
- function _fnSettingsFromNode ( table )
- {
- var settings = DataTable.settings;
- var idx = $.inArray( table, _pluck( settings, 'nTable' ) );
-
- return idx !== -1 ?
- settings[ idx ] :
- null;
}
-
/**
* Log an error message
* @param {object} settings dataTables settings object
@@ -6648,7 +6051,7 @@
if ( tn ) {
msg += '. For more information about this error, please see '+
- 'http://datatables.net/tn/'+tn;
+ 'https://datatables.net/tn/'+tn;
}
if ( ! level ) {
@@ -6657,7 +6060,7 @@
var type = ext.sErrMode || ext.errMode;
if ( settings ) {
- _fnCallbackFire( settings, null, 'error', [ settings, tn, msg ] );
+ _fnCallbackFire( settings, null, 'dt-error', [ settings, tn, msg ], true );
}
if ( type == 'alert' ) {
@@ -6731,7 +6134,7 @@
var val;
for ( var prop in extender ) {
- if ( extender.hasOwnProperty(prop) ) {
+ if ( Object.prototype.hasOwnProperty.call(extender, prop) ) {
val = extender[prop];
if ( $.isPlainObject( val ) ) {
@@ -6758,47 +6161,42 @@
* This is good for accessibility since a return on the keyboard will have the
* same effect as a click, if the element has focus.
* @param {element} n Element to bind the action to
- * @param {object} oData Data object to pass to the triggered function
+ * @param {object|string} selector Selector (for delegated events) or data object
+ * to pass to the triggered function
* @param {function} fn Callback function for when the event is triggered
* @memberof DataTable#oApi
*/
- function _fnBindAction( n, oData, fn )
+ function _fnBindAction( n, selector, fn )
{
$(n)
- .on( 'click.DT', oData, function (e) {
- $(n).trigger('blur'); // Remove focus outline for mouse users
+ .on( 'click.DT', selector, function (e) {
+ fn(e);
+ } )
+ .on( 'keypress.DT', selector, function (e){
+ if ( e.which === 13 ) {
+ e.preventDefault();
fn(e);
- } )
- .on( 'keypress.DT', oData, function (e){
- if ( e.which === 13 ) {
- e.preventDefault();
- fn(e);
- }
- } )
- .on( 'selectstart.DT', function () {
- /* Take the brutal approach to cancelling text selection */
- return false;
- } );
+ }
+ } )
+ .on( 'selectstart.DT', selector, function () {
+ // Don't want a double click resulting in text selection
+ return false;
+ } );
}
/**
* Register a callback function. Easily allows a callback function to be added to
* an array store of callback functions that can then all be called together.
- * @param {object} oSettings dataTables settings object
- * @param {string} sStore Name of the array storage for the callbacks in oSettings
+ * @param {object} settings dataTables settings object
+ * @param {string} store Name of the array storage for the callbacks in oSettings
* @param {function} fn Function to be called back
- * @param {string} sName Identifying name for the callback (i.e. a label)
* @memberof DataTable#oApi
*/
- function _fnCallbackReg( oSettings, sStore, fn, sName )
+ function _fnCallbackReg( settings, store, fn )
{
- if ( fn )
- {
- oSettings[sStore].push( {
- "fn": fn,
- "sName": sName
- } );
+ if ( fn ) {
+ settings[store].push(fn);
}
}
@@ -6815,27 +6213,31 @@
* null no trigger is fired
* @param {array} args Array of arguments to pass to the callback function /
* trigger
+ * @param {boolean} [bubbles] True if the event should bubble
* @memberof DataTable#oApi
*/
- function _fnCallbackFire( settings, callbackArr, eventName, args )
+ function _fnCallbackFire( settings, callbackArr, eventName, args, bubbles )
{
var ret = [];
if ( callbackArr ) {
- ret = $.map( settings[callbackArr].slice().reverse(), function (val, i) {
- return val.fn.apply( settings.oInstance, args );
+ ret = settings[callbackArr].slice().reverse().map( function (val) {
+ return val.apply( settings.oInstance, args );
} );
}
- if ( eventName !== null ) {
+ if ( eventName !== null) {
var e = $.Event( eventName+'.dt' );
var table = $(settings.nTable);
+
+ // Expose the DataTables API on the event object for easy access
+ e.dt = settings.api;
- table.trigger( e, args );
+ table[bubbles ? 'trigger' : 'triggerHandler']( e, args );
// If not yet attached to the document, trigger the event
// on the body directly to sort of simulate the bubble
- if (table.parents('body').length === 0) {
+ if (bubbles && table.parents('body').length === 0) {
$('body').trigger( e, args );
}
@@ -6905,12 +6307,43 @@
if ( settings.oFeatures.bServerSide ) {
return 'ssp';
}
- else if ( settings.ajax || settings.sAjaxSource ) {
+ else if ( settings.ajax ) {
return 'ajax';
}
return 'dom';
}
+ /**
+ * Common replacement for language strings
+ *
+ * @param {*} settings DT settings object
+ * @param {*} str String with values to replace
+ * @param {*} entries Plural number for _ENTRIES_ - can be undefined
+ * @returns String
+ */
+ function _fnMacros ( settings, str, entries )
+ {
+ // When infinite scrolling, we are always starting at 1. _iDisplayStart is
+ // used only internally
+ var
+ formatter = settings.fnFormatNumber,
+ start = settings._iDisplayStart+1,
+ len = settings._iDisplayLength,
+ vis = settings.fnRecordsDisplay(),
+ max = settings.fnRecordsTotal(),
+ all = len === -1;
+
+ return str.
+ replace(/_START_/g, formatter.call( settings, start ) ).
+ replace(/_END_/g, formatter.call( settings, settings.fnDisplayEnd() ) ).
+ replace(/_MAX_/g, formatter.call( settings, max ) ).
+ replace(/_TOTAL_/g, formatter.call( settings, vis ) ).
+ replace(/_PAGE_/g, formatter.call( settings, all ? 1 : Math.ceil( start / len ) ) ).
+ replace(/_PAGES_/g, formatter.call( settings, all ? 1 : Math.ceil( vis / len ) ) ).
+ replace(/_ENTRIES_/g, settings.api.i18n('entries', '', entries) ).
+ replace(/_ENTRIES-MAX_/g, settings.api.i18n('entries', '', max) ).
+ replace(/_ENTRIES-TOTAL_/g, settings.api.i18n('entries', '', vis) );
+ }
@@ -6986,20 +6419,18 @@
{
var idx, jq;
var settings = DataTable.settings;
- var tables = $.map( settings, function (el, i) {
- return el.nTable;
- } );
+ var tables = _pluck(settings, 'nTable');
if ( ! mixed ) {
return [];
}
- else if ( mixed.nTable && mixed.oApi ) {
+ else if ( mixed.nTable && mixed.oFeatures ) {
// DataTables settings object
return [ mixed ];
}
else if ( mixed.nodeName && mixed.nodeName.toLowerCase() === 'table' ) {
// Table node
- idx = $.inArray( mixed, tables );
+ idx = tables.indexOf(mixed);
return idx !== -1 ? [ settings[idx] ] : null;
}
else if ( mixed && typeof mixed.settings === 'function' ) {
@@ -7007,18 +6438,17 @@
}
else if ( typeof mixed === 'string' ) {
// jQuery selector
- jq = $(mixed);
+ jq = $(mixed).get();
}
else if ( mixed instanceof $ ) {
// jQuery object (also DataTables instance)
- jq = mixed;
+ jq = mixed.get();
}
if ( jq ) {
- return jq.map( function(i) {
- idx = $.inArray( this, tables );
- return idx !== -1 ? settings[idx] : null;
- } ).toArray();
+ return settings.filter(function (v, idx) {
+ return jq.includes(tables[idx]);
+ });
}
};
@@ -7075,7 +6505,7 @@
*
* @example
* // Initialisation as a constructor
- * var api = new $.fn.DataTable.Api( 'table.dataTable' );
+ * var api = new DataTable.Api( 'table.dataTable' );
*/
_Api = function ( context, data )
{
@@ -7101,11 +6531,13 @@
}
// Remove duplicates
- this.context = _unique( settings );
+ this.context = settings.length > 1
+ ? _unique( settings )
+ : settings;
// Initial data
if ( data ) {
- $.merge( this, data );
+ this.push.apply(this, data);
}
// selector
@@ -7128,19 +6560,13 @@
return this.count() !== 0;
},
-
- concat: __arrayProto.concat,
-
-
context: [], // array of table settings objects
-
count: function ()
{
return this.flatten().length;
},
-
each: function ( fn )
{
for ( var i=0, ien=this.length ; i<ien; i++ ) {
@@ -7150,7 +6576,6 @@
return this;
},
-
eq: function ( idx )
{
var ctx = this.context;
@@ -7160,47 +6585,33 @@
null;
},
-
filter: function ( fn )
{
- var a = [];
-
- if ( __arrayProto.filter ) {
- a = __arrayProto.filter.call( this, fn, this );
- }
- else {
- // Compatibility for browsers without EMCA-252-5 (JS 1.6)
- for ( var i=0, ien=this.length ; i<ien ; i++ ) {
- if ( fn.call( this, this[i], i, this ) ) {
- a.push( this[i] );
- }
- }
- }
+ var a = __arrayProto.filter.call( this, fn, this );
return new _Api( this.context, a );
},
-
flatten: function ()
{
var a = [];
+
return new _Api( this.context, a.concat.apply( a, this.toArray() ) );
},
+ get: function ( idx )
+ {
+ return this[ idx ];
+ },
join: __arrayProto.join,
-
- indexOf: __arrayProto.indexOf || function (obj, start)
- {
- for ( var i=(start || 0), ien=this.length ; i<ien ; i++ ) {
- if ( this[i] === obj ) {
- return i;
- }
- }
- return -1;
+ includes: function ( find ) {
+ return this.indexOf( find ) === -1 ? false : true;
},
+ indexOf: __arrayProto.indexOf,
+
iterator: function ( flatten, type, fn, alwaysNew ) {
var
a = [], ret,
@@ -7235,7 +6646,7 @@
a.push( ret );
}
}
- else if ( type === 'column' || type === 'column-rows' || type === 'row' || type === 'cell' ) {
+ else if ( type === 'every' || type === 'column' || type === 'column-rows' || type === 'row' || type === 'cell' ) {
// columns and rows share the same structure.
// 'this' is an array of column indexes for each context
items = this[i];
@@ -7272,35 +6683,17 @@
return this;
},
-
- lastIndexOf: __arrayProto.lastIndexOf || function (obj, start)
- {
- // Bit cheeky...
- return this.indexOf.apply( this.toArray.reverse(), arguments );
- },
-
+ lastIndexOf: __arrayProto.lastIndexOf,
length: 0,
-
map: function ( fn )
{
- var a = [];
-
- if ( __arrayProto.map ) {
- a = __arrayProto.map.call( this, fn, this );
- }
- else {
- // Compatibility for browsers without EMCA-252-5 (JS 1.6)
- for ( var i=0, ien=this.length ; i<ien ; i++ ) {
- a.push( fn.call( this, this[i], i ) );
- }
- }
+ var a = __arrayProto.map.call( this, fn, this );
return new _Api( this.context, a );
},
-
pluck: function ( prop )
{
var fn = DataTable.util.get(prop);
@@ -7312,72 +6705,72 @@
pop: __arrayProto.pop,
-
push: __arrayProto.push,
+ reduce: __arrayProto.reduce,
- // Does not return an API instance
- reduce: __arrayProto.reduce || function ( fn, init )
- {
- return _fnReduce( this, fn, init, 0, this.length, 1 );
- },
-
-
- reduceRight: __arrayProto.reduceRight || function ( fn, init )
- {
- return _fnReduce( this, fn, init, this.length-1, -1, -1 );
- },
-
+ reduceRight: __arrayProto.reduceRight,
reverse: __arrayProto.reverse,
-
// Object with rows, columns and opts
selector: null,
-
shift: __arrayProto.shift,
-
slice: function () {
return new _Api( this.context, this );
},
-
- sort: __arrayProto.sort, // ? name - order?
-
+ sort: __arrayProto.sort,
splice: __arrayProto.splice,
-
toArray: function ()
{
return __arrayProto.slice.call( this );
},
-
to$: function ()
{
return $( this );
},
-
toJQuery: function ()
{
return $( this );
},
-
unique: function ()
{
- return new _Api( this.context, _unique(this) );
+ return new _Api( this.context, _unique(this.toArray()) );
},
-
unshift: __arrayProto.unshift
} );
+ function _api_scope( scope, fn, struc ) {
+ return function () {
+ var ret = fn.apply( scope || this, arguments );
+
+ // Method extension
+ _Api.extend( ret, ret, struc.methodExt );
+ return ret;
+ };
+ }
+
+ function _api_find( src, name ) {
+ for ( var i=0, ien=src.length ; i<ien ; i++ ) {
+ if ( src[i].name === name ) {
+ return src[i];
+ }
+ }
+ return null;
+ }
+
+ window.__apiStruct = __apiStruct;
+
_Api.extend = function ( scope, obj, ext )
{
// Only extend API instances and static properties of the API
@@ -7387,23 +6780,14 @@
var
i, ien,
- struct,
- methodScoping = function ( scope, fn, struc ) {
- return function () {
- var ret = fn.apply( scope, arguments );
-
- // Method extension
- _Api.extend( ret, ret, struc.methodExt );
- return ret;
- };
- };
+ struct;
for ( i=0, ien=ext.length ; i<ien ; i++ ) {
struct = ext[i];
// Value
obj[ struct.name ] = struct.type === 'function' ?
- methodScoping( scope, struct.val, struct ) :
+ _api_scope( scope, struct.val, struct ) :
struct.type === 'object' ?
{} :
struct.val;
@@ -7415,17 +6799,6 @@
}
};
-
- // @todo - Is there need for an augment function?
- // _Api.augment = function ( inst, name )
- // {
- // // Find src object in the structure from the name
- // var parts = name.split('.');
-
- // _Api.extend( inst, obj );
- // };
-
-
// [
// {
// name: 'data' -- string - Property name
@@ -7449,6 +6822,7 @@
// }
// ]
+
_Api.register = _api_register = function ( name, val )
{
if ( Array.isArray( name ) ) {
@@ -7464,22 +6838,13 @@
struct = __apiStruct,
key, method;
- var find = function ( src, name ) {
- for ( var i=0, ien=src.length ; i<ien ; i++ ) {
- if ( src[i].name === name ) {
- return src[i];
- }
- }
- return null;
- };
-
for ( i=0, ien=heir.length ; i<ien ; i++ ) {
method = heir[i].indexOf('()') !== -1;
key = method ?
heir[i].replace('()', '') :
heir[i];
- var src = find( struct, key );
+ var src = _api_find( struct, key );
if ( ! src ) {
src = {
name: key,
@@ -7545,9 +6910,17 @@
var __table_selector = function ( selector, a )
{
if ( Array.isArray(selector) ) {
- return $.map( selector, function (item) {
- return __table_selector(item, a);
- } );
+ var result = [];
+
+ selector.forEach(function (sel) {
+ var inner = __table_selector(sel, a);
+
+ result.push.apply(result, inner);
+ });
+
+ return result.filter( function (item) {
+ return item;
+ });
}
// Integer is used to pick out a table by index
@@ -7556,15 +6929,15 @@
}
// Perform a jQuery selector on the table nodes
- var nodes = $.map( a, function (el, i) {
+ var nodes = a.map( function (el) {
return el.nTable;
} );
return $(nodes)
.filter( selector )
- .map( function (i) {
+ .map( function () {
// Need to translate back from the table node to the settings
- var idx = $.inArray( this, nodes );
+ var idx = nodes.indexOf(this);
return a[ idx ];
} )
.toArray();
@@ -7601,41 +6974,107 @@
tables;
} );
+ // Common methods, combined to reduce size
+ [
+ ['nodes', 'node', 'nTable'],
+ ['body', 'body', 'nTBody'],
+ ['header', 'header', 'nTHead'],
+ ['footer', 'footer', 'nTFoot'],
+ ].forEach(function (item) {
+ _api_registerPlural(
+ 'tables().' + item[0] + '()',
+ 'table().' + item[1] + '()' ,
+ function () {
+ return this.iterator( 'table', function ( ctx ) {
+ return ctx[item[2]];
+ }, 1 );
+ }
+ );
+ });
- _api_registerPlural( 'tables().nodes()', 'table().node()' , function () {
- return this.iterator( 'table', function ( ctx ) {
- return ctx.nTable;
- }, 1 );
- } );
+ // Structure methods
+ [
+ ['header', 'aoHeader'],
+ ['footer', 'aoFooter'],
+ ].forEach(function (item) {
+ _api_register( 'table().' + item[0] + '.structure()' , function (selector) {
+ var indexes = this.columns(selector).indexes().flatten();
+ var ctx = this.context[0];
+
+ return _fnHeaderLayout(ctx, ctx[item[1]], indexes);
+ } );
+ })
- _api_registerPlural( 'tables().body()', 'table().body()' , function () {
+ _api_registerPlural( 'tables().containers()', 'table().container()' , function () {
return this.iterator( 'table', function ( ctx ) {
- return ctx.nTBody;
+ return ctx.nTableWrapper;
}, 1 );
} );
+ _api_register( 'tables().every()', function ( fn ) {
+ var that = this;
- _api_registerPlural( 'tables().header()', 'table().header()' , function () {
- return this.iterator( 'table', function ( ctx ) {
- return ctx.nTHead;
- }, 1 );
- } );
+ return this.iterator('table', function (s, i) {
+ fn.call(that.table(i), i);
+ });
+ });
+ _api_register( 'caption()', function ( value, side ) {
+ var context = this.context;
- _api_registerPlural( 'tables().footer()', 'table().footer()' , function () {
- return this.iterator( 'table', function ( ctx ) {
- return ctx.nTFoot;
- }, 1 );
- } );
+ // Getter - return existing node's content
+ if ( value === undefined ) {
+ var caption = context[0].captionNode;
+ return caption && context.length ?
+ caption.innerHTML :
+ null;
+ }
- _api_registerPlural( 'tables().containers()', 'table().container()' , function () {
return this.iterator( 'table', function ( ctx ) {
- return ctx.nTableWrapper;
+ var table = $(ctx.nTable);
+ var caption = $(ctx.captionNode);
+ var container = $(ctx.nTableWrapper);
+
+ // Create the node if it doesn't exist yet
+ if ( ! caption.length ) {
+ caption = $('<caption/>').html( value );
+ ctx.captionNode = caption[0];
+
+ // If side isn't set, we need to insert into the document to let the
+ // CSS decide so we can read it back, otherwise there is no way to
+ // know if the CSS would put it top or bottom for scrolling
+ if (! side) {
+ table.prepend(caption);
+
+ side = caption.css('caption-side');
+ }
+ }
+
+ caption.html( value );
+
+ if ( side ) {
+ caption.css( 'caption-side', side );
+ caption[0]._captionSide = side;
+ }
+
+ if (container.find('div.dataTables_scroll').length) {
+ var selector = (side === 'top' ? 'Head' : 'Foot');
+
+ container.find('div.dataTables_scroll'+ selector +' table').prepend(caption);
+ }
+ else {
+ table.prepend(caption);
+ }
}, 1 );
} );
+ _api_register( 'caption.node()', function () {
+ var ctx = this.context;
+
+ return ctx.length ? ctx[0].captionNode : null;
+ } );
/**
@@ -7709,7 +7148,7 @@
* * `recordsDisplay` - Data set length once the current filtering criterion
* are applied.
*/
- _api_register( 'page.info()', function ( action ) {
+ _api_register( 'page.info()', function () {
if ( this.context.length === 0 ) {
return undefined;
}
@@ -7786,7 +7225,7 @@
}
// Trigger xhr
- _fnBuildAjax( settings, [], function( json ) {
+ _fnBuildAjax( settings, {}, function( json ) {
_fnClearTable( settings );
var data = _fnAjaxDataSrc( settings, json );
@@ -7795,6 +7234,7 @@
}
_fnReDraw( settings, holdPosition );
+ _fnInitComplete( settings );
_fnProcessingDisplay( settings, false );
} );
}
@@ -7871,11 +7311,9 @@
}
ctx = ctx[0];
- return ctx.ajax ?
- $.isPlainObject( ctx.ajax ) ?
- ctx.ajax.url :
- ctx.ajax :
- ctx.sAjaxSource;
+ return $.isPlainObject( ctx.ajax ) ?
+ ctx.ajax.url :
+ ctx.ajax;
}
// set
@@ -7886,9 +7324,6 @@
else {
settings.ajax = url;
}
- // No need to consider sAjaxSource here since DataTables gives priority
- // to `ajax` over `sAjaxSource`. So setting `ajax` here, renders any
- // value of `sAjaxSource` redundant.
} );
} );
@@ -7928,13 +7363,18 @@
for ( i=0, ien=selector.length ; i<ien ; i++ ) {
// Only split on simple strings - complex expressions will be jQuery selectors
- a = selector[i] && selector[i].split && ! selector[i].match(/[\[\(:]/) ?
+ a = selector[i] && selector[i].split && ! selector[i].match(/[[(:]/) ?
selector[i].split(',') :
[ selector[i] ];
for ( j=0, jen=a.length ; j<jen ; j++ ) {
res = selectFn( typeof a[j] === 'string' ? (a[j]).trim() : a[j] );
+ // Remove empty items
+ res = res.filter( function (item) {
+ return item !== null && item !== undefined;
+ });
+
if ( res && res.length ) {
out = out.concat( res );
}
@@ -7973,24 +7413,24 @@
};
- var _selector_first = function ( inst )
+ // Reduce the API instance to the first item found
+ var _selector_first = function ( old )
{
- // Reduce the API instance to the first item found
- for ( var i=0, ien=inst.length ; i<ien ; i++ ) {
- if ( inst[i].length > 0 ) {
- // Assign the first element to the first item in the instance
- // and truncate the instance and context
- inst[0] = inst[i];
- inst[0].length = 1;
- inst.length = 1;
- inst.context = [ inst.context[i] ];
+ let inst = new _Api(old.context[0]);
- return inst;
- }
+ // Use a push rather than passing to the constructor, since it will
+ // merge arrays down automatically, which isn't what is wanted here
+ if (old.length) {
+ inst.push( old[0] );
+ }
+
+ inst.selector = old.selector;
+
+ // Limit to a single row / column / cell
+ if (inst.length && inst[0].length > 1) {
+ inst[0].splice(1);
}
- // Not found - return an empty instance
- inst.length = 0;
return inst;
};
@@ -8035,24 +7475,28 @@
// O(n+m) solution by creating a hash map
var displayFilteredMap = {};
- for ( var i=0, ien=displayFiltered.length ; i<ien ; i++ ) {
+ for ( i=0, ien=displayFiltered.length ; i<ien ; i++ ) {
displayFilteredMap[displayFiltered[i]] = null;
}
- a = $.map( displayMaster, function (el) {
- return ! displayFilteredMap.hasOwnProperty(el) ?
- el :
- null;
- } );
+ displayMaster.forEach(function (item) {
+ if (! Object.prototype.hasOwnProperty.call(displayFilteredMap, item)) {
+ a.push(item);
+ }
+ });
}
}
else if ( order == 'index' || order == 'original' ) {
for ( i=0, ien=settings.aoData.length ; i<ien ; i++ ) {
+ if (! settings.aoData[i]) {
+ continue;
+ }
+
if ( search == 'none' ) {
a.push( i );
}
else { // applied | removed
- tmp = $.inArray( i, displayFiltered );
+ tmp = displayFiltered.indexOf(i);
if ((tmp === -1 && search == 'removed') ||
(tmp >= 0 && search == 'applied') )
@@ -8062,6 +7506,25 @@
}
}
}
+ else if ( typeof order === 'number' ) {
+ // Order the rows by the given column
+ var ordered = _fnSort(settings, order, 'asc');
+
+ if (search === 'none') {
+ a = ordered;
+ }
+ else { // applied | removed
+ for (i=0; i<ordered.length; i++) {
+ tmp = displayFiltered.indexOf(ordered[i]);
+
+ if ((tmp === -1 && search == 'removed') ||
+ (tmp >= 0 && search == 'applied') )
+ {
+ a.push( ordered[i] );
+ }
+ }
+ }
+ }
return a;
};
@@ -8082,7 +7545,6 @@
var rows;
var run = function ( sel ) {
var selInt = _intVal( sel );
- var i, ien;
var aoData = settings.aoData;
// Short cut - selector is a number and no options provided (default is
@@ -8096,7 +7558,7 @@
rows = _selector_row_indexes( settings, opts );
}
- if ( selInt !== null && $.inArray( selInt, rows ) !== -1 ) {
+ if ( selInt !== null && rows.indexOf(selInt) !== -1 ) {
// Selector - integer
return [ selInt ];
}
@@ -8107,7 +7569,7 @@
// Selector - function
if ( typeof sel === 'function' ) {
- return $.map( rows, function (idx) {
+ return rows.map( function (idx) {
var row = aoData[ idx ];
return sel( idx, row._aData, row.nTr ) ? idx : null;
} );
@@ -8173,7 +7635,17 @@
.toArray();
};
- return _selector_run( 'row', selector, run, settings, opts );
+ var matched = _selector_run( 'row', selector, run, settings, opts );
+
+ if (opts.order === 'current' || opts.order === 'applied') {
+ var master = settings.aiDisplayMaster;
+
+ matched.sort(function(a, b) {
+ return master.indexOf(a) - master.indexOf(b);
+ });
+ }
+
+ return matched;
};
@@ -8247,38 +7719,20 @@
} );
_api_registerPlural( 'rows().remove()', 'row().remove()', function () {
- var that = this;
-
- this.iterator( 'row', function ( settings, row, thatIdx ) {
+ this.iterator( 'row', function ( settings, row ) {
var data = settings.aoData;
var rowData = data[ row ];
- var i, ien, j, jen;
- var loopRow, loopCells;
-
- data.splice( row, 1 );
-
- // Update the cached indexes
- for ( i=0, ien=data.length ; i<ien ; i++ ) {
- loopRow = data[i];
- loopCells = loopRow.anCells;
-
- // Rows
- if ( loopRow.nTr !== null ) {
- loopRow.nTr._DT_RowIndex = i;
- }
- // Cells
- if ( loopCells !== null ) {
- for ( j=0, jen=loopCells.length ; j<jen ; j++ ) {
- loopCells[j]._DT_CellIndex.row = i;
- }
- }
+ // Delete from the display arrays
+ var idx = settings.aiDisplayMaster.indexOf(row);
+ if (idx !== -1) {
+ settings.aiDisplayMaster.splice(idx, 1);
}
- // Delete from the display arrays
- _fnDeleteIndex( settings.aiDisplayMaster, row );
- _fnDeleteIndex( settings.aiDisplay, row );
- _fnDeleteIndex( that[ thatIdx ], row, false ); // maintain local indexes
+ idx = settings.aiDisplay.indexOf(row);
+ if (idx !== -1) {
+ settings.aiDisplay.splice(idx, 1);
+ }
// For server-side processing tables - subtract the deleted row from the count
if ( settings._iRecordsDisplay > 0 ) {
@@ -8293,12 +7747,8 @@
if ( id !== undefined ) {
delete settings.aIds[ id ];
}
- } );
- this.iterator( 'table', function ( settings ) {
- for ( var i=0, ien=settings.aoData.length ; i<ien ; i++ ) {
- settings.aoData[i].idx = i;
- }
+ data[row] = null;
} );
return this;
@@ -8327,7 +7777,7 @@
// Return an Api.rows() extended instance, so rows().nodes() etc can be used
var modRows = this.rows( -1 );
modRows.pop();
- $.merge( modRows, newRows );
+ modRows.push.apply(modRows, newRows);
return modRows;
} );
@@ -8349,7 +7799,7 @@
if ( data === undefined ) {
// Get
- return ctx.length && this.length ?
+ return ctx.length && this.length && this[0].length ?
ctx[0].aoData[ this[0] ]._aData :
undefined;
}
@@ -8373,7 +7823,7 @@
_api_register( 'row().node()', function () {
var ctx = this.context;
- return ctx.length && this.length ?
+ return ctx.length && this.length && this[0].length ?
ctx[0].aoData[ this[0] ].nTr || null :
null;
} );
@@ -8400,42 +7850,47 @@
$(document).on('plugin-init.dt', function (e, context) {
var api = new _Api( context );
- var namespace = 'on-plugin-init';
- var stateSaveParamsEvent = 'stateSaveParams.' + namespace;
- var destroyEvent = 'destroy. ' + namespace;
- api.on( stateSaveParamsEvent, function ( e, settings, d ) {
+ api.on( 'stateSaveParams.DT', function ( e, settings, d ) {
// This could be more compact with the API, but it is a lot faster as a simple
// internal loop
var idFn = settings.rowIdFn;
- var data = settings.aoData;
+ var rows = settings.aiDisplayMaster;
var ids = [];
- for (var i=0 ; i<data.length ; i++) {
- if (data[i]._detailsShow) {
- ids.push( '#' + idFn(data[i]._aData) );
+ for (var i=0 ; i<rows.length ; i++) {
+ var rowIdx = rows[i];
+ var data = settings.aoData[rowIdx];
+
+ if (data._detailsShow) {
+ ids.push( '#' + idFn(data._aData) );
}
}
d.childRows = ids;
});
- api.on( destroyEvent, function () {
- api.off(stateSaveParamsEvent + ' ' + destroyEvent);
+ // For future state loads (e.g. with StateRestore)
+ api.on( 'stateLoaded.DT', function (e, settings, state) {
+ __details_state_load( api, state );
});
- var loaded = api.state.loaded();
+ // And the initial load state
+ __details_state_load( api, api.state.loaded() );
+ });
- if ( loaded && loaded.childRows ) {
+ var __details_state_load = function (api, state)
+ {
+ if ( state && state.childRows ) {
api
- .rows( $.map(loaded.childRows, function (id){
+ .rows( state.childRows.map(function (id){
return id.replace(/:/g, '\\:')
}) )
.every( function () {
- _fnCallbackFire( context, null, 'requestChild', [ this ] )
+ _fnCallbackFire( api.settings()[0], null, 'requestChild', [ this ] )
});
}
- });
+ }
var __details_add = function ( ctx, row, data, klass )
{
@@ -8453,15 +7908,18 @@
// If we get a TR element, then just add it directly - up to the dev
// to add the correct number of columns etc
if ( r.nodeName && r.nodeName.toLowerCase() === 'tr' ) {
+ r.setAttribute( 'data-dt-row', row.idx );
rows.push( r );
}
else {
// Otherwise create a row with a wrapper
- var created = $('<tr><td></td></tr>').addClass( k );
+ var created = $('<tr><td></td></tr>')
+ .attr( 'data-dt-row', row.idx )
+ .addClass( k );
+
$('td', created)
.addClass( k )
- .html( r )
- [0].colSpan = _fnVisbleColumns( ctx );
+ .html( r )[0].colSpan = _fnVisbleColumns( ctx );
rows.push( created[0] );
}
@@ -8566,7 +8024,7 @@
} );
// Column visibility change - update the colspan
- api.on( colvisEvent, function ( e, ctx, idx, vis ) {
+ api.on( colvisEvent, function ( e, ctx ) {
if ( settings !== ctx ) {
return;
}
@@ -8579,7 +8037,13 @@
row = data[i];
if ( row._details ) {
- row._details.children('td[colspan]').attr('colspan', visible );
+ row._details.each(function () {
+ var el = $(this).children('td');
+
+ if (el.length == 1) {
+ el.attr('colspan', visible);
+ }
+ });
}
}
} );
@@ -8637,7 +8101,7 @@
_api_register( [
_child_obj+'.show()',
_child_mth+'.show()' // only when `child()` was called with parameters (without
- ], function ( show ) { // it returns an object and this method is not executed)
+ ], function () { // it returns an object and this method is not executed)
__details_display( this, true );
return this;
} );
@@ -8687,15 +8151,15 @@
// can be an array of these items, comma separated list, or an array of comma
// separated lists
- var __re_column_selector = /^([^:]+):(name|visIdx|visible)$/;
+ var __re_column_selector = /^([^:]+):(name|title|visIdx|visible)$/;
// r1 and r2 are redundant - but it means that the parameters match for the
// iterator callback in columns().data()
- var __columnData = function ( settings, column, r1, r2, rows ) {
+ var __columnData = function ( settings, column, r1, r2, rows, type ) {
var a = [];
for ( var row=0, ien=rows.length ; row<ien ; row++ ) {
- a.push( _fnGetCellData( settings, rows[row], column ) );
+ a.push( _fnGetCellData( settings, rows[row], column, type ) );
}
return a;
};
@@ -8706,8 +8170,10 @@
var
columns = settings.aoColumns,
names = _pluck( columns, 'sName' ),
- nodes = _pluck( columns, 'nTh' );
-
+ titles = _pluck( columns, 'sTitle' ),
+ cells = DataTable.util.get('[].[].cell')(settings.aoHeader),
+ nodes = _unique( _flatten([], cells) );
+
var run = function ( s ) {
var selInt = _intVal( s );
@@ -8728,13 +8194,12 @@
if ( typeof s === 'function' ) {
var rows = _selector_row_indexes( settings, opts );
- return $.map( columns, function (col, idx) {
+ return columns.map(function (col, idx) {
return s(
idx,
- __columnData( settings, idx, 0, 0, rows ),
- nodes[ idx ]
+ __columnData( settings, idx, 0, 0, rows )
) ? idx : null;
- } );
+ });
}
// jQuery or string selector
@@ -8750,7 +8215,7 @@
// Visible index given, convert to column index
if ( idx < 0 ) {
// Counting from the right
- var visColumns = $.map( columns, function (col,i) {
+ var visColumns = columns.map( function (col,i) {
return col.bVisible ? i : null;
} );
return [ visColumns[ visColumns.length + idx ] ];
@@ -8760,10 +8225,16 @@
case 'name':
// match by name. `names` is column index complete and in order
- return $.map( names, function (name, i) {
+ return names.map( function (name, i) {
return name === match[1] ? i : null;
} );
+ case 'title':
+ // match by column title
+ return titles.map( function (title, i) {
+ return title === match[1] ? i : null;
+ } );
+
default:
return [];
}
@@ -8778,7 +8249,7 @@
var jqResult = $( nodes )
.filter( s )
.map( function () {
- return $.inArray( this, nodes ); // `nodes` is column index complete and in order
+ return _fnColumnsFromHeader( this ); // `nodes` is column index complete and in order
} )
.toArray();
@@ -8803,7 +8274,7 @@
cols = settings.aoColumns,
col = cols[ column ],
data = settings.aoData,
- row, cells, i, ien, tr;
+ cells, i, ien, tr;
// Get
if ( vis === undefined ) {
@@ -8813,21 +8284,23 @@
// Set
// No change
if ( col.bVisible === vis ) {
- return;
+ return false;
}
if ( vis ) {
// Insert column
// Need to decide if we should use appendChild or insertBefore
- var insertBefore = $.inArray( true, _pluck(cols, 'bVisible'), column+1 );
+ var insertBefore = _pluck(cols, 'bVisible').indexOf(true, column+1);
for ( i=0, ien=data.length ; i<ien ; i++ ) {
- tr = data[i].nTr;
- cells = data[i].anCells;
+ if (data[i]) {
+ tr = data[i].nTr;
+ cells = data[i].anCells;
- if ( tr ) {
- // insertBefore can act like appendChild if 2nd arg is null
- tr.insertBefore( cells[ column ], cells[ insertBefore ] || null );
+ if ( tr ) {
+ // insertBefore can act like appendChild if 2nd arg is null
+ tr.insertBefore( cells[ column ], cells[ insertBefore ] || null );
+ }
}
}
}
@@ -8838,6 +8311,10 @@
// Common actions
col.bVisible = vis;
+
+ _colGroup(settings);
+
+ return true;
};
@@ -8864,15 +8341,28 @@
return inst;
} );
- _api_registerPlural( 'columns().header()', 'column().header()', function ( selector, opts ) {
+ _api_registerPlural( 'columns().header()', 'column().header()', function ( row ) {
return this.iterator( 'column', function ( settings, column ) {
- return settings.aoColumns[column].nTh;
+ var header = settings.aoHeader;
+ var target = row !== undefined
+ ? row
+ : settings.bSortCellsTop // legacy support
+ ? 0
+ : header.length - 1;
+
+ return header[target][column].cell;
}, 1 );
} );
- _api_registerPlural( 'columns().footer()', 'column().footer()', function ( selector, opts ) {
+ _api_registerPlural( 'columns().footer()', 'column().footer()', function ( row ) {
return this.iterator( 'column', function ( settings, column ) {
- return settings.aoColumns[column].nTf;
+ var footer = settings.aoFooter;
+
+ if (! footer.length) {
+ return null;
+ }
+
+ return settings.aoFooter[row !== undefined ? row : 0][column].cell;
}, 1 );
} );
@@ -8880,6 +8370,12 @@
return this.iterator( 'column-rows', __columnData, 1 );
} );
+ _api_registerPlural( 'columns().render()', 'column().render()', function ( type ) {
+ return this.iterator( 'column-rows', function ( settings, column, i, j, rows ) {
+ return __columnData( settings, column, i, j, rows, type );
+ }, 1 );
+ } );
+
_api_registerPlural( 'columns().dataSrc()', 'column().dataSrc()', function () {
return this.iterator( 'column', function ( settings, column ) {
return settings.aoColumns[column].mData;
@@ -8894,19 +8390,63 @@
}, 1 );
} );
+ _api_registerPlural( 'columns().init()', 'column().init()', function () {
+ return this.iterator( 'column', function ( settings, column ) {
+ return settings.aoColumns[column];
+ }, 1 );
+ } );
+
_api_registerPlural( 'columns().nodes()', 'column().nodes()', function () {
return this.iterator( 'column-rows', function ( settings, column, i, j, rows ) {
return _pluck_order( settings.aoData, rows, 'anCells', column ) ;
}, 1 );
} );
+ _api_registerPlural( 'columns().titles()', 'column().title()', function (title, row) {
+ return this.iterator( 'column', function ( settings, column ) {
+ // Argument shifting
+ if (typeof title === 'number') {
+ row = title;
+ title = undefined;
+ }
+
+ var span = $('span.dt-column-title', this.column(column).header(row));
+
+ if (title !== undefined) {
+ span.html(title);
+ return this;
+ }
+
+ return span.html();
+ }, 1 );
+ } );
+
+ _api_registerPlural( 'columns().types()', 'column().type()', function () {
+ return this.iterator( 'column', function ( settings, column ) {
+ var type = settings.aoColumns[column].sType;
+
+ // If the type was invalidated, then resolve it. This actually does
+ // all columns at the moment. Would only happen once if getting all
+ // column's data types.
+ if (! type) {
+ _fnColumnTypes(settings);
+ }
+
+ return type;
+ }, 1 );
+ } );
+
_api_registerPlural( 'columns().visible()', 'column().visible()', function ( vis, calc ) {
var that = this;
+ var changed = [];
var ret = this.iterator( 'column', function ( settings, column ) {
if ( vis === undefined ) {
return settings.aoColumns[ column ].bVisible;
} // else
- __setColumnVis( settings, column, vis );
+
+ if (__setColumnVis( settings, column, vis )) {
+ changed.push(column);
+ }
} );
// Group the column visibility changes
@@ -8926,10 +8466,12 @@
// Second loop once the first is done for events
that.iterator( 'column', function ( settings, column ) {
- _fnCallbackFire( settings, null, 'column-visibility', [settings, column, vis, calc] );
+ if (changed.includes(column)) {
+ _fnCallbackFire( settings, null, 'column-visibility', [settings, column, vis, calc] );
+ }
} );
- if ( calc === undefined || calc ) {
+ if ( changed.length && (calc === undefined || calc) ) {
that.columns.adjust();
}
});
@@ -8938,6 +8480,28 @@
return ret;
} );
+ _api_registerPlural( 'columns().widths()', 'column().width()', function () {
+ // Injects a fake row into the table for just a moment so the widths can
+ // be read, regardless of colspan in the header and rows being present in
+ // the body
+ var columns = this.columns(':visible').count();
+ var row = $('<tr>').html('<td>' + Array(columns).join('</td><td>') + '</td>');
+
+ $(this.table().body()).append(row);
+
+ var widths = row.children().map(function () {
+ return $(this).outerWidth();
+ });
+
+ row.remove();
+
+ return this.iterator( 'column', function ( settings, column ) {
+ var visIdx = _fnColumnIndexToVisible( settings, column );
+
+ return visIdx !== null ? widths[visIdx] : 0;
+ }, 1);
+ } );
+
_api_registerPlural( 'columns().indexes()', 'column().index()', function ( type ) {
return this.iterator( 'column', function ( settings, column ) {
return type === 'visible' ?
@@ -9016,7 +8580,7 @@
// Selector - index
if ( $.isPlainObject( s ) ) {
// Valid cell index and its in the array of selectable rows
- return s.column !== undefined && s.row !== undefined && $.inArray( s.row, rows ) !== -1 ?
+ return s.column !== undefined && s.row !== undefined && rows.indexOf(s.row) !== -1 ?
[s] :
[];
}
@@ -9028,7 +8592,7 @@
return { // use a new object, in case someone changes the values
row: el._DT_CellIndex.row,
column: el._DT_CellIndex.column
- };
+ };
} )
.toArray();
@@ -9233,6 +8797,7 @@
*/
_api_register( 'order()', function ( order, dir ) {
var ctx = this.context;
+ var args = Array.prototype.slice.call( arguments );
if ( order === undefined ) {
// get
@@ -9246,14 +8811,14 @@
// Simple column / direction passed in
order = [ [ order, dir ] ];
}
- else if ( order.length && ! Array.isArray( order[0] ) ) {
+ else if ( args.length > 1 ) {
// Arguments passed in (list of 1D arrays)
- order = Array.prototype.slice.call( arguments );
+ order = args;
}
// otherwise a 2D array was passed in
return this.iterator( 'table', function ( settings ) {
- settings.aaSorting = order.slice();
+ settings.aaSorting = Array.isArray(order) ? order.slice() : order;
} );
} );
@@ -9270,7 +8835,7 @@
*/
_api_register( 'order.listener()', function ( node, column, callback ) {
return this.iterator( 'table', function ( settings ) {
- _fnSortAttachListener( settings, node, column, callback );
+ _fnSortAttachListener(settings, node, {}, column, callback);
} );
} );
@@ -9300,18 +8865,45 @@
], function ( dir ) {
var that = this;
- return this.iterator( 'table', function ( settings, i ) {
- var sort = [];
+ if ( ! dir ) {
+ return this.iterator( 'column', function ( settings, idx ) {
+ var sort = _fnSortFlatten( settings );
- $.each( that[i], function (j, col) {
- sort.push( [ col, dir ] );
+ for ( var i=0, ien=sort.length ; i<ien ; i++ ) {
+ if ( sort[i].col === idx ) {
+ return sort[i].dir;
+ }
+ }
+
+ return null;
+ }, 1 );
+ }
+ else {
+ return this.iterator( 'table', function ( settings, i ) {
+ settings.aaSorting = that[i].map( function (col) {
+ return [ col, dir ];
+ } );
} );
+ }
+ } );
- settings.aaSorting = sort;
- } );
+ _api_registerPlural('columns().orderable()', 'column().orderable()', function ( directions ) {
+ return this.iterator( 'column', function ( settings, idx ) {
+ var col = settings.aoColumns[idx];
+
+ return directions ?
+ col.asSorting :
+ col.bSortable;
+ }, 1 );
} );
+ _api_register( 'processing()', function ( show ) {
+ return this.iterator( 'table', function ( ctx ) {
+ _fnProcessingDisplay( ctx, show );
+ } );
+ } );
+
_api_register( 'search()', function ( input, regex, smart, caseInsen ) {
var ctx = this.context;
@@ -9319,7 +8911,7 @@
if ( input === undefined ) {
// get
return ctx.length !== 0 ?
- ctx[0].oPreviousSearch.sSearch :
+ ctx[0].oPreviousSearch.search :
undefined;
}
@@ -9329,15 +8921,48 @@
return;
}
- _fnFilterComplete( settings, $.extend( {}, settings.oPreviousSearch, {
- "sSearch": input+"",
- "bRegex": regex === null ? false : regex,
- "bSmart": smart === null ? true : smart,
- "bCaseInsensitive": caseInsen === null ? true : caseInsen
- } ), 1 );
+ if (typeof regex === 'object') {
+ // New style options to pass to the search builder
+ _fnFilterComplete( settings, $.extend( settings.oPreviousSearch, regex, {
+ search: input
+ } ) );
+ }
+ else {
+ // Compat for the old options
+ _fnFilterComplete( settings, $.extend( settings.oPreviousSearch, {
+ search: input,
+ regex: regex === null ? false : regex,
+ smart: smart === null ? true : smart,
+ caseInsensitive: caseInsen === null ? true : caseInsen
+ } ) );
+ }
} );
} );
+ _api_register( 'search.fixed()', function ( name, search ) {
+ var ret = this.iterator( true, 'table', function ( settings ) {
+ var fixed = settings.searchFixed;
+
+ if (! name) {
+ return Object.keys(fixed)
+ }
+ else if (search === undefined) {
+ return fixed[name];
+ }
+ else if (search === null) {
+ delete fixed[name];
+ }
+ else {
+ fixed[name] = search;
+ }
+
+ return this;
+ } );
+
+ return name !== undefined && search === undefined
+ ? ret[0]
+ : ret;
+ } );
_api_registerPlural(
'columns().search()',
@@ -9348,7 +8973,7 @@
if ( input === undefined ) {
// get
- return preSearch[ column ].sSearch;
+ return preSearch[ column ].search;
}
// set
@@ -9356,26 +8981,78 @@
return;
}
- $.extend( preSearch[ column ], {
- "sSearch": input+"",
- "bRegex": regex === null ? false : regex,
- "bSmart": smart === null ? true : smart,
- "bCaseInsensitive": caseInsen === null ? true : caseInsen
- } );
+ if (typeof regex === 'object') {
+ // New style options to pass to the search builder
+ $.extend( preSearch[ column ], regex, {
+ search: input
+ } );
+ }
+ else {
+ // Old style (with not all options available)
+ $.extend( preSearch[ column ], {
+ search: input,
+ regex: regex === null ? false : regex,
+ smart: smart === null ? true : smart,
+ caseInsensitive: caseInsen === null ? true : caseInsen
+ } );
+ }
- _fnFilterComplete( settings, settings.oPreviousSearch, 1 );
+ _fnFilterComplete( settings, settings.oPreviousSearch );
} );
}
);
+ _api_register([
+ 'columns().search.fixed()',
+ 'column().search.fixed()'
+ ],
+ function ( name, search ) {
+ var ret = this.iterator( true, 'column', function ( settings, colIdx ) {
+ var fixed = settings.aoColumns[colIdx].searchFixed;
+
+ if (! name) {
+ return Object.keys(fixed)
+ }
+ else if (search === undefined) {
+ return fixed[name];
+ }
+ else if (search === null) {
+ delete fixed[name];
+ }
+ else {
+ fixed[name] = search;
+ }
+
+ return this;
+ } );
+
+ return name !== undefined && search === undefined
+ ? ret[0]
+ : ret;
+ }
+ );
/*
* State API methods
*/
- _api_register( 'state()', function () {
- return this.context.length ?
- this.context[0].oSavedState :
- null;
+ _api_register( 'state()', function ( set, ignoreTime ) {
+ // getter
+ if ( ! set ) {
+ return this.context.length ?
+ this.context[0].oSavedState :
+ null;
+ }
+
+ var setMutate = $.extend( true, {}, set );
+
+ // setter
+ return this.iterator( 'table', function ( settings ) {
+ if ( ignoreTime !== false ) {
+ setMutate.time = +new Date() + 100;
+ }
+
+ _fnImplementState( settings, setMutate, function(){} );
+ } );
} );
@@ -9400,8 +9077,6 @@
} );
} );
-
-
/**
* Set the jQuery or window object to be used by DataTables
*
@@ -9454,6 +9129,8 @@
*
* @param {string} version Version string to check for, in the format "X.Y.Z".
* Note that the formats "X" and "X.Y" are also acceptable.
+ * @param {string} [version2=current DataTables version] As above, but optional.
+ * If not given the current DataTables version will be used.
* @returns {boolean} true if this version of DataTables is greater or equal to
* the required version, or false if this version of DataTales is not
* suitable
@@ -9463,9 +9140,11 @@
* @example
* alert( $.fn.dataTable.versionCheck( '1.9.0' ) );
*/
- DataTable.versionCheck = DataTable.fnVersionCheck = function( version )
+ DataTable.versionCheck = function( version, version2 )
{
- var aThis = DataTable.version.split('.');
+ var aThis = version2 ?
+ version2.split('.') :
+ DataTable.version.split('.');
var aThat = version.split('.');
var iThis, iThat;
@@ -9501,7 +9180,7 @@
* $('#example').dataTable();
* }
*/
- DataTable.isDataTable = DataTable.fnIsDataTable = function ( table )
+ DataTable.isDataTable = function ( table )
{
var t = $(table).get(0);
var is = false;
@@ -9539,7 +9218,7 @@
* $(table).DataTable().columns.adjust();
* } );
*/
- DataTable.tables = DataTable.fnTables = function ( visible )
+ DataTable.tables = function ( visible )
{
var api = false;
@@ -9548,11 +9227,15 @@
visible = visible.visible;
}
- var a = $.map( DataTable.settings, function (o) {
- if ( !visible || (visible && $(o.nTable).is(':visible')) ) {
+ var a = DataTable.settings
+ .filter( function (o) {
+ return !visible || (visible && $(o.nTable).is(':visible'))
+ ? true
+ : false;
+ } )
+ .map( function (o) {
return o.nTable;
- }
- } );
+ });
return api ?
new _Api( a ) :
@@ -9598,7 +9281,7 @@
var args = Array.prototype.slice.call(arguments);
// Add the `dt` namespace automatically if it isn't already present
- args[0] = $.map( args[0].split( /\s/ ), function ( e ) {
+ args[0] = args[0].split( /\s/ ).map( function ( e ) {
return ! e.match(/\.dt\b/) ?
e+'.dt' :
e;
@@ -9618,6 +9301,13 @@
} );
+ _api_register( 'error()', function (msg) {
+ return this.iterator( 'table', function ( settings ) {
+ _fnLog( settings, 0, msg );
+ } );
+ } );
+
+
_api_register( 'settings()', function () {
return new _Api( this.context, this.context );
} );
@@ -9636,6 +9326,38 @@
} );
+ _api_register( 'trigger()', function ( name, args, bubbles ) {
+ return this.iterator( 'table', function ( settings ) {
+ return _fnCallbackFire( settings, null, name, args, bubbles );
+ } ).flatten();
+ } );
+
+
+ _api_register( 'ready()', function ( fn ) {
+ var ctx = this.context;
+
+ // Get status of first table
+ if (! fn) {
+ return ctx.length
+ ? (ctx[0]._bInitComplete || false)
+ : null;
+ }
+
+ // Function to run either once the table becomes ready or
+ // immediately if it is already ready.
+ return this.tables().every(function () {
+ if (this.context[0]._bInitComplete) {
+ fn.call(this);
+ }
+ else {
+ this.on('init', function () {
+ fn.call(this);
+ });
+ }
+ } );
+ } );
+
+
_api_register( 'destroy()', function ( remove ) {
remove = remove || false;
@@ -9648,15 +9370,15 @@
var jqTable = $(table);
var jqTbody = $(tbody);
var jqWrapper = $(settings.nTableWrapper);
- var rows = $.map( settings.aoData, function (r) { return r.nTr; } );
- var i, ien;
+ var rows = settings.aoData.map( function (r) { return r ? r.nTr : null; } );
+ var orderClasses = classes.order;
// Flag to note that the table is currently being destroyed - no action
// should be taken
settings.bDestroying = true;
// Fire off the destroy callbacks for plug-ins etc
- _fnCallbackFire( settings, "aoDestroyCallback", "destroy", [settings] );
+ _fnCallbackFire( settings, "aoDestroyCallback", "destroy", [settings], true );
// If not being removed from the document, make all columns visible
if ( ! remove ) {
@@ -9684,17 +9406,21 @@
settings.aaSortingFixed = [];
_fnSortingClasses( settings );
- $( rows ).removeClass( settings.asStripeClasses.join(' ') );
-
- $('th, td', thead).removeClass( classes.sSortable+' '+
- classes.sSortableAsc+' '+classes.sSortableDesc+' '+classes.sSortableNone
- );
+ $('th, td', thead)
+ .removeClass(
+ orderClasses.canAsc + ' ' +
+ orderClasses.canDesc + ' ' +
+ orderClasses.isAsc + ' ' +
+ orderClasses.isDesc
+ )
+ .css('width', '');
// Add the TR elements back into the table in their original order
jqTbody.children().detach();
jqTbody.append( rows );
var orig = settings.nTableWrapper.parentNode;
+ var insertBefore = settings.nTableWrapper.nextSibling;
// Remove the DataTables generated nodes, events and classes
var removedMethod = remove ? 'remove' : 'detach';
@@ -9704,28 +9430,17 @@
// If we need to reattach the table to the document
if ( ! remove && orig ) {
// insertBefore acts like appendChild if !arg[1]
- orig.insertBefore( table, settings.nTableReinsertBefore );
+ orig.insertBefore( table, insertBefore );
// Restore the width of the original table - was read from the style property,
// so we can restore directly to that
jqTable
.css( 'width', settings.sDestroyWidth )
- .removeClass( classes.sTable );
-
- // If the were originally stripe classes - then we add them back here.
- // Note this is not fool proof (for example if not all rows had stripe
- // classes - but it's a good effort without getting carried away
- ien = settings.asDestroyStripes.length;
-
- if ( ien ) {
- jqTbody.children().each( function (i) {
- $(this).addClass( settings.asDestroyStripes[i % ien] );
- } );
- }
+ .removeClass( classes.table );
}
/* Remove the settings object from the settings array */
- var idx = $.inArray( settings, DataTable.settings );
+ var idx = DataTable.settings.indexOf(settings);
if ( idx !== -1 ) {
DataTable.settings.splice( idx, 1 );
}
@@ -9738,26 +9453,20 @@
_api_register( type+'s().every()', function ( fn ) {
var opts = this.selector.opts;
var api = this;
+ var inst;
+ var counter = 0;
- return this.iterator( type, function ( settings, arg1, arg2, arg3, arg4 ) {
- // Rows and columns:
- // arg1 - index
- // arg2 - table counter
- // arg3 - loop counter
- // arg4 - undefined
- // Cells:
- // arg1 - row index
- // arg2 - column index
- // arg3 - table counter
- // arg4 - loop counter
- fn.call(
- api[ type ](
- arg1,
- type==='cell' ? arg2 : opts,
- type==='cell' ? opts : undefined
- ),
- arg1, arg2, arg3, arg4
- );
+ return this.iterator( 'every', function ( settings, selectedIdx, tableIdx ) {
+ inst = api[ type ](selectedIdx, opts);
+
+ if (type === 'cell') {
+ fn.call(inst, inst[0][0].row, inst[0][0].column, tableIdx, counter);
+ }
+ else {
+ fn.call(inst, selectedIdx, tableIdx, counter);
+ }
+
+ counter++;
} );
} );
} );
@@ -9773,8 +9482,8 @@
resolved = def;
}
- if ( plural !== undefined && $.isPlainObject( resolved ) ) {
- resolved = resolved[ plural ] !== undefined ?
+ if ( $.isPlainObject( resolved ) ) {
+ resolved = plural !== undefined && resolved[ plural ] !== undefined ?
resolved[ plural ] :
resolved._;
}
@@ -9782,16 +9491,17 @@
return typeof resolved === 'string'
? resolved.replace( '%d', plural ) // nb: plural might be undefined,
: resolved;
- } );
+ } );
+
/**
* Version string for plug-ins to check compatibility. Allowed format is
* `a.b.c-d` where: a:int, b:int, c:int, d:string(dev|beta|alpha). `d` is used
- * only for non-release builds. See http://semver.org/ for more information.
+ * only for non-release builds. See https://semver.org/ for more information.
* @member
* @type string
* @default Version number
*/
- DataTable.version = "1.13.6";
+ DataTable.version = "2.0.0";
/**
* Private data store, containing all of the settings objects that are
@@ -9825,39 +9535,29 @@
DataTable.models.oSearch = {
/**
* Flag to indicate if the filtering should be case insensitive or not
- * @type boolean
- * @default true
*/
- "bCaseInsensitive": true,
+ "caseInsensitive": true,
/**
* Applied search term
- * @type string
- * @default <i>Empty string</i>
*/
- "sSearch": "",
+ "search": "",
/**
* Flag to indicate if the search term should be interpreted as a
* regular expression (true) or not (false) and therefore and special
* regex characters escaped.
- * @type boolean
- * @default false
*/
- "bRegex": false,
+ "regex": false,
/**
* Flag to indicate if DataTables is to use its smart filtering or not.
- * @type boolean
- * @default true
*/
- "bSmart": true,
+ "smart": true,
/**
* Flag to indicate if DataTables should only trigger a search when
* the return key is pressed.
- * @type boolean
- * @default false
*/
"return": false
};
@@ -9874,16 +9574,12 @@
DataTable.models.oRow = {
/**
* TR element for the row
- * @type node
- * @default null
*/
"nTr": null,
/**
* Array of TD elements for each row. This is null until the row has been
* created.
- * @type array nodes
- * @default []
*/
"anCells": null,
@@ -9893,8 +9589,6 @@
* using mData options. The exact type will depend on the passed in
* data from the data source, or will be an array if using DOM a data
* source.
- * @type array|object
- * @default []
*/
"_aData": [],
@@ -9906,18 +9600,12 @@
* the formatting of the sort data need be done only once for each cell
* per sort. This array should not be read from or written to by anything
* other than the master sorting methods.
- * @type array
- * @default null
- * @private
*/
"_aSortData": null,
/**
* Per cell filtering data cache. As per the sort data cache, used to
* increase the performance of the filtering in DataTables
- * @type array
- * @default null
- * @private
*/
"_aFilterData": null,
@@ -9926,41 +9614,27 @@
* in this case a string rather than an array. This is easily computed with
* a join on `_aFilterData`, but is provided as a cache so the join isn't
* needed on every search (memory traded for performance)
- * @type array
- * @default null
- * @private
*/
"_sFilterRow": null,
/**
- * Cache of the class name that DataTables has applied to the row, so we
- * can quickly look at this variable rather than needing to do a DOM check
- * on className for the nTr property.
- * @type string
- * @default <i>Empty string</i>
- * @private
- */
- "_sRowStripe": "",
-
- /**
* Denote if the original data source was from the DOM, or the data source
* object. This is used for invalidating data, so DataTables can
* automatically read data from the original source, unless uninstructed
* otherwise.
- * @type string
- * @default null
- * @private
*/
"src": null,
/**
* Index in the aoData array. This saves an indexOf lookup when we have the
* object, but want to know the index
- * @type integer
- * @default -1
- * @private
*/
- "idx": -1
+ "idx": -1,
+
+ /**
+ * Cached display value
+ */
+ displayData: null
};
@@ -9977,10 +9651,7 @@
*/
DataTable.models.oColumn = {
/**
- * Column index. This could be worked out on-the-fly with $.inArray, but it
- * is faster to just hold it as a variable
- * @type integer
- * @default null
+ * Column index.
*/
"idx": null,
@@ -9991,7 +9662,6 @@
* would benefit from this). The values are integers pointing to the
* columns to be sorted on (typically it will be a single integer pointing
* at itself, but that doesn't need to be the case).
- * @type array
*/
"aDataSort": null,
@@ -10001,44 +9671,34 @@
* as the sorting direction when the column if first sorted (clicked on).
* Sort it again (click again) and it will move on to the next index.
* Repeat until loop.
- * @type array
*/
"asSorting": null,
/**
* Flag to indicate if the column is searchable, and thus should be included
* in the filtering or not.
- * @type boolean
*/
"bSearchable": null,
/**
* Flag to indicate if the column is sortable or not.
- * @type boolean
*/
"bSortable": null,
/**
* Flag to indicate if the column is currently visible in the table or not
- * @type boolean
*/
"bVisible": null,
/**
* Store for manual type assignment using the `column.type` option. This
* is held in store so we can manipulate the column's `sType` property.
- * @type string
- * @default null
- * @private
*/
"_sManualType": null,
/**
* Flag to indicate if HTML5 data attributes should be used as the data
* source for filtering or sorting. True is either are.
- * @type boolean
- * @default false
- * @private
*/
"_bAttrSrc": false,
@@ -10047,12 +9707,6 @@
* etc) or processed for input (DOM source). This can be used as a compliment to mRender
* allowing you to modify the DOM element (add background colour for example) when the
* element is available.
- * @type function
- * @param {element} nTd The TD node that has been created
- * @param {*} sData The Data for the cell
- * @param {array|object} oData The data for the whole row
- * @param {int} iRow The row index for the aoData data store
- * @default null
*/
"fnCreatedCell": null,
@@ -10062,13 +9716,6 @@
* the method attached to this property. It allows mData to function as
* required. This function is automatically assigned by the column
* initialisation method
- * @type function
- * @param {array|object} oData The data array/object for the array
- * (i.e. aoData[]._aData)
- * @param {string} sSpecific The specific data type you want to get -
- * 'display', 'type' 'filter' 'sort'
- * @returns {*} The data for the cell from the given row's data
- * @default null
*/
"fnGetData": null,
@@ -10077,11 +9724,6 @@
* set the data directly to _aData internally in DataTables - always use
* this method. It allows mData to function as required. This function
* is automatically assigned by the column initialisation method
- * @type function
- * @param {array|object} oData The data array/object for the array
- * (i.e. aoData[]._aData)
- * @param {*} sValue Value to set
- * @default null
*/
"fnSetData": null,
@@ -10089,8 +9731,6 @@
* Property to read the value for the cells in the column from the data
* source array / object. If null, then the default content is used, if a
* function is given then the return from the function is used.
- * @type function|int|string|null
- * @default null
*/
"mData": null,
@@ -10099,32 +9739,11 @@
* the data - i.e. it is basically the same as mData, but without the
* 'set' option, and also the data fed to it is the result from mData.
* This is the rendering method to match the data method of mData.
- * @type function|int|string|null
- * @default null
*/
"mRender": null,
/**
- * Unique header TH/TD element for this column - this is what the sorting
- * listener is attached to (if sorting is enabled.)
- * @type node
- * @default null
- */
- "nTh": null,
-
- /**
- * Unique footer TH/TD element for this column (if there is one). Not used
- * in DataTables as such, but can be used for plug-ins to reference the
- * footer for each column.
- * @type node
- * @default null
- */
- "nTf": null,
-
- /**
* The class to apply to all TD elements in the table's TBODY for the column
- * @type string
- * @default null
*/
"sClass": null,
@@ -10137,7 +9756,6 @@
* it into an DOM object and measuring that is horribly(!) slow). Thus as
* a "work around" we provide this option. It will append its value to the
* text that is found to be the longest string for the column - i.e. padding.
- * @type string
*/
"sContentPadding": null,
@@ -10145,67 +9763,53 @@
* Allows a default value to be given for a column's data, and will be used
* whenever a null data source is encountered (this can be because mData
* is set to null, or because the data source itself is null).
- * @type string
- * @default null
*/
"sDefaultContent": null,
/**
* Name for the column, allowing reference to the column by name as well as
* by index (needs a lookup to work by name).
- * @type string
*/
"sName": null,
/**
* Custom sorting data type - defines which of the available plug-ins in
* afnSortData the custom sorting will use - if any is defined.
- * @type string
- * @default std
*/
"sSortDataType": 'std',
/**
* Class to be applied to the header element when sorting on this column
- * @type string
- * @default null
*/
"sSortingClass": null,
/**
- * Class to be applied to the header element when sorting on this column -
- * when jQuery UI theming is used.
- * @type string
- * @default null
- */
- "sSortingClassJUI": null,
-
- /**
* Title of the column - what is seen in the TH element (nTh).
- * @type string
*/
"sTitle": null,
/**
* Column sorting and filtering type
- * @type string
- * @default null
*/
"sType": null,
/**
* Width of the column
- * @type string
- * @default null
*/
"sWidth": null,
/**
* Width of the column when it was first "encountered"
- * @type string
- * @default null
*/
- "sWidthOrig": null
+ "sWidthOrig": null,
+
+ /** Cached string which is the longest in the column */
+ maxLenString: null,
+
+ /**
+ * Store for named searches
+ */
+ searchFixed: null
};
@@ -10236,59 +9840,6 @@
* will be used in preference to any data which is already in the DOM. This is
* particularly useful for constructing tables purely in Javascript, for
* example with a custom Ajax call.
- * @type array
- * @default null
- *
- * @dtopt Option
- * @name DataTable.defaults.data
- *
- * @example
- * // Using a 2D array data source
- * $(document).ready( function () {
- * $('#example').dataTable( {
- * "data": [
- * ['Trident', 'Internet Explorer 4.0', 'Win 95+', 4, 'X'],
- * ['Trident', 'Internet Explorer 5.0', 'Win 95+', 5, 'C'],
- * ],
- * "columns": [
- * { "title": "Engine" },
- * { "title": "Browser" },
- * { "title": "Platform" },
- * { "title": "Version" },
- * { "title": "Grade" }
- * ]
- * } );
- * } );
- *
- * @example
- * // Using an array of objects as a data source (`data`)
- * $(document).ready( function () {
- * $('#example').dataTable( {
- * "data": [
- * {
- * "engine": "Trident",
- * "browser": "Internet Explorer 4.0",
- * "platform": "Win 95+",
- * "version": 4,
- * "grade": "X"
- * },
- * {
- * "engine": "Trident",
- * "browser": "Internet Explorer 5.0",
- * "platform": "Win 95+",
- * "version": 5,
- * "grade": "C"
- * }
- * ],
- * "columns": [
- * { "title": "Engine", "data": "engine" },
- * { "title": "Browser", "data": "browser" },
- * { "title": "Platform", "data": "platform" },
- * { "title": "Version", "data": "version" },
- * { "title": "Grade", "data": "grade" }
- * ]
- * } );
- * } );
*/
"aaData": null,
@@ -10299,26 +9850,6 @@
* upon, and the sorting direction, with this variable. The `sorting` array
* should contain an array for each column to be sorted initially containing
* the column's index and a direction string ('asc' or 'desc').
- * @type array
- * @default [[0,'asc']]
- *
- * @dtopt Option
- * @name DataTable.defaults.order
- *
- * @example
- * // Sort by 3rd column first, and then 4th column
- * $(document).ready( function() {
- * $('#example').dataTable( {
- * "order": [[2,'asc'], [3,'desc']]
- * } );
- * } );
- *
- * // No initial sorting
- * $(document).ready( function() {
- * $('#example').dataTable( {
- * "order": []
- * } );
- * } );
*/
"aaSorting": [[0,'asc']],
@@ -10330,18 +9861,6 @@
* will always be forced on first - any sorting after that (from the user)
* will then be performed as required. This can be useful for grouping rows
* together.
- * @type array
- * @default null
- *
- * @dtopt Option
- * @name DataTable.defaults.orderFixed
- *
- * @example
- * $(document).ready( function() {
- * $('#example').dataTable( {
- * "orderFixed": [[0,'asc']]
- * } );
- * } )
*/
"aaSortingFixed": [],
@@ -10367,7 +9886,7 @@
* --------
*
* As an object, the parameters in the object are passed to
- * [jQuery.ajax](http://api.jquery.com/jQuery.ajax/) allowing fine control
+ * [jQuery.ajax](https://api.jquery.com/jQuery.ajax/) allowing fine control
* of the Ajax request. DataTables has a number of default parameters which
* you can override using this option. Please refer to the jQuery
* documentation for a full description of the options available, although
@@ -10391,8 +9910,7 @@
* it my be used as a function. As a function it takes a single parameter,
* the JSON returned from the server, which can be manipulated as
* required, with the returned value being that used by DataTables as the
- * data source for the table. This supersedes `sAjaxDataProp` from
- * DataTables 1.9-.
+ * data source for the table.
*
* * `success` - Should not be overridden it is used internally in
* DataTables. To manipulate / transform the data returned by the server
@@ -10414,91 +9932,6 @@
* data has been obtained. That data should be passed into the callback
* as the only parameter
* 3. _object_ - DataTables settings object for the table
- *
- * Note that this supersedes `fnServerData` from DataTables 1.9-.
- *
- * @type string|object|function
- * @default null
- *
- * @dtopt Option
- * @name DataTable.defaults.ajax
- * @since 1.10.0
- *
- * @example
- * // Get JSON data from a file via Ajax.
- * // Note DataTables expects data in the form `{ data: [ ...data... ] }` by default).
- * $('#example').dataTable( {
- * "ajax": "data.json"
- * } );
- *
- * @example
- * // Get JSON data from a file via Ajax, using `dataSrc` to change
- * // `data` to `tableData` (i.e. `{ tableData: [ ...data... ] }`)
- * $('#example').dataTable( {
- * "ajax": {
- * "url": "data.json",
- * "dataSrc": "tableData"
- * }
- * } );
- *
- * @example
- * // Get JSON data from a file via Ajax, using `dataSrc` to read data
- * // from a plain array rather than an array in an object
- * $('#example').dataTable( {
- * "ajax": {
- * "url": "data.json",
- * "dataSrc": ""
- * }
- * } );
- *
- * @example
- * // Manipulate the data returned from the server - add a link to data
- * // (note this can, should, be done using `render` for the column - this
- * // is just a simple example of how the data can be manipulated).
- * $('#example').dataTable( {
- * "ajax": {
- * "url": "data.json",
- * "dataSrc": function ( json ) {
- * for ( var i=0, ien=json.length ; i<ien ; i++ ) {
- * json[i][0] = '<a href="/message/'+json[i][0]+'>View message</a>';
- * }
- * return json;
- * }
- * }
- * } );
- *
- * @example
- * // Add data to the request
- * $('#example').dataTable( {
- * "ajax": {
- * "url": "data.json",
- * "data": function ( d ) {
- * return {
- * "extra_search": $('#extra').val()
- * };
- * }
- * }
- * } );
- *
- * @example
- * // Send request as POST
- * $('#example').dataTable( {
- * "ajax": {
- * "url": "data.json",
- * "type": "POST"
- * }
- * } );
- *
- * @example
- * // Get the data from localStorage (could interface with a form for
- * // adding, editing and removing rows).
- * $('#example').dataTable( {
- * "ajax": function (data, callback, settings) {
- * callback(
- * JSON.parse( localStorage.getItem('dataTablesData') )
- * );
- * }
- * } );
*/
"ajax": null,
@@ -10513,18 +9946,6 @@
*
* Note that the `pageLength` property will be automatically set to the
* first value given in this array, unless `pageLength` is also provided.
- * @type array
- * @default [ 10, 25, 50, 100 ]
- *
- * @dtopt Option
- * @name DataTable.defaults.lengthMenu
- *
- * @example
- * $(document).ready( function() {
- * $('#example').dataTable( {
- * "lengthMenu": [[10, 25, 50, -1], [10, 25, 50, "All"]]
- * } );
- * } );
*/
"aLengthMenu": [ 10, 25, 50, 100 ],
@@ -10537,9 +9958,6 @@
* define your columns, you must have an entry in the array for every single
* column that you have in your table (these can be null if you don't which
* to specify any options).
- * @member
- *
- * @name DataTable.defaults.column
*/
"aoColumns": null,
@@ -10558,9 +9976,6 @@
* <li>a negative integer - column index counting from the right</li>
* <li>the string "_all" - all columns (i.e. assign a default)</li>
* </ul>
- * @member
- *
- * @name DataTable.defaults.columnDefs
*/
"aoColumnDefs": null,
@@ -10571,64 +9986,14 @@
* as the number of columns, and each element be an object with the parameters
* `search` and `escapeRegex` (the latter is optional). 'null' is also
* accepted and the default will be used.
- * @type array
- * @default []
- *
- * @dtopt Option
- * @name DataTable.defaults.searchCols
- *
- * @example
- * $(document).ready( function() {
- * $('#example').dataTable( {
- * "searchCols": [
- * null,
- * { "search": "My filter" },
- * null,
- * { "search": "^[0-9]", "escapeRegex": false }
- * ]
- * } );
- * } )
*/
"aoSearchCols": [],
/**
- * An array of CSS classes that should be applied to displayed rows. This
- * array may be of any length, and DataTables will apply each class
- * sequentially, looping when required.
- * @type array
- * @default null <i>Will take the values determined by the `oClasses.stripe*`
- * options</i>
- *
- * @dtopt Option
- * @name DataTable.defaults.stripeClasses
- *
- * @example
- * $(document).ready( function() {
- * $('#example').dataTable( {
- * "stripeClasses": [ 'strip1', 'strip2', 'strip3' ]
- * } );
- * } )
- */
- "asStripeClasses": null,
-
-
- /**
* Enable or disable automatic column width calculation. This can be disabled
* as an optimisation (it takes some time to calculate the widths) if the
* tables widths are passed in using `columns`.
- * @type boolean
- * @default true
- *
- * @dtopt Features
- * @name DataTable.defaults.autoWidth
- *
- * @example
- * $(document).ready( function () {
- * $('#example').dataTable( {
- * "autoWidth": false
- * } );
- * } );
*/
"bAutoWidth": true,
@@ -10639,21 +10004,8 @@
* true, will cause DataTables to defer the creation of the table elements for
* each row until they are needed for a draw - saving a significant amount of
* time.
- * @type boolean
- * @default false
- *
- * @dtopt Features
- * @name DataTable.defaults.deferRender
- *
- * @example
- * $(document).ready( function() {
- * $('#example').dataTable( {
- * "ajax": "sources/arrays.txt",
- * "deferRender": true
- * } );
- * } );
*/
- "bDeferRender": false,
+ "bDeferRender": true,
/**
@@ -10661,25 +10013,6 @@
* one which has the properties of the new initialisation object passed. If no
* table matches the selector, then the new DataTable will be constructed as
* per normal.
- * @type boolean
- * @default false
- *
- * @dtopt Options
- * @name DataTable.defaults.destroy
- *
- * @example
- * $(document).ready( function() {
- * $('#example').dataTable( {
- * "srollY": "200px",
- * "paginate": false
- * } );
- *
- * // Some time later....
- * $('#example').dataTable( {
- * "filter": false,
- * "destroy": true
- * } );
- * } );
*/
"bDestroy": false,
@@ -10692,75 +10025,23 @@
* wish to use filtering in DataTables this must remain 'true' - to remove the
* default filtering input box and retain filtering abilities, please use
* {@link DataTable.defaults.dom}.
- * @type boolean
- * @default true
- *
- * @dtopt Features
- * @name DataTable.defaults.searching
- *
- * @example
- * $(document).ready( function () {
- * $('#example').dataTable( {
- * "searching": false
- * } );
- * } );
*/
"bFilter": true,
-
/**
- * Enable or disable the table information display. This shows information
- * about the data that is currently visible on the page, including information
- * about filtered data if that action is being performed.
- * @type boolean
- * @default true
- *
- * @dtopt Features
- * @name DataTable.defaults.info
- *
- * @example
- * $(document).ready( function () {
- * $('#example').dataTable( {
- * "info": false
- * } );
- * } );
+ * Used only for compatiblity with DT1
+ * @deprecated
*/
"bInfo": true,
-
/**
- * Allows the end user to select the size of a formatted page from a select
- * menu (sizes are 10, 25, 50 and 100). Requires pagination (`paginate`).
- * @type boolean
- * @default true
- *
- * @dtopt Features
- * @name DataTable.defaults.lengthChange
- *
- * @example
- * $(document).ready( function () {
- * $('#example').dataTable( {
- * "lengthChange": false
- * } );
- * } );
+ * Used only for compatiblity with DT1
+ * @deprecated
*/
"bLengthChange": true,
-
/**
* Enable or disable pagination.
- * @type boolean
- * @default true
- *
- * @dtopt Features
- * @name DataTable.defaults.paging
- *
- * @example
- * $(document).ready( function () {
- * $('#example').dataTable( {
- * "paging": false
- * } );
- * } );
*/
"bPaginate": true,
@@ -10770,18 +10051,6 @@
* being processed (e.g. a sort). This is particularly useful for tables with
* large amounts of data where it can take a noticeable amount of time to sort
* the entries.
- * @type boolean
- * @default false
- *
- * @dtopt Features
- * @name DataTable.defaults.processing
- *
- * @example
- * $(document).ready( function () {
- * $('#example').dataTable( {
- * "processing": true
- * } );
- * } );
*/
"bProcessing": false,
@@ -10794,32 +10063,6 @@
* passed to DataTables (setting this parameter to true is an acknowledgement
* that you understand this). `destroy` can be used to reinitialise a table if
* you need.
- * @type boolean
- * @default false
- *
- * @dtopt Options
- * @name DataTable.defaults.retrieve
- *
- * @example
- * $(document).ready( function() {
- * initTable();
- * tableActions();
- * } );
- *
- * function initTable ()
- * {
- * return $('#example').dataTable( {
- * "scrollY": "200px",
- * "paginate": false,
- * "retrieve": true
- * } );
- * }
- *
- * function tableActions ()
- * {
- * var table = initTable();
- * // perform API operations with oTable
- * }
*/
"bRetrieve": false,
@@ -10831,19 +10074,6 @@
* and the footer is left "floating" further down. This parameter (when
* enabled) will cause DataTables to collapse the table's viewport down when
* the result set will fit within the given Y height.
- * @type boolean
- * @default false
- *
- * @dtopt Options
- * @name DataTable.defaults.scrollCollapse
- *
- * @example
- * $(document).ready( function() {
- * $('#example').dataTable( {
- * "scrollY": "200",
- * "scrollCollapse": true
- * } );
- * } );
*/
"bScrollCollapse": false,
@@ -10852,20 +10082,6 @@
* Configure DataTables to use server-side processing. Note that the
* `ajax` parameter must also be given in order to give DataTables a
* source to obtain the required data for each draw.
- * @type boolean
- * @default false
- *
- * @dtopt Features
- * @dtopt Server-side
- * @name DataTable.defaults.serverSide
- *
- * @example
- * $(document).ready( function () {
- * $('#example').dataTable( {
- * "serverSide": true,
- * "ajax": "xhr.php"
- * } );
- * } );
*/
"bServerSide": false,
@@ -10873,18 +10089,6 @@
/**
* Enable or disable sorting of columns. Sorting of individual columns can be
* disabled by the `sortable` option for each column.
- * @type boolean
- * @default true
- *
- * @dtopt Features
- * @name DataTable.defaults.ordering
- *
- * @example
- * $(document).ready( function () {
- * $('#example').dataTable( {
- * "ordering": false
- * } );
- * } );
*/
"bSort": true,
@@ -10892,19 +10096,6 @@
/**
* Enable or display DataTables' ability to sort multiple columns at the
* same time (activated by shift-click by the user).
- * @type boolean
- * @default true
- *
- * @dtopt Options
- * @name DataTable.defaults.orderMulti
- *
- * @example
- * // Disable multiple column sorting ability
- * $(document).ready( function () {
- * $('#example').dataTable( {
- * "orderMulti": false
- * } );
- * } );
*/
"bSortMulti": true,
@@ -10913,20 +10104,8 @@
* Allows control over whether DataTables should use the top (true) unique
* cell that is found for a single column, or the bottom (false - default).
* This is useful when using complex headers.
- * @type boolean
- * @default false
- *
- * @dtopt Options
- * @name DataTable.defaults.orderCellsTop
- *
- * @example
- * $(document).ready( function() {
- * $('#example').dataTable( {
- * "orderCellsTop": true
- * } );
- * } );
*/
- "bSortCellsTop": false,
+ "bSortCellsTop": null,
/**
@@ -10935,18 +10114,6 @@
* presented as a feature switch as it can increase processing time (while
* classes are removed and added) so for large data sets you might want to
* turn this off.
- * @type boolean
- * @default true
- *
- * @dtopt Features
- * @name DataTable.defaults.orderClasses
- *
- * @example
- * $(document).ready( function () {
- * $('#example').dataTable( {
- * "orderClasses": false
- * } );
- * } );
*/
"bSortClasses": true,
@@ -10956,22 +10123,6 @@
* used to save table display information such as pagination information,
* display length, filtering and sorting. As such when the end user reloads
* the page the display display will match what thy had previously set up.
- *
- * Due to the use of `localStorage` the default state saving is not supported
- * in IE6 or 7. If state saving is required in those browsers, use
- * `stateSaveCallback` to provide a storage solution such as cookies.
- * @type boolean
- * @default false
- *
- * @dtopt Features
- * @name DataTable.defaults.stateSave
- *
- * @example
- * $(document).ready( function () {
- * $('#example').dataTable( {
- * "stateSave": true
- * } );
- * } );
*/
"bStateSave": false,
@@ -10980,26 +10131,6 @@
* This function is called when a TR element is created (and all TD child
* elements have been inserted), or registered if using a DOM source, allowing
* manipulation of the TR element (adding classes etc).
- * @type function
- * @param {node} row "TR" element for the current row
- * @param {array} data Raw data array for this row
- * @param {int} dataIndex The index of this row in the internal aoData array
- *
- * @dtopt Callbacks
- * @name DataTable.defaults.createdRow
- *
- * @example
- * $(document).ready( function() {
- * $('#example').dataTable( {
- * "createdRow": function( row, data, dataIndex ) {
- * // Bold the grade for all 'A' grade browsers
- * if ( data[4] == "A" )
- * {
- * $('td:eq(4)', row).html( '<b>A</b>' );
- * }
- * }
- * } );
- * } );
*/
"fnCreatedRow": null,
@@ -11007,20 +10138,6 @@
/**
* This function is called on every 'draw' event, and allows you to
* dynamically modify any aspect you want about the created DOM.
- * @type function
- * @param {object} settings DataTables settings object
- *
- * @dtopt Callbacks
- * @name DataTable.defaults.drawCallback
- *
- * @example
- * $(document).ready( function() {
- * $('#example').dataTable( {
- * "drawCallback": function( settings ) {
- * alert( 'DataTables has redrawn the table' );
- * }
- * } );
- * } );
*/
"fnDrawCallback": null,
@@ -11028,27 +10145,6 @@
/**
* Identical to fnHeaderCallback() but for the table footer this function
* allows you to modify the table footer on every 'draw' event.
- * @type function
- * @param {node} foot "TR" element for the footer
- * @param {array} data Full table data (as derived from the original HTML)
- * @param {int} start Index for the current display starting point in the
- * display array
- * @param {int} end Index for the current display ending point in the
- * display array
- * @param {array int} display Index array to translate the visual position
- * to the full data array
- *
- * @dtopt Callbacks
- * @name DataTable.defaults.footerCallback
- *
- * @example
- * $(document).ready( function() {
- * $('#example').dataTable( {
- * "footerCallback": function( tfoot, data, start, end, display ) {
- * tfoot.getElementsByTagName('th')[0].innerHTML = "Starting index is "+start;
- * }
- * } );
- * } )
*/
"fnFooterCallback": null,
@@ -11059,26 +10155,6 @@
* to have a comma separator for the 'thousands' units (e.g. 1 million is
* rendered as "1,000,000") to help readability for the end user. This
* function will override the default method DataTables uses.
- * @type function
- * @member
- * @param {int} toFormat number to be formatted
- * @returns {string} formatted string for DataTables to show the number
- *
- * @dtopt Callbacks
- * @name DataTable.defaults.formatNumber
- *
- * @example
- * // Format a number using a single quote for the separator (note that
- * // this can also be done with the language.thousands option)
- * $(document).ready( function() {
- * $('#example').dataTable( {
- * "formatNumber": function ( toFormat ) {
- * return toFormat.toString().replace(
- * /\B(?=(\d{3})+(?!\d))/g, "'"
- * );
- * };
- * } );
- * } );
*/
"fnFormatNumber": function ( toFormat ) {
return toFormat.toString().replace(
@@ -11092,27 +10168,6 @@
* This function is called on every 'draw' event, and allows you to
* dynamically modify the header row. This can be used to calculate and
* display useful information about the table.
- * @type function
- * @param {node} head "TR" element for the header
- * @param {array} data Full table data (as derived from the original HTML)
- * @param {int} start Index for the current display starting point in the
- * display array
- * @param {int} end Index for the current display ending point in the
- * display array
- * @param {array int} display Index array to translate the visual position
- * to the full data array
- *
- * @dtopt Callbacks
- * @name DataTable.defaults.headerCallback
- *
- * @example
- * $(document).ready( function() {
- * $('#example').dataTable( {
- * "fheaderCallback": function( head, data, start, end, display ) {
- * head.getElementsByTagName('th')[0].innerHTML = "Displaying "+(end-start)+" records";
- * }
- * } );
- * } )
*/
"fnHeaderCallback": null,
@@ -11123,26 +10178,6 @@
* DataTables are quite capable of dealing with most customisations, there may
* be times where you wish to customise the string further. This callback
* allows you to do exactly that.
- * @type function
- * @param {object} oSettings DataTables settings object
- * @param {int} start Starting position in data for the draw
- * @param {int} end End position in data for the draw
- * @param {int} max Total number of rows in the table (regardless of
- * filtering)
- * @param {int} total Total number of rows in the data set, after filtering
- * @param {string} pre The string that DataTables has formatted using it's
- * own rules
- * @returns {string} The string to be displayed in the information element.
- *
- * @dtopt Callbacks
- * @name DataTable.defaults.infoCallback
- *
- * @example
- * $('#example').dataTable( {
- * "infoCallback": function( settings, start, end, max, total, pre ) {
- * return start +" to "+ end;
- * }
- * } );
*/
"fnInfoCallback": null,
@@ -11152,22 +10187,6 @@
* initialise sequentially and there will be no need for this function,
* however, this does not hold true when using external language information
* since that is obtained using an async XHR call.
- * @type function
- * @param {object} settings DataTables settings object
- * @param {object} json The JSON object request from the server - only
- * present if client-side Ajax sourced data is used
- *
- * @dtopt Callbacks
- * @name DataTable.defaults.initComplete
- *
- * @example
- * $(document).ready( function() {
- * $('#example').dataTable( {
- * "initComplete": function(settings, json) {
- * alert( 'DataTables has finished its initialisation.' );
- * }
- * } );
- * } )
*/
"fnInitComplete": null,
@@ -11176,24 +10195,6 @@
* Called at the very start of each table draw and can be used to cancel the
* draw by returning false, any other return (including undefined) results in
* the full draw occurring).
- * @type function
- * @param {object} settings DataTables settings object
- * @returns {boolean} False will cancel the draw, anything else (including no
- * return) will allow it to complete.
- *
- * @dtopt Callbacks
- * @name DataTable.defaults.preDrawCallback
- *
- * @example
- * $(document).ready( function() {
- * $('#example').dataTable( {
- * "preDrawCallback": function( settings ) {
- * if ( $('#test').val() == 1 ) {
- * return false;
- * }
- * }
- * } );
- * } );
*/
"fnPreDrawCallback": null,
@@ -11202,113 +10203,14 @@
* This function allows you to 'post process' each row after it have been
* generated for each table draw, but before it is rendered on screen. This
* function might be used for setting the row class name etc.
- * @type function
- * @param {node} row "TR" element for the current row
- * @param {array} data Raw data array for this row
- * @param {int} displayIndex The display index for the current table draw
- * @param {int} displayIndexFull The index of the data in the full list of
- * rows (after filtering)
- *
- * @dtopt Callbacks
- * @name DataTable.defaults.rowCallback
- *
- * @example
- * $(document).ready( function() {
- * $('#example').dataTable( {
- * "rowCallback": function( row, data, displayIndex, displayIndexFull ) {
- * // Bold the grade for all 'A' grade browsers
- * if ( data[4] == "A" ) {
- * $('td:eq(4)', row).html( '<b>A</b>' );
- * }
- * }
- * } );
- * } );
*/
"fnRowCallback": null,
/**
- * __Deprecated__ The functionality provided by this parameter has now been
- * superseded by that provided through `ajax`, which should be used instead.
- *
- * This parameter allows you to override the default function which obtains
- * the data from the server so something more suitable for your application.
- * For example you could use POST data, or pull information from a Gears or
- * AIR database.
- * @type function
- * @member
- * @param {string} source HTTP source to obtain the data from (`ajax`)
- * @param {array} data A key/value pair object containing the data to send
- * to the server
- * @param {function} callback to be called on completion of the data get
- * process that will draw the data on the page.
- * @param {object} settings DataTables settings object
- *
- * @dtopt Callbacks
- * @dtopt Server-side
- * @name DataTable.defaults.serverData
- *
- * @deprecated 1.10. Please use `ajax` for this functionality now.
- */
- "fnServerData": null,
-
-
- /**
- * __Deprecated__ The functionality provided by this parameter has now been
- * superseded by that provided through `ajax`, which should be used instead.
- *
- * It is often useful to send extra data to the server when making an Ajax
- * request - for example custom filtering information, and this callback
- * function makes it trivial to send extra information to the server. The
- * passed in parameter is the data set that has been constructed by
- * DataTables, and you can add to this or modify it as you require.
- * @type function
- * @param {array} data Data array (array of objects which are name/value
- * pairs) that has been constructed by DataTables and will be sent to the
- * server. In the case of Ajax sourced data with server-side processing
- * this will be an empty array, for server-side processing there will be a
- * significant number of parameters!
- * @returns {undefined} Ensure that you modify the data array passed in,
- * as this is passed by reference.
- *
- * @dtopt Callbacks
- * @dtopt Server-side
- * @name DataTable.defaults.serverParams
- *
- * @deprecated 1.10. Please use `ajax` for this functionality now.
- */
- "fnServerParams": null,
-
-
- /**
* Load the table state. With this function you can define from where, and how, the
* state of a table is loaded. By default DataTables will load from `localStorage`
* but you might wish to use a server-side database or cookies.
- * @type function
- * @member
- * @param {object} settings DataTables settings object
- * @param {object} callback Callback that can be executed when done. It
- * should be passed the loaded state object.
- * @return {object} The DataTables state object to be loaded
- *
- * @dtopt Callbacks
- * @name DataTable.defaults.stateLoadCallback
- *
- * @example
- * $(document).ready( function() {
- * $('#example').dataTable( {
- * "stateSave": true,
- * "stateLoadCallback": function (settings, callback) {
- * $.ajax( {
- * "url": "/state_load",
- * "dataType": "json",
- * "success": function (json) {
- * callback( json );
- * }
- * } );
- * }
- * } );
- * } );
*/
"fnStateLoadCallback": function ( settings ) {
try {
@@ -11329,34 +10231,6 @@
* prior to the settings object being modified by the saved state. Note that for
* plug-in authors, you should use the `stateLoadParams` event to load parameters for
* a plug-in.
- * @type function
- * @param {object} settings DataTables settings object
- * @param {object} data The state object that is to be loaded
- *
- * @dtopt Callbacks
- * @name DataTable.defaults.stateLoadParams
- *
- * @example
- * // Remove a saved filter, so filtering is never loaded
- * $(document).ready( function() {
- * $('#example').dataTable( {
- * "stateSave": true,
- * "stateLoadParams": function (settings, data) {
- * data.oSearch.sSearch = "";
- * }
- * } );
- * } );
- *
- * @example
- * // Disallow state loading by returning false
- * $(document).ready( function() {
- * $('#example').dataTable( {
- * "stateSave": true,
- * "stateLoadParams": function (settings, data) {
- * return false;
- * }
- * } );
- * } );
*/
"fnStateLoadParams": null,
@@ -11364,23 +10238,6 @@
/**
* Callback that is called when the state has been loaded from the state saving method
* and the DataTables settings object has been modified as a result of the loaded state.
- * @type function
- * @param {object} settings DataTables settings object
- * @param {object} data The state object that was loaded
- *
- * @dtopt Callbacks
- * @name DataTable.defaults.stateLoaded
- *
- * @example
- * // Show an alert with the filtering value that was saved
- * $(document).ready( function() {
- * $('#example').dataTable( {
- * "stateSave": true,
- * "stateLoaded": function (settings, data) {
- * alert( 'Saved filter was: '+data.oSearch.sSearch );
- * }
- * } );
- * } );
*/
"fnStateLoaded": null,
@@ -11389,30 +10246,6 @@
* Save the table state. This function allows you to define where and how the state
* information for the table is stored By default DataTables will use `localStorage`
* but you might wish to use a server-side database or cookies.
- * @type function
- * @member
- * @param {object} settings DataTables settings object
- * @param {object} data The state object to be saved
- *
- * @dtopt Callbacks
- * @name DataTable.defaults.stateSaveCallback
- *
- * @example
- * $(document).ready( function() {
- * $('#example').dataTable( {
- * "stateSave": true,
- * "stateSaveCallback": function (settings, data) {
- * // Send an Ajax request to the server with the state object
- * $.ajax( {
- * "url": "/state_save",
- * "data": data,
- * "dataType": "json",
- * "method": "POST"
- * "success": function () {}
- * } );
- * }
- * } );
- * } );
*/
"fnStateSaveCallback": function ( settings, data ) {
try {
@@ -11420,7 +10253,9 @@
'DataTables_'+settings.sInstance+'_'+location.pathname,
JSON.stringify( data )
);
- } catch (e) {}
+ } catch (e) {
+ // noop
+ }
},
@@ -11430,23 +10265,6 @@
* the state saving object prior to actually doing the save, including addition or
* other state properties or modification. Note that for plug-in authors, you should
* use the `stateSaveParams` event to save parameters for a plug-in.
- * @type function
- * @param {object} settings DataTables settings object
- * @param {object} data The state object to be saved
- *
- * @dtopt Callbacks
- * @name DataTable.defaults.stateSaveParams
- *
- * @example
- * // Remove a saved filter, so filtering is never saved
- * $(document).ready( function() {
- * $('#example').dataTable( {
- * "stateSave": true,
- * "stateSaveParams": function (settings, data) {
- * data.oSearch.sSearch = "";
- * }
- * } );
- * } );
*/
"fnStateSaveParams": null,
@@ -11455,82 +10273,14 @@
* Duration for which the saved state information is considered valid. After this period
* has elapsed the state will be returned to the default.
* Value is given in seconds.
- * @type int
- * @default 7200 <i>(2 hours)</i>
- *
- * @dtopt Options
- * @name DataTable.defaults.stateDuration
- *
- * @example
- * $(document).ready( function() {
- * $('#example').dataTable( {
- * "stateDuration": 60*60*24; // 1 day
- * } );
- * } )
*/
"iStateDuration": 7200,
/**
- * When enabled DataTables will not make a request to the server for the first
- * page draw - rather it will use the data already on the page (no sorting etc
- * will be applied to it), thus saving on an XHR at load time. `deferLoading`
- * is used to indicate that deferred loading is required, but it is also used
- * to tell DataTables how many records there are in the full table (allowing
- * the information element and pagination to be displayed correctly). In the case
- * where a filtering is applied to the table on initial load, this can be
- * indicated by giving the parameter as an array, where the first element is
- * the number of records available after filtering and the second element is the
- * number of records without filtering (allowing the table information element
- * to be shown correctly).
- * @type int | array
- * @default null
- *
- * @dtopt Options
- * @name DataTable.defaults.deferLoading
- *
- * @example
- * // 57 records available in the table, no filtering applied
- * $(document).ready( function() {
- * $('#example').dataTable( {
- * "serverSide": true,
- * "ajax": "scripts/server_processing.php",
- * "deferLoading": 57
- * } );
- * } );
- *
- * @example
- * // 57 records after filtering, 100 without filtering (an initial filter applied)
- * $(document).ready( function() {
- * $('#example').dataTable( {
- * "serverSide": true,
- * "ajax": "scripts/server_processing.php",
- * "deferLoading": [ 57, 100 ],
- * "search": {
- * "search": "my_filter"
- * }
- * } );
- * } );
- */
- "iDeferLoading": null,
-
-
- /**
* Number of rows to display on a single page when using pagination. If
* feature enabled (`lengthChange`) then the end user will be able to override
* this to a custom setting using a pop-up menu.
- * @type int
- * @default 10
- *
- * @dtopt Options
- * @name DataTable.defaults.pageLength
- *
- * @example
- * $(document).ready( function() {
- * $('#example').dataTable( {
- * "pageLength": 50
- * } );
- * } )
*/
"iDisplayLength": 10,
@@ -11540,18 +10290,6 @@
* pagination. Note that this parameter is the number of records, rather than
* the page number, so if you have 10 records per page and want to start on
* the third page, it should be "20".
- * @type int
- * @default 0
- *
- * @dtopt Options
- * @name DataTable.defaults.displayStart
- *
- * @example
- * $(document).ready( function() {
- * $('#example').dataTable( {
- * "displayStart": 20
- * } );
- * } )
*/
"iDisplayStart": 0,
@@ -11563,18 +10301,6 @@
* The tabindex is default 0, meaning that the tab follows the flow of the document.
* You can overrule this using this parameter if you wish. Use a value of -1 to
* disable built-in keyboard navigation.
- * @type int
- * @default 0
- *
- * @dtopt Options
- * @name DataTable.defaults.tabIndex
- *
- * @example
- * $(document).ready( function() {
- * $('#example').dataTable( {
- * "tabIndex": 1
- * } );
- * } );
*/
"iTabIndex": 0,
@@ -11584,8 +10310,6 @@
* that it adds to the HTML table. This allows classes to be configured
* during initialisation in addition to through the static
* {@link DataTable.ext.oStdClasses} object).
- * @namespace
- * @name DataTable.defaults.classes
*/
"oClasses": {},
@@ -11594,162 +10318,70 @@
* All strings that DataTables uses in the user interface that it creates
* are defined in this object, allowing you to modified them individually or
* completely replace them all as required.
- * @namespace
- * @name DataTable.defaults.language
*/
"oLanguage": {
/**
* Strings that are used for WAI-ARIA labels and controls only (these are not
* actually visible on the page, but will be read by screenreaders, and thus
* must be internationalised as well).
- * @namespace
- * @name DataTable.defaults.language.aria
*/
"oAria": {
/**
- * ARIA label that is added to the table headers when the column may be
- * sorted ascending by activing the column (click or return when focused).
- * Note that the column header is prefixed to this string.
- * @type string
- * @default : activate to sort column ascending
- *
- * @dtopt Language
- * @name DataTable.defaults.language.aria.sortAscending
- *
- * @example
- * $(document).ready( function() {
- * $('#example').dataTable( {
- * "language": {
- * "aria": {
- * "sortAscending": " - click/return to sort ascending"
- * }
- * }
- * } );
- * } );
+ * ARIA label that is added to the table headers when the column may be sorted
+ */
+ "orderable": ": Activate to sort",
+
+ /**
+ * ARIA label that is added to the table headers when the column is currently being sorted
*/
- "sSortAscending": ": activate to sort column ascending",
+ "orderableReverse": ": Activate to invert sorting",
/**
- * ARIA label that is added to the table headers when the column may be
- * sorted descending by activing the column (click or return when focused).
- * Note that the column header is prefixed to this string.
- * @type string
- * @default : activate to sort column ascending
- *
- * @dtopt Language
- * @name DataTable.defaults.language.aria.sortDescending
- *
- * @example
- * $(document).ready( function() {
- * $('#example').dataTable( {
- * "language": {
- * "aria": {
- * "sortDescending": " - click/return to sort descending"
- * }
- * }
- * } );
- * } );
+ * ARIA label that is added to the table headers when the column is currently being
+ * sorted and next step is to remove sorting
*/
- "sSortDescending": ": activate to sort column descending"
+ "orderableRemove": ": Activate to remove sorting",
+
+ paginate: {
+ first: 'First',
+ last: 'Last',
+ next: 'Next',
+ previous: 'Previous'
+ }
},
/**
* Pagination string used by DataTables for the built-in pagination
* control types.
- * @namespace
- * @name DataTable.defaults.language.paginate
*/
"oPaginate": {
/**
- * Text to use when using the 'full_numbers' type of pagination for the
- * button to take the user to the first page.
- * @type string
- * @default First
- *
- * @dtopt Language
- * @name DataTable.defaults.language.paginate.first
- *
- * @example
- * $(document).ready( function() {
- * $('#example').dataTable( {
- * "language": {
- * "paginate": {
- * "first": "First page"
- * }
- * }
- * } );
- * } );
+ * Label and character for first page button
*/
- "sFirst": "First",
-
+ "sFirst": "«",
/**
- * Text to use when using the 'full_numbers' type of pagination for the
- * button to take the user to the last page.
- * @type string
- * @default Last
- *
- * @dtopt Language
- * @name DataTable.defaults.language.paginate.last
- *
- * @example
- * $(document).ready( function() {
- * $('#example').dataTable( {
- * "language": {
- * "paginate": {
- * "last": "Last page"
- * }
- * }
- * } );
- * } );
+ * Last page button
*/
- "sLast": "Last",
-
+ "sLast": "»",
/**
- * Text to use for the 'next' pagination button (to take the user to the
- * next page).
- * @type string
- * @default Next
- *
- * @dtopt Language
- * @name DataTable.defaults.language.paginate.next
- *
- * @example
- * $(document).ready( function() {
- * $('#example').dataTable( {
- * "language": {
- * "paginate": {
- * "next": "Next page"
- * }
- * }
- * } );
- * } );
+ * Next page button
*/
- "sNext": "Next",
-
+ "sNext": "›",
/**
- * Text to use for the 'previous' pagination button (to take the user to
- * the previous page).
- * @type string
- * @default Previous
- *
- * @dtopt Language
- * @name DataTable.defaults.language.paginate.previous
- *
- * @example
- * $(document).ready( function() {
- * $('#example').dataTable( {
- * "language": {
- * "paginate": {
- * "previous": "Previous page"
- * }
- * }
- * } );
- * } );
+ * Previous page button
*/
- "sPrevious": "Previous"
+ "sPrevious": "‹",
+ },
+
+ /**
+ * Plural object for the data type the table is showing
+ */
+ entries: {
+ _: "entries",
+ 1: "entry"
},
/**
@@ -11757,20 +10389,6 @@
* empty of data (regardless of filtering). Note that this is an optional
* parameter - if it is not given, the value of `zeroRecords` will be used
* instead (either the default or given value).
- * @type string
- * @default No data available in table
- *
- * @dtopt Language
- * @name DataTable.defaults.language.emptyTable
- *
- * @example
- * $(document).ready( function() {
- * $('#example').dataTable( {
- * "language": {
- * "emptyTable": "No data available in table"
- * }
- * } );
- * } );
*/
"sEmptyTable": "No data available in table",
@@ -11788,66 +10406,23 @@
* * `\_MAX\_` - Number of records in the table without filtering
* * `\_PAGE\_` - Current page number
* * `\_PAGES\_` - Total number of pages of data in the table
- *
- * @type string
- * @default Showing _START_ to _END_ of _TOTAL_ entries
- *
- * @dtopt Language
- * @name DataTable.defaults.language.info
- *
- * @example
- * $(document).ready( function() {
- * $('#example').dataTable( {
- * "language": {
- * "info": "Showing page _PAGE_ of _PAGES_"
- * }
- * } );
- * } );
*/
- "sInfo": "Showing _START_ to _END_ of _TOTAL_ entries",
+ "sInfo": "Showing _START_ to _END_ of _TOTAL_ _ENTRIES-TOTAL_",
/**
* Display information string for when the table is empty. Typically the
* format of this string should match `info`.
- * @type string
- * @default Showing 0 to 0 of 0 entries
- *
- * @dtopt Language
- * @name DataTable.defaults.language.infoEmpty
- *
- * @example
- * $(document).ready( function() {
- * $('#example').dataTable( {
- * "language": {
- * "infoEmpty": "No entries to show"
- * }
- * } );
- * } );
*/
- "sInfoEmpty": "Showing 0 to 0 of 0 entries",
+ "sInfoEmpty": "Showing 0 to 0 of 0 _ENTRIES-TOTAL_",
/**
* When a user filters the information in a table, this string is appended
* to the information (`info`) to give an idea of how strong the filtering
* is. The variable _MAX_ is dynamically updated.
- * @type string
- * @default (filtered from _MAX_ total entries)
- *
- * @dtopt Language
- * @name DataTable.defaults.language.infoFiltered
- *
- * @example
- * $(document).ready( function() {
- * $('#example').dataTable( {
- * "language": {
- * "infoFiltered": " - filtering from _MAX_ records"
- * }
- * } );
- * } );
*/
- "sInfoFiltered": "(filtered from _MAX_ total entries)",
+ "sInfoFiltered": "(filtered from _MAX_ total _ENTRIES-MAX_)",
/**
@@ -11855,20 +10430,6 @@
* and this variable does exactly that. This information will be appended to
* the `info` (`infoEmpty` and `infoFiltered` in whatever combination they are
* being used) at all times.
- * @type string
- * @default <i>Empty string</i>
- *
- * @dtopt Language
- * @name DataTable.defaults.language.infoPostFix
- *
- * @example
- * $(document).ready( function() {
- * $('#example').dataTable( {
- * "language": {
- * "infoPostFix": "All records shown are derived from real information."
- * }
- * } );
- * } );
*/
"sInfoPostFix": "",
@@ -11885,21 +10446,6 @@
* the same table and still be sortable, the table must be consistent.
* However, multiple different tables on the page can use different
* decimal place characters.
- * @type string
- * @default
- *
- * @dtopt Language
- * @name DataTable.defaults.language.decimal
- *
- * @example
- * $(document).ready( function() {
- * $('#example').dataTable( {
- * "language": {
- * "decimal": ","
- * "thousands": "."
- * }
- * } );
- * } );
*/
"sDecimal": "",
@@ -11909,20 +10455,6 @@
* used to format large numbers that are used in the table information.
* By default a comma is used, but this can be trivially changed to any
* character you wish with this parameter.
- * @type string
- * @default ,
- *
- * @dtopt Language
- * @name DataTable.defaults.language.thousands
- *
- * @example
- * $(document).ready( function() {
- * $('#example').dataTable( {
- * "language": {
- * "thousands": "'"
- * }
- * } );
- * } );
*/
"sThousands": ",",
@@ -11932,40 +10464,8 @@
* pagination length option is changed. The '_MENU_' variable is replaced
* with a default select list of 10, 25, 50 and 100, and can be replaced
* with a custom select box if required.
- * @type string
- * @default Show _MENU_ entries
- *
- * @dtopt Language
- * @name DataTable.defaults.language.lengthMenu
- *
- * @example
- * // Language change only
- * $(document).ready( function() {
- * $('#example').dataTable( {
- * "language": {
- * "lengthMenu": "Display _MENU_ records"
- * }
- * } );
- * } );
- *
- * @example
- * // Language and options change
- * $(document).ready( function() {
- * $('#example').dataTable( {
- * "language": {
- * "lengthMenu": 'Display <select>'+
- * '<option value="10">10</option>'+
- * '<option value="20">20</option>'+
- * '<option value="30">30</option>'+
- * '<option value="40">40</option>'+
- * '<option value="50">50</option>'+
- * '<option value="-1">All</option>'+
- * '</select> records'
- * }
- * } );
- * } );
*/
- "sLengthMenu": "Show _MENU_ entries",
+ "sLengthMenu": "_MENU_ _ENTRIES_ per page",
/**
@@ -11974,20 +10474,6 @@
* indicate to the end user the the data is being loaded. Note that this
* parameter is not used when loading data by server-side processing, just
* Ajax sourced data with client-side processing.
- * @type string
- * @default Loading...
- *
- * @dtopt Language
- * @name DataTable.defaults.language.loadingRecords
- *
- * @example
- * $(document).ready( function() {
- * $('#example').dataTable( {
- * "language": {
- * "loadingRecords": "Please wait - loading..."
- * }
- * } );
- * } );
*/
"sLoadingRecords": "Loading...",
@@ -11995,19 +10481,6 @@
/**
* Text which is displayed when the table is processing a user action
* (usually a sort command or similar).
- * @type string
- *
- * @dtopt Language
- * @name DataTable.defaults.language.processing
- *
- * @example
- * $(document).ready( function() {
- * $('#example').dataTable( {
- * "language": {
- * "processing": "DataTables is currently busy"
- * }
- * } );
- * } );
*/
"sProcessing": "",
@@ -12018,31 +10491,6 @@
* is replaced with the HTML text box for the filtering input allowing
* control over where it appears in the string. If "_INPUT_" is not given
* then the input box is appended to the string automatically.
- * @type string
- * @default Search:
- *
- * @dtopt Language
- * @name DataTable.defaults.language.search
- *
- * @example
- * // Input text box will be appended at the end automatically
- * $(document).ready( function() {
- * $('#example').dataTable( {
- * "language": {
- * "search": "Filter records:"
- * }
- * } );
- * } );
- *
- * @example
- * // Specify where the filter should appear
- * $(document).ready( function() {
- * $('#example').dataTable( {
- * "language": {
- * "search": "Apply filter _INPUT_ to table"
- * }
- * } );
- * } );
*/
"sSearch": "Search:",
@@ -12065,20 +10513,6 @@
* and the object has the same properties as the oLanguage object in the
* initialiser object (i.e. the above parameters). Please refer to one of
* the example language files to see how this works in action.
- * @type string
- * @default <i>Empty string - i.e. disabled</i>
- *
- * @dtopt Language
- * @name DataTable.defaults.language.url
- *
- * @example
- * $(document).ready( function() {
- * $('#example').dataTable( {
- * "language": {
- * "url": "http://www.sprymedia.co.uk/dataTables/lang.txt"
- * }
- * } );
- * } );
*/
"sUrl": "",
@@ -12087,20 +10521,6 @@
* Text shown inside the table records when the is no information to be
* displayed after filtering. `emptyTable` is shown when there is simply no
* information in the table at all (regardless of filtering).
- * @type string
- * @default No matching records found
- *
- * @dtopt Language
- * @name DataTable.defaults.language.zeroRecords
- *
- * @example
- * $(document).ready( function() {
- * $('#example').dataTable( {
- * "language": {
- * "zeroRecords": "No records to display"
- * }
- * } );
- * } );
*/
"sZeroRecords": "No matching records found"
},
@@ -12114,132 +10534,31 @@
* (default) it will be treated as a straight string. When `smart`
* DataTables will use it's smart filtering methods (to word match at
* any point in the data), when false this will not be done.
- * @namespace
- * @extends DataTable.models.oSearch
- *
- * @dtopt Options
- * @name DataTable.defaults.search
- *
- * @example
- * $(document).ready( function() {
- * $('#example').dataTable( {
- * "search": {"search": "Initial search"}
- * } );
- * } )
*/
"oSearch": $.extend( {}, DataTable.models.oSearch ),
/**
- * __Deprecated__ The functionality provided by this parameter has now been
- * superseded by that provided through `ajax`, which should be used instead.
- *
- * By default DataTables will look for the property `data` (or `aaData` for
- * compatibility with DataTables 1.9-) when obtaining data from an Ajax
- * source or for server-side processing - this parameter allows that
- * property to be changed. You can use Javascript dotted object notation to
- * get a data source for multiple levels of nesting.
- * @type string
- * @default data
- *
- * @dtopt Options
- * @dtopt Server-side
- * @name DataTable.defaults.ajaxDataProp
- *
- * @deprecated 1.10. Please use `ajax` for this functionality now.
+ * Table and control layout. This replaces the legacy `dom` option.
*/
- "sAjaxDataProp": "data",
-
-
- /**
- * __Deprecated__ The functionality provided by this parameter has now been
- * superseded by that provided through `ajax`, which should be used instead.
- *
- * You can instruct DataTables to load data from an external
- * source using this parameter (use aData if you want to pass data in you
- * already have). Simply provide a url a JSON object can be obtained from.
- * @type string
- * @default null
- *
- * @dtopt Options
- * @dtopt Server-side
- * @name DataTable.defaults.ajaxSource
- *
- * @deprecated 1.10. Please use `ajax` for this functionality now.
- */
- "sAjaxSource": null,
+ layout: {
+ topStart: 'pageLength',
+ topEnd: 'search',
+ bottomStart: 'info',
+ bottomEnd: 'paging'
+ },
/**
- * This initialisation variable allows you to specify exactly where in the
- * DOM you want DataTables to inject the various controls it adds to the page
- * (for example you might want the pagination controls at the top of the
- * table). DIV elements (with or without a custom class) can also be added to
- * aid styling. The follow syntax is used:
- * <ul>
- * <li>The following options are allowed:
- * <ul>
- * <li>'l' - Length changing</li>
- * <li>'f' - Filtering input</li>
- * <li>'t' - The table!</li>
- * <li>'i' - Information</li>
- * <li>'p' - Pagination</li>
- * <li>'r' - pRocessing</li>
- * </ul>
- * </li>
- * <li>The following constants are allowed:
- * <ul>
- * <li>'H' - jQueryUI theme "header" classes ('fg-toolbar ui-widget-header ui-corner-tl ui-corner-tr ui-helper-clearfix')</li>
- * <li>'F' - jQueryUI theme "footer" classes ('fg-toolbar ui-widget-header ui-corner-bl ui-corner-br ui-helper-clearfix')</li>
- * </ul>
- * </li>
- * <li>The following syntax is expected:
- * <ul>
- * <li>'&lt;' and '&gt;' - div elements</li>
- * <li>'&lt;"class" and '&gt;' - div with a class</li>
- * <li>'&lt;"#id" and '&gt;' - div with an ID</li>
- * </ul>
- * </li>
- * <li>Examples:
- * <ul>
- * <li>'&lt;"wrapper"flipt&gt;'</li>
- * <li>'&lt;lf&lt;t&gt;ip&gt;'</li>
- * </ul>
- * </li>
- * </ul>
- * @type string
- * @default lfrtip <i>(when `jQueryUI` is false)</i> <b>or</b>
- * <"H"lfr>t<"F"ip> <i>(when `jQueryUI` is true)</i>
- *
- * @dtopt Options
- * @name DataTable.defaults.dom
- *
- * @example
- * $(document).ready( function() {
- * $('#example').dataTable( {
- * "dom": '&lt;"top"i&gt;rt&lt;"bottom"flp&gt;&lt;"clear"&gt;'
- * } );
- * } );
+ * Legacy DOM layout option
*/
- "sDom": "lfrtip",
+ "sDom": null,
/**
* Search delay option. This will throttle full table searches that use the
* DataTables provided search input element (it does not effect calls to
* `dt-api search()`, providing a delay before the search is made.
- * @type integer
- * @default 0
- *
- * @dtopt Options
- * @name DataTable.defaults.searchDelay
- *
- * @example
- * $(document).ready( function() {
- * $('#example').dataTable( {
- * "searchDelay": 200
- * } );
- * } )
*/
"searchDelay": null,
@@ -12254,22 +10573,8 @@
* * `full` - 'First', 'Previous', 'Next' and 'Last' buttons
* * `full_numbers` - 'First', 'Previous', 'Next' and 'Last' buttons, plus page numbers
* * `first_last_numbers` - 'First' and 'Last' buttons, plus page numbers
- *
- * Further methods can be added using {@link DataTable.ext.oPagination}.
- * @type string
- * @default simple_numbers
- *
- * @dtopt Options
- * @name DataTable.defaults.pagingType
- *
- * @example
- * $(document).ready( function() {
- * $('#example').dataTable( {
- * "pagingType": "full_numbers"
- * } );
- * } )
*/
- "sPaginationType": "simple_numbers",
+ "sPaginationType": "full_numbers",
/**
@@ -12280,19 +10585,6 @@
* scroll horizontally when needed, or any CSS unit, or a number (in which
* case it will be treated as a pixel measurement). Setting as simply `true`
* is recommended.
- * @type boolean|string
- * @default <i>blank string - i.e. disabled</i>
- *
- * @dtopt Features
- * @name DataTable.defaults.scrollX
- *
- * @example
- * $(document).ready( function() {
- * $('#example').dataTable( {
- * "scrollX": true,
- * "scrollCollapse": true
- * } );
- * } );
*/
"sScrollX": "",
@@ -12304,19 +10596,6 @@
* "over-sizing" the table, and thus forcing scrolling. This property can by
* any CSS unit, or a number (in which case it will be treated as a pixel
* measurement).
- * @type string
- * @default <i>blank string - i.e. disabled</i>
- *
- * @dtopt Options
- * @name DataTable.defaults.scrollXInner
- *
- * @example
- * $(document).ready( function() {
- * $('#example').dataTable( {
- * "scrollX": "100%",
- * "scrollXInner": "110%"
- * } );
- * } );
*/
"sScrollXInner": "",
@@ -12328,19 +10607,6 @@
* a lot of data in a small area (although paging and scrolling can both be
* enabled at the same time). This property can be any CSS unit, or a number
* (in which case it will be treated as a pixel measurement).
- * @type string
- * @default <i>blank string - i.e. disabled</i>
- *
- * @dtopt Features
- * @name DataTable.defaults.scrollY
- *
- * @example
- * $(document).ready( function() {
- * $('#example').dataTable( {
- * "scrollY": "200px",
- * "paginate": false
- * } );
- * } );
*/
"sScrollY": "",
@@ -12351,14 +10617,6 @@
*
* Set the HTTP method that is used to make the Ajax call for server-side
* processing or Ajax sourced data.
- * @type string
- * @default GET
- *
- * @dtopt Options
- * @dtopt Server-side
- * @name DataTable.defaults.serverMethod
- *
- * @deprecated 1.10. Please use `ajax` for this functionality now.
*/
"sServerMethod": "GET",
@@ -12372,11 +10630,6 @@
*
* For further information about the renderers available see
* DataTable.ext.renderer
- * @type string|object
- * @default null
- *
- * @name DataTable.defaults.renderer
- *
*/
"renderer": null,
@@ -12384,12 +10637,14 @@
/**
* Set the data property name that DataTables should use to get a row's id
* to set as the `id` property in the node.
- * @type string
- * @default DT_RowId
- *
- * @name DataTable.defaults.rowId
*/
- "rowId": "DT_RowId"
+ "rowId": "DT_RowId",
+
+
+ /**
+ * Caption value
+ */
+ "caption": null
};
_fnHungarianMap( DataTable.defaults );
@@ -12412,176 +10667,35 @@
* doing a sort or use the data from a different column. For example first
* name / last name columns make sense to do a multi-column sort over the
* two columns.
- * @type array|int
- * @default null <i>Takes the value of the column index automatically</i>
- *
- * @name DataTable.defaults.column.orderData
- * @dtopt Columns
- *
- * @example
- * // Using `columnDefs`
- * $(document).ready( function() {
- * $('#example').dataTable( {
- * "columnDefs": [
- * { "orderData": [ 0, 1 ], "targets": [ 0 ] },
- * { "orderData": [ 1, 0 ], "targets": [ 1 ] },
- * { "orderData": 2, "targets": [ 2 ] }
- * ]
- * } );
- * } );
- *
- * @example
- * // Using `columns`
- * $(document).ready( function() {
- * $('#example').dataTable( {
- * "columns": [
- * { "orderData": [ 0, 1 ] },
- * { "orderData": [ 1, 0 ] },
- * { "orderData": 2 },
- * null,
- * null
- * ]
- * } );
- * } );
*/
"aDataSort": null,
"iDataSort": -1,
+ ariaTitle: '',
+
/**
* You can control the default ordering direction, and even alter the
* behaviour of the sort handler (i.e. only allow ascending ordering etc)
* using this parameter.
- * @type array
- * @default [ 'asc', 'desc' ]
- *
- * @name DataTable.defaults.column.orderSequence
- * @dtopt Columns
- *
- * @example
- * // Using `columnDefs`
- * $(document).ready( function() {
- * $('#example').dataTable( {
- * "columnDefs": [
- * { "orderSequence": [ "asc" ], "targets": [ 1 ] },
- * { "orderSequence": [ "desc", "asc", "asc" ], "targets": [ 2 ] },
- * { "orderSequence": [ "desc" ], "targets": [ 3 ] }
- * ]
- * } );
- * } );
- *
- * @example
- * // Using `columns`
- * $(document).ready( function() {
- * $('#example').dataTable( {
- * "columns": [
- * null,
- * { "orderSequence": [ "asc" ] },
- * { "orderSequence": [ "desc", "asc", "asc" ] },
- * { "orderSequence": [ "desc" ] },
- * null
- * ]
- * } );
- * } );
*/
- "asSorting": [ 'asc', 'desc' ],
+ "asSorting": [ 'asc', 'desc', '' ],
/**
* Enable or disable filtering on the data in this column.
- * @type boolean
- * @default true
- *
- * @name DataTable.defaults.column.searchable
- * @dtopt Columns
- *
- * @example
- * // Using `columnDefs`
- * $(document).ready( function() {
- * $('#example').dataTable( {
- * "columnDefs": [
- * { "searchable": false, "targets": [ 0 ] }
- * ] } );
- * } );
- *
- * @example
- * // Using `columns`
- * $(document).ready( function() {
- * $('#example').dataTable( {
- * "columns": [
- * { "searchable": false },
- * null,
- * null,
- * null,
- * null
- * ] } );
- * } );
*/
"bSearchable": true,
/**
* Enable or disable ordering on this column.
- * @type boolean
- * @default true
- *
- * @name DataTable.defaults.column.orderable
- * @dtopt Columns
- *
- * @example
- * // Using `columnDefs`
- * $(document).ready( function() {
- * $('#example').dataTable( {
- * "columnDefs": [
- * { "orderable": false, "targets": [ 0 ] }
- * ] } );
- * } );
- *
- * @example
- * // Using `columns`
- * $(document).ready( function() {
- * $('#example').dataTable( {
- * "columns": [
- * { "orderable": false },
- * null,
- * null,
- * null,
- * null
- * ] } );
- * } );
*/
"bSortable": true,
/**
* Enable or disable the display of this column.
- * @type boolean
- * @default true
- *
- * @name DataTable.defaults.column.visible
- * @dtopt Columns
- *
- * @example
- * // Using `columnDefs`
- * $(document).ready( function() {
- * $('#example').dataTable( {
- * "columnDefs": [
- * { "visible": false, "targets": [ 0 ] }
- * ] } );
- * } );
- *
- * @example
- * // Using `columns`
- * $(document).ready( function() {
- * $('#example').dataTable( {
- * "columns": [
- * { "visible": false },
- * null,
- * null,
- * null,
- * null
- * ] } );
- * } );
*/
"bVisible": true,
@@ -12591,43 +10705,11 @@
* etc) or processed for input (DOM source). This can be used as a compliment to mRender
* allowing you to modify the DOM element (add background colour for example) when the
* element is available.
- * @type function
- * @param {element} td The TD node that has been created
- * @param {*} cellData The Data for the cell
- * @param {array|object} rowData The data for the whole row
- * @param {int} row The row index for the aoData data store
- * @param {int} col The column index for aoColumns
- *
- * @name DataTable.defaults.column.createdCell
- * @dtopt Columns
- *
- * @example
- * $(document).ready( function() {
- * $('#example').dataTable( {
- * "columnDefs": [ {
- * "targets": [3],
- * "createdCell": function (td, cellData, rowData, row, col) {
- * if ( cellData == "1.7" ) {
- * $(td).css('color', 'blue')
- * }
- * }
- * } ]
- * });
- * } );
*/
"fnCreatedCell": null,
/**
- * This parameter has been replaced by `data` in DataTables to ensure naming
- * consistency. `dataProp` can still be used, as there is backwards
- * compatibility in DataTables for this option, but it is strongly
- * recommended that you use `data` in preference to `dataProp`.
- * @name DataTable.defaults.column.dataProp
- */
-
-
- /**
* This property can be used to read data from any data source property,
* including deeply nested objects / properties. `data` can be given in a
* number of different ways which effect its behaviour:
@@ -12688,113 +10770,6 @@
* with the naming of mRender. If 'mDataProp' is given, then it will still
* be used by DataTables, as it automatically maps the old name to the new
* if required.
- *
- * @type string|int|function|null
- * @default null <i>Use automatically calculated column index</i>
- *
- * @name DataTable.defaults.column.data
- * @dtopt Columns
- *
- * @example
- * // Read table data from objects
- * // JSON structure for each row:
- * // {
- * // "engine": {value},
- * // "browser": {value},
- * // "platform": {value},
- * // "version": {value},
- * // "grade": {value}
- * // }
- * $(document).ready( function() {
- * $('#example').dataTable( {
- * "ajaxSource": "sources/objects.txt",
- * "columns": [
- * { "data": "engine" },
- * { "data": "browser" },
- * { "data": "platform" },
- * { "data": "version" },
- * { "data": "grade" }
- * ]
- * } );
- * } );
- *
- * @example
- * // Read information from deeply nested objects
- * // JSON structure for each row:
- * // {
- * // "engine": {value},
- * // "browser": {value},
- * // "platform": {
- * // "inner": {value}
- * // },
- * // "details": [
- * // {value}, {value}
- * // ]
- * // }
- * $(document).ready( function() {
- * $('#example').dataTable( {
- * "ajaxSource": "sources/deep.txt",
- * "columns": [
- * { "data": "engine" },
- * { "data": "browser" },
- * { "data": "platform.inner" },
- * { "data": "details.0" },
- * { "data": "details.1" }
- * ]
- * } );
- * } );
- *
- * @example
- * // Using `data` as a function to provide different information for
- * // sorting, filtering and display. In this case, currency (price)
- * $(document).ready( function() {
- * $('#example').dataTable( {
- * "columnDefs": [ {
- * "targets": [ 0 ],
- * "data": function ( source, type, val ) {
- * if (type === 'set') {
- * source.price = val;
- * // Store the computed display and filter values for efficiency
- * source.price_display = val=="" ? "" : "$"+numberFormat(val);
- * source.price_filter = val=="" ? "" : "$"+numberFormat(val)+" "+val;
- * return;
- * }
- * else if (type === 'display') {
- * return source.price_display;
- * }
- * else if (type === 'filter') {
- * return source.price_filter;
- * }
- * // 'sort', 'type' and undefined all just use the integer
- * return source.price;
- * }
- * } ]
- * } );
- * } );
- *
- * @example
- * // Using default content
- * $(document).ready( function() {
- * $('#example').dataTable( {
- * "columnDefs": [ {
- * "targets": [ 0 ],
- * "data": null,
- * "defaultContent": "Click to edit"
- * } ]
- * } );
- * } );
- *
- * @example
- * // Using array notation - outputting a list from an array
- * $(document).ready( function() {
- * $('#example').dataTable( {
- * "columnDefs": [ {
- * "targets": [ 0 ],
- * "data": "name[, ]"
- * } ]
- * } );
- * } );
- *
*/
"mData": null,
@@ -12848,75 +10823,6 @@
* * Return:
* * The return value from the function is what will be used for the
* data requested.
- *
- * @type string|int|function|object|null
- * @default null Use the data source value.
- *
- * @name DataTable.defaults.column.render
- * @dtopt Columns
- *
- * @example
- * // Create a comma separated list from an array of objects
- * $(document).ready( function() {
- * $('#example').dataTable( {
- * "ajaxSource": "sources/deep.txt",
- * "columns": [
- * { "data": "engine" },
- * { "data": "browser" },
- * {
- * "data": "platform",
- * "render": "[, ].name"
- * }
- * ]
- * } );
- * } );
- *
- * @example
- * // Execute a function to obtain data
- * $(document).ready( function() {
- * $('#example').dataTable( {
- * "columnDefs": [ {
- * "targets": [ 0 ],
- * "data": null, // Use the full data source object for the renderer's source
- * "render": "browserName()"
- * } ]
- * } );
- * } );
- *
- * @example
- * // As an object, extracting different data for the different types
- * // This would be used with a data source such as:
- * // { "phone": 5552368, "phone_filter": "5552368 555-2368", "phone_display": "555-2368" }
- * // Here the `phone` integer is used for sorting and type detection, while `phone_filter`
- * // (which has both forms) is used for filtering for if a user inputs either format, while
- * // the formatted phone number is the one that is shown in the table.
- * $(document).ready( function() {
- * $('#example').dataTable( {
- * "columnDefs": [ {
- * "targets": [ 0 ],
- * "data": null, // Use the full data source object for the renderer's source
- * "render": {
- * "_": "phone",
- * "filter": "phone_filter",
- * "display": "phone_display"
- * }
- * } ]
- * } );
- * } );
- *
- * @example
- * // Use as a function to create a link from the data source
- * $(document).ready( function() {
- * $('#example').dataTable( {
- * "columnDefs": [ {
- * "targets": [ 0 ],
- * "data": "download_link",
- * "render": function ( data, type, full ) {
- * return '<a href="'+data+'">Download</a>';
- * }
- * } ]
- * } );
- * } );
*/
"mRender": null,
@@ -12925,57 +10831,12 @@
* Change the cell type created for the column - either TD cells or TH cells. This
* can be useful as TH cells have semantic meaning in the table body, allowing them
* to act as a header for a row (you may wish to add scope='row' to the TH elements).
- * @type string
- * @default td
- *
- * @name DataTable.defaults.column.cellType
- * @dtopt Columns
- *
- * @example
- * // Make the first column use TH cells
- * $(document).ready( function() {
- * $('#example').dataTable( {
- * "columnDefs": [ {
- * "targets": [ 0 ],
- * "cellType": "th"
- * } ]
- * } );
- * } );
*/
"sCellType": "td",
/**
* Class to give to each cell in this column.
- * @type string
- * @default <i>Empty string</i>
- *
- * @name DataTable.defaults.column.class
- * @dtopt Columns
- *
- * @example
- * // Using `columnDefs`
- * $(document).ready( function() {
- * $('#example').dataTable( {
- * "columnDefs": [
- * { "class": "my_class", "targets": [ 0 ] }
- * ]
- * } );
- * } );
- *
- * @example
- * // Using `columns`
- * $(document).ready( function() {
- * $('#example').dataTable( {
- * "columns": [
- * { "class": "my_class" },
- * null,
- * null,
- * null,
- * null
- * ]
- * } );
- * } );
*/
"sClass": "",
@@ -12989,26 +10850,6 @@
* a "work around" we provide this option. It will append its value to the
* text that is found to be the longest string for the column - i.e. padding.
* Generally you shouldn't need this!
- * @type string
- * @default <i>Empty string<i>
- *
- * @name DataTable.defaults.column.contentPadding
- * @dtopt Columns
- *
- * @example
- * // Using `columns`
- * $(document).ready( function() {
- * $('#example').dataTable( {
- * "columns": [
- * null,
- * null,
- * null,
- * {
- * "contentPadding": "mmm"
- * }
- * ]
- * } );
- * } );
*/
"sContentPadding": "",
@@ -13017,41 +10858,6 @@
* Allows a default value to be given for a column's data, and will be used
* whenever a null data source is encountered (this can be because `data`
* is set to null, or because the data source itself is null).
- * @type string
- * @default null
- *
- * @name DataTable.defaults.column.defaultContent
- * @dtopt Columns
- *
- * @example
- * // Using `columnDefs`
- * $(document).ready( function() {
- * $('#example').dataTable( {
- * "columnDefs": [
- * {
- * "data": null,
- * "defaultContent": "Edit",
- * "targets": [ -1 ]
- * }
- * ]
- * } );
- * } );
- *
- * @example
- * // Using `columns`
- * $(document).ready( function() {
- * $('#example').dataTable( {
- * "columns": [
- * null,
- * null,
- * null,
- * {
- * "data": null,
- * "defaultContent": "Edit"
- * }
- * ]
- * } );
- * } );
*/
"sDefaultContent": null,
@@ -13063,39 +10869,6 @@
* also allow DataTables to reorder information from the server if it comes
* back in an unexpected order (i.e. if you switch your columns around on the
* client-side, your server-side code does not also need updating).
- * @type string
- * @default <i>Empty string</i>
- *
- * @name DataTable.defaults.column.name
- * @dtopt Columns
- *
- * @example
- * // Using `columnDefs`
- * $(document).ready( function() {
- * $('#example').dataTable( {
- * "columnDefs": [
- * { "name": "engine", "targets": [ 0 ] },
- * { "name": "browser", "targets": [ 1 ] },
- * { "name": "platform", "targets": [ 2 ] },
- * { "name": "version", "targets": [ 3 ] },
- * { "name": "grade", "targets": [ 4 ] }
- * ]
- * } );
- * } );
- *
- * @example
- * // Using `columns`
- * $(document).ready( function() {
- * $('#example').dataTable( {
- * "columns": [
- * { "name": "engine" },
- * { "name": "browser" },
- * { "name": "platform" },
- * { "name": "version" },
- * { "name": "grade" }
- * ]
- * } );
- * } );
*/
"sName": "",
@@ -13105,75 +10878,12 @@
* real-time information from the table (updating the internally cached
* version) prior to ordering. This allows ordering to occur on user
* editable elements such as form inputs.
- * @type string
- * @default std
- *
- * @name DataTable.defaults.column.orderDataType
- * @dtopt Columns
- *
- * @example
- * // Using `columnDefs`
- * $(document).ready( function() {
- * $('#example').dataTable( {
- * "columnDefs": [
- * { "orderDataType": "dom-text", "targets": [ 2, 3 ] },
- * { "type": "numeric", "targets": [ 3 ] },
- * { "orderDataType": "dom-select", "targets": [ 4 ] },
- * { "orderDataType": "dom-checkbox", "targets": [ 5 ] }
- * ]
- * } );
- * } );
- *
- * @example
- * // Using `columns`
- * $(document).ready( function() {
- * $('#example').dataTable( {
- * "columns": [
- * null,
- * null,
- * { "orderDataType": "dom-text" },
- * { "orderDataType": "dom-text", "type": "numeric" },
- * { "orderDataType": "dom-select" },
- * { "orderDataType": "dom-checkbox" }
- * ]
- * } );
- * } );
*/
"sSortDataType": "std",
/**
* The title of this column.
- * @type string
- * @default null <i>Derived from the 'TH' value for this column in the
- * original HTML table.</i>
- *
- * @name DataTable.defaults.column.title
- * @dtopt Columns
- *
- * @example
- * // Using `columnDefs`
- * $(document).ready( function() {
- * $('#example').dataTable( {
- * "columnDefs": [
- * { "title": "My column title", "targets": [ 0 ] }
- * ]
- * } );
- * } );
- *
- * @example
- * // Using `columns`
- * $(document).ready( function() {
- * $('#example').dataTable( {
- * "columns": [
- * { "title": "My column title" },
- * null,
- * null,
- * null,
- * null
- * ]
- * } );
- * } );
*/
"sTitle": null,
@@ -13186,35 +10896,6 @@
* date. For example: "Mar 26, 2008 5:03 PM". May take the values: 'string',
* 'numeric', 'date' or 'html' (by default). Further types can be adding
* through plug-ins.
- * @type string
- * @default null <i>Auto-detected from raw data</i>
- *
- * @name DataTable.defaults.column.type
- * @dtopt Columns
- *
- * @example
- * // Using `columnDefs`
- * $(document).ready( function() {
- * $('#example').dataTable( {
- * "columnDefs": [
- * { "type": "html", "targets": [ 0 ] }
- * ]
- * } );
- * } );
- *
- * @example
- * // Using `columns`
- * $(document).ready( function() {
- * $('#example').dataTable( {
- * "columns": [
- * { "type": "html" },
- * null,
- * null,
- * null,
- * null
- * ]
- * } );
- * } );
*/
"sType": null,
@@ -13224,35 +10905,6 @@
* (3em, 20px etc). DataTables applies 'smart' widths to columns which have not
* been given a specific width through this interface ensuring that the table
* remains readable.
- * @type string
- * @default null <i>Automatic</i>
- *
- * @name DataTable.defaults.column.width
- * @dtopt Columns
- *
- * @example
- * // Using `columnDefs`
- * $(document).ready( function() {
- * $('#example').dataTable( {
- * "columnDefs": [
- * { "width": "20%", "targets": [ 0 ] }
- * ]
- * } );
- * } );
- *
- * @example
- * // Using `columns`
- * $(document).ready( function() {
- * $('#example').dataTable( {
- * "columns": [
- * { "width": "20%" },
- * null,
- * null,
- * null,
- * null
- * ]
- * } );
- * } );
*/
"sWidth": null
};
@@ -13274,19 +10926,10 @@
* one is the internal data store for DataTables's cache of columns. It should
* NOT be manipulated outside of DataTables. Any configuration should be done
* through the initialisation options.
- * @namespace
- * @todo Really should attach the settings object to individual instances so we
- * don't need to create new instances on each $().dataTable() call (if the
- * table already exists). It would also save passing oSettings around and
- * into every single function. However, this is a very significant
- * architecture change for DataTables and will almost certainly break
- * backwards compatibility with older installations. This is something that
- * will be done in 2.0.
*/
DataTable.models.oSettings = {
/**
* Primary features of DataTables and their enablement state.
- * @namespace
*/
"oFeatures": {
@@ -13295,7 +10938,6 @@
* optimum table and columns widths (true) or not (false).
* Note that this parameter will be set by the initialisation routine. To
* set a default use {@link DataTable.defaults}.
- * @type boolean
*/
"bAutoWidth": null,
@@ -13306,7 +10948,6 @@
* difference at all for DOM and server-side processing tables.
* Note that this parameter will be set by the initialisation routine. To
* set a default use {@link DataTable.defaults}.
- * @type boolean
*/
"bDeferRender": null,
@@ -13316,34 +10957,26 @@
* To just remove the filtering input use sDom and remove the 'f' option.
* Note that this parameter will be set by the initialisation routine. To
* set a default use {@link DataTable.defaults}.
- * @type boolean
*/
"bFilter": null,
/**
- * Table information element (the 'Showing x of y records' div) enable
- * flag.
- * Note that this parameter will be set by the initialisation routine. To
- * set a default use {@link DataTable.defaults}.
- * @type boolean
+ * Used only for compatiblity with DT1
+ * @deprecated
*/
- "bInfo": null,
+ "bInfo": true,
/**
- * Present a user control allowing the end user to change the page size
- * when pagination is enabled.
- * Note that this parameter will be set by the initialisation routine. To
- * set a default use {@link DataTable.defaults}.
- * @type boolean
+ * Used only for compatiblity with DT1
+ * @deprecated
*/
- "bLengthChange": null,
+ "bLengthChange": true,
/**
* Pagination enabled or not. Note that if this is disabled then length
* changing must also be disabled.
* Note that this parameter will be set by the initialisation routine. To
* set a default use {@link DataTable.defaults}.
- * @type boolean
*/
"bPaginate": null,
@@ -13352,7 +10985,6 @@
* user request - typically an Ajax request for server-side processing.
* Note that this parameter will be set by the initialisation routine. To
* set a default use {@link DataTable.defaults}.
- * @type boolean
*/
"bProcessing": null,
@@ -13362,7 +10994,6 @@
* sorting or paging done on the client-side.
* Note that this parameter will be set by the initialisation routine. To
* set a default use {@link DataTable.defaults}.
- * @type boolean
*/
"bServerSide": null,
@@ -13370,7 +11001,6 @@
* Sorting enablement flag.
* Note that this parameter will be set by the initialisation routine. To
* set a default use {@link DataTable.defaults}.
- * @type boolean
*/
"bSort": null,
@@ -13378,7 +11008,6 @@
* Multi-column sorting
* Note that this parameter will be set by the initialisation routine. To
* set a default use {@link DataTable.defaults}.
- * @type boolean
*/
"bSortMulti": null,
@@ -13388,7 +11017,6 @@
* there is a lot of DOM interaction.
* Note that this parameter will be set by the initialisation routine. To
* set a default use {@link DataTable.defaults}.
- * @type boolean
*/
"bSortClasses": null,
@@ -13396,7 +11024,6 @@
* State saving enablement flag.
* Note that this parameter will be set by the initialisation routine. To
* set a default use {@link DataTable.defaults}.
- * @type boolean
*/
"bStateSave": null
},
@@ -13404,7 +11031,6 @@
/**
* Scrolling settings for a table.
- * @namespace
*/
"oScroll": {
/**
@@ -13412,15 +11038,12 @@
* table container down to the height of the table (when true).
* Note that this parameter will be set by the initialisation routine. To
* set a default use {@link DataTable.defaults}.
- * @type boolean
*/
"bCollapse": null,
/**
* Width of the scrollbar for the web-browser's platform. Calculated
* during table initialisation.
- * @type int
- * @default 0
*/
"iBarWidth": 0,
@@ -13429,7 +11052,6 @@
* disabled if an empty string.
* Note that this parameter will be set by the initialisation routine. To
* set a default use {@link DataTable.defaults}.
- * @type string
*/
"sX": null,
@@ -13438,7 +11060,6 @@
* should not need to use this.
* Note that this parameter will be set by the initialisation routine. To
* set a default use {@link DataTable.defaults}.
- * @type string
* @deprecated
*/
"sXInner": null,
@@ -13448,59 +11069,34 @@
* if an empty string.
* Note that this parameter will be set by the initialisation routine. To
* set a default use {@link DataTable.defaults}.
- * @type string
*/
"sY": null
},
/**
* Language information for the table.
- * @namespace
- * @extends DataTable.defaults.oLanguage
*/
"oLanguage": {
/**
* Information callback function. See
* {@link DataTable.defaults.fnInfoCallback}
- * @type function
- * @default null
*/
"fnInfoCallback": null
},
/**
* Browser support parameters
- * @namespace
*/
"oBrowser": {
/**
- * Indicate if the browser incorrectly calculates width:100% inside a
- * scrolling element (IE6/7)
- * @type boolean
- * @default false
- */
- "bScrollOversize": false,
-
- /**
* Determine if the vertical scrollbar is on the right or left of the
* scrolling container - needed for rtl language layout, although not
* all browsers move the scrollbar (Safari).
- * @type boolean
- * @default false
*/
"bScrollbarLeft": false,
/**
- * Flag for if `getBoundingClientRect` is fully supported or not
- * @type boolean
- * @default false
- */
- "bBounding": false,
-
- /**
* Browser scrollbar width
- * @type integer
- * @default 0
*/
"barWidth": 0
},
@@ -13520,58 +11116,42 @@
* <li>'p' - Pagination</li>
* <li>'r' - pRocessing</li>
* </ul>
- * @type array
- * @default []
*/
"aanFeatures": [],
/**
* Store data information - see {@link DataTable.models.oRow} for detailed
* information.
- * @type array
- * @default []
*/
"aoData": [],
/**
* Array of indexes which are in the current display (after filtering etc)
- * @type array
- * @default []
*/
"aiDisplay": [],
/**
* Array of indexes for display - no filtering
- * @type array
- * @default []
*/
"aiDisplayMaster": [],
/**
* Map of row ids to data indexes
- * @type object
- * @default {}
*/
"aIds": {},
/**
* Store information about each column that is in use
- * @type array
- * @default []
*/
"aoColumns": [],
/**
* Store information about the table's header
- * @type array
- * @default []
*/
"aoHeader": [],
/**
* Store information about the table's footer
- * @type array
- * @default []
*/
"aoFooter": [],
@@ -13580,17 +11160,18 @@
* research or compare the old search to a new one.
* Note that this parameter will be set by the initialisation routine. To
* set a default use {@link DataTable.defaults}.
- * @namespace
- * @extends DataTable.models.oSearch
*/
"oPreviousSearch": {},
/**
+ * Store for named searches
+ */
+ searchFixed: {},
+
+ /**
* Store the applied search for each column - see
* {@link DataTable.models.oSearch} for the format that is used for the
* filtering information for each column.
- * @type array
- * @default []
*/
"aoPreSearchCols": [],
@@ -13603,8 +11184,6 @@
* </ul>
* Note that this parameter will be set by the initialisation routine. To
* set a default use {@link DataTable.defaults}.
- * @type array
- * @todo These inner arrays should really be objects
*/
"aaSorting": null,
@@ -13613,81 +11192,47 @@
* aaSorting).
* Note that this parameter will be set by the initialisation routine. To
* set a default use {@link DataTable.defaults}.
- * @type array
- * @default []
*/
"aaSortingFixed": [],
/**
- * Classes to use for the striping of a table.
- * Note that this parameter will be set by the initialisation routine. To
- * set a default use {@link DataTable.defaults}.
- * @type array
- * @default []
- */
- "asStripeClasses": null,
-
- /**
- * If restoring a table - we should restore its striping classes as well
- * @type array
- * @default []
- */
- "asDestroyStripes": [],
-
- /**
* If restoring a table - we should restore its width
- * @type int
- * @default 0
*/
"sDestroyWidth": 0,
/**
* Callback functions array for every time a row is inserted (i.e. on a draw).
- * @type array
- * @default []
*/
"aoRowCallback": [],
/**
* Callback functions for the header on each draw.
- * @type array
- * @default []
*/
"aoHeaderCallback": [],
/**
* Callback function for the footer on each draw.
- * @type array
- * @default []
*/
"aoFooterCallback": [],
/**
* Array of callback functions for draw callback functions
- * @type array
- * @default []
*/
"aoDrawCallback": [],
/**
* Array of callback functions for row created function
- * @type array
- * @default []
*/
"aoRowCreatedCallback": [],
/**
* Callback functions for just before the table is redrawn. A return of
* false will be used to cancel the draw.
- * @type array
- * @default []
*/
"aoPreDrawCallback": [],
/**
* Callback functions for when the table has been initialised.
- * @type array
- * @default []
*/
"aoInitComplete": [],
@@ -13695,91 +11240,59 @@
/**
* Callbacks for modifying the settings to be stored for state saving, prior to
* saving state.
- * @type array
- * @default []
*/
"aoStateSaveParams": [],
/**
* Callbacks for modifying the settings that have been stored for state saving
* prior to using the stored values to restore the state.
- * @type array
- * @default []
*/
"aoStateLoadParams": [],
/**
* Callbacks for operating on the settings object once the saved state has been
* loaded
- * @type array
- * @default []
*/
"aoStateLoaded": [],
/**
* Cache the table ID for quick access
- * @type string
- * @default <i>Empty string</i>
*/
"sTableId": "",
/**
* The TABLE node for the main table
- * @type node
- * @default null
*/
"nTable": null,
/**
* Permanent ref to the thead element
- * @type node
- * @default null
*/
"nTHead": null,
/**
* Permanent ref to the tfoot element - if it exists
- * @type node
- * @default null
*/
"nTFoot": null,
/**
* Permanent ref to the tbody element
- * @type node
- * @default null
*/
"nTBody": null,
/**
* Cache the wrapper node (contains all DataTables controlled elements)
- * @type node
- * @default null
*/
"nTableWrapper": null,
/**
- * Indicate if when using server-side processing the loading of data
- * should be deferred until the second draw.
- * Note that this parameter will be set by the initialisation routine. To
- * set a default use {@link DataTable.defaults}.
- * @type boolean
- * @default false
- */
- "bDeferLoading": false,
-
- /**
* Indicate if all required information has been read in
- * @type boolean
- * @default false
*/
"bInitialised": false,
/**
* Information about open rows. Each object in the array has the parameters
* 'nTr' and 'nParent'
- * @type array
- * @default []
*/
"aoOpenRows": [],
@@ -13788,15 +11301,11 @@
* {@link DataTable.model.oInit.sDom}.
* Note that this parameter will be set by the initialisation routine. To
* set a default use {@link DataTable.defaults}.
- * @type string
- * @default null
*/
"sDom": null,
/**
* Search delay (in mS)
- * @type integer
- * @default null
*/
"searchDelay": null,
@@ -13804,17 +11313,18 @@
* Which type of pagination should be used.
* Note that this parameter will be set by the initialisation routine. To
* set a default use {@link DataTable.defaults}.
- * @type string
- * @default two_button
*/
"sPaginationType": "two_button",
/**
+ * Number of paging controls on the page. Only used for backwards compatibility
+ */
+ pagingControls: 0,
+
+ /**
* The state duration (for `stateSave`) in seconds.
* Note that this parameter will be set by the initialisation routine. To
* set a default use {@link DataTable.defaults}.
- * @type int
- * @default 0
*/
"iStateDuration": 0,
@@ -13828,8 +11338,6 @@
* (i.e. '"param": [ 0, 1, 2]')</li>
* <li>string:sName - name of callback</li>
* </ul>
- * @type array
- * @default []
*/
"aoStateSave": [],
@@ -13841,89 +11349,46 @@
* and the object stored. May return false to cancel state loading</li>
* <li>string:sName - name of callback</li>
* </ul>
- * @type array
- * @default []
*/
"aoStateLoad": [],
/**
* State that was saved. Useful for back reference
- * @type object
- * @default null
*/
"oSavedState": null,
/**
* State that was loaded. Useful for back reference
- * @type object
- * @default null
*/
"oLoadedState": null,
/**
- * Source url for AJAX data for the table.
- * Note that this parameter will be set by the initialisation routine. To
- * set a default use {@link DataTable.defaults}.
- * @type string
- * @default null
- */
- "sAjaxSource": null,
-
- /**
- * Property from a given object from which to read the table data from. This
- * can be an empty string (when not server-side processing), in which case
- * it is assumed an an array is given directly.
- * Note that this parameter will be set by the initialisation routine. To
- * set a default use {@link DataTable.defaults}.
- * @type string
+ * Note if draw should be blocked while getting data
*/
- "sAjaxDataProp": null,
+ "bAjaxDataGet": true,
/**
* The last jQuery XHR object that was used for server-side data gathering.
* This can be used for working with the XHR information in one of the
* callbacks
- * @type object
- * @default null
*/
"jqXHR": null,
/**
* JSON returned from the server in the last Ajax request
- * @type object
- * @default undefined
*/
"json": undefined,
/**
* Data submitted as part of the last Ajax request
- * @type object
- * @default undefined
*/
"oAjaxData": undefined,
/**
- * Function to get the server-side data.
- * Note that this parameter will be set by the initialisation routine. To
- * set a default use {@link DataTable.defaults}.
- * @type function
- */
- "fnServerData": null,
-
- /**
- * Functions which are called prior to sending an Ajax request so extra
- * parameters can easily be sent to the server
- * @type array
- * @default []
- */
- "aoServerParams": [],
-
- /**
* Send the XHR HTTP method - GET or POST (could be PUT or DELETE if
* required).
* Note that this parameter will be set by the initialisation routine. To
* set a default use {@link DataTable.defaults}.
- * @type string
*/
"sServerMethod": null,
@@ -13931,7 +11396,6 @@
* Format numbers for display.
* Note that this parameter will be set by the initialisation routine. To
* set a default use {@link DataTable.defaults}.
- * @type function
*/
"fnFormatNumber": null,
@@ -13939,44 +11403,32 @@
* List of options that can be used for the user selectable length menu.
* Note that this parameter will be set by the initialisation routine. To
* set a default use {@link DataTable.defaults}.
- * @type array
- * @default []
*/
"aLengthMenu": null,
/**
* Counter for the draws that the table does. Also used as a tracker for
* server-side processing
- * @type int
- * @default 0
*/
"iDraw": 0,
/**
* Indicate if a redraw is being done - useful for Ajax
- * @type boolean
- * @default false
*/
"bDrawing": false,
/**
* Draw index (iDraw) of the last error when parsing the returned data
- * @type int
- * @default -1
*/
"iDrawError": -1,
/**
* Paging display length
- * @type int
- * @default 10
*/
"_iDisplayLength": 10,
/**
* Paging start point - aiDisplay index
- * @type int
- * @default 0
*/
"_iDisplayStart": 0,
@@ -13985,9 +11437,6 @@
* (i.e. before filtering), Use fnRecordsTotal rather than
* this property to get the value of the number of records, regardless of
* the server-side processing setting.
- * @type int
- * @default 0
- * @private
*/
"_iRecordsTotal": 0,
@@ -13996,16 +11445,11 @@
* (i.e. after filtering). Use fnRecordsDisplay rather than
* this property to get the value of the number of records, regardless of
* the server-side processing setting.
- * @type boolean
- * @default 0
- * @private
*/
"_iRecordsDisplay": 0,
/**
* The classes to use for the table
- * @type object
- * @default {}
*/
"oClasses": {},
@@ -14013,8 +11457,6 @@
* Flag attached to the settings object so you can check in the draw
* callback if filtering has been done in the draw. Deprecated in favour of
* events.
- * @type boolean
- * @default false
* @deprecated
*/
"bFiltered": false,
@@ -14023,8 +11465,6 @@
* Flag attached to the settings object so you can check in the draw
* callback if sorting has been done in the draw. Deprecated in favour of
* events.
- * @type boolean
- * @default false
* @deprecated
*/
"bSorted": false,
@@ -14035,29 +11475,23 @@
* should be used for sorting / title by DataTables.
* Note that this parameter will be set by the initialisation routine. To
* set a default use {@link DataTable.defaults}.
- * @type boolean
*/
"bSortCellsTop": null,
/**
* Initialisation object that is used for the table
- * @type object
- * @default null
*/
"oInit": null,
/**
* Destroy callback functions - for plug-ins to attach themselves to the
* destroy so they can clean up markup and events.
- * @type array
- * @default []
*/
"aoDestroyCallback": [],
/**
* Get the number of records in the current record set, before filtering
- * @type function
*/
"fnRecordsTotal": function ()
{
@@ -14068,7 +11502,6 @@
/**
* Get the number of records in the current record set, after filtering
- * @type function
*/
"fnRecordsDisplay": function ()
{
@@ -14079,7 +11512,6 @@
/**
* Get the display end point - aiDisplay index
- * @type function
*/
"fnDisplayEnd": function ()
{
@@ -14105,8 +11537,6 @@
/**
* The DataTables object for this table
- * @type object
- * @default null
*/
"oInstance": null,
@@ -14114,8 +11544,6 @@
* Unique identifier for each instance of the DataTables object. If there
* is an ID on the table node, then it takes that value, otherwise an
* incrementing internal counter is used.
- * @type string
- * @default null
*/
"sInstance": null,
@@ -14137,31 +11565,29 @@
/**
* Last applied sort
- * @type array
- * @default []
*/
"aLastSort": [],
/**
* Stored plug-in instances
- * @type object
- * @default {}
*/
"oPlugins": {},
/**
* Function used to get a row's id from the row's data
- * @type function
- * @default null
*/
"rowIdFn": null,
/**
* Data location where to store a row's id
- * @type string
- * @default null
*/
- "rowId": null
+ "rowId": null,
+
+ caption: '',
+
+ captionNode: null,
+
+ colgroup: null
};
/**
@@ -14215,7 +11641,7 @@
*
* @type string
*/
- build:"bs5/dt-1.13.6",
+ build:"bs5/dt-2.0.0",
/**
@@ -14231,43 +11657,17 @@
/**
+ * Legacy so v1 plug-ins don't throw js errors on load
+ */
+ feature: [],
+
+ /**
* Feature plug-ins.
*
- * This is an array of objects which describe the feature plug-ins that are
- * available to DataTables. These feature plug-ins are then available for
- * use through the `dom` initialisation option.
- *
- * Each feature plug-in is described by an object which must have the
- * following properties:
- *
- * * `fnInit` - function that is used to initialise the plug-in,
- * * `cFeature` - a character so the feature can be enabled by the `dom`
- * instillation option. This is case sensitive.
- *
- * The `fnInit` function has the following input parameters:
- *
- * 1. `{object}` DataTables settings object: see
- * {@link DataTable.models.oSettings}
- *
- * And the following return is expected:
- *
- * * {node|null} The element which contains your feature. Note that the
- * return may also be void if your plug-in does not require to inject any
- * DOM elements into DataTables control (`dom`) - for example this might
- * be useful when developing a plug-in which allows table control via
- * keyboard entry
- *
- * @type array
- *
- * @example
- * $.fn.dataTable.ext.features.push( {
- * "fnInit": function( oSettings ) {
- * return new TableTools( { "oDTSettings": oSettings } );
- * },
- * "cFeature": "T"
- * } );
+ * This is an object of callbacks which provide the features for DataTables
+ * to be initialised via the `layout` option.
*/
- feature: [],
+ features: {},
/**
@@ -14363,19 +11763,6 @@
/**
- * Internal functions, exposed for used in plug-ins.
- *
- * Please note that you should not need to use the internal methods for
- * anything other than a plug-in (and even then, try to avoid if possible).
- * The internal function may change between releases.
- *
- * @type object
- * @default {}
- */
- internal: {},
-
-
- /**
* Legacy configuration options. Enable and disable legacy options that
* are available in DataTables.
*
@@ -14502,6 +11889,11 @@
*/
type: {
/**
+ * Automatic column class assignment
+ */
+ className: {},
+
+ /**
* Type detection functions.
*
* The functions defined in this object are used to automatically detect
@@ -14543,6 +11935,11 @@
*/
detect: [],
+ /**
+ * Automatic renderer assignment
+ */
+ render: {},
+
/**
* Type based search formatting.
@@ -14683,14 +12080,6 @@
/**
- * jQuery UI class container
- * @type object
- * @deprecated Since v1.10
- */
- oJUIClasses: {},
-
-
- /**
* Software version
* @type string
* @deprecated Since v1.10
@@ -14709,547 +12098,174 @@
oSort: _ext.type.order,
afnSortData: _ext.order,
aoFeatures: _ext.feature,
- oApi: _ext.internal,
oStdClasses: _ext.classes,
oPagination: _ext.pager
} );
$.extend( DataTable.ext.classes, {
- "sTable": "dataTable",
- "sNoFooter": "no-footer",
-
- /* Paging buttons */
- "sPageButton": "paginate_button",
- "sPageButtonActive": "current",
- "sPageButtonDisabled": "disabled",
-
- /* Striping classes */
- "sStripeOdd": "odd",
- "sStripeEven": "even",
-
- /* Empty row */
- "sRowEmpty": "dataTables_empty",
-
- /* Features */
- "sWrapper": "dataTables_wrapper",
- "sFilter": "dataTables_filter",
- "sInfo": "dataTables_info",
- "sPaging": "dataTables_paginate paging_", /* Note that the type is postfixed */
- "sLength": "dataTables_length",
- "sProcessing": "dataTables_processing",
-
- /* Sorting */
- "sSortAsc": "sorting_asc",
- "sSortDesc": "sorting_desc",
- "sSortable": "sorting", /* Sortable in both directions */
- "sSortableAsc": "sorting_desc_disabled",
- "sSortableDesc": "sorting_asc_disabled",
- "sSortableNone": "sorting_disabled",
- "sSortColumn": "sorting_", /* Note that an int is postfixed for the sorting order */
-
- /* Filtering */
- "sFilterInput": "",
-
- /* Page length */
- "sLengthSelect": "",
-
- /* Scrolling */
- "sScrollWrapper": "dataTables_scroll",
- "sScrollHead": "dataTables_scrollHead",
- "sScrollHeadInner": "dataTables_scrollHeadInner",
- "sScrollBody": "dataTables_scrollBody",
- "sScrollFoot": "dataTables_scrollFoot",
- "sScrollFootInner": "dataTables_scrollFootInner",
-
- /* Misc */
- "sHeaderTH": "",
- "sFooterTH": "",
-
- // Deprecated
- "sSortJUIAsc": "",
- "sSortJUIDesc": "",
- "sSortJUI": "",
- "sSortJUIAscAllowed": "",
- "sSortJUIDescAllowed": "",
- "sSortJUIWrapper": "",
- "sSortIcon": "",
- "sJUIHeader": "",
- "sJUIFooter": ""
+ container: 'dt-container',
+ empty: {
+ row: 'dt-empty'
+ },
+ info: {
+ container: 'dt-info'
+ },
+ length: {
+ container: 'dt-length',
+ select: 'dt-input'
+ },
+ order: {
+ canAsc: 'dt-orderable-asc',
+ canDesc: 'dt-orderable-desc',
+ isAsc: 'dt-ordering-asc',
+ isDesc: 'dt-ordering-desc',
+ none: 'dt-orderable-none',
+ position: 'sorting_'
+ },
+ processing: {
+ container: 'dt-processing'
+ },
+ scrolling: {
+ body: 'dt-scroll-body',
+ container: 'dt-scroll',
+ footer: {
+ self: 'dt-scroll-foot',
+ inner: 'dt-scroll-footInner'
+ },
+ header: {
+ self: 'dt-scroll-head',
+ inner: 'dt-scroll-headInner'
+ }
+ },
+ search: {
+ container: 'dt-search',
+ input: 'dt-input'
+ },
+ table: 'dataTable',
+ tbody: {
+ cell: '',
+ row: ''
+ },
+ thead: {
+ cell: '',
+ row: ''
+ },
+ tfoot: {
+ cell: '',
+ row: ''
+ },
+ paging: {
+ active: 'current',
+ button: 'dt-paging-button',
+ container: 'dt-paging',
+ disabled: 'disabled'
+ }
} );
var extPagination = DataTable.ext.pager;
- function _numbers ( page, pages ) {
- var
- numbers = [],
- buttons = extPagination.numbers_length,
- half = Math.floor( buttons / 2 ),
- i = 1;
-
- if ( pages <= buttons ) {
- numbers = _range( 0, pages );
- }
- else if ( page <= half ) {
- numbers = _range( 0, buttons-2 );
- numbers.push( 'ellipsis' );
- numbers.push( pages-1 );
- }
- else if ( page >= pages - 1 - half ) {
- numbers = _range( pages-(buttons-2), pages );
- numbers.splice( 0, 0, 'ellipsis' ); // no unshift in ie6
- numbers.splice( 0, 0, 0 );
- }
- else {
- numbers = _range( page-half+2, page+half-1 );
- numbers.push( 'ellipsis' );
- numbers.push( pages-1 );
- numbers.splice( 0, 0, 'ellipsis' );
- numbers.splice( 0, 0, 0 );
- }
-
- numbers.DT_el = 'span';
- return numbers;
- }
-
-
+ // Paging buttons configuration
$.extend( extPagination, {
- simple: function ( page, pages ) {
+ simple: function () {
return [ 'previous', 'next' ];
},
- full: function ( page, pages ) {
+ full: function () {
return [ 'first', 'previous', 'next', 'last' ];
},
- numbers: function ( page, pages ) {
- return [ _numbers(page, pages) ];
+ numbers: function () {
+ return [ 'numbers' ];
},
- simple_numbers: function ( page, pages ) {
- return [ 'previous', _numbers(page, pages), 'next' ];
+ simple_numbers: function () {
+ return [ 'previous', 'numbers', 'next' ];
},
- full_numbers: function ( page, pages ) {
- return [ 'first', 'previous', _numbers(page, pages), 'next', 'last' ];
+ full_numbers: function () {
+ return [ 'first', 'previous', 'numbers', 'next', 'last' ];
+ },
+
+ first_last: function () {
+ return ['first', 'last'];
},
- first_last_numbers: function (page, pages) {
- return ['first', _numbers(page, pages), 'last'];
- },
+ first_last_numbers: function () {
+ return ['first', 'numbers', 'last'];
+ },
// For testing and plug-ins to use
- _numbers: _numbers,
+ _numbers: _pagingNumbers,
- // Number of number buttons (including ellipsis) to show. _Must be odd!_
+ // Number of number buttons - legacy, use `numbers` option for paging feature
numbers_length: 7
} );
$.extend( true, DataTable.ext.renderer, {
- pageButton: {
- _: function ( settings, host, idx, buttons, page, pages ) {
- var classes = settings.oClasses;
- var lang = settings.oLanguage.oPaginate;
- var aria = settings.oLanguage.oAria.paginate || {};
- var btnDisplay, btnClass;
-
- var attach = function( container, buttons ) {
- var i, ien, node, button;
- var disabledClass = classes.sPageButtonDisabled;
- var clickHandler = function ( e ) {
- _fnPageChange( settings, e.data.action, true );
- };
-
- for ( i=0, ien=buttons.length ; i<ien ; i++ ) {
- button = buttons[i];
-
- if ( Array.isArray( button ) ) {
- var inner = $( '<'+(button.DT_el || 'div')+'/>' )
- .appendTo( container );
- attach( inner, button );
- }
- else {
- var disabled = false;
-
- btnDisplay = null;
- btnClass = button;
-
- switch ( button ) {
- case 'ellipsis':
- container.append('<span class="ellipsis">&#x2026;</span>');
- break;
-
- case 'first':
- btnDisplay = lang.sFirst;
-
- if ( page === 0 ) {
- disabled = true;
- }
- break;
-
- case 'previous':
- btnDisplay = lang.sPrevious;
+ pagingButton: {
+ _: function (settings, buttonType, content, active, disabled) {
+ var classes = settings.oClasses.paging;
+ var btnClasses = [classes.button];
+ var btn;
- if ( page === 0 ) {
- disabled = true;
- }
- break;
-
- case 'next':
- btnDisplay = lang.sNext;
-
- if ( pages === 0 || page === pages-1 ) {
- disabled = true;
- }
- break;
-
- case 'last':
- btnDisplay = lang.sLast;
-
- if ( pages === 0 || page === pages-1 ) {
- disabled = true;
- }
- break;
-
- default:
- btnDisplay = settings.fnFormatNumber( button + 1 );
- btnClass = page === button ?
- classes.sPageButtonActive : '';
- break;
- }
-
- if ( btnDisplay !== null ) {
- var tag = settings.oInit.pagingTag || 'a';
-
- if (disabled) {
- btnClass += ' ' + disabledClass;
- }
-
- node = $('<'+tag+'>', {
- 'class': classes.sPageButton+' '+btnClass,
- 'aria-controls': settings.sTableId,
- 'aria-disabled': disabled ? 'true' : null,
- 'aria-label': aria[ button ],
- 'role': 'link',
- 'aria-current': btnClass === classes.sPageButtonActive ? 'page' : null,
- 'data-dt-idx': button,
- 'tabindex': disabled ? -1 : settings.iTabIndex,
- 'id': idx === 0 && typeof button === 'string' ?
- settings.sTableId +'_'+ button :
- null
- } )
- .html( btnDisplay )
- .appendTo( container );
-
- _fnBindAction(
- node, {action: button}, clickHandler
- );
- }
- }
- }
- };
-
- // IE9 throws an 'unknown error' if document.activeElement is used
- // inside an iframe or frame. Try / catch the error. Not good for
- // accessibility, but neither are frames.
- var activeEl;
+ if (active) {
+ btnClasses.push(classes.active);
+ }
- try {
- // Because this approach is destroying and recreating the paging
- // elements, focus is lost on the select button which is bad for
- // accessibility. So we want to restore focus once the draw has
- // completed
- activeEl = $(host).find(document.activeElement).data('dt-idx');
+ if (disabled) {
+ btnClasses.push(classes.disabled)
}
- catch (e) {}
- attach( $(host).empty(), buttons );
+ if (buttonType === 'ellipsis') {
+ btn = $('<span class="ellipsis"></span>').html(content)[0];
+ }
+ else {
+ btn = $('<button>', {
+ class: btnClasses.join(' '),
+ role: 'link',
+ type: 'button'
+ }).html(content);
+ }
- if ( activeEl !== undefined ) {
- $(host).find( '[data-dt-idx='+activeEl+']' ).trigger('focus');
+ return {
+ display: btn,
+ clicker: btn
}
}
- }
- } );
-
-
-
- // Built in type detection. See model.ext.aTypes for information about
- // what is required from this methods.
- $.extend( DataTable.ext.type.detect, [
- // Plain numbers - first since V8 detects some plain numbers as dates
- // e.g. Date.parse('55') (but not all, e.g. Date.parse('22')...).
- function ( d, settings )
- {
- var decimal = settings.oLanguage.sDecimal;
- return _isNumber( d, decimal ) ? 'num'+decimal : null;
},
- // Dates (only those recognised by the browser's Date.parse)
- function ( d, settings )
- {
- // V8 tries _very_ hard to make a string passed into `Date.parse()`
- // valid, so we need to use a regex to restrict date formats. Use a
- // plug-in for anything other than ISO8601 style strings
- if ( d && !(d instanceof Date) && ! _re_date.test(d) ) {
- return null;
+ pagingContainer: {
+ _: function (settings, buttons) {
+ // No wrapping element - just append directly to the host
+ return buttons;
}
- var parsed = Date.parse(d);
- return (parsed !== null && !isNaN(parsed)) || _empty(d) ? 'date' : null;
- },
-
- // Formatted numbers
- function ( d, settings )
- {
- var decimal = settings.oLanguage.sDecimal;
- return _isNumber( d, decimal, true ) ? 'num-fmt'+decimal : null;
- },
-
- // HTML numeric
- function ( d, settings )
- {
- var decimal = settings.oLanguage.sDecimal;
- return _htmlNumeric( d, decimal ) ? 'html-num'+decimal : null;
- },
-
- // HTML numeric, formatted
- function ( d, settings )
- {
- var decimal = settings.oLanguage.sDecimal;
- return _htmlNumeric( d, decimal, true ) ? 'html-num-fmt'+decimal : null;
- },
-
- // HTML (this is strict checking - there must be html)
- function ( d, settings )
- {
- return _empty( d ) || (typeof d === 'string' && d.indexOf('<') !== -1) ?
- 'html' : null;
- }
- ] );
-
-
-
- // Filter formatting functions. See model.ext.ofnSearch for information about
- // what is required from these methods.
- //
- // Note that additional search methods are added for the html numbers and
- // html formatted numbers by `_addNumericSort()` when we know what the decimal
- // place is
-
-
- $.extend( DataTable.ext.type.search, {
- html: function ( data ) {
- return _empty(data) ?
- data :
- typeof data === 'string' ?
- data
- .replace( _re_new_lines, " " )
- .replace( _re_html, "" ) :
- '';
- },
-
- string: function ( data ) {
- return _empty(data) ?
- data :
- typeof data === 'string' ?
- data.replace( _re_new_lines, " " ) :
- data;
}
} );
+ // Common function to remove new lines, strip HTML and diacritic control
+ var _filterString = function (stripHtml, diacritics) {
+ return function (str) {
+ if (_empty(str) || typeof str !== 'string') {
+ return str;
+ }
+ str = str.replace( _re_new_lines, " " );
- var __numericReplace = function ( d, decimalPlace, re1, re2 ) {
- if ( d !== 0 && (!d || d === '-') ) {
- return -Infinity;
- }
-
- var type = typeof d;
-
- if (type === 'number' || type === 'bigint') {
- return d;
- }
-
- // If a decimal place other than `.` is used, it needs to be given to the
- // function so we can detect it and replace with a `.` which is the only
- // decimal place Javascript recognises - it is not locale aware.
- if ( decimalPlace ) {
- d = _numToDecimal( d, decimalPlace );
- }
-
- if ( d.replace ) {
- if ( re1 ) {
- d = d.replace( re1, '' );
+ if (stripHtml) {
+ str = _stripHtml(str);
}
- if ( re2 ) {
- d = d.replace( re2, '' );
+ if (diacritics) {
+ str = _normalize(str, true);
}
- }
-
- return d * 1;
- };
-
-
- // Add the numeric 'deformatting' functions for sorting and search. This is done
- // in a function to provide an easy ability for the language options to add
- // additional methods if a non-period decimal place is used.
- function _addNumericSort ( decimalPlace ) {
- $.each(
- {
- // Plain numbers
- "num": function ( d ) {
- return __numericReplace( d, decimalPlace );
- },
-
- // Formatted numbers
- "num-fmt": function ( d ) {
- return __numericReplace( d, decimalPlace, _re_formatted_numeric );
- },
- // HTML numeric
- "html-num": function ( d ) {
- return __numericReplace( d, decimalPlace, _re_html );
- },
-
- // HTML numeric, formatted
- "html-num-fmt": function ( d ) {
- return __numericReplace( d, decimalPlace, _re_html, _re_formatted_numeric );
- }
- },
- function ( key, fn ) {
- // Add the ordering method
- _ext.type.order[ key+decimalPlace+'-pre' ] = fn;
-
- // For HTML types add a search formatter that will strip the HTML
- if ( key.match(/^html\-/) ) {
- _ext.type.search[ key+decimalPlace ] = _ext.type.search.html;
- }
- }
- );
+ return str;
+ };
}
-
- // Default sort methods
- $.extend( _ext.type.order, {
- // Dates
- "date-pre": function ( d ) {
- var ts = Date.parse( d );
- return isNaN(ts) ? -Infinity : ts;
- },
-
- // html
- "html-pre": function ( a ) {
- return _empty(a) ?
- '' :
- a.replace ?
- a.replace( /<.*?>/g, "" ).toLowerCase() :
- a+'';
- },
-
- // string
- "string-pre": function ( a ) {
- // This is a little complex, but faster than always calling toString,
- // http://jsperf.com/tostring-v-check
- return _empty(a) ?
- '' :
- typeof a === 'string' ?
- a.toLowerCase() :
- ! a.toString ?
- '' :
- a.toString();
- },
-
- // string-asc and -desc are retained only for compatibility with the old
- // sort methods
- "string-asc": function ( x, y ) {
- return ((x < y) ? -1 : ((x > y) ? 1 : 0));
- },
-
- "string-desc": function ( x, y ) {
- return ((x < y) ? 1 : ((x > y) ? -1 : 0));
- }
- } );
-
-
- // Numeric sorting types - order doesn't matter here
- _addNumericSort( '' );
-
-
- $.extend( true, DataTable.ext.renderer, {
- header: {
- _: function ( settings, cell, column, classes ) {
- // No additional mark-up required
- // Attach a sort listener to update on sort - note that using the
- // `DT` namespace will allow the event to be removed automatically
- // on destroy, while the `dt` namespaced event is the one we are
- // listening for
- $(settings.nTable).on( 'order.dt.DT', function ( e, ctx, sorting, columns ) {
- if ( settings !== ctx ) { // need to check this this is the host
- return; // table, not a nested one
- }
-
- var colIdx = column.idx;
-
- cell
- .removeClass(
- classes.sSortAsc +' '+
- classes.sSortDesc
- )
- .addClass( columns[ colIdx ] == 'asc' ?
- classes.sSortAsc : columns[ colIdx ] == 'desc' ?
- classes.sSortDesc :
- column.sSortingClass
- );
- } );
- },
-
- jqueryui: function ( settings, cell, column, classes ) {
- $('<div/>')
- .addClass( classes.sSortJUIWrapper )
- .append( cell.contents() )
- .append( $('<span/>')
- .addClass( classes.sSortIcon+' '+column.sSortingClassJUI )
- )
- .appendTo( cell );
-
- // Attach a sort listener to update on sort
- $(settings.nTable).on( 'order.dt.DT', function ( e, ctx, sorting, columns ) {
- if ( settings !== ctx ) {
- return;
- }
-
- var colIdx = column.idx;
-
- cell
- .removeClass( classes.sSortAsc +" "+classes.sSortDesc )
- .addClass( columns[ colIdx ] == 'asc' ?
- classes.sSortAsc : columns[ colIdx ] == 'desc' ?
- classes.sSortDesc :
- column.sSortingClass
- );
-
- cell
- .find( 'span.'+classes.sSortIcon )
- .removeClass(
- classes.sSortJUIAsc +" "+
- classes.sSortJUIDesc +" "+
- classes.sSortJUI +" "+
- classes.sSortJUIAscAllowed +" "+
- classes.sSortJUIDescAllowed
- )
- .addClass( columns[ colIdx ] == 'asc' ?
- classes.sSortJUIAsc : columns[ colIdx ] == 'desc' ?
- classes.sSortJUIDesc :
- column.sSortingClassJUI
- );
- } );
- }
- }
- } );
-
/*
* Public helper functions. These aren't used internally by DataTables, or
* called by any of the options passed into DataTables, but they can be used
@@ -15257,19 +12273,9 @@
* to make working with DataTables a little bit easier.
*/
- var __htmlEscapeEntities = function ( d ) {
- if (Array.isArray(d)) {
- d = d.join(',');
- }
-
- return typeof d === 'string' ?
- d
- .replace(/&/g, '&amp;')
- .replace(/</g, '&lt;')
- .replace(/>/g, '&gt;')
- .replace(/"/g, '&quot;') :
- d;
- };
+ function __mldFnName(name) {
+ return name.replace(/[\W]/g, '_')
+ }
// Common logic for moment, luxon or a date action
function __mld( dt, momentFn, luxonFn, dateFn, arg1 ) {
@@ -15343,39 +12349,25 @@
from = null;
}
- var typeName = 'datetime-' + to;
+ var typeName = 'datetime' + (to ? '-' + __mldFnName(to) : '');
// Add type detection and sorting specific to this date format - we need to be able to identify
// date type columns as such, rather than as numbers in extensions. Hence the need for this.
if (! DataTable.ext.type.order[typeName]) {
- // The renderer will give the value to type detect as the type!
- DataTable.ext.type.detect.unshift(function (d) {
- return d === typeName ? typeName : false;
+ DataTable.type(typeName, {
+ detect: function (d) {
+ // The renderer will give the value to type detect as the type!
+ return d === typeName ? typeName : false;
+ },
+ order: {
+ pre: function (d) {
+ // The renderer gives us Moment, Luxon or Date obects for the sorting, all of which have a
+ // `valueOf` which gives milliseconds epoch
+ return d.valueOf();
+ }
+ },
+ className: 'dt-right'
});
-
- // The renderer gives us Moment, Luxon or Date obects for the sorting, all of which have a
- // `valueOf` which gives milliseconds epoch
- DataTable.ext.type.order[typeName + '-asc'] = function (a, b) {
- var x = a.valueOf();
- var y = b.valueOf();
-
- return x === y
- ? 0
- : x < y
- ? -1
- : 1;
- }
-
- DataTable.ext.type.order[typeName + '-desc'] = function (a, b) {
- var x = a.valueOf();
- var y = b.valueOf();
-
- return x === y
- ? 0
- : x > y
- ? -1
- : 1;
- }
}
return function ( d, type ) {
@@ -15429,7 +12421,7 @@
// XSS protection
return type === 'display' ?
- __htmlEscapeEntities( formatted ) :
+ _escapeHtml( formatted ) :
formatted;
};
}
@@ -15460,21 +12452,25 @@
// Formatted date time detection - use by declaring the formats you are going to use
DataTable.datetime = function ( format, locale ) {
- var typeName = 'datetime-detect-' + format;
+ var typeName = 'datetime-detect-' + __mldFnName(format);
if (! locale) {
locale = 'en';
}
if (! DataTable.ext.type.order[typeName]) {
- DataTable.ext.type.detect.unshift(function (d) {
- var dt = __mldObj(d, format, locale);
- return d === '' || dt ? typeName : false;
+ DataTable.type(typeName, {
+ detect: function (d) {
+ var dt = __mldObj(d, format, locale);
+ return d === '' || dt ? typeName : false;
+ },
+ order: {
+ pre: function (d) {
+ return __mldObj(d, format, locale) || 0;
+ }
+ },
+ className: 'dt-right'
});
-
- DataTable.ext.type.order[typeName + '-pre'] = function (d) {
- return __mldObj(d, format, locale) || 0;
- }
}
}
@@ -15484,6 +12480,17 @@
* The options defined here can be used with the `columns.render` initialisation
* option to provide a display renderer. The following functions are defined:
*
+ * * `moment` - Uses the MomentJS library to convert from a given format into another.
+ * This renderer has three overloads:
+ * * 1 parameter:
+ * * `string` - Format to convert to (assumes input is ISO8601 and locale is `en`)
+ * * 2 parameters:
+ * * `string` - Format to convert from
+ * * `string` - Format to convert to. Assumes `en` locale
+ * * 3 parameters:
+ * * `string` - Format to convert from
+ * * `string` - Format to convert to
+ * * `string` - Locale
* * `number` - Will format numeric data (defined by `columns.data`) for
* display, retaining the original unformatted data for sorting and filtering.
* It takes 5 parameters:
@@ -15530,12 +12537,19 @@
var negative = d < 0 ? '-' : '';
var flo = parseFloat( d );
+ var abs = Math.abs(flo);
+
+ // Scientific notation for large and small numbers
+ if (abs >= 100000000000 || (abs < 0.0001 && abs !== 0) ) {
+ var exp = flo.toExponential(precision).split(/e\+?/);
+ return exp[0] + ' x 10<sup>' + exp[1] + '</sup>';
+ }
// If NaN then there isn't much formatting that we can do - just
// return immediately, escaping any HTML (this was supposed to
// be a number after all)
if ( isNaN( flo ) ) {
- return __htmlEscapeEntities( d );
+ return _escapeHtml( d );
}
flo = flo.toFixed( precision );
@@ -15563,139 +12577,984 @@
text: function () {
return {
- display: __htmlEscapeEntities,
- filter: __htmlEscapeEntities
+ display: _escapeHtml,
+ filter: _escapeHtml
};
}
};
- /*
- * This is really a good bit rubbish this method of exposing the internal methods
- * publicly... - To be fixed in 2.0 using methods on the prototype
- */
+ var _extTypes = DataTable.ext.type;
+
+ // Get / set type
+ DataTable.type = function (name, prop, val) {
+ if (! prop) {
+ return {
+ className: _extTypes.className[name],
+ detect: _extTypes.detect.find(function (fn) {
+ return fn.name === name;
+ }),
+ order: {
+ pre: _extTypes.order[name + '-pre'],
+ asc: _extTypes.order[name + '-asc'],
+ desc: _extTypes.order[name + '-desc']
+ },
+ render: _extTypes.render[name],
+ search: _extTypes.search[name]
+ };
+ }
+
+ var setProp = function(prop, propVal) {
+ _extTypes[prop][name] = propVal;
+ };
+ var setDetect = function (fn) {
+ // Wrap to allow the function to return `true` rather than
+ // specifying the type name.
+ var cb = function (d, s) {
+ var ret = fn(d, s);
+
+ return ret === true
+ ? name
+ : ret;
+ };
+ Object.defineProperty(cb, "name", {value: name});
+
+ var idx = _extTypes.detect.findIndex(function (fn) {
+ return fn.name === name;
+ });
+
+ if (idx === -1) {
+ _extTypes.detect.unshift(cb);
+ }
+ else {
+ _extTypes.detect.splice(idx, 1, cb);
+ }
+ };
+ var setOrder = function (obj) {
+ _extTypes.order[name + '-pre'] = obj.pre; // can be undefined
+ _extTypes.order[name + '-asc'] = obj.asc; // can be undefined
+ _extTypes.order[name + '-desc'] = obj.desc; // can be undefined
+ };
+
+ // prop is optional
+ if (! val) {
+ val = prop;
+ prop = null;
+ }
+
+ if (prop === 'className') {
+ setProp('className', val);
+ }
+ else if (prop === 'detect') {
+ setDetect(val);
+ }
+ else if (prop === 'order') {
+ setOrder(val);
+ }
+ else if (prop === 'render') {
+ setProp('render', val);
+ }
+ else if (prop === 'search') {
+ setProp('search', val);
+ }
+ else if (! prop) {
+ if (val.className) {
+ setProp('className', val.className);
+ }
+
+ if (val.detect !== undefined) {
+ setDetect(val.detect);
+ }
+
+ if (val.order) {
+ setOrder(val.order);
+ }
+
+ if (val.render !== undefined) {
+ setProp('render', val.render);
+ }
+
+ if (val.search !== undefined) {
+ setProp('search', val.search);
+ }
+ }
+ }
+
+ // Get a list of types
+ DataTable.types = function () {
+ return _extTypes.detect.map(function (fn) {
+ return fn.name;
+ });
+ };
+
+ //
+ // Built in data types
+ //
+
+ DataTable.type('string', {
+ detect: function () {
+ return 'string';
+ },
+ order: {
+ pre: function ( a ) {
+ // This is a little complex, but faster than always calling toString,
+ // http://jsperf.com/tostring-v-check
+ return _empty(a) ?
+ '' :
+ typeof a === 'string' ?
+ a.toLowerCase() :
+ ! a.toString ?
+ '' :
+ a.toString();
+ }
+ },
+ search: _filterString(false, true)
+ });
+
+
+ DataTable.type('html', {
+ detect: function ( d ) {
+ return _empty( d ) || (typeof d === 'string' && d.indexOf('<') !== -1) ?
+ 'html' : null;
+ },
+ order: {
+ pre: function ( a ) {
+ return _empty(a) ?
+ '' :
+ a.replace ?
+ _stripHtml(a).trim().toLowerCase() :
+ a+'';
+ }
+ },
+ search: _filterString(true, true)
+ });
+
+
+ DataTable.type('date', {
+ className: 'dt-type-date',
+ detect: function ( d )
+ {
+ // V8 tries _very_ hard to make a string passed into `Date.parse()`
+ // valid, so we need to use a regex to restrict date formats. Use a
+ // plug-in for anything other than ISO8601 style strings
+ if ( d && !(d instanceof Date) && ! _re_date.test(d) ) {
+ return null;
+ }
+ var parsed = Date.parse(d);
+ return (parsed !== null && !isNaN(parsed)) || _empty(d) ? 'date' : null;
+ },
+ order: {
+ pre: function ( d ) {
+ var ts = Date.parse( d );
+ return isNaN(ts) ? -Infinity : ts;
+ }
+ }
+ });
+
+
+ DataTable.type('html-num-fmt', {
+ className: 'dt-type-numeric',
+ detect: function ( d, settings )
+ {
+ var decimal = settings.oLanguage.sDecimal;
+ return _htmlNumeric( d, decimal, true ) ? 'html-num-fmt' : null;
+ },
+ order: {
+ pre: function ( d, s ) {
+ var dp = s.oLanguage.sDecimal;
+ return __numericReplace( d, dp, _re_html, _re_formatted_numeric );
+ }
+ },
+ search: _filterString(true, true)
+ });
+
+
+ DataTable.type('html-num', {
+ className: 'dt-type-numeric',
+ detect: function ( d, settings )
+ {
+ var decimal = settings.oLanguage.sDecimal;
+ return _htmlNumeric( d, decimal ) ? 'html-num' : null;
+ },
+ order: {
+ pre: function ( d, s ) {
+ var dp = s.oLanguage.sDecimal;
+ return __numericReplace( d, dp, _re_html );
+ }
+ },
+ search: _filterString(true, true)
+ });
+
+
+ DataTable.type('num-fmt', {
+ className: 'dt-type-numeric',
+ detect: function ( d, settings )
+ {
+ var decimal = settings.oLanguage.sDecimal;
+ return _isNumber( d, decimal, true ) ? 'num-fmt' : null;
+ },
+ order: {
+ pre: function ( d, s ) {
+ var dp = s.oLanguage.sDecimal;
+ return __numericReplace( d, dp, _re_formatted_numeric );
+ }
+ }
+ });
+
+
+ DataTable.type('num', {
+ className: 'dt-type-numeric',
+ detect: function ( d, settings )
+ {
+ var decimal = settings.oLanguage.sDecimal;
+ return _isNumber( d, decimal ) ? 'num' : null;
+ },
+ order: {
+ pre: function (d, s) {
+ var dp = s.oLanguage.sDecimal;
+ return __numericReplace( d, dp );
+ }
+ }
+ });
+
+
+ var __numericReplace = function ( d, decimalPlace, re1, re2 ) {
+ if ( d !== 0 && (!d || d === '-') ) {
+ return -Infinity;
+ }
+
+ var type = typeof d;
+
+ if (type === 'number' || type === 'bigint') {
+ return d;
+ }
+
+ // If a decimal place other than `.` is used, it needs to be given to the
+ // function so we can detect it and replace with a `.` which is the only
+ // decimal place Javascript recognises - it is not locale aware.
+ if ( decimalPlace ) {
+ d = _numToDecimal( d, decimalPlace );
+ }
+
+ if ( d.replace ) {
+ if ( re1 ) {
+ d = d.replace( re1, '' );
+ }
+
+ if ( re2 ) {
+ d = d.replace( re2, '' );
+ }
+ }
+
+ return d * 1;
+ };
+
+
+ $.extend( true, DataTable.ext.renderer, {
+ footer: {
+ _: function ( settings, cell, classes ) {
+ cell.addClass(classes.tfoot.cell);
+ }
+ },
+
+ header: {
+ _: function ( settings, cell, classes ) {
+ cell.addClass(classes.thead.cell);
+
+ if (! settings.oFeatures.bSort) {
+ cell.addClass(classes.order.none);
+ }
+
+ var legacyTop = settings.bSortCellsTop;
+ var headerRows = cell.closest('thead').find('tr');
+ var rowIdx = cell.parent().index();
+
+ // Conditions to not apply the ordering icons
+ if (
+ // Cells and rows which have the attribute to disable the icons
+ cell.attr('data-dt-order') === 'disable' ||
+ cell.parent().attr('data-dt-order') === 'disable' ||
+
+ // Legacy support for `orderCellsTop`. If it is set, then cells
+ // which are not in the top or bottom row of the header (depending
+ // on the value) do not get the sorting classes applied to them
+ (legacyTop === true && rowIdx !== 0) ||
+ (legacyTop === false && rowIdx !== headerRows.length - 1)
+ ) {
+ return;
+ }
+
+ // No additional mark-up required
+ // Attach a sort listener to update on sort - note that using the
+ // `DT` namespace will allow the event to be removed automatically
+ // on destroy, while the `dt` namespaced event is the one we are
+ // listening for
+ $(settings.nTable).on( 'order.dt.DT', function ( e, ctx, sorting ) {
+ if ( settings !== ctx ) { // need to check this this is the host
+ return; // table, not a nested one
+ }
+
+ var orderClasses = classes.order;
+ var columns = ctx.api.columns( cell );
+ var col = settings.aoColumns[columns.flatten()[0]];
+ var orderable = columns.orderable().includes(true);
+ var ariaType = '';
+ var indexes = columns.indexes();
+ var sortDirs = columns.orderable(true).flatten();
+ var orderedColumns = sorting.map( function (val) {
+ return val.col;
+ } ).join(',');
+
+ cell
+ .removeClass(
+ orderClasses.isAsc +' '+
+ orderClasses.isDesc
+ )
+ .toggleClass( orderClasses.none, ! orderable )
+ .toggleClass( orderClasses.canAsc, orderable && sortDirs.includes('asc') )
+ .toggleClass( orderClasses.canDesc, orderable && sortDirs.includes('desc') );
+
+ var sortIdx = orderedColumns.indexOf( indexes.toArray().join(',') );
+
+ if ( sortIdx !== -1 ) {
+ // Get the ordering direction for the columns under this cell
+ // Note that it is possible for a cell to be asc and desc sorting
+ // (column spanning cells)
+ var orderDirs = columns.order();
+
+ cell.addClass(
+ orderDirs.includes('asc') ? orderClasses.isAsc : '' +
+ orderDirs.includes('desc') ? orderClasses.isDesc : ''
+ );
+ }
+
+ // The ARIA spec says that only one column should be marked with aria-sort
+ if ( sortIdx === 0 && orderedColumns.length === indexes.count() ) {
+ var firstSort = sorting[0];
+ var sortOrder = col.asSorting;
+
+ cell.attr('aria-sort', firstSort.dir === 'asc' ? 'ascending' : 'descending');
+
+ // Determine if the next click will remove sorting or change the sort
+ ariaType = ! sortOrder[firstSort.index + 1] ? 'Remove' : 'Reverse';
+ }
+ else {
+ cell.removeAttr('aria-sort');
+ }
+
+ cell.attr('aria-label', orderable
+ ? col.ariaTitle + ctx.api.i18n('oAria.orderable' + ariaType)
+ : col.ariaTitle
+ );
+
+ if (orderable) {
+ cell.find('.dt-column-title').attr('role', 'button');
+ cell.attr('tabindex', 0)
+ }
+ } );
+ }
+ },
+
+ layout: {
+ _: function ( settings, container, items ) {
+ var row = $('<div/>')
+ .addClass('dt-layout-row')
+ .appendTo( container );
+
+ $.each( items, function (key, val) {
+ var klass = ! val.table ?
+ 'dt-'+key+' ' :
+ '';
+
+ if (val.table) {
+ row.addClass('dt-layout-table');
+ }
+
+ $('<div/>')
+ .attr({
+ id: val.id || null,
+ "class": 'dt-layout-cell '+klass+(val.className || '')
+ })
+ .append( val.contents )
+ .appendTo( row );
+ } );
+ }
+ }
+ } );
+
+
+ DataTable.feature = {};
+
+ // Third parameter is internal only!
+ DataTable.feature.register = function ( name, cb, legacy ) {
+ DataTable.ext.features[ name ] = cb;
+
+ if (legacy) {
+ _ext.feature.push({
+ cFeature: legacy,
+ fnInit: cb
+ });
+ }
+ };
+
+ DataTable.feature.register( 'info', function ( settings, opts ) {
+ // For compatibility with the legacy `info` top level option
+ if (! settings.oFeatures.bInfo) {
+ return null;
+ }
+
+ var
+ lang = settings.oLanguage,
+ tid = settings.sTableId,
+ n = $('<div/>', {
+ 'class': settings.oClasses.info.container,
+ } );
+
+ opts = $.extend({
+ callback: lang.fnInfoCallback,
+ empty: lang.sInfoEmpty,
+ postfix: lang.sInfoPostFix,
+ search: lang.sInfoFiltered,
+ text: lang.sInfo,
+ }, opts);
+
+
+ // Update display on each draw
+ settings.aoDrawCallback.push(function (s) {
+ _fnUpdateInfo(s, opts, n);
+ });
+
+ // For the first info display in the table, we add a callback and aria information.
+ if (! $('#' + tid+'_info', settings.nWrapper).length) {
+ n.attr({
+ 'aria-live': 'polite',
+ id: tid+'_info',
+ role: 'status'
+ });
+
+ // Table is described by our info div
+ $(settings.nTable).attr( 'aria-describedby', tid+'_info' );
+ }
+
+ return n;
+ }, 'i' );
+
/**
- * Create a wrapper function for exporting an internal functions to an external API.
- * @param {string} fn API function name
- * @returns {function} wrapped function
- * @memberof DataTable#internal
+ * Update the information elements in the display
+ * @param {object} settings dataTables settings object
+ * @memberof DataTable#oApi
*/
- function _fnExternApiFunc (fn)
+ function _fnUpdateInfo ( settings, opts, node )
{
- return function() {
- var args = [_fnSettingsFromNode( this[DataTable.ext.iApiIndex] )].concat(
- Array.prototype.slice.call(arguments)
+ var
+ start = settings._iDisplayStart+1,
+ end = settings.fnDisplayEnd(),
+ max = settings.fnRecordsTotal(),
+ total = settings.fnRecordsDisplay(),
+ out = total
+ ? opts.text
+ : opts.empty;
+
+ if ( total !== max ) {
+ // Record set after filtering
+ out += ' ' + opts.search;
+ }
+
+ // Convert the macros
+ out += opts.postfix;
+ out = _fnMacros( settings, out );
+
+ if ( opts.callback ) {
+ out = opts.callback.call( settings.oInstance,
+ settings, start, end, max, total, out
);
- return DataTable.ext.internal[fn].apply( this, args );
+ }
+
+ node.html( out );
+
+ _fnCallbackFire(settings, null, 'info', [settings, node[0], out]);
+ }
+
+ var __searchCounter = 0;
+
+ // opts
+ // - text
+ // - placeholder
+ DataTable.feature.register( 'search', function ( settings, opts ) {
+ // Don't show the input if filtering isn't available on the table
+ if (! settings.oFeatures.bFilter) {
+ return null;
+ }
+
+ var classes = settings.oClasses.search;
+ var tableId = settings.sTableId;
+ var language = settings.oLanguage;
+ var previousSearch = settings.oPreviousSearch;
+ var input = '<input type="search" class="'+classes.input+'"/>';
+
+ opts = $.extend({
+ placeholder: language.sSearchPlaceholder,
+ text: language.sSearch
+ }, opts);
+
+ // The _INPUT_ is optional - is appended if not present
+ if (opts.text.indexOf('_INPUT_') === -1) {
+ opts.text += '_INPUT_';
+ }
+
+ opts.text = _fnMacros(settings, opts.text);
+
+ // We can put the <input> outside of the label if it is at the start or end
+ // which helps improve accessability (not all screen readers like implicit
+ // for elements).
+ var end = opts.text.match(/_INPUT_$/);
+ var start = opts.text.match(/^_INPUT_/);
+ var removed = opts.text.replace(/_INPUT_/, '');
+ var str = '<label>' + opts.text + '</label>';
+
+ if (start) {
+ str = '_INPUT_<label>' + removed + '</label>';
+ }
+ else if (end) {
+ str = '<label>' + removed + '</label>_INPUT_';
+ }
+
+ var filter = $('<div>')
+ .addClass(classes.container)
+ .append(str.replace(/_INPUT_/, input));
+
+ // add for and id to label and input
+ filter.find('label').attr('for', 'dt-search-' + __searchCounter);
+ filter.find('input').attr('id', 'dt-search-' + __searchCounter);
+ __searchCounter++;
+
+ var searchFn = function(event) {
+ var val = this.value;
+
+ if(previousSearch.return && event.key !== "Enter") {
+ return;
+ }
+
+ /* Now do the filter */
+ if ( val != previousSearch.search ) {
+ previousSearch.search = val;
+
+ _fnFilterComplete( settings, previousSearch );
+
+ // Need to redraw, without resorting
+ settings._iDisplayStart = 0;
+ _fnDraw( settings );
+ }
+ };
+
+ var searchDelay = settings.searchDelay !== null ?
+ settings.searchDelay :
+ 0;
+
+ var jqFilter = $('input', filter)
+ .val( previousSearch.search )
+ .attr( 'placeholder', opts.placeholder )
+ .on(
+ 'keyup.DT search.DT input.DT paste.DT cut.DT',
+ searchDelay ?
+ DataTable.util.debounce( searchFn, searchDelay ) :
+ searchFn
+ )
+ .on( 'mouseup.DT', function(e) {
+ // Edge fix! Edge 17 does not trigger anything other than mouse events when clicking
+ // on the clear icon (Edge bug 17584515). This is safe in other browsers as `searchFn`
+ // checks the value to see if it has changed. In other browsers it won't have.
+ setTimeout( function () {
+ searchFn.call(jqFilter[0], e);
+ }, 10);
+ } )
+ .on( 'keypress.DT', function(e) {
+ /* Prevent form submission */
+ if ( e.keyCode == 13 ) {
+ return false;
+ }
+ } )
+ .attr('aria-controls', tableId);
+
+ // Update the input elements whenever the table is filtered
+ $(settings.nTable).on( 'search.dt.DT', function ( ev, s ) {
+ if ( settings === s && jqFilter[0] !== document.activeElement ) {
+ jqFilter.val( typeof previousSearch.search !== 'function'
+ ? previousSearch.search
+ : ''
+ );
+ }
+ } );
+
+ return filter;
+ }, 'f' );
+
+ // opts
+ // - type - button configuration
+ // - numbers - number of buttons to show - must be odd
+ DataTable.feature.register( 'paging', function ( settings, opts ) {
+ // Don't show the paging input if the table doesn't have paging enabled
+ if (! settings.oFeatures.bPaginate) {
+ return null;
+ }
+
+ opts = $.extend({
+ numbers: DataTable.ext.pager.numbers_length,
+ type: settings.sPaginationType
+ }, opts)
+
+ var host = $('<div/>').addClass( settings.oClasses.paging.container + ' paging_' + opts.type );
+ var draw = function () {
+ _pagingDraw(settings, host, opts);
};
+
+ settings.aoDrawCallback.push(draw);
+
+ // Responsive redraw of paging control
+ $(settings.nTable).on('column-sizing.dt.DT', draw);
+
+ return host;
+ }, 'p' );
+
+ function _pagingDraw(settings, host, opts) {
+ if (! settings._bInitComplete) {
+ return;
+ }
+
+ var
+ plugin = DataTable.ext.pager[ opts.type ],
+ aria = settings.oLanguage.oAria.paginate || {},
+ start = settings._iDisplayStart,
+ len = settings._iDisplayLength,
+ visRecords = settings.fnRecordsDisplay(),
+ all = len === -1,
+ page = all ? 0 : Math.ceil( start / len ),
+ pages = all ? 1 : Math.ceil( visRecords / len ),
+ buttons = plugin()
+ .map(function (val) {
+ return val === 'numbers'
+ ? _pagingNumbers(page, pages, opts.numbers)
+ : val;
+ })
+ .flat();
+
+ var buttonEls = [];
+
+ for (var i=0 ; i<buttons.length ; i++) {
+ var button = buttons[i];
+
+ var btnInfo = _pagingButtonInfo(settings, button, page, pages);
+ var btn = _fnRenderer( settings, 'pagingButton' )(
+ settings,
+ button,
+ btnInfo.display,
+ btnInfo.active,
+ btnInfo.disabled
+ );
+
+ // Common attributes
+ $(btn.clicker).attr({
+ 'aria-controls': settings.sTableId,
+ 'aria-disabled': btnInfo.disabled ? 'true' : null,
+ 'aria-current': btnInfo.active ? 'page' : null,
+ 'aria-label': aria[ button ],
+ 'data-dt-idx': button,
+ 'tabIndex': btnInfo.disabled ? -1 : settings.iTabIndex,
+ });
+
+ if (typeof button !== 'number') {
+ $(btn.clicker).addClass(button);
+ }
+
+ _fnBindAction(
+ btn.clicker, {action: button}, function(e) {
+ e.preventDefault();
+
+ _fnPageChange( settings, e.data.action, true );
+ }
+ );
+
+ buttonEls.push(btn.display);
+ }
+
+ var wrapped = _fnRenderer(settings, 'pagingContainer')(
+ settings, buttonEls
+ );
+
+ var activeEl = host.find(document.activeElement).data('dt-idx');
+
+ host.empty().append(wrapped);
+
+ if ( activeEl !== undefined ) {
+ host.find( '[data-dt-idx='+activeEl+']' ).trigger('focus');
+ }
+
+ // Responsive - check if the buttons are over two lines based on the
+ // height of the buttons and the container.
+ if (
+ buttonEls.length && // any buttons
+ opts.numbers > 1 && // prevent infinite
+ $(host).outerHeight() >= ($(buttonEls[0]).outerHeight() * 2) - 10
+ ) {
+ _pagingDraw(settings, host, $.extend({}, opts, { numbers: opts.numbers - 2 }));
+ }
}
+ /**
+ * Get properties for a button based on the current paging state of the table
+ *
+ * @param {*} settings DT settings object
+ * @param {*} button The button type in question
+ * @param {*} page Table's current page
+ * @param {*} pages Number of pages
+ * @returns Info object
+ */
+ function _pagingButtonInfo(settings, button, page, pages) {
+ var lang = settings.oLanguage.oPaginate;
+ var o = {
+ display: '',
+ active: false,
+ disabled: false
+ };
+
+ switch ( button ) {
+ case 'ellipsis':
+ o.display = '&#x2026;';
+ o.disabled = true;
+ break;
+
+ case 'first':
+ o.display = lang.sFirst;
+
+ if (page === 0) {
+ o.disabled = true;
+ }
+ break;
+
+ case 'previous':
+ o.display = lang.sPrevious;
+
+ if ( page === 0 ) {
+ o.disabled = true;
+ }
+ break;
+
+ case 'next':
+ o.display = lang.sNext;
+
+ if ( pages === 0 || page === pages-1 ) {
+ o.disabled = true;
+ }
+ break;
+
+ case 'last':
+ o.display = lang.sLast;
+
+ if ( pages === 0 || page === pages-1 ) {
+ o.disabled = true;
+ }
+ break;
+
+ default:
+ if ( typeof button === 'number' ) {
+ o.display = settings.fnFormatNumber( button + 1 );
+
+ if (page === button) {
+ o.active = true;
+ }
+ }
+ break;
+ }
+
+ return o;
+ }
/**
- * Reference to internal functions for use by plug-in developers. Note that
- * these methods are references to internal functions and are considered to be
- * private. If you use these methods, be aware that they are liable to change
- * between versions.
- * @namespace
+ * Compute what number buttons to show in the paging control
+ *
+ * @param {*} page Current page
+ * @param {*} pages Total number of pages
+ * @param {*} buttons Target number of number buttons
+ * @returns Buttons to show
*/
- $.extend( DataTable.ext.internal, {
- _fnExternApiFunc: _fnExternApiFunc,
- _fnBuildAjax: _fnBuildAjax,
- _fnAjaxUpdate: _fnAjaxUpdate,
- _fnAjaxParameters: _fnAjaxParameters,
- _fnAjaxUpdateDraw: _fnAjaxUpdateDraw,
- _fnAjaxDataSrc: _fnAjaxDataSrc,
- _fnAddColumn: _fnAddColumn,
- _fnColumnOptions: _fnColumnOptions,
- _fnAdjustColumnSizing: _fnAdjustColumnSizing,
- _fnVisibleToColumnIndex: _fnVisibleToColumnIndex,
- _fnColumnIndexToVisible: _fnColumnIndexToVisible,
- _fnVisbleColumns: _fnVisbleColumns,
- _fnGetColumns: _fnGetColumns,
- _fnColumnTypes: _fnColumnTypes,
- _fnApplyColumnDefs: _fnApplyColumnDefs,
- _fnHungarianMap: _fnHungarianMap,
- _fnCamelToHungarian: _fnCamelToHungarian,
- _fnLanguageCompat: _fnLanguageCompat,
- _fnBrowserDetect: _fnBrowserDetect,
- _fnAddData: _fnAddData,
- _fnAddTr: _fnAddTr,
- _fnNodeToDataIndex: _fnNodeToDataIndex,
- _fnNodeToColumnIndex: _fnNodeToColumnIndex,
- _fnGetCellData: _fnGetCellData,
- _fnSetCellData: _fnSetCellData,
- _fnSplitObjNotation: _fnSplitObjNotation,
- _fnGetObjectDataFn: _fnGetObjectDataFn,
- _fnSetObjectDataFn: _fnSetObjectDataFn,
- _fnGetDataMaster: _fnGetDataMaster,
- _fnClearTable: _fnClearTable,
- _fnDeleteIndex: _fnDeleteIndex,
- _fnInvalidate: _fnInvalidate,
- _fnGetRowElements: _fnGetRowElements,
- _fnCreateTr: _fnCreateTr,
- _fnBuildHead: _fnBuildHead,
- _fnDrawHead: _fnDrawHead,
- _fnDraw: _fnDraw,
- _fnReDraw: _fnReDraw,
- _fnAddOptionsHtml: _fnAddOptionsHtml,
- _fnDetectHeader: _fnDetectHeader,
- _fnGetUniqueThs: _fnGetUniqueThs,
- _fnFeatureHtmlFilter: _fnFeatureHtmlFilter,
- _fnFilterComplete: _fnFilterComplete,
- _fnFilterCustom: _fnFilterCustom,
- _fnFilterColumn: _fnFilterColumn,
- _fnFilter: _fnFilter,
- _fnFilterCreateSearch: _fnFilterCreateSearch,
- _fnEscapeRegex: _fnEscapeRegex,
- _fnFilterData: _fnFilterData,
- _fnFeatureHtmlInfo: _fnFeatureHtmlInfo,
- _fnUpdateInfo: _fnUpdateInfo,
- _fnInfoMacros: _fnInfoMacros,
- _fnInitialise: _fnInitialise,
- _fnInitComplete: _fnInitComplete,
- _fnLengthChange: _fnLengthChange,
- _fnFeatureHtmlLength: _fnFeatureHtmlLength,
- _fnFeatureHtmlPaginate: _fnFeatureHtmlPaginate,
- _fnPageChange: _fnPageChange,
- _fnFeatureHtmlProcessing: _fnFeatureHtmlProcessing,
- _fnProcessingDisplay: _fnProcessingDisplay,
- _fnFeatureHtmlTable: _fnFeatureHtmlTable,
- _fnScrollDraw: _fnScrollDraw,
- _fnApplyToChildren: _fnApplyToChildren,
- _fnCalculateColumnWidths: _fnCalculateColumnWidths,
- _fnThrottle: _fnThrottle,
- _fnConvertToWidth: _fnConvertToWidth,
- _fnGetWidestNode: _fnGetWidestNode,
- _fnGetMaxLenString: _fnGetMaxLenString,
- _fnStringToCss: _fnStringToCss,
- _fnSortFlatten: _fnSortFlatten,
- _fnSort: _fnSort,
- _fnSortAria: _fnSortAria,
- _fnSortListener: _fnSortListener,
- _fnSortAttachListener: _fnSortAttachListener,
- _fnSortingClasses: _fnSortingClasses,
- _fnSortData: _fnSortData,
- _fnSaveState: _fnSaveState,
- _fnLoadState: _fnLoadState,
- _fnImplementState: _fnImplementState,
- _fnSettingsFromNode: _fnSettingsFromNode,
- _fnLog: _fnLog,
- _fnMap: _fnMap,
- _fnBindAction: _fnBindAction,
- _fnCallbackReg: _fnCallbackReg,
- _fnCallbackFire: _fnCallbackFire,
- _fnLengthOverflow: _fnLengthOverflow,
- _fnRenderer: _fnRenderer,
- _fnDataSource: _fnDataSource,
- _fnRowAttributes: _fnRowAttributes,
- _fnExtend: _fnExtend,
- _fnCalculateEnd: function () {} // Used by a lot of plug-ins, but redundant
- // in 1.10, so this dead-end function is
- // added to prevent errors
- } );
+ function _pagingNumbers ( page, pages, buttons ) {
+ var
+ numbers = [],
+ half = Math.floor(buttons / 2);
+
+ if ( pages <= buttons ) {
+ numbers = _range(0, pages);
+ }
+ else if (buttons === 1) {
+ // Single button - current page only
+ numbers = [page];
+ }
+ else if (buttons === 3) {
+ // Special logic for just three buttons
+ if (page <= 1) {
+ numbers = [0, 1, 'ellipsis'];
+ }
+ else if (page >= pages - 2) {
+ numbers = _range(pages-2, pages);
+ numbers.unshift('ellipsis');
+ }
+ else {
+ numbers = ['ellipsis', page, 'ellipsis'];
+ }
+ }
+ else if ( page <= half ) {
+ numbers = _range(0, buttons-2);
+ numbers.push('ellipsis', pages-1);
+ }
+ else if ( page >= pages - 1 - half ) {
+ numbers = _range(pages-(buttons-2), pages);
+ numbers.unshift(0, 'ellipsis');
+ }
+ else {
+ numbers = _range(page-half+2, page+half-1);
+ numbers.push('ellipsis', pages-1);
+ numbers.unshift(0, 'ellipsis');
+ }
+
+ return numbers;
+ }
+
+ var __lengthCounter = 0;
+
+ // opts
+ // - menu
+ // - text
+ DataTable.feature.register( 'pageLength', function ( settings, opts ) {
+ var features = settings.oFeatures;
+
+ // For compatibility with the legacy `pageLength` top level option
+ if (! features.bPaginate || ! features.bLengthChange) {
+ return null;
+ }
+
+ opts = $.extend({
+ menu: settings.aLengthMenu,
+ text: settings.oLanguage.sLengthMenu
+ }, opts);
+
+ var
+ classes = settings.oClasses.length,
+ tableId = settings.sTableId,
+ menu = opts.menu,
+ lengths = [],
+ language = [],
+ i;
+
+ // Options can be given in a number of ways
+ if (Array.isArray( menu[0] )) {
+ // Old 1.x style - 2D array
+ lengths = menu[0];
+ language = menu[1];
+ }
+ else {
+ for ( i=0 ; i<menu.length ; i++ ) {
+ // An object with different label and value
+ if ($.isPlainObject(menu[i])) {
+ lengths.push(menu[i].value);
+ language.push(menu[i].label);
+ }
+ else {
+ // Or just a number to display and use
+ lengths.push(menu[i]);
+ language.push(menu[i]);
+ }
+ }
+ }
+
+ // We can put the <select> outside of the label if it is at the start or
+ // end which helps improve accessability (not all screen readers like
+ // implicit for elements).
+ var end = opts.text.match(/_MENU_$/);
+ var start = opts.text.match(/^_MENU_/);
+ var removed = opts.text.replace(/_MENU_/, '');
+ var str = '<label>' + opts.text + '</label>';
+
+ if (start) {
+ str = '_MENU_<label>' + removed + '</label>';
+ }
+ else if (end) {
+ str = '<label>' + removed + '</label>_MENU_';
+ }
+
+ // Wrapper element - use a span as a holder for where the select will go
+ var div = $('<div/>')
+ .addClass( classes.container )
+ .append(
+ str.replace( '_MENU_', '<span></span>' )
+ );
+
+ // Save text node content for macro updating
+ var textNodes = [];
+ div.find('label')[0].childNodes.forEach(function (el) {
+ if (el.nodeType === Node.TEXT_NODE) {
+ textNodes.push({
+ el: el,
+ text: el.textContent
+ });
+ }
+ })
+
+ // Update the label text in case it has an entries value
+ var updateEntries = function (len) {
+ textNodes.forEach(function (node) {
+ node.el.textContent = _fnMacros(settings, node.text, len);
+ });
+ }
+
+ // Next, the select itself, along with the options
+ var select = $('<select/>', {
+ 'name': tableId+'_length',
+ 'aria-controls': tableId,
+ 'class': classes.select
+ } );
+
+ for ( i=0 ; i<lengths.length ; i++ ) {
+ select[0][ i ] = new Option(
+ typeof language[i] === 'number' ?
+ settings.fnFormatNumber( language[i] ) :
+ language[i],
+ lengths[i]
+ );
+ }
+
+ // add for and id to label and input
+ div.find('label').attr('for', 'dt-length-' + __lengthCounter);
+ select.attr('id', 'dt-length-' + __lengthCounter);
+ __lengthCounter++;
+ // Swap in the select list
+ div.find('span').replaceWith(select);
+
+ // Can't use `select` variable as user might provide their own and the
+ // reference is broken by the use of outerHTML
+ $('select', div)
+ .val( settings._iDisplayLength )
+ .on( 'change.DT', function() {
+ _fnLengthChange( settings, $(this).val() );
+ _fnDraw( settings );
+ } );
+
+ // Update node value whenever anything changes the table's length
+ $(settings.nTable).on( 'length.dt.DT', function (e, s, len) {
+ if ( settings === s ) {
+ $('select', div).val( len );
+
+ // Resolve plurals in the text for the new length
+ updateEntries(len);
+ }
+ } );
+
+ updateEntries(settings._iDisplayLength);
+
+ return div;
+ }, 'l' );
// jQuery access
$.fn.dataTable = DataTable;
@@ -15768,7 +13627,7 @@
// Browser
factory( jQuery, window, document );
}
-}(function( $, window, document, undefined ) {
+}(function( $, window, document ) {
'use strict';
var DataTable = $.fn.dataTable;
@@ -15776,160 +13635,96 @@ var DataTable = $.fn.dataTable;
/**
* DataTables integration for Bootstrap 5. This requires Bootstrap 5 and
- * DataTables 1.10 or newer.
+ * DataTables 2 or newer.
*
* This file sets the defaults and adds options to DataTables to style its
- * controls using Bootstrap. See http://datatables.net/manual/styling/bootstrap
+ * controls using Bootstrap. See https://datatables.net/manual/styling/bootstrap
* for further information.
*/
/* Set the defaults for DataTables initialisation */
$.extend( true, DataTable.defaults, {
- dom:
- "<'row'<'col-sm-12 col-md-6'l><'col-sm-12 col-md-6'f>>" +
- "<'row dt-row'<'col-sm-12'tr>>" +
- "<'row'<'col-sm-12 col-md-5'i><'col-sm-12 col-md-7'p>>",
renderer: 'bootstrap'
} );
/* Default class modification */
-$.extend( DataTable.ext.classes, {
- sWrapper: "dataTables_wrapper dt-bootstrap5",
- sFilterInput: "form-control form-control-sm",
- sLengthSelect: "form-select form-select-sm",
- sProcessing: "dataTables_processing card",
- sPageButton: "paginate_button page-item"
+$.extend( true, DataTable.ext.classes, {
+ container: "dt-container dt-bootstrap5",
+ search: {
+ input: "form-control form-control-sm"
+ },
+ length: {
+ select: "form-select form-select-sm"
+ },
+ processing: {
+ container: "dt-processing card"
+ }
} );
/* Bootstrap paging button renderer */
-DataTable.ext.renderer.pageButton.bootstrap = function ( settings, host, idx, buttons, page, pages ) {
- var api = new DataTable.Api( settings );
- var classes = settings.oClasses;
- var lang = settings.oLanguage.oPaginate;
- var aria = settings.oLanguage.oAria.paginate || {};
- var btnDisplay, btnClass;
-
- var attach = function( container, buttons ) {
- var i, ien, node, button;
- var clickHandler = function ( e ) {
- e.preventDefault();
- if ( !$(e.currentTarget).hasClass('disabled') && api.page() != e.data.action ) {
- api.page( e.data.action ).draw( 'page' );
- }
- };
-
- for ( i=0, ien=buttons.length ; i<ien ; i++ ) {
- button = buttons[i];
-
- if ( Array.isArray( button ) ) {
- attach( container, button );
- }
- else {
- btnDisplay = '';
- btnClass = '';
-
- switch ( button ) {
- case 'ellipsis':
- btnDisplay = '&#x2026;';
- btnClass = 'disabled';
- break;
-
- case 'first':
- btnDisplay = lang.sFirst;
- btnClass = button + (page > 0 ?
- '' : ' disabled');
- break;
-
- case 'previous':
- btnDisplay = lang.sPrevious;
- btnClass = button + (page > 0 ?
- '' : ' disabled');
- break;
+DataTable.ext.renderer.pagingButton.bootstrap = function (settings, buttonType, content, active, disabled) {
+ var btnClasses = ['dt-paging-button', 'page-item'];
- case 'next':
- btnDisplay = lang.sNext;
- btnClass = button + (page < pages-1 ?
- '' : ' disabled');
- break;
-
- case 'last':
- btnDisplay = lang.sLast;
- btnClass = button + (page < pages-1 ?
- '' : ' disabled');
- break;
-
- default:
- btnDisplay = button + 1;
- btnClass = page === button ?
- 'active' : '';
- break;
- }
+ if (active) {
+ btnClasses.push('active');
+ }
- if ( btnDisplay ) {
- var disabled = btnClass.indexOf('disabled') !== -1;
+ if (disabled) {
+ btnClasses.push('disabled')
+ }
- node = $('<li>', {
- 'class': classes.sPageButton+' '+btnClass,
- 'id': idx === 0 && typeof button === 'string' ?
- settings.sTableId +'_'+ button :
- null
- } )
- .append( $('<a>', {
- 'href': disabled ? null : '#',
- 'aria-controls': settings.sTableId,
- 'aria-disabled': disabled ? 'true' : null,
- 'aria-label': aria[ button ],
- 'role': 'link',
- 'aria-current': btnClass === 'active' ? 'page' : null,
- 'data-dt-idx': button,
- 'tabindex': disabled ? -1 : settings.iTabIndex,
- 'class': 'page-link'
- } )
- .html( btnDisplay )
- )
- .appendTo( container );
+ var li = $('<li>').addClass(btnClasses.join(' '));
+ var a = $('<a>', {
+ 'href': disabled ? null : '#',
+ 'class': 'page-link'
+ })
+ .html(content)
+ .appendTo(li);
- settings.oApi._fnBindAction(
- node, {action: button}, clickHandler
- );
- }
- }
- }
+ return {
+ display: li,
+ clicker: a
};
+};
- var hostEl = $(host);
- // IE9 throws an 'unknown error' if document.activeElement is used
- // inside an iframe or frame.
- var activeEl;
-
- try {
- // Because this approach is destroying and recreating the paging
- // elements, focus is lost on the select button which is bad for
- // accessibility. So we want to restore focus once the draw has
- // completed
- activeEl = hostEl.find(document.activeElement).data('dt-idx');
- }
- catch (e) {}
+DataTable.ext.renderer.pagingContainer.bootstrap = function (settings, buttonEls) {
+ return $('<ul/>').addClass('pagination').append(buttonEls);
+};
- var paginationEl = hostEl.children('ul.pagination');
+DataTable.ext.renderer.layout.bootstrap = function ( settings, container, items ) {
+ var row = $( '<div/>', {
+ "class": items.full ?
+ 'row mt-2 justify-content-md-center' :
+ 'row mt-2 justify-content-between'
+ } )
+ .appendTo( container );
- if (paginationEl.length) {
- paginationEl.empty();
- }
- else {
- paginationEl = hostEl.html('<ul/>').children('ul').addClass('pagination');
- }
+ $.each( items, function (key, val) {
+ var klass;
- attach(
- paginationEl,
- buttons
- );
+ // Apply start / end (left / right when ltr) margins
+ if (val.table) {
+ klass = 'col-12';
+ }
+ else if (key === 'start') {
+ klass = 'col-md-auto me-auto';
+ }
+ else if (key === 'end') {
+ klass = 'col-md-auto ms-auto';
+ }
+ else {
+ klass = 'col-md';
+ }
- if ( activeEl !== undefined ) {
- hostEl.find('[data-dt-idx='+activeEl+']').trigger('focus');
- }
+ $( '<div/>', {
+ id: val.id || null,
+ "class": klass + ' ' + (val.className || '')
+ } )
+ .append( val.contents )
+ .appendTo( row );
+ } );
};
diff --git a/src/static/scripts/jquery-3.7.0.slim.js b/src/static/scripts/jquery-3.7.1.slim.js
index 15a1a291..f122b10d 100644
--- a/src/static/scripts/jquery-3.7.0.slim.js
+++ b/src/static/scripts/jquery-3.7.1.slim.js
@@ -1,12 +1,12 @@
/*!
- * jQuery JavaScript Library v3.7.0 -ajax,-ajax/jsonp,-ajax/load,-ajax/script,-ajax/var/location,-ajax/var/nonce,-ajax/var/rquery,-ajax/xhr,-manipulation/_evalUrl,-deprecated/ajax-event-alias,-effects,-effects/animatedSelector,-effects/Tween
+ * jQuery JavaScript Library v3.7.1 -ajax,-ajax/jsonp,-ajax/load,-ajax/script,-ajax/var/location,-ajax/var/nonce,-ajax/var/rquery,-ajax/xhr,-manipulation/_evalUrl,-deprecated/ajax-event-alias,-effects,-effects/animatedSelector,-effects/Tween
* https://jquery.com/
*
* Copyright OpenJS Foundation and other contributors
* Released under the MIT license
* https://jquery.org/license
*
- * Date: 2023-05-11T18:29Z
+ * Date: 2023-08-28T13:37Z
*/
( function( global, factory ) {
@@ -147,7 +147,7 @@ function toType( obj ) {
-var version = "3.7.0 -ajax,-ajax/jsonp,-ajax/load,-ajax/script,-ajax/var/location,-ajax/var/nonce,-ajax/var/rquery,-ajax/xhr,-manipulation/_evalUrl,-deprecated/ajax-event-alias,-effects,-effects/animatedSelector,-effects/Tween",
+var version = "3.7.1 -ajax,-ajax/jsonp,-ajax/load,-ajax/script,-ajax/var/location,-ajax/var/nonce,-ajax/var/rquery,-ajax/xhr,-manipulation/_evalUrl,-deprecated/ajax-event-alias,-effects,-effects/animatedSelector,-effects/Tween",
rhtmlSuffix = /HTML$/i,
@@ -411,9 +411,14 @@ jQuery.extend( {
// Do not traverse comment nodes
ret += jQuery.text( node );
}
- } else if ( nodeType === 1 || nodeType === 9 || nodeType === 11 ) {
+ }
+ if ( nodeType === 1 || nodeType === 11 ) {
return elem.textContent;
- } else if ( nodeType === 3 || nodeType === 4 ) {
+ }
+ if ( nodeType === 9 ) {
+ return elem.documentElement.textContent;
+ }
+ if ( nodeType === 3 || nodeType === 4 ) {
return elem.nodeValue;
}
@@ -1126,12 +1131,17 @@ function setDocument( node ) {
documentElement.msMatchesSelector;
// Support: IE 9 - 11+, Edge 12 - 18+
- // Accessing iframe documents after unload throws "permission denied" errors (see trac-13936)
- // Support: IE 11+, Edge 17 - 18+
- // IE/Edge sometimes throw a "Permission denied" error when strict-comparing
- // two documents; shallow comparisons work.
- // eslint-disable-next-line eqeqeq
- if ( preferredDoc != document &&
+ // Accessing iframe documents after unload throws "permission denied" errors
+ // (see trac-13936).
+ // Limit the fix to IE & Edge Legacy; despite Edge 15+ implementing `matches`,
+ // all IE 9+ and Edge Legacy versions implement `msMatchesSelector` as well.
+ if ( documentElement.msMatchesSelector &&
+
+ // Support: IE 11+, Edge 17 - 18+
+ // IE/Edge sometimes throw a "Permission denied" error when strict-comparing
+ // two documents; shallow comparisons work.
+ // eslint-disable-next-line eqeqeq
+ preferredDoc != document &&
( subWindow = document.defaultView ) && subWindow.top !== subWindow ) {
// Support: IE 9 - 11+, Edge 12 - 18+
@@ -2694,12 +2704,12 @@ jQuery.find = find;
jQuery.expr[ ":" ] = jQuery.expr.pseudos;
jQuery.unique = jQuery.uniqueSort;
-// These have always been private, but they used to be documented
-// as part of Sizzle so let's maintain them in the 3.x line
-// for backwards compatibility purposes.
+// These have always been private, but they used to be documented as part of
+// Sizzle so let's maintain them for now for backwards compatibility purposes.
find.compile = compile;
find.select = select;
find.setDocument = setDocument;
+find.tokenize = tokenize;
find.escape = jQuery.escapeSelector;
find.getText = jQuery.text;
@@ -5913,7 +5923,7 @@ function domManip( collection, args, callback, ignored ) {
if ( hasScripts ) {
doc = scripts[ scripts.length - 1 ].ownerDocument;
- // Reenable scripts
+ // Re-enable scripts
jQuery.map( scripts, restoreScript );
// Evaluate executable scripts on first document insertion
@@ -6370,7 +6380,7 @@ var rboxStyle = new RegExp( cssExpand.join( "|" ), "i" );
trChild = document.createElement( "div" );
table.style.cssText = "position:absolute;left:-11111px;border-collapse:separate";
- tr.style.cssText = "border:1px solid";
+ tr.style.cssText = "box-sizing:content-box;border:1px solid";
// Support: Chrome 86+
// Height set through cssText does not get applied.
@@ -6382,7 +6392,7 @@ var rboxStyle = new RegExp( cssExpand.join( "|" ), "i" );
// In our bodyBackground.html iframe,
// display for all div elements is set to "inline",
// which causes a problem only in Android 8 Chrome 86.
- // Ensuring the div is display: block
+ // Ensuring the div is `display: block`
// gets around this issue.
trChild.style.display = "block";
@@ -8451,7 +8461,9 @@ jQuery.fn.extend( {
},
hover: function( fnOver, fnOut ) {
- return this.mouseenter( fnOver ).mouseleave( fnOut || fnOver );
+ return this
+ .on( "mouseenter", fnOver )
+ .on( "mouseleave", fnOut || fnOver );
}
} );
diff --git a/src/static/templates/admin/organizations.hbs b/src/static/templates/admin/organizations.hbs
index f0563cec..ab442e8f 100644
--- a/src/static/templates/admin/organizations.hbs
+++ b/src/static/templates/admin/organizations.hbs
@@ -59,7 +59,7 @@
</main>
<link rel="stylesheet" href="{{urlpath}}/vw_static/datatables.css" />
-<script src="{{urlpath}}/vw_static/jquery-3.7.0.slim.js"></script>
+<script src="{{urlpath}}/vw_static/jquery-3.7.1.slim.js"></script>
<script src="{{urlpath}}/vw_static/datatables.js"></script>
<script src="{{urlpath}}/vw_static/admin_organizations.js"></script>
<script src="{{urlpath}}/vw_static/jdenticon.js"></script>
diff --git a/src/static/templates/admin/users.hbs b/src/static/templates/admin/users.hbs
index d8b7289f..d1fd3e5d 100644
--- a/src/static/templates/admin/users.hbs
+++ b/src/static/templates/admin/users.hbs
@@ -140,7 +140,7 @@
</main>
<link rel="stylesheet" href="{{urlpath}}/vw_static/datatables.css" />
-<script src="{{urlpath}}/vw_static/jquery-3.7.0.slim.js"></script>
+<script src="{{urlpath}}/vw_static/jquery-3.7.1.slim.js"></script>
<script src="{{urlpath}}/vw_static/datatables.js"></script>
<script src="{{urlpath}}/vw_static/admin_users.js"></script>
<script src="{{urlpath}}/vw_static/jdenticon.js"></script>
diff --git a/tools/global_domains.py b/tools/global_domains.py
index 5692d798..bd1df58d 100755
--- a/tools/global_domains.py
+++ b/tools/global_domains.py
@@ -10,19 +10,19 @@ import urllib.request
from collections import OrderedDict
-if not (2 <= len(sys.argv) <= 3):
- print("usage: %s <OUTPUT-FILE> [GIT-REF]" % sys.argv[0])
+if not 2 <= len(sys.argv) <= 3:
+ print(f"usage: {sys.argv[0]} <OUTPUT-FILE> [GIT-REF]")
print()
print("This script generates a global equivalent domains JSON file from")
print("the upstream Bitwarden source repo.")
sys.exit(1)
OUTPUT_FILE = sys.argv[1]
-GIT_REF = 'master' if len(sys.argv) == 2 else sys.argv[2]
+GIT_REF = 'main' if len(sys.argv) == 2 else sys.argv[2]
-BASE_URL = 'https://github.com/bitwarden/server/raw/%s' % GIT_REF
-ENUMS_URL = '%s/src/Core/Enums/GlobalEquivalentDomainsType.cs' % BASE_URL
-DOMAIN_LISTS_URL = '%s/src/Core/Utilities/StaticStore.cs' % BASE_URL
+BASE_URL = f'https://github.com/bitwarden/server/raw/{GIT_REF}'
+ENUMS_URL = f'{BASE_URL}/src/Core/Enums/GlobalEquivalentDomainsType.cs'
+DOMAIN_LISTS_URL = f'{BASE_URL}/src/Core/Utilities/StaticStore.cs'
# Enum lines look like:
#
@@ -77,5 +77,5 @@ for name, domain_list in domain_lists.items():
global_domains.append(entry)
# Write out the global domains JSON file.
-with open(OUTPUT_FILE, 'w') as f:
+with open(file=OUTPUT_FILE, mode='w', encoding='utf-8') as f:
json.dump(global_domains, f, indent=2)