This commit is contained in:
Ilya Kantor 2015-11-18 16:15:29 +03:00
parent 4bca225593
commit 547854a151
1655 changed files with 847 additions and 89231 deletions

View file

@ -1,25 +0,0 @@
Решение:
```html
<!--+ run -->
<select>
<option value="Rock">Рок</option>
<option value="Blues" selected>Блюз</option>
</select>
<script>
var select = document.body.children[0];
// 1)
var selectedOption = select.options[select.selectedIndex];
alert( selectedOption.value );
// 2)
var newOption = new Option("Classic", "Классика");
select.appendChild(newOption);
// 3)
newOption.selected = true;
</script>
```

View file

@ -1,19 +0,0 @@
# Добавьте опцию к селекту
[importance 5]
Есть селект:
```html
<select>
<option value="Rock">Рок</option>
<option value="Blues" selected>Блюз</option>
</select>
```
При помощи JavaScript:
<ol>
<li>Выведите значение и текст текущей выбранной опции.</li>
<li>Добавьте опцию: `<option value="Classic">Классика</option>`.</li>
<li>Сделайте её выбранной.</li>
</ol>

View file

@ -1,318 +0,0 @@
# Навигация и свойства элементов формы
Элементы управления, такие как `<form>`, `<input>` и другие имеют большое количество своих важных свойств и ссылок.
[cut]
## Псевдомассив form.elements
Элементы `FORM` можно получить по имени или номеру, используя свойство `document.forms[name/index]`.
Например:
```js
//+ no-beautify
document.forms.my -- форма с именем 'my'
document.forms[0] -- первая форма в документе
```
**Любой *элемент* формы `form` можно получить аналогичным образом, используя свойство `form.elements`.**
<img src="form.png">
Например:
```html
<!--+ run height=40 -->
<body>
<form name="my">
<input name="one" value="1">
<input name="two" value="2">
</form>
<script>
var form = document.forms.my; // можно document.forms[0]
var elem = form.elements.one; // можно form.elements[0]
alert( elem.value ); // "один"
</script>
</body>
```
**Может быть несколько элементов с *одинаковым именем*. В таком случае `form.elements[name]` вернет коллекцию элементов**, например:
```html
<!--+ run height=40 -->
<body>
<form>
<input type="radio" name="*!*age*/!*" value="10">
<input type="radio" name="*!*age*/!*" value="20">
</form>
<script>
var form = document.forms[0];
var elems = form.elements.age;
alert(elems[0].value); // 10, первый input
</script>
</body>
```
Эти ссылки не зависят от окружающих тегов. Элемент может быть "зарыт" где-то глубоко в форме, но он всё равно доступен через `form.elements`.
**Свойство `elements` также есть у элементов `<fieldset>`.**
Вот пример:
```html
<!--+ run height=80 -->
<body>
<form>
<fieldset name="set">
<legend>fieldset</legend>
<input name="text" type="text">
</fieldset>
</form>
<script>
var form = document.forms[0];
alert( form.elements.text ); // INPUT
*!*
alert( form.elements.set.elements.text ); // INPUT
*/!*
</script>
</body>
```
Спецификация: [HTML5 Forms](https://html.spec.whatwg.org/multipage/forms.html).
[warn header="Доступ `form.name` тоже работает, но с особенностями"]
Получить доступ к элементам формы можно не только через `form.elements[name/index]`, но и проще: `form[index/name]`.
Этот способ короче, так как обладает одной неприятной особенностью: если к элементу обратиться по его `name`, а потом свойство `name` изменить, то он по-прежнему будет доступен под старым именем.
Звучит странно, поэтому посмотрим на примере.
```html
<!--+ run height=40 -->
<form name="myform">
<input name="text">
</form>
<script>
var form = document.forms.myform;
alert( form.elements.text == form.text ); // true, это тот самый INPUT
form.text.name = "new-name"; // меняем name ему
// нет больше элемента с таким именем
alert( form.elements.text ); // undefined
alert( form.text ); // INPUT (а должно быть undefined!)
</script>
```
[/warn]
## Ссылка на форму element.form
По элементу можно получить его форму, используя свойство `element.form`.
Пример:
```html
<!--+ run height=40 -->
<body>
<form>
<input type="text" name="*!*surname*/!*">
</form>
<script>
var form = document.forms[0];
var elem = form.elements.surname;
*!*
alert(elem.form == form); // true
*/!*
</script>
</body>
```
Познакомиться с другими свойствами элементов можно в спецификации [HTML5 Forms](https://html.spec.whatwg.org/multipage/forms.html).
## Элемент label
Элемент `label` -- один из самых важных в формах.
**Клик на `label` засчитывается как фокусировка или клик на элементе формы, к которому он относится.**
Это позволяет посетителям кликать на большой красивой метке, а не на маленьком квадратике `input type=checkbox` (`radio`). Конечно, это очень удобно.
Есть два способа показать, какой элемент относится к `label`:
<ol>
<li>Дать метке атрибут `for`, равный `id` соответствующего `input`:
```html
<!--+ autorun -->
<table>
<tr>
<td>
<label for="agree">Согласен с правилами</label>
</td>
<td>
<input id="agree" type="checkbox">
</td>
</tr>
<tr>
<td>
<label for="not-a-robot">Я не робот</label>
</td>
<td>
<input id="not-a-robot" type="checkbox">
</td>
</tr>
</table>
```
</li>
<li>Завернуть элемент в `label`. В этом случае можно обойтись без дополнительных атрибутов:
```html
<!--+ autorun no-beautify -->
<label>Кликни меня <input type="checkbox"></label>
```
</li>
</ol>
## Элементы input и textarea
Для большинства типов `input` значение ставится/читается через свойство `value`.
```js
input.value = "Новое значение";
textarea.value = "Новый текст";
```
[warn header="Не используйте `textarea.innerHTML`"]
Для элементов `textarea` также доступно свойство `innerHTML`, но лучше им не пользоваться: оно хранит только HTML, изначально присутствовавший в элементе, и не меняется при изменении значения.
[/warn]
Исключения -- `input type="checkbox"` и `input type="radio"`
**Текущее "отмеченное" состояние для `checkbox` и `radio` находится в свойстве `checked` (`true/false`).**
```js
if (input.checked) {
alert( "Чекбокс выбран" );
}
```
## Элементы select и option
Селект в JavaScript можно установить двумя путями: поставив значение `select.value`, либо установив свойство `select.selectedIndex` в номер нужной опции.:
```js
select.selectedIndex = 0; // первая опция
```
Установка `selectedIndex = -1` очистит выбор.
**Список элементов-опций доступен через `select.options`.**
Если `select` допускает множественный выбор (атрибут `multiple`), то значения можно получить/установить, сделав цикл по `select.options`. При этом выбранные опции будут иметь свойство `option.selected = true`.
Пример:
```html
<!--+ run -->
<form name="form">
<select name="genre" *!*multiple*/!*>
<option value="blues" selected>Мягкий блюз</option>
<option value="rock" selected>Жёсткий рок</option>
<option value="classic">Классика</option>
</select>
</form>
<script>
var form = document.forms[0];
var select = form.elements.genre;
for (var i = 0; i < select.options.length; i++) {
var option = select.options[i];
*!*
if(option.selected) {
alert( option.value );
}
*/!*
}
</script>
```
Спецификация: [the select element](https://html.spec.whatwg.org/multipage/forms.html#the-select-element).
[smart header="`new Option`"]
В стандарте [the option element](https://html.spec.whatwg.org/multipage/forms.html#the-option-element) есть любопытный короткий синтаксис для создания элемента с тегом `option`:
```js
option = new Option(text, value, defaultSelected, selected);
```
Параметры:
<ul>
<li>`text` -- содержимое,</li>
<li>`value` -- значение,</li>
<li>`defaultSelected` и `selected` поставьте в `true`, чтобы сделать элемент выбранным.</li>
</ul>
Его можно использовать вместо `document.createElement('option')`, например:
```js
var option = new Option("Текст", "value");
// создаст <option value="value">Текст</option>
```
Такой же элемент, но выбранный:
```js
var option = new Option("Текст", "value", true, true);
```
[/smart]
[smart header="Дополнительные свойства `option`"]
У элементов `option` также есть особые свойства, которые могут оказаться полезными (см. [the option element](https://html.spec.whatwg.org/multipage/forms.html#the-option-element)):
<dl>
<dt>`selected`</dt>
<dd>выбрана ли опция</dd>
<dt>`index`</dt>
<dd>номер опции в списке селекта</dd>
<dt>`text`</dt>
<dd>Текстовое содержимое опции (то, что видит посетитель).</dd>
</dl>
[/smart]
## Итого
Свойства для навигации по формам:
<dl>
<dt>`document.forms`</dt>
<dd>Форму можно получить как `document.forms[name/index]`.</dd>
<dt>`form.elements`</dt>
<dd>Элементы в форме: `form.elements[name/index]`. Каждый элемент имеет ссылку на форму в свойстве `form`. Свойство `elements` также есть у `<fieldset>`.</dd>
</dl>
Значение элементов читается/ставится через `value` или `checked`.
Для элемента `select` можно задать опцию по номеру через `select.selectedIndex` и перебрать опции через `select.options`. При этом выбранные опции (в том числе при мультиселекте) будут иметь свойство `option.selected = true`.

Binary file not shown.

Before

Width:  |  Height:  |  Size: 3.8 KiB

View file

@ -1,3 +0,0 @@
В данном случае достаточно событий `input.focus/input.blur`.
Если бы мы хотели реализовать это на уровне документа, то применили бы делегирование и события `focusin/focusout` (эмуляцию для firefox), так как обычные `focus/blur` не всплывают.

View file

@ -1,74 +0,0 @@
<!DOCTYPE HTML>
<html>
<head>
<meta charset="UTF-8">
<style>
.placeholder {
color: blue;
font-family: Georgia;
}
.placeholder-tooltip {
color: blue;
font-family: Georgia;
position: fixed;
}
</style>
</head>
<body>
<p>Красивый placeholder:</p>
<input type="email" data-placeholder="E-mail">
<script>
var input = document.querySelector('[data-placeholder]');
showPlaceholder(input);
// Показать placeholder внутри input
// Также можно сделать это при помощи вёрстки, отдельным элементом
function showPlaceholder(input) {
input.classList.add('placeholder');
input.value = input.dataset.placeholder;
}
// Показать подсказку над элементом (будет вместо placeholder)
function showTooltip(input) {
var tooltip = document.createElement('span');
tooltip.innerHTML = input.dataset.placeholder;
tooltip.className = 'placeholder-tooltip';
tooltip.style.fontSize = getComputedStyle(input).fontSize;
tooltip.style.left = input.getBoundingClientRect().left + 'px';
document.body.appendChild(tooltip);
tooltip.style.top = input.getBoundingClientRect().top - tooltip.offsetHeight - 4 + 'px';
input.tooltip = tooltip;
}
input.onfocus = function() {
if (input.classList.contains('placeholder')) {
input.classList.remove('placeholder');
input.value = '';
}
showTooltip(input);
};
input.onblur = function() {
document.body.removeChild(input.tooltip);
delete input.tooltip;
// показываем placeholder обратно, если input пуст
if (input.value == '') {
showPlaceholder(input);
}
};
</script>
</body>
</html>

View file

@ -1,48 +0,0 @@
<!DOCTYPE HTML>
<html>
<head>
<meta charset="UTF-8">
<style>
/* стиль для input с плейсхолдером */
.placeholder {
color: blue;
font-family: Georgia;
}
/* стиль для подсказки над элементом (вместо плейсхолдера при фокусировке) */
.placeholder-tooltip {
color: blue;
font-family: Georgia;
position: fixed;
}
</style>
</head>
<body>
<p>Красивый placeholder:</p>
<input type="email" data-placeholder="E-mail">
<script>
var input = document.querySelector('[data-placeholder]');
showPlaceholder(input);
// Показать placeholder внутри input
// Также можно сделать это при помощи вёрстки, отдельным элементом
function showPlaceholder(input) {
input.classList.add('placeholder');
input.value = input.dataset.placeholder;
}
// ...ваш код для input...
</script>
</body>
</html>

View file

@ -1,19 +0,0 @@
# Улучшенный плейсхолдер
[importance 5]
Реализуйте более удобный плейсхолдер-подсказку на JavaScript через атрибут `data-placeholder`.
Правила работы плейсхолдера:
<ul>
<li>Элемент изначально содержит плейсхолдер. Специальный класс `placeholder` придает ему синий цвет.</li>
<li>При фокусировке плейсхолдер показывается уже над полем, становясь "подсказкой".</li>
<li>При снятии фокуса, подсказка убирается, если поле пустое -- плейсхолдер возвращается в него.</li>
</ul>
Демо:
[iframe src="solution" height=100]
В этой задаче плейсхолдер должен работать на одном конкретном input. Подумайте, если input много, как здесь применить делегирование?

View file

@ -1,9 +0,0 @@
Нам нужно ловить `onclick` на мышонке и в `onkeydown` на нём смотреть коды символов. При скан-кодах стрелок двигать мышонка через `position:absolute` или `position:fixed`.
Скан-коды для клавиш стрелок можно узнать, нажимая на них на [тестовом стенде](#keyboard-test-stand). Вот они: 37-38-39-40 (влево-вверх-вправо-вниз).
Проблема может возникнуть одна -- `keydown` не возникает на элементе, если на нём нет фокуса.
Чтобы фокус был -- нужно добавить мышонку атрибут `tabindex` через JS или в HTML.

View file

@ -1,65 +0,0 @@
<!DOCTYPE HTML>
<html>
<head>
<meta charset="utf-8">
<style>
#mouse {
display: inline-block;
cursor: pointer;
margin: 0;
}
#mouse:focus {
outline: 1px dashed black;
}
</style>
</head>
<body>
<p>Кликните на мышонка и передвигайте его, нажимая клавиши со стрелками.</p>
<pre id="mouse" tabindex="0">
_ _
(q\_/p)
/. .\
=\_t_/= __
/ \ (
(( )) )
/\) (/\ /
\ Y /-'
nn^nn
</pre>
<script>
document.getElementById('mouse').onclick = function() {
this.style.left = this.getBoundingClientRect().left + 'px';
this.style.top = this.getBoundingClientRect().top + 'px';
this.style.position = 'fixed';
};
document.getElementById('mouse').onkeydown = function(e) {
switch (e.keyCode) {
case 37: // влево
this.style.left = parseInt(this.style.left) - this.offsetWidth + 'px';
return false;
case 38: // вверх
this.style.top = parseInt(this.style.top) - this.offsetHeight + 'px';
return false;
case 39: // вправо
this.style.left = parseInt(this.style.left) + this.offsetWidth + 'px';
return false;
case 40: // вниз
this.style.top = parseInt(this.style.top) + this.offsetHeight + 'px';
return false;
}
};
</script>
</body>
</html>

View file

@ -1,42 +0,0 @@
<!DOCTYPE HTML>
<html>
<head>
<meta charset="utf-8">
<style>
#mouse {
display: inline-block;
cursor: pointer;
margin: 0;
}
#mouse:focus {
outline: 1px dashed black;
}
</style>
</head>
<body>
<p>Кликните на мышонка и передвигайте его, нажимая клавиши со стрелками.</p>
<pre id="mouse">
_ _
(q\_/p)
/. .\
=\_t_/= __
/ \ (
(( )) )
/\) (/\ /
\ Y /-'
nn^nn
</pre>
<script>
// ваш код
</script>
</body>
</html>

View file

@ -1,11 +0,0 @@
# Мышонок на "клавиатурном" приводе
[importance 4]
Кликните по мышонку. Затем нажимайте клавиши со стрелками, и он будет двигаться.
[demo src="solution"]
В этой задаче запрещается ставить обработчики куда-либо, кроме элемента `#mouse`.
Можно изменять атрибуты и классы в HTML.

View file

@ -1,100 +0,0 @@
# CSS для решения
Как видно из исходного кода, `#view` -- это `<div>`, который будет содержать результат, а `#area` - это редактируемое текстовое поле.
Так как мы преобразуем `<div>` в `<textarea>` и обратно, нам нужно сделать их практически одинаковыми с виду:
```css
#view,
#area {
height: 150px;
width: 400px;
font-family: arial;
font-size: 14px;
}
```
Текстовое поле нужно как-то выделить. Можно добавить границу, но тогда изменится блок: он увеличится в размерах и немного съедет текст.
Для того, чтобы сделать размер `#area` таким же, как и `#view`, добавим поля(padding):
```css
#view {
/* padding + border = 3px */
padding: 2px;
border: 1px solid black;
}
```
CSS для `#area` заменяет поля границами:
```css
#area {
border: 3px groove blue;
padding: 0px;
display: none;
}
```
По умолчанию, текстовое поле скрыто. Кстати, этот код убирает дополнительную рамку в ряде браузеров, которая появляется вокруг поля, когда на него попадает фокус:
```css
/*+ no-beautify */
#area:focus {
outline: none; /* убирает рамку при фокусе */
}
```
# Горячие клавиши
Чтобы отследить горячие клавиши, нам нужны их скан-коды, а не символы. Это важно, потому что горячие клавиши должны работать независимо от языковой раскладки. Поэтому, мы будем использовать <code>keydown</code>:
```js
document.onkeydown = function(e) {
if (e.keyCode == 27) { // escape
cancel();
return false;
}
if ((e.ctrlKey && e.keyCode == 'E'.charCodeAt(0)) && !area.offsetHeight) {
edit();
return false;
}
if ((e.ctrlKey && e.keyCode == 'S'.charCodeAt(0)) && area.offsetHeight) {
save();
return false;
}
};
```
В примере выше, `offsetHeight` используется для того, чтобы проверить, отображается элемент или нет. Это очень надежный способ для всех элементов, кроме `<tr>` в некоторых старых браузерах.
В отличие от простой проверки `display=='none'`, этот способ работает с элементом, спрятанным с помощью стилей, а так же для элементов, у которых скрыты родители.
# Редактирование
Следующие функции переключают режимы. HTML-код разрешен, поэтому возможна прямая трансформация в `<textarea>` и обратно.
```js
function edit() {
view.style.display = 'none';
area.value = view.innerHTML;
area.style.display = 'block';
area.focus();
}
function save() {
area.style.display = 'none';
view.innerHTML = area.value;
view.style.display = 'block';
}
function cancel() {
area.style.display = 'none';
view.style.display = 'block';
}
```

View file

@ -1,61 +0,0 @@
<!DOCTYPE HTML>
<html>
<head>
<link type="text/css" rel="stylesheet" href="my.css">
<meta charset="utf-8">
</head>
<body>
<ul>
<li>Ctrl-E для начала редактирования.</li>
<li>Во время редактирования: Ctrl-S для сохранения, Esc для отмены.</li>
</ul>
HTML разрешён.
<textarea id="area"></textarea>
<div id="view">Текст</div>
<script>
document.onkeydown = function(e) {
if (e.keyCode == 27) { // escape
cancel();
return false;
}
if ((e.ctrlKey && e.keyCode == 'E'.charCodeAt(0)) && !area.offsetHeight) {
edit();
return false;
}
if ((e.ctrlKey && e.keyCode == 'S'.charCodeAt(0)) && area.offsetHeight) {
save();
return false;
}
}
function edit() {
view.style.display = 'none';
area.value = view.innerHTML;
area.style.display = 'block';
area.focus();
}
function save() {
area.style.display = 'none';
view.innerHTML = area.value;
view.style.display = 'block';
}
function cancel() {
area.style.display = 'none';
view.style.display = 'block';
}
</script>
</body>
</html>

View file

@ -1,27 +0,0 @@
#view,
#area {
height: 150px;
width: 400px;
font-family: arial;
font-size: 14px;
}
#view {
/* padding + border = 3px */
padding: 2px;
border: 1px solid black;
}
#area {
display: none;
/* replace padding with border (still 3px not to shift the contents) */
border: 3px groove blue;
padding: 0px;
}
#area:focus {
outline: none;
/* remove focus border in Safari */
}

View file

@ -1,22 +0,0 @@
<!DOCTYPE HTML>
<html>
<head>
<link type="text/css" rel="stylesheet" href="my.css">
</head>
<body>
<ul>
<li>Ctrl-E to start editing.</li>
<li>While editing: Ctrl-S to save, Esc to cancel.</li>
</ul>
<textarea id="area"></textarea>
<div id="view">Text</div>
</body>
</html>

View file

@ -1,27 +0,0 @@
#view,
#area {
height: 150px;
width: 400px;
font-family: arial;
font-size: 14px;
}
#view {
/* padding + border = 3px */
padding: 2px;
border: 1px solid black;
}
#area {
display: none;
/* replace padding with border (still 3px not to shift the contents) */
border: 3px groove blue;
padding: 0px;
}
#area:focus {
outline: none;
/* remove focus border in Safari */
}

View file

@ -1,14 +0,0 @@
# Горячие клавиши
[importance 5]
Создайте `<div>`, который при нажатии [key Ctrl+E] превращается в `<textarea>`.
Изменения, внесенные в поле, можно сохранить обратно в `<div>` сочетанием клавиш [key Ctrl+S], при этом `<div>` получит в виде HTML содержимое `<textarea>`.
Если же нажать [key Esc], то `<textarea>` снова превращается в `<div>`, изменения не сохраняются.
[demo src="solution"].

View file

@ -1,7 +0,0 @@
<ol>
<li>При клике -- заменяем `innerHTML` ячейки на `<textarea>` с размерами "под ячейку", без рамки.</li>
<li>В `textarea.value` присваиваем содержимое ячейки.</li>
<li>Фокусируем посетителя на ячейке вызовом `focus()`.</li>
<li>Показываем кнопки OK/CANCEL под ячейкой.</li>
</ol>

View file

@ -1,56 +0,0 @@
/* общие стили для таблицы */
th {
text-align: center;
font-weight: bold;
}
td {
width: 150px;
white-space: nowrap;
text-align: center;
vertical-align: middle;
padding: 10px;
}
.nw {
background-color: #999;
}
.n {
background-color: #03f;
color: #fff;
}
.ne {
background-color: #ff6;
}
.w {
background-color: #ff0;
}
.c {
background-color: #60c;
color: #fff;
}
.e {
background-color: #09f;
color: #fff;
}
.sw {
background-color: #963;
color: #fff;
}
.s {
background-color: #f60;
color: #fff;
}
.se {
background-color: #0c3;
color: #fff;
}

View file

@ -1,78 +0,0 @@
<!DOCTYPE HTML>
<html>
<head>
<meta charset="utf-8">
</head>
<body>
<link rel="stylesheet" href="bagua.css">
<link rel="stylesheet" href="my.css">
<p>Кликните на ячейке для начала редактирования. Когда закончите -- нажмите OK или CANCEL.</p>
<table id="bagua-table">
<tr>
<th colspan="3"><em>Bagua</em> Chart: Direction, Element, Color, Meaning</th>
</tr>
<tr>
<td class="nw"><strong>Northwest</strong>
<br>Metal
<br>Silver
<br>Elders
</td>
<td class="n"><strong>North</strong>
<br>Water
<br>Blue
<br>Change
</td>
<td class="ne"><strong>Northeast</strong>
<br>Earth
<br>Yellow
<br>Direction
</td>
</tr>
<tr>
<td class="w"><strong>West</strong>
<br>Metal
<br>Gold
<br>Youth
</td>
<td class="c"><strong>Center</strong>
<br>All
<br>Purple
<br>Harmony
</td>
<td class="e"><strong>East</strong>
<br>Wood
<br>Blue
<br>Future
</td>
</tr>
<tr>
<td class="sw"><strong>Southwest</strong>
<br>Earth
<br>Brown
<br>Tranquility
</td>
<td class="s"><strong>South</strong>
<br>Fire
<br>Orange
<br>Fame
</td>
<td class="se"><strong>Southeast</strong>
<br>Wood
<br>Green
<br>Romance
</td>
</tr>
</table>
<script src="script.js"></script>
</body>
</html>

View file

@ -1,23 +0,0 @@
.edit-td .edit-area {
border: none;
margin: 0;
padding: 0;
display: block;
resize: none;
/* remove resizing handle in Firefox */
outline: none;
/* remove outline on focus in Chrome */
overflow: auto;
/* remove scrollbar in IE */
}
.edit-controls {
position: absolute;
}
.edit-td {
position: relative;
padding: 0;
}

View file

@ -1,62 +0,0 @@
var table = document.getElementById('bagua-table');
var editingTd;
table.onclick = function(event) {
var target = event.target;
while (target != table) {
if (target.className == 'edit-cancel') {
finishTdEdit(editingTd.elem, false);
return;
}
if (target.className == 'edit-ok') {
finishTdEdit(editingTd.elem, true);
return;
}
if (target.nodeName == 'TD') {
if (editingTd) return; // already editing
makeTdEditable(target);
return;
}
target = target.parentNode;
}
}
function makeTdEditable(td) {
editingTd = {
elem: td,
data: td.innerHTML
};
td.classList.add('edit-td'); // td, not textarea! the rest of rules will cascade
var textArea = document.createElement('textarea');
textArea.style.width = td.clientWidth + 'px';
textArea.style.height = td.clientHeight + 'px';
textArea.className = 'edit-area';
textArea.value = td.innerHTML;
td.innerHTML = '';
td.appendChild(textArea);
textArea.focus();
td.insertAdjacentHTML("beforeEnd",
'<div class="edit-controls"><button class="edit-ok">OK</button><button class="edit-cancel">CANCEL</button></div>'
);
}
function finishTdEdit(td, isOk) {
if (isOk) {
td.innerHTML = td.firstChild.value;
} else {
td.innerHTML = editingTd.data;
}
td.classList.remove('edit-td'); // remove edit class
editingTd = null;
}

View file

@ -1,56 +0,0 @@
/* общие стили для таблицы */
th {
text-align: center;
font-weight: bold;
}
td {
width: 150px;
white-space: nowrap;
text-align: center;
vertical-align: middle;
padding: 10px;
}
.nw {
background-color: #999;
}
.n {
background-color: #03f;
color: #fff;
}
.ne {
background-color: #ff6;
}
.w {
background-color: #ff0;
}
.c {
background-color: #60c;
color: #fff;
}
.e {
background-color: #09f;
color: #fff;
}
.sw {
background-color: #963;
color: #fff;
}
.s {
background-color: #f60;
color: #fff;
}
.se {
background-color: #0c3;
color: #fff;
}

View file

@ -1,78 +0,0 @@
<!DOCTYPE HTML>
<html>
<head>
<meta charset="utf-8">
</head>
<body>
<link rel="stylesheet" href="bagua.css">
<link rel="stylesheet" href="my.css">
<p>Кликните на ячейке для начала редактирования. Когда закончите -- нажмите OK или CANCEL.</p>
<table id="bagua-table">
<tr>
<th colspan="3"><em>Bagua</em> Chart: Direction, Element, Color, Meaning</th>
</tr>
<tr>
<td class="nw"><strong>Northwest</strong>
<br>Metal
<br>Silver
<br>Elders
</td>
<td class="n"><strong>North</strong>
<br>Water
<br>Blue
<br>Change
</td>
<td class="ne"><strong>Northeast</strong>
<br>Earth
<br>Yellow
<br>Direction
</td>
</tr>
<tr>
<td class="w"><strong>West</strong>
<br>Metal
<br>Gold
<br>Youth
</td>
<td class="c"><strong>Center</strong>
<br>All
<br>Purple
<br>Harmony
</td>
<td class="e"><strong>East</strong>
<br>Wood
<br>Blue
<br>Future
</td>
</tr>
<tr>
<td class="sw"><strong>Southwest</strong>
<br>Earth
<br>Brown
<br>Tranquility
</td>
<td class="s"><strong>South</strong>
<br>Fire
<br>Orange
<br>Fame
</td>
<td class="se"><strong>Southeast</strong>
<br>Wood
<br>Green
<br>Romance
</td>
</tr>
</table>
<script src="script.js"></script>
</body>
</html>

View file

@ -1 +0,0 @@
/* ваши стили */

View file

@ -1,3 +0,0 @@
var table = document.getElementById('bagua-table');
/* ваш код */

View file

@ -1,16 +0,0 @@
# Редактирование TD по клику
[importance 5]
Сделать ячейки таблицы `td` редактируемыми по клику.
<ul>
<li>При клике -- ячейка `<td>` превращается в редактируемую, можно менять HTML. Размеры ячеек при этом не должны меняться.</li>
<li>В один момент может редактироваться одна ячейка.</li>
<li>При редактировании под ячейкой появляются кнопки для приема и отмена редактирования, только клик на них заканчивает редактирование.</li>
</ul>
Демо:
[iframe src="solution"]

View file

@ -1,22 +0,0 @@
# Вёрстка
Для вёрстки можно использовать отрицательный `margin` у текста с подсказкой.
Решение в плане вёрстка есть в решении задачи [](/task/position-text-into-input).
# Решение
```js
placeholder.onclick = function() {
input.focus();
}
// onfocus сработает и вызове input.focus() и при клике на input
input.onfocus = function() {
if (placeholder.parentNode) {
placeholder.parentNode.removeChild(placeholder);
}
}
```
[edit src="solution"]Открыть полный код решения[/edit]

View file

@ -1,33 +0,0 @@
<!DOCTYPE html>
<html>
<head>
<meta charset="utf-8">
<link rel="stylesheet" href="style.css">
</head>
<body>
<div>Добро пожаловать</div>
<input type="password" id="input">
<div id="placeholder">Скажи пароль, друг</div>
<div>.. и заходи</div>
<script>
var placeholder = document.getElementById('placeholder');
var input = document.getElementById('input');
placeholder.onclick = function() {
input.focus();
}
input.onfocus = function() {
placeholder.parentNode && placeholder.parentNode.removeChild(placeholder);
}
</script>
</body>
</html>

View file

@ -1,17 +0,0 @@
body {
font: 14px/14px Arial, sans-serif;
}
input {
font: 14px/14px Arial, sans-serif;
width: 12em;
padding: 0;
margin: 0;
}
#placeholder {
font: 14px/14px Arial, sans-serif;
position: absolute;
margin: -1.2em 0 0 0.2em;
color: red;
}

View file

@ -1,21 +0,0 @@
<!DOCTYPE html>
<html>
<head>
<meta charset="utf-8">
<link rel="stylesheet" href="style.css">
</head>
<body>
<div>Добро пожаловать</div>
<input type="password" id="input">
<div id="placeholder">Скажи пароль, друг</div>
<div>.. и заходи</div>
</body>
</html>

View file

@ -1,17 +0,0 @@
body {
font: 14px/14px Arial, sans-serif;
}
input {
font: 14px/14px Arial, sans-serif;
width: 12em;
padding: 0;
margin: 0;
}
#placeholder {
font: 14px/14px Arial, sans-serif;
position: absolute;
margin: -1.2em 0 0 0.2em;
color: red;
}

View file

@ -1,11 +0,0 @@
# Красивый плейсхолдер для INPUT
[importance 5]
Создайте для `<input type="password">` красивый, стилизованный плейсхолдер, например (кликните на тексте):
[iframe src="solution" height=90]
При клике плейсхолдер просто исчезает и дальше не показывается.

View file

@ -1,91 +0,0 @@
# Алгоритм
JavaScript не имеет доступа к текущему состоянию [key CapsLock]. При загрузке страницы не известно, включён он или нет.
Но мы можем догадаться о его состоянии из событий:
<ol>
<li>Проверив символ, полученный по `keypress`. Символ в верхнем регистре без нажатого [key Shift] означает, что включён [key CapsLock]. Аналогично, символ в нижнем регистре, но с [key Shift] говорят о включенном [key CapsLock]. Свойство `event.shiftKey` показывает, нажат ли [key Shift]. Так мы можем точно узнать, нажат ли [key CapsLock].</li>
<li>Проверять `keydown`. Если нажат CapsLock (скан-код равен `20`), то переключить состояние, но лишь в том случае, когда оно уже известно.
Под Mac так делать не получится, поскольку клавиатурные события с CapsLock [работают некорректно](#keyboard-events-order).</li>
</ol>
Имея состояние `CapsLock` в переменной, можно при фокусировке на `INPUT` выдавать предупреждение.
Отслеживать оба события: `keydown` и `keypress` хорошо бы на уровне документа, чтобы уже на момент входа в поле ввода мы знали состояние CapsLock.
Но при вводе сразу в нужный `input` событие `keypress` событие доплывёт до `document` и поставит состояние CapsLock *после того, как сработает на `input`*. Как это обойти -- подумайте сами.
# Решение
При загрузке страницы, когда еще ничего не набрано, мы ничего не знаем о состоянии [key CapsLock], поэтому оно равно `null`:
```js
var capsLockEnabled = null;
```
Когда нажата клавиша, мы можем попытаться проверить, совпадает ли регистр символа и состояние [key Shift]:
```js
document.onkeypress = function(e) {
var chr = getChar(e);
if (!chr) return; // специальная клавиша
if (chr.toLowerCase() == chr.toUpperCase()) {
// символ, который не имеет регистра, такой как пробел,
// мы не можем использовать для определения состояния CapsLock
return;
}
capsLockEnabled = (chr.toLowerCase() == chr && e.shiftKey) || (chr.toUpperCase() == chr && !e.shiftKey);
}
```
Когда пользователь нажимает [key CapsLock], мы должны изменить его текущее состояние. Но мы можем сделать это только если знаем, что был нажат [key CapsLock].
Например, когда пользователь открыл страницу, мы не знаем, включен ли [key CapsLock]. Затем, мы получаем событие `keydown` для [key CapsLock]. Но мы все равно не знаем его состояния, был ли [key CapsLock] *выключен* или, наоборот, включен.
```js
if (navigator.platform.substr(0, 3) != 'Mac') { // событие для CapsLock глючит под Mac
document.onkeydown = function(e) {
if (e.keyCode == 20 && capsLockEnabled !== null) {
capsLockEnabled = !capsLockEnabled;
}
};
}
```
Теперь поле. Задание состоит в том, чтобы предупредить пользователя о включенном CapsLock, чтобы уберечь его от неправильного ввода.
<ol>
<li>Для начала, когда пользователь сфокусировался на поле, мы должны вывести предупреждение о CapsLock, если он включен.</li>
<li>Пользователь начинает ввод. Каждое событие `keypress` всплывает до обработчика `document.keypress`, который обновляет состояние `capsLockEnabled`.
Мы не можем использовать событие `input.onkeypress`, для отображения состояния пользователю, потому что оно сработает *до* `document.onkeypress` (из-за всплытия) и, следовательно, до того, как мы узнаем состояние [key CapsLock].
Есть много способов решить эту проблему. Можно, например, назначить обработчик состояния CapsLock на событие `input.onkeyup`. То есть, индикация будет с задержкой, но это несущественно.
Альтернативное решение -- добавить на `input` такой же обработчик, как и на `document.onkeypress`.
</li>
<li>...И наконец, пользователь убирает фокус с поля. Предупреждение может быть видно, если [key CapsLock] включен, но так как пользователь уже ушел с поля, то нам нужно спрятать предупреждение.</li>
</ol>
Код проверки поля:
```html
<input type="text" onkeyup="checkCapsWarning(event)" onfocus="checkCapsWarning(event)" onblur="removeCapsWarning()" />
<div style="display:none;color:red" id="caps">Внимание: нажат CapsLock!</div>
<script>
function checkCapsWarning() {
document.getElementById('caps').style.display = capsLockEnabled ? 'block' : 'none';
}
function removeCapsWarning() {
document.getElementById('caps').style.display = 'none';
}
</script>
```
[edit src="solution"]Полный код решения[/edit]

View file

@ -1,77 +0,0 @@
<!DOCTYPE HTML>
<html>
<head>
<meta charset="utf-8">
</head>
<body>
Введите текст(например, пароль) с нажатым CapsLock:
<input type="text" onkeyup="checkCapsWarning(event)" onfocus="checkCapsWarning(event)" onblur="removeCapsWarning()" />
<div style="display:none;color:red" id="capsIndicator">Внимание: нажат CapsLock!</div>
<script>
/**
* Текущее состояние CapsLock
* - null : неизвестно
* - true/false : CapsLock включен/выключен
*/
var capsLockEnabled = null;
function getChar(event) {
if (event.which == null) {
if (event.keyCode < 32) return null;
return String.fromCharCode(event.keyCode) // IE
}
if (event.which != 0 && event.charCode != 0) {
if (event.which < 32) return null;
return String.fromCharCode(event.which) // остальные
}
return null; // специальная клавиша
}
if (navigator.platform.substr(0, 3) != 'Mac') { // событие для CapsLock глючит под Mac
document.onkeydown = function(e) {
if (e.keyCode == 20 && capsLockEnabled !== null) {
capsLockEnabled = !capsLockEnabled;
}
}
}
document.onkeypress = function(e) {
e = e || event;
var chr = getChar(e);
if (!chr) return // special key
if (chr.toLowerCase() == chr.toUpperCase()) {
// символ, не зависящий от регистра, например пробел
// не может быть использован для определения CapsLock
return;
}
capsLockEnabled = (chr.toLowerCase() == chr && e.shiftKey) || (chr.toUpperCase() == chr && !e.shiftKey);
}
/**
* Проверить CapsLock
*/
function checkCapsWarning() {
document.getElementById('capsIndicator').style.display = capsLockEnabled ? 'block' : 'none';
}
function removeCapsWarning() {
document.getElementById('capsIndicator').style.display = 'none';
}
</script>
</body>
</html>

View file

@ -1,19 +0,0 @@
<!DOCTYPE HTML>
<html>
<head>
<meta charset="utf-8">
</head>
<body>
Введите текст(например, пароль) с нажатым CapsLock:
<input type="text" />
<div style="display:none;color:red" id="capsIndicator">Внимание: нажат CapsLock!</div>
</body>
</html>

View file

@ -1,10 +0,0 @@
# Поле, предупреждающее о включенном CapsLock
[importance 3]
Создайте поле, которое будет предупреждать пользователя, если включен [key CapsLock]. Выключение [key CapsLock] уберёт предупреждение.
Такое поле может помочь избежать ошибок при вводе пароля.
[iframe height=80 src="solution"]

View file

@ -1,340 +0,0 @@
# Фокусировка: focus/blur
Говорят, что элемент "получает фокус", когда посетитель фокусируется на нём. Обычно фокусировка автоматически происходит при нажатии на элементе мышкой, но также можно перейти на нужный элемент клавиатурой -- через клавишу [key Tab], нажатие пальцем на планшете и так далее.
Момент получения фокуса и потери очень важен.
При получении фокуса мы можем подгрузить данные для автодополнения, начать отслеживать изменения. При потере -- проверить данные, которые ввёл посетитель.
Кроме того, иногда полезно "вручную", из JavaScript перевести фокус на нужный элемент, например, на поле в динамически созданной форме.
[cut]
## События focus/blur
Событие `focus` вызывается тогда, когда пользователь фокусируется на элементе, а `blur` -- когда фокус исчезает, например посетитель кликает на другом месте экрана.
Давайте сразу посмотрим на них в деле, используем для проверки ("валидации") введённых в форму значений.
В примере ниже:
<ul>
<li>Обработчик `onblur` проверяет, что в поле введено число, если нет -- показывает ошибку.</li>
<li>Обработчик `onfocus`, если текущее состояние поля ввода -- "ошибка" -- скрывает её (потом при `onblur` будет повторная проверка).</li>
</ul>
В примере ниже, если набрать что-нибудь в поле "возраст" и завершить ввод, нажав [key Tab] или кликнув в другое место страницы, то введённое значение будет автоматически проверено:
```html
<!--+ run autorun height=60 -->
<style> .error { border-color: red; } </style>
Введите ваш возраст: <input type="text" id="input">
<div id="error"></div>
<script>
*!*input.onblur*/!* = function() {
if (isNaN(this.value)) { // введено не число
// показать ошибку
this.className = "error";
error.innerHTML = 'Вы ввели не число. Исправьте, пожалуйста.'
}
};
*!*input.onfocus*/!* = function() {
if (this.className == 'error') { // сбросить состояние "ошибка", если оно есть
this.className = "";
error.innerHTML = "";
}
};
</script>
```
## Методы focus/blur
Методы с теми же названиями переводят/уводят фокус с элемента.
Для примера модифицируем пример выше, чтобы при неверном вводе посетитель просто не мог уйти с элемента:
```html
<!--+ run autorun height=80 -->
<style>
.error {
background: red;
}
</style>
<div>Возраст:
<input type="text" id="age">
</div>
<div>Имя:
<input type="text">
</div>
<script>
age.onblur = function() {
if (isNaN(this.value)) { // введено не число
// показать ошибку
this.classList.add("error");
*!*
//... и вернуть фокус обратно
age.focus();
*/!*
} else {
this.classList.remove("error");
}
};
</script>
```
Этот пример работает во всех браузерах, кроме Firefox ([ошибка](https://bugzilla.mozilla.org/show_bug.cgi?id=53579)).
Если ввести что-то нецифровое в поле "возраст", и потом попытаться табом или мышкой перейти на другой `<input>`, то обработчик `onblur` вернёт фокус обратно.
Обратим внимание -- если из `onblur` сделать `event.preventDefault()`, то такого же эффекта не будет, потому что `onblur` срабатывает уже *после* того, как элемент потерял фокус.
## HTML5 и CSS3 вместо focus/blur
Прежде чем переходить к более сложным примерам, использующим JavaScript, мы рассмотрим три примера, когда его использовать не надо, а достаточно современного HTML/CSS.
### Подсветка при фокусировке
Стилизация полей ввода может быть решена средствами CSS (CSS2.1), а именно -- селектором `:focus`:
```html
<!--+ autorun height=100 -->
<style>
*!*input:focus*/!* {
background: #FA6;
outline: none; /* убрать рамку */
}
</style>
<input type="text">
<p>Селектор :focus выделит элемент при фокусировке на нем и уберёт рамку, которой браузер выделяет этот элемент по умолчанию.</p>
```
В IE (включая более старые) скрыть фокус также может установка специального атрибута [hideFocus](http://msdn.microsoft.com/en-us/library/ie/ms533783.aspx).
### Автофокус
При загрузке страницы, если на ней существует элемент с атрибутом `autofocus` -- браузер автоматически фокусируется на этом элементе. Работает во всех браузерах, кроме IE9-.
```html
<!--+ run link -->
<input type="text" name="search" *!*autofocus*/!*>
```
Если нужны старые IE, то же самое может сделать JavaScript:
```html
<input type="text" name="search">
<script>
document.getElementsByName('search')[0].focus();
</script>
```
Как правило, этот атрибут используется при изначальной загрузке, для страниц поиска и так далее, где главный элемент очевиден.
### Плейсхолдер
*Плейсхолдер* -- это значение-подсказка внутри `INPUT`, которое автоматически исчезает при фокусировке и существует, пока посетитель не начал вводить текст.
Во всех браузерах, кроме IE9-, это реализуется специальным атрибутом `placeholder`:
```html
<!--+ autorun height=80 -->
<input type="text" placeholder="E-mail">
```
В некоторых браузерах этот текст можно стилизовать:
```html
<!--+ autorun height=80 -->
<style>
.my*!*::-webkit-input-placeholder*/!* {
color: red;
font-style: italic;
}
.my*!*::-moz-input-placeholder*/!* {
color: red;
font-style: italic;
}
.my*!*::-ms-input-placeholder*/!* {
color: red;
font-style: italic;
}
</style>
<input class="my" type="text" placeholder="E-mail">
Стилизованный плейсхолдер
```
## Разрешаем фокус на любом элементе: tabindex
По умолчанию не все элементы поддерживают фокусировку.
Перечень элементов немного рознится от браузера к браузеру, например, список для IE описан <a href="http://msdn.microsoft.com/en-us/library/ms536934.aspx">в MSDN</a>, одно лишь верно всегда -- заведомо поддерживают `focus/blur` те элементы, c которыми посетитель может взаимодействовать: `<button>`, `<input>`, `<select>`, `<a>` и т.д.
С другой стороны, на элементах для форматирования, таких как `<div>`, `<span>`, `<table>` -- по умолчанию сфокусироваться нельзя. Впрочем, существует способ включить фокусировку и для них.
В HTML есть атрибут `tabindex`.
Его основной смысл -- это указать номер элемента при переборе клавишей [key Tab].
То есть, если есть два элемента, первый имеет `tabindex="1"`, а второй `tabindex="2"`, то нажатие [key Tab] при фокусе на первом элементе -- переведёт его на второй.
Исключением являются специальные значения:
<ul>
<li>`tabindex="0"` делает элемент всегда последним.</li>
<li>`tabindex="-1"` означает, что клавиша [key Tab] будет элемент игнорировать.</li>
</ul>
**Любой элемент поддерживает фокусировку, если у него есть `tabindex`.**
В примере ниже есть список элементов. Кликните на любой из них и нажмите "tab".
```html
<!--+ autorun no-beautify -->
Кликните на первый элемент списка и нажмите Tab. Внимание! Дальнейшие нажатия Tab могут вывести за границы iframe'а с примером.
<ul>
<li tabindex="1">Один</li>
<li tabindex="0">Ноль</li>
<li tabindex="2">Два</li>
<li tabindex="-1">Минус один</li>
</ul>
<style>
li { cursor: pointer; }
:focus { outline: 1px dashed green; }
</style>
```
Порядок перемещения по клавише "Tab" в примере выше должен быть таким: `1 - 2 - 0` (ноль всегда последний). Продвинутые пользователи частенько используют "Tab" для навигации, и ваше хорошее отношение к ним будет вознаграждено :)
Обычно `<li>` не поддерживает фокусировку, но здесь есть `tabindex`.
## Делегирование с focus/blur
События `focus` и `blur` не всплывают.
Это грустно, поскольку мы не можем использовать делегирование с ними. Например, мы не можем сделалать так, чтобы при фокусировке в форме она вся подсвечивалась:
```html
<!--+ autorun height=100 -->
<!-- при фокусировке на форме ставим ей класс -->
<form *!*onfocus="this.className='focused'"*/!*>
<input type="text" name="name" value="Ваше имя">
<input type="text" name="surname" value="Ваша фамилия">
</form>
<style> .focused { outline: 1px solid red; } </style>
```
Пример выше не работает, т.к. при фокусировке на любом `<input>` событие `focus` срабатывает только на этом элементе и не всплывает наверх. Так что обработчик `onfocus` на форме никогда не сработает.
Что делать? Неужели мы должны присваивать обработчик каждому полю `<input>`?
**Это забавно, но хотя `focus/blur` не всплывают, они могут быть пойманы на фазе перехвата.**
Вот так сработает:
```html
<!--+ autorun height=100 -->
<form id="form">
<input type="text" name="name" value="Ваше имя">
<input type="text" name="surname" value="Ваша фамилия">
</form>
<style>
.focused {
outline: 1px solid red;
}
</style>
<script>
*!*
// ставим обработчики на фазе перехвата, последний аргумент true
form.addEventListener("focus", function() {
this.classList.add('focused');
}, true);
form.addEventListener("blur", function() {
this.classList.remove('focused');
}, true);
*/!*
</script>
```
### События focusin/focusout
События `focusin/focusout` -- то же самое, что и `focus/blur`, только они всплывают.
У них две особенности:
<ul>
<li>Не поддерживаются Firefox (хотя поддерживаются даже старейшими IE), см. [](https://bugzilla.mozilla.org/show_bug.cgi?id=687787).</li>
<li>Должны быть назначены не через `on`-свойство, а при помощи `elem.addEventListener`.</li>
</ul>
Из-за отсутствия подержки Firefox эти события используют редко. Получается, что во всех браузерах можно использовать `focus` на стадии перехвата, ну а `focusin/focusout` -- в IE8-, где стадии перехвата нет.
Подсветка формы в примере ниже работает во всех браузерах.
```html
<!--+ autorun height=60 run -->
<form name="form">
<input type="text" name="name" value="Ваше имя">
<input type="text" name="surname" value="Ваша фамилия">
</form>
<style>
.focused {
outline: 1px solid red;
}
</style>
<script>
function onFormFocus() {
this.className = 'focused';
}
function onFormBlur() {
this.className = '';
}
var form = document.forms.form;
if (form.addEventListener) {
// focus/blur на стадии перехвата срабатывают во всех браузерах
// поэтому используем их
form.addEventListener('focus', onFormFocus, true);
form.addEventListener('blur', onFormBlur, true);
} else {
// ветка для IE8-, где нет стадии перехвата, но есть focusin/focusout
form.onfocusin = onFormFocus;
form.onfocusout = onFormBlur;
}
</script>
```
## Итого
События `focus/blur` происходят при получении и снятия фокуса с элемента.
У них есть особенности:
<ul>
<li>Они не всплывают. Но на фазе перехвата их можно перехватить. Это странно, но это так, не спрашивайте почему.
Везде, кроме Firefox, поддерживаются всплывающие альтернативы `focusin/focusout`.</li>
<li>По умолчанию многие элементы не могут получить фокус. Например, если вы кликните по `DIV`, то фокусировка на нем не произойдет.
Но это можно изменить, если поставить элементу атрибут `tabIndex`. Этот атрибут также дает возможность контролировать порядок перехода при нажатии [key Tab].
</li>
</ul>
[smart header="Текущий элемент: `document.activeElement`"]
Кстати, текущий элемент, на котором фокус, доступен как `document.activeElement`.
[/smart]

View file

@ -1,10 +0,0 @@
Алгоритм решения такой.
Только численный ввод в поле с суммой разрешаем, повесив обработчик на `keypress`.
Отслеживаем события изменения для перевычисления результатов:
<ul>
<li>На `input`: событие `input` и дополнительно `propertychange/keyup` для совместимости со старыми IE.</li>
<li>На `checkbox`: событие `click` вместо `change` для совместимости с IE8-.</li>
<li>На `select`: событие `change`.</li>
</ul>

View file

@ -1,153 +0,0 @@
<!DOCTYPE html>
<html>
<head>
<meta charset="utf-8">
<style>
td select,
td input {
width: 150px;
}
#diagram td {
vertical-align: bottom;
text-align: center;
padding: 10px;
}
#diagram div {
margin: auto;
}
</style>
</head>
<body>
Калькулятор процентов, из расчёта 12% годовых.
<form name="calculator">
<table>
<tr>
<td>Сумма</td>
<td>
<input name="money" type="text" value="10000">
</td>
</tr>
<tr>
<td>Срок в месяцах</td>
<td>
<select name="months">
<option value="3">3 (минимум)</option>
<option value="6">6 (полгода)</option>
<option value="12" selected>12 (год)</option>
<option value="18">18 (1.5 года)</option>
<option value="24">24 (2 года)</option>
<option value="30">30 (2.5 года)</option>
<option value="36">36 (3 года)</option>
</select>
</td>
</tr>
<tr>
<td>С капитализацией</td>
<td>
<input name="capitalization" type="checkbox">
</td>
</tr>
</table>
</form>
<table id="diagram">
<tr>
<th>Было:</th>
<th>Станет:</th>
</tr>
<tr>
<th id="money-before"></th>
<th id="money-after"></th>
</tr>
<td>
<div style="background: red;width:40px;height:100px"></div>
</td>
<td>
<div style="background: green;width:40px;height:0" id="height-after"></div>
</td>
</table>
<script>
// event.type должен быть keypress
function getChar(event) {
if (event.which == null) {
if (event.keyCode < 32) return null;
return String.fromCharCode(event.keyCode) // IE
}
if (event.which != 0 && event.charCode != 0) {
if (event.which < 32) return null;
return String.fromCharCode(event.which) // остальные
}
return null; // специальная клавиша
}
var form = document.forms.calculator;
var moneyElem = form.elements.money;
moneyElem.onkeypress = function(e) {
e = e || event;
var chr = getChar(e);
if (e.ctrlKey || e.altKey || chr == null) return; // специальная клавиша
if (chr < '0' || chr > '9') return false;
}
// клавиатура, вставить/вырезать клавиатурой
moneyElem.onkeyup = calculate;
// любые действия, кроме IE. В IE9 также работает, кроме удаления
moneyElem.oninput = calculate;
moneyElem.onpropertychange = function() { // для IE8- изменение значения, кроме удаления
event.propertyName == "value" && calculate();
}
var capitalizationElem = form.elements.capitalization;
capitalizationElem.onclick = calculate;
var monthsElem = form.elements.months;
monthsElem.onchange = calculate;
function calculate() {
var sum = +moneyElem.value;
if (!sum) return;
var monthlyIncrease = 0.01;
if (!capitalizationElem.checked) {
sum = sum * (1 + monthlyIncrease * monthsElem.value);
} else {
for (var i = 0; i < monthsElem.value; i++) {
// 1000 1010 1020.1
sum = sum * (1 + monthlyIncrease);
}
}
sum = Math.round(sum);
var height = sum / moneyElem.value * 100 + 'px';
document.getElementById('height-after').style.height = height;
document.getElementById('money-before').innerHTML = moneyElem.value;
document.getElementById('money-after').innerHTML = sum;
}
calculate();
</script>
</body>
</html>

View file

@ -1,102 +0,0 @@
<!DOCTYPE html>
<html>
<head>
<meta charset="utf-8">
<style>
td select,
td input {
width: 150px;
}
#diagram td {
vertical-align: bottom;
text-align: center;
padding: 10px;
}
#diagram div {
margin: auto;
}
</style>
</head>
<body>
Калькулятор процентов, из расчёта 12% годовых.
<form name="calculator">
<table>
<tr>
<td>Сумма</td>
<td>
<input name="money" type="text" value="10000">
</td>
</tr>
<tr>
<td>Срок в месяцах</td>
<td>
<select name="months">
<option value="3">3 (минимум)</option>
<option value="6">6 (полгода)</option>
<option value="12" selected>12 (год)</option>
<option value="18">18 (1.5 года)</option>
<option value="24">24 (2 года)</option>
<option value="30">30 (2.5 года)</option>
<option value="36">36 (3 года)</option>
</select>
</td>
</tr>
<tr>
<td>С капитализацией</td>
<td>
<input name="capitalization" type="checkbox">
</td>
</tr>
</table>
</form>
<table id="diagram">
<tr>
<th>Было:</th>
<th>Станет:</th>
</tr>
<tr>
<th id="money-before"></th>
<th id="money-after"></th>
</tr>
<td>
<div style="background: red;width:40px;height:100px"></div>
</td>
<td>
<div style="background: green;width:40px;height:0" id="height-after"></div>
</td>
</table>
<script>
// вспомогательная функция для получения символа из события keypress
// (вдруг понадобится))
function getChar(event) {
if (event.which == null) {
if (event.keyCode < 32) return null;
return String.fromCharCode(event.keyCode) // IE
}
if (event.which != 0 && event.charCode != 0) {
if (event.which < 32) return null;
return String.fromCharCode(event.which) // остальные
}
return null; // специальная клавиша
}
// ваш код...
</script>
</body>
</html>

View file

@ -1,20 +0,0 @@
# Автовычисление процентов по вкладу
[importance 5]
Создайте интерфейс для автоматического вычисления процентов по вкладу.
Ставка фиксирована: 12% годовых. При включённом поле "капитализация" -- проценты приплюсовываются к сумме вклада каждый месяц ([сложный процент](http://damoney.ru/finance/slozniy-procent.php)).
Пример:
[iframe src="solution" height="350" border="1"]
Технические требования:
<ul>
<li>В поле с суммой должно быть нельзя ввести не-цифру. При этом пусть в нём работают специальные клавиши и сочетания Ctrl-X/Ctrl-V.</li>
<li>Изменения в форме отражаются в результатах сразу.</li>
</ul>

View file

@ -1,218 +0,0 @@
# Изменение: change, input, cut, copy, paste
На элементах формы происходят события клавиатуры и мыши, но есть и несколько других, особенных событий.
## Событие change
Событие [change](http://www.w3.org/TR/html5/forms.html#event-input-change) происходит по окончании изменении значения элемента формы, когда это изменение зафиксировано.
Для текстовых элементов это означает, что событие произойдёт не при каждом вводе, а при потере фокуса.
Например, пока вы набираете что-то в текстовом поле ниже -- события нет. Но как только вы уведёте фокус на другой элемент, например, нажмёте кнопку -- произойдет событие `onchange`.
```html
<!--+ autorun height=40 -->
<input type="text" onchange="alert(this.value)">
<input type="button" value="Кнопка">
```
Для остальных же элементов: `select`, `input type=checkbox/radio` оно срабатывает сразу при выборе значения.
[warn header="Поздний `onchange` в IE8-"]
В IE8- `checkbox/radio` при изменении мышью не инициируют событие сразу, а ждут потери фокуса.
Для того, чтобы видеть изменения `checkbox/radio` тут же -- в IE8- нужно повесить обработчик на событие `click` (оно произойдет и при изменении значения с клавиатуры) или воспользоваться событием `propertychange`, описанным далее.
[/warn]
## Событие input
Событие `input` срабатывает *тут же* при изменении значения текстового элемента и поддерживается всеми браузерами, кроме IE8-.
В IE9 оно поддерживается частично, а именно -- *не возникает при удалении символов* (как и `onpropertychange`).
Пример использования (не работает в IE8-):
```html
<!--+ autorun height=40 -->
<input type="text"> oninput: <span id="result"></span>
<script>
var input = document.body.children[0];
input.oninput = function() {
document.getElementById('result').innerHTML = input.value;
};
</script>
```
В современных браузерах `oninput` -- самое главное событие для работы с элементом формы. Именно его, а не `keydown/keypress` следует использовать.
Если бы ещё не проблемы со старыми IE... Впрочем, их можно решить при помощи события `propertychange`.
## IE10-, событие propertychange
Это событие происходит только в IE10-, при любом изменении свойства. Оно позволяет отлавливать изменение тут же. Оно нестандартное, и его основная область использования -- исправление недочётов обработки событий в старых IE.
Если поставить его на `checkbox` в IE8-, то получится "правильное" событие `change`:
```html
<!--+ autorun height=40 -->
<input type="checkbox"> Чекбокс с "onchange", работающим везде одинаково
<script>
var checkbox = document.body.children[0];
if ("onpropertychange" in checkbox) {
// старый IE
*!*
checkbox.onpropertychange = function() {
// проверим имя изменённого свойства
if (event.propertyName == "checked") {
alert( checkbox.checked );
}
};
*/!*
} else {
// остальные браузеры
checkbox.onchange = function() {
alert( checkbox.checked );
};
}
</script>
```
Это событие также срабатывает при изменении значения текстового элемента. Поэтому его можно использовать в старых IE вместо `oninput`.
К сожалению, в IE9 у него недочёт: оно не срабатывает при удалении символов. Поэтому сочетания `onpropertychange` + `oninput` недостаточно, чтобы поймать любое изменение поля в старых IE. Далее мы рассмотрим пример, как это можно сделать иначе.
## События cut, copy, paste
Эти события используются редко. Они происходят при вырезании/вставке/копировании значения.
К сожалению, кросс-браузерного способа получить данные, которые вставляются/копируются, не существует, поэтому их основное применение -- это отмена соответствующей операции.
Например, вот так:
```html
<!--+ autorun height=40 -->
<input type="text" id="input"> event: <span id="result"></span>
<script>
input.oncut = input.oncopy = input.onpaste = function(event) {
result.innerHTML = event.type + ' ' + input.value;
return false;
};
</script>
```
## Пример: поле с контролем СМС
Как видим, событий несколько и они взаимно дополняют друг друга.
Посмотрим, как их использовать, на примере.
Сделаем поле для СМС, рядом с которым должно показываться число символов, обновляющееся при каждом изменении поля.
Как такое реализовать?
Событие `input` идеально решит задачу во всех браузерах, кроме IE9-. Собственно, если IE9- нам не нужен, то на этом можно и остановиться.
### IE9-
В IE8- событие `input` не поддерживается, но, как мы видели ранее, есть `onpropertychange`, которое может заменить его.
Что же касается IE9 -- там поддерживаются и `input` и `onpropertychange`, но они оба не работают при удалении символов. Поэтому мы будем отслеживать удаление при помощи `keyup` на [key Delete] и [key BackSpace] . А вот удаление командой "вырезать" из меню -- сможет отловить лишь `oncut`.
Получается вот такая комбинация:
```html
<!--+ autorun run height=60 -->
<input type="text" id="sms"> символов: <span id="result"></span>
<script>
function showCount() {
result.innerHTML = sms.value.length;
}
sms.onkeyup = sms.oninput = showCount;
sms.onpropertychange = function() {
if (event.propertyName == "value") showCount();
}
sms.oncut = function() {
setTimeout(showCount, 0); // на момент oncut значение еще старое
};
</script>
```
Здесь мы добавили вызов `showCount` на все события, которые могут приводить к изменению значения. Да, иногда изменение будет обрабатываться несколько раз, но зато с гарантией. А лишние вызовы легко убрать, например, при помощи `throttle`-декоратора, описанного в задаче [](/task/throttle).
**Есть и совсем другой простой, но действенный вариант: через `setInterval` регулярно проверять значение и, если оно слишком длинное, обрезать его.**
Чтобы сэкономить ресурсы браузера, мы можем начинать отслеживание по `onfocus`, а прекращать -- по `onblur`, вот так:
```html
<!--+ autorun height=60 -->
<input type="text" id="sms"> символов: <span id="result"></span>
<script>
var timerId;
sms.onfocus = function() {
var lastValue = sms.value;
timerId = setInterval(function() {
if (sms.value != lastValue) {
showCount();
lastValue = sms.value;
}
}, 20);
};
sms.onblur = function() {
clearInterval(timerId);
};
function showCount() {
result.innerHTML = sms.value.length;
}
</script>
```
Обратим внимание -- весь этот "танец с бубном" нужен только для поддержки IE8-, в которых не поддерживается `oninput` и IE9, где `oninput` не работает при удалении.
## Итого
События изменения данных:
<table>
<thead>
<tr>
<th>Событие</th>
<th>Описание</th>
<th>Особенности</th>
</tr>
</thead>
<tbody>
<tr>
<td>`change`</td>
<td>Изменение значения любого элемента формы. Для текстовых элементов срабатывает при потере фокуса.</td>
<td>В IE8- на чекбоксах ждет потери фокуса, поэтому для мгновенной реакции ставят также `onclick`-обработчик или `onpropertychange`.</td>
</tr>
<tr>
<td>`input`</td>
<td>Событие срабатывает только на текстовых элементах. Оно не ждет потери фокуса, в отличие от `change`.</td>
<td>В IE8- не поддерживается, в IE9 не работает при удалении символов.</td>
</tr>
<tr>
<td>`propertychange`</td>
<td>Только для IE10-. Универсальное событие для отслеживания изменения свойств элементов. Имя изменённого свойства содержится в `event.propertyName`. Используют для мгновенной реакции на изменение значения в старых IE.
</td>
<td>В IE9 не срабатывает при удалении символов.</td>
</tr>
<tr>
<td>`cut/copy/paste`</td>
<td>Срабатывают при вставке/копировании/удалении текста. Если в их обработчиках отменить действие браузера, то вставки/копирования/удаления не произойдёт.</td>
<td>Вставляемое значение получить нельзя: на момент срабатывания события в элементе всё ещё *старое* значение, а новое недоступно.</td>
</tr>
</tbody>
</table>
Ещё особенность: в IE8- события `change`, `propertychange`, `cut` и аналогичные не всплывают. То есть, обработчики нужно назначать на сам элемент, без делегирования.

View file

@ -1,21 +0,0 @@
Модальное окно делается путём добавления к документу `DIV`, полностью перекрывающего документ и имеющего больший `z-index`.
В результате все клики будут доставаться этому `DIV'у`:
Стиль:
```css
#cover-div {
position: fixed;
top: 0;
left: 0;
z-index: 9000;
width: 100%;
height: 100%;
background-color: gray;
opacity: 0.3;
}
```
Самой форме можно дать еще больший `z-index`, чтобы она была над `DIV'ом`. Мы не помещаем форму в контейнер, чтобы она не унаследовала полупрозрачность.

View file

@ -1,155 +0,0 @@
<!DOCTYPE html>
<html>
<head>
<meta charset="utf-8">
<style>
html,
body {
margin: 0;
padding: 0;
width: 100%;
height: 100%;
}
#prompt-form {
display: inline-block;
padding: 5px 5px 5px 70px;
width: 200px;
border: 1px solid black;
background: white url(https://js.cx/clipart/prompt.png) no-repeat left 5px;
vertical-align: middle;
}
#prompt-form-container {
position: fixed;
top: 0;
left: 0;
z-index: 9999;
display: none;
width: 100%;
height: 100%;
text-align: center;
}
#prompt-form-container:before {
display: inline-block;
height: 100%;
content: '';
vertical-align: middle;
}
#cover-div {
position: fixed;
top: 0;
left: 0;
z-index: 9000;
width: 100%;
height: 100%;
background-color: gray;
opacity: 0.3;
}
#prompt-form input[name="text"] {
display: block;
margin: 5px;
width: 180px;
}
</style>
</head>
<body style="height:3000px">
<h1>Нажмите на кнопку ниже</h1>
<input type="button" value="Нажмите для показа формы ввода" id="show-button">
<div id="prompt-form-container">
<form id="prompt-form">
<div id="prompt-message"></div>
<input name="text" type="text">
<input type="submit" value="Ок">
<input type="button" name="cancel" value="Отмена">
</form>
</div>
<script>
// Показать полупрозрачный DIV, затеняющий всю страницу
// (а форма будет не в нем, а рядом с ним, чтобы не полупрозрачная)
function showCover() {
var coverDiv = document.createElement('div');
coverDiv.id = 'cover-div';
document.body.appendChild(coverDiv);
}
function hideCover() {
document.body.removeChild(document.getElementById('cover-div'));
}
function showPrompt(text, callback) {
showCover();
var form = document.getElementById('prompt-form');
var container = document.getElementById('prompt-form-container');
document.getElementById('prompt-message').innerHTML = text;
form.elements.text.value = '';
function complete(value) {
hideCover();
container.style.display = 'none';
document.onkeydown = null;
callback(value);
}
form.onsubmit = function() {
var value = form.elements.text.value;
if (value == '') return false; // игнорировать пустой submit
complete(value);
return false;
};
form.elements.cancel.onclick = function() {
complete(null);
};
document.onkeydown = function(e) {
if (e.keyCode == 27) { // escape
complete(null);
}
};
var lastElem = form.elements[form.elements.length - 1];
var firstElem = form.elements[0];
lastElem.onkeydown = function(e) {
if (e.keyCode == 9 && !e.shiftKey) {
firstElem.focus();
return false;
}
};
firstElem.onkeydown = function(e) {
if (e.keyCode == 9 && e.shiftKey) {
lastElem.focus();
return false;
}
};
container.style.display = 'block';
form.elements.text.focus();
}
document.getElementById('show-button').onclick = function() {
showPrompt("Введите что-нибудь<br>...умное :)", function(value) {
alert("Вы ввели: " + value);
});
};
</script>
</body>
</html>

