Skip to content

Commit bd1d5e4

Browse files
committed
renovations
1 parent 11f2d73 commit bd1d5e4

23 files changed

Lines changed: 803 additions & 947 deletions

File tree

2-ui/3-event-details/3-mousemove-mouseover-mouseout-mouseenter-mouseleave/2-hoverintent/task.md

Lines changed: 3 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -4,13 +4,11 @@
44

55
Нужно написать функцию, которая показывает подсказку при *наведении* на элемент, но не при *быстром проходе* над ним.
66

7-
То есть, если посетитель именно навёл курсор мыши на элемент и почти остановился -- подсказку показать, а если быстро провёл над ним, то не надо (зачем излишнее мигание?).
7+
То есть, если посетитель именно навёл курсор мыши на элемент и почти остановился -- подсказку показать, а если быстро провёл над ним, то не надо, зачем излишнее мигание?
88

99
Технически -- можно измерять скорость движения мыши над элементом, если она маленькая, то считаем, что это "наведение на элемент" (показать подсказку), если большая -- "быстрый проход мимо элемента" (не показывать).
1010

11-
Задача -- сделать универсальный код, который отслеживает "наведение на элемент".
12-
13-
Пусть это будет объект `new HoverIntent(options)`, который при создании принимает `options`:
11+
Реализуйте это через универсальный объект `new HoverIntent(options)`, с параметрами `options`:
1412
<ul>
1513
<li>`elem` -- элемент, наведение на который нужно отслеживать.</li>
1614
<li>`over` -- функция-обработчик наведения на элемент.</li>
@@ -19,10 +17,6 @@
1917

