diff --git a/1-js/3-writing-js/2-coding-style/code-style.svg b/1-js/3-writing-js/2-coding-style/code-style.svg index 71e1ce4a..64fa7c07 100644 --- a/1-js/3-writing-js/2-coding-style/code-style.svg +++ b/1-js/3-writing-js/2-coding-style/code-style.svg @@ -1,8 +1,8 @@ - + code-style.svg - Created with Sketch. + Created with bin/sketchtool. diff --git a/2-ui/5-widgets/4-template-lodash/1-table-template/solution.view/index.html b/2-ui/5-widgets/4-template-lodash/1-table-template/solution.view/index.html index 11e61c9f..e24e7ea1 100755 --- a/2-ui/5-widgets/4-template-lodash/1-table-template/solution.view/index.html +++ b/2-ui/5-widgets/4-template-lodash/1-table-template/solution.view/index.html @@ -2,8 +2,7 @@ - - + - - - -
- - 0 - + -
- - - - - - diff --git a/2-ui/5-widgets/5-custom-events/1-voter-events/solution.view/index.html b/2-ui/5-widgets/5-custom-events/1-voter-events/solution.view/index.html index ba822a6a..6b80f167 100755 --- a/2-ui/5-widgets/5-custom-events/1-voter-events/solution.view/index.html +++ b/2-ui/5-widgets/5-custom-events/1-voter-events/solution.view/index.html @@ -2,7 +2,6 @@ - + + @@ -24,67 +25,14 @@ diff --git a/2-ui/5-widgets/5-custom-events/1-voter-events/solution.view/voter.js b/2-ui/5-widgets/5-custom-events/1-voter-events/solution.view/voter.js new file mode 100644 index 00000000..81a9bfde --- /dev/null +++ b/2-ui/5-widgets/5-custom-events/1-voter-events/solution.view/voter.js @@ -0,0 +1,36 @@ +function Voter(options) { + var elem = options.elem; + + var voteElem = elem.querySelector('.vote'); + + elem.onclick = function(event) { + // сам обработчик не меняет голос, он вызывает функцию + if (event.target.closest('.down')) { + voteDecrease(); + } else if (event.target.closest('.up')) { + voteIncrease(); + } + } + + elem.onmousedown = function() { + return false; + }; + + // ----------- методы ------------- + + function voteDecrease() { + setVote(+voteElem.innerHTML - 1); + } + + function voteIncrease() { + setVote(+voteElem.innerHTML + 1); + } + + function setVote(vote) { + voteElem.innerHTML = +vote; + var widgetEvent = new CustomEvent("change", { bubbles: true, detail: +vote }); + elem.dispatchEvent(widgetEvent); + }; + + this.setVote = setVote; +} diff --git a/2-ui/5-widgets/5-custom-events/1-voter-events/task.md b/2-ui/5-widgets/5-custom-events/1-voter-events/task.md index e55c538b..07a130d9 100644 --- a/2-ui/5-widgets/5-custom-events/1-voter-events/task.md +++ b/2-ui/5-widgets/5-custom-events/1-voter-events/task.md @@ -2,24 +2,25 @@ [importance 5] -Добавьте событие в голосовалку, созданную в задаче [](/task/voter), используя jQuery-механизм генерации событий на объекте. +Добавьте событие в голосовалку, созданную в задаче [](/task/voter), используя механизм генерации событий на объекте. -Пусть каждое изменение голоса сопровождается событием `change`: +Пусть каждое изменение голоса сопровождается событием `change` со свойством `detail`, содержащим обновлённое значение: ```js var voter = new Voter({ - elem: $('#voter'), - value: 5 + elem: document.getElementById('voter') }); -$(voter).on('change', function(e) { - alert(e.value); +voter.setVote(5); + +document.getElementById('voter').addEventListener('change', function(e) { + alert(e.detail); // новое значение голоса }); ``` Все изменения голоса должны производиться централизованно, через метод `setVote`, который и генерирует событие. Результат использования кода выше (планируемый): -[iframe border=1 height=60 src="index.html"]. +[iframe border=1 height=60 src="solution"] Исходный документ возьмите из решения задачи [](/task/voter). \ No newline at end of file diff --git a/2-ui/5-widgets/5-custom-events/2-selectable-list-evented/solution.md b/2-ui/5-widgets/5-custom-events/2-selectable-list-evented/solution.md index f09f45fe..e69de29b 100644 --- a/2-ui/5-widgets/5-custom-events/2-selectable-list-evented/solution.md +++ b/2-ui/5-widgets/5-custom-events/2-selectable-list-evented/solution.md @@ -1,8 +0,0 @@ - - -Обратите внимание: - \ No newline at end of file diff --git a/2-ui/5-widgets/5-custom-events/2-selectable-list-evented/solution.view/index.html b/2-ui/5-widgets/5-custom-events/2-selectable-list-evented/solution.view/index.html index 649ca116..a8153c03 100755 --- a/2-ui/5-widgets/5-custom-events/2-selectable-list-evented/solution.view/index.html +++ b/2-ui/5-widgets/5-custom-events/2-selectable-list-evented/solution.view/index.html @@ -2,22 +2,18 @@ - - + + + Клик на элементе выделяет только его.
-Shift+Клик добавляет/убирает элемент из выделенных.
+Ctrl(Cmd)+Клик добавляет/убирает элемент из выделенных.
+Shift+Клик добавляет промежуток от последнего кликнутого к выделению.
-
-
Выберите
-
    + +
+
diff --git a/2-ui/5-widgets/5-custom-events/3-custom-select/source.view/customselect.css b/2-ui/5-widgets/5-custom-events/3-custom-select/source.view/customselect.css new file mode 100644 index 00000000..ff8ae390 --- /dev/null +++ b/2-ui/5-widgets/5-custom-events/3-custom-select/source.view/customselect.css @@ -0,0 +1,50 @@ +.customselect { + width: 200px; + font-size: 14px; + display: inline-block; +} + +.customselect .title { + height: 20px; + border: 2px groove #ADD8E6; + background: white; + width: 200px; + box-sizing: border-box; + padding: 2px; + line-height: 14px; + cursor: pointer; + text-align: left; +} + +.customselect li { + padding: 2px; + cursor: pointer; +} + +.customselect li:nth-child(even) { + background-color: #f0f8ff; +} + +.customselect li:hover { + background-color: #7fffd4; +} + +.customselect ul { + list-style: none; + margin: 0; + padding: 0; + display: none; + + position: absolute; + z-index: 1000; + background: white; + width: 200px; + border-bottom: 1px solid #add8e6; + border-left: 1px solid #add8e6; + border-right: 1px solid #add8e6; + box-sizing: border-box; +} + +.customselect.open ul { + display: block; +} diff --git a/2-ui/5-widgets/5-custom-events/3-custom-select/source.view/customselect.js b/2-ui/5-widgets/5-custom-events/3-custom-select/source.view/customselect.js new file mode 100644 index 00000000..c6fb05b4 --- /dev/null +++ b/2-ui/5-widgets/5-custom-events/3-custom-select/source.view/customselect.js @@ -0,0 +1 @@ +// ваш код CustomSelect \ No newline at end of file diff --git a/2-ui/5-widgets/5-custom-events/3-custom-select/source.view/index.html b/2-ui/5-widgets/5-custom-events/3-custom-select/source.view/index.html index 826163f7..5119c7ee 100755 --- a/2-ui/5-widgets/5-custom-events/3-custom-select/source.view/index.html +++ b/2-ui/5-widgets/5-custom-events/3-custom-select/source.view/index.html @@ -2,54 +2,51 @@ Селект - + +
Последний результат: ...
- -
-
Выберите
-
    + +
+
-
Выберите
-
    + +
+
- + \ No newline at end of file diff --git a/2-ui/5-widgets/5-custom-events/3-custom-select/task.md b/2-ui/5-widgets/5-custom-events/3-custom-select/task.md index 785c9f8b..49aac1a2 100644 --- a/2-ui/5-widgets/5-custom-events/3-custom-select/task.md +++ b/2-ui/5-widgets/5-custom-events/3-custom-select/task.md @@ -8,12 +8,12 @@ Например: -[iframe src="solution" border="1" height="200" newwin] +[iframe src="solution" height="200"] В примере выше два селекта, чтобы можно было проверить процесс открытия-закрытия. diff --git a/2-ui/5-widgets/5-custom-events/article.md b/2-ui/5-widgets/5-custom-events/article.md index 87b3a24f..ddbdd7c9 100644 --- a/2-ui/5-widgets/5-custom-events/article.md +++ b/2-ui/5-widgets/5-custom-events/article.md @@ -1,6 +1,6 @@ # Коллбэки и события на компонентах -Компоненты, хоть и каждый сам по себе, обычно интегрированы друг с другом. +Компоненты, хоть и каждый сам по себе, обычно как-то общаются с остальной частью страницы Есть несколько способов, при помощи которых компоненты сообщают друг другу о важных событиях, которые в них произошли. @@ -15,8 +15,8 @@ ```js var menu = new Menu({ title: "Сладости", - template: _.template($('#menu-template').html()), - listTemplate: _.template($('#menu-list-template').html()), + template: _.template(document.getElementById('menu-template').innerHTML), + listTemplate: _.template(document.getElementById('menu-list-template').innerHTML, items: { "donut": "Пончик", "cake": "Пирожное", @@ -34,321 +34,84 @@ function showSelected(href) { */!* ``` -В коде меню нужно будет вызывать её, как-то так: +В коде меню нужно будет вызывать её, например так: ```js ... - function onItemClick(e) { - e.preventDefault(); -*!* - var onselect = options.onselect; - if (onselect) { - onselect(e.currentTarget.getAttribute('href').slice(1)); - } -*/!* + function select(link) { + options.onselect(link.getAttribute('href').slice(1)); + ... } ... ``` -Демо: +Полный пример: [codetabs src="menu-callback" height="180"] ## Свои события -Оповещение через коллбэки -- это примерный аналог назначения обработчика через `onсвойство` для DOM-элементов. +Как мы уже знаем, в современных браузерах DOM-элементы могут [генерировать поизвольные события](/dispatch-events) при помощи встроенных методов, а в IE8- это возможно с использованием фреймворка, к примеру, jQuery. -Да, он работает, но чтобы можно было назначать сколько угодно обработчиков в любой момент, нужна полноценная поддержка событий, то есть аналог `addEventListener`. +Воспользуемся ими, чтобы корневой элемент меню генерировал событие, которое мы назовём `select`, при выборе элемента, и передавал в объект события выбранное значение. -Поддержка событий для компонентов будет выглядеть так: +Для этого модифицируем функцию `select`: + +```js +function Menu(options) { + ... + + function select(link) { +*!* + var widgetEvent = new CustomEvent("select", { + bubbles: true, + // detail - стандартное свойство CustomEvent для произвольных данных + detail: link.getAttribute('href').slice(1) + }); + elem.dispatchEvent(widgetEvent); +*/!* + } + + ... +} +``` + +Код, который заинтересован в том, чтобы узнавать, что выбрано в меню, подписывается на событие `select` его корневого элемента: ```js var menu = new Menu(...); -// любой код может подписаться на событие "select" -menu.on("select", function(item) { - // при выборе пункта меню сработает этот обработчик - alert("Выбран элемент " + item); +var elem = menu.getElem(); + +elem.addEventListener('select', function(event) { + alert(event.detail); }); ``` -Код, который заинтересован в том, чтобы узнавать, что происходит с меню, подписывается на нужные события вызовом `menu.on(имя события, обработчик)`. +Вместо `detail` можно было бы выбрать и другое название свойства, но тогда нужно позаботиться о том, чтобы оно не конфликтовало со стандартными. Кроме того, в конструкторе `CustomEvent` разрешено только `detail`, другое свойство понадобилось бы присваивать в отдельной строке. -Далее `Menu` при наступлении события вызывает обработчик методом `trigger`, при необходимости передавая ему важные данные в качестве аргументов, вот так: +Полный пример: -```js -function Menu(options) { - var self = this; - -*!* - // ... при клике на item - сгенерировать событие (trigger) - function onItemClick(e) { - e.preventDefault(); - - self.trigger("select", e.currentTarget.getAttribute('href').slice(1)); - } -*/!* - -} -``` - -Обратим внимание -- события будут генерироваться не на элементе `