Pull to refresh

Javascript Templater ноль.два

Reading time10 min
Views1.2K
Нашел в закромах свой старый JavaScript шаблонизатор, почитал отзывы в прошлой статье и решил кое-то переделать, изменений не так много, но они вполне существенны, добавил поддержку функций и методов в шаблонах…

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

меньше слов, небольшой пример все прояснит:

<html>
<head>
<script>

// собственно сам шаблонизатор
function Template( template )
{
  var _template  = template.toString();
  // паттерн вырезающий нужные ключи
  var _pattern   = /#\{(.*?)\}/g;
  // паттерн проверки на использование функций
  var _funcPattern = /(\w+)\((.*)\)/;
  // паттерн проверки на использование методов
  var _methodPattern = /(\w+)\.(\w+)\((.*)?\)/;

  
  this.evaluate  = function(object)
  {
    if( !( object instanceof Array ) )
    {
      object = new Array( object );
    }

    var result = [];
    for( var q = 0; q < object.length; q++ )
    {
      var tmpTemplate = _template;
      result.push( tmpTemplate.replace(_pattern, function(match, key)
                  {
                    
                    if( undefined !== object[q][key] )
                    {
                      return object[q][key];
                    }
                    else
                    {
                      if( key.indexOf('.') && ( matches = key.match(_methodPattern) ) )
                      {
                        key = matches[1];
                        func = matches[2];
                        params = matches[3].split(',');
                        
                        if( undefined !== object[q][key] )
                        {
                          return object[q][key][func].apply(object[q][key], params);
                        }
                      }
                      if( key.indexOf('(') && ( matches = key.match(_funcPattern) ) )
                      {
                        func = matches[1];
                        params = matches[2].split(',');
                        var value = null;
                        for(var w = 0; w < params.length; w++)
                        {
                          if( undefined !== object[q][params[w]] )
                          {
                            key = params[w];
                            params[w] = object[q][params[w]];
                            break;
                          }
                        }
                        if( undefined !== object[q][key] )
                        {
                          return window[func].apply(window, params);
                        }
                      }
                    }
                    return '';
                  }) );
    }
    return result.join("\n");
  }
};

// функция для обработки данных,
// обрезает длинные коментарии, и вставляет "..." в конце
function cut(text, count)
{
  if( text.length < count )
  {
    return text;
  }
  return text.substr(0, count) + ' ...'
}

</script>
</head>
<body>

<div id="result">
</div>

<script>

var table = "<table>#{content}</table>";
// шаблон строк с данными
// #{email.replace(@,[dog])} тут применяем стандартный метод строки, просто заменяем @ на [dog]
// #{cut(comment,20)} тут мы применяем описанную выше функцию для обрезки длинных коментариев
var row  = "<tr><td>#{name}</td><td>#{email.replace(@,[dog])}</td><td>#{salary}</td><td>#{cut(comment,20)}</td></tr>";
// принимаемые данные
var data = [
      {name:'John', email:'john@mail.com', salary:1000, comment:'some text'},
      {name:'Tina', email:'tina@mail.com', salary:1300, comment:'some other text'},
      {name:'Megan', email:'megan@mail.com', salary:800, comment:'some comment'},
      {name:'Richi', email:'richi@mail.com', salary:500, comment:'blah blah blah'},
      {name:'Max', email:'max@mail.com', salary:2000, comment:'UFO is goes here'},
      {name:'Leonard', email:'leonard@mail.com', salary:1250, comment:'i saw UFO to'},
      {name:'Kenny', email:'kenny@mail.com', salary:970, comment:'some wery long long long text, it should be cutted'},
      {name:'Martha', email:'martha@mail.com', salary:670, comment:'she is driver'},
      {name:'Arnold', email:'arnold@mail.com', salary:550, comment:'works very bad'},
      {name:'Michael', email:'michael@mail.com', salary:430, comment:'qweqweqwe'}
    ];
// манипуляции с двумя шаблонами (почему два? просто для наглядности работы)
var content = new Template(table);
var rowTemplater = new Template(row);
var rowsResult = rowTemplater.evaluate(data);
var result = content.evaluate( {content:rowsResult} );
// вставляем результат в нужное место
document.getElementById('result').innerHTML = result;
</script>

</body>
</html>


* This source code was highlighted with Source Code Highlighter.


в итоге у нас получается такой результат:

<table>
  <tr>
    <td>John</td>
    <td>john[dog]mail.com</td>
    <td>1000</td>
    <td>some text</td>
  </tr>
  <tr>
    <td>Tina</td>
    <td>tina[dog]mail.com</td>
    <td>1300</td>
    <td>some other text</td>
  </tr>
  <tr>
    <td>Megan</td>
    <td>megan[dog]mail.com</td>
    <td>800</td>
    <td>some comment</td>
  </tr>
  <tr>
    <td>Richi</td>
    <td>richi[dog]mail.com</td>
    <td>500</td>
    <td>blah blah blah</td>
  </tr>
  <tr>
    <td>Max</td>
    <td>max[dog]mail.com</td>
    <td>2000</td>
    <td>UFO is goes here</td>
  </tr>
  <tr>
    <td>Leonard</td>
    <td>leonard[dog]mail.com</td>
    <td>1250</td>
    <td>i saw UFO to</td>
  </tr>
  <tr>
    <td>Kenny</td>
    <td>kenny[dog]mail.com</td>
    <td>970</td>
    <td>some wery long long ...</td>
  </tr>
  <tr>
    <td>Martha</td>
    <td>martha[dog]mail.com</td>
    <td>670</td>
    <td>she is driver</td>
  </tr>
  <tr>
    <td>Arnold</td>
    <td>arnold[dog]mail.com</td>
    <td>550</td>
    <td>works very bad</td>
  </tr>
  <tr>
    <td>Michael</td>
    <td>michael[dog]mail.com</td>
    <td>430</td>
    <td>qweqweqwe</td>
  </tr>
</table>


Заранее отвечу на некоторые вопросы, которые, мне кажется, будут первыми:
Q. почему не сделать функцию вместо обьекта, почему такие дурацкие скобки, почему такой дурацкий метод evaluate?
A. так как задумка не моя, я ее выдрал из библиотеки prototype я попытался оставить все as is, в как можно большей степени, если вам это кажется недостатками, это легко меняется
Q. как со скоростью?
A. со скоростью все в порядке, этот пример выполняется за 2мс (ибо хорошая машина и маленький пример) в общем тупить сильно не будет, регулярки не сложные, выполняться будут вполне сносно
Q. нафига оно надо, у меня вот jQuery/prototype/mootools/yui/etc... и там этот функционал уже есть
A. рад за вас, я не всегда использую jQuery/prototype/mootools/yui/etc... и когда мне понадобился этот функционал я не использовал библиотек никаких, а только ради этого брать библиотеку не собирался
Q. а я вот на сервере обрабатываю шаблоны и передаю уже готовый html, при условии что твои шаблоны передаются тоже (они не создаются на клиенте и должны как-то туда передаться), то загрузка канала будет такая-же, тогда в чем смысл этого всего?
A. смысл в том что сейчас все браузеры поддерживают persistent storage где и можно хранить шаблоны и при переходах на другие страницы грузить только данные

Вот в принципе и все, это далеко не первая моя статья, можете пинать

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

upd тестирвано в фф3.5 опера 10.10 ие8
так как вызовы эмулируются, есть парочка НО:
1. строки не нужно обрамлять ковычками
2. не желательно ставить пробел до/после аргментов

* This source code was highlighted with Source Code Highlighter.

Tags:
Hubs:
Total votes 7: ↑5 and ↓2+3
Comments10

Articles