diff --git a/1-js/02-first-steps/01-hello-world/article.md b/1-js/02-first-steps/01-hello-world/article.md index 6cbb3c4d..8de9df96 100644 --- a/1-js/02-first-steps/01-hello-world/article.md +++ b/1-js/02-first-steps/01-hello-world/article.md @@ -130,7 +130,7 @@ The example above can be split into two scripts to work: - We can use a ``. +- A script in an external file can be inserted with ``. There is much more about browser scripts and their interaction with the web-page. But let's keep in mind that this part of the tutorial is devoted to Javascript language. So we shouldn't distract ourselves from it. We'll be using a browser as a way to run Javascript, very convenient for online reading, but yet one of many. diff --git a/1-js/02-first-steps/16-javascript-specials/article.md b/1-js/02-first-steps/16-javascript-specials/article.md index 5406bbfb..12a6c255 100644 --- a/1-js/02-first-steps/16-javascript-specials/article.md +++ b/1-js/02-first-steps/16-javascript-specials/article.md @@ -218,7 +218,7 @@ let age = prompt('Your age?', 18); switch (age) { case 18: - alert("Won't work"); // the result of prompt is a string, not a number число + alert("Won't work"); // the result of prompt is a string, not a number case "18": alert("This works!""); diff --git a/1-js/03-code-quality/02-coding-style/1-style-errors/solution.md b/1-js/03-code-quality/02-coding-style/1-style-errors/solution.md index 07ce7d02..810fdad5 100644 --- a/1-js/03-code-quality/02-coding-style/1-style-errors/solution.md +++ b/1-js/03-code-quality/02-coding-style/1-style-errors/solution.md @@ -1,50 +1,48 @@ -# Ответ -Вы могли заметить следующие недостатки, сверху-вниз: +You could note the following: ```js no-beautify -function pow(x,n) // <- отсутствует пробел между аргументами -{ // <- фигурная скобка на отдельной строке - var result=1; // <- нет пробелов вокруг знака = - for(var i=0;i. Это потому что библиотеки Chai, Mocha и Sinon объединены в один файл: - -```html - -``` - -Этот файл содержит код библиотек, стили, настройки для них и запуск `mocha.run` по окончании загрузки страницы. Если нет элемента с `id="mocha"`, то результаты выводятся в ``. - -Сборка сделана исключительно для более компактного представления задач, без рекомендаций использовать именно её в проектах. diff --git a/1-js/03-code-quality/05-testing/2-pow-test-0/solution.md b/1-js/03-code-quality/05-testing/2-pow-test-0/solution.md deleted file mode 100644 index 3392d3d1..00000000 --- a/1-js/03-code-quality/05-testing/2-pow-test-0/solution.md +++ /dev/null @@ -1,38 +0,0 @@ -Новый тест может быть, к примеру, таким: - -```js -it("любое число в степени 0 равно 1", function() { - assert.equal(pow(123, 0), 1); -}); -``` - -Конечно, желательно проверить на нескольких числах. - -Поэтому лучше будет создать блок `describe`, аналогичный тому, что мы делали для произвольных чисел: - -```js -describe("любое число, кроме нуля, в степени 0 равно 1", function() { - - function makeTest(x) { - it("при возведении " + x + " в степень 0 результат: 1", function() { - assert.equal(pow(x, 0), 1); - }); - } - - for (var x = -5; x <= 5; x += 2) { - makeTest(x); - } - -}); -``` - -И не забудем добавить отдельный тест для нуля: - -```js no-beautify -... -it("ноль в нулевой степени даёт NaN", function() { - assert( isNaN(pow(0, 0)), "0 в степени 0 не NaN"); -}); -... -``` - diff --git a/1-js/03-code-quality/05-testing/2-pow-test-0/solution.view/index.html b/1-js/03-code-quality/05-testing/2-pow-test-0/solution.view/index.html deleted file mode 100644 index eb1aedbf..00000000 --- a/1-js/03-code-quality/05-testing/2-pow-test-0/solution.view/index.html +++ /dev/null @@ -1,27 +0,0 @@ - - - - - - - - - - - - - \ No newline at end of file diff --git a/1-js/03-code-quality/05-testing/2-pow-test-0/solution.view/test.js b/1-js/03-code-quality/05-testing/2-pow-test-0/solution.view/test.js deleted file mode 100644 index d2b9a771..00000000 --- a/1-js/03-code-quality/05-testing/2-pow-test-0/solution.view/test.js +++ /dev/null @@ -1,44 +0,0 @@ -describe("pow", function() { - - describe("возводит x в степень n", function() { - - function makeTest(x) { - var expected = x * x * x; - it("при возведении " + x + " в степень 3 результат: " + expected, function() { - assert.equal(pow(x, 3), expected); - }); - } - - for (var x = 1; x <= 5; x++) { - makeTest(x); - } - - }); - - it("при возведении в отрицательную степень результат NaN", function() { - assert(isNaN(pow(2, -1)), "pow(2, -1) не NaN"); - }); - - it("при возведении в дробную степень результат NaN", function() { - assert(isNaN(pow(2, 1.5)), "pow(2, -1.5) не NaN"); - }); - - describe("любое число, кроме нуля, в степени 0 равно 1", function() { - - function makeTest(x) { - it("при возведении " + x + " в степень 0 результат: 1", function() { - assert.equal(pow(x, 0), 1); - }); - } - - for (var x = -5; x <= 5; x += 2) { - makeTest(x); - } - - }); - - it("ноль в нулевой степени даёт NaN", function() { - assert(isNaN(pow(0, 0)), "0 в степени 0 не NaN"); - }); - -}); \ No newline at end of file diff --git a/1-js/03-code-quality/05-testing/2-pow-test-0/source.view/index.html b/1-js/03-code-quality/05-testing/2-pow-test-0/source.view/index.html deleted file mode 100644 index 7cc184b0..00000000 --- a/1-js/03-code-quality/05-testing/2-pow-test-0/source.view/index.html +++ /dev/null @@ -1,26 +0,0 @@ - - - - - - - - - - - - - \ No newline at end of file diff --git a/1-js/03-code-quality/05-testing/2-pow-test-0/source.view/test.js b/1-js/03-code-quality/05-testing/2-pow-test-0/source.view/test.js deleted file mode 100644 index 61453678..00000000 --- a/1-js/03-code-quality/05-testing/2-pow-test-0/source.view/test.js +++ /dev/null @@ -1,26 +0,0 @@ -describe("pow", function() { - - describe("возводит x в степень n", function() { - - function makeTest(x) { - var expected = x * x * x; - it("при возведении " + x + " в степень 3 результат: " + expected, function() { - assert.equal(pow(x, 3), expected); - }); - } - - for (var x = 1; x <= 5; x++) { - makeTest(x); - } - - }); - - it("при возведении в отрицательную степень результат NaN", function() { - assert(isNaN(pow(2, -1)), "pow(2, -1) не NaN"); - }); - - it("при возведении в дробную степень результат NaN", function() { - assert(isNaN(pow(2, 1.5)), "pow(2, -1.5) не NaN"); - }); - -}); \ No newline at end of file diff --git a/1-js/03-code-quality/05-testing/2-pow-test-0/task.md b/1-js/03-code-quality/05-testing/2-pow-test-0/task.md deleted file mode 100644 index 974d90aa..00000000 --- a/1-js/03-code-quality/05-testing/2-pow-test-0/task.md +++ /dev/null @@ -1,9 +0,0 @@ -importance: 5 - ---- - -# Добавьте тест к задаче - -Добавьте к [предыдущей задаче](/task/pow-nan-spec) тесты, которые будут проверять, что любое число, кроме нуля, в нулевой степени равно `1`, а ноль в нулевой степени даёт `NaN` (это математически корректно, результат 00 не определён). - -При необходимости, исправьте реализацию, чтобы тесты проходили без ошибок. \ No newline at end of file diff --git a/1-js/03-code-quality/05-testing/3-pow-test-wrong/solution.md b/1-js/03-code-quality/05-testing/3-pow-test-wrong/solution.md index e4c94ed8..a6d7ef91 100644 --- a/1-js/03-code-quality/05-testing/3-pow-test-wrong/solution.md +++ b/1-js/03-code-quality/05-testing/3-pow-test-wrong/solution.md @@ -4,28 +4,47 @@ What we have here is actually 3 tests, but layed out as a single function with 3 Sometimes it's easier to write this way, but if an error occurs, it's much less obvious what went wrong. -If an error happens inside a complex execution flow, then we'll have to figure out what was the data at that point. +If an error happens inside a complex execution flow, then we'll have to figure out the data at that point. We'll actually have to *debug the test*. -TODO - -Если в сложном тесте произошла ошибка где-то посередине потока вычислений, то придётся выяснять, какие конкретно были входные и выходные данные на этот момент, то есть по сути -- отлаживать код самого теста. - -Гораздо лучше будет разбить тест на несколько блоков `it`, с чётко прописанными входными и выходными данными. +It would be much better to break the test into multiple `it` blocks with clearly written inputs and outputs. +Like this: ```js -describe("Возводит x в степень n", function() { - it("5 в степени 1 равно 5", function() { +describe("Raises x to power n", function() { + it("5 in the power of 1 equals 5", function() { assert.equal(pow(5, 1), 5); }); - it("5 в степени 2 равно 25", function() { + it("5 in the power of 2 equals 25", function() { assert.equal(pow(5, 2), 25); }); - it("5 в степени 3 равно 125", function() { + it("5 in the power of 3 equals 125", function() { assert.equal(pow(5, 3), 125); }); }); ``` -Можно использовать цикл для генерации блоков `it`, в этом случае важно, чтобы сам код такого цикла был достаточно простым. Иногда проще записать несколько блоков `it` вручную, как сделано выше, чем "городить огород" из синтаксических конструкций. +We replaced the single `it` with `describe` and a group of `it` blocks. Now if something fails we would see clearly what the data was. + +Also we can isolate a single test and run it in standalone mode by writing `it.only` instead of `it`: + + +```js +describe("Raises x to power n", function() { + it("5 in the power of 1 equals 5", function() { + assert.equal(pow(5, 1), 5); + }); + +*!* + // Mocha will run only this block + it.only("5 in the power of 2 equals 25", function() { + assert.equal(pow(5, 2), 25); + }); +*/!* + + it("5 in the power of 3 equals 125", function() { + assert.equal(pow(5, 3), 125); + }); +}); +``` diff --git a/2-ui/1-document/11-modifying-document/11-append-to-list/solution.md b/2-ui/1-document/11-modifying-document/11-append-to-list/solution.md new file mode 100644 index 00000000..a7b703e7 --- /dev/null +++ b/2-ui/1-document/11-modifying-document/11-append-to-list/solution.md @@ -0,0 +1,6 @@ + +There are many possible solutions here. + +For instance: + +- `one.insertAdjacentHTML('afterend', '
  • 2
  • 3
  • ')` diff --git a/2-ui/1-document/11-modifying-document/11-append-to-list/task.md b/2-ui/1-document/11-modifying-document/11-append-to-list/task.md new file mode 100644 index 00000000..543cd3e4 --- /dev/null +++ b/2-ui/1-document/11-modifying-document/11-append-to-list/task.md @@ -0,0 +1,14 @@ +importance: 5 + +--- + +# Insert the HTML in the list + +Write the code to insert `
  • 2
  • 3
  • ` between two `
  • ` here: + +```html + +``` diff --git a/2-ui/1-document/11-modifying-document/12-sort-table/solution.md b/2-ui/1-document/11-modifying-document/12-sort-table/solution.md new file mode 100644 index 00000000..25dd58b0 --- /dev/null +++ b/2-ui/1-document/11-modifying-document/12-sort-table/solution.md @@ -0,0 +1,19 @@ +The solution is short, yet may look a bit tricky, so here I provide it with extensive comments: + + +```js +let sortedRows = Array.from(table.rows) + .slice(1) + .sort((rowA, rowB) => rowA.cells[0].innerHTML > rowB.cells[0].innerHTML ? 1 : -1); + +table.tBodies[0].append(...sortedRows); +``` + +1. Get all ``, like `table.querySelectorAll('tr')`, then make an array from them, cause we need array methods. +2. The first TR (`table.rows[0]`) is actually a table header, so we take the rest by `.slice(1)`. +3. Then sort them comparing by the content of the first `` (the name field). +4. Now insert nodes in the right order by `.append(...sortedRows)`. + + Tables always have an implicit element, so we need to take it and insert into it: a simple `table.append(...)` would fail. + + Please note: we don't have to remove them, just "re-insert", they leave the old place automatically. diff --git a/2-ui/1-document/11-modifying-document/12-sort-table/solution.view/index.html b/2-ui/1-document/11-modifying-document/12-sort-table/solution.view/index.html new file mode 100644 index 00000000..81e98574 --- /dev/null +++ b/2-ui/1-document/11-modifying-document/12-sort-table/solution.view/index.html @@ -0,0 +1,37 @@ + + + + + + + + + + + + + + + + + + + + + + + + + +
    NameSurnameAge
    JohnSmith10
    PeteBrown15
    AnnLee5
    + + + + + diff --git a/2-ui/1-document/11-modifying-document/12-sort-table/source.view/index.html b/2-ui/1-document/11-modifying-document/12-sort-table/source.view/index.html new file mode 100644 index 00000000..e41eb229 --- /dev/null +++ b/2-ui/1-document/11-modifying-document/12-sort-table/source.view/index.html @@ -0,0 +1,33 @@ + + + + + + + + + + + + + + + + + + + + + + + + + +
    NameSurnameAge
    JohnSmith10
    PeteBrown15
    AnnLee5
    + + + + + diff --git a/2-ui/1-document/11-modifying-document/12-sort-table/task.md b/2-ui/1-document/11-modifying-document/12-sort-table/task.md new file mode 100644 index 00000000..41d6fca2 --- /dev/null +++ b/2-ui/1-document/11-modifying-document/12-sort-table/task.md @@ -0,0 +1,39 @@ +importance: 5 + +--- + +# Sort the table + +There's a table: + + + + + + + + + + + + + + + + + + + + + + + + + + + +
    NameSurnameAge
    JohnSmith10
    PeteBrown15
    AnnLee5
    .........
    + +There may be more rows in it. + +Write the code to sort it by the `"name"` column. diff --git a/2-ui/1-document/11-modifying-document/8-tree-count/solution.view/index.html b/2-ui/1-document/11-modifying-document/8-tree-count/solution.view/index.html index f720f877..54d683ee 100644 --- a/2-ui/1-document/11-modifying-document/8-tree-count/solution.view/index.html +++ b/2-ui/1-document/11-modifying-document/8-tree-count/solution.view/index.html @@ -49,7 +49,6 @@ // добавить кол-во детей к текстовому узлу li.firstChild.data += ' [' + childCount + ']'; - } 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 index 8ceb2f99..d6343bf3 100644 --- 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 @@ -2,7 +2,7 @@ importance: 5 --- -# Дерево +# Show descendants in a tree There's a tree organized as nested `ul/li`. diff --git a/2-ui/1-document/11-modifying-document/article.md b/2-ui/1-document/11-modifying-document/article.md index 772ccefa..8c54dd03 100644 --- a/2-ui/1-document/11-modifying-document/article.md +++ b/2-ui/1-document/11-modifying-document/article.md @@ -394,6 +394,54 @@ Let's make our message to disappear after a second: ``` +## A word about "document.write" + +There's one more, quite ancient method of adding something to a web-page: `document.write`. + +The syntax: + +```html run +

    Somewhere in the page...

    +*!* + +*/!* +

    The end

    +``` + +The call to `document.write(html)` writes the `html` into page "right here and now". The `html` string can be dynamically generated, so it's kind of flexible. + +The method comes from times when there were no DOM, no standards... Really old times. It still lives, because there are scripts using it. + +In modern scripts we can rarely see it, because of the important limitation. + +**The call to `document.write` only works while the page is loading.** + +If we call it after it, the existing document will be erased. + +For instance: + +```html run +

    After one second the contents of this page will be replaced...

    +*!* + +*/!* +``` + +The method `document.write` works at the "reading HTML" phase. It appends something to the page and the browser consumes it along with the rest of HTML. + +So it's kind of unusable at "after loaded" stage, unlike other DOM methods we covered above. + +That was the downside. + +The upside -- it works blazingly fast, because it writes directly into the text, without interfering with complex DOM structures. + +So if we need to add a lot of text into HTML dynamically, and we're at page loading phase, and the speed matters, it may help. But in practice that's a really rare use case. Mostly we can see this method in scripts just because they are old. + ## Summary Methods to create new nodes: @@ -429,3 +477,8 @@ Insertion and removal of nodes: - `"afterend"` -- insert `html` right after `elem`. Also there are similar methods `elem.insertAdjacentText` and `elem.insertAdjacentElement`, they insert text strings and elements, but they are rarely used. + +- To append HTML to the page before it has finished loading: + - `document.write(html)` + + After the page is loaded such call erases the document. Mostly seen in old scripts. diff --git a/2-ui/1-document/14-styles-and-classes/1-round-button-javascript/solution.md b/2-ui/1-document/14-styles-and-classes/1-round-button-javascript/solution.md new file mode 100644 index 00000000..204d4c0c --- /dev/null +++ b/2-ui/1-document/14-styles-and-classes/1-round-button-javascript/solution.md @@ -0,0 +1,41 @@ +Есть два варианта. + +1. Можно использовать свойство `elem.style.cssText` и присвоить стиль в текстовом виде. При этом все присвоенные ранее свойства `elem.style` будут удалены. +2. Можно назначить подсвойства `elem.style` одно за другим. Этот способ более безопасен, т.к. меняет только явно присваемые свойства. + +Мы выберем второй путь. + +**Описание CSS-свойств:** + +```css +.button { + -moz-border-radius: 8px; + -webkit-border-radius: 8px; + border-radius: 8px; + border: 2px groove green; + display: block; + height: 30px; + line-height: 30px; + width: 100px; + text-decoration: none; + text-align: center; + color: red; + font-weight: bold; +} +``` + +`*-border-radius` +: Добавляет скругленные углы. Свойство присваивается в вариантах для Firefox `-moz-...`, Chrome/Safari `-webkit-...` и стандартное CSS3-свойство для тех, кто его поддерживает (Opera). + +`display` +: По умолчанию, у `A` это свойство имеет значение `display: inline`. + +`height`, `line-height` +: Устанавливает высоту и делает текст вертикально центрированным путем установки `line-height` в значение, равное высоте. Такой способ центрирования текста работает, если он состоит из одной строки. + +`text-align` +: Центрирует текст горизонтально. + +`color`, `font-weight` +: Делает текст красным и жирным. + diff --git a/2-ui/1-document/14-styles-and-classes/1-round-button-javascript/solution.view/index.html b/2-ui/1-document/14-styles-and-classes/1-round-button-javascript/solution.view/index.html new file mode 100755 index 00000000..bf487e59 --- /dev/null +++ b/2-ui/1-document/14-styles-and-classes/1-round-button-javascript/solution.view/index.html @@ -0,0 +1,40 @@ + + + + + + + + + +
    + Кнопка: + +
    + + + + + + + \ No newline at end of file diff --git a/2-ui/1-document/14-styles-and-classes/1-round-button-javascript/source.view/index.html b/2-ui/1-document/14-styles-and-classes/1-round-button-javascript/source.view/index.html new file mode 100755 index 00000000..3492198b --- /dev/null +++ b/2-ui/1-document/14-styles-and-classes/1-round-button-javascript/source.view/index.html @@ -0,0 +1,22 @@ + + + + + + + + + +
    + Кнопка: + +
    + + + + + + + \ No newline at end of file diff --git a/2-ui/1-document/14-styles-and-classes/1-round-button-javascript/task.md b/2-ui/1-document/14-styles-and-classes/1-round-button-javascript/task.md new file mode 100644 index 00000000..7dcc06a4 --- /dev/null +++ b/2-ui/1-document/14-styles-and-classes/1-round-button-javascript/task.md @@ -0,0 +1,33 @@ +importance: 3 + +--- + +# Скругленая кнопка со стилями из JavaScript + +Создайте кнопку в виде элемента `` с заданным стилем, используя JavaScript. + +В примере ниже такая кнопка создана при помощи HTML/CSS. В вашем решении кнопка должна создаваться, настраиваться и добавляться в документ при помощи *только JavaScript*, без тегов ` + +Нажми меня +``` + +**Проверьте себя: вспомните, что означает каждое свойство. В чём состоит эффект его появления здесь?** + diff --git a/2-ui/1-document/14-styles-and-classes/2-create-notification/solution.md b/2-ui/1-document/14-styles-and-classes/2-create-notification/solution.md new file mode 100644 index 00000000..e69de29b diff --git a/2-ui/1-document/14-styles-and-classes/2-create-notification/solution.view/index.css b/2-ui/1-document/14-styles-and-classes/2-create-notification/solution.view/index.css new file mode 100755 index 00000000..b21a80be --- /dev/null +++ b/2-ui/1-document/14-styles-and-classes/2-create-notification/solution.view/index.css @@ -0,0 +1,14 @@ +.notification { + position: fixed; + z-index: 1000; + padding: 5px; + border: 1px solid black; + font: normal 20px Georgia; + background: white; + text-align: center; +} + +.welcome { + background: red; + color: yellow; +} \ No newline at end of file diff --git a/2-ui/1-document/14-styles-and-classes/2-create-notification/solution.view/index.html b/2-ui/1-document/14-styles-and-classes/2-create-notification/solution.view/index.html new file mode 100755 index 00000000..07ba7a03 --- /dev/null +++ b/2-ui/1-document/14-styles-and-classes/2-create-notification/solution.view/index.html @@ -0,0 +1,65 @@ + + + + + + + + + + +

    Уведомление

    + +

    + Lorem ipsum dolor sit amet, consectetur adipisicing elit. Dolorum aspernatur quam ex eaque inventore quod voluptatem adipisci omnis nemo nulla fugit iste numquam ducimus cumque minima porro ea quidem maxime necessitatibus beatae labore soluta voluptatum + magnam consequatur sit laboriosam velit excepturi laborum sequi eos placeat et quia deleniti? Corrupti velit impedit autem et obcaecati fuga debitis nemo ratione iste veniam amet dicta hic ipsam unde cupiditate incidunt aut iure ipsum officiis soluta + temporibus. Tempore dicta ullam delectus numquam consectetur quisquam explicabo culpa excepturi placeat quo sequi molestias reprehenderit hic at nemo cumque voluptates quidem repellendus maiores unde earum molestiae ad. +

    + + + + + + + \ No newline at end of file diff --git a/2-ui/1-document/14-styles-and-classes/2-create-notification/source.view/index.css b/2-ui/1-document/14-styles-and-classes/2-create-notification/source.view/index.css new file mode 100755 index 00000000..b21a80be --- /dev/null +++ b/2-ui/1-document/14-styles-and-classes/2-create-notification/source.view/index.css @@ -0,0 +1,14 @@ +.notification { + position: fixed; + z-index: 1000; + padding: 5px; + border: 1px solid black; + font: normal 20px Georgia; + background: white; + text-align: center; +} + +.welcome { + background: red; + color: yellow; +} \ No newline at end of file diff --git a/2-ui/1-document/14-styles-and-classes/2-create-notification/source.view/index.html b/2-ui/1-document/14-styles-and-classes/2-create-notification/source.view/index.html new file mode 100755 index 00000000..dd184fce --- /dev/null +++ b/2-ui/1-document/14-styles-and-classes/2-create-notification/source.view/index.html @@ -0,0 +1,50 @@ + + + + + + + + + + +

    Уведомление

    + +

    + Lorem ipsum dolor sit amet, consectetur adipisicing elit. Dolorum aspernatur quam ex eaque inventore quod voluptatem adipisci omnis nemo nulla fugit iste numquam ducimus cumque minima porro ea quidem maxime necessitatibus beatae labore soluta voluptatum + magnam consequatur sit laboriosam velit excepturi laborum sequi eos placeat et quia deleniti? Corrupti velit impedit autem et obcaecati fuga debitis nemo ratione iste veniam amet dicta hic ipsam unde cupiditate incidunt aut iure ipsum officiis soluta + temporibus. Tempore dicta ullam delectus numquam consectetur quisquam explicabo culpa excepturi placeat quo sequi molestias reprehenderit hic at nemo cumque voluptates quidem repellendus maiores unde earum molestiae ad. +

    + +

    В CSS есть готовый класс notification, который можно ставить уведомлению.

    + + + + + + + \ No newline at end of file diff --git a/2-ui/1-document/14-styles-and-classes/2-create-notification/task.md b/2-ui/1-document/14-styles-and-classes/2-create-notification/task.md new file mode 100644 index 00000000..70eba7ed --- /dev/null +++ b/2-ui/1-document/14-styles-and-classes/2-create-notification/task.md @@ -0,0 +1,41 @@ +importance: 5 + +--- + +# Создать уведомление + +Напишите функцию `showNotification(options)`, которая показывает уведомление, пропадающее через 1.5 сек. + +Описание функции: + +```js +/** + * Показывает уведомление, пропадающее через 1.5 сек + * + * @param options.top {number} вертикальный отступ, в px + * @param options.right {number} правый отступ, в px + * @param options.cssText {string} строка стиля + * @param options.className {string} CSS-класс + * @param options.html {string} HTML-текст для показа + */ +function showNotification(options) { + // ваш код +} +``` + +Пример использования: + +```js +// покажет элемент с текстом "Привет" и классом welcome справа-сверху окна +showNotification({ + top: 10, + right: 10, + html: "Привет", + className: "welcome" +}); +``` + +[demo src="solution"] + +Элемент уведомления должен иметь CSS-класс `notification`, к которому добавляется класс из `options.className`, если есть. Исходный документ содержит готовые стили. + diff --git a/2-ui/1-document/14-styles-and-classes/article.md b/2-ui/1-document/14-styles-and-classes/article.md new file mode 100644 index 00000000..3452874c --- /dev/null +++ b/2-ui/1-document/14-styles-and-classes/article.md @@ -0,0 +1,295 @@ +# Styles and classes + +Before we get to Javascript ways of dealing with styles and classes -- here's an important rule. + +There are generally two ways to style an element, both in HTML and Javascript: + +1. Create a class in CSS and add it: `
    ` +2. Write properties directly into `style`: `
    `. + +[cut] + +CSS is always the preferred way, both in HTML and Javascript. We should only use `style` if classes "can't handle it". + +For instance, `style` is acceptable if we calculated coordinates for an element dynamically and want to set them from Javascript, like here: + +```js +let top = /* complex calculations */; +let left = /* complex calculations */; +elem.style.left = left; // e.g '123px' +elem.style.top = top; // e.g '456px' +``` + +For other cases, like making the text red, adding a background icon -- describe that in CSS and then apply the class. That's more flexible and easier to support. + +## className and classList + +Changing a class is one of the most often actions in scripts. + +In the ancient time, there was a limitation in Javascript: a reserved word like `"class"` could not be an object property. That limitation does not exist now, but at that time it was impossible to use `elem.class`. + +So instead of `elem.class` we have `elem.className` property. It's the string with all classes, the same value as in the `"class"` attribute. + +For instance: + +```html run + + + +``` + +Adding/removing a class is a widespread operation. Using a string for such purpose is cumbersome, so there's another property for that: `elem.classList`. + +The `elem.classList` is a special object with methods to `add/remove/toggle` classes. + +For instance: + +```html run + + + +``` + +So we can operate both on the full class string using `className` or on individual classes using `classList`. What we choose depends on our needs. + +Methods of `classList`: + +- `elem.classList.add/remove("class")` -- adds/removes the class. +- `elem.classList.toggle("class")` -- if the class exists, then removes it, otherwise adds it. +- `elem.classList.contains("class")` -- returns `true/false`, checks for the given class. + +Besides that, `classList` is iterable, so we can list all classes like this: + +```html run + + + +``` + +## Element style + +The property `elem.style` is an object that corresponds to what's written in the `"style"` attribute. Setting `elem.style.width="100px"` works as if we had in the attribute `style="width:100px"`. + +For multi-word property the camelCase is used: + +```js no-beautify +background-color => elem.style.backgroundColor +z-index => elem.style.zIndex +border-left-width => elem.style.borderLeftWidth +``` + +For instance: + +```js run +document.body.style.backgroundColor = prompt('background color?', 'green'); +``` + +````smart header="Prefixed properties" +Browser-prefixed properties like `-moz-border-radius`, `-webkit-border-radius` also follow the same rule, for instance: + +```js +button.style.MozBorderRadius = '5px'; +button.style.WebkitBorderRadius = '5px'; +``` + +That is: a dash `"-"` becomes an uppercase. +```` + +## Resetting the style + +To "reset" the style property, we should assign an empty line to it. For instance, if we set a `width` and now want to remove it, then `elem.style.width=""`. + +For instance, to hide an element, we can set `elem.style.display = "none"`. + +And to show it back, we should not set another `display` like `elem.style.display = "block"`. To return the "default" `display`: `elem.style.display = ""`. + +```js run +// if we run this code, the would "blink" +document.body.style.display = "none"; + +setTimeout(() => document.body.style.display = "", 1000); +``` + +If we set `display` to an empty string, then the browser applies CSS classes and its built-in styles normally, as if there were no such `style` property. + +````smart header="Full rewrite with `style.cssText`" +Normally, `style.*` assign individual style properties. We can't set the full style like `div.style="color: red; width: 100px"`, because `div.style` is an object. + +To set the full style as a string, there's a special property `style.cssText`: + +```html run +
    Button
    + + +``` + +We rarely use it, because such a setting removes all existing styles: not adds, but rather replaces them. But still can be done for new elements when we know we don't delete something important. + +The same can be accomplished by setting an attribute: `div.setAttribute('style', "color: red...")`. +```` + +## Mind the units + +CSS units must exist in values. We should not set `elem.style.top` to `10`, but rather to `10px`. Otherwise it wouldn't work. + +For instance: + +```html run height=100 + + + +``` + +Please note how the browser "unpacks" the property `style.margin` and infers `style.marginLeft` and `style.marginTop` (and other partial margins) from it. + +## Computed styles: getComputedStyle + +Modifying a style is easy. But how to *read* it? + +For instance, we want to know the size, margins, the color of an element. How to do it? + +**The `style` property contains only the style in the `"style"` attribute, without any CSS cascade.** + +So we can't read anything that comes from CSS classes. + +For instance, here `style` won't see the margin: + +```html run height=60 no-beautify + + + + + + The red text + + +``` + +...But what if we need, say, increase the margin by 20px? We want the current value for that. + +There's another method for that: `getComputedStyle`. + +The syntax is: + +```js +getComputedStyle(element[, pseudo]) +``` + +element +: Element to read the value for. + +pseudo +: A pseudo-element if required, for instance `::before`. An empty string or no argument mean the element itself. + +The result is an object with style properties, like `elem.style`, but now with respect to all CSS classes. + +For instance: + +```html run height=100 + + + + + + + + +``` + +```smart header="Computed and resolved values" +There are two concepts in [CSS](https://drafts.csswg.org/cssom/#resolved-values): + +1. A *computed* style value is the one after all CSS rules and CSS inheritance is applied. If can look like `width: auto` or `font-size: 125%`. +2. A *resolved* style value is the one finally applied to the element. The browser takes the computed value and makes all units fixed and absolute, for instance: `width: 212px` or `font-size: 16px`. In some browsers values can have a floating point. + +Long time ago `getComputedStyle` was created to get computed values, but it turned out that resolved values are much more convenient. + +So nowadays `getComputedStyle` actually returns the final, resolved value. +``` + +````warn header="`getComputedStyle` requires the full property name" +We should always ask for the exact property that we want, like `paddingLeft` or `marginTop` or `borderTopWidth`. Otherwise the correct result is not guaranteed. + +For instance, if properties `paddingLeft/paddingTop` come from the different CSS classes, then what should we get for `getComputedStyle(elem).padding`? + +Some browsers (Chrome) show `10px` in the document below, and some of them (Firefox) -- do not: + +```html run + + +``` +```` + +```smart header="\"Visited\" links styles are hidden!" +Visited links may be colored using `:visited` CSS pseudoclass. + +But `getComputedStyle` does not give access to that color, because otherwise an arbitrary page could find out whether the user visited a link by creating it on the page and checking the styles. + +Javascript we may not see the styles applied by `:visited`. And also, there's a limitation in CSS that forbids to apply geometry-changing styles in `:visited`. That's to guarantee that there's no side way for an evil page to see if a link was visited and hence to break the privacy. +``` + +## Summary + +To manage classes, there are two DOM properties: +- `className` -- the string value, good to manage the whole set of classes. +- `classList` -- the object with methods `add/remove/toggle/contains`, good for individual classes. + +To change the styles: + +- The `style` property is an object with camelCased styles. Reading and writing to it has the same meaning as modifying individual properties in the `"style"` attribute. To see how to apply `important` and other rare stuff -- there's a list of methods at [MDN](mdn:api/CSSStyleDeclaration). + +- The `style.cssText` property corresponds to the whole `"style"` attribute, the full string of styles. + +To read the resolved styles (after all CSS is applied and final values are calculated): + +- The `getComputedStyles(elem[, pseudo])` returns the style-like object with them. Read-only. diff --git a/2-ui/1-document/14-styles-and-classes/getiecomputedstyle.view/getiecomputedstyle.js b/2-ui/1-document/14-styles-and-classes/getiecomputedstyle.view/getiecomputedstyle.js new file mode 100644 index 00000000..12a7e04c --- /dev/null +++ b/2-ui/1-document/14-styles-and-classes/getiecomputedstyle.view/getiecomputedstyle.js @@ -0,0 +1,18 @@ +function getIEComputedStyle(elem, prop) { + var value = elem.currentStyle[prop] || 0; + + // we use 'left' property as a place holder so backup values + var leftCopy = elem.style.left; + var runtimeLeftCopy = elem.runtimeStyle.left; + + // assign to runtimeStyle and get pixel value + elem.runtimeStyle.left = elem.currentStyle.left; + elem.style.left = (prop === "fontSize") ? "1em" : value; + value = elem.style.pixelLeft + "px"; + + // restore values for left + elem.style.left = leftCopy; + elem.runtimeStyle.left = runtimeLeftCopy; + + return value; +} \ No newline at end of file diff --git a/2-ui/1-document/14-styles-and-classes/getiecomputedstyle.view/index.html b/2-ui/1-document/14-styles-and-classes/getiecomputedstyle.view/index.html new file mode 100644 index 00000000..a757f39f --- /dev/null +++ b/2-ui/1-document/14-styles-and-classes/getiecomputedstyle.view/index.html @@ -0,0 +1,30 @@ + + + + + + + + + + + + +
    Тестовый элемент с margin 1%
    + + + + + \ No newline at end of file diff --git a/2-ui/1-document/5-searching-elements-dom/2-tree-info/solution.md b/2-ui/1-document/5-searching-elements-dom/2-tree-info/solution.md index 615c88d7..5bb2effa 100644 --- a/2-ui/1-document/5-searching-elements-dom/2-tree-info/solution.md +++ b/2-ui/1-document/5-searching-elements-dom/2-tree-info/solution.md @@ -1,18 +1,19 @@ -Сделаем цикл по узлам `
  • `: +Let's make a loop over `
  • `: ```js -var lis = document.getElementsByTagName('li'); - -for (i = 0; i < lis.length; i++) { +for (let li of document.querySelector('li')) { ... } ``` -В цикле для каждого `lis[i]` можно получить текст, используя свойство `firstChild`. Ведь первым в `
  • ` является как раз текстовый узел, содержащий текст названия. +In the loop we need to get the text inside every `li`. We can read it directly from the first child node, that is the text node: -Также можно получить количество потомков, используя `lis[i].getElementsByTagName('li')`. +```js +for (let li of document.querySelector('li')) { + let title = li.firstChild.data; -Напишите код с этой подсказкой. - -Если уж не выйдет -- тогда откройте решение. + // title is the text in
  • before any other nodes +} +``` +Then we can get the number of descendants `li.getElementsByTagName('li')`. diff --git a/2-ui/1-document/5-searching-elements-dom/2-tree-info/solution.view/index.html b/2-ui/1-document/5-searching-elements-dom/2-tree-info/solution.view/index.html index e9b5d644..d712bb9d 100644 --- a/2-ui/1-document/5-searching-elements-dom/2-tree-info/solution.view/index.html +++ b/2-ui/1-document/5-searching-elements-dom/2-tree-info/solution.view/index.html @@ -1,44 +1,38 @@ - - - - - - - \ No newline at end of file + diff --git a/2-ui/1-document/5-searching-elements-dom/2-tree-info/source.view/index.html b/2-ui/1-document/5-searching-elements-dom/2-tree-info/source.view/index.html index 2f45460c..fbfacaa8 100644 --- a/2-ui/1-document/5-searching-elements-dom/2-tree-info/source.view/index.html +++ b/2-ui/1-document/5-searching-elements-dom/2-tree-info/source.view/index.html @@ -1,44 +1,38 @@ - - - - - - - \ No newline at end of file + diff --git a/2-ui/1-document/5-searching-elements-dom/2-tree-info/task.md b/2-ui/1-document/5-searching-elements-dom/2-tree-info/task.md index c1fdc1db..f2d9edc6 100644 --- a/2-ui/1-document/5-searching-elements-dom/2-tree-info/task.md +++ b/2-ui/1-document/5-searching-elements-dom/2-tree-info/task.md @@ -2,14 +2,13 @@ importance: 5 --- -# Дерево +# Count descendants -Есть дерево из тегов `