Spiegel von
https://github.com/dani-garcia/vaultwarden.git
synchronisiert 2024-11-16 04:12:53 +01:00
Change the handling of login errors.
Previously FlashMessage was used to provide an error message during login. This PR changes that flow to not use redirect for this, but renders the HTML and responds using the correct status code where needed. This should solve some issues which were reported in the past. Thanks to @RealOrangeOne, for initiating this with a PR. Fixes #2448 Fixes #2712 Closes #2715 Co-authored-by: Jake Howard <git@theorangeone.net>
Dieser Commit ist enthalten in:
Ursprung
a62dc102fb
Commit
5a05139efe
6 geänderte Dateien mit 262 neuen und 1205 gelöschten Zeilen
|
@ -7,8 +7,8 @@ use rocket::serde::json::Json;
|
||||||
use rocket::{
|
use rocket::{
|
||||||
form::Form,
|
form::Form,
|
||||||
http::{Cookie, CookieJar, SameSite, Status},
|
http::{Cookie, CookieJar, SameSite, Status},
|
||||||
request::{self, FlashMessage, FromRequest, Outcome, Request},
|
request::{self, FromRequest, Outcome, Request},
|
||||||
response::{content::RawHtml as Html, Flash, Redirect},
|
response::{content::RawHtml as Html, Redirect},
|
||||||
Route,
|
Route,
|
||||||
};
|
};
|
||||||
|
|
||||||
|
@ -141,10 +141,24 @@ fn admin_url(referer: Referer) -> String {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#[derive(Responder)]
|
||||||
|
enum AdminResponse {
|
||||||
|
#[response(status = 200)]
|
||||||
|
Ok(ApiResult<Html<String>>),
|
||||||
|
#[response(status = 401)]
|
||||||
|
Unauthorized(ApiResult<Html<String>>),
|
||||||
|
#[response(status = 429)]
|
||||||
|
TooManyRequests(ApiResult<Html<String>>),
|
||||||
|
}
|
||||||
|
|
||||||
#[get("/", rank = 2)]
|
#[get("/", rank = 2)]
|
||||||
fn admin_login(flash: Option<FlashMessage<'_>>) -> ApiResult<Html<String>> {
|
fn admin_login() -> ApiResult<Html<String>> {
|
||||||
|
render_admin_login(None)
|
||||||
|
}
|
||||||
|
|
||||||
|
fn render_admin_login(msg: Option<&str>) -> ApiResult<Html<String>> {
|
||||||
// If there is an error, show it
|
// If there is an error, show it
|
||||||
let msg = flash.map(|msg| format!("{}: {}", msg.kind(), msg.message()));
|
let msg = msg.map(|msg| format!("Error: {msg}"));
|
||||||
let json = json!({
|
let json = json!({
|
||||||
"page_content": "admin/login",
|
"page_content": "admin/login",
|
||||||
"version": VERSION,
|
"version": VERSION,
|
||||||
|
@ -163,22 +177,17 @@ struct LoginForm {
|
||||||
}
|
}
|
||||||
|
|
||||||
#[post("/", data = "<data>")]
|
#[post("/", data = "<data>")]
|
||||||
fn post_admin_login(
|
fn post_admin_login(data: Form<LoginForm>, cookies: &CookieJar<'_>, ip: ClientIp) -> AdminResponse {
|
||||||
data: Form<LoginForm>,
|
|
||||||
cookies: &CookieJar<'_>,
|
|
||||||
ip: ClientIp,
|
|
||||||
referer: Referer,
|
|
||||||
) -> Result<Redirect, Flash<Redirect>> {
|
|
||||||
let data = data.into_inner();
|
let data = data.into_inner();
|
||||||
|
|
||||||
if crate::ratelimit::check_limit_admin(&ip.ip).is_err() {
|
if crate::ratelimit::check_limit_admin(&ip.ip).is_err() {
|
||||||
return Err(Flash::error(Redirect::to(admin_url(referer)), "Too many requests, try again later."));
|
return AdminResponse::TooManyRequests(render_admin_login(Some("Too many requests, try again later.")));
|
||||||
}
|
}
|
||||||
|
|
||||||
// If the token is invalid, redirect to login page
|
// If the token is invalid, redirect to login page
|
||||||
if !_validate_token(&data.token) {
|
if !_validate_token(&data.token) {
|
||||||
error!("Invalid admin token. IP: {}", ip.ip);
|
error!("Invalid admin token. IP: {}", ip.ip);
|
||||||
Err(Flash::error(Redirect::to(admin_url(referer)), "Invalid admin token, please try again."))
|
AdminResponse::Unauthorized(render_admin_login(Some("Invalid admin token, please try again.")))
|
||||||
} else {
|
} else {
|
||||||
// If the token received is valid, generate JWT and save it as a cookie
|
// If the token received is valid, generate JWT and save it as a cookie
|
||||||
let claims = generate_admin_claims();
|
let claims = generate_admin_claims();
|
||||||
|
@ -192,7 +201,7 @@ fn post_admin_login(
|
||||||
.finish();
|
.finish();
|
||||||
|
|
||||||
cookies.add(cookie);
|
cookies.add(cookie);
|
||||||
Ok(Redirect::to(admin_url(referer)))
|
AdminResponse::Ok(render_admin_page())
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -244,12 +253,16 @@ impl AdminTemplateData {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
#[get("/", rank = 1)]
|
fn render_admin_page() -> ApiResult<Html<String>> {
|
||||||
fn admin_page(_token: AdminToken) -> ApiResult<Html<String>> {
|
|
||||||
let text = AdminTemplateData::new().render()?;
|
let text = AdminTemplateData::new().render()?;
|
||||||
Ok(Html(text))
|
Ok(Html(text))
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#[get("/", rank = 1)]
|
||||||
|
fn admin_page(_token: AdminToken) -> ApiResult<Html<String>> {
|
||||||
|
render_admin_page()
|
||||||
|
}
|
||||||
|
|
||||||
#[derive(Deserialize, Debug)]
|
#[derive(Deserialize, Debug)]
|
||||||
#[allow(non_snake_case)]
|
#[allow(non_snake_case)]
|
||||||
struct InviteData {
|
struct InviteData {
|
||||||
|
@ -303,7 +316,7 @@ async fn test_smtp(data: Json<InviteData>, _token: AdminToken) -> EmptyResult {
|
||||||
#[get("/logout")]
|
#[get("/logout")]
|
||||||
fn logout(cookies: &CookieJar<'_>, referer: Referer) -> Redirect {
|
fn logout(cookies: &CookieJar<'_>, referer: Referer) -> Redirect {
|
||||||
cookies.remove(Cookie::build(COOKIE_NAME, "").path(admin_path()).finish());
|
cookies.remove(Cookie::build(COOKIE_NAME, "").path(admin_path()).finish());
|
||||||
Redirect::to(admin_url(referer))
|
Redirect::temporary(admin_url(referer))
|
||||||
}
|
}
|
||||||
|
|
||||||
#[get("/users")]
|
#[get("/users")]
|
||||||
|
@ -509,7 +522,6 @@ use cached::proc_macro::cached;
|
||||||
async fn get_release_info(has_http_access: bool, running_within_docker: bool) -> (String, String, String) {
|
async fn get_release_info(has_http_access: bool, running_within_docker: 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 {
|
||||||
info!("Running get_release_info!!");
|
|
||||||
(
|
(
|
||||||
match get_github_api::<GitRelease>("https://api.github.com/repos/dani-garcia/vaultwarden/releases/latest")
|
match get_github_api::<GitRelease>("https://api.github.com/repos/dani-garcia/vaultwarden/releases/latest")
|
||||||
.await
|
.await
|
||||||
|
|
|
@ -88,8 +88,8 @@ fn static_files(filename: String) -> Result<(ContentType, &'static [u8]), Error>
|
||||||
"identicon.js" => Ok((ContentType::JavaScript, include_bytes!("../static/scripts/identicon.js"))),
|
"identicon.js" => Ok((ContentType::JavaScript, include_bytes!("../static/scripts/identicon.js"))),
|
||||||
"datatables.js" => Ok((ContentType::JavaScript, include_bytes!("../static/scripts/datatables.js"))),
|
"datatables.js" => Ok((ContentType::JavaScript, include_bytes!("../static/scripts/datatables.js"))),
|
||||||
"datatables.css" => Ok((ContentType::CSS, include_bytes!("../static/scripts/datatables.css"))),
|
"datatables.css" => Ok((ContentType::CSS, include_bytes!("../static/scripts/datatables.css"))),
|
||||||
"jquery-3.6.0.slim.js" => {
|
"jquery-3.6.1.slim.js" => {
|
||||||
Ok((ContentType::JavaScript, include_bytes!("../static/scripts/jquery-3.6.0.slim.js")))
|
Ok((ContentType::JavaScript, include_bytes!("../static/scripts/jquery-3.6.1.slim.js")))
|
||||||
}
|
}
|
||||||
_ => err!(format!("Static file not found: {}", filename)),
|
_ => err!(format!("Static file not found: {}", filename)),
|
||||||
}
|
}
|
||||||
|
|
1223
src/static/scripts/bootstrap.css
gevendort
1223
src/static/scripts/bootstrap.css
gevendort
Datei-Diff unterdrückt, da er zu groß ist
Diff laden
|
@ -1,5 +1,5 @@
|
||||||
/*!
|
/*!
|
||||||
* jQuery JavaScript Library v3.6.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/Tween,-effects/animatedSelector
|
* jQuery JavaScript Library v3.6.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/Tween,-effects/animatedSelector
|
||||||
* https://jquery.com/
|
* https://jquery.com/
|
||||||
*
|
*
|
||||||
* Includes Sizzle.js
|
* Includes Sizzle.js
|
||||||
|
@ -9,7 +9,7 @@
|
||||||
* Released under the MIT license
|
* Released under the MIT license
|
||||||
* https://jquery.org/license
|
* https://jquery.org/license
|
||||||
*
|
*
|
||||||
* Date: 2021-03-02T17:08Z
|
* Date: 2022-08-26T17:52Z
|
||||||
*/
|
*/
|
||||||
( function( global, factory ) {
|
( function( global, factory ) {
|
||||||
|
|
||||||
|
@ -23,7 +23,7 @@
|
||||||
// (such as Node.js), expose a factory as module.exports.
|
// (such as Node.js), expose a factory as module.exports.
|
||||||
// This accentuates the need for the creation of a real `window`.
|
// This accentuates the need for the creation of a real `window`.
|
||||||
// e.g. var jQuery = require("jquery")(window);
|
// e.g. var jQuery = require("jquery")(window);
|
||||||
// See ticket #14549 for more info.
|
// See ticket trac-14549 for more info.
|
||||||
module.exports = global.document ?
|
module.exports = global.document ?
|
||||||
factory( global, true ) :
|
factory( global, true ) :
|
||||||
function( w ) {
|
function( w ) {
|
||||||
|
@ -151,7 +151,7 @@ function toType( obj ) {
|
||||||
|
|
||||||
|
|
||||||
var
|
var
|
||||||
version = "3.6.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/Tween,-effects/animatedSelector",
|
version = "3.6.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/Tween,-effects/animatedSelector",
|
||||||
|
|
||||||
// Define a local copy of jQuery
|
// Define a local copy of jQuery
|
||||||
jQuery = function( selector, context ) {
|
jQuery = function( selector, context ) {
|
||||||
|
@ -3129,8 +3129,8 @@ jQuery.fn.extend( {
|
||||||
var rootjQuery,
|
var rootjQuery,
|
||||||
|
|
||||||
// A simple way to check for HTML strings
|
// A simple way to check for HTML strings
|
||||||
// Prioritize #id over <tag> to avoid XSS via location.hash (#9521)
|
// Prioritize #id over <tag> to avoid XSS via location.hash (trac-9521)
|
||||||
// Strict HTML recognition (#11290: must start with <)
|
// Strict HTML recognition (trac-11290: must start with <)
|
||||||
// Shortcut simple #id case for speed
|
// Shortcut simple #id case for speed
|
||||||
rquickExpr = /^(?:\s*(<[\w\W]+>)[^>]*|#([\w-]+))$/,
|
rquickExpr = /^(?:\s*(<[\w\W]+>)[^>]*|#([\w-]+))$/,
|
||||||
|
|
||||||
|
@ -4087,7 +4087,7 @@ jQuery.extend( {
|
||||||
isReady: false,
|
isReady: false,
|
||||||
|
|
||||||
// A counter to track how many items to wait for before
|
// A counter to track how many items to wait for before
|
||||||
// the ready event fires. See #6781
|
// the ready event fires. See trac-6781
|
||||||
readyWait: 1,
|
readyWait: 1,
|
||||||
|
|
||||||
// Handle when the DOM is ready
|
// Handle when the DOM is ready
|
||||||
|
@ -4215,7 +4215,7 @@ function fcamelCase( _all, letter ) {
|
||||||
|
|
||||||
// Convert dashed to camelCase; used by the css and data modules
|
// Convert dashed to camelCase; used by the css and data modules
|
||||||
// Support: IE <=9 - 11, Edge 12 - 15
|
// Support: IE <=9 - 11, Edge 12 - 15
|
||||||
// Microsoft forgot to hump their vendor prefix (#9572)
|
// Microsoft forgot to hump their vendor prefix (trac-9572)
|
||||||
function camelCase( string ) {
|
function camelCase( string ) {
|
||||||
return string.replace( rmsPrefix, "ms-" ).replace( rdashAlpha, fcamelCase );
|
return string.replace( rmsPrefix, "ms-" ).replace( rdashAlpha, fcamelCase );
|
||||||
}
|
}
|
||||||
|
@ -4251,7 +4251,7 @@ Data.prototype = {
|
||||||
value = {};
|
value = {};
|
||||||
|
|
||||||
// We can accept data for non-element nodes in modern browsers,
|
// We can accept data for non-element nodes in modern browsers,
|
||||||
// but we should not, see #8335.
|
// but we should not, see trac-8335.
|
||||||
// Always return an empty object.
|
// Always return an empty object.
|
||||||
if ( acceptData( owner ) ) {
|
if ( acceptData( owner ) ) {
|
||||||
|
|
||||||
|
@ -4490,7 +4490,7 @@ jQuery.fn.extend( {
|
||||||
while ( i-- ) {
|
while ( i-- ) {
|
||||||
|
|
||||||
// Support: IE 11 only
|
// Support: IE 11 only
|
||||||
// The attrs elements can be null (#14894)
|
// The attrs elements can be null (trac-14894)
|
||||||
if ( attrs[ i ] ) {
|
if ( attrs[ i ] ) {
|
||||||
name = attrs[ i ].name;
|
name = attrs[ i ].name;
|
||||||
if ( name.indexOf( "data-" ) === 0 ) {
|
if ( name.indexOf( "data-" ) === 0 ) {
|
||||||
|
@ -4913,9 +4913,9 @@ var rscriptType = ( /^$|^module$|\/(?:java|ecma)script/i );
|
||||||
input = document.createElement( "input" );
|
input = document.createElement( "input" );
|
||||||
|
|
||||||
// Support: Android 4.0 - 4.3 only
|
// Support: Android 4.0 - 4.3 only
|
||||||
// Check state lost if the name is set (#11217)
|
// Check state lost if the name is set (trac-11217)
|
||||||
// Support: Windows Web Apps (WWA)
|
// Support: Windows Web Apps (WWA)
|
||||||
// `name` and `type` must use .setAttribute for WWA (#14901)
|
// `name` and `type` must use .setAttribute for WWA (trac-14901)
|
||||||
input.setAttribute( "type", "radio" );
|
input.setAttribute( "type", "radio" );
|
||||||
input.setAttribute( "checked", "checked" );
|
input.setAttribute( "checked", "checked" );
|
||||||
input.setAttribute( "name", "t" );
|
input.setAttribute( "name", "t" );
|
||||||
|
@ -4939,7 +4939,7 @@ var rscriptType = ( /^$|^module$|\/(?:java|ecma)script/i );
|
||||||
} )();
|
} )();
|
||||||
|
|
||||||
|
|
||||||
// We have to close these tags to support XHTML (#13200)
|
// We have to close these tags to support XHTML (trac-13200)
|
||||||
var wrapMap = {
|
var wrapMap = {
|
||||||
|
|
||||||
// XHTML parsers do not magically insert elements in the
|
// XHTML parsers do not magically insert elements in the
|
||||||
|
@ -4965,7 +4965,7 @@ if ( !support.option ) {
|
||||||
function getAll( context, tag ) {
|
function getAll( context, tag ) {
|
||||||
|
|
||||||
// Support: IE <=9 - 11 only
|
// Support: IE <=9 - 11 only
|
||||||
// Use typeof to avoid zero-argument method invocation on host objects (#15151)
|
// Use typeof to avoid zero-argument method invocation on host objects (trac-15151)
|
||||||
var ret;
|
var ret;
|
||||||
|
|
||||||
if ( typeof context.getElementsByTagName !== "undefined" ) {
|
if ( typeof context.getElementsByTagName !== "undefined" ) {
|
||||||
|
@ -5048,7 +5048,7 @@ function buildFragment( elems, context, scripts, selection, ignored ) {
|
||||||
// Remember the top-level container
|
// Remember the top-level container
|
||||||
tmp = fragment.firstChild;
|
tmp = fragment.firstChild;
|
||||||
|
|
||||||
// Ensure the created nodes are orphaned (#12392)
|
// Ensure the created nodes are orphaned (trac-12392)
|
||||||
tmp.textContent = "";
|
tmp.textContent = "";
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -5469,15 +5469,15 @@ jQuery.event = {
|
||||||
|
|
||||||
for ( ; cur !== this; cur = cur.parentNode || this ) {
|
for ( ; cur !== this; cur = cur.parentNode || this ) {
|
||||||
|
|
||||||
// Don't check non-elements (#13208)
|
// Don't check non-elements (trac-13208)
|
||||||
// Don't process clicks on disabled elements (#6911, #8165, #11382, #11764)
|
// Don't process clicks on disabled elements (trac-6911, trac-8165, trac-11382, trac-11764)
|
||||||
if ( cur.nodeType === 1 && !( event.type === "click" && cur.disabled === true ) ) {
|
if ( cur.nodeType === 1 && !( event.type === "click" && cur.disabled === true ) ) {
|
||||||
matchedHandlers = [];
|
matchedHandlers = [];
|
||||||
matchedSelectors = {};
|
matchedSelectors = {};
|
||||||
for ( i = 0; i < delegateCount; i++ ) {
|
for ( i = 0; i < delegateCount; i++ ) {
|
||||||
handleObj = handlers[ i ];
|
handleObj = handlers[ i ];
|
||||||
|
|
||||||
// Don't conflict with Object.prototype properties (#13203)
|
// Don't conflict with Object.prototype properties (trac-13203)
|
||||||
sel = handleObj.selector + " ";
|
sel = handleObj.selector + " ";
|
||||||
|
|
||||||
if ( matchedSelectors[ sel ] === undefined ) {
|
if ( matchedSelectors[ sel ] === undefined ) {
|
||||||
|
@ -5731,7 +5731,7 @@ jQuery.Event = function( src, props ) {
|
||||||
|
|
||||||
// Create target properties
|
// Create target properties
|
||||||
// Support: Safari <=6 - 7 only
|
// Support: Safari <=6 - 7 only
|
||||||
// Target should not be a text node (#504, #13143)
|
// Target should not be a text node (trac-504, trac-13143)
|
||||||
this.target = ( src.target && src.target.nodeType === 3 ) ?
|
this.target = ( src.target && src.target.nodeType === 3 ) ?
|
||||||
src.target.parentNode :
|
src.target.parentNode :
|
||||||
src.target;
|
src.target;
|
||||||
|
@ -5854,10 +5854,10 @@ jQuery.each( { focus: "focusin", blur: "focusout" }, function( type, delegateTyp
|
||||||
return true;
|
return true;
|
||||||
},
|
},
|
||||||
|
|
||||||
// Suppress native focus or blur as it's already being fired
|
// Suppress native focus or blur if we're currently inside
|
||||||
// in leverageNative.
|
// a leveraged native-event stack
|
||||||
_default: function() {
|
_default: function( event ) {
|
||||||
return true;
|
return dataPriv.get( event.target, type );
|
||||||
},
|
},
|
||||||
|
|
||||||
delegateType: delegateType
|
delegateType: delegateType
|
||||||
|
@ -5956,7 +5956,8 @@ var
|
||||||
|
|
||||||
// checked="checked" or checked
|
// checked="checked" or checked
|
||||||
rchecked = /checked\s*(?:[^=]|=\s*.checked.)/i,
|
rchecked = /checked\s*(?:[^=]|=\s*.checked.)/i,
|
||||||
rcleanScript = /^\s*<!(?:\[CDATA\[|--)|(?:\]\]|--)>\s*$/g;
|
|
||||||
|
rcleanScript = /^\s*<!\[CDATA\[|\]\]>\s*$/g;
|
||||||
|
|
||||||
// Prefer a tbody over its parent table for containing new rows
|
// Prefer a tbody over its parent table for containing new rows
|
||||||
function manipulationTarget( elem, content ) {
|
function manipulationTarget( elem, content ) {
|
||||||
|
@ -6070,7 +6071,7 @@ function domManip( collection, args, callback, ignored ) {
|
||||||
|
|
||||||
// Use the original fragment for the last item
|
// Use the original fragment for the last item
|
||||||
// instead of the first because it can end up
|
// instead of the first because it can end up
|
||||||
// being emptied incorrectly in certain situations (#8070).
|
// being emptied incorrectly in certain situations (trac-8070).
|
||||||
for ( ; i < l; i++ ) {
|
for ( ; i < l; i++ ) {
|
||||||
node = fragment;
|
node = fragment;
|
||||||
|
|
||||||
|
@ -6111,6 +6112,12 @@ function domManip( collection, args, callback, ignored ) {
|
||||||
}, doc );
|
}, doc );
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
|
|
||||||
|
// Unwrap a CDATA section containing script contents. This shouldn't be
|
||||||
|
// needed as in XML documents they're already not visible when
|
||||||
|
// inspecting element contents and in HTML documents they have no
|
||||||
|
// meaning but we're preserving that logic for backwards compatibility.
|
||||||
|
// This will be removed completely in 4.0. See gh-4904.
|
||||||
DOMEval( node.textContent.replace( rcleanScript, "" ), node, doc );
|
DOMEval( node.textContent.replace( rcleanScript, "" ), node, doc );
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -6393,9 +6400,12 @@ jQuery.each( {
|
||||||
} );
|
} );
|
||||||
var rnumnonpx = new RegExp( "^(" + pnum + ")(?!px)[a-z%]+$", "i" );
|
var rnumnonpx = new RegExp( "^(" + pnum + ")(?!px)[a-z%]+$", "i" );
|
||||||
|
|
||||||
|
var rcustomProp = /^--/;
|
||||||
|
|
||||||
|
|
||||||
var getStyles = function( elem ) {
|
var getStyles = function( elem ) {
|
||||||
|
|
||||||
// Support: IE <=11 only, Firefox <=30 (#15098, #14150)
|
// Support: IE <=11 only, Firefox <=30 (trac-15098, trac-14150)
|
||||||
// IE throws on elements created in popups
|
// IE throws on elements created in popups
|
||||||
// FF meanwhile throws on frame elements through "defaultView.getComputedStyle"
|
// FF meanwhile throws on frame elements through "defaultView.getComputedStyle"
|
||||||
var view = elem.ownerDocument.defaultView;
|
var view = elem.ownerDocument.defaultView;
|
||||||
|
@ -6430,6 +6440,15 @@ var swap = function( elem, options, callback ) {
|
||||||
|
|
||||||
var rboxStyle = new RegExp( cssExpand.join( "|" ), "i" );
|
var rboxStyle = new RegExp( cssExpand.join( "|" ), "i" );
|
||||||
|
|
||||||
|
var whitespace = "[\\x20\\t\\r\\n\\f]";
|
||||||
|
|
||||||
|
|
||||||
|
var rtrimCSS = new RegExp(
|
||||||
|
"^" + whitespace + "+|((?:^|[^\\\\])(?:\\\\.)*)" + whitespace + "+$",
|
||||||
|
"g"
|
||||||
|
);
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
( function() {
|
( function() {
|
||||||
|
@ -6495,7 +6514,7 @@ var rboxStyle = new RegExp( cssExpand.join( "|" ), "i" );
|
||||||
}
|
}
|
||||||
|
|
||||||
// Support: IE <=9 - 11 only
|
// Support: IE <=9 - 11 only
|
||||||
// Style of cloned element affects source element cloned (#8908)
|
// Style of cloned element affects source element cloned (trac-8908)
|
||||||
div.style.backgroundClip = "content-box";
|
div.style.backgroundClip = "content-box";
|
||||||
div.cloneNode( true ).style.backgroundClip = "";
|
div.cloneNode( true ).style.backgroundClip = "";
|
||||||
support.clearCloneStyle = div.style.backgroundClip === "content-box";
|
support.clearCloneStyle = div.style.backgroundClip === "content-box";
|
||||||
|
@ -6575,6 +6594,7 @@ var rboxStyle = new RegExp( cssExpand.join( "|" ), "i" );
|
||||||
|
|
||||||
function curCSS( elem, name, computed ) {
|
function curCSS( elem, name, computed ) {
|
||||||
var width, minWidth, maxWidth, ret,
|
var width, minWidth, maxWidth, ret,
|
||||||
|
isCustomProp = rcustomProp.test( name ),
|
||||||
|
|
||||||
// Support: Firefox 51+
|
// Support: Firefox 51+
|
||||||
// Retrieving style before computed somehow
|
// Retrieving style before computed somehow
|
||||||
|
@ -6585,11 +6605,22 @@ function curCSS( elem, name, computed ) {
|
||||||
computed = computed || getStyles( elem );
|
computed = computed || getStyles( elem );
|
||||||
|
|
||||||
// getPropertyValue is needed for:
|
// getPropertyValue is needed for:
|
||||||
// .css('filter') (IE 9 only, #12537)
|
// .css('filter') (IE 9 only, trac-12537)
|
||||||
// .css('--customProperty) (#3144)
|
// .css('--customProperty) (gh-3144)
|
||||||
if ( computed ) {
|
if ( computed ) {
|
||||||
ret = computed.getPropertyValue( name ) || computed[ name ];
|
ret = computed.getPropertyValue( name ) || computed[ name ];
|
||||||
|
|
||||||
|
// trim whitespace for custom property (issue gh-4926)
|
||||||
|
if ( isCustomProp ) {
|
||||||
|
|
||||||
|
// rtrim treats U+000D CARRIAGE RETURN and U+000C FORM FEED
|
||||||
|
// as whitespace while CSS does not, but this is not a problem
|
||||||
|
// because CSS preprocessing replaces them with U+000A LINE FEED
|
||||||
|
// (which *is* CSS whitespace)
|
||||||
|
// https://www.w3.org/TR/css-syntax-3/#input-preprocessing
|
||||||
|
ret = ret.replace( rtrimCSS, "$1" );
|
||||||
|
}
|
||||||
|
|
||||||
if ( ret === "" && !isAttached( elem ) ) {
|
if ( ret === "" && !isAttached( elem ) ) {
|
||||||
ret = jQuery.style( elem, name );
|
ret = jQuery.style( elem, name );
|
||||||
}
|
}
|
||||||
|
@ -6685,7 +6716,6 @@ var
|
||||||
// except "table", "table-cell", or "table-caption"
|
// except "table", "table-cell", or "table-caption"
|
||||||
// See here for display values: https://developer.mozilla.org/en-US/docs/CSS/display
|
// See here for display values: https://developer.mozilla.org/en-US/docs/CSS/display
|
||||||
rdisplayswap = /^(none|table(?!-c[ea]).+)/,
|
rdisplayswap = /^(none|table(?!-c[ea]).+)/,
|
||||||
rcustomProp = /^--/,
|
|
||||||
cssShow = { position: "absolute", visibility: "hidden", display: "block" },
|
cssShow = { position: "absolute", visibility: "hidden", display: "block" },
|
||||||
cssNormalTransform = {
|
cssNormalTransform = {
|
||||||
letterSpacing: "0",
|
letterSpacing: "0",
|
||||||
|
@ -6921,15 +6951,15 @@ jQuery.extend( {
|
||||||
if ( value !== undefined ) {
|
if ( value !== undefined ) {
|
||||||
type = typeof value;
|
type = typeof value;
|
||||||
|
|
||||||
// Convert "+=" or "-=" to relative numbers (#7345)
|
// Convert "+=" or "-=" to relative numbers (trac-7345)
|
||||||
if ( type === "string" && ( ret = rcssNum.exec( value ) ) && ret[ 1 ] ) {
|
if ( type === "string" && ( ret = rcssNum.exec( value ) ) && ret[ 1 ] ) {
|
||||||
value = adjustCSS( elem, name, ret );
|
value = adjustCSS( elem, name, ret );
|
||||||
|
|
||||||
// Fixes bug #9237
|
// Fixes bug trac-9237
|
||||||
type = "number";
|
type = "number";
|
||||||
}
|
}
|
||||||
|
|
||||||
// Make sure that null and NaN values aren't set (#7116)
|
// Make sure that null and NaN values aren't set (trac-7116)
|
||||||
if ( value == null || value !== value ) {
|
if ( value == null || value !== value ) {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
@ -7149,7 +7179,6 @@ jQuery.fn.extend( {
|
||||||
|
|
||||||
|
|
||||||
// Based off of the plugin by Clint Helfers, with permission.
|
// Based off of the plugin by Clint Helfers, with permission.
|
||||||
// https://web.archive.org/web/20100324014747/http://blindsignals.com/index.php/2009/07/jquery-delay/
|
|
||||||
jQuery.fn.delay = function( time, type ) {
|
jQuery.fn.delay = function( time, type ) {
|
||||||
time = jQuery.fx ? jQuery.fx.speeds[ time ] || time : time;
|
time = jQuery.fx ? jQuery.fx.speeds[ time ] || time : time;
|
||||||
type = type || "fx";
|
type = type || "fx";
|
||||||
|
@ -7374,8 +7403,7 @@ jQuery.extend( {
|
||||||
// Support: IE <=9 - 11 only
|
// Support: IE <=9 - 11 only
|
||||||
// elem.tabIndex doesn't always return the
|
// elem.tabIndex doesn't always return the
|
||||||
// correct value when it hasn't been explicitly set
|
// correct value when it hasn't been explicitly set
|
||||||
// https://web.archive.org/web/20141116233347/http://fluidproject.org/blog/2008/01/09/getting-setting-and-removing-tabindex-values-with-javascript/
|
// Use proper attribute retrieval (trac-12072)
|
||||||
// Use proper attribute retrieval(#12072)
|
|
||||||
var tabindex = jQuery.find.attr( elem, "tabindex" );
|
var tabindex = jQuery.find.attr( elem, "tabindex" );
|
||||||
|
|
||||||
if ( tabindex ) {
|
if ( tabindex ) {
|
||||||
|
@ -7479,8 +7507,7 @@ function classesToArray( value ) {
|
||||||
|
|
||||||
jQuery.fn.extend( {
|
jQuery.fn.extend( {
|
||||||
addClass: function( value ) {
|
addClass: function( value ) {
|
||||||
var classes, elem, cur, curValue, clazz, j, finalValue,
|
var classNames, cur, curValue, className, i, finalValue;
|
||||||
i = 0;
|
|
||||||
|
|
||||||
if ( isFunction( value ) ) {
|
if ( isFunction( value ) ) {
|
||||||
return this.each( function( j ) {
|
return this.each( function( j ) {
|
||||||
|
@ -7488,36 +7515,35 @@ jQuery.fn.extend( {
|
||||||
} );
|
} );
|
||||||
}
|
}
|
||||||
|
|
||||||
classes = classesToArray( value );
|
classNames = classesToArray( value );
|
||||||
|
|
||||||
if ( classes.length ) {
|
if ( classNames.length ) {
|
||||||
while ( ( elem = this[ i++ ] ) ) {
|
return this.each( function() {
|
||||||
curValue = getClass( elem );
|
curValue = getClass( this );
|
||||||
cur = elem.nodeType === 1 && ( " " + stripAndCollapse( curValue ) + " " );
|
cur = this.nodeType === 1 && ( " " + stripAndCollapse( curValue ) + " " );
|
||||||
|
|
||||||
if ( cur ) {
|
if ( cur ) {
|
||||||
j = 0;
|
for ( i = 0; i < classNames.length; i++ ) {
|
||||||
while ( ( clazz = classes[ j++ ] ) ) {
|
className = classNames[ i ];
|
||||||
if ( cur.indexOf( " " + clazz + " " ) < 0 ) {
|
if ( cur.indexOf( " " + className + " " ) < 0 ) {
|
||||||
cur += clazz + " ";
|
cur += className + " ";
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// Only assign if different to avoid unneeded rendering.
|
// Only assign if different to avoid unneeded rendering.
|
||||||
finalValue = stripAndCollapse( cur );
|
finalValue = stripAndCollapse( cur );
|
||||||
if ( curValue !== finalValue ) {
|
if ( curValue !== finalValue ) {
|
||||||
elem.setAttribute( "class", finalValue );
|
this.setAttribute( "class", finalValue );
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
} );
|
||||||
}
|
}
|
||||||
|
|
||||||
return this;
|
return this;
|
||||||
},
|
},
|
||||||
|
|
||||||
removeClass: function( value ) {
|
removeClass: function( value ) {
|
||||||
var classes, elem, cur, curValue, clazz, j, finalValue,
|
var classNames, cur, curValue, className, i, finalValue;
|
||||||
i = 0;
|
|
||||||
|
|
||||||
if ( isFunction( value ) ) {
|
if ( isFunction( value ) ) {
|
||||||
return this.each( function( j ) {
|
return this.each( function( j ) {
|
||||||
|
@ -7529,45 +7555,42 @@ jQuery.fn.extend( {
|
||||||
return this.attr( "class", "" );
|
return this.attr( "class", "" );
|
||||||
}
|
}
|
||||||
|
|
||||||
classes = classesToArray( value );
|
classNames = classesToArray( value );
|
||||||
|
|
||||||
if ( classes.length ) {
|
if ( classNames.length ) {
|
||||||
while ( ( elem = this[ i++ ] ) ) {
|
return this.each( function() {
|
||||||
curValue = getClass( elem );
|
curValue = getClass( this );
|
||||||
|
|
||||||
// This expression is here for better compressibility (see addClass)
|
// This expression is here for better compressibility (see addClass)
|
||||||
cur = elem.nodeType === 1 && ( " " + stripAndCollapse( curValue ) + " " );
|
cur = this.nodeType === 1 && ( " " + stripAndCollapse( curValue ) + " " );
|
||||||
|
|
||||||
if ( cur ) {
|
if ( cur ) {
|
||||||
j = 0;
|
for ( i = 0; i < classNames.length; i++ ) {
|
||||||
while ( ( clazz = classes[ j++ ] ) ) {
|
className = classNames[ i ];
|
||||||
|
|
||||||
// Remove *all* instances
|
// Remove *all* instances
|
||||||
while ( cur.indexOf( " " + clazz + " " ) > -1 ) {
|
while ( cur.indexOf( " " + className + " " ) > -1 ) {
|
||||||
cur = cur.replace( " " + clazz + " ", " " );
|
cur = cur.replace( " " + className + " ", " " );
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// Only assign if different to avoid unneeded rendering.
|
// Only assign if different to avoid unneeded rendering.
|
||||||
finalValue = stripAndCollapse( cur );
|
finalValue = stripAndCollapse( cur );
|
||||||
if ( curValue !== finalValue ) {
|
if ( curValue !== finalValue ) {
|
||||||
elem.setAttribute( "class", finalValue );
|
this.setAttribute( "class", finalValue );
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
} );
|
||||||
}
|
}
|
||||||
|
|
||||||
return this;
|
return this;
|
||||||
},
|
},
|
||||||
|
|
||||||
toggleClass: function( value, stateVal ) {
|
toggleClass: function( value, stateVal ) {
|
||||||
var type = typeof value,
|
var classNames, className, i, self,
|
||||||
|
type = typeof value,
|
||||||
isValidValue = type === "string" || Array.isArray( value );
|
isValidValue = type === "string" || Array.isArray( value );
|
||||||
|
|
||||||
if ( typeof stateVal === "boolean" && isValidValue ) {
|
|
||||||
return stateVal ? this.addClass( value ) : this.removeClass( value );
|
|
||||||
}
|
|
||||||
|
|
||||||
if ( isFunction( value ) ) {
|
if ( isFunction( value ) ) {
|
||||||
return this.each( function( i ) {
|
return this.each( function( i ) {
|
||||||
jQuery( this ).toggleClass(
|
jQuery( this ).toggleClass(
|
||||||
|
@ -7577,17 +7600,20 @@ jQuery.fn.extend( {
|
||||||
} );
|
} );
|
||||||
}
|
}
|
||||||
|
|
||||||
return this.each( function() {
|
if ( typeof stateVal === "boolean" && isValidValue ) {
|
||||||
var className, i, self, classNames;
|
return stateVal ? this.addClass( value ) : this.removeClass( value );
|
||||||
|
}
|
||||||
|
|
||||||
|
classNames = classesToArray( value );
|
||||||
|
|
||||||
|
return this.each( function() {
|
||||||
if ( isValidValue ) {
|
if ( isValidValue ) {
|
||||||
|
|
||||||
// Toggle individual class names
|
// Toggle individual class names
|
||||||
i = 0;
|
|
||||||
self = jQuery( this );
|
self = jQuery( this );
|
||||||
classNames = classesToArray( value );
|
|
||||||
|
|
||||||
while ( ( className = classNames[ i++ ] ) ) {
|
for ( i = 0; i < classNames.length; i++ ) {
|
||||||
|
className = classNames[ i ];
|
||||||
|
|
||||||
// Check each className given, space separated list
|
// Check each className given, space separated list
|
||||||
if ( self.hasClass( className ) ) {
|
if ( self.hasClass( className ) ) {
|
||||||
|
@ -7721,7 +7747,7 @@ jQuery.extend( {
|
||||||
val :
|
val :
|
||||||
|
|
||||||
// Support: IE <=10 - 11 only
|
// Support: IE <=10 - 11 only
|
||||||
// option.text throws exceptions (#14686, #14858)
|
// option.text throws exceptions (trac-14686, trac-14858)
|
||||||
// Strip and collapse whitespace
|
// Strip and collapse whitespace
|
||||||
// https://html.spec.whatwg.org/#strip-and-collapse-whitespace
|
// https://html.spec.whatwg.org/#strip-and-collapse-whitespace
|
||||||
stripAndCollapse( jQuery.text( elem ) );
|
stripAndCollapse( jQuery.text( elem ) );
|
||||||
|
@ -7748,7 +7774,7 @@ jQuery.extend( {
|
||||||
option = options[ i ];
|
option = options[ i ];
|
||||||
|
|
||||||
// Support: IE <=9 only
|
// Support: IE <=9 only
|
||||||
// IE8-9 doesn't update selected after form reset (#2551)
|
// IE8-9 doesn't update selected after form reset (trac-2551)
|
||||||
if ( ( option.selected || i === index ) &&
|
if ( ( option.selected || i === index ) &&
|
||||||
|
|
||||||
// Don't return options that are disabled or in a disabled optgroup
|
// Don't return options that are disabled or in a disabled optgroup
|
||||||
|
@ -7891,8 +7917,8 @@ jQuery.extend( jQuery.event, {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
// Determine event propagation path in advance, per W3C events spec (#9951)
|
// Determine event propagation path in advance, per W3C events spec (trac-9951)
|
||||||
// Bubble up to document, then to window; watch for a global ownerDocument var (#9724)
|
// Bubble up to document, then to window; watch for a global ownerDocument var (trac-9724)
|
||||||
if ( !onlyHandlers && !special.noBubble && !isWindow( elem ) ) {
|
if ( !onlyHandlers && !special.noBubble && !isWindow( elem ) ) {
|
||||||
|
|
||||||
bubbleType = special.delegateType || type;
|
bubbleType = special.delegateType || type;
|
||||||
|
@ -7944,7 +7970,7 @@ jQuery.extend( jQuery.event, {
|
||||||
acceptData( elem ) ) {
|
acceptData( elem ) ) {
|
||||||
|
|
||||||
// Call a native DOM method on the target with the same name as the event.
|
// Call a native DOM method on the target with the same name as the event.
|
||||||
// Don't do default actions on window, that's where global variables be (#6170)
|
// Don't do default actions on window, that's where global variables be (trac-6170)
|
||||||
if ( ontype && isFunction( elem[ type ] ) && !isWindow( elem ) ) {
|
if ( ontype && isFunction( elem[ type ] ) && !isWindow( elem ) ) {
|
||||||
|
|
||||||
// Don't re-trigger an onFOO event when we call its FOO() method
|
// Don't re-trigger an onFOO event when we call its FOO() method
|
||||||
|
@ -8654,7 +8680,9 @@ jQuery.each(
|
||||||
|
|
||||||
// Support: Android <=4.0 only
|
// Support: Android <=4.0 only
|
||||||
// Make sure we trim BOM and NBSP
|
// Make sure we trim BOM and NBSP
|
||||||
var rtrim = /^[\s\uFEFF\xA0]+|[\s\uFEFF\xA0]+$/g;
|
// Require that the "whitespace run" starts from a non-whitespace
|
||||||
|
// to avoid O(N^2) behavior when the engine would try matching "\s+$" at each space position.
|
||||||
|
var rtrim = /^[\s\uFEFF\xA0]+|([^\s\uFEFF\xA0])[\s\uFEFF\xA0]+$/g;
|
||||||
|
|
||||||
// Bind a function to a context, optionally partially applying any
|
// Bind a function to a context, optionally partially applying any
|
||||||
// arguments.
|
// arguments.
|
||||||
|
@ -8721,7 +8749,7 @@ jQuery.isNumeric = function( obj ) {
|
||||||
jQuery.trim = function( text ) {
|
jQuery.trim = function( text ) {
|
||||||
return text == null ?
|
return text == null ?
|
||||||
"" :
|
"" :
|
||||||
( text + "" ).replace( rtrim, "" );
|
( text + "" ).replace( rtrim, "$1" );
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
||||||
|
@ -8769,8 +8797,8 @@ jQuery.noConflict = function( deep ) {
|
||||||
};
|
};
|
||||||
|
|
||||||
// Expose jQuery and $ identifiers, even in AMD
|
// Expose jQuery and $ identifiers, even in AMD
|
||||||
// (#7102#comment:10, https://github.com/jquery/jquery/pull/557)
|
// (trac-7102#comment:10, https://github.com/jquery/jquery/pull/557)
|
||||||
// and CommonJS for browser emulators (#13566)
|
// and CommonJS for browser emulators (trac-13566)
|
||||||
if ( typeof noGlobal === "undefined" ) {
|
if ( typeof noGlobal === "undefined" ) {
|
||||||
window.jQuery = window.$ = jQuery;
|
window.jQuery = window.$ = jQuery;
|
||||||
}
|
}
|
|
@ -49,7 +49,7 @@
|
||||||
</main>
|
</main>
|
||||||
|
|
||||||
<link rel="stylesheet" href="{{urlpath}}/vw_static/datatables.css" />
|
<link rel="stylesheet" href="{{urlpath}}/vw_static/datatables.css" />
|
||||||
<script src="{{urlpath}}/vw_static/jquery-3.6.0.slim.js"></script>
|
<script src="{{urlpath}}/vw_static/jquery-3.6.1.slim.js"></script>
|
||||||
<script src="{{urlpath}}/vw_static/datatables.js"></script>
|
<script src="{{urlpath}}/vw_static/datatables.js"></script>
|
||||||
<script>
|
<script>
|
||||||
'use strict';
|
'use strict';
|
||||||
|
|
|
@ -136,7 +136,7 @@
|
||||||
</main>
|
</main>
|
||||||
|
|
||||||
<link rel="stylesheet" href="{{urlpath}}/vw_static/datatables.css" />
|
<link rel="stylesheet" href="{{urlpath}}/vw_static/datatables.css" />
|
||||||
<script src="{{urlpath}}/vw_static/jquery-3.6.0.slim.js"></script>
|
<script src="{{urlpath}}/vw_static/jquery-3.6.1.slim.js"></script>
|
||||||
<script src="{{urlpath}}/vw_static/datatables.js"></script>
|
<script src="{{urlpath}}/vw_static/datatables.js"></script>
|
||||||
<script>
|
<script>
|
||||||
'use strict';
|
'use strict';
|
||||||
|
|
Laden …
In neuem Issue referenzieren