Skip to content

Commit cd3e3d4

Browse files
committed
archive
1 parent a0d751f commit cd3e3d4

File tree

758 files changed

+44512
-0
lines changed

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

758 files changed

+44512
-0
lines changed

2-ui/99-ui-misc/02-selection-range/article.md

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -649,3 +649,5 @@ button.onclick = () => {
649649
И пару слов о курсоре. Позиция курсора в редактируемых элементах, таких как `<textarea>`, всегда находится в начале или конце выделения.
650650

651651
Мы можем использовать это, как для того, чтобы получить позицию курсора, так и чтобы переместить его, установив `elem.selectionStart` и `elem.selectionEnd`.
652+
653+
P.S. Если вам нужна поддержка старого IE8-, посмотрите в [архивную статью](info:range-textrange-selection).
Lines changed: 67 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,67 @@
1+
archive:
2+
ref: regexp-anchors
3+
4+
---
5+
6+
# Начало строки ^ и конец $
7+
8+
Знак каретки `pattern:'^'` и доллара `pattern:'$'` имеют в регулярном выражении особый смысл. Их называют "якорями" (anchor - англ.).
9+
10+
Каретка `pattern:^` совпадает в начале текста, а доллар `pattern:$` -- в конце.
11+
12+
**Якоря являются не символами, а проверками.**
13+
14+
До этого мы говорили о регулярных выражениях, которые ищут один или несколько символов. Если совпадение есть -- эти символы включаются в результат.
15+
16+
А якоря -- не такие. Когда поиск ходит до якоря -- он проверяет, есть ли соответствие, если есть -- продолжает идти по шаблону, не прибавляя ничего к результату.
17+
18+
Каретку `pattern:^` обычно используют, чтобы указать, что регулярное выражение необходимо проверить именно с начала текста.
19+
20+
Например, без каретки найдёт все числа:
21+
22+
```js run
23+
var str = '100500 попугаев съели 500100 бананов!';
24+
alert( str.match(/\d+/ig) ); // 100500, 500100 (нашло все числа)
25+
```
26+
27+
А с кареткой -- только первое:
28+
29+
```js run
30+
var str = '100500 попугаев съели 500100 бананов!';
31+
alert( str.match(/^\d+/ig) ); // 100500 (только в начале строки)*!*
32+
```
33+
34+
Знак доллара `pattern:$` используют, чтобы указать, что паттерн должен заканчиваться в конце текста.
35+
36+
Аналогичный пример с долларом для поиска числа в конце:
37+
38+
```js run
39+
var str = '100500 попугаев съели 500100';
40+
alert( str.match(/\d+$/ig) ); // 500100
41+
```
42+
43+
Оба якоря используют одновременно, если требуется, чтобы шаблон охватывал текст с начала и до конца. Обычно это требуется при валидации.
44+
45+
Например, мы хотим проверить, что в переменной `num` хранится именно десятичная дробь.
46+
47+
Ей соответствует регэксп `pattern:\d+\.\d+`. Но простой поиск найдёт дробь в любом тексте:
48+
49+
```js run
50+
var num = "ля-ля 12.34";
51+
alert( num.match(/\d+\.\d+/ig) ); // 12.34
52+
```
53+
54+
Наша же задача -- проверить, что `num` *целиком* соответствует паттерну `pattern:\d+\.\d+`.
55+
56+
Для этого обернём шаблон в якоря `pattern:^...$`:
57+
58+
```js run
59+
var num = "ля-ля 12.34";
60+
alert( num.match(/^\d+\.\d+$/ig) ); // null, не дробь
61+
62+
var num = "12.34";
63+
alert( num.match(/^\d+\.\d+$/ig) ); // 12.34, дробь!
64+
```
65+
66+
Теперь поиск ищет начало текста, за которым идёт число, затем точка, ещё число и конец текста. Это как раз то, что нужно.
67+

99-archive/002-behavior/article.md

Lines changed: 96 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,96 @@
1+
archive:
2+
ref: event-delegation#the-behavior-pattern
3+
4+
---
5+
6+
# Приём проектирования "поведение"
7+
8+
Шаблон проектирования "поведение" (behavior) позволяет задавать хитрые обработчики на элементе *декларативно*, установкой специальных HTML-атрибутов и классов.
9+
10+
## Описание
11+
12+
Приём проектирования "поведение" состоит из двух частей:
13+
14+
1. Элементу ставится атрибут, описывающий его поведение.
15+
2. При помощи делегирования ставится обработчик на документ, который ловит все клики и, если элемент имеет нужный атрибут, производит нужное действие.
16+
17+
## Пример
18+
19+
Например, добавим "поведение", которое всем элементам, у которых стоит атрибут `data-counter`, будет при клике увеличивать значение на `1`:
20+
21+
```html run autorun height=60
22+
Счётчик:
23+
<button data-counter>1</button>
24+
Ещё счётчик:
25+
<button data-counter>2</button>
26+
27+
<script>
28+
document.onclick = function(event) {
29+
if (!event.target.hasAttribute('data-counter')) return;
30+
31+
var counter = event.target;
32+
33+
counter.innerHTML++;
34+
};
35+
</script>
36+
```
37+
38+
Если запустить HTML-код выше, то при клике на каждую кнопку -- её значение будет увеличиваться.
39+
40+
Конечно, нам важны не счётчики, а общий подход, который они демонстрируют.
41+
42+
Элементов `data-counter` может быть сколько угодно. Новые могут добавляться в HTML в любой момент. При помощи делегирования мы, фактически, добавили новый "псевдо-стандартный" атрибут в HTML, который добавляет элементу новую возможность ("поведение").
43+
44+
## Ещё пример
45+
46+
Добавим ещё поведение.
47+
48+
Сделаем так, что при клике на элемент с атрибутом `data-toggle-id` будет скрываться/показываться элемент с заданным `id`:
49+
50+
```html autorun run height=60
51+
<button *!*data-toggle-id="subscribe-mail"*/!*>
52+
Показать форму подписки
53+
</button>
54+
55+
<form id="subscribe-mail" hidden>
56+
Ваша почта: <input type="email">
57+
</form>
58+
59+
<script>
60+
*!*
61+
document.onclick = function(event) {
62+
var target = event.target;
63+
64+
var id = target.getAttribute('data-toggle-id');
65+
if (!id) return;
66+
67+
var elem = document.getElementById(id);
68+
69+
elem.hidden = !elem.hidden;
70+
};
71+
*/!*
72+
</script>
73+
```
74+
75+
Ещё раз заметим, что мы сделали. Теперь для того, чтобы добавить скрытие-раскрытие любому элементу -- даже не надо знать JavaScript, можно просто написать атрибут `data-toggle-id`.
76+
77+
Это бывает очень удобно -- не нужно писать JavaScript-код для каждого элемента, который должен служить такой кнопкой. Просто используем поведение.
78+
79+
Обратите внимание: обработчик поставлен на `document`, клик на любом элементе страницы пройдёт через него, так что поведение определено глобально.
80+
81+
```smart header="Не только атрибут"
82+
Для своих целей мы можем использовать в HTML любые атрибуты, но стандарт рекомендует для своих целей называть атрибуты `data-*`.
83+
84+
В обработчике `document.onclick` мы могли бы проверять не атрибут, а класс или что-то ещё, но с атрибутом -- проще и понятнее всего.
85+
86+
Также для добавления обработчиков на `document` рекомендуется использовать `addEventListener`, чтобы можно было добавить более одного обработчика для типа события.
87+
```
88+
89+
## Итого
90+
91+
Шаблон "поведение" удобен тем, что сколь угодно сложное JavaScript-поведение можно "навесить" на элемент одним лишь атрибутом. А можно -- несколькими атрибутами на связанных элементах.
92+
93+
Здесь мы рассмотрели базовый пример, который можно как угодно модифицировать и масштабировать. Важно не переусердствовать.
94+
95+
Приём разработки "поведение" рекомендуется использовать для расширения возможностей разметки, как альтернативу мини-фрагментам JavaScript.
96+
Lines changed: 28 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,28 @@
1+
# Подсказка
2+
3+
У события клика есть координаты. Проверьте по ним, попал ли клик на заголовок.
4+
5+
Самый глубокий узел на координатах можно получить вызовом [document.elementFromPoint(clientX, clientY)](https://developer.mozilla.org/en/DOM/document.elementFromPoint).
6+
7+
...Но заголовок является текстовым узлом, поэтому эта функция для него работать не будет. Однако это, всё же, можно обойти. Как?
8+
9+
# Подсказка 2
10+
11+
Можно при клике на `LI` сделать временный `SPAN` и переместить в него текстовый узел-заголовок.
12+
13+
После этого проверить, попал ли клик в него и вернуть всё как было.
14+
15+
```js
16+
// 1) заворачиваем текстовый узел в SPAN
17+
18+
// 2) проверяем
19+
var elem = document.elementFromPoint(e.clientX, e.clientY);
20+
var isClickOnTitle = (elem == span);
21+
22+
// 3) возвращаем текстовый узел обратно из SPAN
23+
```
24+
25+
На шаге 3 текстовый узел вынимается обратно из `SPAN`, всё возвращается в исходное состояние.
26+
27+
# Решение
28+
Lines changed: 94 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,94 @@
1+
<!DOCTYPE HTML>
2+
<html>
3+
4+
<head>
5+
<meta charset="utf-8">
6+
<style>
7+
.tree li {
8+
cursor: pointer;
9+
}
10+
</style>
11+
</head>
12+
13+
<body>
14+
15+
<ul class="tree" id="tree">
16+
<li>Животные
17+
<ul>
18+
<li>Млекопитающие
19+
<ul>
20+
<li>Коровы</li>
21+
<li>Ослы</li>
22+
<li>Собаки</li>
23+
<li>Тигры</li>
24+
</ul>
25+
</li>
26+
<li>Другие
27+
<ul>
28+
<li>Змеи</li>
29+
<li>Птицы</li>
30+
<li>Ящерицы</li>
31+
</ul>
32+
</li>
33+
</ul>
34+
</li>
35+
<li>Рыбы
36+
<ul>
37+
<li>Аквариумные
38+
<ul>
39+
<li>Гуппи</li>
40+
<li>Скалярии</li>
41+
</ul>
42+
43+
</li>
44+
<li>Морские
45+
<ul>
46+
<li>Морская форель</li>
47+
</ul>
48+
</li>
49+
</ul>
50+
</li>
51+
</ul>
52+
53+
<script>
54+
var tree = document.getElementById('tree');
55+
56+
/* проверить на попадание события в заголовок LI */
57+
function isOverTitle(evt, li) {
58+
/* обернуть заголовок в span */
59+
var titleWrapper = document.createElement('span');
60+
var titleTextNode = li.firstChild; // <li>TITLE...
61+
li.insertBefore(titleWrapper, titleTextNode); // <li><span></span>TITLE
62+
titleWrapper.appendChild(titleTextNode); // <li><span>TITLE</span>
63+
64+
/* определить, был ли клик по координатам - в SPAN ?*/
65+
var isClickOnTitle = (document.elementFromPoint(evt.clientX, evt.clientY) == titleWrapper);
66+
67+
/* в любом случае вернуть заголовок в текст обратно перед тем как идти дальше */
68+
titleWrapper.removeChild(titleWrapper.firstChild); // <li><span></span>
69+
li.replaceChild(titleTextNode, titleWrapper); // <li>TITLE...
70+
71+
return isClickOnTitle;
72+
}
73+
74+
/* отслеживаем клики на всём дереве */
75+
tree.onclick = function(evt) {
76+
var evt = evt || event;
77+
var target = evt.target || evt.srcElement;
78+
79+
80+
if (!isOverTitle(evt, target)) {
81+
return; // клик не на заголовке
82+
}
83+
84+
/* раскрыть-закрыть детей */
85+
var node = target.getElementsByTagName('ul')[0];
86+
if (!node) return; // нет детей
87+
88+
node.style.display = node.style.display ? '' : 'none';
89+
}
90+
</script>
91+
92+
</body>
93+
94+
</html>
Lines changed: 70 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,70 @@
1+
<!DOCTYPE HTML>
2+
<html>
3+
4+
<head>
5+
<meta charset="utf-8">
6+
<style>
7+
.tree li {
8+
cursor: pointer;
9+
}
10+
</style>
11+
</head>
12+
13+
<body>
14+
15+
<ul class="tree" id="tree">
16+
<li>Животные
17+
<ul>
18+
<li>Млекопитающие
19+
<ul>
20+
<li>Коровы</li>
21+
<li>Ослы</li>
22+
<li>Собаки</li>
23+
<li>Тигры</li>
24+
</ul>
25+
</li>
26+
<li>Другие
27+
<ul>
28+
<li>Змеи</li>
29+
<li>Птицы</li>
30+
<li>Ящерицы</li>
31+
</ul>
32+
</li>
33+
</ul>
34+
</li>
35+
<li>Рыбы
36+
<ul>
37+
<li>Аквариумные
38+
<ul>
39+
<li>Гуппи</li>
40+
<li>Скалярии</li>
41+
</ul>
42+
43+
</li>
44+
<li>Морские
45+
<ul>
46+
<li>Морская форель</li>
47+
</ul>
48+
</li>
49+
</ul>
50+
</li>
51+
</ul>
52+
53+
<script>
54+
var tree = document.getElementById('tree');
55+
56+
tree.onclick = function(evt) {
57+
var evt = evt || event;
58+
var target = evt.target || evt.srcElement;
59+
60+
/* раскрыть-закрыть детей */
61+
var node = target.getElementsByTagName('ul')[0];
62+
if (!node) return; // нет детей
63+
64+
node.style.display = node.style.display ? '' : 'none';
65+
}
66+
</script>
67+
68+
</body>
69+
70+
</html>

0 commit comments

Comments
 (0)