renovations

This commit is contained in:
Ilya Kantor 2015-02-16 00:00:48 +03:00
parent 0eabad2516
commit 9bf1b61cab
72 changed files with 299 additions and 670 deletions

View file

@ -13,10 +13,10 @@
Можно указать и полный URL, например: Можно указать и полный URL, например:
```html ```html
<script src="http://code.jquery.com/jquery.js"></script> <script src="https://cdnjs.cloudflare.com/ajax/libs/lodash.js/3.2.0/lodash.js"></script>
``` ```
Вы также можете использовать путь относительно текущей страницы, например `src="jquery.js"` обозначает файл из текущей директории. Вы также можете использовать путь относительно текущей страницы, например `src="lodash.js"` обозначает файл из текущей директории.
Чтобы подключить несколько скриптов, используйте несколько тегов: Чтобы подключить несколько скриптов, используйте несколько тегов:

View file

@ -2,7 +2,6 @@
<html> <html>
<head> <head>
<meta charset="utf-8"> <meta charset="utf-8">
<script src="http://code.jquery.com/jquery.min.js"></script>
<style type="text/css"> <style type="text/css">
* { * {
margin: 0; margin: 0;
@ -42,22 +41,21 @@
<script> <script>
var example = document.getElementById('example') var example = document.getElementById('example')
$(function() { var info = document.getElementById('info')
var info = document.getElementById('info')
var props = { var props = {
'размеры': 'размеры':
['clientLeft','clientTop', 'clientWidth','clientHeight','offsetWidth','offsetHeight','scrollWidth', 'scrollHeight'], ['clientLeft','clientTop', 'clientWidth','clientHeight','offsetWidth','offsetHeight','scrollWidth', 'scrollHeight'],
'прокрутка': 'прокрутка':
['scrollLeft','scrollTop'] , ['scrollLeft','scrollTop'] ,
'позиционирование по рендерингу': 'позиционирование по рендерингу':
['offsetParent', 'offsetLeft','offsetTop'] ['offsetParent', 'offsetLeft','offsetTop']
} }
info.innerHTML = '<h3>Нажмите для просмотра значения:</h3>'; info.innerHTML = '<h3>Нажмите для просмотра значения:</h3>';
for (var k in props) { for (var k in props) {
info.innerHTML += '<h4>' + k + '</h4>'; info.innerHTML += '<h4>' + k + '</h4>';
var prop = props[k]; var prop = props[k];
for (var i = 0; i < prop.length; i++) { for (var i = 0; i < prop.length; i++) {
@ -69,21 +67,22 @@
info.innerHTML += "<br/>"; info.innerHTML += "<br/>";
} }
} }
$(document).delegate('span.key','click', function() { document.onclick = function(event) {
var prop = this.innerHTML; var target = event.target;
if (!target.classList.contains('key')) return;
var prop = target.innerHTML;
var value = example[prop]; var value = example[prop];
value = value.tagName || value; value = value.tagName || value;
$('#'+prop).html(value); document.getElementById(prop).innerHTML = value;
}) };
})
document.onmousemove = function(e) { document.onmousemove = function(e) {
e = e || window.event;
document.getElementById('mouse').innerHTML = Math.round(e.clientX)+':'+Math.round(e.clientY); document.getElementById('mouse').innerHTML = Math.round(e.clientX)+':'+Math.round(e.clientY);
} };
</script> </script>

View file

@ -142,7 +142,6 @@ document.getElementById('getBoundingClientRectEx').onclick = function(event) {
var o = getOffsetSum(this); var o = getOffsetSum(this);
var orect = getCoords(this); var orect = getCoords(this);
event = event || window.event;
if ( event.pageX == null && event.clientX != null ) { if ( event.pageX == null && event.clientX != null ) {
var html = document.documentElement, body = document.body; var html = document.documentElement, body = document.body;
event.pageX = event.clientX + (html && html.scrollLeft || body && body.scrollLeft || 0) - (html.clientLeft || 0) event.pageX = event.clientX + (html && html.scrollLeft || body && body.scrollLeft || 0) - (html.clientLeft || 0)

View file

@ -53,12 +53,10 @@
var grid = document.getElementById('grid'); var grid = document.getElementById('grid');
grid.onclick = function(e) { grid.onclick = function(e) {
var target = e && e.target || window.event.srcElement; if (e.target.tagName != 'TH') return;
if (target.tagName != 'TH') return;
// Если TH -- сортируем // Если TH -- сортируем
sortGrid(target.cellIndex, target.getAttribute('data-type')); sortGrid(e.target.cellIndex, e.target.getAttribute('data-type'));
}; };
function sortGrid(colNum, type) { function sortGrid(colNum, type) {
@ -89,18 +87,8 @@
// Убрать tbody из большого DOM документа для лучшей производительности // Убрать tbody из большого DOM документа для лучшей производительности
grid.removeChild(tbody); grid.removeChild(tbody);
// Убрать TR из TBODY.
// Присваивание tbody.innerHTML = '' не работает в IE
//
// на самом деле без этих строк можно обойтись!
// при добавлении appendChild все узлы будут сами перемещены на правильное место!
while(tbody.firstChild) {
tbody.removeChild(tbody.firstChild);
}
// добавить результат в нужном порядке в TBODY // добавить результат в нужном порядке в TBODY
// они автоматически будут убраны со старых мест и вставлены в правильном порядке
for(var i=0; i<rowsArray.length; i++) { for(var i=0; i<rowsArray.length; i++) {
tbody.appendChild(rowsArray[i]); tbody.appendChild(rowsArray[i]);
} }
@ -109,8 +97,6 @@
} }
// P.S. В IE7 cells, cellIndex не работают, если элемент вне документа
</script> </script>
</body> </body>

View file

@ -8,8 +8,7 @@
var largeImg = document.getElementById('largeImg'); var largeImg = document.getElementById('largeImg');
document.getElementById('thumbs').onclick = function(e) { document.getElementById('thumbs').onclick = function(e) {
e = e || window.event; var target = e.target;
var target = e.target || e.srcElement;
while(target != this) { while(target != this) {

View file

@ -24,7 +24,7 @@
Обработчик на него вешается только через `addEventListener`: Обработчик на него вешается только через `addEventListener`:
```js ```js
document.addEventListener( "DOMContentLoaded", ready, false ); document.addEventListener("DOMContentLoaded", ready);
``` ```
Пример: Пример:
@ -38,7 +38,7 @@ document.addEventListener( "DOMContentLoaded", ready, false );
} }
*!* *!*
document.addEventListener( "DOMContentLoaded", ready, false ); document.addEventListener("DOMContentLoaded", ready);
*/!* */!*
</script> </script>
@ -128,15 +128,14 @@ window.onbeforeunload = function() {
``` ```
[warn header="Firefox игнорирует текст, он показывает своё сообщение"] [warn header="Firefox игнорирует текст, он показывает своё сообщение"]
Firefox игнорирует текст, а всегда показывает своё сообщение. Firefox игнорирует текст, а всегда показывает своё сообщение. Это сделано в целях большей безопасности посетителя, чтобы его нельзя было ввести в заблуждение сообщением.
Это сделано в целях безопасности.
[/warn] [/warn]
[online]
Кликните на кнопку в `IFRAME'е` ниже, чтобы поставить обработчик, а затем по ссылке, чтобы увидеть его в действии: Кликните на кнопку в `IFRAME'е` ниже, чтобы поставить обработчик, а затем по ссылке, чтобы увидеть его в действии:
[iframe src="window-onbeforeunload" border="1" height="80" link] [iframe src="window-onbeforeunload" border="1" height="80" link]
[/online]
## Эмуляция DOMContentLoaded для IE8- ## Эмуляция DOMContentLoaded для IE8-

View file

@ -91,7 +91,7 @@ script.onerror = function() {
```js ```js
//+ run //+ run
var script = document.createElement('script'); var script = document.createElement('script');
script.src = "http://ajax.googleapis.com/ajax/libs/jquery/1/jquery.js"; script.src = "https://code.jquery.com/jquery.js";
document.documentElement.appendChild(script); document.documentElement.appendChild(script);
*!* *!*
@ -134,7 +134,7 @@ script.onreadystatechange = function() {
```js ```js
//+ run //+ run
var script = document.createElement('script'); var script = document.createElement('script');
script.src = "http://ajax.googleapis.com/ajax/libs/jquery/1/jquery.js"; script.src = "https://code.jquery.com/jquery.js";
document.documentElement.appendChild(script); document.documentElement.appendChild(script);
function afterLoad() { function afterLoad() {
@ -172,7 +172,7 @@ script.onreadystatechange = function() {
```js ```js
//+ run //+ run
var script = document.createElement('script'); var script = document.createElement('script');
script.src = "http://ajax.googleapis.com/ajax/libs/jquery/1/jquery.js"; script.src = "https://code.jquery.com/jquery.js";
document.documentElement.appendChild(script); document.documentElement.appendChild(script);
function afterLoad() { function afterLoad() {

View file

@ -13,13 +13,13 @@ function addOnWheel(elem, handler) {
if (elem.addEventListener) { if (elem.addEventListener) {
if ('onwheel' in document) { if ('onwheel' in document) {
// IE9+, FF17+ // IE9+, FF17+
elem.addEventListener ("wheel", handler, false); elem.addEventListener ("wheel", handler);
} else if ('onmousewheel' in document) { } else if ('onmousewheel' in document) {
// устаревший вариант события // устаревший вариант события
elem.addEventListener ("mousewheel", handler, false); elem.addEventListener ("mousewheel", handler);
} else { } else {
// 3.5 <= Firefox < 17, более старое событие DOMMouseScroll пропустим // 3.5 <= Firefox < 17, более старое событие DOMMouseScroll пропустим
elem.addEventListener ("MozMousePixelScroll", handler, false); elem.addEventListener ("MozMousePixelScroll", handler);
} }
} else { // IE<9 } else { // IE<9
text.attachEvent ("onmousewheel", handler); text.attachEvent ("onmousewheel", handler);

View file

@ -39,13 +39,13 @@
if (elem.addEventListener) { if (elem.addEventListener) {
if ('onwheel' in document) { if ('onwheel' in document) {
// IE9+, FF17+, Ch31+ // IE9+, FF17+, Ch31+
elem.addEventListener ("wheel", onWheel, false); elem.addEventListener ("wheel", onWheel);
} else if ('onmousewheel' in document) { } else if ('onmousewheel' in document) {
// устаревший вариант события // устаревший вариант события
elem.addEventListener ("mousewheel", onWheel, false); elem.addEventListener ("mousewheel", onWheel);
} else { } else {
// Firefox < 17 // Firefox < 17
elem.addEventListener ("MozMousePixelScroll", onWheel, false); elem.addEventListener ("MozMousePixelScroll", onWheel);
} }
} else { // IE<9 } else { // IE<9
elem.attachEvent ("onmousewheel", onWheel); elem.attachEvent ("onmousewheel", onWheel);

View file

@ -26,13 +26,13 @@ var elem = document.getElementById('container');
if (elem.addEventListener) { if (elem.addEventListener) {
if ('onwheel' in document) { if ('onwheel' in document) {
// IE9+, FF17+ // IE9+, FF17+
elem.addEventListener ("wheel", onWheel, false); elem.addEventListener ("wheel", onWheel);
} else if ('onmousewheel' in document) { } else if ('onmousewheel' in document) {
// устаревший вариант события // устаревший вариант события
elem.addEventListener ("mousewheel", onWheel, false); elem.addEventListener ("mousewheel", onWheel);
} else { } else {
// 3.5 <= Firefox < 17, более старое событие DOMMouseScroll пропустим // 3.5 <= Firefox < 17, более старое событие DOMMouseScroll пропустим
elem.addEventListener ("MozMousePixelScroll", onWheel, false); elem.addEventListener ("MozMousePixelScroll", onWheel);
} }
} else { // IE<9 } else { // IE<9
elem.attachEvent ("onmousewheel", onWheel); elem.attachEvent ("onmousewheel", onWheel);

View file

@ -1,14 +1,14 @@
# Мышь: исправление события для IE8- # Мышь: IE8-, исправление события
В предыдущих главах мы говорили о различных несовместимостях при работе с событиями для IE8-. Ранее мы говорили о различных несовместимостях при работе с событиями для IE8-. Самая главная -- это, конечно, назначение событий при помощи `attachEvent/detachEvent` вместо `addEventListener/removeEventListener` и отсутствие фазы перехвата. Но и в самом объекте события есть различия.
Самая главная -- это, конечно, назначение событий при помощи `attachEvent/detachEvent` вместо `addEventListener/removeEventListener` и отсутствие фазы перехвата. Что касается событий мыши, различия в свойствах можно легко исправить при помощи функции `fixEvent`, которая описана в этой главе.
Что же касается событий мыши, то различия в свойствах можно легко исправить при помощи функции `fixEvent`, которая описана в этой главе.
[cut] [cut]
[warn header="Только IE8"] [warn header="Только IE8-"]
Эта функция нужна только для IE8. Эта глава и описанная далее функция `fixEvent` нужны только для поддержки IE8-.
Если IE8- для Вас неактуален, то пролистывайте дальше, это читать Вам не надо.
[/warn] [/warn]
@ -63,4 +63,4 @@ function fixEvent(e) {
} }
``` ```
Эта функция не нужна, если используются JavaScript-фреймворки, но может быть полезной, если вы по какой-то причине пишите без них. Эта функция может быть полена, если не используются JavaScript-фреймворки, в которых есть свои средства сглаживания кросс-браузерных различий.

View file

@ -295,9 +295,9 @@ var option = new Option("Текст", "value", true, true);
<dl> <dl>
<dt>`document.forms`</dt> <dt>`document.forms`</dt>
<dd>Форму можно получить как <code>document.forms[name/index].</dd> <dd>Форму можно получить как `document.forms[name/index]`.</dd>
<dt>`form.elements`</dt> <dt>`form.elements`</dt>
<dd>Элементы в форме: <code>form.elements[name/index]</code>. Каждый элемент имеет ссылку на форму в свойстве `form`. Свойство `elements` также есть у `<fieldset>`.</dd> <dd>Элементы в форме: `form.elements[name/index]`. Каждый элемент имеет ссылку на форму в свойстве `form`. Свойство `elements` также есть у `<fieldset>`.</dd>
</dl> </dl>
Значение элементов читается/ставится через `value` или `checked`. Значение элементов читается/ставится через `value` или `checked`.

View file

@ -1,51 +1,3 @@
Состояние элемента определяется наличием класса `placeholder`. Для простоты будем считать, что это -- единственный возможный класс у `INPUT'а` В данном случае достаточно событий `input.focus/input.blur`.
При фокусировке, если в элементе находится плейсхолдер -- он должен исчезать:
```js
input.onfocus = function() {
if (this.className == 'placeholder') {
prepareInput(this);
}
}
function prepareInput(input) { // превратить элемент в простой пустой input
input.className = '';
input.value = '';
}
```
...Затем элемент потеряет фокус. При этом нужно возвратить плейсхолдер, но только в том случае, если элемент пустой:
```js
input.onblur = function() {
if (this.value == '') { // если пустой
resetInput(this); // заполнить плейсхолдером
}
}
function resetInput(input) {
input.className = 'placeholder';
input.value = 'E-mail';
}
```
Это решение можно сделать удобнее в поддержке, если при выполнении `prepareInput` копировать значение в специальное свойство, а в `resetInput` -- восстанавливать его:
```js
function prepareInput(input) {
input.className = '';
*!*
input.oldValue = input.value;
*/!*
input.value = '';
}
function resetInput(input) {
input.className = 'placeholder';
input.value = input.oldValue;
}
```
Теперь, если понадобится изменить значение плейсхолдера -- это достаточно сделать в HTML, и не надо трогать JavaScript-код.
Если бы мы хотели реализовать это на уровне документа, то применили бы делегирование и события `focusin/focusout` (эмуляцию для firefox), так как обычные `focus/blur` не всплывают.

View file

@ -4,43 +4,66 @@
<meta charset="UTF-8"> <meta charset="UTF-8">
<style> <style>
.placeholder { .placeholder {
color: gray; color: blue;
font-family: Georgia;
}
.placeholder-tooltip {
color: blue;
font-family: Georgia;
position: fixed;
} }
</style> </style>
</head> </head>
<body> <body>
<p>Красивый placeholder:</p>
<input type="text" class="placeholder" value="E-mail"> <input type="email" data-placeholder="E-mail">
<script> <script>
var input = document.getElementsByTagName('input')[0]; var input = document.querySelector('[data-placeholder]');
function prepareInput(input) { showPlaceholder(input);
input.className = '';
input.oldValue = input.value; // Показать 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 = ''; input.value = '';
} }
function resetInput(input) { showTooltip(input);
input.className = 'placeholder'; };
input.value = input.oldValue;
}
input.onfocus = function() {
if (this.className == 'placeholder') {
prepareInput(this);
}
}
input.onblur = function() { input.onblur = function() {
if (this.value == '') { document.body.removeChild(input.tooltip);
resetInput(this); delete input.tooltip;
}
// показываем placeholder обратно, если input пуст
if (input.value == '') {
showPlaceholder(input);
} }
};
</script> </script>

View file

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

View file

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

View file

@ -1,110 +1,9 @@
# Алгоритм
Самый естественный алгоритм решения: Нам нужно ловить `onclick` на мышонке и в `onkeydown` на нём смотреть коды символов. При скан-кодах стрелок двигать мышонка через `position:absolute` или `position:fixed`.
<ol>
<li>При клике мышонок получает фокус. Для этого нужно либо заменить `DIV` на другой тег, либо добавить ему `tabindex="-1"`.</li>
<li>Когда на элементе фокус, то клавиатурные события будут срабатывать прямо на нём. То есть ловим `mousie.onkeydown`.
Мы выбираем `keydown`, потому что он позволяет во-первых отлавливать нажатия на спец. клавиши (стрелки), а во-вторых, отменить действие браузера, которым по умолчанию является прокрутка страницы. Скан-коды для клавиш стрелок можно узнать, нажимая на них на [тестовом стенде](#keyboard-test-stand). Вот они: 37-38-39-40 (влево-вверх-вправо-вниз).
</li>
<li>При нажатии на стрелки двигаем мышонка через `position:absolute` и `top/left`.</li>
</ol>
Дальше решение -- попробуйте сделать сами. Возможны подводные камни :) Проблема может возникнуть одна -- `keydown` не возникает на элементе, если на нём нет фокуса.
# Решение Чтобы фокус был -- нужно добавить мышонку атрибут `tabindex` через JS или в HTML.
<ol>
<li>
При получении фокуса -- готовим мышонка к перемещению:
```js
mousie.onfocus = function() {
this.style.position = 'relative';
this.style.left = '0px';
this.style.top = '0px';
}
```
</li>
<li>Коды для клавиш стрелок можно узнать, нажимая на них на [тестовом стенде](#keyboard-test-stand). Вот они: 37-38-39-40 (влево-вверх-вправо-вниз).
При нажатии стрелки -- двигаем мышонка:
```js
mousie.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;
}
}
```
Обратите внимание, что действием по умолчанию для стрелок является прокрутка страницы. Поэтому, чтобы её отменить, нужно использовать `return false`.
Когда пользователь убирает фокус с мышки, то она перестает реагировать на клавиши. Нет нужды удалять обработчики на `blur`, потому что браузер перестанет вызывать `keydown`.
</li>
</ol>
**В решении выше есть проблема. Мышонок находится в `DIV` с `position:relative`.** Это означает, что его `left/top` являются координатами не относительно документа, а относительно позиционированного предка.
Что делать? Решений три.
<ol><li>Первое -- учесть этого позиционированного предка при вычислении `left/top`, вычитать его координаты из координат относительно документа.</li>
<li>Второе -- сделать `position:fixed`. При этом координаты мышонка можно взять напрямую из [mousie.getBoundingClientRect()](https://developer.mozilla.org/en/DOM/element.getBoundingClientRect), т.е. все вычисления выполнять относительно окна. Это больше компьютерно-игровой подход, чем работа с документом.</li>
<li>Третье -- переместить мышонка под `document.body` в начале движения. Тогда и с координатами всё будет в порядке. Но при этом могут "слететь" стили.</li>
</ol>
Хочется верить, что первое и второе решения понятны. А вот третье более интересно, так как скрывает новые тонкости.
Если пойти этим путём, то в обработчик `onfocus` следует добавить перемещение мышонка под `BODY`:
```js
mousie.onfocus = function() {
var coords = getCoords(this);
*!*
document.body.appendChild(this);
*/!*
this.style.position = 'absolute';
this.style.left = coords.left + 'px';
this.style.top = coords.top + 'px';
};
```
...Но вот беда! **При `document.body.appendChild(this)` с элемента слетает фокус!**
Фокус нужно восстановить, чтобы ловить `keydown`. Однако некоторые браузеры, например FF и IE, не дают вызвать метод `focus()` элемента из его обработчика `onfocus`. То есть сделать это нельзя.
Чтобы это обойти, можно поставить обработчик не `onfocus`, а `onclick`:
```js
mousie.onclick = function() {
var coords = getCoords(this);
this.style.position = 'absolute';
this.style.left = coords.left + 'px';
this.style.top = coords.top + 'px';
*!*
if (this.parentNode != document.body) {
document.body.appendChild(this);
this.focus();
}
*/!*
};
```
Обычно событие `focus` всё равно происходит *после* `click`, но здесь элемент перемещается, поэтому оно "съедается" и мы инициируем его сами вызовом `focus()`.
[edit src="solution"]Окончательное решение[/edit]

View file

@ -3,42 +3,45 @@
<head> <head>
<meta charset="utf-8"> <meta charset="utf-8">
<style> <style>
#mousie:focus { #mouse {
outline: none; display: inline-block;
border: 1px dashed black; cursor: pointer;
}
html, body {
margin: 0; margin: 0;
height: 100%; }
#mouse:focus {
outline: 1px dashed black;
} }
</style> </style>
</head> </head>
<body> <body>
Кликните на мышонка и передвигайте его, нажимая клавиши со стрелками. <p>Кликните на мышонка и передвигайте его, нажимая клавиши со стрелками.</p>
<pre id="mouse" tabindex="0">
_ _
(q\_/p)
/. .\
=\_t_/= __
/ \ (
(( )) )
/\) (/\ /
\ Y /-'
nn^nn
</pre>
<div style="position:relative;top:30px;width:50px;height:50px">
<div style="width:41px; height:48px; background:url(https://js.cx/clipart/mousie.gif)" id="mousie" tabindex="-1"></div>
</div>
<script> <script>
document.getElementById('mousie').onclick = function() { document.getElementById('mouse').onclick = function() {
var coords = getCoords(this); this.style.left = this.getBoundingClientRect().left + 'px';
this.style.position = 'absolute'; this.style.top = this.getBoundingClientRect().top + 'px';
this.style.left = coords.left + 'px';
this.style.top = coords.top + 'px';
if (this.parentNode != document.body) { this.style.position = 'fixed';
document.body.appendChild(this);
this.focus();
}
}; };
document.getElementById('mousie').onkeydown = function(e) { document.getElementById('mouse').onkeydown = function(e) {
e = e || event;
switch(e.keyCode) { switch(e.keyCode) {
case 37: // влево case 37: // влево
this.style.left = parseInt(this.style.left) - this.offsetWidth + 'px'; this.style.left = parseInt(this.style.left) - this.offsetWidth + 'px';
@ -55,27 +58,6 @@ document.getElementById('mousie').onkeydown = function(e) {
} }
}; };
// -----------------------
function getCoords(elem) {
var box = elem.getBoundingClientRect();
var body = document.body;
var docElem = document.documentElement;
var scrollTop = window.pageYOffset || docElem.scrollTop || body.scrollTop;
var scrollLeft = window.pageXOffset || docElem.scrollLeft || body.scrollLeft;
var clientTop = docElem.clientTop || body.clientTop || 0;
var clientLeft = docElem.clientLeft || body.clientLeft || 0;
var top = box.top + scrollTop - clientTop;
var left = box.left + scrollLeft - clientLeft;
return { top: Math.round(top), left: Math.round(left) };
}
</script> </script>
</body> </body>

View file

@ -3,52 +3,37 @@
<head> <head>
<meta charset="utf-8"> <meta charset="utf-8">
<style> <style>
#mousie:focus { #mouse {
outline: none; display: inline-block;
border: 1px dashed black; cursor: pointer;
}
html, body {
margin: 0; margin: 0;
height: 100%; }
#mouse:focus {
outline: 1px dashed black;
} }
</style> </style>
</head> </head>
<body> <body>
Кликните на мышонка и передвигайте его, нажимая клавиши со стрелками. <p>Кликните на мышонка и передвигайте его, нажимая клавиши со стрелками.</p>
<div style="width:41px;height:48px;background:url(https://js.cx/clipart/mousie.gif)"></div>
<pre id="mouse">
_ _
(q\_/p)
/. .\
=\_t_/= __
/ \ (
(( )) )
/\) (/\ /
\ Y /-'
nn^nn
</pre>
<script> <script>
// ваш код
/* ваш код */
// -----------------------
function getCoords(elem) {
var box = elem.getBoundingClientRect();
var body = document.body;
var docElem = document.documentElement;
var scrollTop = window.pageYOffset || docElem.scrollTop || body.scrollTop;
var scrollLeft = window.pageXOffset || docElem.scrollLeft || body.scrollLeft;
var clientTop = docElem.clientTop || body.clientTop || 0;
var clientLeft = docElem.clientLeft || body.clientLeft || 0;
var top = box.top + scrollTop - clientTop;
var left = box.left + scrollLeft - clientLeft;
return { top: Math.round(top), left: Math.round(left) };
}
</script> </script>
</body> </body>
</html> </html>

View file

@ -4,73 +4,8 @@
Кликните по мышонку. Затем нажимайте клавиши со стрелками, и он будет двигаться. Кликните по мышонку. Затем нажимайте клавиши со стрелками, и он будет двигаться.
<style> [demo src="solution"]
##mousie:focus {
outline: none;
border: 1px dashed black;
}
</style>
<div style="position:relative;top:20px;width:100px;height:100px"> В этой задаче запрещается ставить обработчики куда-либо, кроме элемента `#mouse`.
<div style="width:41px; height:48px;background:url(https://js.cx/clipart/mousie.gif)" id="mousie" tabindex="0"></div>
</div>
<script>
mousie.onclick = function() {
var coords = getCoords(this);
this.style.position = 'absolute';
this.style.left = coords.left + 'px';
this.style.top = coords.top + 'px';
if (this.parentNode != document.body) {
document.body.appendChild(this);
this.focus();
}
};
mousie.onkeydown = function(e) {
e = e || event;
switch(e.keyCode) {
case 40: // вниз
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 38: // вверх
this.style.top = parseInt(this.style.top) - this.offsetHeight + 'px';
return false;
case 37: // влево
this.style.left = parseInt(this.style.left) - this.offsetWidth + 'px';
return false;
}
};
// -----------------------
function getCoords(elem) {
var box = elem.getBoundingClientRect();
var body = document.body;
var docElem = document.documentElement;
var scrollTop = window.pageYOffset || docElem.scrollTop || body.scrollTop;
var scrollLeft = window.pageXOffset || docElem.scrollLeft || body.scrollLeft;
var clientTop = docElem.clientTop || body.clientTop || 0;
var clientLeft = docElem.clientLeft || body.clientLeft || 0;
var top = box.top + scrollTop - clientTop;
var left = box.left + scrollLeft - clientLeft;
return { top: Math.round(top), left: Math.round(left) };
}
</script>
Учтите при решении, что мышонок изначально находится где-то в глубине документа, в `DIV'е` с `position:relative`.
Можно изменять атрибуты и классы в HTML.

View file

@ -1,14 +1,15 @@
# CSS для решения # CSS для решения
Как видно из исходного кода, `#view` -- это `DIV`, который будет содержать результат, а `#area` - это редактируемое текстовое поле. Как видно из исходного кода, `#view` -- это `<div>`, который будет содержать результат, а `#area` - это редактируемое текстовое поле.
Так как мы преобразуем `DIV` в `TEXTAREA` и обратно, нам нужно сделать их практически одинаковыми с виду: Так как мы преобразуем `<div>` в `<textarea>` и обратно, нам нужно сделать их практически одинаковыми с виду:
```css ```css
#view, #area { #view, #area {
height:150px; height: 150px;
width:400px; width: 400px;
font-family:arial; font-family: arial;
font-size: 14px;
} }
``` ```
@ -66,13 +67,13 @@ document.onkeydown = function(e) {
}; };
``` ```
В примере выше, `offsetHeight` используется для того, чтобы проверить, отображается элемент или нет. Это очень надежный способ для всех элементов, кроме `TR` в некоторых старых браузерах. В примере выше, `offsetHeight` используется для того, чтобы проверить, отображается элемент или нет. Это очень надежный способ для всех элементов, кроме `<tr>` в некоторых старых браузерах.
В отличие от простой проверки `display=='none'`, этот способ работает с элементом, спрятанным с помощью стилей, а так же для элементов, у которых скрыты родители. В отличие от простой проверки `display=='none'`, этот способ работает с элементом, спрятанным с помощью стилей, а так же для элементов, у которых скрыты родители.
# Редактирование # Редактирование
Следующие функции переключают режимы. HTML-код разрешен, поэтому возможна прямая трансформация в `TEXTAREA` и обратно. Следующие функции переключают режимы. HTML-код разрешен, поэтому возможна прямая трансформация в `<textarea>` и обратно.
```js ```js
function edit() { function edit() {
@ -94,5 +95,4 @@ function cancel() {
} }
``` ```
Чтобы проверить полное решение, сфокусируйтесь на правом iframe, пожалуйста.

View file

@ -18,11 +18,7 @@ HTML разрешён.
<script> <script>
area = document.getElementById('area');
view = document.getElementById('view');
document.onkeydown = function(e) { document.onkeydown = function(e) {
e = e || event;
if (e.keyCode == 27) { // escape if (e.keyCode == 27) { // escape
cancel(); cancel();
return false; return false;

View file

@ -1,7 +1,8 @@
#view, #area { #view, #area {
height:150px; height:150px;
width:400px; width:400px;
font-family:arial; font-family: arial;
font-size: 14px;
} }
#view { #view {

View file

@ -1,7 +1,8 @@
#view, #area { #view, #area {
height:150px; height:150px;
width:400px; width:400px;
font-family:arial; font-family: arial;
font-size: 14px;
} }
#view { #view {

View file

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

View file

@ -1,12 +0,0 @@
.edit-area {
border: none;
width: 100%;
height: 100%;
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 */
}

View file

@ -1,35 +0,0 @@
var table = document.getElementById('bagua-table');
table.onclick = function(event) {
var target = event.target;
while(target != table) {
if (target.nodeName == 'TD') {
if (target.firstChild.tagName == 'TEXTAREA') { // already editing
return;
}
makeTdEditable(target);
return;
}
target = target.parentNode;
}
}
function makeTdEditable(td) {
var textArea = document.createElement('textarea');
textArea.className = 'edit-area';
textArea.value = td.innerHTML;
textArea.onkeydown = function(e) {
if (e.keyCode == 13 && e.shiftKey) {
finishTdEditing(td);
}
}
td.innerHTML = '';
td.appendChild(textArea);
textArea.focus();
}
function finishTdEditing(td) {
td.innerHTML = td.firstChild.value;
}

View file

@ -1,52 +0,0 @@
#bagua-table th {
text-align:center;
font-weight:bold;
}
#bagua-table td {
width: 150px;
white-space: nowrap;
text-align:center;
vertical-align: bottom;
padding: 0;
}
#bagua-table .nw {
background-color: #999;
}
#bagua-table .n {
background-color: #03f;
color: #fff;
}
#bagua-table .ne {
background-color: #ff6;
}
#bagua-table .w {
background-color: #ff0;
}
#bagua-table .c {
background-color: #60c;
color: #fff;
}
#bagua-table .e {
background-color: #09f;
color: #fff;
}
#bagua-table .sw {
background-color: #963;
color: #fff;
}
#bagua-table .s {
background-color: #f60;
color: #fff;
}
#bagua-table .se {
background-color: #0c3;
color: #fff;
}

View file

@ -1,40 +0,0 @@
<!DOCTYPE HTML>
<html>
<body>
<link type="text/css" rel="stylesheet" href="bagua.css">
<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>
</body>
</html>

View file

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

View file

@ -2,6 +2,6 @@
<li>При клике -- заменяем `innerHTML` ячейки на `<textarea>` с размерами "под ячейку", без рамки.</li> <li>При клике -- заменяем `innerHTML` ячейки на `<textarea>` с размерами "под ячейку", без рамки.</li>
<li>В `textarea.value` присваиваем содержимое ячейки.</li> <li>В `textarea.value` присваиваем содержимое ячейки.</li>
<li>Фокусируем посетителя на ячейке вызовом `focus()`.</li> <li>Фокусируем посетителя на ячейке вызовом `focus()`.</li>
<li>По `keydown` отслеживаем нажатие с `keyCode = 13` ([key Enter]) с `shiftKey` и трансформируем ячейку обратно.</li> <li>Показываем кнопки OK/CANCEL под ячейкой.</li>
</ol> </ol>

View file

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

View file

@ -1,10 +1,12 @@
<!DOCTYPE HTML> <!DOCTYPE HTML>
<html> <html>
<head><meta charset="utf-8"></head>
<body> <body>
<link type="text/css" rel="stylesheet" href="bagua.css"> <link rel="stylesheet" href="bagua.css">
<link type="text/css" rel="stylesheet" href="my.css"> <link rel="stylesheet" href="my.css">
Кликните на ячейке для начала редактирования. Когда закончите -- нажмите, находясь в ней, Shift+Enter.
<p>Кликните на ячейке для начала редактирования. Когда закончите -- нажмите OK или CANCEL.</p>
<table id="bagua-table"> <table id="bagua-table">
<tr> <tr>
@ -37,6 +39,7 @@
</table> </table>
<script src="script.js"></script> <script src="script.js"></script>
</body> </body>

View file

@ -13,4 +13,5 @@
} }
.edit-td { .edit-td {
position: relative; position: relative;
padding: 0;
} }

