Обнаружение типа HTML5 и инициализация плагина - PullRequest
14 голосов
/ 12 ноября 2010

ЧАСТЬ 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-includes.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 без добавления классов для инициализации off)

Существуют ли более эффективные методы для перебора DOM для ввода загадоктипы?И должен ли я использовать If Else, или функцию, или кейс в моем примере?

Спасибо всем,

Джоэл

Ответы [ 7 ]

26 голосов
/ 12 ноября 2010

Прежде всего, прекратите использовать 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){
    try {
        tester.type = i;
        if (tester.type === i){
            supported[i] = true;
        }
    } catch (e) {
        // IE raises an exception if you try to set the type to 
        // an invalid value, so we just swallow the error
    }
}

Это фактически использует тот факт, что браузеры, которые не поддерживают этот конкретный тип ввода, будут использовать текст, что позволит вам проверить, поддерживаются они или нет.

Затем вы можете использовать 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/

9 голосов
/ 09 октября 2013

Запрос атрибута типа работает не во всех стандартных 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 голосов
/ 18 ноября 2010

Я бы сказал, что это ошибка в JQuery! Если вы посмотрите на функцию attr () в самом коде JQuery, JQuery сначала попытается получить значение для имени, которое вы передали, используя скобочную запись , Если он не неопределен, он возвращает это значение. Если он не определен, он вместо этого использует метод getAttribute ().

Jquery делает нечто подобное для $ ("# elem"). Attr (name):

 if (elem[ name ] !== undefined)
 {
    return elem[name];
 }
 else
 {
    return elem.getAttribute( name )
 }

Проблема в том, что Jquery предполагает, что если elem [имя] не определено, то elem [имя] верно.

Рассмотрим следующий пример:

<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'] возвращает "text", поэтому Jquery возвращает "text". Если вы передали .attr ("joel"), myInput ['joel'] возвращает неопределенное значение, поэтому вместо этого Jquery использует getAttribute ('joel'), который возвращает "crawford".

3 голосов
/ 12 ноября 2010

Атрибут type не является «готовым» элементом, он определен здесь:

http://www.w3.org/TR/REC-html40/interact/forms.html#h-17.4

... и браузеры только «знают» о значениях @type, определенных там (если они не осведомлены о HTML5 - который определил некоторые новые значения, такие как «дата», «email» и т. Д.)

Когда вы запрашиваете атрибут type, некоторые браузеры возвращают вам «текст», потому что, если браузер не поддерживает тип «date» (или что-то еще, что он не понимает), он возвращается к значению по умолчанию - что is type = "text"

Задумывались ли вы о добавлении имени класса (class = "date") к входным данным, тогда вы можете просто $ ('. Date'). Each () и затем выполнить обнаружение на этом наборе

0 голосов
/ 27 декабря 2017

Вот скрипт jQuery, который определяет, поддерживает ли браузер формат 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 );
    }
}
0 голосов
/ 06 марта 2017

Просто 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());

Всегда проверяйте, никогда не копируйте вслепую!

0 голосов
/ 12 ноября 2010

Вы не можете получить type = "date" в браузере, который не поддерживает это. Если браузер обнаруживает атрибут type, он не понимает, что он переопределяет его с type = "text" (по умолчанию).

Способ обойти это (используя jQuery) - просто добавить дату класса.

Тогда вы можете сделать что-то вроде

$('input.date').each(function() {
    var $this = $(this);
    if($this.attr('type') != 'date') $this.datepicker();
});
...