123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254 |
- //ДЗ: Functional OOP
- //Password
- //LoginForm
- //LoginForm Constructor
- //Password Verify
- let wrapper = document.querySelector(".wrapper"); // Сюда буду создавать поле ввода для пароля
- function Password(parent, open){ // Функция конструктор
- let container = document.createElement("div"); // Создаю контейнер для инпутов
- let button = document.createElement("button"); // Создание кнопки
- button.disabled = true; // Отключаю кнопку т.к. при создании формы инпут логина по умолчанию пустой
- let openCheck = open; // Переменная с которой я буду сравнивать открытость текста в поле ввода
- let buildInputs = function(type, innerText) { // Функция для создания одних и тех же инпутов с разными типами
- let input = document.createElement("input");
- let label = document.createElement("label");
- input.type = type;
- label.innerText = innerText;
- label.appendChild(input);
- return label;
- }
- let toggleHiddenPassword = function(type, open) { // Функция для переключения состояния инпута с паролем с видимого на невидимый и переключение чекбокса
- inputPassword.type = type;
- inputCheckbox.checked = open;
- };
- let toggleHiddenCheckPassword = function(check) { // Функция для скрытия повтора пароля если Password в открытом режиме
- if(check) {
- container.removeChild(checkPasswordLabel);
- } else {
- container.insertBefore(checkPasswordLabel, container.children[2]);
- }
- };
- let verifyPassword = function(additional = true) { // Проверка на наличие символов в логине и пароле, если в одном из полей пусто то кнопка disabled
- if(inputLogin.value.length > 0 && inputPassword.value.length > 0 && additional) {
- button.disabled = false;
- } else {
- button.disabled = true;
- }
- }
- container.appendChild(buildInputs("login", "Login")); // Собираю форму ввода
- container.appendChild(buildInputs("password", "Password"));
- container.appendChild(buildInputs("password", "Повторите пароль")).classList.add("check-password"); // Тут добавил класс что бы различать два инпута, type = password, друг от друга
- container.appendChild(buildInputs("checkbox", "Показать пароль"));
- container.appendChild(button).innerText = "Отправить";
- parent.appendChild(container);
- let inputLogin = container.querySelector("input[type='login']"); // Нахожу все инпуты и присваиваю их в переменные для дальнейшей работы с ними
- let inputPassword = container.querySelector("input[type='password']");
- let inputCheckPassword = container.querySelector(".check-password input");
- let checkPasswordLabel = inputCheckPassword.parentElement;
- let inputCheckbox = container.querySelector("input[type='checkbox']");
- open == true ? toggleHiddenPassword("text", true) : toggleHiddenPassword("password", false); // Один раз запускаю функцию toggleHiddenPassword для корректной отрисовки инпутов в зависимости от переданных параметров в конструкторе
- if(open == true) { // Скрываю inputCheckPassword если конструктор вызвали с параметром open = true, то есть когда Password в открытом режиме
- container.removeChild(container.querySelector(".check-password"));
- }
- this.setValue = function(value) {
- inputPassword.value = value;
- };
- this.getValue = function() {
- return inputPassword.value;
- };
- this.setOpen = function(hidden) {
- hidden == true ? toggleHiddenPassword("text", true) : toggleHiddenPassword("password", false);
- openCheck = hidden;
- toggleHiddenCheckPassword(hidden);
- };
- this.getOpen = function() {
- return openCheck;
- };
- container.oninput = (evt) => { // Навешиваю слушатель события на весь контейнер, а не на каждый инпут в отдельности
- if(evt.target.type == "text" || evt.target.type == "password") { // Тут идет проверка что изменения происходят на инпутах типа text или password для передачи value в onChange
- this.onChange(evt.target.value);
- } else { // Если эти изменения в инпуте с другим типом (Остается только чекбокс) то я запускаю setOpen с противоположным значением openCheck, как бы переключаю значение на противоположное
- this.setOpen(!openCheck);
- this.onOpenChange(openCheck);
- }
- if(openCheck == true) { // Тут идет проверка, если Password в открытом режиме то мне не нужно проверять на совпадение value у inputPassword и inputCheckPassword
- verifyPassword();
- } else {
- verifyPassword(inputPassword.value == inputCheckPassword.value);
- }
- };
- };
- let p = new Password(wrapper, true);
- p.onChange = data => console.log(data);
- p.onOpenChange = open => console.log(open);
- p.setValue('qwerty');
- console.log(p.getValue());
- p.setOpen(false);
- console.log(p.getOpen());
- //Form
- //Отображение
- //Sync
- //Validators
- //Many Inputs
- //Validators messages
- //OkButton
- //CancelButton
- let formContainer = document.querySelector(".form-container"); // Контейнер для формы
- function Form(el, data, okCallback, cancelCallback){
- let formBody = document.createElement('div')
- let okButton = document.createElement('button')
- let table = document.createElement("table"); // Создаю таблицу, в ней буду отрисовывать key и value из data
- let copyData = data; // Копия объекта data для возможности перейти к дефолтным значениям
- okButton.innerHTML = 'OK'
- let cancelButton = document.createElement('button')
- cancelButton.innerHTML = 'Cancel'
- formBody.innerHTML = '<h1>тут будет форма после перервы</h1>'
- if (typeof okCallback === 'function'){
- formBody.appendChild(okButton);
- okButton.onclick = (e) => {
- console.log(this)
- this.okCallback(this.data) // Отдаю текущий поредактированный объект data первым параметром в okCallback
- }
- }
- if (typeof cancelCallback === 'function'){
- formBody.appendChild(cancelButton);
- cancelButton.onclick = cancelCallback
- }
- let trCreator = function(key, value, trElement, labelElement, inputElement, inputType) { // Функция для корректной сборки таблицы и расположению в ней key и value
- for(let i = 0; i < 2; i++) {
- let td = document.createElement("td");
- if(i == 0) { // В tr нужно поместить два элемента tb, в первом должен быть label с key внутри, а во втором input, собсна тут я этим и занимаюсь
- labelElement.innerText = key;
- labelElement.htmlFor = key;
- td.appendChild(labelElement);
- } else {
- inputElement.value = value;
- inputElement.id = key;
- inputElement.type = inputType;
- td.appendChild(inputElement);
- }
- trElement.appendChild(td);
- }
- return trElement;
- };
- let inputCreators = {
- String(key, value, oninput){
- let tr = document.createElement("tr");
- let label = document.createElement("label");
- let input = document.createElement("input");
- input.oninput = () => oninput(input.value);
- return trCreator(key, value, tr, label, input, "text");
- },
- Boolean(key, value, oninput){
- let tr = document.createElement("tr");
- let label = document.createElement("label");
- let input = document.createElement("input");
- if(value == true) {
- input.checked = true;
- }
- input.oninput = () => oninput(input.checked);
- return trCreator(key, value, tr, label, input, "checkbox");
- },
- Date(key, value, oninput){
- let tr = document.createElement("tr");
- let label = document.createElement("label");
- let input = document.createElement("input");
- let timespan = value.getTime();
- let dateValue = ((new Date(timespan - value.getTimezoneOffset() * 60 * 1000)).toISOString()).slice(0, -14);
- input.oninput = () => oninput(new Date(input.value));
- return trCreator(key, dateValue, tr, label, input, "date");
- }
- }
- for(let [key, value] of Object.entries(data)) { // Итерирую объект data и создаю для каждой пары ключ-значение input
- let inputCreatorFunction = inputCreators[value.constructor.name];
- let tr = inputCreatorFunction(key, value, (newValue) => {
- if(this.validators[key] != undefined) { // Если this.validator[key] не равен undefined для этого input предусмотрена валидация и поэтому ее нужно запустить
- if(typeof(this.validators[key](newValue, key, data, tr.querySelector(`#${key}`))) == "string") { // Если все это чудо вернуло тип данных который равен "String" то значит поле не прошло валидацию
- let span = document.createElement("span"); // Тут будет лежать текст ошибки
- span.innerText = this.validators[key](newValue, key, data, tr.querySelector(`#${key}`)); // Собсна пишу сам текст ошибки в span
- span.style.position = "absolute"; // Задаю спану absolute что бы табличка не скакала когда я его добавлю в tr
- tr.style.backgroundColor = "red";
- tr.appendChild(span);
- okButton.disabled = true; // Отключаю кнопку okButton если форма не прошла валидацию
- } else {
- tr.style.backgroundColor = "inherit";
- data[key] = newValue;
- if(tr.querySelector("span") != null) { // Тут идет проверка на наличие span с ошибкой, если его нет то удалять не нужно
- tr.removeChild(tr.querySelector("span"));
- okButton.disabled = false; // Включаю кнопку okButton если форма прошла валидацию
- }
- };
- } else {
- data[key] = newValue;
- }
- });
-
- table.appendChild(tr);
- }
- formBody.insertBefore(table, formBody.children[1]);
- el.appendChild(formBody);
- this.okCallback = okCallback
- this.cancelCallback = cancelCallback
- this.data = data
- this.validators = {}
- }
- let form = new Form(formContainer, {
- name: 'Anakin',
- surname: 'Skywalker',
- married: true,
- birthday: new Date((new Date).getTime() - 86400000 * 30*365)
- }, () => console.log('ok'),() => console.log('cancel') )
- form.okCallback = (e) => console.log(e);
- form.validators.surname = (value, key, data, input) => value.length > 2 &&
- value[0].toUpperCase() == value[0] &&
- !value.includes(' ') ? true : 'Wrong name'
- console.log(form)
|