View file

@ -30,9 +30,12 @@ table.onclick = function(event) {
} }
function makeTdEditable(td) { function makeTdEditable(td) {
editingTd = { elem: td, data: td.innerHTML }; editingTd = {
elem: td,
data: td.innerHTML
};
td.className += ' edit-td'; // td, not textarea! the rest of rules will cascade td.classList.add('edit-td'); // td, not textarea! the rest of rules will cascade
var textArea = document.createElement('textarea'); var textArea = document.createElement('textarea');
textArea.style.width = td.clientWidth + 'px'; textArea.style.width = td.clientWidth + 'px';
@ -44,10 +47,9 @@ function makeTdEditable(td) {
td.appendChild(textArea); td.appendChild(textArea);
textArea.focus(); textArea.focus();
var controls = document.createElement('div'); td.insertAdjacentHTML("beforeEnd",
controls.innerHTML = '<button class="edit-ok">OK</button><button class="edit-cancel">CANCEL</button>'; '<div class="edit-controls"><button class="edit-ok">OK</button><button class="edit-cancel">CANCEL</button></div>'
controls.className = 'edit-controls'; );
td.appendChild(controls);
} }
function finishTdEdit(td, isOk) { function finishTdEdit(td, isOk) {
@ -56,7 +58,7 @@ function finishTdEdit(td, isOk) {
} else { } else {
td.innerHTML = editingTd.data; td.innerHTML = editingTd.data;
} }
td.className = td.className.replace(' edit-td', ''); // remove edit class td.classList.remove('edit-td'); // remove edit class
editingTd = null; editingTd = null;
} }

