UNPKG

bootstrap-italia

Version:

Bootstrap Italia è un tema Bootstrap 5 per la creazione di applicazioni web nel pieno rispetto delle linee guida di design per i siti internet e i servizi digitali della PA

432 lines (365 loc) 12.8 kB
import BaseComponent from 'bootstrap/js/src/base-component'; import EventHandler from 'bootstrap/js/src/dom/event-handler'; import SelectorEngine from 'bootstrap/js/src/dom/selector-engine'; import Manipulator from 'bootstrap/js/src/dom/manipulator'; import InputLabel from './input-label.js'; const NAME = 'inputpassword'; const DATA_KEY = 'bs.inputpassword'; const EVENT_KEY = `.${DATA_KEY}`; const DATA_API_KEY = '.data-api'; const Default = { shortPass: 'Password molto debole', badPass: 'Password debole', goodPass: 'Password sicura', strongPass: 'Password molto sicura', enterPass: 'Inserisci almeno 8 caratteri e una lettera maiuscola', alertCaps: 'CAPS LOCK inserito', showText: true, minimumLength: 4, }; const EVENT_CLICK = `click${EVENT_KEY}`; const EVENT_KEYUP = `keyup${EVENT_KEY}`; const EVENT_KEYDOWN = `keydown${EVENT_KEY}`; const EVENT_KEYPRESS = `keypress${EVENT_KEY}`; const EVENT_SCORE = `score${EVENT_KEY}`; const EVENT_TEXT = `text${EVENT_KEY}`; const EVENT_CLICK_DATA_API = `click${EVENT_KEY}${DATA_API_KEY}`; const EVENT_MOUSEDOWN_DATA_API = `mousedown${EVENT_KEY}${DATA_API_KEY}`; const EVENT_KEYUP_DATA_API = `keyup${EVENT_KEY}${DATA_API_KEY}`; const CLASS_NAME_PASSWORD = 'input-password'; //const CLASS_NAME_METER = 'input-password-strength-meter' const CLASS_NAME_SHOW = 'show'; const SELECTOR_PASSWORD = 'input[data-bs-input][type="password"]'; const SELECTOR_BTN_SHOW_PWD = '.password-icon'; const SELECTOR_METER = '.password-strength-meter'; const SELECTOR_METER_GRAYBAR = '.password-meter'; const SELECTOR_METER_COLBAR = '.progress-bar'; const SELECTOR_CAPS = '.password-caps'; const SELECTOR_TEXT = '.form-text'; class InputPassword extends BaseComponent { constructor(element, config) { super(element); this._config = this._getConfig(config); this._isCustom = this._element.classList.contains(CLASS_NAME_PASSWORD); this._meter = this._element.parentNode.querySelector(SELECTOR_METER); this._isShiftPressed = false; this._isCapsOn = false; this._grayBarElement = null; this._colorBarElement = null; this._textElement = null; this._capsElement = null; this._showPwdElement = null; this._text = {}; this._label = new InputLabel(element); this._init(); this._bindEvents(); } // Getters static get NAME() { return NAME } // Public // Private _getConfig(config) { config = { ...Default, ...Manipulator.getDataAttributes(this._element), ...(typeof config === 'object' ? config : {}), }; return config } _init() { if (this._meter) { /*this._grayBarElement = document.createElement('div') this._grayBarElement.classList.add('password-meter', 'progress', 'rounded-0', 'position-absolute') this._grayBarElement.innerHTML = `<div class="row position-absolute w-100 m-0"> <div class="col-3 border-start border-end border-white"></div> <div class="col-3 border-start border-end border-white"></div> <div class="col-3 border-start border-end border-white"></div> <div class="col-3 border-start border-end border-white"></div> </div>` this._colorBarElement = document.createElement('div') this._colorBarElement.classList.add('progress-bar') this._colorBarElement.setAttribute('role', 'progressbar') this._colorBarElement.setAttribute('aria-valuenow', '0') this._colorBarElement.setAttribute('aria-valuemin', '0') this._colorBarElement.setAttribute('aria-valuemax', '100') const wrapper = document.createElement('div') wrapper.classList.add('password-strength-meter') this._grayBarElement.appendChild(this._colorBarElement) if (this._config.showText) { this._textElement = document.createElement('small') this._textElement.classList.add('form-text', 'text-muted') this._textElement.innerHTML = this._config.enterPass wrapper.appendChild(this._textElement) } wrapper.appendChild(this._grayBarElement) this._element.parentNode.insertBefore(wrapper, this._element.nextSibling)*/ this._grayBarElement = this._meter.querySelector(SELECTOR_METER_GRAYBAR); this._colorBarElement = this._meter.querySelector(SELECTOR_METER_COLBAR); this._textElement = this._meter.querySelector(SELECTOR_TEXT); if (this._textElement) { this._config = Object.assign({}, this._config, { ...Manipulator.getDataAttributes(this._textElement) }, { enterPass: this._textElement.innerText }); } } if (this._isCustom) { /*this._capsElement = document.createElement('small') this._capsElement.style.display = 'none' this._capsElement.classList.add('password-caps', 'form-text', 'text-warning', 'position-absolute', 'bg-white', 'w-100') this._capsElement.innerHTML = this._config.alertCaps this._element.parentNode.appendChild(this._capsElement)*/ this._capsElement = this._element.parentNode.querySelector(SELECTOR_CAPS); } this._showPwdElement = SelectorEngine.findOne(SELECTOR_BTN_SHOW_PWD, this._element.parentNode); } _bindEvents() { if (this._meter) { EventHandler.on(this._element, EVENT_KEYUP, () => this._checkPassword()); } if (this._isCustom) { EventHandler.on(this._element, EVENT_KEYDOWN, (evt) => { if (evt.key === 'Shift') { this._isShiftPressed = true; } }); EventHandler.on(this._element, EVENT_KEYUP, (evt) => { if (evt.key === 'Shift') { this._isShiftPressed = false; } if (evt.key === 'CapsLock') { this._isCapsOn = !this._isCapsOn; if (this._isCapsOn) { this._showCapsMsg(); } else { this._hideCapsMsg(); } } }); EventHandler.on(this._element, EVENT_KEYPRESS, (evt) => { const matches = evt.key.match(/[A-Z]$/) || []; if (matches.length > 0 && !this._isShiftPressed) { this._isCapsOn = true; this._showCapsMsg(); } else if (this._isCapsOn) { this._isCapsOn = false; this._hideCapsMsg(); } }); } if (this._showPwdElement) { EventHandler.on(this._showPwdElement, EVENT_CLICK, () => this._toggleShowPassword()); } } _showCapsMsg() { if (this._capsElement) { this._capsElement.classList.add(CLASS_NAME_SHOW); } } _hideCapsMsg() { if (this._capsElement) { this._capsElement.classList.remove(CLASS_NAME_SHOW); } } _toggleShowPassword() { const toShow = this._element.getAttribute('type') === 'password'; SelectorEngine.find('[class^="password-icon"]', this._showPwdElement).forEach((icon) => icon.classList.toggle('d-none')); if (toShow) { this._element.setAttribute('type', 'text'); } else { this._element.setAttribute('type', 'password'); } } _checkPassword() { const score = this._calculateScore(this._element.value); const perc = score < 0 ? 0 : score; this._colorBarElement.classList.forEach((className) => { if (className.match(/(^|\s)bg-\S+/g)) { this._colorBarElement.classList.remove(className); } }); this._colorBarElement.classList.add('bg-' + this._scoreColor(score)); this._colorBarElement.style.width = perc + '%'; this._colorBarElement.setAttribute('aria-valuenow', perc); EventHandler.trigger(this._element, EVENT_SCORE); if (this._textElement) { let text = this._scoreText(score); if (this._element.value.length === 0 && score <= 0) { text = this._config.enterPass; } if (this._textElement.innerHTML.search(text) === -1) { this._textElement.innerHTML = text; this._textElement.classList.forEach((className) => { if (className.match(/(^|\s)text-\S+/g)) { this._textElement.classList.remove(className); } }); this._textElement.classList.add('text-' + this._scoreColor(score)); EventHandler.trigger(this._element, EVENT_TEXT); } } } /** * Returns strings based on the score given. * * @param int score Score base. * @return string */ _scoreText(score) { if (score === -1) { return this._config.shortPass } score = score < 0 ? 0 : score; if (score < 26) { return this._config.shortPass } if (score < 51) { return this._config.badPass } if (score < 76) { return this._config.goodPass } return this._config.strongPass } _scoreColor(score) { if (score === -1) { return 'danger' } if (score === -2) { return 'muted' } score = score < 0 ? 0 : score; if (score < 26) { return 'danger' } if (score < 51) { return 'warning' } if (score < 76) { return 'success' } return 'success' } /** * Returns a value between -1 and 100 to score * the user's password. * * @param string password The password to be checked. * @return int */ _calculateScore(password) { var score = 0; // empty password if (password.trim().length === 0) { return -2 } // password < this._config.minimumLength if (password.length < this._config.minimumLength) { return -1 } // password length score += password.length * 4; score += this._checkRepetition(1, password).length - password.length; score += this._checkRepetition(2, password).length - password.length; score += this._checkRepetition(3, password).length - password.length; score += this._checkRepetition(4, password).length - password.length; // password has 3 numbers if (password.match(/(.*[0-9].*[0-9].*[0-9])/)) { score += 5; } // password has at least 2 sybols var symbols = '.*[!,@,#,$,%,^,&,*,?,_,~]'; symbols = new RegExp('(' + symbols + symbols + ')'); if (password.match(symbols)) { score += 5; } // password has Upper and Lower chars if (password.match(/([a-z].*[A-Z])|([A-Z].*[a-z])/)) { score += 10; } // password has number and chars if (password.match(/([a-zA-Z])/) && password.match(/([0-9])/)) { score += 15; } // password has number and symbol if (password.match(/([!,@,#,$,%,^,&,*,?,_,~])/) && password.match(/([0-9])/)) { score += 15; } // password has char and symbol if (password.match(/([!,@,#,$,%,^,&,*,?,_,~])/) && password.match(/([a-zA-Z])/)) { score += 15; } // password is just numbers or chars if (password.match(/^\w+$/) || password.match(/^\d+$/)) { score -= 10; } if (score > 100) { score = 100; } if (score < 0) { score = 0; } return score } /** * Checks for repetition of characters in * a string * * @param int rLen Repetition length. * @param string str The string to be checked. * @return string */ _checkRepetition(rLen, str) { var res = '', repeated = false; for (var i = 0; i < str.length; i++) { repeated = true; for (var j = 0; j < rLen && j + i + rLen < str.length; j++) { repeated = repeated && str.charAt(j + i) === str.charAt(j + i + rLen); } if (j < rLen) { repeated = false; } if (repeated) { i += rLen - 1; repeated = false; } else { res += str.charAt(i); } } return res } } /** * ------------------------------------------------------------------------ * Data Api implementation * ------------------------------------------------------------------------ */ /*const inputs = SelectorEngine.find(SELECTOR_PASSWORD) inputs.forEach((input) => { InputPassword.getOrCreateInstance(input) })*/ const createInput = (element) => { if (element && element.matches(SELECTOR_PASSWORD)) { return InputPassword.getOrCreateInstance(element) } return null }; EventHandler.on(document, EVENT_MOUSEDOWN_DATA_API, SELECTOR_PASSWORD + ', label', function () { const target = InputLabel.getInputFromLabel(this) || this; createInput(target); }); EventHandler.on(document, EVENT_KEYUP_DATA_API, SELECTOR_PASSWORD + ', label', function () { const target = InputLabel.getInputFromLabel(this) || this; const element = createInput(target); if (element && element._label) { element._label._labelOut(); } }); EventHandler.on(document, EVENT_CLICK_DATA_API, SELECTOR_BTN_SHOW_PWD, function () { const target = this.parentNode && this.parentNode.querySelector(SELECTOR_PASSWORD); if (target) { InputPassword.getOrCreateInstance(target); } }); export { InputPassword as default }; //# sourceMappingURL=input-password.js.map