main.js 13 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254
  1. //ДЗ: Functional OOP
  2. //Password
  3. //LoginForm
  4. //LoginForm Constructor
  5. //Password Verify
  6. let wrapper = document.querySelector(".wrapper"); // Сюда буду создавать поле ввода для пароля
  7. function Password(parent, open){ // Функция конструктор
  8. let container = document.createElement("div"); // Создаю контейнер для инпутов
  9. let button = document.createElement("button"); // Создание кнопки
  10. button.disabled = true; // Отключаю кнопку т.к. при создании формы инпут логина по умолчанию пустой
  11. let openCheck = open; // Переменная с которой я буду сравнивать открытость текста в поле ввода
  12. let buildInputs = function(type, innerText) { // Функция для создания одних и тех же инпутов с разными типами
  13. let input = document.createElement("input");
  14. let label = document.createElement("label");
  15. input.type = type;
  16. label.innerText = innerText;
  17. label.appendChild(input);
  18. return label;
  19. }
  20. let toggleHiddenPassword = function(type, open) { // Функция для переключения состояния инпута с паролем с видимого на невидимый и переключение чекбокса
  21. inputPassword.type = type;
  22. inputCheckbox.checked = open;
  23. };
  24. let toggleHiddenCheckPassword = function(check) { // Функция для скрытия повтора пароля если Password в открытом режиме
  25. if(check) {
  26. container.removeChild(checkPasswordLabel);
  27. } else {
  28. container.insertBefore(checkPasswordLabel, container.children[2]);
  29. }
  30. };
  31. let verifyPassword = function(additional = true) { // Проверка на наличие символов в логине и пароле, если в одном из полей пусто то кнопка disabled
  32. if(inputLogin.value.length > 0 && inputPassword.value.length > 0 && additional) {
  33. button.disabled = false;
  34. } else {
  35. button.disabled = true;
  36. }
  37. }
  38. container.appendChild(buildInputs("login", "Login")); // Собираю форму ввода
  39. container.appendChild(buildInputs("password", "Password"));
  40. container.appendChild(buildInputs("password", "Повторите пароль")).classList.add("check-password"); // Тут добавил класс что бы различать два инпута, type = password, друг от друга
  41. container.appendChild(buildInputs("checkbox", "Показать пароль"));
  42. container.appendChild(button).innerText = "Отправить";
  43. parent.appendChild(container);
  44. let inputLogin = container.querySelector("input[type='login']"); // Нахожу все инпуты и присваиваю их в переменные для дальнейшей работы с ними
  45. let inputPassword = container.querySelector("input[type='password']");
  46. let inputCheckPassword = container.querySelector(".check-password input");
  47. let checkPasswordLabel = inputCheckPassword.parentElement;
  48. let inputCheckbox = container.querySelector("input[type='checkbox']");
  49. open == true ? toggleHiddenPassword("text", true) : toggleHiddenPassword("password", false); // Один раз запускаю функцию toggleHiddenPassword для корректной отрисовки инпутов в зависимости от переданных параметров в конструкторе
  50. if(open == true) { // Скрываю inputCheckPassword если конструктор вызвали с параметром open = true, то есть когда Password в открытом режиме
  51. container.removeChild(container.querySelector(".check-password"));
  52. }
  53. this.setValue = function(value) {
  54. inputPassword.value = value;
  55. };
  56. this.getValue = function() {
  57. return inputPassword.value;
  58. };
  59. this.setOpen = function(hidden) {
  60. hidden == true ? toggleHiddenPassword("text", true) : toggleHiddenPassword("password", false);
  61. openCheck = hidden;
  62. toggleHiddenCheckPassword(hidden);
  63. };
  64. this.getOpen = function() {
  65. return openCheck;
  66. };
  67. container.oninput = (evt) => { // Навешиваю слушатель события на весь контейнер, а не на каждый инпут в отдельности
  68. if(evt.target.type == "text" || evt.target.type == "password") { // Тут идет проверка что изменения происходят на инпутах типа text или password для передачи value в onChange
  69. this.onChange(evt.target.value);
  70. } else { // Если эти изменения в инпуте с другим типом (Остается только чекбокс) то я запускаю setOpen с противоположным значением openCheck, как бы переключаю значение на противоположное
  71. this.setOpen(!openCheck);
  72. this.onOpenChange(openCheck);
  73. }
  74. if(openCheck == true) { // Тут идет проверка, если Password в открытом режиме то мне не нужно проверять на совпадение value у inputPassword и inputCheckPassword
  75. verifyPassword();
  76. } else {
  77. verifyPassword(inputPassword.value == inputCheckPassword.value);
  78. }
  79. };
  80. };
  81. let p = new Password(wrapper, true);
  82. p.onChange = data => console.log(data);
  83. p.onOpenChange = open => console.log(open);
  84. p.setValue('qwerty');
  85. console.log(p.getValue());
  86. p.setOpen(false);
  87. console.log(p.getOpen());
  88. //Form
  89. //Отображение
  90. //Sync
  91. //Validators
  92. //Many Inputs
  93. //Validators messages
  94. //OkButton
  95. //CancelButton
  96. let formContainer = document.querySelector(".form-container"); // Контейнер для формы
  97. function Form(el, data, okCallback, cancelCallback){
  98. let formBody = document.createElement('div')
  99. let okButton = document.createElement('button')
  100. let table = document.createElement("table"); // Создаю таблицу, в ней буду отрисовывать key и value из data
  101. let copyData = data; // Копия объекта data для возможности перейти к дефолтным значениям
  102. okButton.innerHTML = 'OK'
  103. let cancelButton = document.createElement('button')
  104. cancelButton.innerHTML = 'Cancel'
  105. formBody.innerHTML = '<h1>тут будет форма после перервы</h1>'
  106. if (typeof okCallback === 'function'){
  107. formBody.appendChild(okButton);
  108. okButton.onclick = (e) => {
  109. console.log(this)
  110. this.okCallback(this.data) // Отдаю текущий поредактированный объект data первым параметром в okCallback
  111. }
  112. }
  113. if (typeof cancelCallback === 'function'){
  114. formBody.appendChild(cancelButton);
  115. cancelButton.onclick = cancelCallback
  116. }
  117. let trCreator = function(key, value, trElement, labelElement, inputElement, inputType) { // Функция для корректной сборки таблицы и расположению в ней key и value
  118. for(let i = 0; i < 2; i++) {
  119. let td = document.createElement("td");
  120. if(i == 0) { // В tr нужно поместить два элемента tb, в первом должен быть label с key внутри, а во втором input, собсна тут я этим и занимаюсь
  121. labelElement.innerText = key;
  122. labelElement.htmlFor = key;
  123. td.appendChild(labelElement);
  124. } else {
  125. inputElement.value = value;
  126. inputElement.id = key;
  127. inputElement.type = inputType;
  128. td.appendChild(inputElement);
  129. }
  130. trElement.appendChild(td);
  131. }
  132. return trElement;
  133. };
  134. let inputCreators = {
  135. String(key, value, oninput){
  136. let tr = document.createElement("tr");
  137. let label = document.createElement("label");
  138. let input = document.createElement("input");
  139. input.oninput = () => oninput(input.value);
  140. return trCreator(key, value, tr, label, input, "text");
  141. },
  142. Boolean(key, value, oninput){
  143. let tr = document.createElement("tr");
  144. let label = document.createElement("label");
  145. let input = document.createElement("input");
  146. if(value == true) {
  147. input.checked = true;
  148. }
  149. input.oninput = () => oninput(input.checked);
  150. return trCreator(key, value, tr, label, input, "checkbox");
  151. },
  152. Date(key, value, oninput){
  153. let tr = document.createElement("tr");
  154. let label = document.createElement("label");
  155. let input = document.createElement("input");
  156. let timespan = value.getTime();
  157. let dateValue = ((new Date(timespan - value.getTimezoneOffset() * 60 * 1000)).toISOString()).slice(0, -14);
  158. input.oninput = () => oninput(new Date(input.value));
  159. return trCreator(key, dateValue, tr, label, input, "date");
  160. }
  161. }
  162. for(let [key, value] of Object.entries(data)) { // Итерирую объект data и создаю для каждой пары ключ-значение input
  163. let inputCreatorFunction = inputCreators[value.constructor.name];
  164. let tr = inputCreatorFunction(key, value, (newValue) => {
  165. if(this.validators[key] != undefined) { // Если this.validator[key] не равен undefined для этого input предусмотрена валидация и поэтому ее нужно запустить
  166. if(typeof(this.validators[key](newValue, key, data, tr.querySelector(`#${key}`))) == "string") { // Если все это чудо вернуло тип данных который равен "String" то значит поле не прошло валидацию
  167. let span = document.createElement("span"); // Тут будет лежать текст ошибки
  168. span.innerText = this.validators[key](newValue, key, data, tr.querySelector(`#${key}`)); // Собсна пишу сам текст ошибки в span
  169. span.style.position = "absolute"; // Задаю спану absolute что бы табличка не скакала когда я его добавлю в tr
  170. tr.style.backgroundColor = "red";
  171. tr.appendChild(span);
  172. okButton.disabled = true; // Отключаю кнопку okButton если форма не прошла валидацию
  173. } else {
  174. tr.style.backgroundColor = "inherit";
  175. data[key] = newValue;
  176. if(tr.querySelector("span") != null) { // Тут идет проверка на наличие span с ошибкой, если его нет то удалять не нужно
  177. tr.removeChild(tr.querySelector("span"));
  178. okButton.disabled = false; // Включаю кнопку okButton если форма прошла валидацию
  179. }
  180. };
  181. } else {
  182. data[key] = newValue;
  183. }
  184. });
  185. table.appendChild(tr);
  186. }
  187. formBody.insertBefore(table, formBody.children[1]);
  188. el.appendChild(formBody);
  189. this.okCallback = okCallback
  190. this.cancelCallback = cancelCallback
  191. this.data = data
  192. this.validators = {}
  193. }
  194. let form = new Form(formContainer, {
  195. name: 'Anakin',
  196. surname: 'Skywalker',
  197. married: true,
  198. birthday: new Date((new Date).getTime() - 86400000 * 30*365)
  199. }, () => console.log('ok'),() => console.log('cancel') )
  200. form.okCallback = (e) => console.log(e);
  201. form.validators.surname = (value, key, data, input) => value.length > 2 &&
  202. value[0].toUpperCase() == value[0] &&
  203. !value.includes(' ') ? true : 'Wrong name'
  204. console.log(form)