up
This commit is contained in:
parent
5ef1b92e8b
commit
d7d25f4d8b
36 changed files with 1239 additions and 25 deletions
|
@ -0,0 +1,18 @@
|
|||
Answer: **1 and 3**.
|
||||
|
||||
Both commands result in adding `text` "as text" into the `elem`.
|
||||
|
||||
Here's an example:
|
||||
|
||||
```html run height=80
|
||||
<div id="elem1"></div>
|
||||
<div id="elem2"></div>
|
||||
<div id="elem3"></div>
|
||||
<script>
|
||||
let text = '<b>text</b>';
|
||||
|
||||
elem1.append(document.createTextNode(text));
|
||||
elem2.textContent = text;
|
||||
elem3.innerHTML = text;
|
||||
</script>
|
||||
```
|
|
@ -0,0 +1,13 @@
|
|||
importance: 5
|
||||
|
||||
---
|
||||
|
||||
# createTextNode vs innerHTML vs textContent
|
||||
|
||||
We have an empty DOM element `elem` and a string `text`.
|
||||
|
||||
Which of these 3 commands do exactly the same?
|
||||
|
||||
1. `elem.append(document.createTextNode(text))`
|
||||
2. `elem.innerHTML = text`
|
||||
3. `elem.textContent = text`
|
|
@ -0,0 +1,53 @@
|
|||
First, let's make HTML/CSS.
|
||||
|
||||
Each component of the time would look great in its own `<span>`:
|
||||
|
||||
```html
|
||||
<div id="clock">
|
||||
<span class="hour">hh</span>:<span class="min">mm</span>:<span class="sec">ss</span>
|
||||
</div>
|
||||
```
|
||||
|
||||
Also we'll need CSS to color them.
|
||||
|
||||
The `update` function will refresh the clock, to be called by `setInterval` every second:
|
||||
|
||||
```js
|
||||
function update() {
|
||||
let clock = document.getElementById('clock');
|
||||
*!*
|
||||
let date = new Date(); // (*)
|
||||
*/!*
|
||||
let hours = date.getHours();
|
||||
if (hours < 10) hours = '0' + hours;
|
||||
clock.children[0].innerHTML = hours;
|
||||
|
||||
let minutes = date.getMinutes();
|
||||
if (minutes < 10) minutes = '0' + minutes;
|
||||
clock.children[1].innerHTML = minutes;
|
||||
|
||||
let seconds = date.getSeconds();
|
||||
if (seconds < 10) seconds = '0' + seconds;
|
||||
clock.children[2].innerHTML = seconds;
|
||||
}
|
||||
```
|
||||
|
||||
In the line `(*)` we every time check the current date. The calls to `setInterval` are not reliable: they may happen with delays.
|
||||
|
||||
The clock-managing functions:
|
||||
|
||||
```js
|
||||
let timerId;
|
||||
|
||||
function clockStart() { // run the clock
|
||||
timerId = setInterval(update, 1000);
|
||||
update(); // (*)
|
||||
}
|
||||
|
||||
function clockStop() {
|
||||
clearInterval(timerId);
|
||||
timerId = null;
|
||||
}
|
||||
```
|
||||
|
||||
Please note that the call to `update()` is not only scheduled in `clockStart()`, but immediately run in the line `(*)`. Otherwise the visitor would have to wait till the first execution of `setInterval`. And the clock would be empty till then.
|
|
@ -0,0 +1,58 @@
|
|||
<!DOCTYPE HTML>
|
||||
<html>
|
||||
<head>
|
||||
<style>
|
||||
.hour {
|
||||
color: red
|
||||
}
|
||||
|
||||
.min {
|
||||
color: green
|
||||
}
|
||||
|
||||
.sec {
|
||||
color: blue
|
||||
}
|
||||
</style>
|
||||
</head>
|
||||
|
||||
<body>
|
||||
|
||||
<div id="clock">
|
||||
<span class="hour">hh</span>:<span class="min">mm</span>:<span class="sec">ss</span>
|
||||
</div>
|
||||
|
||||
<script>
|
||||
let timerId;
|
||||
|
||||
function update() {
|
||||
let clock = document.getElementById('clock');
|
||||
let date = new Date();
|
||||
|
||||
let hours = date.getHours();
|
||||
if (hours < 10) hours = '0' + hours;
|
||||
clock.children[0].innerHTML = hours;
|
||||
|
||||
let minutes = date.getMinutes();
|
||||
if (minutes < 10) minutes = '0' + minutes;
|
||||
clock.children[1].innerHTML = minutes;
|
||||
|
||||
let seconds = date.getSeconds();
|
||||
if (seconds < 10) seconds = '0' + seconds;
|
||||
clock.children[2].innerHTML = seconds;
|
||||
}
|
||||
|
||||
function clockStart() {
|
||||
timerId = setInterval(update, 1000);
|
||||
update(); // <-- start right now, don't wait 1 second till the first setInterval works
|
||||
}
|
||||
|
||||
function clockStop() {
|
||||
clearInterval(timerId);
|
||||
}
|
||||
|
||||
clockStart();
|
||||
</script>
|
||||
|
||||
</body>
|
||||
</html>
|
|
@ -0,0 +1,12 @@
|
|||
<!DOCTYPE HTML>
|
||||
<html>
|
||||
<body>
|
||||
|
||||
<!-- click on this button calls clockStart() -->
|
||||
<input type="button" onclick="clockStart()" value="Start">
|
||||
|
||||
<!-- click on this button calls clockStop() -->
|
||||
<input type="button" onclick="clockStop()" value="Stop">
|
||||
|
||||
</body>
|
||||
</html>
|
|
@ -0,0 +1,9 @@
|
|||
importance: 4
|
||||
|
||||
---
|
||||
|
||||
# Colored clock with setInterval
|
||||
|
||||
Create a colored clock like here:
|
||||
|
||||
[iframe src="solution" height=100]
|
|
@ -0,0 +1,32 @@
|
|||
|
||||
First, let's see how not to do it:
|
||||
|
||||
```js
|
||||
function clear(elem) {
|
||||
for (let i=0; i < elem.childNodes.length; i++) {
|
||||
elem.childNodes[i].remove();
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
That won't work, because the call to `remove()` shifts the collection `elem.childNodes` every time, so elements every time start from index `0`. So `i` should not increase in the loop at all.
|
||||
|
||||
The `for..of` loop also does the same.
|
||||
|
||||
The right variant would be:
|
||||
|
||||
```js
|
||||
function clear(elem) {
|
||||
while (elem.firstChild) {
|
||||
elem.firstChild.remove();
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
And also there's a simpler variant:
|
||||
|
||||
```js
|
||||
function clear(elem) {
|
||||
elem.innerHTML = '';
|
||||
}
|
||||
```
|
20
2-ui/1-document/11-modifying-document/4-clear-elem/task.md
Normal file
20
2-ui/1-document/11-modifying-document/4-clear-elem/task.md
Normal file
|
@ -0,0 +1,20 @@
|
|||
importance: 5
|
||||
|
||||
---
|
||||
|
||||
# clear
|
||||
|
||||
Create a function `clear(elem)` that removes everything from element.
|
||||
|
||||
```html run
|
||||
<ol id="elem">
|
||||
<li>Hello</li>
|
||||
<li>World</li>
|
||||
</ol>
|
||||
|
||||
<script>
|
||||
function clear(elem) { /* your code */ }
|
||||
|
||||
clear(elem); // clears the list
|
||||
</script>
|
||||
```
|
|
@ -0,0 +1,5 @@
|
|||
The HTML in the task is incorrect. That's the matter. There may be no text inside the `<table>`, only table-specific tags.
|
||||
|
||||
The question can be easily solved by exploring the DOM in the browser tools. Then we'll see that the browser placed the text `"aaa"` *before* the table.
|
||||
|
||||
The HTML standard thoroughly specifies how to process bad HTML, and the behavior of the browser here is correct.
|
23
2-ui/1-document/11-modifying-document/5-why-aaa/task.md
Normal file
23
2-ui/1-document/11-modifying-document/5-why-aaa/task.md
Normal file
|
@ -0,0 +1,23 @@
|
|||
importance: 1
|
||||
|
||||
---
|
||||
|
||||
# Why "ааа" remains?
|
||||
|
||||
Run the example. Why `table.remove()` does not delete the text `"aaa"`?
|
||||
|
||||
```html height=100 run
|
||||
<table id="table">
|
||||
aaa
|
||||
<tr>
|
||||
<td>Test</td>
|
||||
</tr>
|
||||
</table>
|
||||
|
||||
<script>
|
||||
alert(table); // the table, as it should be
|
||||
|
||||
table.remove();
|
||||
// why there's still aaa in the document?
|
||||
</script>
|
||||
```
|
|
@ -0,0 +1 @@
|
|||
Please note using `textContent` to assign the `<li>` content.
|
24
2-ui/1-document/11-modifying-document/6-create-list/solution.view/index.html
Executable file
24
2-ui/1-document/11-modifying-document/6-create-list/solution.view/index.html
Executable file
|
@ -0,0 +1,24 @@
|
|||
<!DOCTYPE HTML>
|
||||
<html>
|
||||
<body>
|
||||
<h1>Create a list</h1>
|
||||
|
||||
<script>
|
||||
let ul = document.createElement('ul');
|
||||
document.body.append(ul);
|
||||
|
||||
while (true) {
|
||||
let data = prompt("Enter the text for the list item", "");
|
||||
|
||||
if (!data) {
|
||||
break;
|
||||
}
|
||||
|
||||
let li = document.createElement('li');
|
||||
li.textContent = data;
|
||||
ul.append(li);
|
||||
}
|
||||
</script>
|
||||
|
||||
</body>
|
||||
</html>
|
19
2-ui/1-document/11-modifying-document/6-create-list/task.md
Normal file
19
2-ui/1-document/11-modifying-document/6-create-list/task.md
Normal file
|
@ -0,0 +1,19 @@
|
|||
importance: 4
|
||||
|
||||
---
|
||||
|
||||
# Create a list
|
||||
|
||||
Write an interface to create a list from user input.
|
||||
|
||||
For every list item:
|
||||
|
||||
1. Ask a user about its content using `prompt`.
|
||||
2. Create the `<li>` with it and add it to `<ul>`.
|
||||
3. Continue until the user cancels the input (by pressing `key:Esc` or CANCEL in prompt).
|
||||
|
||||
All elements should be created dynamically.
|
||||
|
||||
If a user types HTML-tags, they should be treated like a text.
|
||||
|
||||
[demo src="solution"]
|
|
@ -0,0 +1,57 @@
|
|||
<!DOCTYPE html>
|
||||
<html>
|
||||
<body>
|
||||
|
||||
<div id="container"></div>
|
||||
|
||||
<script>
|
||||
let data = {
|
||||
"Fish": {
|
||||
"trout": {},
|
||||
"salmon": {}
|
||||
},
|
||||
|
||||
"Tree": {
|
||||
"Huge": {
|
||||
"sequoia": {},
|
||||
"oak": {}
|
||||
},
|
||||
"Flowering": {
|
||||
"redbud": {},
|
||||
"magnolia": {}
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
function createTree(container, obj) {
|
||||
container.append(createTreeDom(obj));
|
||||
}
|
||||
|
||||
function createTreeDom(obj) {
|
||||
// if there's no children, then the call returns undefined
|
||||
// and the <ul> won't be created
|
||||
if (!Object.keys(obj).length) return;
|
||||
|
||||
let ul = document.createElement('ul');
|
||||
|
||||
for (let key in obj) {
|
||||
let li = document.createElement('li');
|
||||
li.innerHTML = key;
|
||||
|
||||
let childrenUl = createTreeDom(obj[key]);
|
||||
if (childrenUl) {
|
||||
li.append(childrenUl);
|
||||
}
|
||||
|
||||
ul.append(li);
|
||||
}
|
||||
|
||||
return ul;
|
||||
}
|
||||
|
||||
let container = document.getElementById('container');
|
||||
createTree(container, data);
|
||||
</script>
|
||||
|
||||
</body>
|
||||
</html>
|
|
@ -0,0 +1,45 @@
|
|||
<!DOCTYPE html>
|
||||
<html>
|
||||
<body>
|
||||
|
||||
<div id="container"></div>
|
||||
|
||||
<script>
|
||||
let data = {
|
||||
"Fish": {
|
||||
"trout": {},
|
||||
"salmon": {}
|
||||
},
|
||||
|
||||
"Tree": {
|
||||
"Huge": {
|
||||
"sequoia": {},
|
||||
"oak": {}
|
||||
},
|
||||
"Flowering": {
|
||||
"redbud": {},
|
||||
"magnolia": {}
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
function createTree(container, obj) {
|
||||
container.innerHTML = createTreeText(obj);
|
||||
}
|
||||
|
||||
function createTreeText(obj) { // отдельная рекурсивная функция
|
||||
let li = '';
|
||||
for (let key in obj) {
|
||||
li += '<li>' + key + createTreeText(obj[key]) + '</li>';
|
||||
}
|
||||
if (li) {
|
||||
let ul = '<ul>' + li + '</ul>'
|
||||
}
|
||||
return ul || '';
|
||||
}
|
||||
|
||||
let container = document.getElementById('container');
|
||||
createTree(container, data);
|
||||
</script>
|
||||
</body>
|
||||
</html>
|
|
@ -0,0 +1,4 @@
|
|||
The easiest way to walk the object is to use recursion.
|
||||
|
||||
1. [The solution with innerHTML](sandbox:innerhtml).
|
||||
2. [The solution with DOM](sandbox:build-tree-dom).
|
|
@ -0,0 +1,68 @@
|
|||
<!DOCTYPE html>
|
||||
<html>
|
||||
|
||||
<head>
|
||||
<meta charset="utf-8">
|
||||
</head>
|
||||
|
||||
<body>
|
||||
|
||||
<div id="tree"></div>
|
||||
|
||||
<!-- The result should be:
|
||||
<div id="tree">
|
||||
<ul>
|
||||
<li>Fish
|
||||
<ul>
|
||||
<li>trout</li>
|
||||
<li>salmon</li>
|
||||
</ul>
|
||||
</li>
|
||||
<li>Trees
|
||||
<ul>
|
||||
<li>Huge
|
||||
<ul>
|
||||
<li>sequoia</li>
|
||||
<li>oak</li>
|
||||
</ul>
|
||||
</li>
|
||||
<li>Flowering
|
||||
<ul>
|
||||
<li>redbud</li>
|
||||
<li>magnolia</li>
|
||||
</ul>
|
||||
</li>
|
||||
</ul>
|
||||
</li>
|
||||
</ul>
|
||||
</div>
|
||||
-->
|
||||
|
||||
<script>
|
||||
let data = {
|
||||
"Fish": {
|
||||
"trout": {},
|
||||
"salmon": {}
|
||||
},
|
||||
|
||||
"Tree": {
|
||||
"Huge": {
|
||||
"sequoia": {},
|
||||
"oak": {}
|
||||
},
|
||||
"Flowering": {
|
||||
"redbud": {},
|
||||
"magnolia": {}
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
function createTree(container, data) {
|
||||
/* your code */
|
||||
}
|
||||
|
||||
createTree(document.getElementById('tree'), data);
|
||||
</script>
|
||||
|
||||
</body>
|
||||
</html>
|
|
@ -0,0 +1,51 @@
|
|||
importance: 5
|
||||
|
||||
---
|
||||
|
||||
# Create a tree from the object
|
||||
|
||||
Write a function `createTree` that creates a nested `ul/li` list from the nested object.
|
||||
|
||||
For instance:
|
||||
|
||||
```js
|
||||
let data = {
|
||||
"Fish": {
|
||||
"trout": {},
|
||||
"salmon": {}
|
||||
},
|
||||
|
||||
"Tree": {
|
||||
"Huge": {
|
||||
"sequoia": {},
|
||||
"oak": {}
|
||||
},
|
||||
"Flowering": {
|
||||
"redbud": {},
|
||||
"magnolia": {}
|
||||
}
|
||||
}
|
||||
};
|
||||
```
|
||||
|
||||
The syntax:
|
||||
|
||||
```js
|
||||
let container = document.getElementById('container');
|
||||
*!*
|
||||
createTree(container, data); // creates the tree in the container
|
||||
*/!*
|
||||
```
|
||||
|
||||
The result (tree) should look like this:
|
||||
|
||||
[iframe border=1 src="build-tree-dom"]
|
||||
|
||||
Choose one of two ways of solving this task:
|
||||
|
||||
1. Create the HTML for the tree and then assign to `container.innerHTML`.
|
||||
2. Create tree nodes and append with DOM methods.
|
||||
|
||||
Would be great if you could do both.
|
||||
|
||||
P.S. The tree should not have "extra" elements like empty `<ul></ul>` for the leaves.
|
|
@ -0,0 +1 @@
|
|||
To append text to each `<li>` we can alter the text node `data`.
|
|
@ -0,0 +1,57 @@
|
|||
<!DOCTYPE HTML>
|
||||
<html>
|
||||
<body>
|
||||
|
||||
<ul>
|
||||
<li>Animals
|
||||
<ul>
|
||||
<li>Mammals
|
||||
<ul>
|
||||
<li>Cows</li>
|
||||
<li>Donkeys</li>
|
||||
<li>Dogs</li>
|
||||
<li>Tigers</li>
|
||||
</ul>
|
||||
</li>
|
||||
<li>Other
|
||||
<ul>
|
||||
<li>Snakes</li>
|
||||
<li>Birds</li>
|
||||
<li>Lizards</li>
|
||||
</ul>
|
||||
</li>
|
||||
</ul>
|
||||
</li>
|
||||
<li>Fishes
|
||||
<ul>
|
||||
<li>Aquarium
|
||||
<ul>
|
||||
<li>Guppy</li>
|
||||
<li>Angelfish</li>
|
||||
</ul>
|
||||
</li>
|
||||
<li>Sea
|
||||
<ul>
|
||||
<li>Sea trout</li>
|
||||
</ul>
|
||||
</li>
|
||||
</ul>
|
||||
</li>
|
||||
</ul>
|
||||
|
||||
<script>
|
||||
let lis = document.getElementsByTagName('li');
|
||||
|
||||
for (let li of lis) {
|
||||
// получить количество детей
|
||||
let childCount = li.getElementsByTagName('li').length;
|
||||
if (!childCount) continue;
|
||||
|
||||
// добавить кол-во детей к текстовому узлу
|
||||
li.firstChild.data += ' [' + childCount + ']';
|
||||
|
||||
}
|
||||
</script>
|
||||
|
||||
</body>
|
||||
</html>
|
|
@ -0,0 +1,47 @@
|
|||
<!DOCTYPE HTML>
|
||||
<html>
|
||||
<body>
|
||||
|
||||
<ul>
|
||||
<li>Animals
|
||||
<ul>
|
||||
<li>Mammals
|
||||
<ul>
|
||||
<li>Cows</li>
|
||||
<li>Donkeys</li>
|
||||
<li>Dogs</li>
|
||||
<li>Tigers</li>
|
||||
</ul>
|
||||
</li>
|
||||
<li>Other
|
||||
<ul>
|
||||
<li>Snakes</li>
|
||||
<li>Birds</li>
|
||||
<li>Lizards</li>
|
||||
</ul>
|
||||
</li>
|
||||
</ul>
|
||||
</li>
|
||||
<li>Fishes
|
||||
<ul>
|
||||
<li>Aquarium
|
||||
<ul>
|
||||
<li>Guppy</li>
|
||||
<li>Angelfish</li>
|
||||
</ul>
|
||||
</li>
|
||||
<li>Sea
|
||||
<ul>
|
||||
<li>Sea trout</li>
|
||||
</ul>
|
||||
</li>
|
||||
</ul>
|
||||
</li>
|
||||
</ul>
|
||||
|
||||
<script>
|
||||
// ... your code ...
|
||||
</script>
|
||||
|
||||
</body>
|
||||
</html>
|
13
2-ui/1-document/11-modifying-document/8-tree-count/task.md
Normal file
13
2-ui/1-document/11-modifying-document/8-tree-count/task.md
Normal file
|
@ -0,0 +1,13 @@
|
|||
importance: 5
|
||||
|
||||
---
|
||||
|
||||
# Дерево
|
||||
|
||||
There's a tree organized as nested `ul/li`.
|
||||
|
||||
Write the code that adds to each `<li>` the number of its descendants. Skip leaves (nodes without children).
|
||||
|
||||
The result:
|
||||
|
||||
[iframe border=1 src="solution"]
|
|
@ -0,0 +1,9 @@
|
|||
We'll create the table as a string: `"<table>...</table>"`, and then assign it to `innerHTML`.
|
||||
|
||||
The algorithm:
|
||||
|
||||
1. Create the table header with `<th>` and weekday names.
|
||||
1. Create the date object `d = new Date(year, month-1)`. That's the first day of `month` (taking into account that months in JavaScript start from `0`, not `1`).
|
||||
2. First few cells till the first day of the month `d.getDay()` may be empty. Let's fill them in with `<td></td>`.
|
||||
3. Increase the day in `d`: `d.setDate(d.getDate()+1)`. If `d.getMonth()` is not yet the next month, then add the new cell `<td>` to the calendar. If that's a Sunday, then add a newline <code>"</tr><tr>"</code>.
|
||||
4. If the month has finished, but the table row is not yet full, add empty `<td>` into it, to make it square.
|
|
@ -0,0 +1,79 @@
|
|||
<!DOCTYPE HTML>
|
||||
<html>
|
||||
|
||||
<head>
|
||||
<style>
|
||||
table {
|
||||
border-collapse: collapse;
|
||||
}
|
||||
|
||||
td,
|
||||
th {
|
||||
border: 1px solid black;
|
||||
padding: 3px;
|
||||
text-align: center;
|
||||
}
|
||||
|
||||
th {
|
||||
font-weight: bold;
|
||||
background-color: #E6E6E6;
|
||||
}
|
||||
</style>
|
||||
</head>
|
||||
|
||||
<body>
|
||||
|
||||
|
||||
<div id="calendar"></div>
|
||||
|
||||
<script>
|
||||
function createCalendar(elem, year, month) {
|
||||
|
||||
let mon = month - 1; // months in JS are 0..11, not 1..12
|
||||
let d = new Date(year, mon);
|
||||
|
||||
let table = '<table><tr><th>MO</th><th>TU</th><th>WE</th><th>TH</th><th>FR</th><th>SA</th><th>SU</th></tr><tr>';
|
||||
|
||||
// spaces for the first row
|
||||
// from Monday till the first day of the month
|
||||
// * * * 1 2 3 4
|
||||
for (let i = 0; i < getDay(d); i++) {
|
||||
table += '<td></td>';
|
||||
}
|
||||
|
||||
// <td> with actual dates
|
||||
while (d.getMonth() == mon) {
|
||||
table += '<td>' + d.getDate() + '</td>';
|
||||
|
||||
if (getDay(d) % 7 == 6) { // sunday, last day of week - newline
|
||||
table += '</tr><tr>';
|
||||
}
|
||||
|
||||
d.setDate(d.getDate() + 1);
|
||||
}
|
||||
|
||||
// add spaces after last days of month for the last row
|
||||
// 29 30 31 * * * *
|
||||
if (getDay(d) != 0) {
|
||||
for (let i = getDay(d); i < 7; i++) {
|
||||
table += '<td></td>';
|
||||
}
|
||||
}
|
||||
|
||||
// close the table
|
||||
table += '</tr></table>';
|
||||
|
||||
elem.innerHTML = table;
|
||||
}
|
||||
|
||||
function getDay(date) { // get day number from 0 (monday) to 6 (sunday)
|
||||
let day = date.getDay();
|
||||
if (day == 0) day = 7; // make Sunday (0) the last day
|
||||
return day - 1;
|
||||
}
|
||||
|
||||
createCalendar(calendar, 2012, 9);
|
||||
</script>
|
||||
|
||||
</body>
|
||||
</html>
|
|
@ -0,0 +1,38 @@
|
|||
<!DOCTYPE HTML>
|
||||
<html>
|
||||
|
||||
<head>
|
||||
<style>
|
||||
table {
|
||||
border-collapse: collapse;
|
||||
}
|
||||
|
||||
td,
|
||||
th {
|
||||
border: 1px solid black;
|
||||
padding: 3px;
|
||||
text-align: center;
|
||||
}
|
||||
|
||||
th {
|
||||
font-weight: bold;
|
||||
background-color: #E6E6E6;
|
||||
}
|
||||
</style>
|
||||
</head>
|
||||
|
||||
<body>
|
||||
|
||||
|
||||
<div id="calendar"></div>
|
||||
|
||||
<script>
|
||||
function createCalendar(elem, year, month) {
|
||||
// ...your code that generates the calndar in elem...
|
||||
}
|
||||
|
||||
createCalendar(calendar, 2012, 9);
|
||||
</script>
|
||||
|
||||
</body>
|
||||
</html>
|
|
@ -0,0 +1,17 @@
|
|||
importance: 4
|
||||
|
||||
---
|
||||
|
||||
# Create a calendar
|
||||
|
||||
Write a function `createCalendar(elem, year, month)`.
|
||||
|
||||
The call should create a calendar for the given year/month and put it inside `elem`.
|
||||
|
||||
The calendar should be a table, where a week is `<tr>`, and a day is `<td>`. The table top should be `<th>` with weekday names: the first day should be Monday, and so on till Sunday.
|
||||
|
||||
For instance, `createCalendar(cal, 2012, 9)` should generate in <code><div id='cal'></div></code> the following calendar:
|
||||
|
||||
[iframe height=210 src="solution"]
|
||||
|
||||
P.S. For this task it's enough to generate the calendar, should not yet be clickable.
|
431
2-ui/1-document/11-modifying-document/article.md
Normal file
431
2-ui/1-document/11-modifying-document/article.md
Normal file
|
@ -0,0 +1,431 @@
|
|||
# Modifying DOM
|
||||
|
||||
Modifying DOM is the key to create "live" pages.
|
||||
|
||||
Here we'll see how to create new elements "on the fly" and modify the existing page content.
|
||||
|
||||
There are many methods for that. First we'll see a simple example and then explain them.
|
||||
|
||||
[cut]
|
||||
|
||||
## Example: show a message
|
||||
|
||||
For the start, let's see how to add a message on the page, that looks nicer than `alert`.
|
||||
|
||||
Here's how it will look:
|
||||
|
||||
```html autorun height="80"
|
||||
<style>
|
||||
.alert {
|
||||
padding: 15px;
|
||||
border: 1px solid #d6e9c6;
|
||||
border-radius: 4px;
|
||||
color: #3c763d;
|
||||
background-color: #dff0d8;
|
||||
}
|
||||
</style>
|
||||
|
||||
*!*
|
||||
<div class="alert">
|
||||
<strong>Hi there!</strong> You've read an important message.
|
||||
</div>
|
||||
*/!*
|
||||
```
|
||||
|
||||
Now let's create the same `div` with Javascript.
|
||||
|
||||
## Creating an element
|
||||
|
||||
|
||||
To create DOM nodes, there are two methods:
|
||||
|
||||
`document.createElement(tag)`
|
||||
: Creates a new element with the given tag:
|
||||
|
||||
```js
|
||||
let div = document.createElement('div');
|
||||
```
|
||||
|
||||
`document.createTextNode(text)`
|
||||
: Creates a new *text node* with the given text:
|
||||
|
||||
```js
|
||||
let textNode = document.createTextNode('Here I am');
|
||||
```
|
||||
|
||||
### Creating the message
|
||||
|
||||
In our case we want to make a `div`, add classes and the message into it:
|
||||
|
||||
```js
|
||||
let div = document.createElement('div');
|
||||
div.className = "alert alert-success";
|
||||
div.innerHTML = "<strong>Hi there!</strong> You've read an important message.";
|
||||
```
|
||||
|
||||
After that, we have a ready DOM element. Right now it's in the variable `div`, but not yet seen, because not inserted into the page.
|
||||
|
||||
## Insertion methods
|
||||
|
||||
To make the `div` show up, we need to insert it somewhere into `document`.
|
||||
|
||||
Let's say we want to insert it into `parentElem`, like `let parentElem=document.body`.
|
||||
|
||||
There exist following methods to insert a node:
|
||||
|
||||
`parentElem.appendChild(elem)`
|
||||
: Appends `elem` as the last child of `parentElem`.
|
||||
|
||||
The following example adds a new `<li>` to the end of `<ol>`:
|
||||
|
||||
```html run height=100
|
||||
<ol id="list">
|
||||
<li>0</li>
|
||||
<li>1</li>
|
||||
<li>2</li>
|
||||
</ol>
|
||||
|
||||
<script>
|
||||
let newLi = document.createElement('li');
|
||||
newLi.innerHTML = 'Hello, world!';
|
||||
|
||||
list.appendChild(newLi);
|
||||
</script>
|
||||
```
|
||||
|
||||
`parentElem.insertBefore(elem, nextSibling)`
|
||||
: Inserts `elem` before `nextSibling` into `parentElem`.
|
||||
|
||||
The following code inserts a new list item before the second `<li>`:
|
||||
|
||||
```html run height=100
|
||||
<ol id="list">
|
||||
<li>0</li>
|
||||
<li>1</li>
|
||||
<li>2</li>
|
||||
</ol>
|
||||
<script>
|
||||
let newLi = document.createElement('li');
|
||||
newLi.innerHTML = 'Hello, world!';
|
||||
|
||||
*!*
|
||||
list.insertBefore(newLi, list.children[1]);
|
||||
*/!*
|
||||
</script>
|
||||
```
|
||||
|
||||
To insert as the first element, we can do like this:
|
||||
|
||||
```js
|
||||
list.insertBefore(newLi, list.firstChild);
|
||||
```
|
||||
|
||||
`parentElem.replaceChild(elem, oldChild)`
|
||||
: Replaces `oldChild` with `elem` among children of `parentElem`.
|
||||
|
||||
All these methods return the inserted node. In other words, `parentElem.appendChild(elem)` returns `elem`. But usually the returned value is not used, we just run the method.
|
||||
|
||||
For our example, it would be like this:
|
||||
|
||||
```html run height="80"
|
||||
<style>
|
||||
.alert {
|
||||
padding: 15px;
|
||||
border: 1px solid #d6e9c6;
|
||||
border-radius: 4px;
|
||||
color: #3c763d;
|
||||
background-color: #dff0d8;
|
||||
}
|
||||
</style>
|
||||
|
||||
<script>
|
||||
*!*
|
||||
let div = document.createElement('div');
|
||||
div.className = "alert alert-success";
|
||||
div.innerHTML = "<strong>Hi there!</strong> You've read an important message.";
|
||||
|
||||
document.body.appendChild(div);
|
||||
*/!*
|
||||
</script>
|
||||
```
|
||||
|
||||
These methods are "old school": they exist from the ancient times and we can meet them in many old scripts.
|
||||
|
||||
Unfortunately, there are some tasks that are hard to solve with them.
|
||||
|
||||
For instance, how to insert *html* if we have it as a string? Or, given a node, how to insert something not into it, but *before* it?
|
||||
|
||||
Of course, all that is solvable, but not in an elegant way.
|
||||
|
||||
So there exist two other sets of insertion methods to handle all cases easily.
|
||||
|
||||
### prepend/append/before/after
|
||||
|
||||
This set of methods provides more flexible insertions:
|
||||
|
||||
- `node.append(...nodes or strings)` -- append nodes or strings at the end of `node`,
|
||||
- `node.prepend(...nodes or strings)` -- insert nodes or strings into the beginning of `node`,
|
||||
- `node.before(...nodes or strings)` –- insert nodes or strings before the `node`,
|
||||
- `node.after(...nodes or strings)` –- insert nodes or strings after the `node`,
|
||||
- `node.replaceWith(...nodes or strings)` –- replaces `node` with the given nodes or strings.
|
||||
|
||||
Let's say we have a list, like this:
|
||||
|
||||
```html autorun
|
||||
<ol id="ol">
|
||||
<li>0</li>
|
||||
<li>1</li>
|
||||
<li>2</li>
|
||||
</ol>
|
||||
|
||||
<script>
|
||||
ol.before('before');
|
||||
ol.after('after');
|
||||
|
||||
let prepend = document.createElement('li');
|
||||
prepend.innerHTML = 'prepend';
|
||||
ol.prepend(prepend);
|
||||
|
||||
let append = document.createElement('li');
|
||||
append.innerHTML = 'append';
|
||||
ol.append(append);
|
||||
</script>
|
||||
```
|
||||
|
||||
Here's where the insertions will go:
|
||||
|
||||

|
||||
|
||||
So the final list will be:
|
||||
|
||||
```html
|
||||
before
|
||||
<ol id="ol">
|
||||
<li>prepend</li>
|
||||
<li>0</li>
|
||||
<li>1</li>
|
||||
<li>2</li>
|
||||
<li>append</li>
|
||||
</ol>
|
||||
after
|
||||
```
|
||||
|
||||
These methods can insert a list of nodes and text pieces. But please note: all text is inserted *as text*.
|
||||
|
||||
For instance, here a string and an element are inserted:
|
||||
|
||||
```html run
|
||||
<div id="div"></div>
|
||||
<script>
|
||||
div.before('<p>Hello</p>', document.createElement('hr'));
|
||||
</script>
|
||||
```
|
||||
|
||||
The final HTML would be:
|
||||
|
||||
```html run
|
||||
*!*
|
||||
<p>Hello</p>
|
||||
*/!*
|
||||
<hr>
|
||||
<div id="div"></div>
|
||||
```
|
||||
|
||||
In other words, strings are inserted exactly "as text", in a safe way, like `elem.textContent` does it.
|
||||
|
||||
So, these methods allow to insert DOM nodes or text pieces at given places.
|
||||
|
||||
But what if we want to insert HTML "as html", with all tags and stuff working, like `elem.innerHTML` does it?
|
||||
|
||||
### insertAdjacentHTML/Text/Element
|
||||
|
||||
There's a versatile method `elem.insertAdjacentHTML(where, html)`.
|
||||
|
||||
The first parameter is a string, specifying where to insert, must be one of the following:
|
||||
|
||||
- `"beforebegin"` -- insert `html` before `elem`,
|
||||
- `"afterbegin"` -- insert `html` into `elem`, at the beginning,
|
||||
- `"beforeend"` -- insert `html` into `elem`, at the end,
|
||||
- `"afterend"` -- insert `html` after `elem`.
|
||||
|
||||
The second parameter `html` is a HTML string, inserted "as is".
|
||||
|
||||
For instance:
|
||||
|
||||
```html run
|
||||
<div id="div"></div>
|
||||
<script>
|
||||
div.insertAdjacentHTML('beforebegin', '<p>Hello</p>');
|
||||
</script>
|
||||
```
|
||||
|
||||
...Would lead to:
|
||||
|
||||
```html run
|
||||
<p>Hello</p>
|
||||
<div id="div"></div>
|
||||
```
|
||||
|
||||
That's how we can append an arbitrary HTML to our page.
|
||||
|
||||
Here's the picture of insertion variants:
|
||||
|
||||

|
||||
|
||||
We definitely can notice similarities between this and the previous picture. The insertion points are actually the same, but here we can insert HTML.
|
||||
|
||||
The method has two brothers:
|
||||
|
||||
- `elem.insertAdjacentText(where, text)` -- the same syntax, but a string of `text` in inserted "as text" instead of HTML,
|
||||
- `elem.insertAdjacentElement(where, elem)` -- the same syntax, but inserts an element.
|
||||
|
||||
They exist mainly to make the syntax "uniform". In practice, most of time only `insertAdjacentHTML` is used, because for elements and text we have methods `append/prepend/before/after` -- they are just shorter to write.
|
||||
|
||||
So here's an alternative variant of showing a message:
|
||||
|
||||
```html run
|
||||
<style>
|
||||
.alert {
|
||||
padding: 15px;
|
||||
border: 1px solid #d6e9c6;
|
||||
border-radius: 4px;
|
||||
color: #3c763d;
|
||||
background-color: #dff0d8;
|
||||
}
|
||||
</style>
|
||||
|
||||
<script>
|
||||
document.body.insertAdjacentHTML("afterbegin", `<div class="alert alert-success">
|
||||
<strong>Hi there!</strong> You've read an important message.
|
||||
</div>`);
|
||||
</script>
|
||||
```
|
||||
|
||||
## Cloning nodes: cloneNode
|
||||
|
||||
How to insert one more similar message?
|
||||
|
||||
We could do a message-generating function and put the code there. But the alternative way would be to *clone* the existing `div` and modify the text inside it.
|
||||
|
||||
Sometimes when we have a big element, that may be faster and simpler.
|
||||
|
||||
The call `elem.cloneNode(true)` creates a "deep" clone of the element -- with all attributes and subelements. If we call it with `false`, then there would be no child elements.
|
||||
|
||||
An example of copying the message:
|
||||
|
||||
```html run height="120"
|
||||
<style>
|
||||
.alert {
|
||||
padding: 15px;
|
||||
border: 1px solid #d6e9c6;
|
||||
border-radius: 4px;
|
||||
color: #3c763d;
|
||||
background-color: #dff0d8;
|
||||
}
|
||||
</style>
|
||||
|
||||
<div class="alert" id="div">
|
||||
<strong>Hi there!</strong> You've read an important message.
|
||||
</div>
|
||||
|
||||
<script>
|
||||
*!*
|
||||
let div2 = div.cloneNode(true); // clone the message
|
||||
div2.querySelector('strong').innerHTML = 'Bye there!'; // change the clone
|
||||
|
||||
div.after(div2); // show the clone after the existing div
|
||||
*/!*
|
||||
</script>
|
||||
```
|
||||
|
||||
## Removal methods
|
||||
|
||||
To remove nodes, there are following methods:
|
||||
|
||||
|
||||
`parentElem.removeChild(node)`
|
||||
: Removes `elem` from `parentElem` (assuming it's a child).
|
||||
|
||||
`node.remove()`
|
||||
: Removes the `node` from its place.
|
||||
|
||||
We can easily see that the second method is much shorter. The first one exists for historical reasons.
|
||||
|
||||
````smart
|
||||
If we want to *move* an element to another place -- there's no need to remove it from the old one.
|
||||
|
||||
**All insertion methods automatically remove the node from the old place.**
|
||||
|
||||
For instance, let's swap elements:
|
||||
|
||||
```html run height=50
|
||||
<div id="first">First</div>
|
||||
<div id="second">Second</div>
|
||||
<script>
|
||||
// no need to call remove
|
||||
second.after(first); // after second insert first
|
||||
</script>
|
||||
```
|
||||
````
|
||||
|
||||
Let's make our message to disappear after a second:
|
||||
|
||||
```html run untrusted
|
||||
<style>
|
||||
.alert {
|
||||
padding: 15px;
|
||||
border: 1px solid #d6e9c6;
|
||||
border-radius: 4px;
|
||||
color: #3c763d;
|
||||
background-color: #dff0d8;
|
||||
}
|
||||
</style>
|
||||
|
||||
<script>
|
||||
let div = document.createElement('div');
|
||||
div.className = "alert alert-success";
|
||||
div.innerHTML = "<strong>Hi there!</strong> You've read an important message.";
|
||||
|
||||
document.body.append(div);
|
||||
*!*
|
||||
setTimeout(div => div.remove(), 1000);
|
||||
// or setTimeout(div => document.body.removeChild(div), 1000);
|
||||
*/!*
|
||||
</script>
|
||||
```
|
||||
|
||||
## Summary
|
||||
|
||||
Methods to create new nodes:
|
||||
|
||||
- `document.createElement(tag)` -- creates an element with the given tag,
|
||||
- `document.createTextNode(value)` -- creates a text node (rarely used),
|
||||
- `elem.cloneNode(deep)` -- clones the element, if `deep==true` then with all descendants.
|
||||
|
||||
Insertion and removal of nodes:
|
||||
|
||||
- From the parent:
|
||||
- `parent.appendChild(elem)`
|
||||
- `parent.insertBefore(elem, nextSibling)`
|
||||
- `parent.removeChild(elem)`
|
||||
- `parent.replaceChild(newElem, elem)`
|
||||
|
||||
all thes methods return `elem`.
|
||||
|
||||
- Given a node:
|
||||
- `node.append(...nodes or strings)` -- insert into `node`, at the end,
|
||||
- `node.prepend(...nodes or strings)` -- insert into `node`, at the beginning,
|
||||
- `node.before(...nodes or strings)` –- insert right before `node`,
|
||||
- `node.after(...nodes or strings)` –- insert right after `node`,
|
||||
- `node.replaceWith(...nodes or strings)` –- replace `node`.
|
||||
- `node.remove()` –- remove the `node`.
|
||||
|
||||
All these methods accept a list of DOM nodes or text strings. Text strings are inserted "as text".
|
||||
|
||||
- To insert HTML: `elem.insertAdjacentHTML(where, html)`, inserts depending on where:
|
||||
- `"beforebegin"` -- insert `html` right before `elem`,
|
||||
- `"afterbegin"` -- insert `html` into `elem`, at the beginning,
|
||||
- `"beforeend"` -- insert `html` into `elem`, at the end,
|
||||
- `"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.
|
Binary file not shown.
After Width: | Height: | Size: 20 KiB |
Binary file not shown.
After Width: | Height: | Size: 49 KiB |
BIN
2-ui/1-document/11-modifying-document/insert-adjacent.png
Normal file
BIN
2-ui/1-document/11-modifying-document/insert-adjacent.png
Normal file
Binary file not shown.
After Width: | Height: | Size: 22 KiB |
BIN
2-ui/1-document/11-modifying-document/insert-adjacent@2x.png
Normal file
BIN
2-ui/1-document/11-modifying-document/insert-adjacent@2x.png
Normal file
Binary file not shown.
After Width: | Height: | Size: 53 KiB |
|
@ -179,13 +179,13 @@ alert( document.body.previousSibling ); // HTMLHeadElement
|
|||
|
||||
Navigation properties listed above refer to *all* nodes. For instance, in `childNodes` we can see both text nodes, element nodes, and even comment nodes if there exist.
|
||||
|
||||
But for many tasks we don't want text or comment nodes. We want to manipulate on element nodes that represent tags.
|
||||
But for many tasks we don't want text or comment nodes. We want to manipulate element nodes that represent tags and structure of the page.
|
||||
|
||||
So let's check out more navigation links that only take *element nodes* into account:
|
||||
So let's see more navigation links that only take *element nodes* into account:
|
||||
|
||||

|
||||
|
||||
The links look like those given above, just with `Element` word inside:
|
||||
The links are similar to those given above, just with `Element` word inside:
|
||||
|
||||
- `children` -- only those children that are element nodes.
|
||||
- `firstElementChild`, `lastElementChild` -- first and last element children.
|
||||
|
@ -230,26 +230,26 @@ Let's modify one of examples above: replace `childNodes` with `children`. Now it
|
|||
</html>
|
||||
```
|
||||
|
||||
## More links, tables [#dom-navigation-tables]
|
||||
## More links: tables [#dom-navigation-tables]
|
||||
|
||||
Till now we described the basic navigation properties. Certain DOM element types may provide more, specific to their type, for better convenience.
|
||||
Till now we described the basic navigation properties. Certain types of DOM elements may provide more, specific to their type, for better convenience.
|
||||
|
||||
Tables are a great example and important particular case of that.
|
||||
|
||||
`<table>` elements support these properties:
|
||||
**`<table>`** elements support these properties:
|
||||
- `table.rows` -- the collection of `<tr>` elements of the table.
|
||||
- `table.caption/tHead/tFoot` -- references to elements `<caption>`, `<thead>`, `<tfoot>`.
|
||||
- `table.tBodies` -- the collection of `<tbody>` elements (can be many according to the standard).
|
||||
|
||||
`<thead>`, `<tfoot>`, `<tbody>` elements provide:
|
||||
**`<thead>`, `<tfoot>`, `<tbody>`** elements provide:
|
||||
- `tbody.rows` -- the collection of `<tr>` inside them.
|
||||
|
||||
`<tr>`:
|
||||
**`<tr>`:**
|
||||
- `tr.cells` -- the collection of `<td>` and `<th>` cells inside the given `<tr>`.
|
||||
- `tr.sectionRowIndex` -- the number of the given `<tr>` inside the enclosing `<thead>/<tbody>`.
|
||||
- `tr.rowIndex` -- the number of the `<tr>` in the table.
|
||||
|
||||
`<td>` and `<th>`:
|
||||
**`<td>` and `<th>`:**
|
||||
- `td.cellIndex` -- the number of the cell inside the enclosing `<tr>`.
|
||||
|
||||
An example of usage:
|
||||
|
@ -276,9 +276,11 @@ There are also additional navigation properties for HTML forms. We'll look at th
|
|||
|
||||
# Summary
|
||||
|
||||
The main navigation sets are:
|
||||
Given a DOM node, we can go to its immediate neighbours using navigation properties.
|
||||
|
||||
- `parentNode`, `childNodes`, `firstChild`, `lastChild`, `previousSibling`, `nextSibling` -- for all nodes.
|
||||
- `parentElement`, `children`, `firstElementChild`, `lastElementChild`, `previousElementSibling`, `nextElementSibling` -- if we take only element nodes into account.
|
||||
There are two main sets of them:
|
||||
|
||||
- For all nodes: `parentNode`, `childNodes`, `firstChild`, `lastChild`, `previousSibling`, `nextSibling`.
|
||||
- For element nodes only: `parentElement`, `children`, `firstElementChild`, `lastElementChild`, `previousElementSibling`, `nextElementSibling`.
|
||||
|
||||
Some types of DOM elements, e.g. tables, provide additional properties and collections to access their content.
|
||||
|
|
|
@ -351,3 +351,6 @@ Besides that:
|
|||
|
||||
- There is `elem.matches(css)` to check if `elem` matches the given CSS selector.
|
||||
- There is `elem.closest(css)` to look for a nearest ancestor that matches the given CSS-selector. The `elem` itself is also checked.
|
||||
|
||||
And let's mention one more method here to check for the child-parent relationship:
|
||||
- `elemA.contains(elemB)` returns true if `elemB` is inside `elemA`. Or when it's the same element.
|
||||
|
|
|
@ -18,18 +18,23 @@ The root object is [EventTarget](https://dom.spec.whatwg.org/#eventtarget), then
|
|||
|
||||

|
||||
|
||||
The main classes are:
|
||||
The classes are:
|
||||
|
||||
- [EventTarget](https://dom.spec.whatwg.org/#eventtarget) is an "abstract" class. Objects of that class are never created. It serves as a base, because all DOM nodes support so-called "events", we'll study them later.
|
||||
- [Node](http://dom.spec.whatwg.org/#interface-node) is also an "abstract" class, serving as a base for DOM nodes. It provides the core tree functionality like `parentNode`, `nextSibling`, `childNodes` and so on. That class is abstract as well. Objects of bare `Node` are never created. But there are concrete node classes that inherit from it, namely: `Text` for text nodes, `Element` for element nodes and more exotic classes like `Comment` for comment nodes.
|
||||
- [Element](http://dom.spec.whatwg.org/#interface-element) is for DOM elements: not only for HTML, but also XML and SVG documents. It provides element-level navigation like `nextElementSibling`, `children` and searching methods like `getElementsByTagName`, `querySelector`.
|
||||
- [EventTarget](https://dom.spec.whatwg.org/#eventtarget) is the root "abstract" class. Objects of that class are never created. It serves as a base, because all DOM nodes support so-called "events", we'll study them later.
|
||||
- [Node](http://dom.spec.whatwg.org/#interface-node) is also an "abstract" class, serving as a base for DOM nodes. It provides the core tree functionality like `parentNode`, `nextSibling`, `childNodes` and so on. Objects of bare `Node` are never created. But there are concrete node classes that inherit from it, namely: `Text` for text nodes, `Element` for element nodes and few more exotic ones like `Comment` for comment nodes.
|
||||
- [Element](http://dom.spec.whatwg.org/#interface-element) is a base class for DOM elements. It provides element-level navigation like `nextElementSibling`, `children` and searching methods like `getElementsByTagName`, `querySelector`. In the browser there may be not only HTML, but also XML and SVG documents. The `Element` class serves as a base for `SVGElement`, `XMLElement` and `HTMLElement`.
|
||||
- [HTMLElement](https://html.spec.whatwg.org/multipage/dom.html#htmlelement) is finally the class for HTML elements. It is inherited by various HTML elements:
|
||||
- For `<input>` -- `HTMLInputElement`
|
||||
- For `<body>` -- `HTMLBodyElement`
|
||||
- For `<a>` -- `HTMLAnchorElement`... and so on, that have their own specific properties.
|
||||
|
||||
|
||||
For instance, DOM element that corresponds to `<input>` is of the [HTMLInputElement]((https://html.spec.whatwg.org/multipage/forms.html#htmlinputelement) class. The class provides input-specific properties and methods and inherits more common stuff from `HTMLElement`. In turn, it provides HTML element functionality and inherits more generic methods from `Element` and so on.
|
||||
So, the full set of properties and methods of a given node comes as the result of the inheritance.
|
||||
|
||||
For instance, `<input>` element is of the [HTMLInputElement](https://html.spec.whatwg.org/multipage/forms.html#htmlinputelement) class:
|
||||
- `HTMLInputElement` provides input-specific properties and inherits the common HTML element properties from `HTMLElement`.
|
||||
- Then it has common element properties, because `HTMLElement` inherits from `Element`.
|
||||
- Then it has common DOM node properties from `Node` and so on.
|
||||
|
||||
To see the DOM node class, we can check its constructor name or just `toString` it:
|
||||
|
||||
|
@ -48,7 +53,7 @@ alert( document.body instanceof Node ); // true
|
|||
alert( document.body instanceof EventTarget ); // true
|
||||
```
|
||||
|
||||
As we can see, DOM nodes are regular Javascript objects. They use prototype-style classes for inheritance. That's easy to see by outputting an element with `console.dir(elem)`. There you can see `Node.prototype`, `Element.prototype` and so on.
|
||||
As we can see, DOM nodes are regular Javascript objects. They use prototype-style classes for inheritance. That's easy to see by outputting an element with `console.dir(elem)`. There you can see `HTMLElement.prototype`, `Element.prototype` and so on.
|
||||
|
||||
```smart header="`console.dir(elem)` versus `console.log(elem)`"
|
||||
Most browsers support two commands: `console.log` and `console.dir`. For Javascript objects these commands usually do the same.
|
||||
|
@ -71,18 +76,18 @@ Here's an excerpt from it, with comments:
|
|||
// The colon means that it inherits from HTMLElement
|
||||
interface HTMLInputElement: HTMLElement {
|
||||
|
||||
// such elements have string properties
|
||||
// string properties
|
||||
// accept, alt, autocomplete, value
|
||||
attribute DOMString accept;
|
||||
attribute DOMString alt;
|
||||
attribute DOMString autocomplete;
|
||||
attribute DOMString value;
|
||||
|
||||
// and the boolean property autofocus
|
||||
// and the boolean property: autofocus
|
||||
attribute boolean autofocus;
|
||||
...
|
||||
// and also the method select(),
|
||||
// that returns no value ("void")
|
||||
// "void" means that that returns no value
|
||||
void select();
|
||||
...
|
||||
}
|
||||
|
@ -97,7 +102,7 @@ It has a numeric value:
|
|||
- `elem.nodeType == 1` for element nodes,
|
||||
- `elem.nodeType == 3` for text nodes,
|
||||
- `elem.nodeType == 9` for the document object,
|
||||
- there are few other values in [the docs](https://dom.spec.whatwg.org/#node).
|
||||
- there are few other values in [the specification](https://dom.spec.whatwg.org/#node).
|
||||
|
||||
For instance:
|
||||
|
||||
|
|
|
@ -1,4 +1,4 @@
|
|||
# DOM: attributes and properties [todo]
|
||||
# DOM: attributes and properties
|
||||
|
||||
The browser "reads" HTML text and generates DOM objects from it. For element nodes most standard HTML attributes automatically become properties of DOM objects.
|
||||
|
||||
|
|
BIN
figures.sketch
BIN
figures.sketch
Binary file not shown.
Loading…
Add table
Add a link
Reference in a new issue