2018
Пример использования такого объекта для подсказки:
2119
```js
22-
function HoverIntent(options) {
23-
//... ваш код ...
24-
}
25-
2620
// образец подсказки
2721
var tooltip = document.createElement('div');
2822
tooltip.className = "tooltip";
@@ -48,6 +42,6 @@ new HoverIntent({
4842

4943
Если провести мышкой над "часиками" быстро, то ничего не будет, а если медленно или остановиться на них, то появится подсказка.
5044

51-
Обратите внимание -- подсказка не "мигает"" при проходе мыши внутри "часиков", по подэлементам.
45+
Обратите внимание -- подсказка не "мигает" при проходе мыши внутри "часиков", по подэлементам.
5246

5347

3-more/7-frames-and-windows/1-window-open/article.md renamed to 3-more/5-frames-and-windows/1-window-open/article.md

Lines changed: 108 additions & 72 deletions
Large diffs are not rendered by default.
Lines changed: 160 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,160 @@
1+
# Окно внутри ифрейма
2+
3+
Элемент `iframe` является обычным узлом DOM, как и любой другой. Существенное отличие -- в том, что с ним связан объект `window` внутреннего окна. Он доступен по ссылке `iframe.contentWindow`.
4+
5+
[cut]
6+
7+
Таким образом, `iframe.contentWindow.document` будет внутренним документом, `iframe.contentWindow.document.body` -- его `<body>` и так далее.
8+
9+
[smart header="Когда-то..."]
10+
В старых браузерах использовались другие свойства, такие как `iframe.contentDocument` и даже `iframe.document`, но они давно не нужны.
11+
[/smart]
12+
13+
## Переход внутрь ифрейма
14+
15+
В примере ниже JavaScript получает документ внутри ифрейма и модифицирует его:
16+
17+
```html
18+
<!--+ run height=100 -->
19+
<iframe src="javascript:'тест'" style="height:60px"></iframe>
20+
21+
<script>
22+
var iframe = document.getElementsByTagName('iframe')[0];
23+
*!*
24+
var iframeDoc = iframe.contentWindow.document;
25+
*/!*
26+
iframeDoc.body.style.backgroundColor = 'green';
27+
</script>
28+
```
29+
30+
[smart header="src='javascript:...'"]
31+
Атрибут `src` может использовать протокол `javascript:...`. При этом код выполняется и его результат будет содержимым ифрейма. Этот способ описан в стандарте и поддерживается всеми браузерами.
32+
33+
Атрибут `src` является обязательным, и его отсутствие может привести к проблемам, вплоть до игнорирования ифрейма браузером.
34+
35+
Чтобы ничего не загружать в ифрейм, можно указать `src="javascript:''"`.
36+
[/smart]
37+
38+
## Кросс-доменность: ограничение доступа к окну
39+
40+
Элемент `<iframe>` является "двуличным". С одной стороны, это обычный узел DOM, с другой -- внутри находится окно, которое может иметь совершенно другой URL, содержать независимый документ из другого источника.
41+
42+
Внешний документ имеет полный доступ к `<iframe>` как к DOM-узлу. А вот к окну -- если они с одного источника.
43+
44+
Это приводит к забавным последствиям. Например, мы можем повесить обработчик `iframe.onload`, чтобы узнать о загрузке `<iframe>`, а вот на `iframe.contentWindow.onload` -- лишь в случае, если окно с того же источника.
45+
46+
```html
47+
<!--+ run height=120 -->
48+
<iframe src="http://example.com" style="height:100px"></iframe>
49+
50+
<script>
51+
var iframe = document.getElementsByTagName('iframe')[0];
52+
53+
// сработает
54+
iframe.onload = function() { alert("iframe onload"); }
55+
56+
// не сработает
57+
iframe.contentWindow.onload = function() { alert("contentWindow onload"); }
58+
</script>
59+
```
60+
61+
Если бы в примере выше `<iframe src>` был с текущего сайта, то оба обработчика сработали бы.
62+
63+
## Иерархия window.frames
64+
65+
Альтернативный способ доступа к окну ифрейма -- это получить его из коллекции `window.frames`.
66+
67+
Есть два способа доступа:
68+
<ol>
69+
<li>`window.frames[0]` -- доступ по номеру.</li>
70+
<li>`window.frames.iframeName` -- доступ по `name` ифрейма.</li>
71+
</ol>
72+
73+
Обратим внимание: в коллекции хранится именно окно (`contentWindow`), а не DOM-элемент.
74+
75+
Демонстрация всех способов доступа к окну:
76+
77+
```html
78+
<!--+ run -->
79+
<iframe src="javascript:''" style="height:80px" name="i"></iframe>
80+
81+
<script>
82+
var iframeTag = document.body.children[0];
83+
84+
var iframeWindow = iframe.contentWindow; // окно из тега
85+
86+
alert(frames[0] === iframeWindow); // true, окно из коллекции frames
87+
alert(frames.i == iframeWindow); // true, окно из frames по имени
88+
</script>
89+
```
90+
91+
Внутри ифрейма могут быть свои вложенные ифреймы. Всё это вместе образует иерархию.
92+
93+
Ссылки для навигации по ней:
94+
95+
<ul>
96+
<li>`window.frames` -- коллекция "детей" (вложенных ифреймов)</li>
97+
<li>`window.parent` -- содержит ссылку на родительское окно, позволяет обратиться к нему из ифрейма.
98+
99+
Всегда верно:
100+
101+
```js
102+
// (из окна со фреймом)
103+
window.frames[0].parent === window; // true
104+
```
105+
106+
</li>
107+
<li>`window.top` -- содержит ссылку на самое верхнее окно (вершину иерархии).
108+
109+
Всегда верно (в предположении, что вложенные фреймы существуют):
110+
111+
```js
112+
window.frames[0].frames[0].frames[0].top === window
113+
```
114+
115+
</li>
116+
</ul>
117+
118+
**Свойство `top` позволяет легко проверить, во фрейме ли находится текущий документ:**
119+
120+
```js
121+
//+ run
122+
if (window == top) {
123+
alert('Этот скрипт является окном верхнего уровня в браузере');
124+
} else {
125+
alert('Этот скрипт исполняется во фрейме!');
126+
}
127+
```
128+
129+
## Песочница sandbox
130+
131+
Атрибут `sandbox` позволяет построить "песочницу" вокруг ифрейма, запретив ему выполнять ряд действий.
132+
133+
Наличие атрибута `sandbox`:
134+
<ul>
135+
<li>Заставляет браузер считать ифрейм загруженным с другого источника, так что он и внешнее окно больше не могут обращаться к переменным друг друга.</li>
136+
<li>Отключает формы и скрипты в ифрейме.</li>
137+
<li>Запрещает менять `parent.location` из ифрейма.</li>
138+
</ul>
139+
140+
Пример ниже загружает в `<iframe sandbox>` документ с JavaScript и формой. Ни то ни другое не сработает:
141+
142+
[codetabs src="sandbox"]
143+
144+
Если у атрибута `sandbox` нет значения, то браузер применяет максимум ограничений.
145+
146+
Атрибут `sandbox` может содержать через пробел список ограничений, которые не нужны:
147+
<dl>
148+
<dt>allow-same-origin</dt>
149+
<dd>Браузер может не считать документ в ифрейме пришедшим с другого же домена. Если ифрейм *и так* с другого домена, то ничего не меняется.</dd>
150+
<dt>allow-top-navigation</dt>
151+
<dd>Разрешает ифрейму менять `parent.location`.</dd>
152+
<dt>allow-forms</dt>
153+
<dd>Разрешает отправлять формы из `iframe`.</dd>
154+
<dt>allow-scripts</dt>
155+
<dd>Разрешает выполнение скриптов из ифрейма. Но скриптам, всё же, будет запрещено открывать попапы.</dd>
156+
</dl>
157+
158+
[smart]
159+
Цель атрибута `sandbox` -- наложить дополнительные ограничения. Он не может снять уже существующие, в частности, убрать ограничения безопасности, если ифрейм с другого источника.
160+
[/smart]
Lines changed: 11 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,11 @@
1+
<!doctype html>
2+
<html>
3+
<head>
4+
<meta charset="UTF-8">
5+
</head>
6+
<body>
7+
8+
<iframe sandbox src="sandboxed.html"></iframe>
9+
10+
</body>
11+
</html>
Lines changed: 18 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,18 @@
1+
<!doctype html>
2+
<html>
3+
<head>
4+
<meta charset="UTF-8">
5+
</head>
6+
<body>
7+
8+
<script>
9+
alert(1);
10+
</script>
11+
12+
<form action="http://google.ru">
13+
<input type="text">
14+
<input type="submit" value="Отправить форму на http://google.ru">
15+
</form>
16+
17+
</body>
18+
</html>
Lines changed: 137 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,137 @@
1+
# Кросс-доменные ограничения и их обход
2+
3+
Ограничение "Same Origin" ("тот же источник") ограничивает доступ окон и фреймов друг к другу, а также влияет на AJAX-запросы к серверу.
4+
5+
Причина, по которой оно существует -- безопасность. Если есть два окна, в одном из которых `vasya-pupkin.com`, а в другом `gmail.com`, то мы бы не хотели, чтобы скрипт из первого мог читать нашу почту.
6+
7+
Сама концепция проста, но есть много важных исключений и особенностей, которые нужно знать для полного понимания этого правила.
8+
[cut]
9+
10+
## Концепция Same Origin [#same-origin]
11+
12+
Два URL считаются имеющим один источник ("same origin"), если у них одинаковый протокол, домен и порт.
13+
14+
Эти URL имеют один источник:
15+
<ul>
16+
<li>`http://site.com`</li>
17+
<li>`http://site.com`/</li>
18+
<li>`http://site.com/my/page.html`</li>
19+
</ul>
20+
21+
А вот эти -- все из других источников:
22+
<ul>
23+
<li>http://<span style="color:red;font-weight:bold">www.</span>site.com (другой домен)</li>
24+
<li>http://site.<span style="color:red;font-weight:bold">org</span> (другой домен)</li>
25+
<li>http<span style="color:red; font-weight:bold">s</span>://site.com (другой протокол)</li>
26+
<li>http://site.com<span style="color:red; font-weight:bold">:8080</span> (другой порт)</li>
27+
</ul>
28+
29+
Существует ряд исключений, позволяющих-таки окнам с разных доменов обмениваться информацией, но прямой вызов методов друг друга и чтение свойств запрещены.
30+
31+
## В действии
32+
33+
Если одно окно попытается обратиться к другому, то браузер проверит, из одного ли они источника. Если нет -- доступ будет запрещён.
34+
35+
Например:
36+
37+
```html
38+
<!--+ run -->
39+
<iframe src="http://example.com"></iframe>
40+
41+
<script>
42+
var iframe = document.body.children[0];
43+
44+
iframe.onload = function() {
45+
try {
46+
alert(iframe.contentWindow.document);
47+
} catch(e) {
48+
alert("Ошибка: " + e.message);
49+
}
50+
}
51+
52+
</script>
53+
```
54+
55+
Пример выше выведет ошибку.
56+
57+
## Исключение: запись в location
58+
59+
Окна могут менять `location` друг друга, даже если они из разных источников.
60+
61+
Причём *читать* свойства `location` нельзя, одно окно не имеет право знать, на каком URL пользователь в другом. А вот *запись* браузеры считают безопасной.
62+
63+
Например, открыв на `javascript.ru` iframe с `http://example.com`, из этого ифрейма нельзя будет прочитать URL, а вот поменять его -- запросто:
64+
65+
```html
66+
<!--+ run -->
67+
<iframe src="http://example.com"></iframe>
68+
69+
<script>
70+
var iframe = document.body.children[0];
71+
72+
iframe.onload = function() {
73+
try {
74+
// не сработает (чтение)
75+
alert(iframe.contentWindow.location.href);
76+
} catch(e) {
77+
alert("Ошибка: " + e.message);
78+
}
79+
80+
// сработает (запись)
81+
iframe.contentWindow.location.href = 'http://wikipedia.org';
82+
83+
iframe.onload = null;
84+
}
85+
86+
</script>
87+
```
88+
89+
Если запустить код выше, то окно сначала начнёт загрузит `example.com`, а потом будет перенаправлено на `wikipedia.org`.
90+
91+
## Исключение: поддомен 3го уровня
92+
93+
Ещё одно важное исключение касается доменов третьего уровня.
94+
95+
Если несколько окон имеют общий домен второго уровня, к примеру `john.site.com`, `peter.site.com`, `site.com`, и присваивают в `document.domain` свой общий поддомен 2го уровня `site.com`, то все ограничения снимаются.
96+
97+
То есть, на всех этих сайтах должен быть код:
98+
```js
99+
document.domain = 'site.com';
100+
```
101+
102+
Тогда между ними не будет кросс-доменных ограничений.
103+
104+
Обратим внимание: свойство `document.domain` должно быть присвоено на всех окнах, участвующих в коммуникации. Выглядит абсурдно, но даже на документе с `site.com` нужно вызвать: `document.domain="site.com"`. Иначе не будет работать.
105+
106+
Таким образом разные подсайты в рамках одного общего проекта могут взаимодействовать без ограничений.
107+
108+
## Исключения в IE
109+
110+
В браузере Internet Explorer есть два своих, дополнительных исключения из Same Origin Policy.
111+
112+
<ol>
113+
<li>Порт не входит в понятие "источник" (origin).
114+
115+
Это означает, что окно с `http://site.com` может свободно общаться с `http://site.com:8080`.
116+
117+
Это иногда используют для общения серверов, использующих один IP-адрес. Но допустимо такое только в IE.</li>
118+
<li>Если сайт находится в зоне "Надёжные узлы", то в Internet Explorer ограничения к нему не применяются.
119+
120+
При этом подразумевается, что для этой зоны в параметрах "Безопасность" включена опция "Доступ к источникам данных за пределами домена".</li>
121+
</ol>
122+
123+
## Итого
124+
125+
Ограничение "одного источника" запрещает окнам и фреймам с разных источников вызывать методы друг друга и читать данные друг из друга.
126+
127+
При этом "из одного источника" означает "совпадают протокол, домен и порт".
128+
129+
У этого подхода ряд существенных исключений:
130+
131+
<ul>
132+
<li>Свойства `window.location.*` нельзя читать, но можно менять.</li>
133+
<li>Домены третьего уровня с общим наддоменом могут поменять `document.domain` на их общий домен второго уровня, и тогда они смогут взаимодействовать без ограничений.
134+
</li>
135+
<li>IE не включает порт в понятие источника. Кроме того, он позволяет снять ограничения для конкретного сайта включением в доверенную зону.</li>
136+
</ul>
137+

0 commit comments

Comments
 (0)