среда, 10 августа 2011 г.

JavaScript. Простой шаблонизатор

Когда работаешь с JavaScript, то приходиться часто работать с DOM страницы. Есть задачи, когда нужно вставить в какой-то узел документа - кусочек готового шаблона с подстановкой в него данных. Самым простым вариантом будет склейка готового текста из кусочков, например:
var classname = "myclass";
var value = "test";
var content = "
  • "+value+"
    "+"
  • "; $("#div_id").append(content);

    Но это не совсем удобно, особенно если "склеивать" большое количество частей. jQuery 1.6.x предлагает свой шаблонизатор, но он пока в бета-версии. Есть куча сторонних решений, но они, как правило, громоздкие и надо всегда оценивать целесообразность их применения. Когда-то нашел интересный пример реализации шаблонизатора, который и покажу в действии.

    Расширяем стандартный класс String:
    String.prototype.supplant = function(o) {
       return this.replace(/\{([^{}]*)\}/g, function(a, b) {
          var r = o[b];
          return typeof r === 'string' || typeof r === 'number' ? r : a;
       });
    };
    

    Пример его использования:
    var template = "
    
  • {value}
  • "; var content = template.supplant({classname: 'myclass', value: 'test'});

    Такой подход позволяет держать шаблоны вставки отдельно от логики скрипта, что позволяет удобно править верстку без правки логики.

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


    JavaScript. Простой assert

    Часто бывает полезно поставить в коде некоторые проверки целостности кода, для этого очень хорошо подходит методо assert стандартной console, которая поддерживается всеми современными браузерами (с IE8+ для мелкософта). Так можно реализовать простейшее тестирование кода.

    Применение:
    var x = 1;
    console.assert(x == 1, "X should be eqaul 1");
    

    Первым аргументом идет проверяемое утверждение (результатом должно быть логическое значение TRUE/FALSE), вторым - подсказка отображаемая в консоли.

    Если интересно почитать о консоли глубже - выкладываю ссылку на хабру.

    JavaScript. Получить timestamp из даты

    Для того чтобы получить timestamp из объекта даты, нужно воспользоваться методом valueOf():
    var dateObject = new Date;
    var timestamp = dateObject.valueOf();
    console.log(timestamp);
    
    // Или проще
    var timestamp1 = +dateObject;
    
    // Еще проще
    var timestamp2 = +new Date;
    

    пятница, 15 июля 2011 г.

    jQuery. Проверить существование элемента на странице

    Для того, чтобы проверить существует или нет заданный элемент, можно использовать 2 способа. В основе всего, лежит тот факт, что jQuery селекторы возвращают массив и мы можем искать его длину. Даже если найден только 1 элемент (когда мы конкретный элемент ищем) то размер ответа будет равен 1.

    Способ первый - стандартный:
    if($("#findID").length>0) {
      // exists
    }
    //еще проще:
    if($("#findID").length) {
      // exists
    }
    // Еще вариант:
    if($('#findID')[0]) {
     // exists
    }
    

    Способ второй - удобный (создадим пользовательскую функцию exists() ):
    // Один раз объявляем функцию, потом используем так, как в примере
    jQuery.fn.exists = function() {
       return $(this).length;
    }
    // Пример использования:
    if($("#findID").exists()) {
       // exists
    }
    

    Можно и так:
    jQuery.exists = function(selector) {
       return ($(selector).length > 0);
    }
    
    // Пример использования:
    if ($.exists(selector)) {
      // exists
    }
    

    вторник, 12 июля 2011 г.

    jQuery, CSS. Как отключить выделение мышкой текста для отдельного блока

    Иногда нужно запретить выделение текста в некоторых блоках - например при динамическом изменении размера, текст блока будет выделяться, что не есть красиво.

    Решений тут два: используем jQuery либо CSS.

    jQuery:
    $(".classname").attr('unselectable','on').css('MozUserSelect','none');
    

    CSS:
    .classname{
      -moz-user-select: none;
      -khtml-user-select: none;
      -webkit-user-select: none;
      -o-user-select: none;
      user-select: none;
    }
    
    Учитывая пожелания высказанные в комментариях, привожу пример яваскриптового отключения выделения (организованного в плагин), с явным отключением самого ивента 'onselectstart', а также содержащий весь уже выше перечисленный функционал:
    jQuery.fn.extend({ 
        disableSelection : function() { 
                this.each(function() { 
                        this.onselectstart = function() { return false; }; 
                        this.unselectable = "on"; 
                        jQuery(this).css({
                          '-moz-user-select': 'none',
                          '-khtml-user-select': 'none',
                          '-webkit-user-select': 'none',
                          '-o-user-select': 'none',
                          'user-select': 'none'
                        });
    
                }); 
        },
        enableSelection : function() { 
                this.each(function() { 
                        this.onselectstart = function() {}; 
                        this.unselectable = "off";
                        jQuery(this).css({
                          '-moz-user-select': 'auto',
                          '-khtml-user-select': 'auto',
                          '-webkit-user-select': 'auto',
                          '-o-user-select': 'auto',
                          'user-select': 'auto'
                        });
                }); 
        } 
    });
    
    // Example:
    var selector = "td, span, div";
    $(selector).disableSelection(); // disable
    ....
    $(selector).enableSelection(); // enable
    

    среда, 29 июня 2011 г.

    Yii. Настройка логирования SQL запросов

    В этой статье я расскажу как можно вывести в дебаг SQL которые генерит фреймворк Yii.

    Все изменения будут производится в главном конфиге,  который находиться тут: /protected/config/main.php
    Найдем в нем строчку
    'components' => array(
    
    Наша основная задача - настроить компонент логирования и компонет работы с БД, укажем параметры компоненту log и допишем параметры компоненту db:
    'components' => array(
       'db' => array(
          ..., 
          'enableProfiling' => true,
          'enableParamLogging' => true
        ),
        'log' => array(
          'class' => 'CLogRouter',
          'routes' => array(
             'db' => array(
             'class' => 'CWebLogRoute',
             'categories' => 'system.db.CDbCommand',
             'showInFireBug' => true //Показывать в FireBug или внизу каждой страницы
           )
        ),
        ...
    )
    
    Теперь в любом месте кода, например в каком-то контроллере нужно указать какой блок кода профилировать. В следующем примере выведутся те запросы которые генерит фреймворк для кода замкнутого в блок профилирования:
       Yii::beginProfile('blockId');
       $users = Users::model()->findAll("id>2");
       Yii::endProfile('blockId');
    

    пятница, 10 июня 2011 г.

    jQuery. Как найти и удалить класс по паттерну

    Постановка задачи: есть элемент страницы у которого есть много классов, необходимо удалить из этого списка классы которые попадают под определенный шаблон. Необходимо удалить те имена классов которые содержать суффикс "-find".

    some content

    Я предлагаю два способа решения задачи: первый способ заключается в том, чтобы получить массив классов, пройти по нему последовательно сравнивая элементы с заданным шаблоном, второй способ заключается в том, чтобы сразу искать совпадения классов шаблонов по строке (если к тегу применяется несколько классов, то они разделяются пробелами)

    Пример 1:
    $.fn.removeClassesByPattern = function(pattern) {
       var el = $(this);
       var items = [];
       var re = new RegExp(pattern);            
       $.each(el.attr('class').split(/\s+/), function(index, item){
         if(re.test(item)){
           items.push(item);
         }
       });
       el.removeClass(items.join(' '));
       return el;
    }
    
    Использование:
    $("#div1").removeClassesByPattern(/-find/);
    

    Пример 2
    $.fn.removeClassesByPattern2 = function(pattern) {
      var el = $(this);
      el.removeClass(function (index, _class) {
        var matches = _class.match (pattern) || [];                
        return (matches.join(' '));
      });
      return el;
    }
    
    Использование:
    $("#div1").removeClassesByPattern2(/\s?(\w+-find)/);
    

    Как видно на примерах - оба способа работают неодинаково. В первом случае мы проводим поиск по именам классов и сравниваем их с шаблоном на предмет соответствия. Второй способ заставляет нас писать шаблон поиска названий классов, таким образом шаблон получился значительно сложнее если сравнивать с примером 1. Но в тоже самое время, второй способ позволяет более гибко находить совпадение (если вы владеете регулярными выражениями в нужной степени).

    Какой способ использовать - зависит от поставленной задачи.

    Примечания:
     -  функция removeClass() принимает либо единичное имя класса, либо список имен разделенных пробелами
    - каждая из функций в конце работы возвращают элемент к которому она применяется. Таким образом, мы можем дальше выполнять цепочку вызовов