blob: e0b235834a265ba79ea7d514269e2a39d57330f5 [file] [edit]
/*!
* Bootstrap strength.js v6.0.0-alpha1 (https://getbootstrap.com/)
* Copyright 2011-2026 The Bootstrap Authors (https://github.com/twbs/bootstrap/graphs/contributors)
* Licensed under MIT (https://github.com/twbs/bootstrap/blob/main/LICENSE)
*/
import BaseComponent from "./base-component.js";
import EventHandler from "./dom/event-handler.js";
import SelectorEngine from "./dom/selector-engine.js";
//#region js/src/strength.ts
/**
* --------------------------------------------------------------------------
* Bootstrap strength.ts
* Licensed under MIT (https://github.com/twbs/bootstrap/blob/main/LICENSE)
* --------------------------------------------------------------------------
*/
/**
* Constants
*/
const NAME = "strength";
const EVENT_KEY = `.bs.strength`;
const DATA_API_KEY = ".data-api";
const EVENT_STRENGTH_CHANGE = `strengthChange${EVENT_KEY}`;
const SELECTOR_DATA_STRENGTH = "[data-bs-strength]";
const STRENGTH_LEVELS = [
"weak",
"fair",
"good",
"strong"
];
const Default = {
input: null,
minLength: 8,
messages: {
weak: "Weak",
fair: "Fair",
good: "Good",
strong: "Strong"
},
weights: {
minLength: 1,
extraLength: 1,
lowercase: 1,
uppercase: 1,
numbers: 1,
special: 1,
multipleSpecial: 1,
longPassword: 1
},
thresholds: [
2,
4,
6
],
scorer: null
};
const DefaultType = {
input: "(string|element|null)",
minLength: "number",
messages: "object",
weights: "object",
thresholds: "array",
scorer: "(function|null)"
};
/**
* Class definition
*/
var Strength = class extends BaseComponent {
constructor(element, config) {
super(element, config);
this._input = this._getInput();
this._segments = SelectorEngine.find(".strength-segment", this._element);
this._textElement = SelectorEngine.findOne(".strength-text", this._element.parentElement);
this._currentStrength = null;
if (this._input) {
this._addEventListeners();
this._evaluate();
}
}
static get Default() {
return Default;
}
static get DefaultType() {
return DefaultType;
}
static get NAME() {
return NAME;
}
getStrength() {
return this._currentStrength;
}
evaluate() {
this._evaluate();
}
_getInput() {
if (this._config.input) return typeof this._config.input === "string" ? SelectorEngine.findOne(this._config.input) : this._config.input;
const parent = this._element.parentElement;
return SelectorEngine.findOne("input[type=\"password\"]", parent);
}
_addEventListeners() {
EventHandler.on(this._input, "input", () => this._evaluate());
EventHandler.on(this._input, "change", () => this._evaluate());
}
_evaluate() {
const password = this._input.value;
const score = this._calculateScore(password);
const strength = this._scoreToStrength(score);
if (strength !== this._currentStrength) {
this._currentStrength = strength;
this._updateUI(strength);
EventHandler.trigger(this._element, EVENT_STRENGTH_CHANGE, {
strength,
score,
password: password.length > 0 ? "***" : ""
});
}
}
_calculateScore(password) {
if (!password) return 0;
if (typeof this._config.scorer === "function") return this._config.scorer(password);
const { weights } = this._config;
let score = 0;
if (password.length >= this._config.minLength) score += weights.minLength;
if (password.length >= this._config.minLength + 4) score += weights.extraLength;
if (/[a-z]/.test(password)) score += weights.lowercase;
if (/[A-Z]/.test(password)) score += weights.uppercase;
if (/\d/.test(password)) score += weights.numbers;
if (/[!@#$%^&*(),.?":{}|<>]/.test(password)) score += weights.special;
if (/[!@#$%^&*(),.?":{}|<>].*[!@#$%^&*(),.?":{}|<>]/.test(password)) score += weights.multipleSpecial;
if (password.length >= 16) score += weights.longPassword;
return score;
}
_scoreToStrength(score) {
if (score === 0) return null;
const [weak, fair, good] = this._config.thresholds;
if (score <= weak) return "weak";
if (score <= fair) return "fair";
if (score <= good) return "good";
return "strong";
}
_updateUI(strength) {
if (strength) this._element.dataset.bsStrength = strength;
else delete this._element.dataset.bsStrength;
const strengthIndex = strength ? STRENGTH_LEVELS.indexOf(strength) : -1;
for (const [index, segment] of this._segments.entries()) if (index <= strengthIndex) segment.classList.add("active");
else segment.classList.remove("active");
if (this._textElement) if (strength && this._config.messages[strength]) {
this._textElement.textContent = this._config.messages[strength];
this._textElement.dataset.bsStrength = strength;
this._textElement.style.setProperty("--strength-color", `var(--${{
weak: "danger",
fair: "warning",
good: "info",
strong: "success"
}[strength]}-text)`);
} else {
this._textElement.textContent = "";
delete this._textElement.dataset.bsStrength;
}
}
};
/**
* Data API implementation
*/
EventHandler.on(document, `DOMContentLoaded${EVENT_KEY}${DATA_API_KEY}`, () => {
for (const element of SelectorEngine.find(SELECTOR_DATA_STRENGTH)) Strength.getOrCreateInstance(element);
});
//#endregion
export { Strength as default };
//# sourceMappingURL=strength.js.map