Инициализация типа HTML5 и инициализация плагина
ЧАСТЬ A:
Я знаю, что есть много вещей, которые говорят вам, поддерживает ли браузер определенный атрибут HTML5, например http://diveintohtml5.info/detect.html, но они не говорят вам, как получить тип от отдельных элементов и использовать эту информацию для инициализации ваших плагинов.
Итак, я попробовал:
alert($("input:date"));
//returns "[object Object]"
alert($("input[type='date']"));
//returns "[object Object]"
alert($("input").attr("type"));
//returns "text" ... which is a lie. it should have been "date"
Никто не работал.
В конце концов я придумал это (это работает):
var inputAttr = $('<div>').append($(this).clone()).remove().html().toLowerCase();
alert(inputAttr);
// returns "<input min="-365" max="365" type="date">"
Спасибо: http://jquery-howto.blogspot.com/2009/02/how-to-get-full-html-string-including.html
Итак, мой первый вопрос:
1. Почему я не могу прочитать атрибут "type" в браузерах, которые не поддерживают html5? Вы можете составить любой другой атрибут и фиктивное значение и прочитать его.
2. Почему мое решение работает? Почему это имеет значение, если оно в DOM или нет?
ЧАСТЬ B:
Ниже приведен базовый пример того, что я использую для обнаружения:
<script type="text/javascript" >
$(function () {
var tM = document.createElement("input");
tM.setAttribute("type", "date");
if (tM.type == "text") {
alert("No date type support on a browser level. Start adding date, week, month, and time fallbacks");
// Thanks: http://diveintohtml5.ep.io/detect.html
$("input").each(function () {
// If we read the type attribute directly from the DOM (some browsers) will return unknown attributes as text (like the first detection). Making a clone allows me to read the input as a clone in a variable. I don't know why.
var inputAttr = $('<div>').append($(this).clone()).remove().html().toLowerCase();
alert(inputAttr);
if ( inputAttr.indexOf( "month" ) !== -1 )
{
//get HTML5 attributes from element
var tMmindate = $(this).attr('min');
var tMmaxdate = $(this).attr('max');
//add datepicker with attributes support and no animation (so we can use -ms-filter gradients for ie)
$(this).datepick({
renderer: $.datepick.weekOfYearRenderer,
onShow: $.datepick.monthOnly,
minDate: tMmindate,
maxDate: tMmaxdate,
dateFormat: 'yyyy-mm',
showAnim: ''});
}
else
{
$(this).css('border', '5px solid red');
// test for more input types and apply init to them
}
});
}
});
</script>
Пример в реальном времени: http://joelcrawfordsmith.com/sandbox/html5-type-detection.html
И услуга/вопрос:
Может ли кто-нибудь помочь мне отрезать немного жира в моем блоке ввода типа HTML5?
У меня есть функциональность вниз (добавляет резервные копии для IE6-IE8 и FF без добавления классов для init)
Существуют ли более эффективные методы для итерации по DOM для типов ввода тайны?
И должен ли я использовать If If Else, или функцию, или случай в моем примере?
Спасибо всем,
Joel
Ответы
Ответ 1
Прежде всего, перестаньте использовать alert
, чтобы выполнить отладку! Возьмите копию Firebug и FireQuery и используйте их с console.log()
. Даже если вы работаете с alert()
, вам действительно нужно использовать $("input[type='date']").length
, чтобы найти, если селектор вернул что-либо - object [object]
не говорит вам ничего полезного здесь.
Более высокий метод обнаружения поддерживаемых типов входных данных - это просто создать входной элемент и пропустить все доступные типы входных данных и проверить, не меняется ли type
:
var supported = {date: false, number: false, time: false, month: false, week: false},
tester = document.createElement('input');
for(var i in supported){
tester.type = i;
if(tester.type === i){
supported[i] = true;
}
}
Это фактически использует тот факт, что браузеры, которые не поддерживают этот тип ввода, возвращаются к использованию текста, тем самым позволяя вам проверить, поддерживаются ли они или нет.
Затем вы можете использовать supported['week']
, например, для проверки доступности типа ввода week
и выполнить резервное копирование через это. См. Простую демонстрацию этого здесь: http://www.jsfiddle.net/yijiang/r5Wsa/2/. Вы можете также рассмотреть возможность использования Modernizr для более надежного обнаружения функции HTML5.
И, наконец, лучший способ получить outerHTML
- это, верьте или нет, используйте outerHTML
. Вместо
var inputAttr = $('<div>').append($(this).clone()).remove().html().toLowerCase();
Почему бы просто не использовать:
var inputAttr = this.outerHTML || new XMLSerializer().serializeToString(this);
(Да, как вы можете видеть, есть предостережение - outerHTML
не поддерживается Firefox, поэтому нам понадобится простой обходной путь от этого стека Вопрос переполнения).
Изменить: Найден метод тестирования для поддержки пользовательского интерфейса на родной форме с этой страницы: http://miketaylr.com/code/html5-forms-ui-support.html. Браузеры, которые поддерживают пользовательский интерфейс для этих типов в некотором роде, также должны помешать внесению недопустимых значений в эти поля, поэтому логическое расширение для теста, которое мы делаем выше, будет следующим:
var supported = {date: false, number: false, time: false, month: false, week: false},
tester = document.createElement('input');
for(var i in supported){
tester.type = i;
tester.value = ':(';
if(tester.type === i && tester.value === ''){
supported[i] = true;
}
}
Опять же, не на 100% надежный - это только хорошо для типов, которые имеют определенные ограничения на их ценности, и определенно не очень хорошо, но это шаг в правильном направлении и, безусловно, решит вашу проблему сейчас.
Смотрите обновленную демо: http://www.jsfiddle.net/yijiang/r5Wsa/3/
Ответ 2
Запрос атрибута type не работает во всех браузерах Android. Они притворяются, что они поддерживают inputType = "date", но они не предлагают пользовательский интерфейс (datepicker, например,) для ввода данных.
Это обнаружение этой функции работало для меня:
(function() {
var el = document.createElement('input'),
notADateValue = 'not-a-date';
el.setAttribute('type','date');
el.setAttribute('value', notADateValue);
return el.value !== notADateValue;
})();
Хитрость заключается в установке недопустимого значения в поле даты. Если браузер дезинфицирует этот вход, он также может предложить дампикера.
Ответ 3
Атрибут type не является элементом "make-up", который определяется здесь:
http://www.w3.org/TR/REC-html40/interact/forms.html#h-17.4
... и браузеры только "знают" о значениях @type, определенных там (если только они не знают HTML5), которые определили некоторые новые значения, такие как "дата", "электронная почта" и т.д.)
Когда вы запрашиваете атрибут типа, некоторые браузеры возвращают вам "текст", потому что если браузер не поддерживает тип "дата" (или что-то, что он не понимает), тогда он возвращается к значению по умолчанию - которое is type = "text"
Думали ли вы о добавлении имени класса (class= "date" ) к входам, а затем вы можете просто $('. date'). each(), а затем вы обнаруживаете на этом наборе
Ответ 4
Я бы сказал, что это ошибка в JQuery! Если вы посмотрите на функцию attr() в самом коде JQuery, JQuery сначала попытается получить значение для имени, которое вы передали с помощью скобки нотации. Если это не undefined, то оно возвращает это значение. Если это undefined, тогда вместо этого используется метод getAttribute().
JQuery делает что-то похожее на это для $( "# elem" ). attr (name):
if (elem[ name ] !== undefined)
{
return elem[name];
}
else
{
return elem.getAttribute( name )
}
Проблема заключается в том, что Jquery принимает, если elem [name] не undefined, то elem [name] верен.
Рассмотрим следующий пример:
<input type="date" id="myInput" name="myInput" joel="crawford" />
var myInput = document.getElementById('myInput');
alert(myInput['type']);//returns text
alert(myInput.getAttribute('type'));//returns date
alert($("#myInput").attr('type'));//returns text
alert(myInput['joel']);//returns undefined
alert(myInput.getAttribute('joel'));//returns crawford
alert($("#myInput").attr('joel'));//returns crawford
Когда вы проходите в .attr( "type" ), myInput ['type'] возвращает "текст", поэтому JQuery возвращает "текст". Если вы перешли в .attr( "joel" ), myInput ['joel'] возвращает undefined, поэтому Jquery вместо этого использует getAttribute ('joel'), который возвращает "crawford".
Ответ 5
Вы не можете получить type = "date" в браузере, который не поддерживает это. Если браузер обнаруживает атрибут типа, он не понимает, что он переопределяет его с типом = "текст" (по умолчанию).
Путь к этому (с использованием jQuery) - это просто добавить дату класса.
Затем вы можете сделать что-то вроде
$('input.date').each(function() {
var $this = $(this);
if($this.attr('type') != 'date') $this.datepicker();
});
Ответ 6
Просто tester.type = i;
выдает исключение в IE. Фиксированная версия:
var get_supported_html5_input_types = function() {
var supported = {
date: false,
number: false,
time: false,
datetime: false,
'datetime-local':false,
month: false,
week: false
},
tester = document.createElement('input');
for(var i in supported){
// Do nothing - IE throws, FF/Chrome just ignores
try { tester.type = i; } catch (err) {}
if(tester.type === i){
supported[i] = true;
}
}
return supported;
};
console.log(get_supported_html5_input_types());
Ответ 7
Здесь jQuery script, который определяет, поддерживает ли браузер формат HTML5 date
, и если это так, он изменяет все значения полей date
в формате yyyy-mm-dd
, а все значения полей datetime
равны yyyy-mm-dd hh:mm:ss
формат.
// From https://stackoverflow.com/a/10199306
// If the browser supports HTML5 input type="date", change all the values from y/m/dddd format to yyyy-mm-dd format, so they appear properly:
function fix_date_inputs() {
try {
var input = document.createElement('input');
input.setAttribute('type','date');
var notADateValue = 'not-a-date';
input.setAttribute('value', notADateValue);
var r = (input.value !== notADateValue);
if ( r ) {
$( 'input' ).each( function() {
if (
$(this).attr( 'type' ).match( /^date/ ) // date or datetime
) {
var m_d_y = $(this).context.attributes.value.value; // Because $(this).val() does not work (returns '')
var d = new Date( m_d_y );
var month = '' + (d.getMonth() + 1);
var day = '' + d.getDate();
var year = d.getFullYear();
if (month.length < 2) month = '0' + month;
if (day.length < 2) day = '0' + day;
var yyyy_mm_dd = [ year, month, day ].join( '-' );
// If we're processing a datetime, add the time:
if (
$(this).attr( 'type' ) == 'datetime'
) {
var h = '' + d.getHours();
var i = '' + d.getMinutes();
var s = '' + d.getSeconds();
if (h.length < 2) h = '0' + h;
if (i.length < 2) i = '0' + i;
if (s.length < 2) s = '0' + s;
yyyy_mm_dd += ' ' + [ h, i, s ].join( ':' );
}
$(this).val( yyyy_mm_dd ); // Here, val() works to set the new value. Go figure.
}
});
}
} catch( e ) {
alert( 'Internal error: ' + e.message );
}
}