script.js 18 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477
  1. // Person Constructor
  2. // Переделайте задание createPerson на функцию конструктор Person.
  3. // Для этого методы и свойства заносите не в создаваемый объект, а в this внутри конструктора.
  4. person_constructor: {
  5. function Person(name, surname) {
  6. this.name = name;
  7. this.surname = surname;
  8. this.getFullName = () => {
  9. let fullName = this.fatherName ? this.name + ' ' + this.fatherName + ' ' + this.surname
  10. : this.name + ' ' + this.surname;
  11. return fullName;
  12. };
  13. }
  14. const a = new Person("Вася", "Пупкин")
  15. const b = new Person("Анна", "Иванова")
  16. const c = new Person("Елизавета", "Петрова")
  17. console.log(a.getFullName()); //Вася Пупкин
  18. a.fatherName = 'Иванович'; //Вася Иванович Пупкин
  19. console.log(a.getFullName());
  20. console.log(b.getFullName()); //Анна Иванова
  21. }
  22. // Person Prototype
  23. // Переделайте предыдущее задание, вынеся методы в прототип. Для этого вместо присвоения в this занесите их в
  24. // объект Person.prototype. После этой переделки все должно работать по старому:
  25. person_prototype: {
  26. function Person(name, surname) {
  27. this.name = name;
  28. this.surname = surname;
  29. Person.prototype.getFullName = function () {
  30. let fullName = this.fatherName ? this.name + ' ' + this.fatherName + ' ' + this.surname
  31. : this.name + ' ' + this.surname;
  32. return fullName;
  33. }
  34. }
  35. const a = new Person("Вася", "Пупкин");
  36. const b = new Person("Анна", "Иванова");
  37. const c = new Person("Елизавета", "Петрова");
  38. console.log(a.getFullName()); //Вася Пупкин
  39. a.fatherName = 'Иванович'; //Вася Иванович Пупкин
  40. console.log(a.getFullName());
  41. console.log(b.getFullName()); //Анна Иванова
  42. }
  43. // Store
  44. // Переделайте функцию createStore (та, которая хранилище Redux) на конструктор Store. Прототип не используйте;
  45. // оставьте переменные state, cbs и reducer замкнутыми. Соответственно методы subscribe, dispatch и getState
  46. // должны быть объявлены внутри функции-конструктора и не могут быть в прототипе. Проверьте переделанный
  47. // конструктор на вашем ДЗ по ларьку;
  48. store: {
  49. function reducer(state, { type, name, amount, money }) { //объект action деструктуризируется на три переменных
  50. if (!state) { //начальная уборка в ларьке:
  51. return {
  52. products: {
  53. пиво: {
  54. amount: 100,
  55. price: 30,
  56. },
  57. чипсы: {
  58. amount: 100,
  59. price: 25,
  60. },
  61. сиги: {
  62. amount: 100,
  63. price: 35,
  64. }
  65. },
  66. balance: {
  67. amount: 0
  68. }
  69. }
  70. }
  71. if (type === 'buy') { //если тип action - КУПИТЬ, то:
  72. if (amount > state.products[name].amount) {
  73. alert('You have entered more quantity than is available');
  74. return {
  75. ...state,
  76. }
  77. }
  78. if (money < amount * state.products[name].price) {
  79. alert('You don`t have enought money');
  80. return {
  81. ...state,
  82. }
  83. }
  84. if (money > amount * state.products[name].price) {
  85. alert('You gave more money');
  86. return {
  87. ...state,
  88. }
  89. }
  90. let updatedProducts = state.products
  91. let updatedField = updatedProducts[name];
  92. updatedField.amount -= amount;
  93. let updatedBalance = state.balance;
  94. updatedBalance.amount += +money;
  95. return {
  96. ...state, //берем все что было из ассортимента
  97. products: updatedProducts, //и уменьшаем то, что покупается на количество
  98. balance: updatedBalance,
  99. }
  100. }
  101. return state; //если мы не поняли, что от нас просят в `action` - оставляем все как есть
  102. }
  103. function СreateStore(reducer) {
  104. let state = reducer(undefined, {}) //стартовая инициализация состояния, запуск редьюсера со state === undefined
  105. let cbs = []; //массив подписчиков
  106. this.getState = () => state; //функция, возвращающая переменную из замыкания
  107. this.subscribe = cb => (cbs.push(cb), //запоминаем подписчиков в массиве
  108. () => cbs = cbs.filter(c => c !== cb)); //возвращаем функцию unsubscribe, которая удаляет подписчика из списка
  109. this.dispatch = action => {
  110. const newState = reducer(state, action); //пробуем запустить редьюсер
  111. if (newState !== state) { //проверяем, смог ли редьюсер обработать action
  112. state = newState; //если смог, то обновляем state
  113. for (let cb of cbs) cb(); //и запускаем подписчиков
  114. }
  115. }
  116. }
  117. const store = new СreateStore(reducer);
  118. //запомнит функцию во внутреннем массиве cbs.
  119. //она будет запущена при любом успешном dispatch
  120. const unsubscribe = store.subscribe(() => console.log(store.getState()));
  121. setTimeout(unsubscribe, 10000); //отпишемся через 10 секунд, например
  122. const buyAction = (name, amount, money) => ({ type: 'buy', name, amount, money });
  123. store.dispatch(buyAction('пиво', 1, 30));
  124. }
  125. // Password
  126. // Напишите функцию конструктор Password, которая будет в родительском элементе создавать поле ввода для
  127. // пароля и кнопку/иконку/чекбокс, который будет переключать режим просмотра пароля в поле ввода. (видимый
  128. // пароль или нет, input type='text' или же input type='password')
  129. // Параметры:
  130. // parent - родительский элемент
  131. // open - стартовое состояние
  132. // Методы:
  133. // setValue/getValue - задают/читают значения
  134. // setOpen/getOpen - задают/читают открытость текста в поле ввода
  135. // Колбэки (функции обратного вызова, который возможно, будут заданы снаружи конструктора):
  136. // onChange - запускается по событию oninput в поле ввода, передает текст в колбэк
  137. // onOpenChange - запускается по изменению состояния открытости пароля
  138. password: {
  139. function Password(parent, open) {
  140. let passInputEl = document.createElement('input');
  141. parent.append(passInputEl);
  142. let passVisibilityCheckboxEl = document.createElement('input');
  143. passVisibilityCheckboxEl.type = 'checkbox';
  144. passVisibilityCheckboxEl.checked = open;
  145. parent.append(passVisibilityCheckboxEl);
  146. if (open) {
  147. passInputEl.type = 'text';
  148. } else {
  149. passInputEl.type = 'password';
  150. }
  151. passVisibilityCheckboxEl.addEventListener('change', (event) => {
  152. if (event.currentTarget.checked) {
  153. passInputEl.type = 'text';
  154. } else {
  155. passInputEl.type = 'password';
  156. }
  157. this.onOpenChange(event.currentTarget.checked);
  158. });
  159. passInputEl.addEventListener('input', (event) => {
  160. this.onChange(event.currentTarget.value);
  161. });
  162. this.setValue = (value) => {
  163. passInputEl.value = value;
  164. }
  165. this.getValue = () => {
  166. return passInputEl.value;
  167. }
  168. this.setOpen = (value) => {
  169. passVisibilityCheckboxEl.checked = value;
  170. }
  171. this.getOpen = () => {
  172. return passVisibilityCheckboxEl.checked;
  173. }
  174. }
  175. let p = new Password(document.body, true);
  176. p.onChange = data => console.log(data);
  177. p.onOpenChange = open => console.log(open);
  178. p.setValue('qwerty');
  179. console.log(p.getValue());
  180. p.setOpen(false);
  181. console.log(p.getOpen());
  182. }
  183. // LoginForm
  184. // С помощью предыдущего кода Password сделайте форму логина, кнопка в которой будет активна только если и
  185. // login и пароль не пусты.
  186. // "С помощью предыдущего кода" значит что в коде формы логина вы используете объект, сконструированный
  187. // конструктором Password - const password = new Password(........)
  188. login_form: {
  189. let form = document.createElement('form');
  190. document.body.append(form);
  191. let loginLabel = document.createElement('label');
  192. loginLabel.innerText = 'Login: ';
  193. form.append(loginLabel);
  194. let login = new Login(form);
  195. let passwordLabel = document.createElement('label');
  196. passwordLabel.innerText = 'Password: ';
  197. form.append(passwordLabel);
  198. let password = new Password(form, false);
  199. let submit = document.createElement('button');
  200. submit.innerText = 'Submit';
  201. form.append(submit);
  202. function validateForm() {
  203. if (login.getValue() == '' || password.getValue() == '') {
  204. submit.disabled = true;
  205. } else {
  206. submit.disabled = false;
  207. }
  208. }
  209. validateForm();
  210. login.onChange = validateForm;
  211. password.onChange = validateForm;
  212. function Login(parent) {
  213. let loginInputEl = document.createElement('input');
  214. loginInputEl.type = 'text';
  215. parent.append(loginInputEl);
  216. loginInputEl.addEventListener('input', (event) => {
  217. this.onChange();
  218. });
  219. this.setValue = (value) => {
  220. loginInputEl.value = value;
  221. }
  222. this.getValue = () => {
  223. return loginInputEl.value;
  224. }
  225. }
  226. function Password(parent, open) {
  227. let passInputEl = document.createElement('input');
  228. parent.append(passInputEl);
  229. let passVisibilityCheckboxEl = document.createElement('input');
  230. passVisibilityCheckboxEl.type = 'checkbox';
  231. passVisibilityCheckboxEl.checked = open;
  232. parent.append(passVisibilityCheckboxEl);
  233. if (open) {
  234. passInputEl.type = 'text';
  235. } else {
  236. passInputEl.type = 'password';
  237. }
  238. passVisibilityCheckboxEl.addEventListener('change', (event) => {
  239. if (event.currentTarget.checked) {
  240. passInputEl.type = 'text';
  241. } else {
  242. passInputEl.type = 'password';
  243. }
  244. this.onOpenChange(event.currentTarget.checked);
  245. });
  246. passInputEl.addEventListener('input', (event) => {
  247. this.onChange();
  248. });
  249. this.setValue = (value) => {
  250. passInputEl.value = value;
  251. }
  252. this.getValue = () => {
  253. return passInputEl.value;
  254. }
  255. this.setOpen = (value) => {
  256. passVisibilityCheckboxEl.checked = value;
  257. }
  258. this.getOpen = () => {
  259. return passVisibilityCheckboxEl.checked;
  260. }
  261. }
  262. }
  263. // LoginForm Constructor
  264. // оформите предыдущую задачу как функцию-конструктор. Продумайте и предусмотрите геттеры, сеттеры и колбэки.
  265. login_form_constructor: {
  266. function LoginForm() {
  267. let form = document.createElement('form');
  268. document.body.append(form);
  269. let loginLabel = document.createElement('label');
  270. loginLabel.innerText = 'Login: ';
  271. form.append(loginLabel);
  272. let login = new Login(form);
  273. let passwordLabel = document.createElement('label');
  274. passwordLabel.innerText = 'Password: ';
  275. form.append(passwordLabel);
  276. let password = new Password(form, false);
  277. let submit = document.createElement('button');
  278. submit.innerText = 'Submit';
  279. form.append(submit);
  280. this.validateForm = () => {
  281. if (login.getValue() == '' || password.getValue() == '') {
  282. submit.disabled = true;
  283. } else {
  284. submit.disabled = false;
  285. this.onValidForm();
  286. }
  287. }
  288. submit.addEventListener('click', (e) => {
  289. e.preventDefault();
  290. this.onSubmitForm();
  291. });
  292. this.getLoginValue = () => {
  293. return login.getValue();
  294. }
  295. this.setLoginValue = (value) => {
  296. login.setValue(value);
  297. }
  298. this.getPasswordValue = () => {
  299. return password.getValue();
  300. }
  301. this.setPasswordValue = (value) => {
  302. password.setValue(value);
  303. }
  304. this.validateForm();
  305. login.onChange = this.validateForm;
  306. password.onChange = this.validateForm;
  307. }
  308. let loginForm = new LoginForm();
  309. loginForm.onValidForm = () => console.log('Form is valid');
  310. loginForm.onSubmitForm = () => console.log('Form is submitted');
  311. function Login(parent) {
  312. let loginInputEl = document.createElement('input');
  313. loginInputEl.type = 'text';
  314. parent.append(loginInputEl);
  315. loginInputEl.addEventListener('input', (event) => {
  316. this.onChange();
  317. });
  318. this.setValue = (value) => {
  319. loginInputEl.value = value;
  320. }
  321. this.getValue = () => {
  322. return loginInputEl.value;
  323. }
  324. }
  325. function Password(parent, open) {
  326. let passInputEl = document.createElement('input');
  327. parent.append(passInputEl);
  328. let passVisibilityCheckboxEl = document.createElement('input');
  329. passVisibilityCheckboxEl.type = 'checkbox';
  330. passVisibilityCheckboxEl.checked = open;
  331. parent.append(passVisibilityCheckboxEl);
  332. if (open) {
  333. passInputEl.type = 'text';
  334. } else {
  335. passInputEl.type = 'password';
  336. }
  337. passVisibilityCheckboxEl.addEventListener('change', (event) => {
  338. if (event.currentTarget.checked) {
  339. passInputEl.type = 'text';
  340. } else {
  341. passInputEl.type = 'password';
  342. }
  343. this.onOpenChange(event.currentTarget.checked);
  344. });
  345. passInputEl.addEventListener('input', (event) => {
  346. this.onChange();
  347. });
  348. this.setValue = (value) => {
  349. passInputEl.value = value;
  350. }
  351. this.getValue = () => {
  352. return passInputEl.value;
  353. }
  354. this.setOpen = (value) => {
  355. passVisibilityCheckboxEl.checked = value;
  356. }
  357. this.getOpen = () => {
  358. return passVisibilityCheckboxEl.checked;
  359. }
  360. }
  361. }
  362. // Password Verify
  363. // С помощью Password сделайте пару инпутов, которые проверяют введеный пароль (в двух полях ввода) на
  364. // совпадение. Подсвечивайте поля красным цветом/бордером когда пароли не совпадают При открытом пароле в
  365. // первом поле ввода (которое реализуется с помощью объекта класса Password второе поле вводы должно пропадать
  366. // с экрана Таким образом:
  367. // Когда Password в скрытом режиме - появляется второй инпут (<input type='password'>) с паролем в скрытом режиме
  368. // Когда Password в открытом режиме - второй инпут пропадает
  369. password_verify: {
  370. function PasswordVerify() {
  371. let passVerifyTask = document.createElement('div');
  372. document.body.append(passVerifyTask);
  373. let password = new Password(passVerifyTask, false);
  374. let passwordCheck = new Password(passVerifyTask, false);
  375. password.onChange = validatePasswords;
  376. passwordCheck.onChange = validatePasswords;
  377. function validatePasswords(value) {
  378. const isInvalid = password.getIsTouched() && passwordCheck.getIsTouched() && password.getValue() !== passwordCheck.getValue();
  379. password.setIsValid(!isInvalid);
  380. passwordCheck.setIsValid(!isInvalid);
  381. }
  382. password.onOpenChange = (value) => {
  383. passwordCheck.setIsHidden(value);
  384. }
  385. }
  386. let passVerify = new PasswordVerify();
  387. function Password(parent, open) {
  388. let passInputEl = document.createElement('input');
  389. parent.append(passInputEl);
  390. let passVisibilityCheckboxEl = document.createElement('input');
  391. passVisibilityCheckboxEl.type = 'checkbox';
  392. passVisibilityCheckboxEl.checked = open;
  393. parent.append(passVisibilityCheckboxEl);
  394. let isValid = true;
  395. let isTouched = false;
  396. let isHidden = false;
  397. if (open) {
  398. passInputEl.type = 'text';
  399. } else {
  400. passInputEl.type = 'password';
  401. }
  402. passVisibilityCheckboxEl.addEventListener('change', (event) => {
  403. if (event.currentTarget.checked) {
  404. passInputEl.type = 'text';
  405. } else {
  406. passInputEl.type = 'password';
  407. }
  408. this.onOpenChange(event.currentTarget.checked);
  409. });
  410. passInputEl.addEventListener('input', (event) => {
  411. this.setIsTouched(true);
  412. this.onChange(event.currentTarget.value);
  413. });
  414. this.getIsHidden = () => {
  415. return isHidden;
  416. }
  417. this.setIsHidden = (value) => {
  418. isHidden = value;
  419. isHidden ? passInputEl.classList.add('hidden') : passInputEl.classList.remove('hidden');
  420. isHidden ? passVisibilityCheckboxEl.classList.add('hidden') : passVisibilityCheckboxEl.classList.remove('hidden');
  421. }
  422. this.getIsTouched = () => {
  423. return isTouched;
  424. }
  425. this.setIsTouched = (value) => {
  426. isTouched = value;
  427. isTouched ? passInputEl.classList.add('touched') : passInputEl.classList.remove('touched');
  428. }
  429. this.setValue = (value) => {
  430. passInputEl.value = value;
  431. }
  432. this.getValue = () => {
  433. return passInputEl.value;
  434. }
  435. this.setOpen = (value) => {
  436. passVisibilityCheckboxEl.checked = value;
  437. }
  438. this.getOpen = () => {
  439. return passVisibilityCheckboxEl.checked;
  440. }
  441. this.getIsValid = () => {
  442. return isValid;
  443. }
  444. this.setIsValid = (value) => {
  445. isValid = value;
  446. isValid ? passInputEl.classList.remove('invalid') : passInputEl.classList.add('invalid');
  447. }
  448. }
  449. }