View file

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

View file

@ -2,11 +2,11 @@
<html> <html>
<head><meta charset="utf-8"></head> <head><meta charset="utf-8"></head>
<body> <body>
<link type="text/css" rel="stylesheet" href="bagua.css"> <link rel="stylesheet" href="bagua.css">
<link type="text/css" rel="stylesheet" href="my.css"> <link rel="stylesheet" href="my.css">
Кликните на ячейке для начала редактирования. Когда закончите -- нажмите, находясь в ней, Shift+Enter или кликните на OK/CANCEL. <p>Кликните на ячейке для начала редактирования. Когда закончите -- нажмите OK или CANCEL.</p>
<table id="bagua-table"> <table id="bagua-table">
<tr> <tr>

View file

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

View file

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

View file

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

View file

@ -1 +0,0 @@
[edit src="solution"]Открыть решение в песочнице[/edit]

View file

@ -1,6 +1,6 @@
# Фокусировка: focus/blur # Фокусировка: focus/blur
Говорят, что элемент "получает фокус", когда посетитель фокусируется на нём. Обычно фокусировка автоматически происходит при нажатии на элементе мышкой, но также можно перейти на нужный элемент клавиатурой -- через клавишу [key Tab], нажатие пальцем (на мобильных устройствах) и так далее. Говорят, что элемент "получает фокус", когда посетитель фокусируется на нём. Обычно фокусировка автоматически происходит при нажатии на элементе мышкой, но также можно перейти на нужный элемент клавиатурой -- через клавишу [key Tab], нажатие пальцем на планшете и так далее.
Момент получения фокуса и потери очень важен. Момент получения фокуса и потери очень важен.
@ -21,11 +21,11 @@
<li>Обработчик `onfocus`, если текущее состояние поля ввода -- "ошибка" -- скрывает её (потом при `onblur` будет повторная проверка).</li> <li>Обработчик `onfocus`, если текущее состояние поля ввода -- "ошибка" -- скрывает её (потом при `onblur` будет повторная проверка).</li>
</ul> </ul>
Наберите что-нибудь в поле "возраст" примера ниже и завершите ввод, нажав [key Tab] или кликнув в другое место страницы. Введённое значение будет автоматически проверено: В примере ниже, если набрать что-нибудь в поле "возраст" и завершить ввод, нажав [key Tab] или кликнув в другое место страницы, то введённое значение будет автоматически проверено:
```html ```html
<!--+ run autorun height=60 --> <!--+ run autorun height=60 -->
<style> .error { background: red; } </style> <style> .error { border-color: red; } </style>
Введите ваш возраст: <input type="text" id="input"> Введите ваш возраст: <input type="text" id="input">
@ -36,7 +36,7 @@
if (isNaN(this.value)) { // введено не число if (isNaN(this.value)) { // введено не число
// показать ошибку // показать ошибку
this.className = "error"; this.className = "error";
error.innerHTML = 'Вы ввели не число. Исправьте, пожалуйста' error.innerHTML = 'Вы ввели не число. Исправьте, пожалуйста.'
} }
}; };
@ -186,7 +186,7 @@ age.onblur = function() {
<style> <style>
li { cursor: pointer; } li { cursor: pointer; }
:focus { border: 1px dashed green; outline: 0; } :focus { outline: 1px dashed green; }
</style> </style>
``` ```
@ -207,7 +207,7 @@ age.onblur = function() {
<input type="text" name="surname" value="Ваша фамилия"> <input type="text" name="surname" value="Ваша фамилия">
</form> </form>
<style> .focused { border: 2px solid red; } </style> <style> .focused { outline: 1px solid red; } </style>
``` ```
В примере выше стоит обработчик `onfocus` на форме, но он не работает, т.к. при фокусировке на любом `INPUT` событие `focus` срабатывает только на этом элементе и не всплывает наверх. В примере выше стоит обработчик `onfocus` на форме, но он не работает, т.к. при фокусировке на любом `INPUT` событие `focus` срабатывает только на этом элементе и не всплывает наверх.
@ -225,7 +225,7 @@ age.onblur = function() {
<input type="text" name="surname" value="Ваша фамилия"> <input type="text" name="surname" value="Ваша фамилия">
</form> </form>
<style> .focused { border: 2px solid red; } </style> <style> .focused { outline: 1px solid red; } </style>
<script> <script>
*!* *!*
@ -262,7 +262,7 @@ age.onblur = function() {
<input type="text" name="surname" value="Ваша фамилия"> <input type="text" name="surname" value="Ваша фамилия">
</form> </form>
<style> <style>
.focused { border: 2px solid red; } .focused { outline: 1px solid red; }
</style> </style>
<script> <script>

View file

@ -80,13 +80,13 @@ function growIn(img) {
requestAnimationFrame(function() { requestAnimationFrame(function() {
img.classList.add('growing'); img.classList.add('growing');
img.addEventListener('transitionend', done, false); img.addEventListener('transitionend', done);
}); });
}); });
function done(e) { function done(e) {
// сработать только первый раз // сработать только первый раз
img.removeEventListener('transitionend', done, false); img.removeEventListener('transitionend', done);
placeholder.parentNode.replaceChild(img, placeholder); placeholder.parentNode.replaceChild(img, placeholder);

View file

@ -236,11 +236,11 @@ document.body.style.Transform = "rotate(360deg)";
... ...
go(); go();
elem.addEventListener('transitionend', go, false); /* на будущее */ elem.addEventListener('transitionend', go); /* на будущее */
elem.addEventListener('webkitTransitionEnd', go, false); elem.addEventListener('webkitTransitionEnd', go);
elem.addEventListener('mozTransitionEnd', go, false); elem.addEventListener('mozTransitionEnd', go);
elem.addEventListener('oTransitionEnd', go, false); elem.addEventListener('oTransitionEnd', go);
elem.addEventListener('msTransitionEnd', go, false); elem.addEventListener('msTransitionEnd', go);
... ...
``` ```

View file

@ -47,11 +47,11 @@ function bounceBoat(elem) {
go(); go();
elem.addEventListener('transitionend', go, false); /* на будущее */ elem.addEventListener('transitionend', go); /* на будущее */
elem.addEventListener('webkitTransitionEnd', go, false); elem.addEventListener('webkitTransitionEnd', go);
elem.addEventListener('mozTransitionEnd', go, false); elem.addEventListener('mozTransitionEnd', go);
elem.addEventListener('oTransitionEnd', go, false); elem.addEventListener('oTransitionEnd', go);
elem.addEventListener('msTransitionEnd', go, false); elem.addEventListener('msTransitionEnd', go);
} }
</script> </script>

View file

@ -12,7 +12,7 @@ if (!window.setImmediate) window.setImmediate = (function() {
} }
if(window.addEventListener) { // IE9+, другие браузеры if(window.addEventListener) { // IE9+, другие браузеры
window.addEventListener('message', onmessage, false); window.addEventListener('message', onmessage);
} else { // IE8 } else { // IE8
window.attachEvent( 'onmessage', onmessage ); window.attachEvent( 'onmessage', onmessage );
} }

View file

@ -12,7 +12,7 @@ if (!window.setImmediate) window.setImmediate = (function() {
} }
if(window.addEventListener) { // IE9+, другие браузеры if(window.addEventListener) { // IE9+, другие браузеры
window.addEventListener('message', onmessage, false); window.addEventListener('message', onmessage);
} else { // IE8 } else { // IE8
window.attachEvent( 'onmessage', onmessage ); window.attachEvent( 'onmessage', onmessage );
} }

View file

@ -62,7 +62,7 @@ function listener(event) {
} }
if (window.addEventListener){ if (window.addEventListener){
window.addEventListener("message", listener, false); window.addEventListener("message", listener);
} else { } else {
window.attachEvent("onmessage", listener); window.attachEvent("onmessage", listener);
} }