С выходом нового шаблона компонента sale.order.ajax на форумах битрикса разгораются возмущения и недомения. Мол, теперь код всего шаблона на JavaScript и как его кастомизировать непонятно. На самом деле да, код js-скрипта составляет почти семь тысяч строк. Сходу в таком количестве кода, даже хорошо написанного (к сожалению, битрикс этим не балует), соблюдая паттерны программирования, будет непросто.

В этой заметке я покажу способ, как можно кастомизировать основной скрипт логики шаблона оформления заказа (order_ajax.js), не прибегая к его правке. Что нам это даёт? Когда прилетят очередные обновления шаблона, мы просто заменим его и всё. Все наши кастомизации будут работать (в теории).

Итак, поехали!

Кастомизировать будем так, чтобы в оформлении осталось только 2 блока (блока с вводом данных покупателя, а так же выводом самой корзины), вместо 6. Если у нас интернет-магазин маленький, то задача вполне себе реальная.

Чтобы получилось примерно так:

1C-Битрикс. Кастомизация нового шаблона компонента sale.order.ajax


1C-Битрикс. Кастомизация нового шаблона компонента sale.order.ajax

Все махинации сводятся к расширению BX.Sale.OrderAjaxComponent. Ну как, к расширению.. Полноценным расширением это сложно назвать. Так как битрикс в разработке шаблонов (и не только), практически не ориентируется на расширение этих шаблонов своими партнёрами, то нам приходится выкручивать себе яйца и изобретать костыли. По другому это не назвать. Вот зачем нужно было писать объект BX.Sale.OrderAjaxComponent без прототипа?

Ладно, ближе к делу :)


Кастомизируем

Создаём файл order_ajax_ext.js в папке с шаблоном компонента sale.order.ajax (там же, где лежит файл order_ajax.js) с содержимым:

(function () {
    'use strict'; 
 
    var initParent = BX.Sale.OrderAjaxComponent.init,
        getBlockFooterParent = BX.Sale.OrderAjaxComponent.getBlockFooter,
        editOrderParent = BX.Sale.OrderAjaxComponent.editOrder
        ;
 
    BX.namespace('BX.Sale.OrderAjaxComponentExt');    
 
    BX.Sale.OrderAjaxComponentExt = BX.Sale.OrderAjaxComponent;
 
    BX.Sale.OrderAjaxComponentExt.init = function (parameters) {
        initParent.apply(this, arguments);
 
        var editSteps = this.orderBlockNode.querySelectorAll('.bx-soa-editstep'), i;
        for (i in editSteps) {
            if (editSteps.hasOwnProperty(i)) {
                BX.remove(editSteps[i]);
            }
        }
 
    };
 
    BX.Sale.OrderAjaxComponentExt.getBlockFooter = function (node) {
        var parentNodeSection = BX.findParent(node, {className: 'bx-soa-section'});
 
        getBlockFooterParent.apply(this, arguments);
 
        if (/bx-soa-auth|bx-soa-properties|bx-soa-basket/.test(parentNodeSection.id)) {
            BX.remove(parentNodeSection.querySelector('.pull-left'));
            BX.remove(parentNodeSection.querySelector('.pull-right'));
        }
 
    };
 
 
    BX.Sale.OrderAjaxComponentExt.editOrder = function (section) {
 
        editOrderParent.apply(this, arguments);
 
        var sections = this.orderBlockNode.querySelectorAll('.bx-soa-section.bx-active'), i;
 
        for (i in sections) {
            if (sections.hasOwnProperty(i)) {
                if (!(/bx-soa-auth|bx-soa-properties|bx-soa-basket/.test(sections[i].id))) {
                    sections[i].classList.add('bx-soa-section-hide');
                }
            }
        }
 
        this.show(BX('bx-soa-properties'));
 
        this.editActiveBasketBlock(true);
 
        this.alignBasketColumns();
 
        if (!this.result.IS_AUTHORIZED) {
            this.switchOrderSaveButtons(true);
        }
 
    };
 
 
    BX.Sale.OrderAjaxComponentExt.initFirstSection = function (parameters) {
 
    };
 
 
})();

Подробнее, что происходит

В отдельных переменных определяем функции-методы родительского BX.Sale.OrderAjaxComponent, чтобы их можно было вызвать в дочерних функциях и не получить ошибку Maximum call stack size exceeded.

Копируем ссылку с BX.Sale.OrderAjaxComponent в BX.Sale.OrderAjaxComponentExt.

В методе BX.Sale.OrderAjaxComponentExt.init вызываем родительский init, следом прибиваем ссылки «изменить» у всех блоков. Они нам не нужны.

В методе BX.Sale.OrderAjaxComponentExt.getBlockFooter прибиваем кнопки «Назад» и «Вперед» у блоков. Они нам тоже не понадобятся — все блоки у нас развёрнуты.

В методе BX.Sale.OrderAjaxComponentExt.editOrder ненужным блокам-секциям добавляем css-класс bx-soa-section-hide. По нему мы и будем скрывать ненужные блоки. А так же в этом методе раскрываем только нужные нам блоки: «Покупатель» и «Товары в заказе».

Метод BX.Sale.OrderAjaxComponentExt.initFirstSection оставляем просто пустым. Если этого не сделать, то у анонимов при попытке оформления будет вываливаться эксепшен, по поводу отсутствия необходимых обязательных полей.

Идем дальше.


Правки шаблона: подключаем наш скрипт и меняем вызов BX.Sale.OrderAjaxComponent на свой

В файле template.php нашего шаблона нового оформления добавляем подключение нашего скрипта order_ajax_ext.js:

После строчки:

$this->addExternalJs($templateFolder.'/order_ajax.js');

добавляем:

$this->addExternalJs($templateFolder.'/order_ajax_ext.js');

А так же в файле template.php меняем все вызовы BX.Sale.OrderAjaxComponent на BX.Sale.OrderAjaxComponentExt


Правки CSS

Ну и не забываем добавить в файл стилей, чтобы ненужные блоки скрылись:

.bx-soa-section-hide {
    display: none;
}

На этом всё. Всегда старайтесь подходить к задачам творчески :-)