Инициализация типа 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 );
    }
}