mirror of
https://github.com/dani-garcia/vaultwarden.git
synced 2025-07-18 05:02:47 -04:00
Update admin interface (#5880)
- Updated Backend Admin dependencies - Fixed NTP time by using CloudFlare trace - Fixes #5797 - Fixed web-vault version check = Fixes #5761 - Fixed an issue with the css not hiding the 'Create Account' link. There were no braces around the function call. Also added a hide for newer web-vault versions as it still causes confusion with the cached /api/config. Signed-off-by: BlackDex <black.dex@gmail.com>
This commit is contained in:
parent
a039e227c7
commit
3a44dc963b
@ -591,20 +591,14 @@ struct GitCommit {
|
|||||||
sha: String,
|
sha: String,
|
||||||
}
|
}
|
||||||
|
|
||||||
#[derive(Deserialize)]
|
|
||||||
struct TimeApi {
|
|
||||||
year: u16,
|
|
||||||
month: u8,
|
|
||||||
day: u8,
|
|
||||||
hour: u8,
|
|
||||||
minute: u8,
|
|
||||||
seconds: u8,
|
|
||||||
}
|
|
||||||
|
|
||||||
async fn get_json_api<T: DeserializeOwned>(url: &str) -> Result<T, Error> {
|
async fn get_json_api<T: DeserializeOwned>(url: &str) -> Result<T, Error> {
|
||||||
Ok(make_http_request(Method::GET, url)?.send().await?.error_for_status()?.json::<T>().await?)
|
Ok(make_http_request(Method::GET, url)?.send().await?.error_for_status()?.json::<T>().await?)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
async fn get_text_api(url: &str) -> Result<String, Error> {
|
||||||
|
Ok(make_http_request(Method::GET, url)?.send().await?.error_for_status()?.text().await?)
|
||||||
|
}
|
||||||
|
|
||||||
async fn has_http_access() -> bool {
|
async fn has_http_access() -> bool {
|
||||||
let Ok(req) = make_http_request(Method::HEAD, "https://github.com/dani-garcia/vaultwarden") else {
|
let Ok(req) = make_http_request(Method::HEAD, "https://github.com/dani-garcia/vaultwarden") else {
|
||||||
return false;
|
return false;
|
||||||
@ -616,9 +610,10 @@ async fn has_http_access() -> bool {
|
|||||||
}
|
}
|
||||||
|
|
||||||
use cached::proc_macro::cached;
|
use cached::proc_macro::cached;
|
||||||
/// Cache this function to prevent API call rate limit. Github only allows 60 requests per hour, and we use 3 here already.
|
/// Cache this function to prevent API call rate limit. Github only allows 60 requests per hour, and we use 3 here already
|
||||||
/// It will cache this function for 300 seconds (5 minutes) which should prevent the exhaustion of the rate limit.
|
/// It will cache this function for 600 seconds (10 minutes) which should prevent the exhaustion of the rate limit
|
||||||
#[cached(time = 300, sync_writes = "default")]
|
/// Any cache will be lost if Vaultwarden is restarted
|
||||||
|
#[cached(time = 600, sync_writes = "default")]
|
||||||
async fn get_release_info(has_http_access: bool, running_within_container: bool) -> (String, String, String) {
|
async fn get_release_info(has_http_access: bool, running_within_container: bool) -> (String, String, String) {
|
||||||
// If the HTTP Check failed, do not even attempt to check for new versions since we were not able to connect with github.com anyway.
|
// If the HTTP Check failed, do not even attempt to check for new versions since we were not able to connect with github.com anyway.
|
||||||
if has_http_access {
|
if has_http_access {
|
||||||
@ -636,7 +631,7 @@ async fn get_release_info(has_http_access: bool, running_within_container: bool)
|
|||||||
}
|
}
|
||||||
_ => "-".to_string(),
|
_ => "-".to_string(),
|
||||||
},
|
},
|
||||||
// Do not fetch the web-vault version when running within a container.
|
// Do not fetch the web-vault version when running within a container
|
||||||
// The web-vault version is embedded within the container it self, and should not be updated manually
|
// The web-vault version is embedded within the container it self, and should not be updated manually
|
||||||
if running_within_container {
|
if running_within_container {
|
||||||
"-".to_string()
|
"-".to_string()
|
||||||
@ -658,17 +653,18 @@ async fn get_release_info(has_http_access: bool, running_within_container: bool)
|
|||||||
|
|
||||||
async fn get_ntp_time(has_http_access: bool) -> String {
|
async fn get_ntp_time(has_http_access: bool) -> String {
|
||||||
if has_http_access {
|
if has_http_access {
|
||||||
if let Ok(ntp_time) = get_json_api::<TimeApi>("https://www.timeapi.io/api/Time/current/zone?timeZone=UTC").await
|
if let Ok(cf_trace) = get_text_api("https://cloudflare.com/cdn-cgi/trace").await {
|
||||||
{
|
for line in cf_trace.lines() {
|
||||||
return format!(
|
if let Some((key, value)) = line.split_once('=') {
|
||||||
"{year}-{month:02}-{day:02} {hour:02}:{minute:02}:{seconds:02} UTC",
|
if key == "ts" {
|
||||||
year = ntp_time.year,
|
let ts = value.split_once('.').map_or(value, |(s, _)| s);
|
||||||
month = ntp_time.month,
|
if let Ok(dt) = chrono::DateTime::parse_from_str(ts, "%s") {
|
||||||
day = ntp_time.day,
|
return dt.format("%Y-%m-%d %H:%M:%S UTC").to_string();
|
||||||
hour = ntp_time.hour,
|
}
|
||||||
minute = ntp_time.minute,
|
break;
|
||||||
seconds = ntp_time.seconds
|
}
|
||||||
);
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
String::from("Unable to fetch NTP time.")
|
String::from("Unable to fetch NTP time.")
|
||||||
@ -701,6 +697,12 @@ async fn diagnostics(_token: AdminToken, ip_header: IpHeader, mut conn: DbConn)
|
|||||||
// Get current running versions
|
// Get current running versions
|
||||||
let web_vault_version = get_web_vault_version();
|
let web_vault_version = get_web_vault_version();
|
||||||
|
|
||||||
|
// Check if the running version is newer than the latest stable released version
|
||||||
|
let web_ver_match = semver::VersionReq::parse(&format!(">{latest_web_build}")).unwrap();
|
||||||
|
let web_vault_pre_release = web_ver_match.matches(
|
||||||
|
&semver::Version::parse(&web_vault_version).unwrap_or_else(|_| semver::Version::parse("2025.1.1").unwrap()),
|
||||||
|
);
|
||||||
|
|
||||||
let diagnostics_json = json!({
|
let diagnostics_json = json!({
|
||||||
"dns_resolved": dns_resolved,
|
"dns_resolved": dns_resolved,
|
||||||
"current_release": VERSION,
|
"current_release": VERSION,
|
||||||
@ -709,6 +711,7 @@ async fn diagnostics(_token: AdminToken, ip_header: IpHeader, mut conn: DbConn)
|
|||||||
"web_vault_enabled": &CONFIG.web_vault_enabled(),
|
"web_vault_enabled": &CONFIG.web_vault_enabled(),
|
||||||
"web_vault_version": web_vault_version,
|
"web_vault_version": web_vault_version,
|
||||||
"latest_web_build": latest_web_build,
|
"latest_web_build": latest_web_build,
|
||||||
|
"web_vault_pre_release": web_vault_pre_release,
|
||||||
"running_within_container": running_within_container,
|
"running_within_container": running_within_container,
|
||||||
"container_base_image": if running_within_container { container_base_image() } else { "Not applicable" },
|
"container_base_image": if running_within_container { container_base_image() } else { "Not applicable" },
|
||||||
"has_http_access": has_http_access,
|
"has_http_access": has_http_access,
|
||||||
@ -724,6 +727,7 @@ async fn diagnostics(_token: AdminToken, ip_header: IpHeader, mut conn: DbConn)
|
|||||||
"overrides": &CONFIG.get_overrides().join(", "),
|
"overrides": &CONFIG.get_overrides().join(", "),
|
||||||
"host_arch": env::consts::ARCH,
|
"host_arch": env::consts::ARCH,
|
||||||
"host_os": env::consts::OS,
|
"host_os": env::consts::OS,
|
||||||
|
"tz_env": env::var("TZ").unwrap_or_default(),
|
||||||
"server_time_local": Local::now().format("%Y-%m-%d %H:%M:%S %Z").to_string(),
|
"server_time_local": Local::now().format("%Y-%m-%d %H:%M:%S %Z").to_string(),
|
||||||
"server_time": Utc::now().format("%Y-%m-%d %H:%M:%S UTC").to_string(), // Run the server date/time check as late as possible to minimize the time difference
|
"server_time": Utc::now().format("%Y-%m-%d %H:%M:%S UTC").to_string(), // Run the server date/time check as late as possible to minimize the time difference
|
||||||
"ntp_time": get_ntp_time(has_http_access).await, // Run the ntp check as late as possible to minimize the time difference
|
"ntp_time": get_ntp_time(has_http_access).await, // Run the ntp check as late as possible to minimize the time difference
|
||||||
|
@ -128,9 +128,8 @@ async fn is_email_2fa_required(member_id: Option<MembershipId>, conn: &mut DbCon
|
|||||||
if CONFIG.email_2fa_enforce_on_verified_invite() {
|
if CONFIG.email_2fa_enforce_on_verified_invite() {
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
if member_id.is_some() {
|
if let Some(member_id) = member_id {
|
||||||
return OrgPolicy::is_enabled_for_member(&member_id.unwrap(), OrgPolicyType::TwoFactorAuthentication, conn)
|
return OrgPolicy::is_enabled_for_member(&member_id, OrgPolicyType::TwoFactorAuthentication, conn).await;
|
||||||
.await;
|
|
||||||
}
|
}
|
||||||
false
|
false
|
||||||
}
|
}
|
||||||
|
@ -1581,7 +1581,7 @@ async fn move_cipher_selected(
|
|||||||
nt.send_cipher_update(
|
nt.send_cipher_update(
|
||||||
UpdateType::SyncCipherUpdate,
|
UpdateType::SyncCipherUpdate,
|
||||||
&cipher,
|
&cipher,
|
||||||
&[user_id.clone()],
|
std::slice::from_ref(&user_id),
|
||||||
&headers.device.uuid,
|
&headers.device.uuid,
|
||||||
None,
|
None,
|
||||||
&mut conn,
|
&mut conn,
|
||||||
|
4
src/static/scripts/admin.css
vendored
4
src/static/scripts/admin.css
vendored
@ -38,8 +38,8 @@ img {
|
|||||||
max-width: 130px;
|
max-width: 130px;
|
||||||
}
|
}
|
||||||
#users-table .vw-actions, #orgs-table .vw-actions {
|
#users-table .vw-actions, #orgs-table .vw-actions {
|
||||||
min-width: 135px;
|
min-width: 155px;
|
||||||
max-width: 140px;
|
max-width: 160px;
|
||||||
}
|
}
|
||||||
#users-table .vw-org-cell {
|
#users-table .vw-org-cell {
|
||||||
max-height: 120px;
|
max-height: 120px;
|
||||||
|
17
src/static/scripts/admin_diagnostics.js
vendored
17
src/static/scripts/admin_diagnostics.js
vendored
@ -29,7 +29,7 @@ function isValidIp(ip) {
|
|||||||
return ipv4Regex.test(ip) || ipv6Regex.test(ip);
|
return ipv4Regex.test(ip) || ipv6Regex.test(ip);
|
||||||
}
|
}
|
||||||
|
|
||||||
function checkVersions(platform, installed, latest, commit=null) {
|
function checkVersions(platform, installed, latest, commit=null, pre_release=false) {
|
||||||
if (installed === "-" || latest === "-") {
|
if (installed === "-" || latest === "-") {
|
||||||
document.getElementById(`${platform}-failed`).classList.remove("d-none");
|
document.getElementById(`${platform}-failed`).classList.remove("d-none");
|
||||||
return;
|
return;
|
||||||
@ -37,10 +37,12 @@ function checkVersions(platform, installed, latest, commit=null) {
|
|||||||
|
|
||||||
// Only check basic versions, no commit revisions
|
// Only check basic versions, no commit revisions
|
||||||
if (commit === null || installed.indexOf("-") === -1) {
|
if (commit === null || installed.indexOf("-") === -1) {
|
||||||
if (installed !== latest) {
|
if (platform === "web" && pre_release === true) {
|
||||||
document.getElementById(`${platform}-warning`).classList.remove("d-none");
|
document.getElementById(`${platform}-prerelease`).classList.remove("d-none");
|
||||||
} else {
|
} else if (installed == latest) {
|
||||||
document.getElementById(`${platform}-success`).classList.remove("d-none");
|
document.getElementById(`${platform}-success`).classList.remove("d-none");
|
||||||
|
} else {
|
||||||
|
document.getElementById(`${platform}-warning`).classList.remove("d-none");
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
// Check if this is a branched version.
|
// Check if this is a branched version.
|
||||||
@ -86,7 +88,7 @@ async function generateSupportString(event, dj) {
|
|||||||
supportString += `* Running within a container: ${dj.running_within_container} (Base: ${dj.container_base_image})\n`;
|
supportString += `* Running within a container: ${dj.running_within_container} (Base: ${dj.container_base_image})\n`;
|
||||||
supportString += `* Database type: ${dj.db_type}\n`;
|
supportString += `* Database type: ${dj.db_type}\n`;
|
||||||
supportString += `* Database version: ${dj.db_version}\n`;
|
supportString += `* Database version: ${dj.db_version}\n`;
|
||||||
supportString += `* Environment settings overridden!: ${dj.overrides !== ""}\n`;
|
supportString += `* Uses config.json: ${dj.overrides !== ""}\n`;
|
||||||
supportString += `* Uses a reverse proxy: ${dj.ip_header_exists}\n`;
|
supportString += `* Uses a reverse proxy: ${dj.ip_header_exists}\n`;
|
||||||
if (dj.ip_header_exists) {
|
if (dj.ip_header_exists) {
|
||||||
supportString += `* IP Header check: ${dj.ip_header_match} (${dj.ip_header_name})\n`;
|
supportString += `* IP Header check: ${dj.ip_header_match} (${dj.ip_header_name})\n`;
|
||||||
@ -94,6 +96,9 @@ async function generateSupportString(event, dj) {
|
|||||||
supportString += `* Internet access: ${dj.has_http_access}\n`;
|
supportString += `* Internet access: ${dj.has_http_access}\n`;
|
||||||
supportString += `* Internet access via a proxy: ${dj.uses_proxy}\n`;
|
supportString += `* Internet access via a proxy: ${dj.uses_proxy}\n`;
|
||||||
supportString += `* DNS Check: ${dnsCheck}\n`;
|
supportString += `* DNS Check: ${dnsCheck}\n`;
|
||||||
|
if (dj.tz_env !== "") {
|
||||||
|
supportString += `* TZ environment: ${dj.tz_env}\n`;
|
||||||
|
}
|
||||||
supportString += `* Browser/Server Time Check: ${timeCheck}\n`;
|
supportString += `* Browser/Server Time Check: ${timeCheck}\n`;
|
||||||
supportString += `* Server/NTP Time Check: ${ntpTimeCheck}\n`;
|
supportString += `* Server/NTP Time Check: ${ntpTimeCheck}\n`;
|
||||||
supportString += `* Domain Configuration Check: ${domainCheck}\n`;
|
supportString += `* Domain Configuration Check: ${domainCheck}\n`;
|
||||||
@ -206,7 +211,7 @@ function initVersionCheck(dj) {
|
|||||||
if (!dj.running_within_container) {
|
if (!dj.running_within_container) {
|
||||||
const webInstalled = dj.web_vault_version;
|
const webInstalled = dj.web_vault_version;
|
||||||
const webLatest = dj.latest_web_build;
|
const webLatest = dj.latest_web_build;
|
||||||
checkVersions("web", webInstalled, webLatest);
|
checkVersions("web", webInstalled, webLatest, null, dj.web_vault_pre_release);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
14
src/static/scripts/bootstrap.bundle.js
vendored
14
src/static/scripts/bootstrap.bundle.js
vendored
@ -1,5 +1,5 @@
|
|||||||
/*!
|
/*!
|
||||||
* Bootstrap v5.3.4 (https://getbootstrap.com/)
|
* Bootstrap v5.3.6 (https://getbootstrap.com/)
|
||||||
* Copyright 2011-2025 The Bootstrap Authors (https://github.com/twbs/bootstrap/graphs/contributors)
|
* Copyright 2011-2025 The Bootstrap Authors (https://github.com/twbs/bootstrap/graphs/contributors)
|
||||||
* Licensed under MIT (https://github.com/twbs/bootstrap/blob/main/LICENSE)
|
* Licensed under MIT (https://github.com/twbs/bootstrap/blob/main/LICENSE)
|
||||||
*/
|
*/
|
||||||
@ -647,7 +647,7 @@
|
|||||||
* Constants
|
* Constants
|
||||||
*/
|
*/
|
||||||
|
|
||||||
const VERSION = '5.3.4';
|
const VERSION = '5.3.6';
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Class definition
|
* Class definition
|
||||||
@ -673,6 +673,8 @@
|
|||||||
this[propertyName] = null;
|
this[propertyName] = null;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Private
|
||||||
_queueCallback(callback, element, isAnimated = true) {
|
_queueCallback(callback, element, isAnimated = true) {
|
||||||
executeAfterTransition(callback, element, isAnimated);
|
executeAfterTransition(callback, element, isAnimated);
|
||||||
}
|
}
|
||||||
@ -1604,11 +1606,11 @@
|
|||||||
this._element.style[dimension] = '';
|
this._element.style[dimension] = '';
|
||||||
this._queueCallback(complete, this._element, true);
|
this._queueCallback(complete, this._element, true);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Private
|
||||||
_isShown(element = this._element) {
|
_isShown(element = this._element) {
|
||||||
return element.classList.contains(CLASS_NAME_SHOW$7);
|
return element.classList.contains(CLASS_NAME_SHOW$7);
|
||||||
}
|
}
|
||||||
|
|
||||||
// Private
|
|
||||||
_configAfterMerge(config) {
|
_configAfterMerge(config) {
|
||||||
config.toggle = Boolean(config.toggle); // Coerce string values
|
config.toggle = Boolean(config.toggle); // Coerce string values
|
||||||
config.parent = getElement(config.parent);
|
config.parent = getElement(config.parent);
|
||||||
@ -3688,6 +3690,9 @@
|
|||||||
this._element.setAttribute('aria-expanded', 'false');
|
this._element.setAttribute('aria-expanded', 'false');
|
||||||
Manipulator.removeDataAttribute(this._menu, 'popper');
|
Manipulator.removeDataAttribute(this._menu, 'popper');
|
||||||
EventHandler.trigger(this._element, EVENT_HIDDEN$5, relatedTarget);
|
EventHandler.trigger(this._element, EVENT_HIDDEN$5, relatedTarget);
|
||||||
|
|
||||||
|
// Explicitly return focus to the trigger element
|
||||||
|
this._element.focus();
|
||||||
}
|
}
|
||||||
_getConfig(config) {
|
_getConfig(config) {
|
||||||
config = super._getConfig(config);
|
config = super._getConfig(config);
|
||||||
@ -6209,7 +6214,6 @@
|
|||||||
}
|
}
|
||||||
|
|
||||||
// Private
|
// Private
|
||||||
|
|
||||||
_maybeScheduleHide() {
|
_maybeScheduleHide() {
|
||||||
if (!this._config.autohide) {
|
if (!this._config.autohide) {
|
||||||
return;
|
return;
|
||||||
|
45
src/static/scripts/bootstrap.css
vendored
45
src/static/scripts/bootstrap.css
vendored
@ -1,6 +1,6 @@
|
|||||||
@charset "UTF-8";
|
@charset "UTF-8";
|
||||||
/*!
|
/*!
|
||||||
* Bootstrap v5.3.4 (https://getbootstrap.com/)
|
* Bootstrap v5.3.6 (https://getbootstrap.com/)
|
||||||
* Copyright 2011-2025 The Bootstrap Authors
|
* Copyright 2011-2025 The Bootstrap Authors
|
||||||
* Licensed under MIT (https://github.com/twbs/bootstrap/blob/main/LICENSE)
|
* Licensed under MIT (https://github.com/twbs/bootstrap/blob/main/LICENSE)
|
||||||
*/
|
*/
|
||||||
@ -2156,10 +2156,6 @@ progress {
|
|||||||
display: block;
|
display: block;
|
||||||
padding: 0;
|
padding: 0;
|
||||||
}
|
}
|
||||||
.form-control::-moz-placeholder {
|
|
||||||
color: var(--bs-secondary-color);
|
|
||||||
opacity: 1;
|
|
||||||
}
|
|
||||||
.form-control::placeholder {
|
.form-control::placeholder {
|
||||||
color: var(--bs-secondary-color);
|
color: var(--bs-secondary-color);
|
||||||
opacity: 1;
|
opacity: 1;
|
||||||
@ -2629,17 +2625,10 @@ textarea.form-control-lg {
|
|||||||
.form-floating > .form-control-plaintext {
|
.form-floating > .form-control-plaintext {
|
||||||
padding: 1rem 0.75rem;
|
padding: 1rem 0.75rem;
|
||||||
}
|
}
|
||||||
.form-floating > .form-control::-moz-placeholder, .form-floating > .form-control-plaintext::-moz-placeholder {
|
|
||||||
color: transparent;
|
|
||||||
}
|
|
||||||
.form-floating > .form-control::placeholder,
|
.form-floating > .form-control::placeholder,
|
||||||
.form-floating > .form-control-plaintext::placeholder {
|
.form-floating > .form-control-plaintext::placeholder {
|
||||||
color: transparent;
|
color: transparent;
|
||||||
}
|
}
|
||||||
.form-floating > .form-control:not(:-moz-placeholder), .form-floating > .form-control-plaintext:not(:-moz-placeholder) {
|
|
||||||
padding-top: 1.625rem;
|
|
||||||
padding-bottom: 0.625rem;
|
|
||||||
}
|
|
||||||
.form-floating > .form-control:focus, .form-floating > .form-control:not(:placeholder-shown),
|
.form-floating > .form-control:focus, .form-floating > .form-control:not(:placeholder-shown),
|
||||||
.form-floating > .form-control-plaintext:focus,
|
.form-floating > .form-control-plaintext:focus,
|
||||||
.form-floating > .form-control-plaintext:not(:placeholder-shown) {
|
.form-floating > .form-control-plaintext:not(:placeholder-shown) {
|
||||||
@ -2656,9 +2645,6 @@ textarea.form-control-lg {
|
|||||||
padding-bottom: 0.625rem;
|
padding-bottom: 0.625rem;
|
||||||
padding-left: 0.75rem;
|
padding-left: 0.75rem;
|
||||||
}
|
}
|
||||||
.form-floating > .form-control:not(:-moz-placeholder) ~ label {
|
|
||||||
transform: scale(0.85) translateY(-0.5rem) translateX(0.15rem);
|
|
||||||
}
|
|
||||||
.form-floating > .form-control:focus ~ label,
|
.form-floating > .form-control:focus ~ label,
|
||||||
.form-floating > .form-control:not(:placeholder-shown) ~ label,
|
.form-floating > .form-control:not(:placeholder-shown) ~ label,
|
||||||
.form-floating > .form-control-plaintext ~ label,
|
.form-floating > .form-control-plaintext ~ label,
|
||||||
@ -2668,15 +2654,6 @@ textarea.form-control-lg {
|
|||||||
.form-floating > .form-control:-webkit-autofill ~ label {
|
.form-floating > .form-control:-webkit-autofill ~ label {
|
||||||
transform: scale(0.85) translateY(-0.5rem) translateX(0.15rem);
|
transform: scale(0.85) translateY(-0.5rem) translateX(0.15rem);
|
||||||
}
|
}
|
||||||
.form-floating > textarea:not(:-moz-placeholder) ~ label::after {
|
|
||||||
position: absolute;
|
|
||||||
inset: 1rem 0.375rem;
|
|
||||||
z-index: -1;
|
|
||||||
height: 1.5em;
|
|
||||||
content: "";
|
|
||||||
background-color: var(--bs-body-bg);
|
|
||||||
border-radius: var(--bs-border-radius);
|
|
||||||
}
|
|
||||||
.form-floating > textarea:focus ~ label::after,
|
.form-floating > textarea:focus ~ label::after,
|
||||||
.form-floating > textarea:not(:placeholder-shown) ~ label::after {
|
.form-floating > textarea:not(:placeholder-shown) ~ label::after {
|
||||||
position: absolute;
|
position: absolute;
|
||||||
@ -4540,24 +4517,24 @@ textarea.form-control-lg {
|
|||||||
border-top-right-radius: 0;
|
border-top-right-radius: 0;
|
||||||
border-bottom-right-radius: 0;
|
border-bottom-right-radius: 0;
|
||||||
}
|
}
|
||||||
.card-group > .card:not(:last-child) .card-img-top,
|
.card-group > .card:not(:last-child) > .card-img-top,
|
||||||
.card-group > .card:not(:last-child) .card-header {
|
.card-group > .card:not(:last-child) > .card-header {
|
||||||
border-top-right-radius: 0;
|
border-top-right-radius: 0;
|
||||||
}
|
}
|
||||||
.card-group > .card:not(:last-child) .card-img-bottom,
|
.card-group > .card:not(:last-child) > .card-img-bottom,
|
||||||
.card-group > .card:not(:last-child) .card-footer {
|
.card-group > .card:not(:last-child) > .card-footer {
|
||||||
border-bottom-right-radius: 0;
|
border-bottom-right-radius: 0;
|
||||||
}
|
}
|
||||||
.card-group > .card:not(:first-child) {
|
.card-group > .card:not(:first-child) {
|
||||||
border-top-left-radius: 0;
|
border-top-left-radius: 0;
|
||||||
border-bottom-left-radius: 0;
|
border-bottom-left-radius: 0;
|
||||||
}
|
}
|
||||||
.card-group > .card:not(:first-child) .card-img-top,
|
.card-group > .card:not(:first-child) > .card-img-top,
|
||||||
.card-group > .card:not(:first-child) .card-header {
|
.card-group > .card:not(:first-child) > .card-header {
|
||||||
border-top-left-radius: 0;
|
border-top-left-radius: 0;
|
||||||
}
|
}
|
||||||
.card-group > .card:not(:first-child) .card-img-bottom,
|
.card-group > .card:not(:first-child) > .card-img-bottom,
|
||||||
.card-group > .card:not(:first-child) .card-footer {
|
.card-group > .card:not(:first-child) > .card-footer {
|
||||||
border-bottom-left-radius: 0;
|
border-bottom-left-radius: 0;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -7179,6 +7156,10 @@ textarea.form-control-lg {
|
|||||||
.visually-hidden-focusable:not(:focus):not(:focus-within):not(caption) {
|
.visually-hidden-focusable:not(:focus):not(:focus-within):not(caption) {
|
||||||
position: absolute !important;
|
position: absolute !important;
|
||||||
}
|
}
|
||||||
|
.visually-hidden *,
|
||||||
|
.visually-hidden-focusable:not(:focus):not(:focus-within) * {
|
||||||
|
overflow: hidden !important;
|
||||||
|
}
|
||||||
|
|
||||||
.stretched-link::after {
|
.stretched-link::after {
|
||||||
position: absolute;
|
position: absolute;
|
||||||
|
121
src/static/scripts/datatables.css
vendored
121
src/static/scripts/datatables.css
vendored
@ -4,10 +4,10 @@
|
|||||||
*
|
*
|
||||||
* To rebuild or modify this file with the latest versions of the included
|
* To rebuild or modify this file with the latest versions of the included
|
||||||
* software please visit:
|
* software please visit:
|
||||||
* https://datatables.net/download/#bs5/dt-2.2.2
|
* https://datatables.net/download/#bs5/dt-2.3.1
|
||||||
*
|
*
|
||||||
* Included libraries:
|
* Included libraries:
|
||||||
* DataTables 2.2.2
|
* DataTables 2.3.1
|
||||||
*/
|
*/
|
||||||
|
|
||||||
:root {
|
:root {
|
||||||
@ -104,24 +104,14 @@ table.dataTable thead > tr > td.dt-ordering-desc span.dt-column-order:after {
|
|||||||
content: "\25BC";
|
content: "\25BC";
|
||||||
content: "\25BC"/"";
|
content: "\25BC"/"";
|
||||||
}
|
}
|
||||||
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 > 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-asc span.dt-column-order,
|
||||||
table.dataTable thead > tr > td.dt-orderable-desc 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-asc span.dt-column-order,
|
||||||
table.dataTable thead > tr > td.dt-ordering-desc span.dt-column-order {
|
table.dataTable thead > tr > td.dt-ordering-desc span.dt-column-order {
|
||||||
position: absolute;
|
position: relative;
|
||||||
right: 12px;
|
|
||||||
top: 0;
|
|
||||||
bottom: 0;
|
|
||||||
width: 12px;
|
width: 12px;
|
||||||
|
height: 20px;
|
||||||
}
|
}
|
||||||
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 > 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:before,
|
||||||
@ -163,6 +153,40 @@ table.dataTable thead > tr > td:active {
|
|||||||
outline: none;
|
outline: none;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
table.dataTable thead > tr > th div.dt-column-header,
|
||||||
|
table.dataTable thead > tr > th div.dt-column-footer,
|
||||||
|
table.dataTable thead > tr > td div.dt-column-header,
|
||||||
|
table.dataTable thead > tr > td div.dt-column-footer,
|
||||||
|
table.dataTable tfoot > tr > th div.dt-column-header,
|
||||||
|
table.dataTable tfoot > tr > th div.dt-column-footer,
|
||||||
|
table.dataTable tfoot > tr > td div.dt-column-header,
|
||||||
|
table.dataTable tfoot > tr > td div.dt-column-footer {
|
||||||
|
display: flex;
|
||||||
|
justify-content: space-between;
|
||||||
|
align-items: center;
|
||||||
|
gap: 4px;
|
||||||
|
}
|
||||||
|
table.dataTable thead > tr > th div.dt-column-header span.dt-column-title,
|
||||||
|
table.dataTable thead > tr > th div.dt-column-footer span.dt-column-title,
|
||||||
|
table.dataTable thead > tr > td div.dt-column-header span.dt-column-title,
|
||||||
|
table.dataTable thead > tr > td div.dt-column-footer span.dt-column-title,
|
||||||
|
table.dataTable tfoot > tr > th div.dt-column-header span.dt-column-title,
|
||||||
|
table.dataTable tfoot > tr > th div.dt-column-footer span.dt-column-title,
|
||||||
|
table.dataTable tfoot > tr > td div.dt-column-header span.dt-column-title,
|
||||||
|
table.dataTable tfoot > tr > td div.dt-column-footer span.dt-column-title {
|
||||||
|
flex-grow: 1;
|
||||||
|
}
|
||||||
|
table.dataTable thead > tr > th div.dt-column-header span.dt-column-title:empty,
|
||||||
|
table.dataTable thead > tr > th div.dt-column-footer span.dt-column-title:empty,
|
||||||
|
table.dataTable thead > tr > td div.dt-column-header span.dt-column-title:empty,
|
||||||
|
table.dataTable thead > tr > td div.dt-column-footer span.dt-column-title:empty,
|
||||||
|
table.dataTable tfoot > tr > th div.dt-column-header span.dt-column-title:empty,
|
||||||
|
table.dataTable tfoot > tr > th div.dt-column-footer span.dt-column-title:empty,
|
||||||
|
table.dataTable tfoot > tr > td div.dt-column-header span.dt-column-title:empty,
|
||||||
|
table.dataTable tfoot > tr > td div.dt-column-footer span.dt-column-title:empty {
|
||||||
|
display: none;
|
||||||
|
}
|
||||||
|
|
||||||
div.dt-scroll-body > table.dataTable > thead > tr > th,
|
div.dt-scroll-body > table.dataTable > thead > tr > th,
|
||||||
div.dt-scroll-body > table.dataTable > thead > tr > td {
|
div.dt-scroll-body > table.dataTable > thead > tr > td {
|
||||||
overflow: hidden;
|
overflow: hidden;
|
||||||
@ -258,10 +282,25 @@ table.dataTable td.dt-type-numeric,
|
|||||||
table.dataTable td.dt-type-date {
|
table.dataTable td.dt-type-date {
|
||||||
text-align: right;
|
text-align: right;
|
||||||
}
|
}
|
||||||
|
table.dataTable th.dt-type-numeric div.dt-column-header,
|
||||||
|
table.dataTable th.dt-type-numeric div.dt-column-footer, table.dataTable th.dt-type-date div.dt-column-header,
|
||||||
|
table.dataTable th.dt-type-date div.dt-column-footer,
|
||||||
|
table.dataTable td.dt-type-numeric div.dt-column-header,
|
||||||
|
table.dataTable td.dt-type-numeric div.dt-column-footer,
|
||||||
|
table.dataTable td.dt-type-date div.dt-column-header,
|
||||||
|
table.dataTable td.dt-type-date div.dt-column-footer {
|
||||||
|
flex-direction: row-reverse;
|
||||||
|
}
|
||||||
table.dataTable th.dt-left,
|
table.dataTable th.dt-left,
|
||||||
table.dataTable td.dt-left {
|
table.dataTable td.dt-left {
|
||||||
text-align: left;
|
text-align: left;
|
||||||
}
|
}
|
||||||
|
table.dataTable th.dt-left div.dt-column-header,
|
||||||
|
table.dataTable th.dt-left div.dt-column-footer,
|
||||||
|
table.dataTable td.dt-left div.dt-column-header,
|
||||||
|
table.dataTable td.dt-left div.dt-column-footer {
|
||||||
|
flex-direction: row;
|
||||||
|
}
|
||||||
table.dataTable th.dt-center,
|
table.dataTable th.dt-center,
|
||||||
table.dataTable td.dt-center {
|
table.dataTable td.dt-center {
|
||||||
text-align: center;
|
text-align: center;
|
||||||
@ -270,10 +309,22 @@ table.dataTable th.dt-right,
|
|||||||
table.dataTable td.dt-right {
|
table.dataTable td.dt-right {
|
||||||
text-align: right;
|
text-align: right;
|
||||||
}
|
}
|
||||||
|
table.dataTable th.dt-right div.dt-column-header,
|
||||||
|
table.dataTable th.dt-right div.dt-column-footer,
|
||||||
|
table.dataTable td.dt-right div.dt-column-header,
|
||||||
|
table.dataTable td.dt-right div.dt-column-footer {
|
||||||
|
flex-direction: row-reverse;
|
||||||
|
}
|
||||||
table.dataTable th.dt-justify,
|
table.dataTable th.dt-justify,
|
||||||
table.dataTable td.dt-justify {
|
table.dataTable td.dt-justify {
|
||||||
text-align: justify;
|
text-align: justify;
|
||||||
}
|
}
|
||||||
|
table.dataTable th.dt-justify div.dt-column-header,
|
||||||
|
table.dataTable th.dt-justify div.dt-column-footer,
|
||||||
|
table.dataTable td.dt-justify div.dt-column-header,
|
||||||
|
table.dataTable td.dt-justify div.dt-column-footer {
|
||||||
|
flex-direction: row;
|
||||||
|
}
|
||||||
table.dataTable th.dt-nowrap,
|
table.dataTable th.dt-nowrap,
|
||||||
table.dataTable td.dt-nowrap {
|
table.dataTable td.dt-nowrap {
|
||||||
white-space: nowrap;
|
white-space: nowrap;
|
||||||
@ -295,6 +346,16 @@ table.dataTable tfoot th.dt-head-left,
|
|||||||
table.dataTable tfoot td.dt-head-left {
|
table.dataTable tfoot td.dt-head-left {
|
||||||
text-align: left;
|
text-align: left;
|
||||||
}
|
}
|
||||||
|
table.dataTable thead th.dt-head-left div.dt-column-header,
|
||||||
|
table.dataTable thead th.dt-head-left div.dt-column-footer,
|
||||||
|
table.dataTable thead td.dt-head-left div.dt-column-header,
|
||||||
|
table.dataTable thead td.dt-head-left div.dt-column-footer,
|
||||||
|
table.dataTable tfoot th.dt-head-left div.dt-column-header,
|
||||||
|
table.dataTable tfoot th.dt-head-left div.dt-column-footer,
|
||||||
|
table.dataTable tfoot td.dt-head-left div.dt-column-header,
|
||||||
|
table.dataTable tfoot td.dt-head-left div.dt-column-footer {
|
||||||
|
flex-direction: row;
|
||||||
|
}
|
||||||
table.dataTable thead th.dt-head-center,
|
table.dataTable thead th.dt-head-center,
|
||||||
table.dataTable thead td.dt-head-center,
|
table.dataTable thead td.dt-head-center,
|
||||||
table.dataTable tfoot th.dt-head-center,
|
table.dataTable tfoot th.dt-head-center,
|
||||||
@ -307,12 +368,32 @@ table.dataTable tfoot th.dt-head-right,
|
|||||||
table.dataTable tfoot td.dt-head-right {
|
table.dataTable tfoot td.dt-head-right {
|
||||||
text-align: right;
|
text-align: right;
|
||||||
}
|
}
|
||||||
|
table.dataTable thead th.dt-head-right div.dt-column-header,
|
||||||
|
table.dataTable thead th.dt-head-right div.dt-column-footer,
|
||||||
|
table.dataTable thead td.dt-head-right div.dt-column-header,
|
||||||
|
table.dataTable thead td.dt-head-right div.dt-column-footer,
|
||||||
|
table.dataTable tfoot th.dt-head-right div.dt-column-header,
|
||||||
|
table.dataTable tfoot th.dt-head-right div.dt-column-footer,
|
||||||
|
table.dataTable tfoot td.dt-head-right div.dt-column-header,
|
||||||
|
table.dataTable tfoot td.dt-head-right div.dt-column-footer {
|
||||||
|
flex-direction: row-reverse;
|
||||||
|
}
|
||||||
table.dataTable thead th.dt-head-justify,
|
table.dataTable thead th.dt-head-justify,
|
||||||
table.dataTable thead td.dt-head-justify,
|
table.dataTable thead td.dt-head-justify,
|
||||||
table.dataTable tfoot th.dt-head-justify,
|
table.dataTable tfoot th.dt-head-justify,
|
||||||
table.dataTable tfoot td.dt-head-justify {
|
table.dataTable tfoot td.dt-head-justify {
|
||||||
text-align: justify;
|
text-align: justify;
|
||||||
}
|
}
|
||||||
|
table.dataTable thead th.dt-head-justify div.dt-column-header,
|
||||||
|
table.dataTable thead th.dt-head-justify div.dt-column-footer,
|
||||||
|
table.dataTable thead td.dt-head-justify div.dt-column-header,
|
||||||
|
table.dataTable thead td.dt-head-justify div.dt-column-footer,
|
||||||
|
table.dataTable tfoot th.dt-head-justify div.dt-column-header,
|
||||||
|
table.dataTable tfoot th.dt-head-justify div.dt-column-footer,
|
||||||
|
table.dataTable tfoot td.dt-head-justify div.dt-column-header,
|
||||||
|
table.dataTable tfoot td.dt-head-justify div.dt-column-footer {
|
||||||
|
flex-direction: row;
|
||||||
|
}
|
||||||
table.dataTable thead th.dt-head-nowrap,
|
table.dataTable thead th.dt-head-nowrap,
|
||||||
table.dataTable thead td.dt-head-nowrap,
|
table.dataTable thead td.dt-head-nowrap,
|
||||||
table.dataTable tfoot th.dt-head-nowrap,
|
table.dataTable tfoot th.dt-head-nowrap,
|
||||||
@ -410,6 +491,9 @@ div.dt-container div.dt-layout-table > div {
|
|||||||
margin-left: 0;
|
margin-left: 0;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
div.dt-container {
|
||||||
|
position: relative;
|
||||||
|
}
|
||||||
div.dt-container div.dt-length label {
|
div.dt-container div.dt-length label {
|
||||||
font-weight: normal;
|
font-weight: normal;
|
||||||
text-align: left;
|
text-align: left;
|
||||||
@ -498,14 +582,19 @@ table.dataTable.table-sm > thead > tr td.dt-orderable-asc,
|
|||||||
table.dataTable.table-sm > thead > tr td.dt-orderable-desc,
|
table.dataTable.table-sm > thead > tr td.dt-orderable-desc,
|
||||||
table.dataTable.table-sm > thead > tr td.dt-ordering-asc,
|
table.dataTable.table-sm > thead > tr td.dt-ordering-asc,
|
||||||
table.dataTable.table-sm > thead > tr td.dt-ordering-desc {
|
table.dataTable.table-sm > thead > tr td.dt-ordering-desc {
|
||||||
padding-right: 20px;
|
padding-right: 0.25rem;
|
||||||
}
|
}
|
||||||
table.dataTable.table-sm > thead > tr th.dt-orderable-asc span.dt-column-order, table.dataTable.table-sm > thead > tr th.dt-orderable-desc span.dt-column-order, table.dataTable.table-sm > thead > tr th.dt-ordering-asc span.dt-column-order, table.dataTable.table-sm > thead > tr th.dt-ordering-desc span.dt-column-order,
|
table.dataTable.table-sm > thead > tr th.dt-orderable-asc span.dt-column-order, table.dataTable.table-sm > thead > tr th.dt-orderable-desc span.dt-column-order, table.dataTable.table-sm > thead > tr th.dt-ordering-asc span.dt-column-order, table.dataTable.table-sm > thead > tr th.dt-ordering-desc span.dt-column-order,
|
||||||
table.dataTable.table-sm > thead > tr td.dt-orderable-asc span.dt-column-order,
|
table.dataTable.table-sm > thead > tr td.dt-orderable-asc span.dt-column-order,
|
||||||
table.dataTable.table-sm > thead > tr td.dt-orderable-desc span.dt-column-order,
|
table.dataTable.table-sm > thead > tr td.dt-orderable-desc span.dt-column-order,
|
||||||
table.dataTable.table-sm > thead > tr td.dt-ordering-asc span.dt-column-order,
|
table.dataTable.table-sm > thead > tr td.dt-ordering-asc span.dt-column-order,
|
||||||
table.dataTable.table-sm > thead > tr td.dt-ordering-desc span.dt-column-order {
|
table.dataTable.table-sm > thead > tr td.dt-ordering-desc span.dt-column-order {
|
||||||
right: 5px;
|
right: 0.25rem;
|
||||||
|
}
|
||||||
|
table.dataTable.table-sm > thead > tr th.dt-type-date span.dt-column-order, table.dataTable.table-sm > thead > tr th.dt-type-numeric span.dt-column-order,
|
||||||
|
table.dataTable.table-sm > thead > tr td.dt-type-date span.dt-column-order,
|
||||||
|
table.dataTable.table-sm > thead > tr td.dt-type-numeric span.dt-column-order {
|
||||||
|
left: 0.25rem;
|
||||||
}
|
}
|
||||||
|
|
||||||
div.dt-scroll-head table.table-bordered {
|
div.dt-scroll-head table.table-bordered {
|
||||||
|
426
src/static/scripts/datatables.js
vendored
426
src/static/scripts/datatables.js
vendored
@ -4,13 +4,13 @@
|
|||||||
*
|
*
|
||||||
* To rebuild or modify this file with the latest versions of the included
|
* To rebuild or modify this file with the latest versions of the included
|
||||||
* software please visit:
|
* software please visit:
|
||||||
* https://datatables.net/download/#bs5/dt-2.2.2
|
* https://datatables.net/download/#bs5/dt-2.3.1
|
||||||
*
|
*
|
||||||
* Included libraries:
|
* Included libraries:
|
||||||
* DataTables 2.2.2
|
* DataTables 2.3.1
|
||||||
*/
|
*/
|
||||||
|
|
||||||
/*! DataTables 2.2.2
|
/*! DataTables 2.3.1
|
||||||
* © SpryMedia Ltd - datatables.net/license
|
* © SpryMedia Ltd - datatables.net/license
|
||||||
*/
|
*/
|
||||||
|
|
||||||
@ -101,15 +101,19 @@
|
|||||||
var defaults = DataTable.defaults;
|
var defaults = DataTable.defaults;
|
||||||
var $this = $(this);
|
var $this = $(this);
|
||||||
|
|
||||||
|
// Sanity check
|
||||||
/* Sanity check */
|
|
||||||
if ( this.nodeName.toLowerCase() != 'table' )
|
if ( this.nodeName.toLowerCase() != 'table' )
|
||||||
{
|
{
|
||||||
_fnLog( null, 0, 'Non-table node initialisation ('+this.nodeName+')', 2 );
|
_fnLog( null, 0, 'Non-table node initialisation ('+this.nodeName+')', 2 );
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
$(this).trigger( 'options.dt', oInit );
|
// Special case for options
|
||||||
|
if (oInit.on && oInit.on.options) {
|
||||||
|
_fnListener($this, 'options', oInit.on.options);
|
||||||
|
}
|
||||||
|
|
||||||
|
$this.trigger( 'options.dt', oInit );
|
||||||
|
|
||||||
/* Backwards compatibility for the defaults */
|
/* Backwards compatibility for the defaults */
|
||||||
_fnCompatOpts( defaults );
|
_fnCompatOpts( defaults );
|
||||||
@ -248,6 +252,9 @@
|
|||||||
"caption",
|
"caption",
|
||||||
"layout",
|
"layout",
|
||||||
"orderDescReverse",
|
"orderDescReverse",
|
||||||
|
"orderIndicators",
|
||||||
|
"orderHandler",
|
||||||
|
"titleRow",
|
||||||
"typeDetect",
|
"typeDetect",
|
||||||
[ "iCookieDuration", "iStateDuration" ], // backwards compat
|
[ "iCookieDuration", "iStateDuration" ], // backwards compat
|
||||||
[ "oSearch", "oPreviousSearch" ],
|
[ "oSearch", "oPreviousSearch" ],
|
||||||
@ -276,6 +283,13 @@
|
|||||||
|
|
||||||
oSettings.rowIdFn = _fnGetObjectDataFn( oInit.rowId );
|
oSettings.rowIdFn = _fnGetObjectDataFn( oInit.rowId );
|
||||||
|
|
||||||
|
// Add event listeners
|
||||||
|
if (oInit.on) {
|
||||||
|
Object.keys(oInit.on).forEach(function (key) {
|
||||||
|
_fnListener($this, key, oInit.on[key]);
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
/* Browser support detection */
|
/* Browser support detection */
|
||||||
_fnBrowserDetect( oSettings );
|
_fnBrowserDetect( oSettings );
|
||||||
|
|
||||||
@ -336,7 +350,7 @@
|
|||||||
/* HTML5 attribute detection - build an mData object automatically if the
|
/* HTML5 attribute detection - build an mData object automatically if the
|
||||||
* attributes are found
|
* attributes are found
|
||||||
*/
|
*/
|
||||||
var rowOne = $this.children('tbody').find('tr').eq(0);
|
var rowOne = $this.children('tbody').find('tr:first-child').eq(0);
|
||||||
|
|
||||||
if ( rowOne.length ) {
|
if ( rowOne.length ) {
|
||||||
var a = function ( cell, name ) {
|
var a = function ( cell, name ) {
|
||||||
@ -494,6 +508,13 @@
|
|||||||
* @namespace
|
* @namespace
|
||||||
*/
|
*/
|
||||||
DataTable.ext = _ext = {
|
DataTable.ext = _ext = {
|
||||||
|
/**
|
||||||
|
* DataTables build type (expanded by the download builder)
|
||||||
|
*
|
||||||
|
* @type string
|
||||||
|
*/
|
||||||
|
builder: "bs5/dt-2.3.1",
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Buttons. For use with the Buttons extension for DataTables. This is
|
* Buttons. For use with the Buttons extension for DataTables. This is
|
||||||
* defined here so other extensions can define buttons regardless of load
|
* defined here so other extensions can define buttons regardless of load
|
||||||
@ -505,6 +526,14 @@
|
|||||||
buttons: {},
|
buttons: {},
|
||||||
|
|
||||||
|
|
||||||
|
/**
|
||||||
|
* ColumnControl buttons and content
|
||||||
|
*
|
||||||
|
* @type object
|
||||||
|
*/
|
||||||
|
ccContent: {},
|
||||||
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Element class names
|
* Element class names
|
||||||
*
|
*
|
||||||
@ -514,14 +543,6 @@
|
|||||||
classes: {},
|
classes: {},
|
||||||
|
|
||||||
|
|
||||||
/**
|
|
||||||
* DataTables build type (expanded by the download builder)
|
|
||||||
*
|
|
||||||
* @type string
|
|
||||||
*/
|
|
||||||
builder: "bs5/dt-2.2.2",
|
|
||||||
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Error reporting.
|
* Error reporting.
|
||||||
*
|
*
|
||||||
@ -1887,6 +1908,26 @@
|
|||||||
init.scrollX = init.scrollX ? '100%' : '';
|
init.scrollX = init.scrollX ? '100%' : '';
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Objects for ordering
|
||||||
|
if ( typeof init.bSort === 'object' ) {
|
||||||
|
init.orderIndicators = init.bSort.indicators !== undefined ? init.bSort.indicators : true;
|
||||||
|
init.orderHandler = init.bSort.handler !== undefined ? init.bSort.handler : true;
|
||||||
|
init.bSort = true;
|
||||||
|
}
|
||||||
|
else if (init.bSort === false) {
|
||||||
|
init.orderIndicators = false;
|
||||||
|
init.orderHandler = false;
|
||||||
|
}
|
||||||
|
else if (init.bSort === true) {
|
||||||
|
init.orderIndicators = true;
|
||||||
|
init.orderHandler = true;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Which cells are the title cells?
|
||||||
|
if (typeof init.bSortCellsTop === 'boolean') {
|
||||||
|
init.titleRow = init.bSortCellsTop;
|
||||||
|
}
|
||||||
|
|
||||||
// Column search objects are in an array, so it needs to be converted
|
// Column search objects are in an array, so it needs to be converted
|
||||||
// element by element
|
// element by element
|
||||||
var searchCols = init.aoSearchCols;
|
var searchCols = init.aoSearchCols;
|
||||||
@ -3264,7 +3305,7 @@
|
|||||||
* @param {*} settings DataTables settings
|
* @param {*} settings DataTables settings
|
||||||
* @param {*} source Source layout array
|
* @param {*} source Source layout array
|
||||||
* @param {*} incColumns What columns should be included
|
* @param {*} incColumns What columns should be included
|
||||||
* @returns Layout array
|
* @returns Layout array in column index order
|
||||||
*/
|
*/
|
||||||
function _fnHeaderLayout( settings, source, incColumns )
|
function _fnHeaderLayout( settings, source, incColumns )
|
||||||
{
|
{
|
||||||
@ -3548,7 +3589,9 @@
|
|||||||
|
|
||||||
_fnDraw( settings );
|
_fnDraw( settings );
|
||||||
|
|
||||||
settings._drawHold = false;
|
settings.api.one('draw', function () {
|
||||||
|
settings._drawHold = false;
|
||||||
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
@ -3560,10 +3603,9 @@
|
|||||||
var zero = oLang.sZeroRecords;
|
var zero = oLang.sZeroRecords;
|
||||||
var dataSrc = _fnDataSource( settings );
|
var dataSrc = _fnDataSource( settings );
|
||||||
|
|
||||||
if (
|
// Make use of the fact that settings.json is only set once the initial data has
|
||||||
(settings.iDraw < 1 && dataSrc === 'ssp') ||
|
// been loaded. Show loading when that isn't the case
|
||||||
(settings.iDraw <= 1 && dataSrc === 'ajax')
|
if ((dataSrc === 'ssp' || dataSrc === 'ajax') && ! settings.json) {
|
||||||
) {
|
|
||||||
zero = oLang.sLoadingRecords;
|
zero = oLang.sLoadingRecords;
|
||||||
}
|
}
|
||||||
else if ( oLang.sEmptyTable && settings.fnRecordsTotal() === 0 )
|
else if ( oLang.sEmptyTable && settings.fnRecordsTotal() === 0 )
|
||||||
@ -3933,6 +3975,7 @@
|
|||||||
var rows = $(thead).children('tr');
|
var rows = $(thead).children('tr');
|
||||||
var row, cell;
|
var row, cell;
|
||||||
var i, k, l, iLen, shifted, column, colspan, rowspan;
|
var i, k, l, iLen, shifted, column, colspan, rowspan;
|
||||||
|
var titleRow = settings.titleRow;
|
||||||
var isHeader = thead && thead.nodeName.toLowerCase() === 'thead';
|
var isHeader = thead && thead.nodeName.toLowerCase() === 'thead';
|
||||||
var layout = [];
|
var layout = [];
|
||||||
var unique;
|
var unique;
|
||||||
@ -3961,6 +4004,7 @@
|
|||||||
cell.nodeName.toUpperCase() == 'TH'
|
cell.nodeName.toUpperCase() == 'TH'
|
||||||
) {
|
) {
|
||||||
var cols = [];
|
var cols = [];
|
||||||
|
var jqCell = $(cell);
|
||||||
|
|
||||||
// Get the col and rowspan attributes from the DOM and sanitise them
|
// Get the col and rowspan attributes from the DOM and sanitise them
|
||||||
colspan = cell.getAttribute('colspan') * 1;
|
colspan = cell.getAttribute('colspan') * 1;
|
||||||
@ -3981,7 +4025,7 @@
|
|||||||
if ( write ) {
|
if ( write ) {
|
||||||
if (unique) {
|
if (unique) {
|
||||||
// Allow column options to be set from HTML attributes
|
// Allow column options to be set from HTML attributes
|
||||||
_fnColumnOptions( settings, shifted, $(cell).data() );
|
_fnColumnOptions( settings, shifted, jqCell.data() );
|
||||||
|
|
||||||
// Get the width for the column. This can be defined from the
|
// Get the width for the column. This can be defined from the
|
||||||
// width attribute, style attribute or `columns.width` option
|
// width attribute, style attribute or `columns.width` option
|
||||||
@ -3998,7 +4042,14 @@
|
|||||||
// Column title handling - can be user set, or read from the DOM
|
// Column title handling - can be user set, or read from the DOM
|
||||||
// This happens before the render, so the original is still in place
|
// This happens before the render, so the original is still in place
|
||||||
if ( columnDef.sTitle !== null && ! columnDef.autoTitle ) {
|
if ( columnDef.sTitle !== null && ! columnDef.autoTitle ) {
|
||||||
cell.innerHTML = columnDef.sTitle;
|
if (
|
||||||
|
(titleRow === true && i === 0) || // top row
|
||||||
|
(titleRow === false && i === rows.length -1) || // bottom row
|
||||||
|
(titleRow === i) || // specific row
|
||||||
|
(titleRow === null)
|
||||||
|
) {
|
||||||
|
cell.innerHTML = columnDef.sTitle;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
if (! columnDef.sTitle && unique) {
|
if (! columnDef.sTitle && unique) {
|
||||||
@ -4016,12 +4067,12 @@
|
|||||||
// Fall back to the aria-label attribute on the table header if no ariaTitle is
|
// Fall back to the aria-label attribute on the table header if no ariaTitle is
|
||||||
// provided.
|
// provided.
|
||||||
if (! columnDef.ariaTitle) {
|
if (! columnDef.ariaTitle) {
|
||||||
columnDef.ariaTitle = $(cell).attr("aria-label") || columnDef.sTitle;
|
columnDef.ariaTitle = jqCell.attr("aria-label") || columnDef.sTitle;
|
||||||
}
|
}
|
||||||
|
|
||||||
// Column specific class names
|
// Column specific class names
|
||||||
if ( columnDef.className ) {
|
if ( columnDef.className ) {
|
||||||
$(cell).addClass( columnDef.className );
|
jqCell.addClass( columnDef.className );
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -4033,11 +4084,28 @@
|
|||||||
.appendTo(cell);
|
.appendTo(cell);
|
||||||
}
|
}
|
||||||
|
|
||||||
if ( isHeader && $('span.dt-column-order', cell).length === 0) {
|
if (
|
||||||
|
settings.orderIndicators &&
|
||||||
|
isHeader &&
|
||||||
|
jqCell.filter(':not([data-dt-order=disable])').length !== 0 &&
|
||||||
|
jqCell.parent(':not([data-dt-order=disable])').length !== 0 &&
|
||||||
|
$('span.dt-column-order', cell).length === 0
|
||||||
|
) {
|
||||||
$('<span>')
|
$('<span>')
|
||||||
.addClass('dt-column-order')
|
.addClass('dt-column-order')
|
||||||
.appendTo(cell);
|
.appendTo(cell);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// We need to wrap the elements in the header in another element to use flexbox
|
||||||
|
// layout for those elements
|
||||||
|
var headerFooter = isHeader ? 'header' : 'footer';
|
||||||
|
|
||||||
|
if ( $('span.dt-column-' + headerFooter, cell).length === 0) {
|
||||||
|
$('<div>')
|
||||||
|
.addClass('dt-column-' + headerFooter)
|
||||||
|
.append(cell.childNodes)
|
||||||
|
.appendTo(cell);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// If there is col / rowspan, copy the information into the layout grid
|
// If there is col / rowspan, copy the information into the layout grid
|
||||||
@ -4188,6 +4256,11 @@
|
|||||||
// Allow plug-ins and external processes to modify the data
|
// Allow plug-ins and external processes to modify the data
|
||||||
_fnCallbackFire( oSettings, null, 'preXhr', [oSettings, data, baseAjax], true );
|
_fnCallbackFire( oSettings, null, 'preXhr', [oSettings, data, baseAjax], true );
|
||||||
|
|
||||||
|
// Custom Ajax option to submit the parameters as a JSON string
|
||||||
|
if (baseAjax.submitAs === 'json' && typeof data === 'object') {
|
||||||
|
baseAjax.data = JSON.stringify(data);
|
||||||
|
}
|
||||||
|
|
||||||
if ( typeof ajax === 'function' )
|
if ( typeof ajax === 'function' )
|
||||||
{
|
{
|
||||||
// Is a function - let the caller define what needs to be done
|
// Is a function - let the caller define what needs to be done
|
||||||
@ -5688,24 +5761,30 @@
|
|||||||
function _fnSortInit( settings ) {
|
function _fnSortInit( settings ) {
|
||||||
var target = settings.nTHead;
|
var target = settings.nTHead;
|
||||||
var headerRows = target.querySelectorAll('tr');
|
var headerRows = target.querySelectorAll('tr');
|
||||||
var legacyTop = settings.bSortCellsTop;
|
var titleRow = settings.titleRow;
|
||||||
var notSelector = ':not([data-dt-order="disable"]):not([data-dt-order="icon-only"])';
|
var notSelector = ':not([data-dt-order="disable"]):not([data-dt-order="icon-only"])';
|
||||||
|
|
||||||
// Legacy support for `orderCellsTop`
|
// Legacy support for `orderCellsTop`
|
||||||
if (legacyTop === true) {
|
if (titleRow === true) {
|
||||||
target = headerRows[0];
|
target = headerRows[0];
|
||||||
}
|
}
|
||||||
else if (legacyTop === false) {
|
else if (titleRow === false) {
|
||||||
target = headerRows[ headerRows.length - 1 ];
|
target = headerRows[ headerRows.length - 1 ];
|
||||||
}
|
}
|
||||||
|
else if (titleRow !== null) {
|
||||||
|
target = headerRows[titleRow];
|
||||||
|
}
|
||||||
|
// else - all rows
|
||||||
|
|
||||||
_fnSortAttachListener(
|
if (settings.orderHandler) {
|
||||||
settings,
|
_fnSortAttachListener(
|
||||||
target,
|
settings,
|
||||||
target === settings.nTHead
|
target,
|
||||||
? 'tr'+notSelector+' th'+notSelector+', tr'+notSelector+' td'+notSelector
|
target === settings.nTHead
|
||||||
: 'th'+notSelector+', td'+notSelector
|
? 'tr'+notSelector+' th'+notSelector+', tr'+notSelector+' td'+notSelector
|
||||||
);
|
: 'th'+notSelector+', td'+notSelector
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
// Need to resolve the user input array into our internal structure
|
// Need to resolve the user input array into our internal structure
|
||||||
var order = [];
|
var order = [];
|
||||||
@ -5720,7 +5799,9 @@
|
|||||||
var run = false;
|
var run = false;
|
||||||
var columns = column === undefined
|
var columns = column === undefined
|
||||||
? _fnColumnsFromHeader( e.target )
|
? _fnColumnsFromHeader( e.target )
|
||||||
: [column];
|
: Array.isArray(column)
|
||||||
|
? column
|
||||||
|
: [column];
|
||||||
|
|
||||||
if ( columns.length ) {
|
if ( columns.length ) {
|
||||||
for ( var i=0, ien=columns.length ; i<ien ; i++ ) {
|
for ( var i=0, ien=columns.length ; i<ien ; i++ ) {
|
||||||
@ -6343,16 +6424,19 @@
|
|||||||
|
|
||||||
// A column name was stored and should be used for restore
|
// A column name was stored and should be used for restore
|
||||||
if (typeof col[0] === 'string') {
|
if (typeof col[0] === 'string') {
|
||||||
|
// Find the name from the current list of column names
|
||||||
var idx = currentNames.indexOf(col[0]);
|
var idx = currentNames.indexOf(col[0]);
|
||||||
|
|
||||||
// Find the name from the current list of column names, or fallback to index 0
|
if (idx < 0) {
|
||||||
set[0] = idx >= 0
|
// If the column was not found ignore it and continue
|
||||||
? idx
|
return;
|
||||||
: 0;
|
}
|
||||||
|
|
||||||
|
set[0] = idx;
|
||||||
}
|
}
|
||||||
else if (set[0] >= columns.length) {
|
else if (set[0] >= columns.length) {
|
||||||
// If a column name, but it is out of bounds, set to 0
|
// If the column index is out of bounds ignore it and continue
|
||||||
set[0] = 0;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
settings.aaSorting.push(set);
|
settings.aaSorting.push(set);
|
||||||
@ -6765,6 +6849,23 @@
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Add one or more listeners to the table
|
||||||
|
*
|
||||||
|
* @param {*} that JQ for the table
|
||||||
|
* @param {*} name Event name
|
||||||
|
* @param {*} src Listener(s)
|
||||||
|
*/
|
||||||
|
function _fnListener(that, name, src) {
|
||||||
|
if (!Array.isArray(src)) {
|
||||||
|
src = [src];
|
||||||
|
}
|
||||||
|
|
||||||
|
for (i=0 ; i<src.length ; i++) {
|
||||||
|
that.on(name + '.dt', src[i]);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@ -7421,12 +7522,24 @@
|
|||||||
['footer', 'aoFooter'],
|
['footer', 'aoFooter'],
|
||||||
].forEach(function (item) {
|
].forEach(function (item) {
|
||||||
_api_register( 'table().' + item[0] + '.structure()' , function (selector) {
|
_api_register( 'table().' + item[0] + '.structure()' , function (selector) {
|
||||||
var indexes = this.columns(selector).indexes().flatten();
|
var indexes = this.columns(selector).indexes().flatten().toArray();
|
||||||
var ctx = this.context[0];
|
var ctx = this.context[0];
|
||||||
|
var structure = _fnHeaderLayout(ctx, ctx[item[1]], indexes);
|
||||||
return _fnHeaderLayout(ctx, ctx[item[1]], indexes);
|
|
||||||
} );
|
// The structure is in column index order - but from this method we want the return to be
|
||||||
})
|
// in the columns() selector API order. In order to do that we need to map from one form
|
||||||
|
// to the other
|
||||||
|
var orderedIndexes = indexes.slice().sort(function (a, b) {
|
||||||
|
return a - b;
|
||||||
|
});
|
||||||
|
|
||||||
|
return structure.map(function (row) {
|
||||||
|
return indexes.map(function (colIdx) {
|
||||||
|
return row[orderedIndexes.indexOf(colIdx)];
|
||||||
|
});
|
||||||
|
});
|
||||||
|
});
|
||||||
|
});
|
||||||
|
|
||||||
|
|
||||||
_api_registerPlural( 'tables().containers()', 'table().container()' , function () {
|
_api_registerPlural( 'tables().containers()', 'table().container()' , function () {
|
||||||
@ -7775,7 +7888,7 @@
|
|||||||
{
|
{
|
||||||
var
|
var
|
||||||
out = [], res,
|
out = [], res,
|
||||||
a, i, ien, j, jen,
|
i, ien,
|
||||||
selectorType = typeof selector;
|
selectorType = typeof selector;
|
||||||
|
|
||||||
// Can't just check for isArray here, as an API or jQuery instance might be
|
// Can't just check for isArray here, as an API or jQuery instance might be
|
||||||
@ -7785,22 +7898,15 @@
|
|||||||
}
|
}
|
||||||
|
|
||||||
for ( i=0, ien=selector.length ; i<ien ; i++ ) {
|
for ( i=0, ien=selector.length ; i<ien ; i++ ) {
|
||||||
// Only split on simple strings - complex expressions will be jQuery selectors
|
res = selectFn( typeof selector[i] === 'string' ? selector[i].trim() : selector[i] );
|
||||||
a = selector[i] && selector[i].split && ! selector[i].match(/[[(:]/) ?
|
|
||||||
selector[i].split(',') :
|
|
||||||
[ selector[i] ];
|
|
||||||
|
|
||||||
for ( j=0, jen=a.length ; j<jen ; j++ ) {
|
// Remove empty items
|
||||||
res = selectFn( typeof a[j] === 'string' ? (a[j]).trim() : a[j] );
|
res = res.filter( function (item) {
|
||||||
|
return item !== null && item !== undefined;
|
||||||
|
});
|
||||||
|
|
||||||
// Remove empty items
|
if ( res && res.length ) {
|
||||||
res = res.filter( function (item) {
|
out = out.concat( res );
|
||||||
return item !== null && item !== undefined;
|
|
||||||
});
|
|
||||||
|
|
||||||
if ( res && res.length ) {
|
|
||||||
out = out.concat( res );
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -7829,6 +7935,7 @@
|
|||||||
}
|
}
|
||||||
|
|
||||||
return $.extend( {
|
return $.extend( {
|
||||||
|
columnOrder: 'implied',
|
||||||
search: 'none',
|
search: 'none',
|
||||||
order: 'current',
|
order: 'current',
|
||||||
page: 'all'
|
page: 'all'
|
||||||
@ -8590,23 +8697,60 @@
|
|||||||
|
|
||||||
var __column_header = function ( settings, column, row ) {
|
var __column_header = function ( settings, column, row ) {
|
||||||
var header = settings.aoHeader;
|
var header = settings.aoHeader;
|
||||||
var target = row !== undefined
|
var titleRow = settings.titleRow;
|
||||||
? row
|
var target = null;
|
||||||
: settings.bSortCellsTop // legacy support
|
|
||||||
? 0
|
if (row !== undefined) {
|
||||||
: header.length - 1;
|
target = row;
|
||||||
|
}
|
||||||
|
else if (titleRow === true) { // legacy orderCellsTop support
|
||||||
|
target = 0;
|
||||||
|
}
|
||||||
|
else if (titleRow === false) {
|
||||||
|
target = header.length - 1;
|
||||||
|
}
|
||||||
|
else if (titleRow !== null) {
|
||||||
|
target = titleRow;
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
// Automatic - find the _last_ unique cell from the top that is not empty (last for
|
||||||
|
// backwards compatibility)
|
||||||
|
for (var i=0 ; i<header.length ; i++) {
|
||||||
|
if (header[i][column].unique && $('span.dt-column-title', header[i][column].cell).text()) {
|
||||||
|
target = i;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (target === null) {
|
||||||
|
target = 0;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
return header[target][column].cell;
|
return header[target][column].cell;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
var __column_header_cells = function (header) {
|
||||||
|
var out = [];
|
||||||
|
|
||||||
|
for (var i=0 ; i<header.length ; i++) {
|
||||||
|
for (var j=0 ; j<header[i].length ; j++) {
|
||||||
|
var cell = header[i][j].cell;
|
||||||
|
|
||||||
|
if (!out.includes(cell)) {
|
||||||
|
out.push(cell);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return out;
|
||||||
|
}
|
||||||
|
|
||||||
var __column_selector = function ( settings, selector, opts )
|
var __column_selector = function ( settings, selector, opts )
|
||||||
{
|
{
|
||||||
var
|
var
|
||||||
columns = settings.aoColumns,
|
columns = settings.aoColumns,
|
||||||
names = _pluck( columns, 'sName' ),
|
names, titles,
|
||||||
titles = _pluck( columns, 'sTitle' ),
|
nodes = __column_header_cells(settings.aoHeader);
|
||||||
cells = DataTable.util.get('[].[].cell')(settings.aoHeader),
|
|
||||||
nodes = _unique( _flatten([], cells) );
|
|
||||||
|
|
||||||
var run = function ( s ) {
|
var run = function ( s ) {
|
||||||
var selInt = _intVal( s );
|
var selInt = _intVal( s );
|
||||||
@ -8678,12 +8822,21 @@
|
|||||||
} );
|
} );
|
||||||
|
|
||||||
case 'name':
|
case 'name':
|
||||||
|
// Don't get names, unless needed, and only get once if it is
|
||||||
|
if (!names) {
|
||||||
|
names = _pluck( columns, 'sName' );
|
||||||
|
}
|
||||||
|
|
||||||
// match by name. `names` is column index complete and in order
|
// match by name. `names` is column index complete and in order
|
||||||
return names.map( function (name, i) {
|
return names.map( function (name, i) {
|
||||||
return name === match[1] ? i : null;
|
return name === match[1] ? i : null;
|
||||||
} );
|
} );
|
||||||
|
|
||||||
case 'title':
|
case 'title':
|
||||||
|
if (!titles) {
|
||||||
|
titles = _pluck( columns, 'sTitle' );
|
||||||
|
}
|
||||||
|
|
||||||
// match by column title
|
// match by column title
|
||||||
return titles.map( function (title, i) {
|
return titles.map( function (title, i) {
|
||||||
return title === match[1] ? i : null;
|
return title === match[1] ? i : null;
|
||||||
@ -8722,7 +8875,11 @@
|
|||||||
[];
|
[];
|
||||||
};
|
};
|
||||||
|
|
||||||
return _selector_run( 'column', selector, run, settings, opts );
|
var selected = _selector_run( 'column', selector, run, settings, opts );
|
||||||
|
|
||||||
|
return opts.columnOrder && opts.columnOrder === 'index'
|
||||||
|
? selected.sort(function (a, b) { return a - b; })
|
||||||
|
: selected; // implied
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
||||||
@ -8846,6 +9003,12 @@
|
|||||||
}, 1 );
|
}, 1 );
|
||||||
} );
|
} );
|
||||||
|
|
||||||
|
_api_registerPlural( 'columns().names()', 'column().name()', function () {
|
||||||
|
return this.iterator( 'column', function ( settings, column ) {
|
||||||
|
return settings.aoColumns[column].sName;
|
||||||
|
}, 1 );
|
||||||
|
} );
|
||||||
|
|
||||||
_api_registerPlural( 'columns().nodes()', 'column().nodes()', function () {
|
_api_registerPlural( 'columns().nodes()', 'column().nodes()', function () {
|
||||||
return this.iterator( 'column-rows', function ( settings, column, i, j, rows ) {
|
return this.iterator( 'column-rows', function ( settings, column, i, j, rows ) {
|
||||||
return _pluck_order( settings.aoData, rows, 'anCells', column ) ;
|
return _pluck_order( settings.aoData, rows, 'anCells', column ) ;
|
||||||
@ -9272,7 +9435,10 @@
|
|||||||
// otherwise a 2D array was passed in
|
// otherwise a 2D array was passed in
|
||||||
|
|
||||||
return this.iterator( 'table', function ( settings ) {
|
return this.iterator( 'table', function ( settings ) {
|
||||||
settings.aaSorting = Array.isArray(order) ? order.slice() : order;
|
var resolved = [];
|
||||||
|
_fnSortResolve(settings, resolved, order);
|
||||||
|
|
||||||
|
settings.aaSorting = resolved;
|
||||||
} );
|
} );
|
||||||
} );
|
} );
|
||||||
|
|
||||||
@ -9398,7 +9564,7 @@
|
|||||||
var fixed = settings.searchFixed;
|
var fixed = settings.searchFixed;
|
||||||
|
|
||||||
if (! name) {
|
if (! name) {
|
||||||
return Object.keys(fixed)
|
return Object.keys(fixed);
|
||||||
}
|
}
|
||||||
else if (search === undefined) {
|
else if (search === undefined) {
|
||||||
return fixed[name];
|
return fixed[name];
|
||||||
@ -9465,10 +9631,10 @@
|
|||||||
var fixed = settings.aoColumns[colIdx].searchFixed;
|
var fixed = settings.aoColumns[colIdx].searchFixed;
|
||||||
|
|
||||||
if (! name) {
|
if (! name) {
|
||||||
return Object.keys(fixed)
|
return Object.keys(fixed);
|
||||||
}
|
}
|
||||||
else if (search === undefined) {
|
else if (search === undefined) {
|
||||||
return fixed[name];
|
return fixed[name] || null;
|
||||||
}
|
}
|
||||||
else if (search === null) {
|
else if (search === null) {
|
||||||
delete fixed[name];
|
delete fixed[name];
|
||||||
@ -9920,14 +10086,9 @@
|
|||||||
jqTable.append( tfoot );
|
jqTable.append( tfoot );
|
||||||
}
|
}
|
||||||
|
|
||||||
// Clean up the header
|
// Clean up the header / footer
|
||||||
$(thead).find('span.dt-column-order').remove();
|
cleanHeader(thead, 'header');
|
||||||
$(thead).find('span.dt-column-title').each(function () {
|
cleanHeader(tfoot, 'footer');
|
||||||
var title = $(this).html();
|
|
||||||
$(this).parent().append(title);
|
|
||||||
$(this).remove();
|
|
||||||
});
|
|
||||||
|
|
||||||
settings.colgroup.remove();
|
settings.colgroup.remove();
|
||||||
|
|
||||||
settings.aaSorting = [];
|
settings.aaSorting = [];
|
||||||
@ -9949,7 +10110,6 @@
|
|||||||
orderClasses.isDesc
|
orderClasses.isDesc
|
||||||
)
|
)
|
||||||
.css('width', '')
|
.css('width', '')
|
||||||
.removeAttr('data-dt-column')
|
|
||||||
.removeAttr('aria-sort');
|
.removeAttr('aria-sort');
|
||||||
|
|
||||||
// Add the TR elements back into the table in their original order
|
// Add the TR elements back into the table in their original order
|
||||||
@ -10030,6 +10190,19 @@
|
|||||||
: resolved;
|
: resolved;
|
||||||
} );
|
} );
|
||||||
|
|
||||||
|
// Needed for header and footer, so pulled into its own function
|
||||||
|
function cleanHeader(node, className) {
|
||||||
|
$(node).find('span.dt-column-order').remove();
|
||||||
|
$(node).find('span.dt-column-title').each(function () {
|
||||||
|
var title = $(this).html();
|
||||||
|
$(this).parent().parent().append(title);
|
||||||
|
$(this).remove();
|
||||||
|
});
|
||||||
|
$(node).find('div.dt-column-' + className).remove();
|
||||||
|
|
||||||
|
$('th, td', node).removeAttr('data-dt-column');
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Version string for plug-ins to check compatibility. Allowed format is
|
* 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
|
* `a.b.c-d` where: a:int, b:int, c:int, d:string(dev|beta|alpha). `d` is used
|
||||||
@ -10038,7 +10211,7 @@
|
|||||||
* @type string
|
* @type string
|
||||||
* @default Version number
|
* @default Version number
|
||||||
*/
|
*/
|
||||||
DataTable.version = "2.2.2";
|
DataTable.version = "2.3.1";
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Private data store, containing all of the settings objects that are
|
* Private data store, containing all of the settings objects that are
|
||||||
@ -10645,6 +10818,10 @@
|
|||||||
"bSortCellsTop": null,
|
"bSortCellsTop": null,
|
||||||
|
|
||||||
|
|
||||||
|
/** Specify which row is the title row in the header. Replacement for bSortCellsTop */
|
||||||
|
titleRow: null,
|
||||||
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Enable or disable the addition of the classes `sorting\_1`, `sorting\_2` and
|
* Enable or disable the addition of the classes `sorting\_1`, `sorting\_2` and
|
||||||
* `sorting\_3` to the columns which are currently being sorted on. This is
|
* `sorting\_3` to the columns which are currently being sorted on. This is
|
||||||
@ -10922,6 +11099,13 @@
|
|||||||
1: "entry"
|
1: "entry"
|
||||||
},
|
},
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Page length options
|
||||||
|
*/
|
||||||
|
lengthLabels: {
|
||||||
|
'-1': 'All'
|
||||||
|
},
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* This string is shown in preference to `zeroRecords` when the table is
|
* This string is shown in preference to `zeroRecords` when the table is
|
||||||
* empty of data (regardless of filtering). Note that this is an optional
|
* empty of data (regardless of filtering). Note that this is an optional
|
||||||
@ -11192,7 +11376,10 @@
|
|||||||
/**
|
/**
|
||||||
* For server-side processing - use the data from the DOM for the first draw
|
* For server-side processing - use the data from the DOM for the first draw
|
||||||
*/
|
*/
|
||||||
iDeferLoading: null
|
iDeferLoading: null,
|
||||||
|
|
||||||
|
/** Event listeners */
|
||||||
|
on: null
|
||||||
};
|
};
|
||||||
|
|
||||||
_fnHungarianMap( DataTable.defaults );
|
_fnHungarianMap( DataTable.defaults );
|
||||||
@ -12019,10 +12206,7 @@
|
|||||||
|
|
||||||
/**
|
/**
|
||||||
* Indicate that if multiple rows are in the header and there is more than
|
* Indicate that if multiple rows are in the header and there is more than
|
||||||
* one unique cell per column, if the top one (true) or bottom one (false)
|
* one unique cell per column. Replaced by titleRow
|
||||||
* 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}.
|
|
||||||
*/
|
*/
|
||||||
"bSortCellsTop": null,
|
"bSortCellsTop": null,
|
||||||
|
|
||||||
@ -12147,7 +12331,19 @@
|
|||||||
resizeObserver: null,
|
resizeObserver: null,
|
||||||
|
|
||||||
/** Keep a record of the last size of the container, so we can skip duplicates */
|
/** Keep a record of the last size of the container, so we can skip duplicates */
|
||||||
containerWidth: -1
|
containerWidth: -1,
|
||||||
|
|
||||||
|
/** Reverse the initial order of the data set on desc ordering */
|
||||||
|
orderDescReverse: null,
|
||||||
|
|
||||||
|
/** Show / hide ordering indicators in headers */
|
||||||
|
orderIndicators: true,
|
||||||
|
|
||||||
|
/** Default ordering listener */
|
||||||
|
orderHandler: true,
|
||||||
|
|
||||||
|
/** Title row indicator */
|
||||||
|
titleRow: null
|
||||||
};
|
};
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@ -12977,7 +13173,7 @@
|
|||||||
cell.addClass(classes.order.none);
|
cell.addClass(classes.order.none);
|
||||||
}
|
}
|
||||||
|
|
||||||
var legacyTop = settings.bSortCellsTop;
|
var titleRow = settings.titleRow;
|
||||||
var headerRows = cell.closest('thead').find('tr');
|
var headerRows = cell.closest('thead').find('tr');
|
||||||
var rowIdx = cell.parent().index();
|
var rowIdx = cell.parent().index();
|
||||||
|
|
||||||
@ -12987,11 +13183,10 @@
|
|||||||
cell.attr('data-dt-order') === 'disable' ||
|
cell.attr('data-dt-order') === 'disable' ||
|
||||||
cell.parent().attr('data-dt-order') === 'disable' ||
|
cell.parent().attr('data-dt-order') === 'disable' ||
|
||||||
|
|
||||||
// Legacy support for `orderCellsTop`. If it is set, then cells
|
// titleRow support, for defining a specific row in the header
|
||||||
// which are not in the top or bottom row of the header (depending
|
(titleRow === true && rowIdx !== 0) ||
|
||||||
// on the value) do not get the sorting classes applied to them
|
(titleRow === false && rowIdx !== headerRows.length - 1) ||
|
||||||
(legacyTop === true && rowIdx !== 0) ||
|
(typeof titleRow === 'number' && rowIdx !== titleRow)
|
||||||
(legacyTop === false && rowIdx !== headerRows.length - 1)
|
|
||||||
) {
|
) {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
@ -13001,7 +13196,7 @@
|
|||||||
// `DT` namespace will allow the event to be removed automatically
|
// `DT` namespace will allow the event to be removed automatically
|
||||||
// on destroy, while the `dt` namespaced event is the one we are
|
// on destroy, while the `dt` namespaced event is the one we are
|
||||||
// listening for
|
// listening for
|
||||||
$(settings.nTable).on( 'order.dt.DT column-visibility.dt.DT', function ( e, ctx ) {
|
$(settings.nTable).on( 'order.dt.DT column-visibility.dt.DT', function ( e, ctx, column ) {
|
||||||
if ( settings !== ctx ) { // need to check this this is the host
|
if ( settings !== ctx ) { // need to check this this is the host
|
||||||
return; // table, not a nested one
|
return; // table, not a nested one
|
||||||
}
|
}
|
||||||
@ -13012,6 +13207,16 @@
|
|||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
var orderedColumns = _pluck(sorting, 'col');
|
||||||
|
|
||||||
|
// This handler is only needed on column visibility if the column is part of the
|
||||||
|
// ordering. If it isn't, then we can bail out to save performance. It could be a
|
||||||
|
// separate event handler, but this is a balance between code reuse / size and performance
|
||||||
|
// console.log(e, e.name, column, orderedColumns, orderedColumns.includes(column))
|
||||||
|
if (e.type === 'column-visibility' && ! orderedColumns.includes(column)) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
var i;
|
var i;
|
||||||
var orderClasses = classes.order;
|
var orderClasses = classes.order;
|
||||||
var columns = ctx.api.columns( cell );
|
var columns = ctx.api.columns( cell );
|
||||||
@ -13020,8 +13225,8 @@
|
|||||||
var ariaType = '';
|
var ariaType = '';
|
||||||
var indexes = columns.indexes();
|
var indexes = columns.indexes();
|
||||||
var sortDirs = columns.orderable(true).flatten();
|
var sortDirs = columns.orderable(true).flatten();
|
||||||
var orderedColumns = _pluck(sorting, 'col');
|
|
||||||
var tabIndex = settings.iTabIndex;
|
var tabIndex = settings.iTabIndex;
|
||||||
|
var canOrder = ctx.orderHandler && orderable;
|
||||||
|
|
||||||
cell
|
cell
|
||||||
.removeClass(
|
.removeClass(
|
||||||
@ -13029,8 +13234,8 @@
|
|||||||
orderClasses.isDesc
|
orderClasses.isDesc
|
||||||
)
|
)
|
||||||
.toggleClass( orderClasses.none, ! orderable )
|
.toggleClass( orderClasses.none, ! orderable )
|
||||||
.toggleClass( orderClasses.canAsc, orderable && sortDirs.includes('asc') )
|
.toggleClass( orderClasses.canAsc, canOrder && sortDirs.includes('asc') )
|
||||||
.toggleClass( orderClasses.canDesc, orderable && sortDirs.includes('desc') );
|
.toggleClass( orderClasses.canDesc, canOrder && sortDirs.includes('desc') );
|
||||||
|
|
||||||
// Determine if all of the columns that this cell covers are included in the
|
// Determine if all of the columns that this cell covers are included in the
|
||||||
// current ordering
|
// current ordering
|
||||||
@ -13789,12 +13994,17 @@
|
|||||||
} );
|
} );
|
||||||
|
|
||||||
for ( i=0 ; i<lengths.length ; i++ ) {
|
for ( i=0 ; i<lengths.length ; i++ ) {
|
||||||
select[0][ i ] = new Option(
|
// Attempt to look up the length from the i18n options
|
||||||
typeof language[i] === 'number' ?
|
var label = settings.api.i18n('lengthLabels.' + lengths[i], null);
|
||||||
|
|
||||||
|
if (label === null) {
|
||||||
|
// If not present, fallback to old style
|
||||||
|
label = typeof language[i] === 'number' ?
|
||||||
settings.fnFormatNumber( language[i] ) :
|
settings.fnFormatNumber( language[i] ) :
|
||||||
language[i],
|
language[i];
|
||||||
lengths[i]
|
}
|
||||||
);
|
|
||||||
|
select[0][ i ] = new Option(label, lengths[i]);
|
||||||
}
|
}
|
||||||
|
|
||||||
// add for and id to label and input
|
// add for and id to label and input
|
||||||
|
@ -24,6 +24,7 @@
|
|||||||
<dt class="col-sm-5">Web Installed
|
<dt class="col-sm-5">Web Installed
|
||||||
<span class="badge bg-success d-none" id="web-success" title="Latest version is installed.">Ok</span>
|
<span class="badge bg-success d-none" id="web-success" title="Latest version is installed.">Ok</span>
|
||||||
<span class="badge bg-warning text-dark d-none" id="web-warning" title="There seems to be an update available.">Update</span>
|
<span class="badge bg-warning text-dark d-none" id="web-warning" title="There seems to be an update available.">Update</span>
|
||||||
|
<span class="badge bg-info text-dark d-none" id="web-prerelease" title="You seem to be using a pre-release version.">Pre-Release</span>
|
||||||
</dt>
|
</dt>
|
||||||
<dd class="col-sm-7">
|
<dd class="col-sm-7">
|
||||||
<span id="web-installed">{{page_data.web_vault_version}}</span>
|
<span id="web-installed">{{page_data.web_vault_version}}</span>
|
||||||
@ -68,10 +69,14 @@
|
|||||||
<span class="d-block"><b>No</b></span>
|
<span class="d-block"><b>No</b></span>
|
||||||
{{/unless}}
|
{{/unless}}
|
||||||
</dd>
|
</dd>
|
||||||
<dt class="col-sm-5">Environment settings overridden</dt>
|
<dt class="col-sm-5">Uses config.json
|
||||||
|
{{#if page_data.overrides}}
|
||||||
|
<span class="badge bg-info text-dark" title="Environment variables are overwritten by a config.json.">Note</span>
|
||||||
|
{{/if}}
|
||||||
|
</dt>
|
||||||
<dd class="col-sm-7">
|
<dd class="col-sm-7">
|
||||||
{{#if page_data.overrides}}
|
{{#if page_data.overrides}}
|
||||||
<span class="d-block" title="The following settings are overridden: {{page_data.overrides}}"><b>Yes</b></span>
|
<abbr class="d-block" title="The following settings are overridden: {{page_data.overrides}}"><b>Yes</b></abbr>
|
||||||
{{/if}}
|
{{/if}}
|
||||||
{{#unless page_data.overrides}}
|
{{#unless page_data.overrides}}
|
||||||
<span class="d-block"><b>No</b></span>
|
<span class="d-block"><b>No</b></span>
|
||||||
@ -154,7 +159,11 @@
|
|||||||
<dd class="col-sm-7">
|
<dd class="col-sm-7">
|
||||||
<span id="dns-resolved">{{page_data.dns_resolved}}</span>
|
<span id="dns-resolved">{{page_data.dns_resolved}}</span>
|
||||||
</dd>
|
</dd>
|
||||||
<dt class="col-sm-5">Date & Time (Local)</dt>
|
<dt class="col-sm-5">Date & Time (Local)
|
||||||
|
{{#if page_data.tz_env}}
|
||||||
|
<span class="badge bg-success" title="Configured TZ environment variable">{{page_data.tz_env}}</span>
|
||||||
|
{{/if}}
|
||||||
|
</dt>
|
||||||
<dd class="col-sm-7">
|
<dd class="col-sm-7">
|
||||||
<span><b>Server:</b> {{page_data.server_time_local}}</span>
|
<span><b>Server:</b> {{page_data.server_time_local}}</span>
|
||||||
</dd>
|
</dd>
|
||||||
|
@ -43,7 +43,7 @@
|
|||||||
<span class="d-block"><strong>Groups:</strong> {{group_count}}</span>
|
<span class="d-block"><strong>Groups:</strong> {{group_count}}</span>
|
||||||
<span class="d-block"><strong>Events:</strong> {{event_count}}</span>
|
<span class="d-block"><strong>Events:</strong> {{event_count}}</span>
|
||||||
</td>
|
</td>
|
||||||
<td class="text-end px-0 small">
|
<td class="text-end px-1 small">
|
||||||
<button type="button" class="btn btn-sm btn-link p-0 border-0 float-right" vw-delete-organization data-vw-org-uuid="{{id}}" data-vw-org-name="{{name}}" data-vw-billing-email="{{billingEmail}}">Delete Organization</button><br>
|
<button type="button" class="btn btn-sm btn-link p-0 border-0 float-right" vw-delete-organization data-vw-org-uuid="{{id}}" data-vw-org-name="{{name}}" data-vw-billing-email="{{billingEmail}}">Delete Organization</button><br>
|
||||||
</td>
|
</td>
|
||||||
</tr>
|
</tr>
|
||||||
|
@ -60,7 +60,7 @@
|
|||||||
{{/each}}
|
{{/each}}
|
||||||
</div>
|
</div>
|
||||||
</td>
|
</td>
|
||||||
<td class="text-end px-0 small">
|
<td class="text-end px-1 small">
|
||||||
<span data-vw-user-uuid="{{id}}" data-vw-user-email="{{email}}">
|
<span data-vw-user-uuid="{{id}}" data-vw-user-email="{{email}}">
|
||||||
{{#if twoFactorEnabled}}
|
{{#if twoFactorEnabled}}
|
||||||
<button type="button" class="btn btn-sm btn-link p-0 border-0 float-right" vw-remove2fa>Remove all 2FA</button><br>
|
<button type="button" class="btn btn-sm btn-link p-0 border-0 float-right" vw-remove2fa>Remove all 2FA</button><br>
|
||||||
|
@ -82,15 +82,19 @@ bit-nav-logo bit-nav-item .bwi-shield {
|
|||||||
{{#if signup_disabled}}
|
{{#if signup_disabled}}
|
||||||
/* From web vault 2025.1.2 and onwards, the signup button is hidden
|
/* From web vault 2025.1.2 and onwards, the signup button is hidden
|
||||||
when signups are disabled as the web vault checks the /api/config endpoint.
|
when signups are disabled as the web vault checks the /api/config endpoint.
|
||||||
Note that the clients tend to aggressively cache this endpoint, so it might
|
Note that the clients tend to cache this endpoint for about 1 hour, so it might
|
||||||
take a while for the change to take effect. To avoid the button appearing
|
take a while for the change to take effect. To avoid the button appearing
|
||||||
when it shouldn't, we'll keep this style in place for a couple of versions */
|
when it shouldn't, we'll keep this style in place for a couple of versions */
|
||||||
{{#if webver "<2025.3.0"}}
|
|
||||||
/* Hide the register link on the login screen */
|
/* Hide the register link on the login screen */
|
||||||
|
{{#if (webver "<2025.3.0")}}
|
||||||
app-login form div + div + div + div + hr,
|
app-login form div + div + div + div + hr,
|
||||||
app-login form div + div + div + div + hr + p {
|
app-login form div + div + div + div + hr + p {
|
||||||
@extend %vw-hide;
|
@extend %vw-hide;
|
||||||
}
|
}
|
||||||
|
{{else}}
|
||||||
|
app-root a[routerlink="/signup"] {
|
||||||
|
@extend %vw-hide;
|
||||||
|
}
|
||||||
{{/if}}
|
{{/if}}
|
||||||
{{/if}}
|
{{/if}}
|
||||||
|
|
||||||
|
Loading…
x
Reference in New Issue
Block a user