Как сохранить совместимость при адаптации js шаблона (плагина) к js движка

Зачастую при адаптации шаблонов/плагинов так и тянутся руки поправить js в движке, что чревато потерей совместимости с другими шаблонами и плагинами.

Чтобы разобраться с этим вопросом и с целью самообразования, решил написать этот топик — может кому-то пригодится.

Какие есть варианты:
  1. Редактировать js-файлы прямо в движке
  2. Переписать (переопределить) нужный метод
  3. Использовать хуки js
  4. Использовать options

Я немного запутался с терминами в js, поэтому для начала попытаюсь определится с ними.
Надеюсь, если что-то не так, кто-нибудь поправит.
Возьмем к примеру js движка, обрабатывающий комментарии:
var ls = ls || {};                 // переменная для вызова js-объекта (для удобства определения принадлежности объекта к LS)

ls.comments = (function ($) {      // comments - это ОБЪЕКТ

    this.add = function(...) {     // add - это МЕТОД ОБЪЕКТА
        ...                        // тут ФУНКЦИИ -> МЕТОДА add -> ОБЪЕКТА comments
    };

    this. ...                      // другие методы объекта comments

}).call(ls.comments || {},jQuery); // вызов методов объекта comments

  1. Редактировать js-файлы прямо в движке
    Самый плохой вариант, не гарантируется совместимость.
    Если вы все-же решились на такой вариант, то лучше:
    — скопируйте оригинальный js в папку /skin/skin_name/js и модифицируйте его там
    — перенесите подключение js движка из главного конфига в конфиг шаблона вместо этой строки
    — закомментируйте строку с нужным js, а ниже пропишите путь к этому js в шаблоне
    Этим вы хотя бы сохраните совместимость движка с другими шаблонами. С плагинами возможны конфликты.

  2. Переписать (переопределить) нужный метод
    Например (прописав в js шаблона):
    ls.objectName.methodName = function (param1,...,paramN) {
        ...
    }
    Тоже плохо. Практически = варианту 1, но с небольшими оговорками:
    — совместимость такого шаблона с плагинами под большим вопросом
    — совместимость движка с другими шаблонами сохранится

  3. Использовать хуки js
    Один из немногих источников информации по хукам js — это статья PSNet
    Использование хуков js — самое верное решение! В LS есть два типа использования хуков:

    • Хуки-маркеры (призваны дополнять методы js-объектов LiveStreet)
      Маркер — это некая «помеченная» точка в js движка, при помощи которой можно дополнить какой-либо метод. По факту «помечен» каждый метод js движка, даже если маркера нет.

      Сам маркер (если он есть) выглядит примерно так:
      ls.hook.marker ('hookMarkerName');
      Как правило, такие маркеры есть в функциях сразу после назначения переменных, непосредственно перед выполнением какой-либо логики. Вставить в это место что-свое (в js шаблона) можно примерно так:
      ls.hook.inject (
          [ls.objectName, 'methodName'], // или (ls.objectName.methodName), или 'ls.objectName.methodName'
          function (param1,...,paramN) {
              ...                       // код "инжекта"
          }
          'hookMarkerName'              // название маркера, необязательный параметр
      );
      Параметр с названием маркера можно и не указывать, тогда код вставится в самое начало метода. Т.о. сами маркеры могут и не присутствовать в методе, а дополнить его все равно можно с помощью «инъекции».

    • Хуки (призваны изменять функции внутри методов js-объектов LiveStreet)
      Часто недостаточно дополнить метод, необходимо изменить функцию внутри метода.
      Хуки — это места внутри функций js-объектов движка.

      Выглядят эти «места запуска кода» примерно так:
      ls.hook.run ('ls_hook_name', [param1,...,paramN]);
      Вставить в это место что-то свое можно так (прописав в js шаблона):
      ls.hook.add (
          'ls_hook_name',               // название хука
          function (param1,...,paramN) {
              ...                       // код, вставляемый на место хука
          }
      );

      Стоит обратить внимание, что в отличие от хуков-маркеров, непосредственно хуки неспецифичны к js-объектам.
      Т.е. для вставки кода по хуку достаточно объявить его название и он выполнится там, где хук размещен, независимо от js-объекта.

    Позволю себе немного поразмышлять о хуках js.

    Исходя из вышеописанного у нас есть возможность:
    дополнять методы js-объектов LS
    изменять функции внутри методов js-объектов LS.

    Для полноты красок не хватает возможности заменять функции в методах, по аналогии с блочными хуками в шаблонах {hookb run="hookbName"}...{/hookb}.

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

    Хотя при наличии такой возможности, ее использование будет приравниваться к «более мягкому» переопределению метода (п.2).

  4. Использовать options
    Бывает, что нет возможности использовать хуки — их нет в нужных местах или они не там, где нам нужно )).

    Что делать? Ведь править в движке или переписывать весь метод это плохо.

    Практически в каждом js движка есть т.н. опции (options). Это своего рода переменные, только для всего js-объекта сразу.
    Мое мнение, что когда нет возможности использовать хуки, можно добавить опции без «вреда для здоровья» движка (совместимости).
    Кстати, на мой взгляд, такой способ лишен недостатка возможного дублирования кода при использовании хуков.

    Давайте разберем этот способ на небольшом примере.

    Итак, задача:
    В дереве комментариев заменить иконки сворачивания/разворачивания веток (- и +) на FontAwesome.

    Что по факту:
    — Такие иконки есть у каждого комментария.
    — Если у комментария нет дочерних, то иконка скрывается.
    — Такая проверка (на наличие дочерних комментариев) выполняется перед загрузкой страницы.
    — При сворачивании ветки иконке добавляется класс «свернутости» (folded), а дочерние комментарии скрываются
    — Для класса folded в CSS заданы новые координаты в спрайте

    Выполняем:
    1. Добавим новых опций в comments.js после этой строки:
    folding_folded: 'folded',
    folding_unfolded: ''
    Т.е. сами классы не меняем, просто назначаем им options.

    2. Тут же ниже заменим:
    — класс folded на this.options.classes.folding_folded (строка 353)
    — классы на опции, изменив строки 310-316 на:
    this.expandComment = function(folding) {
        $(folding).removeClass(this.options.classes.folding_folded).addClass(this.options.classes.folding_unfolded).parent().nextAll(".comment-wrapper").show();
    };
    
    this.collapseComment = function(folding) {
        $(folding).addClass(this.options.classes.folding_folded).removeClass(this.options.classes.folding_unfolded).parent().nextAll(".comment-wrapper").hide();
    };

    3. Переопределим классы иконок в js шаблона, добавив выше этой строки:
    ls.comments.options.classes.folding_unfolded = 'fa-minus-square';
    ls.comments.options.classes.folding_folded = 'fa-plus-square';

    4. Заменим иконку в шаблоне на нужную нам:
    <span class="folding fa fa-minus-square text-muted"></span>

    5. Подправим CSS, заменив это на:
    .comment .folding { position: absolute; top: 18px; left: -20px; cursor: pointer; }

    Вот и все!

3 комментария

avatar
Спасибо большое, как раз с этим хотел разбираться, то что надо. Отдельное спасибо за качественное оформление.
avatar
ого спасибо за развернутый материал насущная проблема с дле движком [url=http://www.dle9.com/]www.dle9.com[/url] и адаптация шаблонов
avatar
Мы продаем электронные сигареты, собственноручно проверив их свойства, и знаем в действии эффект. За четыре года etabak.com.ua показал и доказал огромному числу поверивших, что электронная сигарета в Украине будет развиваться, способствовать отказу от обычных сигарет и будет успешно помогать бороться с такими нехорошими привычками, как курение.
Только зарегистрированные и авторизованные пользователи могут оставлять комментарии.