renovations
This commit is contained in:
parent
0eabad2516
commit
9bf1b61cab
72 changed files with 299 additions and 670 deletions
|
@ -13,10 +13,10 @@
|
|||
Можно указать и полный URL, например:
|
||||
|
||||
```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"` обозначает файл из текущей директории.
|
||||
|
||||
Чтобы подключить несколько скриптов, используйте несколько тегов:
|
||||
|
||||
|
|
|
@ -2,7 +2,6 @@
|
|||
<html>
|
||||
<head>
|
||||
<meta charset="utf-8">
|
||||
<script src="http://code.jquery.com/jquery.min.js"></script>
|
||||
<style type="text/css">
|
||||
* {
|
||||
margin: 0;
|
||||
|
@ -44,7 +43,6 @@
|
|||
<script>
|
||||
var example = document.getElementById('example')
|
||||
|
||||
$(function() {
|
||||
var info = document.getElementById('info')
|
||||
|
||||
var props = {
|
||||
|
@ -71,19 +69,20 @@
|
|||
}
|
||||
}
|
||||
|
||||
$(document).delegate('span.key','click', function() {
|
||||
var prop = this.innerHTML;
|
||||
document.onclick = function(event) {
|
||||
var target = event.target;
|
||||
if (!target.classList.contains('key')) return;
|
||||
|
||||
var prop = target.innerHTML;
|
||||
var value = example[prop];
|
||||
value = value.tagName || value;
|
||||
$('#'+prop).html(value);
|
||||
})
|
||||
document.getElementById(prop).innerHTML = value;
|
||||
};
|
||||
|
||||
})
|
||||
|
||||
document.onmousemove = function(e) {
|
||||
e = e || window.event;
|
||||
document.getElementById('mouse').innerHTML = Math.round(e.clientX)+':'+Math.round(e.clientY);
|
||||
}
|
||||
};
|
||||
|
||||
|
||||
</script>
|
||||
|
|
|
@ -142,7 +142,6 @@ document.getElementById('getBoundingClientRectEx').onclick = function(event) {
|
|||
var o = getOffsetSum(this);
|
||||
var orect = getCoords(this);
|
||||
|
||||
event = event || window.event;
|
||||
if ( event.pageX == null && event.clientX != null ) {
|
||||
var html = document.documentElement, body = document.body;
|
||||
event.pageX = event.clientX + (html && html.scrollLeft || body && body.scrollLeft || 0) - (html.clientLeft || 0)
|
||||
|
|
|
@ -53,12 +53,10 @@
|
|||
var grid = document.getElementById('grid');
|
||||
|
||||
grid.onclick = function(e) {
|
||||
var target = e && e.target || window.event.srcElement;
|
||||
|
||||
if (target.tagName != 'TH') return;
|
||||
if (e.target.tagName != 'TH') return;
|
||||
|
||||
// Если TH -- сортируем
|
||||
sortGrid(target.cellIndex, target.getAttribute('data-type'));
|
||||
sortGrid(e.target.cellIndex, e.target.getAttribute('data-type'));
|
||||
};
|
||||
|
||||
function sortGrid(colNum, type) {
|
||||
|
@ -89,18 +87,8 @@
|
|||
// Убрать tbody из большого DOM документа для лучшей производительности
|
||||
grid.removeChild(tbody);
|
||||
|
||||
|
||||
// Убрать TR из TBODY.
|
||||
// Присваивание tbody.innerHTML = '' не работает в IE
|
||||
//
|
||||
// на самом деле без этих строк можно обойтись!
|
||||
// при добавлении appendChild все узлы будут сами перемещены на правильное место!
|
||||
while(tbody.firstChild) {
|
||||
tbody.removeChild(tbody.firstChild);
|
||||
}
|
||||
|
||||
|
||||
// добавить результат в нужном порядке в TBODY
|
||||
// они автоматически будут убраны со старых мест и вставлены в правильном порядке
|
||||
for(var i=0; i<rowsArray.length; i++) {
|
||||
tbody.appendChild(rowsArray[i]);
|
||||
}
|
||||
|
@ -109,8 +97,6 @@
|
|||
|
||||
}
|
||||
|
||||
// P.S. В IE7 cells, cellIndex не работают, если элемент вне документа
|
||||
|
||||
</script>
|
||||
|
||||
</body>
|
||||
|
|
|
@ -8,8 +8,7 @@
|
|||
var largeImg = document.getElementById('largeImg');
|
||||
|
||||
document.getElementById('thumbs').onclick = function(e) {
|
||||
e = e || window.event;
|
||||
var target = e.target || e.srcElement;
|
||||
var target = e.target;
|
||||
|
||||
while(target != this) {
|
||||
|
||||
|
|
|
@ -24,7 +24,7 @@
|
|||
Обработчик на него вешается только через `addEventListener`:
|
||||
|
||||
```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>
|
||||
|
||||
|
@ -128,15 +128,14 @@ window.onbeforeunload = function() {
|
|||
```
|
||||
|
||||
[warn header="Firefox игнорирует текст, он показывает своё сообщение"]
|
||||
Firefox игнорирует текст, а всегда показывает своё сообщение.
|
||||
|
||||
Это сделано в целях безопасности.
|
||||
Firefox игнорирует текст, а всегда показывает своё сообщение. Это сделано в целях большей безопасности посетителя, чтобы его нельзя было ввести в заблуждение сообщением.
|
||||
[/warn]
|
||||
|
||||
[online]
|
||||
Кликните на кнопку в `IFRAME'е` ниже, чтобы поставить обработчик, а затем по ссылке, чтобы увидеть его в действии:
|
||||
|
||||
[iframe src="window-onbeforeunload" border="1" height="80" link]
|
||||
|
||||
[/online]
|
||||
|
||||
## Эмуляция DOMContentLoaded для IE8-
|
||||
|
||||
|
|
|
@ -91,7 +91,7 @@ script.onerror = function() {
|
|||
```js
|
||||
//+ run
|
||||
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);
|
||||
|
||||
*!*
|
||||
|
@ -134,7 +134,7 @@ script.onreadystatechange = function() {
|
|||
```js
|
||||
//+ run
|
||||
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);
|
||||
|
||||
function afterLoad() {
|
||||
|
@ -172,7 +172,7 @@ script.onreadystatechange = function() {
|
|||
```js
|
||||
//+ run
|
||||
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);
|
||||
|
||||
function afterLoad() {
|
||||
|
|
|
@ -13,13 +13,13 @@ function addOnWheel(elem, handler) {
|
|||
if (elem.addEventListener) {
|
||||
if ('onwheel' in document) {
|
||||
// IE9+, FF17+
|
||||
elem.addEventListener ("wheel", handler, false);
|
||||
elem.addEventListener ("wheel", handler);
|
||||
} else if ('onmousewheel' in document) {
|
||||
// устаревший вариант события
|
||||
elem.addEventListener ("mousewheel", handler, false);
|
||||
elem.addEventListener ("mousewheel", handler);
|
||||
} else {
|
||||
// 3.5 <= Firefox < 17, более старое событие DOMMouseScroll пропустим
|
||||
elem.addEventListener ("MozMousePixelScroll", handler, false);
|
||||
elem.addEventListener ("MozMousePixelScroll", handler);
|
||||
}
|
||||
} else { // IE<9
|
||||
text.attachEvent ("onmousewheel", handler);
|
||||
|
|
|
@ -39,13 +39,13 @@
|
|||
if (elem.addEventListener) {
|
||||
if ('onwheel' in document) {
|
||||
// IE9+, FF17+, Ch31+
|
||||
elem.addEventListener ("wheel", onWheel, false);
|
||||
elem.addEventListener ("wheel", onWheel);
|
||||
} else if ('onmousewheel' in document) {
|
||||
// устаревший вариант события
|
||||
elem.addEventListener ("mousewheel", onWheel, false);
|
||||
elem.addEventListener ("mousewheel", onWheel);
|
||||
} else {
|
||||
// Firefox < 17
|
||||
elem.addEventListener ("MozMousePixelScroll", onWheel, false);
|
||||
elem.addEventListener ("MozMousePixelScroll", onWheel);
|
||||
}
|
||||
} else { // IE<9
|
||||
elem.attachEvent ("onmousewheel", onWheel);
|
||||
|
|
|
@ -26,13 +26,13 @@ var elem = document.getElementById('container');
|
|||
if (elem.addEventListener) {
|
||||
if ('onwheel' in document) {
|
||||
// IE9+, FF17+
|
||||
elem.addEventListener ("wheel", onWheel, false);
|
||||
elem.addEventListener ("wheel", onWheel);
|
||||
} else if ('onmousewheel' in document) {
|
||||
// устаревший вариант события
|
||||
elem.addEventListener ("mousewheel", onWheel, false);
|
||||
elem.addEventListener ("mousewheel", onWheel);
|
||||
} else {
|
||||
// 3.5 <= Firefox < 17, более старое событие DOMMouseScroll пропустим
|
||||
elem.addEventListener ("MozMousePixelScroll", onWheel, false);
|
||||
elem.addEventListener ("MozMousePixelScroll", onWheel);
|
||||
}
|
||||
} else { // IE<9
|
||||
elem.attachEvent ("onmousewheel", onWheel);
|
||||
|
|
|
@ -1,14 +1,14 @@
|
|||
# Мышь: исправление события для IE8-
|
||||
# Мышь: IE8-, исправление события
|
||||
|
||||
В предыдущих главах мы говорили о различных несовместимостях при работе с событиями для IE8-.
|
||||
Ранее мы говорили о различных несовместимостях при работе с событиями для IE8-. Самая главная -- это, конечно, назначение событий при помощи `attachEvent/detachEvent` вместо `addEventListener/removeEventListener` и отсутствие фазы перехвата. Но и в самом объекте события есть различия.
|
||||
|
||||
Самая главная -- это, конечно, назначение событий при помощи `attachEvent/detachEvent` вместо `addEventListener/removeEventListener` и отсутствие фазы перехвата.
|
||||
|
||||
Что же касается событий мыши, то различия в свойствах можно легко исправить при помощи функции `fixEvent`, которая описана в этой главе.
|
||||
Что касается событий мыши, различия в свойствах можно легко исправить при помощи функции `fixEvent`, которая описана в этой главе.
|
||||
[cut]
|
||||
|
||||
[warn header="Только IE8"]
|
||||
Эта функция нужна только для IE8.
|
||||
[warn header="Только IE8-"]
|
||||
Эта глава и описанная далее функция `fixEvent` нужны только для поддержки IE8-.
|
||||
|
||||
Если IE8- для Вас неактуален, то пролистывайте дальше, это читать Вам не надо.
|
||||
[/warn]
|
||||
|
||||
|
||||
|
@ -63,4 +63,4 @@ function fixEvent(e) {
|
|||
}
|
||||
```
|
||||
|
||||
Эта функция не нужна, если используются JavaScript-фреймворки, но может быть полезной, если вы по какой-то причине пишите без них.
|
||||
Эта функция может быть полена, если не используются JavaScript-фреймворки, в которых есть свои средства сглаживания кросс-браузерных различий.
|
|
@ -295,9 +295,9 @@ var option = new Option("Текст", "value", true, true);
|
|||
|
||||
<dl>
|
||||
<dt>`document.forms`</dt>
|
||||
<dd>Форму можно получить как <code>document.forms[name/index].</dd>
|
||||
<dd>Форму можно получить как `document.forms[name/index]`.</dd>
|
||||
<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>
|
||||
|
||||
Значение элементов читается/ставится через `value` или `checked`.
|
||||
|
|
|
@ -1,51 +1,3 @@
|
|||
Состояние элемента определяется наличием класса `placeholder`. Для простоты будем считать, что это -- единственный возможный класс у `INPUT'а`
|
||||
|
||||
При фокусировке, если в элементе находится плейсхолдер -- он должен исчезать:
|
||||
|
||||
```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-код.
|
||||
В данном случае достаточно событий `input.focus/input.blur`.
|
||||
|
||||
Если бы мы хотели реализовать это на уровне документа, то применили бы делегирование и события `focusin/focusout` (эмуляцию для firefox), так как обычные `focus/blur` не всплывают.
|
|
@ -4,43 +4,66 @@
|
|||
<meta charset="UTF-8">
|
||||
<style>
|
||||
.placeholder {
|
||||
color: gray;
|
||||
color: blue;
|
||||
font-family: Georgia;
|
||||
}
|
||||
|
||||
.placeholder-tooltip {
|
||||
color: blue;
|
||||
font-family: Georgia;
|
||||
position: fixed;
|
||||
}
|
||||
</style>
|
||||
</head>
|
||||
<body>
|
||||
|
||||
<p>Красивый placeholder:</p>
|
||||
|
||||
<input type="text" class="placeholder" value="E-mail">
|
||||
|
||||
<input type="email" data-placeholder="E-mail">
|
||||
|
||||
|
||||
<script>
|
||||
var input = document.getElementsByTagName('input')[0];
|
||||
var input = document.querySelector('[data-placeholder]');
|
||||
|
||||
function prepareInput(input) {
|
||||
input.className = '';
|
||||
input.oldValue = input.value;
|
||||
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 = '';
|
||||
}
|
||||
|
||||
function resetInput(input) {
|
||||
input.className = 'placeholder';
|
||||
input.value = input.oldValue;
|
||||
}
|
||||
|
||||
|
||||
input.onfocus = function() {
|
||||
if (this.className == 'placeholder') {
|
||||
prepareInput(this);
|
||||
}
|
||||
}
|
||||
showTooltip(input);
|
||||
};
|
||||
|
||||
input.onblur = function() {
|
||||
if (this.value == '') {
|
||||
resetInput(this);
|
||||
}
|
||||
document.body.removeChild(input.tooltip);
|
||||
delete input.tooltip;
|
||||
|
||||
// показываем placeholder обратно, если input пуст
|
||||
if (input.value == '') {
|
||||
showPlaceholder(input);
|
||||
}
|
||||
};
|
||||
|
||||
</script>
|
||||
|
||||
|
|
|
@ -3,22 +3,40 @@
|
|||
<head>
|
||||
<meta charset="UTF-8">
|
||||
<style>
|
||||
/* стиль для input с плейсхолдером */
|
||||
.placeholder {
|
||||
color: gray;
|
||||
color: blue;
|
||||
font-family: Georgia;
|
||||
}
|
||||
|
||||
/* стиль для подсказки над элементом (вместо плейсхолдера при фокусировке) */
|
||||
.placeholder-tooltip {
|
||||
color: blue;
|
||||
font-family: Georgia;
|
||||
position: fixed;
|
||||
}
|
||||
</style>
|
||||
</head>
|
||||
<body>
|
||||
|
||||
<p>Красивый placeholder:</p>
|
||||
|
||||
<input type="text" class="placeholder" value="E-mail">
|
||||
|
||||
<input type="email" data-placeholder="E-mail">
|
||||
|
||||
|
||||
<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>
|
||||
|
||||
|
|
|
@ -1,18 +1,19 @@
|
|||
# Плейсхолдер
|
||||
# Улучшенный плейсхолдер
|
||||
|
||||
[importance 5]
|
||||
|
||||
Реализуйте плейсхолдер на JavaScript, чтобы он работал в IE9-.
|
||||
Реализуйте более удобный плейсхолдер-подсказку на JavaScript через атрибут `data-placeholder`.
|
||||
|
||||
Правила работы плейсхолдера:
|
||||
<ul>
|
||||
<li>Элемент изначально содержит плейсхолдер. Специальный класс `placeholder` придает ему серый цвет.</li>
|
||||
<li>При фокусировке плейсхолдер пропадает.</li>
|
||||
<li>При снятии фокуса, если поле пустое -- плейсхолдер возвращается.</li>
|
||||
<li>Элемент изначально содержит плейсхолдер. Специальный класс `placeholder` придает ему синий цвет.</li>
|
||||
<li>При фокусировке плейсхолдер показывается уже над полем, становясь "подсказкой".</li>
|
||||
<li>При снятии фокуса, подсказка убирается, если поле пустое -- плейсхолдер возвращается в него.</li>
|
||||
</ul>
|
||||
|
||||
Все три пункта должны быть соблюдены кросс-браузерно. Пример:
|
||||
Демо:
|
||||
|
||||
[iframe src="solution" height=40]
|
||||
[iframe src="solution" height=100]
|
||||
|
||||
В этой задаче плейсхолдер должен работать на одном конкретном input. Подумайте, если input много, как здесь применить делегирование?
|
||||
|
||||
|
|
|
@ -1,110 +1,9 @@
|
|||
# Алгоритм
|
||||
|
||||
Самый естественный алгоритм решения:
|
||||
<ol>
|
||||
<li>При клике мышонок получает фокус. Для этого нужно либо заменить `DIV` на другой тег, либо добавить ему `tabindex="-1"`.</li>
|
||||
<li>Когда на элементе фокус, то клавиатурные события будут срабатывать прямо на нём. То есть ловим `mousie.onkeydown`.
|
||||
Нам нужно ловить `onclick` на мышонке и в `onkeydown` на нём смотреть коды символов. При скан-кодах стрелок двигать мышонка через `position:absolute` или `position:fixed`.
|
||||
|
||||
Мы выбираем `keydown`, потому что он позволяет во-первых отлавливать нажатия на спец. клавиши (стрелки), а во-вторых, отменить действие браузера, которым по умолчанию является прокрутка страницы.
|
||||
</li>
|
||||
<li>При нажатии на стрелки двигаем мышонка через `position:absolute` и `top/left`.</li>
|
||||
</ol>
|
||||
Скан-коды для клавиш стрелок можно узнать, нажимая на них на [тестовом стенде](#keyboard-test-stand). Вот они: 37-38-39-40 (влево-вверх-вправо-вниз).
|
||||
|
||||
Дальше решение -- попробуйте сделать сами. Возможны подводные камни :)
|
||||
Проблема может возникнуть одна -- `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]
|
|
@ -3,42 +3,45 @@
|
|||
<head>
|
||||
<meta charset="utf-8">
|
||||
<style>
|
||||
#mousie:focus {
|
||||
outline: none;
|
||||
border: 1px dashed black;
|
||||
}
|
||||
html, body {
|
||||
#mouse {
|
||||
display: inline-block;
|
||||
cursor: pointer;
|
||||
margin: 0;
|
||||
height: 100%;
|
||||
}
|
||||
|
||||
#mouse:focus {
|
||||
outline: 1px dashed black;
|
||||
}
|
||||
</style>
|
||||
</head>
|
||||
<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>
|
||||
|
||||
document.getElementById('mousie').onclick = function() {
|
||||
var coords = getCoords(this);
|
||||
this.style.position = 'absolute';
|
||||
this.style.left = coords.left + 'px';
|
||||
this.style.top = coords.top + 'px';
|
||||
document.getElementById('mouse').onclick = function() {
|
||||
this.style.left = this.getBoundingClientRect().left + 'px';
|
||||
this.style.top = this.getBoundingClientRect().top + 'px';
|
||||
|
||||
if (this.parentNode != document.body) {
|
||||
document.body.appendChild(this);
|
||||
this.focus();
|
||||
}
|
||||
this.style.position = 'fixed';
|
||||
};
|
||||
|
||||
|
||||
document.getElementById('mousie').onkeydown = function(e) {
|
||||
e = e || event;
|
||||
|
||||
document.getElementById('mouse').onkeydown = function(e) {
|
||||
switch(e.keyCode) {
|
||||
case 37: // влево
|
||||
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>
|
||||
|
||||
</body>
|
||||
|
|
|
@ -3,52 +3,37 @@
|
|||
<head>
|
||||
<meta charset="utf-8">
|
||||
<style>
|
||||
#mousie:focus {
|
||||
outline: none;
|
||||
border: 1px dashed black;
|
||||
}
|
||||
html, body {
|
||||
#mouse {
|
||||
display: inline-block;
|
||||
cursor: pointer;
|
||||
margin: 0;
|
||||
height: 100%;
|
||||
}
|
||||
|
||||
#mouse:focus {
|
||||
outline: 1px dashed black;
|
||||
}
|
||||
</style>
|
||||
</head>
|
||||
<body>
|
||||
|
||||
Кликните на мышонка и передвигайте его, нажимая клавиши со стрелками.
|
||||
|
||||
<div style="width:41px;height:48px;background:url(https://js.cx/clipart/mousie.gif)"></div>
|
||||
<p>Кликните на мышонка и передвигайте его, нажимая клавиши со стрелками.</p>
|
||||
|
||||
<pre id="mouse">
|
||||
_ _
|
||||
(q\_/p)
|
||||
/. .\
|
||||
=\_t_/= __
|
||||
/ \ (
|
||||
(( )) )
|
||||
/\) (/\ /
|
||||
\ Y /-'
|
||||
nn^nn
|
||||
</pre>
|
||||
|
||||
|
||||
<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>
|
||||
|
||||
|
||||
</body>
|
||||
</html>
|
|
@ -4,73 +4,8 @@
|
|||
|
||||
Кликните по мышонку. Затем нажимайте клавиши со стрелками, и он будет двигаться.
|
||||
|
||||
<style>
|
||||
##mousie:focus {
|
||||
outline: none;
|
||||
border: 1px dashed black;
|
||||
}
|
||||
</style>
|
||||
[demo src="solution"]
|
||||
|
||||
<div style="position:relative;top:20px;width:100px;height:100px">
|
||||
<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`.
|
||||
В этой задаче запрещается ставить обработчики куда-либо, кроме элемента `#mouse`.
|
||||
|
||||
Можно изменять атрибуты и классы в HTML.
|
||||
|
|
|
@ -1,14 +1,15 @@
|
|||
# CSS для решения
|
||||
|
||||
Как видно из исходного кода, `#view` -- это `DIV`, который будет содержать результат, а `#area` - это редактируемое текстовое поле.
|
||||
Как видно из исходного кода, `#view` -- это `<div>`, который будет содержать результат, а `#area` - это редактируемое текстовое поле.
|
||||
|
||||
Так как мы преобразуем `DIV` в `TEXTAREA` и обратно, нам нужно сделать их практически одинаковыми с виду:
|
||||
Так как мы преобразуем `<div>` в `<textarea>` и обратно, нам нужно сделать их практически одинаковыми с виду:
|
||||
|
||||
```css
|
||||
#view, #area {
|
||||
height: 150px;
|
||||
width: 400px;
|
||||
font-family: arial;
|
||||
font-size: 14px;
|
||||
}
|
||||
```
|
||||
|
||||
|
@ -66,13 +67,13 @@ document.onkeydown = function(e) {
|
|||
};
|
||||
```
|
||||
|
||||
В примере выше, `offsetHeight` используется для того, чтобы проверить, отображается элемент или нет. Это очень надежный способ для всех элементов, кроме `TR` в некоторых старых браузерах.
|
||||
В примере выше, `offsetHeight` используется для того, чтобы проверить, отображается элемент или нет. Это очень надежный способ для всех элементов, кроме `<tr>` в некоторых старых браузерах.
|
||||
|
||||
В отличие от простой проверки `display=='none'`, этот способ работает с элементом, спрятанным с помощью стилей, а так же для элементов, у которых скрыты родители.
|
||||
|
||||
# Редактирование
|
||||
|
||||
Следующие функции переключают режимы. HTML-код разрешен, поэтому возможна прямая трансформация в `TEXTAREA` и обратно.
|
||||
Следующие функции переключают режимы. HTML-код разрешен, поэтому возможна прямая трансформация в `<textarea>` и обратно.
|
||||
|
||||
```js
|
||||
function edit() {
|
||||
|
@ -94,5 +95,4 @@ function cancel() {
|
|||
}
|
||||
```
|
||||
|
||||
Чтобы проверить полное решение, сфокусируйтесь на правом iframe, пожалуйста.
|
||||
|
||||
|
|
|
@ -18,11 +18,7 @@ HTML разрешён.
|
|||
|
||||
<script>
|
||||
|
||||
area = document.getElementById('area');
|
||||
view = document.getElementById('view');
|
||||
|
||||
document.onkeydown = function(e) {
|
||||
e = e || event;
|
||||
if (e.keyCode == 27) { // escape
|
||||
cancel();
|
||||
return false;
|
||||
|
|
|
@ -2,6 +2,7 @@
|
|||
height:150px;
|
||||
width:400px;
|
||||
font-family: arial;
|
||||
font-size: 14px;
|
||||
}
|
||||
|
||||
#view {
|
||||
|
|
|
@ -2,6 +2,7 @@
|
|||
height:150px;
|
||||
width:400px;
|
||||
font-family: arial;
|
||||
font-size: 14px;
|
||||
}
|
||||
|
||||
#view {
|
||||
|
|
|
@ -2,10 +2,11 @@
|
|||
|
||||
[importance 5]
|
||||
|
||||
Создайте `DIV`, который при нажатии [key Ctrl+E] превращается в `TEXTAREA`.
|
||||
Изменения, внесенные в поле, можно сохранить в `DIV` сочетанием клавиш [key Ctrl+S] или же отменить нажав [key Esc]. После этого, `TEXTAREA` снова превращается в `DIV`.
|
||||
Создайте `<div>`, который при нажатии [key Ctrl+E] превращается в `<textarea>`.
|
||||
|
||||
Содержимое, сохраненное как HTML-теги должно работать.
|
||||
Изменения, внесенные в поле, можно сохранить обратно в `<div>` сочетанием клавиш [key Ctrl+S], при этом `<div>` получит в виде HTML содержимое `<textarea>`.
|
||||
|
||||
Если же нажать [key Esc], то `<textarea>` снова превращается в `<div>`, изменения не сохраняются.
|
||||
|
||||
[demo src="solution"].
|
||||
|
||||
|
|
|
@ -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 */
|
||||
}
|
||||
|
|
@ -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;
|
||||
}
|
|
@ -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;
|
||||
}
|
|
@ -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>
|
|
@ -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"]
|
||||
|
|
@ -2,6 +2,6 @@
|
|||
<li>При клике -- заменяем `innerHTML` ячейки на `<textarea>` с размерами "под ячейку", без рамки.</li>
|
||||
<li>В `textarea.value` присваиваем содержимое ячейки.</li>
|
||||
<li>Фокусируем посетителя на ячейке вызовом `focus()`.</li>
|
||||
<li>По `keydown` отслеживаем нажатие с `keyCode = 13` ([key Enter]) с `shiftKey` и трансформируем ячейку обратно.</li>
|
||||
<li>Показываем кнопки OK/CANCEL под ячейкой.</li>
|
||||
</ol>
|
||||
|
|
@ -1,52 +1,53 @@
|
|||
/* общие стили для таблицы */
|
||||
|
||||
#bagua-table th {
|
||||
th {
|
||||
text-align:center;
|
||||
font-weight:bold;
|
||||
}
|
||||
|
||||
#bagua-table td {
|
||||
td {
|
||||
width: 150px;
|
||||
white-space: nowrap;
|
||||
text-align:center;
|
||||
vertical-align: bottom;
|
||||
padding: 0;
|
||||
vertical-align: middle;
|
||||
padding: 10px;
|
||||
}
|
||||
|
||||
#bagua-table .nw {
|
||||
.nw {
|
||||
background-color: #999;
|
||||
}
|
||||
|
||||
#bagua-table .n {
|
||||
.n {
|
||||
background-color: #03f;
|
||||
color: #fff;
|
||||
}
|
||||
|
||||
#bagua-table .ne {
|
||||
.ne {
|
||||
background-color: #ff6;
|
||||
}
|
||||
|
||||
#bagua-table .w {
|
||||
.w {
|
||||
background-color: #ff0;
|
||||
}
|
||||
#bagua-table .c {
|
||||
.c {
|
||||
background-color: #60c;
|
||||
color: #fff;
|
||||
}
|
||||
#bagua-table .e {
|
||||
.e {
|
||||
background-color: #09f;
|
||||
color: #fff;
|
||||
}
|
||||
|
||||
#bagua-table .sw {
|
||||
.sw {
|
||||
background-color: #963;
|
||||
color: #fff;
|
||||
}
|
||||
|
||||
#bagua-table .s {
|
||||
.s {
|
||||
background-color: #f60;
|
||||
color: #fff;
|
||||
}
|
||||
#bagua-table .se {
|
||||
.se {
|
||||
background-color: #0c3;
|
||||
color: #fff;
|
||||
}
|
|
@ -1,10 +1,12 @@
|
|||
<!DOCTYPE HTML>
|
||||
<html>
|
||||
<head><meta charset="utf-8"></head>
|
||||
<body>
|
||||
<link type="text/css" rel="stylesheet" href="bagua.css">
|
||||
<link type="text/css" rel="stylesheet" href="my.css">
|
||||
<link rel="stylesheet" href="bagua.css">
|
||||
<link rel="stylesheet" href="my.css">
|
||||
|
||||
Кликните на ячейке для начала редактирования. Когда закончите -- нажмите, находясь в ней, Shift+Enter.
|
||||
|
||||
<p>Кликните на ячейке для начала редактирования. Когда закончите -- нажмите OK или CANCEL.</p>
|
||||
|
||||
<table id="bagua-table">
|
||||
<tr>
|
||||
|
@ -37,6 +39,7 @@
|
|||
|
||||
</table>
|
||||
|
||||
|
||||
<script src="script.js"></script>
|
||||
|
||||
</body>
|
|
@ -13,4 +13,5 @@
|
|||
}
|
||||
.edit-td {
|
||||
position: relative;
|
||||
padding: 0;
|
||||
}
|
|
@ -30,9 +30,12 @@ table.onclick = function(event) {
|
|||
}
|
||||
|
||||
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');
|
||||
textArea.style.width = td.clientWidth + 'px';
|
||||
|
@ -44,10 +47,9 @@ function makeTdEditable(td) {
|
|||
td.appendChild(textArea);
|
||||
textArea.focus();
|
||||
|
||||
var controls = document.createElement('div');
|
||||
controls.innerHTML = '<button class="edit-ok">OK</button><button class="edit-cancel">CANCEL</button>';
|
||||
controls.className = 'edit-controls';
|
||||
td.appendChild(controls);
|
||||
td.insertAdjacentHTML("beforeEnd",
|
||||
'<div class="edit-controls"><button class="edit-ok">OK</button><button class="edit-cancel">CANCEL</button></div>'
|
||||
);
|
||||
}
|
||||
|
||||
function finishTdEdit(td, isOk) {
|
||||
|
@ -56,7 +58,7 @@ function finishTdEdit(td, isOk) {
|
|||
} else {
|
||||
td.innerHTML = editingTd.data;
|
||||
}
|
||||
td.className = td.className.replace(' edit-td', ''); // remove edit class
|
||||
td.classList.remove('edit-td'); // remove edit class
|
||||
editingTd = null;
|
||||
}
|
||||
|
|
@ -1,52 +1,53 @@
|
|||
/* общие стили для таблицы */
|
||||
|
||||
#bagua-table th {
|
||||
th {
|
||||
text-align:center;
|
||||
font-weight:bold;
|
||||
}
|
||||
|
||||
#bagua-table td {
|
||||
td {
|
||||
width: 150px;
|
||||
white-space: nowrap;
|
||||
text-align:center;
|
||||
vertical-align: bottom;
|
||||
padding: 0;
|
||||
vertical-align: middle;
|
||||
padding: 10px;
|
||||
}
|
||||
|
||||
#bagua-table .nw {
|
||||
.nw {
|
||||
background-color: #999;
|
||||
}
|
||||
|
||||
#bagua-table .n {
|
||||
.n {
|
||||
background-color: #03f;
|
||||
color: #fff;
|
||||
}
|
||||
|
||||
#bagua-table .ne {
|
||||
.ne {
|
||||
background-color: #ff6;
|
||||
}
|
||||
|
||||
#bagua-table .w {
|
||||
.w {
|
||||
background-color: #ff0;
|
||||
}
|
||||
#bagua-table .c {
|
||||
.c {
|
||||
background-color: #60c;
|
||||
color: #fff;
|
||||
}
|
||||
#bagua-table .e {
|
||||
.e {
|
||||
background-color: #09f;
|
||||
color: #fff;
|
||||
}
|
||||
|
||||
#bagua-table .sw {
|
||||
.sw {
|
||||
background-color: #963;
|
||||
color: #fff;
|
||||
}
|
||||
|
||||
#bagua-table .s {
|
||||
.s {
|
||||
background-color: #f60;
|
||||
color: #fff;
|
||||
}
|
||||
#bagua-table .se {
|
||||
.se {
|
||||
background-color: #0c3;
|
||||
color: #fff;
|
||||
}
|
|
@ -2,11 +2,11 @@
|
|||
<html>
|
||||
<head><meta charset="utf-8"></head>
|
||||
<body>
|
||||
<link type="text/css" rel="stylesheet" href="bagua.css">
|
||||
<link type="text/css" rel="stylesheet" href="my.css">
|
||||
<link rel="stylesheet" href="bagua.css">
|
||||
<link rel="stylesheet" href="my.css">
|
||||
|
||||
|
||||
Кликните на ячейке для начала редактирования. Когда закончите -- нажмите, находясь в ней, Shift+Enter или кликните на OK/CANCEL.
|
||||
<p>Кликните на ячейке для начала редактирования. Когда закончите -- нажмите OK или CANCEL.</p>
|
||||
|
||||
<table id="bagua-table">
|
||||
<tr>
|
|
@ -0,0 +1 @@
|
|||
/* ваши стили */
|
|
@ -0,0 +1,4 @@
|
|||
|
||||
var table = document.getElementById('bagua-table');
|
||||
|
||||
/* ваш код */
|
|
@ -1,19 +1,16 @@
|
|||
# Редактирование TD по клику, часть 2
|
||||
# Редактирование TD по клику
|
||||
|
||||
[importance 4]
|
||||
[importance 5]
|
||||
|
||||
Сделать ячейки таблицы `td` редактируемыми по клику.
|
||||
|
||||
Поменяйте алгоритм из задачи [](/task/edit-td-click-1) на следующий:
|
||||
<ul>
|
||||
<li>При клике -- ячейка `<td>` превращается в редактируемую, можно менять HTML. Размеры ячеек при этом не должны меняться.</li>
|
||||
<li>В один момент может редактироваться одна ячейка.</li>
|
||||
<li>При редактировании под ячейкой появляются кнопки для приема и отмена редактирования, только клик на них заканчивает редактирование.</li>
|
||||
</ul>
|
||||
|
||||
При решении этой задачи - максимально использовать делегирование.
|
||||
|
||||
Демо:
|
||||
|
||||
[iframe src="solution"]
|
||||
|
||||
В качестве исходного варианта возьмите решение задачи [](/task/edit-td-click-1).
|
|
@ -1 +0,0 @@
|
|||
[edit src="solution"]Открыть решение в песочнице[/edit]
|
|
@ -1,6 +1,6 @@
|
|||
# Фокусировка: focus/blur
|
||||
|
||||
Говорят, что элемент "получает фокус", когда посетитель фокусируется на нём. Обычно фокусировка автоматически происходит при нажатии на элементе мышкой, но также можно перейти на нужный элемент клавиатурой -- через клавишу [key Tab], нажатие пальцем (на мобильных устройствах) и так далее.
|
||||
Говорят, что элемент "получает фокус", когда посетитель фокусируется на нём. Обычно фокусировка автоматически происходит при нажатии на элементе мышкой, но также можно перейти на нужный элемент клавиатурой -- через клавишу [key Tab], нажатие пальцем на планшете и так далее.
|
||||
|
||||
Момент получения фокуса и потери очень важен.
|
||||
|
||||
|
@ -21,11 +21,11 @@
|
|||
<li>Обработчик `onfocus`, если текущее состояние поля ввода -- "ошибка" -- скрывает её (потом при `onblur` будет повторная проверка).</li>
|
||||
</ul>
|
||||
|
||||
Наберите что-нибудь в поле "возраст" примера ниже и завершите ввод, нажав [key Tab] или кликнув в другое место страницы. Введённое значение будет автоматически проверено:
|
||||
В примере ниже, если набрать что-нибудь в поле "возраст" и завершить ввод, нажав [key Tab] или кликнув в другое место страницы, то введённое значение будет автоматически проверено:
|
||||
|
||||
```html
|
||||
<!--+ run autorun height=60 -->
|
||||
<style> .error { background: red; } </style>
|
||||
<style> .error { border-color: red; } </style>
|
||||
|
||||
Введите ваш возраст: <input type="text" id="input">
|
||||
|
||||
|
@ -36,7 +36,7 @@
|
|||
if (isNaN(this.value)) { // введено не число
|
||||
// показать ошибку
|
||||
this.className = "error";
|
||||
error.innerHTML = 'Вы ввели не число. Исправьте, пожалуйста'
|
||||
error.innerHTML = 'Вы ввели не число. Исправьте, пожалуйста.'
|
||||
}
|
||||
};
|
||||
|
||||
|
@ -186,7 +186,7 @@ age.onblur = function() {
|
|||
|
||||
<style>
|
||||
li { cursor: pointer; }
|
||||
:focus { border: 1px dashed green; outline: 0; }
|
||||
:focus { outline: 1px dashed green; }
|
||||
</style>
|
||||
```
|
||||
|
||||
|
@ -207,7 +207,7 @@ age.onblur = function() {
|
|||
<input type="text" name="surname" value="Ваша фамилия">
|
||||
</form>
|
||||
|
||||
<style> .focused { border: 2px solid red; } </style>
|
||||
<style> .focused { outline: 1px solid red; } </style>
|
||||
```
|
||||
|
||||
В примере выше стоит обработчик `onfocus` на форме, но он не работает, т.к. при фокусировке на любом `INPUT` событие `focus` срабатывает только на этом элементе и не всплывает наверх.
|
||||
|
@ -225,7 +225,7 @@ age.onblur = function() {
|
|||
<input type="text" name="surname" value="Ваша фамилия">
|
||||
</form>
|
||||
|
||||
<style> .focused { border: 2px solid red; } </style>
|
||||
<style> .focused { outline: 1px solid red; } </style>
|
||||
|
||||
<script>
|
||||
*!*
|
||||
|
@ -262,7 +262,7 @@ age.onblur = function() {
|
|||
<input type="text" name="surname" value="Ваша фамилия">
|
||||
</form>
|
||||
<style>
|
||||
.focused { border: 2px solid red; }
|
||||
.focused { outline: 1px solid red; }
|
||||
</style>
|
||||
|
||||
<script>
|
||||
|
|
|
@ -80,13 +80,13 @@ function growIn(img) {
|
|||
requestAnimationFrame(function() {
|
||||
img.classList.add('growing');
|
||||
|
||||
img.addEventListener('transitionend', done, false);
|
||||
img.addEventListener('transitionend', done);
|
||||
});
|
||||
});
|
||||
|
||||
function done(e) {
|
||||
// сработать только первый раз
|
||||
img.removeEventListener('transitionend', done, false);
|
||||
img.removeEventListener('transitionend', done);
|
||||
|
||||
placeholder.parentNode.replaceChild(img, placeholder);
|
||||
|
||||
|
|
|
@ -236,11 +236,11 @@ document.body.style.Transform = "rotate(360deg)";
|
|||
...
|
||||
go();
|
||||
|
||||
elem.addEventListener('transitionend', go, false); /* на будущее */
|
||||
elem.addEventListener('webkitTransitionEnd', go, false);
|
||||
elem.addEventListener('mozTransitionEnd', go, false);
|
||||
elem.addEventListener('oTransitionEnd', go, false);
|
||||
elem.addEventListener('msTransitionEnd', go, false);
|
||||
elem.addEventListener('transitionend', go); /* на будущее */
|
||||
elem.addEventListener('webkitTransitionEnd', go);
|
||||
elem.addEventListener('mozTransitionEnd', go);
|
||||
elem.addEventListener('oTransitionEnd', go);
|
||||
elem.addEventListener('msTransitionEnd', go);
|
||||
...
|
||||
```
|
||||
|
||||
|
|
|
@ -47,11 +47,11 @@ function bounceBoat(elem) {
|
|||
|
||||
go();
|
||||
|
||||
elem.addEventListener('transitionend', go, false); /* на будущее */
|
||||
elem.addEventListener('webkitTransitionEnd', go, false);
|
||||
elem.addEventListener('mozTransitionEnd', go, false);
|
||||
elem.addEventListener('oTransitionEnd', go, false);
|
||||
elem.addEventListener('msTransitionEnd', go, false);
|
||||
elem.addEventListener('transitionend', go); /* на будущее */
|
||||
elem.addEventListener('webkitTransitionEnd', go);
|
||||
elem.addEventListener('mozTransitionEnd', go);
|
||||
elem.addEventListener('oTransitionEnd', go);
|
||||
elem.addEventListener('msTransitionEnd', go);
|
||||
}
|
||||
</script>
|
||||
|
||||
|
|
|
@ -12,7 +12,7 @@ if (!window.setImmediate) window.setImmediate = (function() {
|
|||
}
|
||||
|
||||
if(window.addEventListener) { // IE9+, другие браузеры
|
||||
window.addEventListener('message', onmessage, false);
|
||||
window.addEventListener('message', onmessage);
|
||||
} else { // IE8
|
||||
window.attachEvent( 'onmessage', onmessage );
|
||||
}
|
||||
|
|
|
@ -12,7 +12,7 @@ if (!window.setImmediate) window.setImmediate = (function() {
|
|||
}
|
||||
|
||||
if(window.addEventListener) { // IE9+, другие браузеры
|
||||
window.addEventListener('message', onmessage, false);
|
||||
window.addEventListener('message', onmessage);
|
||||
} else { // IE8
|
||||
window.attachEvent( 'onmessage', onmessage );
|
||||
}
|
||||
|
|
|
@ -62,7 +62,7 @@ function listener(event) {
|
|||
}
|
||||
|
||||
if (window.addEventListener){
|
||||
window.addEventListener("message", listener, false);
|
||||
window.addEventListener("message", listener);
|
||||
} else {
|
||||
window.attachEvent("onmessage", listener);
|
||||
}
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue