RReverser's

Ingvar Stepanyan

JavaScript developer, speaker and reverse engineer. D2D programmer. Sometimes human.


"Условная компиляция" в JavaScript

Естественно, речь на самом деле ни о какой условной компиляции идти не может (собственно говоря, и о компиляции JavaScript вообще), но все же суть аналогична до вышеназванной фичи в компилируемых языках.

По мотивам http://habrahabr.ru/company/microsoft/blog/114971/#comment_3715792 , где мы сообща с kratkar и VolCh пришли к пониманию необходимости ветвлений верстки для различных браузеров. Там в комментариях мною был шутя опубликован кусок кода на jQuery, которым можно реализовать подобный функционал (для тех кто против использования яваскрипта в верстке — я вас понимаю, но так как другого способа сделать условные теги нет, прошу не пинать).

На данный момент этот скрипт был переработан в плагин для jQuery, который позволяет удобным образом выполнять определенные секции кода только в заданных браузерах. Таким образом, его первоначальная идея была немного расширена, но легко осуществляется при помощи данного плагина.

Итак, сам плагин можно взять здесь: http://plugins.jquery.com/project/only .

Использовать можно двумя способами:

$.only(browserList, callback);
$(browserList).only(callback);

Фактически эти вызовы аналогичны между собой, за исключением того, что во втором случае передаваемый список браузеров сперва приводится в объект jQuery, и поэтому так нельзя передавать к примеру массивы (для них лучше использовать первый способ).

Список браузеров может быть задан, как я уже сказал, массивом — [«opera», «mozilla»], объектом (ассоциативный массив вида браузер-версии) — {opera: "-9.54", msie: «6,7»} либо HTML-элементом, в аттрибутах которого заданы версии браузеров.

Собственно использование скрипта:

$.only(['webkit', 'opera', 'mozilla'], function (browserName, browserVersion) {  
 if (browserName != false) alert('I\'m running browser engine ' + browserName + ' v' + browserVersion);
});
$.only({
 msie: '9-'
}, function (browserName) {
 if (browserName != false) alert('I\'m running modern version of Internet Explorer');
});
$.only({
 msie: '-8'
}, function (browserName) {
 if (browserName != false) alert('I\'m running old Internet Explorer');
});
// === $({msie: '-8'}).only(function() { ... });

Как видите, все довольно просто. Вы передаете список поддерживаемых браузеров и callback-функцию формата function(browserName, browserVersion) {… } и она получает название обнаруженного поддерживаемого движка первым параметром либо false если таков не найден. Версия движка передается в callback в любом случае.

Список версий задается в виде «2-4,5.5,6-8,9», то есть промежутками версий либо отдельными версиями, отделенными запятыми.

Давайте теперь попробуем реализовать собственно то, ради чего первоначально затевался этот скрипт — верстка с ветвлениями. Как вы помните, первоначально наш код выглядел так:

<!DOCTYPE html>  
<html>
<head>
<script src="http://ajax.aspnetcdn.com/ajax/jQuery/jquery-1.5.1.min.js"  type="text/javascript"></script>
<script type="text/javascript">
$(document).ready(function(){
  $('only').each(function(){
    var $this = $(this), supported = false, names = ['webkit', 'opera', 'msie', 'mozilla', 'safari'];
    names.forEach(function(name){
      var version = $this.attr(name), bVersion = $.browser.version;
      if($.browser[name] && (version == ""  || (version && bVersion && bVersion.substr(0, bVersion.indexOf('.')) == version.substr(0, version.indexOf('.')))))
        supported = true;
    });
    if(!supported)
      $this.remove();
  });
});
</script>
</head>
<body>
IE is <only webkit opera mozilla>dead</only><only msie>alive</only>  
</body>
</html>

С использованием данного плагина яваскрипт-код для перебора элементов становится проще и очевиднее (а заодно начинает корректно сравнивать версии браузеров и убирает обертку only у всех элементов):

$('only').only(function(browser) {  
    var $this = $(this);
    browser ? $this.replaceWith($this.html()) : $this.remove();
});

Ну вот и все. Наша задача решена, если кому-то и правда понадобится — код под лицензией LGPL, так что используйте на здоровье. Но лично я присоединяюсь к разработчикам jQuery и прошу всегда, когда это возможно, использовать feature detection, а подобный подход оставьте для действительно безвыходных случаев (к сожалению, и такие есть в наши пасмурные времена).

comments powered by Disqus