diff --git a/1-js/2-first-steps/5-variables/variable-brown.svg b/1-js/2-first-steps/5-variables/variable-brown.svg
new file mode 100644
index 00000000..a160bc88
--- /dev/null
+++ b/1-js/2-first-steps/5-variables/variable-brown.svg
@@ -0,0 +1,27 @@
+
+
\ No newline at end of file
diff --git a/1-js/2-first-steps/5-variables/variable-gray.svg b/1-js/2-first-steps/5-variables/variable-gray.svg
new file mode 100644
index 00000000..4b95817a
--- /dev/null
+++ b/1-js/2-first-steps/5-variables/variable-gray.svg
@@ -0,0 +1,27 @@
+
+
\ No newline at end of file
diff --git a/1-js/2-first-steps/5-variables/variable-green.svg b/1-js/2-first-steps/5-variables/variable-green.svg
new file mode 100644
index 00000000..efb03c5a
--- /dev/null
+++ b/1-js/2-first-steps/5-variables/variable-green.svg
@@ -0,0 +1,27 @@
+
+
\ No newline at end of file
diff --git a/2-ui/1-document/1-browser-environment/article.md b/2-ui/1-document/1-browser-environment/article.md
index df975514..12515f49 100644
--- a/2-ui/1-document/1-browser-environment/article.md
+++ b/2-ui/1-document/1-browser-environment/article.md
@@ -1,22 +1,39 @@
# Окружение: DOM, BOM и JS
-Сам по себе язык JavaScript не предусматривает работы с браузером, он вообще не знает про HTML.
+Сам по себе язык JavaScript не предусматривает работы с браузером.
+
+Он вообще не знает про HTML. Но позволяет легко расширять себя новыми функциями и объектами.
-Но в браузере есть ряд специальных объектов, которые образуют Document Object Model (DOM) и дают доступ к документу, а также объекты Browser Object Model (BOM), которые позволяют использовать различные возможности браузера, такие как коммуникация с сервером, открытие новых окон и т.п.
[cut]
+
На рисунке ниже схематически отображена структура, которая получается если посмотреть на совокупность браузерных объектов с "высоты птичьего полёта".
-Как видно из рисунка, на вершине стоит `window`, который играет роль *глобального объекта*, но вместе с этим даёт доступ к функционалу по управлению окном браузера, у него есть методы `window.focus()`, `window.open()` и другие.
-Все остальные объекты делятся на 3 группы.
+Как видно из рисунка, на вершине стоит `window`.
+
+У этого объекта двоякая позиция -- он с одной стороны является глобальным объектом в JavaScript, с другой -- содержит свойства и методы для управления окном браузера, открытия новых окон, например:
+
+```js
+//+ run
+// открыть новое окно/вкладку с URL http://ya.ru
+window.open('http://ya.ru');
+```
## Объектная модель документа (DOM)
Глобальный объект `document` даёт возможность взаимодействовать с содержимым страницы.
-Он и громадное количество его свойств, методов и связанных с ним интерфейсов описаны в [стандарте W3C DOM](http://www.w3.org/DOM/DOMTR).
+Пример использования:
+```js
+//+ run
+document.body.style.background = 'red';
+alert('Элемент BODY стал красным, а сейчас обратно вернётся');
+document.body.style.background = '';
+```
+
+Он и громадное количество его свойств и методов описаны в [стандарте W3C DOM](http://www.w3.org/DOM/DOMTR).
По историческим причинам когда-то появилась первая версия стандарта DOM Level 1, затем придумали ещё свойства и методы, и появился DOM Level 2, на текущий момент поверх них добавили ещё DOM Level 3 и готовится DOM 4.
@@ -24,6 +41,8 @@
Также информацию по работе с элементами страницы можно найти в стандарте [HTML 5](http://www.w3.org/TR/html5/Overview.html).
+Мы подробно ознакомимся с DOM далее в этой части учебника.
+
## Объектная модель браузера (BOM)
BOM -- это объекты для работы с чем угодно, кроме документа.
@@ -32,14 +51,19 @@ BOM -- это объекты для работы с чем угодно, кро
Объект [navigator](https://developer.mozilla.org/en/DOM/window.navigator) содержит общую информацию о браузере и операционной системе. Особенно примечательны два свойства: `navigator.userAgent` -- содержит информацию о браузере и `navigator.platform` -- содержит информацию о платформе, позволяет различать Windows/Linux/Mac и т.п.
Объект [location](https://developer.mozilla.org/en-US/docs/Web/API/Window.location) содержит информацию о текущем URL страницы и позволяет перенаправить посетителя на новый URL.
-
Функции `alert/confirm/prompt` -- тоже входят в BOM.
-
+
Функции `alert/confirm/prompt` -- тоже входят в BOM.
-Большинство возможностей BOM стандартизированы в [HTML 5](http://www.w3.org/TR/html5/Overview.html), но браузеры любят изобрести что-нибудь своё, особенное.
+Пример использования:
+```js
+//+ run
+alert(location.href); // выведет текущий адрес
+```
-## Объекты и функции JavaScript
+Большинство возможностей BOM стандартизированы в [HTML 5](http://www.w3.org/TR/html5/Overview.html), хотя различные браузеры и предоставляют зачастую что-то своё, в дополнение к стандарту.
-JavaScript -- объекты и методы языка JavaScript, который даёт возможность управлять всем этим. Именно их описывает стандарт EcmaScript.
+## Итого
-Далее в этом курсе мы будем, преимущественно, изучать DOM, поскольку именно документ занимает центральную роль в организации интерфейса, и работа с ним -- сложнее всего.
\ No newline at end of file
+Итак, у нас есть DOM, BOM и, собственно, язык JavaScript, который даёт возможность управлять всем этим.
+
+Далее мы приступим к изучению DOM, поскольку именно документ занимает центральную роль в организации интерфейса, и работа с ним -- сложнее всего.
\ No newline at end of file
diff --git a/2-ui/1-document/10-compare-document-position/article.md b/2-ui/1-document/10-compare-document-position/article.md
index 22f23a06..67bb9e0d 100644
--- a/2-ui/1-document/10-compare-document-position/article.md
+++ b/2-ui/1-document/10-compare-document-position/article.md
@@ -1,6 +1,6 @@
# Методы contains и compareDocumentPosition
-Если есть два элемента, то иногда бывает нужно понять, находится ли один в другом, и произвести обработку в зависимости от результата.
+Если есть два элемента, то иногда бывает нужно понять, лежит ли один из них выше другого, то есть является ли его предком.
Обычные поисковые методы здесь не дают ответа, но есть два специальных. Они используются редко, но когда подобная задача встаёт, то знание метода может сэкономить много строк кода.
@@ -20,7 +20,7 @@ var result = parent.contains(child);
Бывает, что у нас есть два элемента, к примеру, `
` в списке, и нужно понять, какой из них выше другого.
-Это поможет сделать другой метод.
+Метод `compareDocumentPosition` -- более мощный, чем `contains`, он предоставляет одновременно информацию и о содержании и об относительном порядке элементов.
Синтаксис:
@@ -55,32 +55,33 @@ var result = nodeA.compareDocumentPosition(nodeB);
1.1
-
...
```
-Комментарии:
+Более подробно:
-
Узлы являются соседями, поэтому стоит только бит "предшествования": какой перед каким.
-
Здесь стоят сразу два бита: `10100` означает, что `ul` одновременно содержит `ul.firstChild` и является его предшественником, то есть при прямом обходе дерева документа сначала встречается `nodeA`, а потом `nodeB`.
-Аналогично, `1010` означает, что `ul.parentNode` содержит `ul` и предшествует ему.
-
Так как ни один из узлов не является предком друг друга, то стоит только бит предшествования: `li` предшествует последнему узлу документа, никакого сюрприза здесь нет.
-
+
Узлы не вложены один в другой, поэтому стоит только бит "предшествования", отсюда `10`.
+
То же самое, но обратный порядок узлов, поэтому `100`.
+
Здесь стоят сразу два бита: `10100` означает, что `ul` одновременно содержит `li` и является его предшественником, то есть при прямом обходе дерева документа сначала встречается `ul`, а потом `li`.
+
Аналогично предыдущему, `1010` означает, что `document.body` содержит `ul` и предшествует ему.
+
[smart header="Перевод в двоичную систему"]
Самый простой способ самостоятельно посмотреть, как число выглядит в 2-ной системе -- вызвать для него `toString(2)`, например:
@@ -101,7 +102,7 @@ alert( 20..toString(2) );
Здесь после `20` две точки, так как если одна, то JS подумает, что после неё десятичная часть -- будет ошибка.
[/smart]
-Проверка условия "`nodeA` содержит `nodeB`" с использованием битовых операций: `nodeA.compareDocumentPosition(nodeB) & 16`, например:
+Проверить конкретное условие, например, "`nodeA` содержит `nodeB`", можно при помощи битовых операций, в данном случае: `nodeA.compareDocumentPosition(nodeB) & 16`, например:
```html
@@ -110,12 +111,12 @@ alert( 20..toString(2) );
@@ -134,76 +135,33 @@ if( nodeA.compareDocumentPosition(nodeB) & 16 ) {
Номер элемента `node` в порядке прямого обхода дерева. Только для узлов-элементов.
-На их основе можно написать кросс-браузерную реализацию `compareDocumentPosition`:
+На их основе можно написать полифилл для `compareDocumentPosition`:
```js
-// Адаптировано с http://ejohn.org/blog/comparing-document-position/
-function compareDocumentPosition(a, b) {
- return a.compareDocumentPosition ?
- a.compareDocumentPosition(b) :
- (a != b && a.contains(b) && 16) +
- (a != b && b.contains(a) && 8) +
- (a.sourceIndex >= 0 && b.sourceIndex >= 0 ?
- (a.sourceIndex < b.sourceIndex && 4) +
- (a.sourceIndex > b.sourceIndex && 2) :
- 1);
-}
+// код с http://compatibility.shwups-cms.ch/en/polyfills/?&id=82
+(function(){
+ var el = document.documentElement;
+ if( !el.compareDocumentPosition && el.sourceIndex !== undefined ){
+
+ Element.prototype.compareDocumentPosition = function(other){
+ return (this != other && this.contains(other) && 16) +
+ (this != other && other.contains(this) && 8) +
+ (this.sourceIndex >= 0 && other.sourceIndex >= 0 ?
+ (this.sourceIndex < other.sourceIndex && 4) +
+ (this.sourceIndex > other.sourceIndex && 2)
+ : 1
+ ) + 0;
+ }
+ }
+}());
```
-Эта функция будет работать для узлов-элементов во всех браузерах.
+С этим полифиллом метод доступен для элементов во всех браузерах.
## Итого
-Для проверки, лежит ли один узел внутри другого, достаточно метода `nodeA.contains(nodeB)`.
-
-Для расширенной проверки на предшествование есть метод `compareDocumentPosition`, кросс-браузерный вариант которого приведён выше.
-
-Пример использования:
-
-```html
-
-
1
-
2
+
Для проверки, является ли один узел предком другого, достаточно метода `nodeA.contains(nodeB)`.
+
Для расширенной проверки на предшествование есть метод `compareDocumentPosition`.
+
Для IE8 нужен полифилл для `compareDocumentPosition`.
-
-
-```
-
-Список битовых масок для проверки:
-
-
-
Биты
-
Число
-
Значение
-
-
000000
0
`nodeA` и `nodeB` -- один и тот же узел
-
000001
1
Узлы в разных документах (или один из них не в документе)
-
000010
2
`nodeB` предшествует `nodeA` (в порядке обхода документа)
-
000100
4
`nodeA` предшествует `nodeB`
-
001000
8
`nodeB` содержит `nodeA`
-
010000
16
`nodeA` содержит `nodeB`
-
diff --git a/2-ui/1-document/11-modifying-document/9-clock-setinterval/solution.md b/2-ui/1-document/11-modifying-document/10-clock-setinterval/solution.md
similarity index 79%
rename from 2-ui/1-document/11-modifying-document/9-clock-setinterval/solution.md
rename to 2-ui/1-document/11-modifying-document/10-clock-setinterval/solution.md
index 551e6f04..682e2e1a 100644
--- a/2-ui/1-document/11-modifying-document/9-clock-setinterval/solution.md
+++ b/2-ui/1-document/11-modifying-document/10-clock-setinterval/solution.md
@@ -10,34 +10,16 @@
Каждый `SPAN` раскрашивается при помощи CSS.
-Жизнь часам будет обеспечивать функция `update`, вызываемая каждую секунду: `setInterval(update, 1000)`.
-
-```js
-var timerId; // таймер, если часы запущены
-
-function clockStart() { // запустить часы
- if (timerId) return;
-
- timerId = setInterval(update, 1000);
- update(); // (*)
-}
-
-function clockStop() {
- clearInterval(timerId);
- timerId = null;
-}
-```
-
-Обратите внимание, что вызов `update` не только запланирован, но и производится тут же в строке `(*)`. Иначе посетителю пришлось бы ждать до первого выполнения `setInterval`.
-
-Функция обновления часов:
+Жизнь часам будет обеспечивать функция `update`, вызываемая каждую секунду:
```js
function update() {
var clock = document.getElementById('clock');
+
*!*
var date = new Date(); // (*)
*/!*
+
var hours = date.getHours();
if (hours < 10) hours = '0'+hours;
clock.children[0].innerHTML = hours;
@@ -56,4 +38,19 @@ function update() {
На самом деле мы не можем опираться на счетчик для вычисления даты, т.к. `setInterval` не гарантирует точную задержку. Если в другом участке кода будет вызван `alert`, то часы остановятся, как и любые счетчики.
-[edit src="solution"]Полный код решения[/edit]
\ No newline at end of file
+Функция `clockStart` для запуска часов:
+
+```js
+function clockStart() { // запустить часы
+ setInterval(update, 1000);
+ update(); // (*)
+}
+
+function clockStop() {
+ clearInterval(timerId);
+ timerId = null;
+}
+```
+
+Обратите внимание, что вызов `update` не только запланирован, но и тут же производится тут же в строке `(*)`. Иначе посетителю пришлось бы ждать до первого выполнения `setInterval`, то есть целую секунду.
+
diff --git a/2-ui/1-document/11-modifying-document/9-clock-setinterval/solution.view/index.html b/2-ui/1-document/11-modifying-document/10-clock-setinterval/solution.view/index.html
old mode 100755
new mode 100644
similarity index 72%
rename from 2-ui/1-document/11-modifying-document/9-clock-setinterval/solution.view/index.html
rename to 2-ui/1-document/11-modifying-document/10-clock-setinterval/solution.view/index.html
index 645c176a..31cf9adb
--- a/2-ui/1-document/11-modifying-document/9-clock-setinterval/solution.view/index.html
+++ b/2-ui/1-document/11-modifying-document/10-clock-setinterval/solution.view/index.html
@@ -2,9 +2,9 @@
@@ -35,25 +35,14 @@ function update() {
}
function clockStart() {
- if (timerId) return;
-
- timerId = setInterval(update, 1000);
+ setInterval(update, 1000);
update(); // <-- начать тут же, не ждать 1 секунду пока setInterval сработает
}
-function clockStop() {
- clearInterval(timerId);
- timerId = null;
-}
-
+clockStart();
-
-
-
-
-
diff --git a/2-ui/1-document/11-modifying-document/9-clock-setinterval/source.view/index.html b/2-ui/1-document/11-modifying-document/10-clock-setinterval/source.view/index.html
old mode 100755
new mode 100644
similarity index 100%
rename from 2-ui/1-document/11-modifying-document/9-clock-setinterval/source.view/index.html
rename to 2-ui/1-document/11-modifying-document/10-clock-setinterval/source.view/index.html
diff --git a/2-ui/1-document/11-modifying-document/9-clock-setinterval/task.md b/2-ui/1-document/11-modifying-document/10-clock-setinterval/task.md
similarity index 64%
rename from 2-ui/1-document/11-modifying-document/9-clock-setinterval/task.md
rename to 2-ui/1-document/11-modifying-document/10-clock-setinterval/task.md
index 35013eb9..e422846b 100644
--- a/2-ui/1-document/11-modifying-document/9-clock-setinterval/task.md
+++ b/2-ui/1-document/11-modifying-document/10-clock-setinterval/task.md
@@ -2,7 +2,7 @@
[importance 4]
-Создайте цветные часики как в примере ниже, **используя `setInterval`**:
+Создайте цветные часики как в примере ниже:
-[iframe src="solution"]
+[iframe src="solution" height=100]
diff --git a/2-ui/1-document/11-modifying-document/10-clock-settimeout/solution.md b/2-ui/1-document/11-modifying-document/10-clock-settimeout/solution.md
deleted file mode 100644
index f71c63c0..00000000
--- a/2-ui/1-document/11-modifying-document/10-clock-settimeout/solution.md
+++ /dev/null
@@ -1,7 +0,0 @@
-Общее решение описано в [аналогичной задаче с setInterval](/task/clock-setinterval).
-
-Способ через `setTimeout` -- по сути, такой же, только функция `update` каждый раз ставит себя в очередь заново.
-
-Заметим, что в данном случае целесообразнее использовать `setInterval`, т.к. нужна не задержка между запусками, а просто запуск каждую секунду.
-
-[edit src="solution"]Открыть решение в песочнице[/edit]
diff --git a/2-ui/1-document/11-modifying-document/10-clock-settimeout/solution.view/index.html b/2-ui/1-document/11-modifying-document/10-clock-settimeout/solution.view/index.html
deleted file mode 100755
index ceec78e3..00000000
--- a/2-ui/1-document/11-modifying-document/10-clock-settimeout/solution.view/index.html
+++ /dev/null
@@ -1,58 +0,0 @@
-
-
-
-
-
-
-
-
Родителя может не быть (элемент уже удален или еще не вставлен).
+
Родителя может не быть (элемент уже удален или еще не вставлен). В этом случае мы не будем ничего делать.
Для совместимости со стандартным методом нужно вернуть удаленный элемент.
@@ -10,7 +10,9 @@
```js
function remove(elem) {
- return elem.parentNode ? elem.parentNode.removeChild(elem) : elem;
+ var parent = elem.parentNode;
+ if (parent) elem.parentNode.removeChild(elem);
+ return elem;
}
```
diff --git a/2-ui/1-document/11-modifying-document/2-remove-elements/task.md b/2-ui/1-document/11-modifying-document/2-remove-elements/task.md
index 763e2ab7..5e129b4c 100644
--- a/2-ui/1-document/11-modifying-document/2-remove-elements/task.md
+++ b/2-ui/1-document/11-modifying-document/2-remove-elements/task.md
@@ -4,7 +4,7 @@
Напишите функцию, которая удаляет элемент из DOM.
-Синтаксис должен быть таким: `remove(elem)`, то есть, в отличие от `parentNode.removeChild(elem)` -- без родительского элемента.
+Синтаксис должен быть таким: `remove(elem)`, то есть, более короткий вариант, чем `parentNode.removeChild(elem)`.
```html
Это
diff --git a/2-ui/1-document/11-modifying-document/3-insert-after/solution.md b/2-ui/1-document/11-modifying-document/3-insert-after/solution.md
index d935d32a..63e6e886 100644
--- a/2-ui/1-document/11-modifying-document/3-insert-after/solution.md
+++ b/2-ui/1-document/11-modifying-document/3-insert-after/solution.md
@@ -1,4 +1,4 @@
-Для того, чтобы добавить элемент *после* `refElem`, мы можем вставить его *перед* `refElem.nextSibling`.
+Для того, чтобы добавить элемент *после* `refElem`, мы можем, используя `insertBefore`, вставить его *перед* `refElem.nextSibling`.
Но что если `nextSibling` нет? Это означает, что `refElem` является последним потомком своего родителя и можем использовать `appendChild`.
@@ -6,17 +6,17 @@
```js
function insertAfter(elem, refElem) {
- var parent = refElem.parentNode;
- var next = refElem.nextSibling;
- if (next) {
- return parent.insertBefore(elem, next);
- } else {
- return parent.appendChild(elem);
- }
+ var parent = refElem.parentNode;
+ var next = refElem.nextSibling;
+ if (next) {
+ return parent.insertBefore(elem, next);
+ } else {
+ return parent.appendChild(elem);
+ }
}
```
-Но код может быть гораздо короче, если использовать фишку со вторым аргументом null метода `insertBefore`:
+Но код может быть гораздо короче, если вспомнить, что `insertBefore` со вторым аргументом null работает как `appendChild`:
```js
function insertAfter(elem, refElem) {
@@ -24,6 +24,6 @@ function insertAfter(elem, refElem) {
}
```
-Если нет `nextSibling`, то второй аргумент `insertBefore` становится `null` и тогда `insertBefore(elem,null)` работает как `appendChild`.
+Если нет `nextSibling`, то второй аргумент `insertBefore` становится `null` и тогда `insertBefore(elem, null)` осуществит вставку в конец, как и требуется.
В решении нет проверки на существование `refElem.parentNode`, поскольку вставка после элемента без родителя -- уже ошибка, пусть она возникнет в функции, это нормально.
\ No newline at end of file
diff --git a/2-ui/1-document/11-modifying-document/4-remove-children/solution.md b/2-ui/1-document/11-modifying-document/4-remove-children/solution.md
index 6a29e291..9ea9f63d 100644
--- a/2-ui/1-document/11-modifying-document/4-remove-children/solution.md
+++ b/2-ui/1-document/11-modifying-document/4-remove-children/solution.md
@@ -12,7 +12,7 @@ function removeChildren(elem) {
Если вы попробуете это на практике, то увидите, то это не сработает.
-Не сработает потому, что `childNodes` всегда начинается 0 и автоматически смещается, когда первый потомок удален(т.е. тот, что был вторым, станет первым), поэтому такой цикл по `k` пропустит половину узлов.
+Не сработает потому, что коллекция `childNodes` всегда начинается с индекса 0 и автоматически обновляется, когда первый потомок удален(т.е. тот, что был вторым, станет первым). А переменная `k` в цикле всё время увеличивается, поэтому такой цикл пропустит половину узлов.
# Решение через DOM
@@ -26,9 +26,9 @@ function removeChildren(elem) {
}
```
-# Неправильное решение (innerHTML)
+# Альтернатива через innerHTML
-Прямая попытка использовать `innerHTML` была бы неправильной:
+Можно и просто обнулить содержимое через `innerHTML`:
```js
function removeChildren(elem) {
@@ -36,11 +36,9 @@ function removeChildren(elem) {
}
```
-Дело в том, что в IE8- свойство `innerHTML` на большинстве табличных элементов (кроме ячеек `TH/TD`) не работает. Будет ошибка.
+Это не будет работать в IE8- для таблиц, так как на большинстве табличных элементов (кроме ячеек `TH/TD`) в старых IE запрещено менять `innerHTML`.
-# Верное решение (innerHTML)
-
-Можно завернуть `innerHTML` в `try/catch`:
+Впрочем, можно завернуть `innerHTML` в `try/catch`:
```js
function removeChildren(elem) {
diff --git a/2-ui/1-document/11-modifying-document/4-remove-children/task.md b/2-ui/1-document/11-modifying-document/4-remove-children/task.md
index 4c2b7386..e7609cc8 100644
--- a/2-ui/1-document/11-modifying-document/4-remove-children/task.md
+++ b/2-ui/1-document/11-modifying-document/4-remove-children/task.md
@@ -25,5 +25,3 @@
removeChildren(ol); // очищает список
```
-
-P.S. Проверьте ваше решение в IE8.
\ No newline at end of file
diff --git a/2-ui/1-document/11-modifying-document/6-create-list/solution.md b/2-ui/1-document/11-modifying-document/6-create-list/solution.md
index d0235e68..f3689eb4 100644
--- a/2-ui/1-document/11-modifying-document/6-create-list/solution.md
+++ b/2-ui/1-document/11-modifying-document/6-create-list/solution.md
@@ -1,6 +1,4 @@
-Делайте проверку на `null` в цикле. `prompt` возвращает это значение только если был нажат ESC.
+Делаем цикл, пока посетитель что-то вводит -- добавляет `
`.
-Контент в `LI` добавляйте с помощью `document.createTextNode`, чтобы правильно работали <, > и т.д.
-
-[edit src="solution"]Решение в песочнице[/edit]
+Содержимое в `
` присваиваем через `document.createTextNode`, чтобы правильно работали <, > и т.д.
diff --git a/2-ui/1-document/11-modifying-document/6-create-list/solution.view/index.html b/2-ui/1-document/11-modifying-document/6-create-list/solution.view/index.html
index 757cf670..f872b42c 100755
--- a/2-ui/1-document/11-modifying-document/6-create-list/solution.view/index.html
+++ b/2-ui/1-document/11-modifying-document/6-create-list/solution.view/index.html
@@ -13,7 +13,7 @@
while (true) {
var data = prompt("Введите текст для пункта списка", "");
- if (data === null) {
+ if (!data) {
break;
}
@@ -22,6 +22,6 @@
ul.appendChild(li);
}
-
+