Как преодолеть WhatWG/W3C/Chrome версии 33.0.1750.146 "ошибка регрессии" с полями <input type = "number" /">
Я помещал слова "ошибка регрессии" в кавычки, так как, очевидно, есть некоторые смешанные мнения по этому поводу. Для полной информации отслеживайте Bug 24796 в Bugzilla.
Короче Google Chrome внедрил изменения в соответствии с последней версией спецификаций WhatWG: http://www.whatwg.org/specs/web-apps/current-work/multipage/the-input-element.html#input-type-attr-summary
что удалено следующие свойства и методы из полей <input type="number"/>
.
Свойства:
- SelectionStart
- selectionEnd
Методы:
- выберите()
- setSelectionRange (начало, конец)
(есть и другие, но они используются с общими ключами)
Методы определяются, если вы проверяете "числовой" экземпляр HTMLInputElement
, однако попытка вызвать методы или запросить свойства вызовет исключение.: - (
IMHO это ошибка (так как функциональность была удалена ничем не получена... и есть 1000 веб-сайтов/приложений, которые обеспечивают расширенное поведение этих числовых полей ввода через JavaScript... но я отвлекаюсь (для тех, кто хотите сразиться, пожалуйста, используйте сообщение об ошибке, указанное выше))
TL; DR
В целях удобства использования я, безусловно, хочу и планирую продолжать использовать поля <input type="number"/>
, поскольку они предоставляют "подсказку" пользовательскому агенту, если на мобильном устройстве (смартфоне/планшете/?), которое я бы
например, представить числовую клавиатуру, когда поле сосредоточено против стандартной альфа-клавиатуры.
Однако для текущей версии Chrome (версия 33.0.1750.146) и любого другого браузера, который слепо реализует это изменение спецификации, я хотел бы безопасно преобразовать отображаемые поля обратно в
<input type="text"/>
Примечания:
- Попытка изменить эти поля "на лету" при изменении их содержимого оказалась неудачной, поскольку поле теряет диапазон выбора при изменении атрибута типа.
- У меня есть решение для решения проблемы, с которым я столкнулся, и я хотел бы опубликовать его в ближайшее время, но я хотел, чтобы этот вопрос/ответ был здесь для всех разработчиков, столкнувшихся с этой проблемой.
Ответы
Ответ 1
Я решил это со следующим кодом:
function checkForInputTypeNumberBug(){
var dummy = document.createElement('input');
try {
dummy.type = 'number';
} catch(ex){
//Older IE versions will fail to set the type
}
if(typeof(dummy.setSelectionRange) != 'undefined' && typeof(dummy.createTextRange) == 'undefined'){
//Chrome, Firefox, Safari, Opera only!
try {
var sel = dummy.setSelectionRange(0,0);
} catch(ex){
//This exception is currently thrown in Chrome v33.0.1750.146 as they have removed support
//for this method on number fields. Thus we need to revert all number fields to text fields.
$('input[type=number]').each(function(){
this.type = 'text';
});
}
}
}
$(document).ready(function(){
checkForInputTypeNumberBug();
});
Я сделал это автономной функцией, так как у меня есть случаи, когда поля загружаются через AJAX, и мне нужно иметь возможность вызывать эту функцию на лету.
Этот код обрабатывает старые версии IE, где попытка установить тип не удалась, а также обрабатывать исключение в Chrome (на фиктивном элементе), чтобы страницы могли преодолеть это изменение поведения.
Обновление:. В соответствии с предложением @Andy E с использованием атрибута inputmode (в настоящее время не поддерживается) я создал ошибку, чтобы попытаться определить приоритет реализации входного режима, прежде чем пользовательские агенты удаляют API-интерфейсы выбора: https://www.w3.org/Bugs/Public/show_bug.cgi?id=26695
Ответ 2
В зависимости от варианта использования может возникнуть более подходящее (хотя и сложное) решение проблемы. Например, чтобы добавить текст в текущую позицию курсора, вы можете сделать следующее (проверено в Chrome):
var len, pre, post,
// Currently focused element
a = document.activeElement,
// Get current selection
s = window.getSelection();
// Delete any existing contents
s.deleteFromDocument();
// Keep moving selection backward until the length stops increasing
do {
len = String(s).length;
s.modify('extend', 'backward', 'line');
}
while (String(s).length !== len);
// Store the selection, then delete it
pre = String(s);
s.deleteFromDocument();
// Keep moving selection forward until the length stops increasing
do {
len = String(s).length;
s.modify('extend', 'forward', 'line');
}
while (String(s).length !== len);
// Store the selection, then delete it
post = String(s);
s.deleteFromDocument();
// Recreate the contents with the new text added
a.setAttribute('value', a.defaultValue);
a.value = pre + txt + post;
// Move the selection to after the new text
a.select();
s = window.getSelection();
s.collapseToEnd();
while (len-- > 0)
s.modify('move', 'backward', 'character');
Существуют ограничения для этого подхода, которые могут потребоваться и более сложные решения, например, когда возвращается другое значение, чем выбран текст (что может иметь место для арабских доменных имен в входе type="email"
, например).
К сожалению, там ошибка, которая предотвращает это обходное решение от работы в Firefox/Gecko, но по крайней мере Firefox по-прежнему позволяет Selection API на <input type="email">
.