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 @@ + + + + noun_1211_cc + Message + Created with Sketch. + + + + + + + + + + + "Hello!" + + + + + + Message + + + + + \ 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 @@ + + + + noun_1211_cc + Message + Created with Sketch. + + + + + + + + + + + "Hello!" + + + + + + Message + + + + + \ 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 @@ + + + + noun_1211_cc + Message + Created with Sketch. + + + + + + + + + + + "Hello!" + + + + + + Message + + + + + \ 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 -- это объекты для работы с чем угодно, кро -Большинство возможностей 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. Узлы являются соседями, поэтому стоит только бит "предшествования": какой перед каким.
    2. -
    3. Здесь стоят сразу два бита: `10100` означает, что `ul` одновременно содержит `ul.firstChild` и является его предшественником, то есть при прямом обходе дерева документа сначала встречается `nodeA`, а потом `nodeB`. -Аналогично, `1010` означает, что `ul.parentNode` содержит `ul` и предшествует ему.
    4. -
    5. Так как ни один из узлов не является предком друг друга, то стоит только бит предшествования: `li` предшествует последнему узлу документа, никакого сюрприза здесь нет.
    6. -
    +
  • Узлы не вложены один в другой, поэтому стоит только бит "предшествования", отсюда `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 - - - -``` - -Список битовых масок для проверки: - - - - - - - - - - - - -
    БитыЧислоЗначение
    0000000`nodeA` и `nodeB` -- один и тот же узел
    0000011Узлы в разных документах (или один из них не в документе)
    0000102`nodeB` предшествует `nodeA` (в порядке обхода документа)
    0001004`nodeA` предшествует `nodeB`
    0010008`nodeB` содержит `nodeA`
    01000016`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 @@ - - - - - - - -
    - hh:mm:ss -
    - - - - - - - - - diff --git a/2-ui/1-document/11-modifying-document/10-clock-settimeout/source.view/index.html b/2-ui/1-document/11-modifying-document/10-clock-settimeout/source.view/index.html deleted file mode 100755 index 57b6c3f2..00000000 --- a/2-ui/1-document/11-modifying-document/10-clock-settimeout/source.view/index.html +++ /dev/null @@ -1,10 +0,0 @@ - - - - - - - - - - diff --git a/2-ui/1-document/11-modifying-document/10-clock-settimeout/task.md b/2-ui/1-document/11-modifying-document/10-clock-settimeout/task.md deleted file mode 100644 index 4f783fed..00000000 --- a/2-ui/1-document/11-modifying-document/10-clock-settimeout/task.md +++ /dev/null @@ -1,10 +0,0 @@ -# Часики при помощи "setTimeout" - -[importance 3] - -Создайте цветные часы, **используя `setTimeout` вместо `setInterval`**: - -[iframe src="solution"] - - - diff --git a/2-ui/1-document/11-modifying-document/2-remove-elements/solution.md b/2-ui/1-document/11-modifying-document/2-remove-elements/solution.md index 0d6d1ec6..99150411 100644 --- a/2-ui/1-document/11-modifying-document/2-remove-elements/solution.md +++ b/2-ui/1-document/11-modifying-document/2-remove-elements/solution.md @@ -2,7 +2,7 @@ Нужно учесть два момента.
      -
    1. Родителя может не быть (элемент уже удален или еще не вставлен).
    2. +
    3. Родителя может не быть (элемент уже удален или еще не вставлен). В этом случае мы не будем ничего делать.
    4. Для совместимости со стандартным методом нужно вернуть удаленный элемент.
    @@ -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); } - + diff --git a/2-ui/1-document/11-modifying-document/6-create-list/task.md b/2-ui/1-document/11-modifying-document/6-create-list/task.md index c86fe48d..f703837f 100644 --- a/2-ui/1-document/11-modifying-document/6-create-list/task.md +++ b/2-ui/1-document/11-modifying-document/6-create-list/task.md @@ -8,13 +8,11 @@
    1. Запрашивайте содержимое пункта у пользователя с помощью `prompt`.
    2. Создавайте пункт и добавляйте его к `UL`.
    3. -
    4. Процесс прерывается, когда пользователь нажимает ESC.
    5. +
    6. Процесс прерывается, когда пользователь нажимает ESC или вводит пустую строку.
    **Все элементы должны создаваться динамически.** -Если посетитель вводит теги -- в списке они показываются как обычный текст. +Если посетитель вводит теги -- пусть в списке они показываются как обычный текст. [demo src="solution"] - -P.S. `prompt` возвращает `null`, если пользователь нажал ESC. \ No newline at end of file diff --git a/2-ui/1-document/11-modifying-document/7-create-object-tree/solution.view/index.html b/2-ui/1-document/11-modifying-document/7-create-object-tree/solution.view/index.html index e4c3501a..fd24ffc4 100755 --- a/2-ui/1-document/11-modifying-document/7-create-object-tree/solution.view/index.html +++ b/2-ui/1-document/11-modifying-document/7-create-object-tree/solution.view/index.html @@ -46,4 +46,4 @@ createTree(container, data); - + diff --git a/2-ui/1-document/11-modifying-document/7-create-object-tree/task.md b/2-ui/1-document/11-modifying-document/7-create-object-tree/task.md index e399a08d..ce416085 100644 --- a/2-ui/1-document/11-modifying-document/7-create-object-tree/task.md +++ b/2-ui/1-document/11-modifying-document/7-create-object-tree/task.md @@ -47,6 +47,4 @@ createTree(container, data); // создаёт Если получится -- сделайте оба. - - P.S. Желательно, чтобы в дереве не было лишних элементов, в частности -- пустых `` на нижнем уровне. \ No newline at end of file diff --git a/2-ui/1-document/11-modifying-document/8-tree-count/solution.md b/2-ui/1-document/11-modifying-document/8-tree-count/solution.md new file mode 100644 index 00000000..539da988 --- /dev/null +++ b/2-ui/1-document/11-modifying-document/8-tree-count/solution.md @@ -0,0 +1,8 @@ +# Подсказки + +
      +
    1. Получить количество вложенных узлов можно через `elem.getElementsByTagName('*').length`.
    2. +
    3. Текст в начале `
    4. ` доступен как `li.firstChild`, его содержимое -- `li.firstChild.data`.
    5. +
    + +# Решение \ No newline at end of file diff --git a/2-ui/1-document/8-searching-elements-dom/2-tree/solution.view/index.html b/2-ui/1-document/11-modifying-document/8-tree-count/solution.view/index.html old mode 100755 new mode 100644 similarity index 92% rename from 2-ui/1-document/8-searching-elements-dom/2-tree/solution.view/index.html rename to 2-ui/1-document/11-modifying-document/8-tree-count/solution.view/index.html index 5d22663e..1adccbb7 --- a/2-ui/1-document/8-searching-elements-dom/2-tree/solution.view/index.html +++ b/2-ui/1-document/11-modifying-document/8-tree-count/solution.view/index.html @@ -42,7 +42,7 @@ diff --git a/2-ui/1-document/8-searching-elements-dom/2-tree/source.view/index.html b/2-ui/1-document/11-modifying-document/8-tree-count/source.view/index.html old mode 100755 new mode 100644 similarity index 100% rename from 2-ui/1-document/8-searching-elements-dom/2-tree/source.view/index.html rename to 2-ui/1-document/11-modifying-document/8-tree-count/source.view/index.html diff --git a/2-ui/1-document/11-modifying-document/8-tree-count/task.md b/2-ui/1-document/11-modifying-document/8-tree-count/task.md new file mode 100644 index 00000000..ac6993b7 --- /dev/null +++ b/2-ui/1-document/11-modifying-document/8-tree-count/task.md @@ -0,0 +1,10 @@ +# Дерево + +[importance 5] + +Есть дерево [edit src="source"]в песочнице[/edit]. + +Напишите код, который добавит каждому элементу списка `
  • ` количество вложенных в него элементов. Узлы нижнего уровня, без детей -- пропускайте. + +Результат: +[iframe border=1 src="solution"] diff --git a/2-ui/1-document/11-modifying-document/8-calendar-table/solution.md b/2-ui/1-document/11-modifying-document/9-calendar-table/solution.md similarity index 100% rename from 2-ui/1-document/11-modifying-document/8-calendar-table/solution.md rename to 2-ui/1-document/11-modifying-document/9-calendar-table/solution.md diff --git a/2-ui/1-document/11-modifying-document/8-calendar-table/solution.view/index.html b/2-ui/1-document/11-modifying-document/9-calendar-table/solution.view/index.html old mode 100755 new mode 100644 similarity index 100% rename from 2-ui/1-document/11-modifying-document/8-calendar-table/solution.view/index.html rename to 2-ui/1-document/11-modifying-document/9-calendar-table/solution.view/index.html diff --git a/2-ui/1-document/11-modifying-document/8-calendar-table/source.view/index.html b/2-ui/1-document/11-modifying-document/9-calendar-table/source.view/index.html old mode 100755 new mode 100644 similarity index 100% rename from 2-ui/1-document/11-modifying-document/8-calendar-table/source.view/index.html rename to 2-ui/1-document/11-modifying-document/9-calendar-table/source.view/index.html diff --git a/2-ui/1-document/11-modifying-document/8-calendar-table/task.md b/2-ui/1-document/11-modifying-document/9-calendar-table/task.md similarity index 100% rename from 2-ui/1-document/11-modifying-document/8-calendar-table/task.md rename to 2-ui/1-document/11-modifying-document/9-calendar-table/task.md diff --git a/2-ui/1-document/11-modifying-document/article.md b/2-ui/1-document/11-modifying-document/article.md index d8c194db..5ff6b187 100644 --- a/2-ui/1-document/11-modifying-document/article.md +++ b/2-ui/1-document/11-modifying-document/article.md @@ -111,19 +111,17 @@ div.innerHTML = "Ура! Вы прочитали это важ ``` -**Этот же метод используется для вставки в начало элемента.** - -Достаточно указать, что вставлять будем перед первым потомком: +Для вставки элемента в начало достаточно указать, что вставлять будем перед первым потомком: ```js list.insertBefore(newLi, list.firstChild); ``` -У человека, который посмотрит на этот код внимательно, наверняка возникнет вопрос: "А что, если `list` вообще пустой, в этом случае ведь `list.firstChild = null`, произойдёт ли вставка?" +У читателя, который посмотрит на этот код внимательно, наверняка возникнет вопрос: "А что, если `list` вообще пустой, в этом случае ведь `list.firstChild = null`, произойдёт ли вставка?" Ответ -- да, произойдёт. -**Дело в том, что если в качестве `nextSibling` указать `null`, то `insertBefore` сработает как `appendChild`:** +**Дело в том, что если вторым аргументом указать `null`, то `insertBefore` сработает как `appendChild`:** ```js parentElem.insertBefore(elem, null); @@ -131,12 +129,18 @@ parentElem.insertBefore(elem, null); parentElem.appendChild(elem) ``` +Так что `insertBefore` универсален. -Все методы вставки возвращают вставленный узел, например `parentElem.appendChild(elem)` возвращает `elem`. +[smart] +Все методы вставки возвращают вставленный узел. -### Добавление сообщения +Например, `parentElem.appendChild(elem)` возвращает `elem`. +[/smart] + + +### Пример использования Добавим сообщение в конец ``: @@ -180,9 +184,9 @@ parentElem.appendChild(elem) ## Клонирование узлов: cloneNode -А как бы мне вставить второе такое же сообщение? +А как бы вставить второе похожее сообщение? -Конечно, можно сделать функцию для генерации сообщений и поместить туда этот код, но в ряде случаев гораздо эффективнее -- *клонировать* существующий `div`. В частности, если элемент большой, то клонировать его будет гораздо быстрее, чем пересоздавать. +Конечно, можно сделать функцию для генерации сообщений и поместить туда этот код, но в ряде случаев гораздо эффективнее -- *клонировать* существующий `div`, а потом изменить текст внутри. В частности, если элемент большой, то клонировать его будет гораздо быстрее, чем пересоздавать. Вызов `elem.cloneNode(true)` создаст "глубокую" копию элемента -- вместе с атрибутами, включая подэлементы. Если же вызвать с аргумнтом `false`, то он копия будет без подэлементов, но это нужно гораздо реже. @@ -223,8 +227,8 @@ div.parentNode.insertBefore( div2, div.nextSibling ); ```
      -
    1. Для вставки нам нужен будущий родитель. Мы, возможно, не знаем, где точно находится `div` (или не хотим зависеть от того, где он), но если нужно вставить рядом с ним, то родителем определённо будет `div.parentNode`.
    2. -
    3. Вставляем в родителя. Мы хотели бы вставить после `div`, но метода `insertAfter` нет, есть только `insertBefore`, поэтому вставляем *перед* его правым соседом `div.nextSibling`.
    4. +
    5. Для вставки нам нужен будущий родитель. Мы, возможно, не знаем, где точно находится `div` (или не хотим зависеть от того, где он), но если нужно вставить рядом с `div`, то родителем определённо будет `div.parentNode`.
    6. +
    7. Мы хотели бы вставить *после* `div`, но метода `insertAfter` нет, есть только `insertBefore`, поэтому вставляем *перед* его правым соседом `div.nextSibling`.
    @@ -292,22 +296,35 @@ div.parentNode.insertBefore( div2, div.nextSibling ); ``` -## Пример использования текстовых узлов +## Текстовые узлы для вставки текста При работе с сообщением мы использовали только узлы-элементы и `innerHTML`. -Но и текстовые узлы тоже имеют интересную область применения! Было бы несправедливо их обойти. +Но и текстовые узлы тоже имеют интересную область применения! -У них есть две особенности. Начнем с небольшого вопроса. +Если текст для сообщения нужно показать именно как текст, а не как HTML, то можно обернуть его в текстовый узел. +Например: -Ответили на вопрос выше? Даже если нет, то, поглядев в решение, вы легко увидите разницу. +```html + + -Итак, отличий два: -
      -
    1. При создании текстового узла `createTextNode('...')` любые специальные символы и теги в строке будут интерпретированы *как текст*. А `innerHTML` обработал бы их *как HTML*.
    2. -
    3. Во всех современных браузерах создание и вставка текстового узла работает гораздо быстрее, чем присвоение HTML.
    4. -
    + +``` + +В современных браузерах (кроме IE8-) в качестве альтернативы можно использовать присвоение `textContent`. ## Итого @@ -329,7 +346,7 @@ div.parentNode.insertBefore( div2, div.nextSibling ); Все эти методы возвращают `elem`. -Запомнить порядок аргументов очень просто: **новый(вставляемый) элемент -- всегда первый.** +**Запомнить порядок аргументов очень просто: новый(вставляемый) элемент -- всегда первый.** Методы для изменения DOM также описаны в спецификации DOM Level 1. diff --git a/2-ui/1-document/12-multi-insert/2-insertadjacenthtml-documentfragment/solution.md b/2-ui/1-document/12-multi-insert/2-insertadjacenthtml-documentfragment/solution.md deleted file mode 100644 index 9de9c2f5..00000000 --- a/2-ui/1-document/12-multi-insert/2-insertadjacenthtml-documentfragment/solution.md +++ /dev/null @@ -1,49 +0,0 @@ -# Подсказки - - - -# Решение - -```html - - - - -``` - diff --git a/2-ui/1-document/12-multi-insert/2-insertadjacenthtml-documentfragment/task.md b/2-ui/1-document/12-multi-insert/2-insertadjacenthtml-documentfragment/task.md deleted file mode 100644 index ad9d8207..00000000 --- a/2-ui/1-document/12-multi-insert/2-insertadjacenthtml-documentfragment/task.md +++ /dev/null @@ -1,34 +0,0 @@ -# Вставка insertAdjacentHTML/DocumentFragment - -[importance 4] - -Напишите кроссбраузерную функцию `insertBefore(elem, html)`, которая: - - - -В обоих случаях должна быть лишь одна операция с DOM документа. - -Следующий код должен вставить два пропущенных элемента списка `
  • 3
  • 4
  • `: - -```html - - - -``` - diff --git a/2-ui/1-document/12-multi-insert/3-sort-table-performance/solution.md b/2-ui/1-document/12-multi-insert/2-sort-table-performance/solution.md similarity index 77% rename from 2-ui/1-document/12-multi-insert/3-sort-table-performance/solution.md rename to 2-ui/1-document/12-multi-insert/2-sort-table-performance/solution.md index f5201d1c..bd110879 100644 --- a/2-ui/1-document/12-multi-insert/3-sort-table-performance/solution.md +++ b/2-ui/1-document/12-multi-insert/2-sort-table-performance/solution.md @@ -8,4 +8,4 @@ P.S. Создавать `DocumentFragment` здесь ни к чему. Можно вытащить из документа `TBODY` и иметь дело с ним в отрыве от DOM (алгоритм 4). -P.P.S. Если нужно сделать много узлов, то обычно `innerHTML` работает быстрее, чем генерация элементов через DOM-вызовы. Но в данном случае мы не создаём элементы, а сортируем и перевставляем готовые, так что результаты могут отличаться. +P.P.S. Если нужно сделать много узлов, то обычно `innerHTML` работает быстрее, чем удаление и вставка элементов через DOM-вызовы. То есть, сгенерировать таблицу заново эффективнее. diff --git a/2-ui/1-document/12-multi-insert/3-sort-table-performance/solution.view/index.html b/2-ui/1-document/12-multi-insert/2-sort-table-performance/solution.view/index.html old mode 100755 new mode 100644 similarity index 100% rename from 2-ui/1-document/12-multi-insert/3-sort-table-performance/solution.view/index.html rename to 2-ui/1-document/12-multi-insert/2-sort-table-performance/solution.view/index.html diff --git a/2-ui/1-document/12-multi-insert/3-sort-table-performance/task.md b/2-ui/1-document/12-multi-insert/2-sort-table-performance/task.md similarity index 99% rename from 2-ui/1-document/12-multi-insert/3-sort-table-performance/task.md rename to 2-ui/1-document/12-multi-insert/2-sort-table-performance/task.md index 0a1dcbf1..600836e0 100644 --- a/2-ui/1-document/12-multi-insert/3-sort-table-performance/task.md +++ b/2-ui/1-document/12-multi-insert/2-sort-table-performance/task.md @@ -44,4 +44,5 @@ Как сделать, чтобы сортировка работала как можно быстрее? А если в таблице 10000 строк (бывает и такое)? P.S. Может ли здесь помочь `DocumentFragment`? + P.P.S. Если предположить, что у нас заранее есть массив данных для таблицы в JavaScript -- что быстрее: отсортировать эту таблицу или сгенерировать новую? \ No newline at end of file diff --git a/2-ui/1-document/12-multi-insert/article.md b/2-ui/1-document/12-multi-insert/article.md index 71b2e967..c8c47401 100644 --- a/2-ui/1-document/12-multi-insert/article.md +++ b/2-ui/1-document/12-multi-insert/article.md @@ -31,7 +31,7 @@ document.body.appendChild(ul); // затем в документ Как ни странно, между этими последовательностями есть разница. В большинстве браузеров, второй вариант -- быстрее. -Почему же? Иногда говорят: "потому что браузер перерисовывает каждый раз при добавлении элемента". Это не так. **Дело вовсе не в перерисовке**. +Почему же? Иногда говорят: "потому что браузер перерисовывает каждый раз при добавлении элемента". Это не так. Дело вовсе не в перерисовке. Браузер достаточно "умён", чтобы ничего не перерисовывать понапрасну. В большинстве случаев процессы перерисовки и сопутствующие вычисления будут отложены до окончания работы скрипта, и на тот момент уже совершенно без разницы, в какой последовательности были изменены узлы. @@ -39,6 +39,7 @@ document.body.appendChild(ul); // затем в документ Что именно происходит -- зависит от конкретной, внутренней браузерной реализации DOM, но это отнимает время. Конечно, браузеры развиваются и стараются свести лишние действия к минимуму. +[online] ### Бенчмарк [#insert-bench-tbody] Чтобы легко проверить текущее состояние дел -- вот два бенчмарка. @@ -53,10 +54,9 @@ document.body.appendChild(ul); // затем в документ
    -```js -//+ hide="открыть код" src="insert-bench.js" -``` +Код для тестов находится в файле [](insert-bench.js). +[/online] ## Добавление множества узлов Продолжим работать со вставкой узлов. @@ -71,7 +71,7 @@ document.body.appendChild(ul); // затем в документ ul.innerHTML += "
  • 1
  • 2
  • ..."; ``` -Но операция `+=` с `innerHTML` не работает с DOM. Она не прибавляет, а заменяет всё содержимое списка на дополненную строку. Это не только медленно, но все внешние ресурсы (картинки) будут загружены заново! Так лучше не делать. +Но операция `+=` с `innerHTML` не работает с DOM. Она не прибавляет, а заменяет всё содержимое списка на дополненную строку. Это не только медленно, но все внешние ресурсы (картинки) будут загружены заново. Так лучше не делать. А если нужно вставить в середину списка? Здесь `innerHTML` вообще не поможет. @@ -122,9 +122,9 @@ li5.insertAdjacentHTML("beforeBegin", "
  • 3
  • 4
  • "); ``` -Единственный недостаток этого метода -- он не работает в Firefox до версии 8. Но его можно легко добавить, используя следующий JavaScript: [insertAdjacentFF.js](/files/tutorial/browser/dom/insertAdjacentFF.js). +Единственный недостаток этого метода -- он не работает в Firefox до версии 8. Но его можно легко добавить, используя [полифилл insertAdjacentHTML для Firefox](insertAdjacentHTML.js). -У этого метода есть "близнецы-братья", которые поддерживаются везде, кроме FF, но в него они добавляются этим же скриптом: +У этого метода есть "близнецы-братья", которые поддерживаются везде, кроме Firefox, но в него они добавляются тем же полифиллом: