// Person Constructor // Переделайте задание createPerson на функцию конструктор Person. // Для этого методы и свойства заносите не в создаваемый объект, а в this внутри конструктора. person_constructor: { function Person(name, surname) { this.name = name; this.surname = surname; this.getFullName = () => { let fullName = this.fatherName ? this.name + ' ' + this.fatherName + ' ' + this.surname : this.name + ' ' + this.surname; return fullName; }; } const a = new Person("Вася", "Пупкин") const b = new Person("Анна", "Иванова") const c = new Person("Елизавета", "Петрова") console.log(a.getFullName()); //Вася Пупкин a.fatherName = 'Иванович'; //Вася Иванович Пупкин console.log(a.getFullName()); console.log(b.getFullName()); //Анна Иванова } // Person Prototype // Переделайте предыдущее задание, вынеся методы в прототип. Для этого вместо присвоения в this занесите их в // объект Person.prototype. После этой переделки все должно работать по старому: person_prototype: { function Person(name, surname) { this.name = name; this.surname = surname; Person.prototype.getFullName = function () { let fullName = this.fatherName ? this.name + ' ' + this.fatherName + ' ' + this.surname : this.name + ' ' + this.surname; return fullName; } } const a = new Person("Вася", "Пупкин"); const b = new Person("Анна", "Иванова"); const c = new Person("Елизавета", "Петрова"); console.log(a.getFullName()); //Вася Пупкин a.fatherName = 'Иванович'; //Вася Иванович Пупкин console.log(a.getFullName()); console.log(b.getFullName()); //Анна Иванова } // Store // Переделайте функцию createStore (та, которая хранилище Redux) на конструктор Store. Прототип не используйте; // оставьте переменные state, cbs и reducer замкнутыми. Соответственно методы subscribe, dispatch и getState // должны быть объявлены внутри функции-конструктора и не могут быть в прототипе. Проверьте переделанный // конструктор на вашем ДЗ по ларьку; store: { function reducer(state, { type, name, amount, money }) { //объект action деструктуризируется на три переменных if (!state) { //начальная уборка в ларьке: return { products: { пиво: { amount: 100, price: 30, }, чипсы: { amount: 100, price: 25, }, сиги: { amount: 100, price: 35, } }, balance: { amount: 0 } } } if (type === 'buy') { //если тип action - КУПИТЬ, то: if (amount > state.products[name].amount) { alert('You have entered more quantity than is available'); return { ...state, } } if (money < amount * state.products[name].price) { alert('You don`t have enought money'); return { ...state, } } if (money > amount * state.products[name].price) { alert('You gave more money'); return { ...state, } } let updatedProducts = state.products let updatedField = updatedProducts[name]; updatedField.amount -= amount; let updatedBalance = state.balance; updatedBalance.amount += +money; return { ...state, //берем все что было из ассортимента products: updatedProducts, //и уменьшаем то, что покупается на количество balance: updatedBalance, } } return state; //если мы не поняли, что от нас просят в `action` - оставляем все как есть } function СreateStore(reducer) { let state = reducer(undefined, {}) //стартовая инициализация состояния, запуск редьюсера со state === undefined let cbs = []; //массив подписчиков this.getState = () => state; //функция, возвращающая переменную из замыкания this.subscribe = cb => (cbs.push(cb), //запоминаем подписчиков в массиве () => cbs = cbs.filter(c => c !== cb)); //возвращаем функцию unsubscribe, которая удаляет подписчика из списка this.dispatch = action => { const newState = reducer(state, action); //пробуем запустить редьюсер if (newState !== state) { //проверяем, смог ли редьюсер обработать action state = newState; //если смог, то обновляем state for (let cb of cbs) cb(); //и запускаем подписчиков } } } const store = new СreateStore(reducer); //запомнит функцию во внутреннем массиве cbs. //она будет запущена при любом успешном dispatch const unsubscribe = store.subscribe(() => console.log(store.getState())); setTimeout(unsubscribe, 10000); //отпишемся через 10 секунд, например const buyAction = (name, amount, money) => ({ type: 'buy', name, amount, money }); store.dispatch(buyAction('пиво', 1, 30)); } // Password // Напишите функцию конструктор Password, которая будет в родительском элементе создавать поле ввода для // пароля и кнопку/иконку/чекбокс, который будет переключать режим просмотра пароля в поле ввода. (видимый // пароль или нет, input type='text' или же input type='password') // Параметры: // parent - родительский элемент // open - стартовое состояние // Методы: // setValue/getValue - задают/читают значения // setOpen/getOpen - задают/читают открытость текста в поле ввода // Колбэки (функции обратного вызова, который возможно, будут заданы снаружи конструктора): // onChange - запускается по событию oninput в поле ввода, передает текст в колбэк // onOpenChange - запускается по изменению состояния открытости пароля password: { function Password(parent, open) { let passInputEl = document.createElement('input'); parent.append(passInputEl); let passVisibilityCheckboxEl = document.createElement('input'); passVisibilityCheckboxEl.type = 'checkbox'; passVisibilityCheckboxEl.checked = open; parent.append(passVisibilityCheckboxEl); if (open) { passInputEl.type = 'text'; } else { passInputEl.type = 'password'; } passVisibilityCheckboxEl.addEventListener('change', (event) => { if (event.currentTarget.checked) { passInputEl.type = 'text'; } else { passInputEl.type = 'password'; } this.onOpenChange(event.currentTarget.checked); }); passInputEl.addEventListener('input', (event) => { this.onChange(event.currentTarget.value); }); this.setValue = (value) => { passInputEl.value = value; } this.getValue = () => { return passInputEl.value; } this.setOpen = (value) => { passVisibilityCheckboxEl.checked = value; } this.getOpen = () => { return passVisibilityCheckboxEl.checked; } } let p = new Password(document.body, 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()); } // LoginForm // С помощью предыдущего кода Password сделайте форму логина, кнопка в которой будет активна только если и // login и пароль не пусты. // "С помощью предыдущего кода" значит что в коде формы логина вы используете объект, сконструированный // конструктором Password - const password = new Password(........) login_form: { let form = document.createElement('form'); document.body.append(form); let loginLabel = document.createElement('label'); loginLabel.innerText = 'Login: '; form.append(loginLabel); let login = new Login(form); let passwordLabel = document.createElement('label'); passwordLabel.innerText = 'Password: '; form.append(passwordLabel); let password = new Password(form, false); let submit = document.createElement('button'); submit.innerText = 'Submit'; form.append(submit); function validateForm() { if (login.getValue() == '' || password.getValue() == '') { submit.disabled = true; } else { submit.disabled = false; } } validateForm(); login.onChange = validateForm; password.onChange = validateForm; function Login(parent) { let loginInputEl = document.createElement('input'); loginInputEl.type = 'text'; parent.append(loginInputEl); loginInputEl.addEventListener('input', (event) => { this.onChange(); }); this.setValue = (value) => { loginInputEl.value = value; } this.getValue = () => { return loginInputEl.value; } } function Password(parent, open) { let passInputEl = document.createElement('input'); parent.append(passInputEl); let passVisibilityCheckboxEl = document.createElement('input'); passVisibilityCheckboxEl.type = 'checkbox'; passVisibilityCheckboxEl.checked = open; parent.append(passVisibilityCheckboxEl); if (open) { passInputEl.type = 'text'; } else { passInputEl.type = 'password'; } passVisibilityCheckboxEl.addEventListener('change', (event) => { if (event.currentTarget.checked) { passInputEl.type = 'text'; } else { passInputEl.type = 'password'; } this.onOpenChange(event.currentTarget.checked); }); passInputEl.addEventListener('input', (event) => { this.onChange(); }); this.setValue = (value) => { passInputEl.value = value; } this.getValue = () => { return passInputEl.value; } this.setOpen = (value) => { passVisibilityCheckboxEl.checked = value; } this.getOpen = () => { return passVisibilityCheckboxEl.checked; } } } // LoginForm Constructor // оформите предыдущую задачу как функцию-конструктор. Продумайте и предусмотрите геттеры, сеттеры и колбэки. login_form_constructor: { function LoginForm() { let form = document.createElement('form'); document.body.append(form); let loginLabel = document.createElement('label'); loginLabel.innerText = 'Login: '; form.append(loginLabel); let login = new Login(form); let passwordLabel = document.createElement('label'); passwordLabel.innerText = 'Password: '; form.append(passwordLabel); let password = new Password(form, false); let submit = document.createElement('button'); submit.innerText = 'Submit'; form.append(submit); this.validateForm = () => { if (login.getValue() == '' || password.getValue() == '') { submit.disabled = true; } else { submit.disabled = false; this.onValidForm(); } } submit.addEventListener('click', (e) => { e.preventDefault(); this.onSubmitForm(); }); this.getLoginValue = () => { return login.getValue(); } this.setLoginValue = (value) => { login.setValue(value); } this.getPasswordValue = () => { return password.getValue(); } this.setPasswordValue = (value) => { password.setValue(value); } this.validateForm(); login.onChange = this.validateForm; password.onChange = this.validateForm; } let loginForm = new LoginForm(); loginForm.onValidForm = () => console.log('Form is valid'); loginForm.onSubmitForm = () => console.log('Form is submitted'); function Login(parent) { let loginInputEl = document.createElement('input'); loginInputEl.type = 'text'; parent.append(loginInputEl); loginInputEl.addEventListener('input', (event) => { this.onChange(); }); this.setValue = (value) => { loginInputEl.value = value; } this.getValue = () => { return loginInputEl.value; } } function Password(parent, open) { let passInputEl = document.createElement('input'); parent.append(passInputEl); let passVisibilityCheckboxEl = document.createElement('input'); passVisibilityCheckboxEl.type = 'checkbox'; passVisibilityCheckboxEl.checked = open; parent.append(passVisibilityCheckboxEl); if (open) { passInputEl.type = 'text'; } else { passInputEl.type = 'password'; } passVisibilityCheckboxEl.addEventListener('change', (event) => { if (event.currentTarget.checked) { passInputEl.type = 'text'; } else { passInputEl.type = 'password'; } this.onOpenChange(event.currentTarget.checked); }); passInputEl.addEventListener('input', (event) => { this.onChange(); }); this.setValue = (value) => { passInputEl.value = value; } this.getValue = () => { return passInputEl.value; } this.setOpen = (value) => { passVisibilityCheckboxEl.checked = value; } this.getOpen = () => { return passVisibilityCheckboxEl.checked; } } } // Password Verify // С помощью Password сделайте пару инпутов, которые проверяют введеный пароль (в двух полях ввода) на // совпадение. Подсвечивайте поля красным цветом/бордером когда пароли не совпадают При открытом пароле в // первом поле ввода (которое реализуется с помощью объекта класса Password второе поле вводы должно пропадать // с экрана Таким образом: // Когда Password в скрытом режиме - появляется второй инпут () с паролем в скрытом режиме // Когда Password в открытом режиме - второй инпут пропадает password_verify: { function PasswordVerify() { let passVerifyTask = document.createElement('div'); document.body.append(passVerifyTask); let password = new Password(passVerifyTask, false); let passwordCheck = new Password(passVerifyTask, false); password.onChange = validatePasswords; passwordCheck.onChange = validatePasswords; function validatePasswords(value) { const isInvalid = password.getIsTouched() && passwordCheck.getIsTouched() && password.getValue() !== passwordCheck.getValue(); password.setIsValid(!isInvalid); passwordCheck.setIsValid(!isInvalid); } password.onOpenChange = (value) => { passwordCheck.setIsHidden(value); } } let passVerify = new PasswordVerify(); function Password(parent, open) { let passInputEl = document.createElement('input'); parent.append(passInputEl); let passVisibilityCheckboxEl = document.createElement('input'); passVisibilityCheckboxEl.type = 'checkbox'; passVisibilityCheckboxEl.checked = open; parent.append(passVisibilityCheckboxEl); let isValid = true; let isTouched = false; let isHidden = false; if (open) { passInputEl.type = 'text'; } else { passInputEl.type = 'password'; } passVisibilityCheckboxEl.addEventListener('change', (event) => { if (event.currentTarget.checked) { passInputEl.type = 'text'; } else { passInputEl.type = 'password'; } this.onOpenChange(event.currentTarget.checked); }); passInputEl.addEventListener('input', (event) => { this.setIsTouched(true); this.onChange(event.currentTarget.value); }); this.getIsHidden = () => { return isHidden; } this.setIsHidden = (value) => { isHidden = value; isHidden ? passInputEl.classList.add('hidden') : passInputEl.classList.remove('hidden'); isHidden ? passVisibilityCheckboxEl.classList.add('hidden') : passVisibilityCheckboxEl.classList.remove('hidden'); } this.getIsTouched = () => { return isTouched; } this.setIsTouched = (value) => { isTouched = value; isTouched ? passInputEl.classList.add('touched') : passInputEl.classList.remove('touched'); } this.setValue = (value) => { passInputEl.value = value; } this.getValue = () => { return passInputEl.value; } this.setOpen = (value) => { passVisibilityCheckboxEl.checked = value; } this.getOpen = () => { return passVisibilityCheckboxEl.checked; } this.getIsValid = () => { return isValid; } this.setIsValid = (value) => { isValid = value; isValid ? passInputEl.classList.remove('invalid') : passInputEl.classList.add('invalid'); } } }