View file

@ -1,65 +0,0 @@
<!DOCTYPE html>
<html>
<head>
<meta charset="utf-8">
<style>
html,
body {
width: 100%;
height: 100%;
padding: 0;
margin: 0;
}
#prompt-form {
display: inline-block;
padding: 5px 5px 5px 70px;
width: 200px;
border: 1px solid black;
background: white url(https://js.cx/clipart/prompt.png) no-repeat left 5px;
vertical-align: middle;
}
#prompt-form-container {
position: fixed;
top: 0;
left: 0;
z-index: 9999;
width: 100%;
height: 100%;
text-align: center;
}
#prompt-form-container:before {
display: inline-block;
height: 100%;
content: '';
vertical-align: middle;
}
#prompt-form input[name="text"] {
display: block;
margin: 5px;
width: 180px;
}
</style>
</head>
<body>
<div id="prompt-form-container">
<form id="prompt-form">
<div id="prompt-message">Введите, пожалуйста...
<br>Что-то..</div>
<input name="text" type="text">
<input type="submit" value="Ок">
<input type="button" name="cancel" value="Отмена">
</form>
</div>
</body>
</html>

View file

@ -1,34 +0,0 @@
# Модальное диалоговое окно
[importance 5]
Создайте функцию `showPrompt(text, callback)`, которая выводит форму для ввода с сообщением `text` и кнопками `ОК/Отмена`.
<ul>
<li>При отправке формы (OK/ввод в текстовом поле) -- должна вызываться функция `callback` со значением поля.</li>
<li>При нажатии на `Отмена` или на клавишу [key Esc] -- должна вызываться функция `callback(null)`. Клавиша [key Esc] должна закрывать форму всегда, даже если поле для ввода сообщения не в фокусе.</li>
</ul>
Особенности реализации:
<ul>
<li>Форма должна показываться в центре окна (и оставаться в центре при изменении его размеров, а также при прокрутке окна!).</li>
<li>Текст может состоять из нескольких строк, возможен любой HTML</li>
<li>При показе формы остальные элементы страницы использовать нельзя, не работают другие кнопки и т.п, это окно -- *модальное*.</li>
<li>При показе формы -- сразу фокус на `INPUT` для ввода.</li>
<li>Нажатия [key Tab]/[key Shift+Tab] переключают в цикле только по полям формы, они не позволяют переключиться на другие элементы страницы.</li>
</ul>
Пример использования:
```js
showPrompt("Введите что-нибудь<br>... умное :)", function(value) {
alert( value );
});
```
Демо в ифрейме:
[iframe src="solution" height=160 border=1]
Исходный HTML/CSS для формы с готовым fixed-позиционированием - в песочнице.

View file

@ -1,118 +0,0 @@
<!DOCTYPE html>
<html>
<head>
<meta charset="utf-8">
<style>
td select,
td input {
width: 150px;
}
label {
display: block;
}
.error input,
.error textarea {
border: 1px solid red;
}
.error {
color: red;
}
</style>
</head>
<body>
<form>
<table>
<tr>
<td>От кого</td>
<td>
<input name="from" type="text">
</td>
</tr>
<tr>
<td>Ваш пароль</td>
<td>
<input name="password" type="password">
</td>
</tr>
<tr>
<td>Повторите пароль</td>
<td>
<input name="password2" type="password">
</td>
</tr>
<tr>
<td>Куда</td>
<td>
<select name="to">
<option></option>
<option value="1">Отдел снабжения</option>
<option value="2">Отдел разработки</option>
<option value="3">Директору</option>
</select>
</td>
</tr>
</table>
Сообщение:
<label>
<textarea name="message" style="display:block;width:400px;height:80px"></textarea>
</label>
<input type="button" onclick="validate(this.form)" value="Проверить">
</form>
<script>
function showError(container, errorMessage) {
container.className = 'error';
var msgElem = document.createElement('span');
msgElem.className = "error-message";
msgElem.innerHTML = errorMessage;
container.appendChild(msgElem);
}
function resetError(container) {
container.className = '';
if (container.lastChild.className == "error-message") {
container.removeChild(container.lastChild);
}
}
function validate(form) {
var elems = form.elements;
resetError(elems.from.parentNode);
if (!elems.from.value) {
showError(elems.from.parentNode, ' Укажите от кого.');
}
resetError(elems.password.parentNode);
if (!elems.password.value) {
showError(elems.password.parentNode, ' Укажите пароль.');
} else if (elems.password.value != elems.password2.value) {
showError(elems.password.parentNode, ' Пароли не совпадают.');
}
resetError(elems.to.parentNode);
if (!elems.to.value) {
showError(elems.to.parentNode, ' Укажите, куда.');
}
resetError(elems.message.parentNode);
if (!elems.message.value) {
showError(elems.message.parentNode, ' Отсутствует текст.');
}
}
</script>
</body>
</html>

View file

@ -1,74 +0,0 @@
<!DOCTYPE html>
<html>
<head>
<meta charset="utf-8">
<style>
td select,
td input {
width: 150px;
}
label {
display: block;
}
/* ваши стили */
</style>
</head>
<body>
<form>
<table>
<tr>
<td>От кого</td>
<td>
<input name="from" type="text">
</td>
</tr>
<tr>
<td>Ваш пароль</td>
<td>
<input name="password" type="password">
</td>
</tr>
<tr>
<td>Повторите пароль</td>
<td>
<input name="password2" type="password">
</td>
</tr>
<tr>
<td>Куда</td>
<td>
<select name="to">
<option></option>
<option value="1">Отдел снабжения</option>
<option value="2">Отдел разработки</option>
<option value="3">Директору</option>
</select>
</td>
</tr>
</table>
Сообщение:
<label>
<textarea name="message" style="display:block;width:400px;height:100px"></textarea>
</label>
<input type="button" onclick="validate(this.form)" value="Проверить">
</form>
<script>
function validate(form) {
/* ваш код */
}
/* ваш код */
</script>
</body>
</html>

View file

@ -1,17 +0,0 @@
# Валидация формы
[importance 3]
Напишите функцию `validate(form)`, которая проверяет содержимое формы по клику на кнопку "Проверить".
Ошибки:
<ol>
<li>Одно из полей не заполнено.</li>
<li>Пароли не совпадают.</li>
</ol>
Ошибка должна сопровождаться сообщением у поля. Например:
[iframe height=280 src="solution"]

View file

@ -1,65 +0,0 @@
# Формы: отправка, событие и метод submit
Событие `submit` возникает при отправке формы. Наиболее частое его применение -- это *валидация* (проверка) формы перед отправкой.
Метод `submit` позволяет инициировать отправку формы из JavaScript, без участия пользователя. Далее мы рассмотрим детали их использования.
[cut]
## Событие submit
Чтобы отправить форму на сервер, у посетителя есть два способа:
<ol>
<li>**Первый -- это нажать кнопку `<input type="submit">` или `<input type="image">`.**</li>
<li>**Второй -- нажать Enter, находясь на каком-нибудь поле.**</li>
</ol>
Какой бы способ ни выбрал посетитель -- будет сгенерировано событие `submit`. Обработчик в нём может проверить данные и, если они неверны, то вывести ошибку и сделать `event.preventDefault()` -- тогда форма не отправится на сервер.
Например, в таком HTML оба способа выведут `alert`, форма не будет отправлена:
```html
<!--+ autorun height=80 no-beautify -->
<form onsubmit="alert('submit!');return false">
Первый: Enter в текстовом поле <input type="text" value="Текст"><br>
Второй: Нажать на "Отправить": <input type="submit" value="Отправить">
</form>
```
Ожидаемое поведение:
<ol><li>Перейдите в текстовое поле и нажмите Enter, будет событие, но форма не отправится на сервер благодаря `return false` в обработчике.</li>
<li>То же самое произойдет при клике на `<input type="submit">`.</li>
</ol>
[smart header="Взаимосвязь событий `submit` и `click`"]
При отправке формы путём нажатия Enter на текстовом поле, на элементе `<input type="submit">` везде, кроме IE8-, генерируется событие `click`.
Это довольно забавно, учитывая что клика-то и не было.
```html
<!--+ autorun height=80 -->
<form onsubmit="alert('submit');return false">
<input type="text" size="30" value="При нажатии Enter будет click">
<input type="submit" value="Submit" *!*onclick="alert('click')"*/!*>
</form>
```
[/smart]
[warn header="В IE8- событие `submit` не всплывает"]
В IE8- событие `submit` не всплывает. Нужно вешать обработчик `submit` на сам элемент формы, без использования делегирования.
[/warn]
## Метод submit
Чтобы отправить форму на сервер из JavaScript -- нужно вызвать на элементе формы метод `form.submit()`.
При этом само событие `submit` не генерируется. Предполагается, что если программист вызывает метод `form.submit()`, то он выполнил все проверки.
Это используют, в частности, для искусственной генерации и отправки формы.

View file

@ -1,3 +0,0 @@
# Формы, элементы управления
Особые свойства, методы и события для работы с формами `<form>` и элементами ввода: `<input>`, `<select>` и другими.