Несколько фокусов с CMS Joomla! Единая кнопка «Сохранить изменения» для корзины Интернет-магазина VirtueMart
- Опубликовано: 25.02.2017
- Автогенерация и отображение эскизов фотоальбомов модулем RokBox
- Доработка горизонтального меню-списка для динамического разворачивания подпунктов
- Единая кнопка «Сохранить изменения» для корзины Интернет-магазина VirtueMart
- Изменение/снятие ограничений на длину строки поиска и его попутная доработка
- Исправление ссылки на главную/домашнюю в горизонтальном меню старого стиля
- Модернизация сайтов на Joomla! старых версий 1.5/2.5 до актуальной 3.6
- Отображение заглушки «сайт в разработке» для всех и всего сайта для избранных
- Подсветка пункта меню типа «внешняя ссылка», или Как сделать ссылки на категории VirtueMart
- Преобразование адресов сайта в дружественные (SEF) для внешних нужд
- Реализация двуязычного сайта с постраничным переключением языков
- Удаление значка печати из списка статей при сохранении его на странице статьи
Единая кнопка «Сохранить изменения» для корзины Интернет-магазина VirtueMart
Данный «фокус» стал вторым, связанным с Joomla-компонентом Интернет-магазина VirtueMart, который мне пришлось придумать и применить в том же самом проекте (первым «фокусом» был «Подсветка пункта меню типа «внешняя ссылка», или Как сделать ссылки на категории VirtueMart»).
Обусловлен он такой особенностью VirtueMart, как корзина в виде таблицы со столбцами товара, его количества (поле редактирования) и значков-кнопок «Обновить» и «Удалить» – то есть эти кнопки есть в каждой строке этой таблицы, а не являются общими для всей таблицы и применимыми к отмеченными флажками товарам. Это и показалось неудобным моему заказчику, правда, почему-то применимо только к кнопке «Обновить». Было решено из каждой строки эти кнопки удалить, а вместо этого сделать общую кнопку «Сохранить изменения» для всей таблицы (корзины).
Удивительно, но как будто никому в мире, кроме моего заказчика, такая идея в голову не приходила – Интернет на мои запросы и попытки найти готовое решение практически безмолвствовал. Я нашёл единственное, точнее, пару свежих описаний такой же задачи в единственном месте, но там, к сожалению, были только вопросы-просьбы и ни одного ответа. Пришлось решать задачу самому. Забегая вперёд, могу сказать, что она оказалась непростой, но в то же время интересной – это было моё первое большое столкновение с AJAX'ом.
Собственно, главная трудность и заключалась в том, что корзина (и вообще весь VirtueMart) в этом проекте работала на AJAX'е, то есть динамически, посредством JavaScript, внося изменения в часть кода страниц без их полной перезагрузки. В сложном и запутанном коде VirtueMart (как будто его писа́ли -надцать разных команд разработчиков, не договорившихся об общей архитектуре) мне не удалось найти не только единого метода для сохранения всех изменений в корзине сразу, но даже и метода сохранения изменений конкретной строки (количества конкретного товара) в ней. Также не удалось сделать это «грубо» – посредством прямого изменения сеансового массива корзины $_SESSION["cart"].
Поэтому было решено сделать «хитрую надстройку» над штатной функциональностью: на форме обновления количества конкретного товара кнопку «Обновить» не удалять совсем, а просто скрыть, и по нажатию собственной новой кнопки «Сохранить изменения» в цикле обходить все строки корзины (товары) и для каждого AJAX'ом вызывать метод отправки формы с актуальным количеством товара.
/components/com_virtuemart/themes/<тема>/templates/basket/basket_b2c.html.php
…
<script src="/components/com_virtuemart/themes/…/templates/basket/ajaxsubmit.js"></script>
<script>
function saveCartChanges(saveButton)
{
saveButton.disabled = true;
saveButton.value = 'Сохранение… 0%';
var forms = document.forms;
var formAction = '';
var i = 0;
var percentage = 0;
for (i = 0; i < forms.length; i++)
{
formAction = forms[i].action;
if (formAction.indexOf('//')) formAction = formAction.substr(formAction.indexOf('//') + 2, formAction.length);
if (formAction.indexOf('/')) formAction = formAction.substr(formAction.indexOf('/') + 1, formAction.length);
if ((formAction.substr(0,54) == 'index.php?page=shop.cart&option=com_virtuemart&Itemid=') && (forms[i].name == ''))
{
forms[i].name = 'update';
xmlhttpPost(forms[i].action,'update','','');
forms[i].name = '';
percentage = Math.round((i + 1) / 2 / ((forms.length - 1) / 2) * 100);
saveButton.value = 'Сохранение… '+percentage+'%';
};
};
saveButton.value = 'Сохранить изменения';
saveButton.disabled = false;
};</script>
<table width="100%" cellspacing="0" cellpadding="0" border="0">
<tr align="left" class="sectiontableheader">
…
<th nowrap><?php echo $VM_LANG->_('PHPSHOP_CART_QUANTITY') ?></th>
<th nowrap><?php echo $VM_LANG->_('PHPSHOP_DELETE') ?></th>
…
</tr>
<?php foreach ($product_rows as $product) { ?>
<tr valign="top" class="<?php echo $product['row_color'] ?>">
…
<td><?php echo $product['update_form'] ?></td>
<td><?php echo $product['delete_form'] ?></td>
…
</tr>
<?php } ?>
<tr><td align=right colspan=…><input type=button value="Сохранить изменения" onclick="saveCartChanges(this);"></td></tr>
</table>
…
/components/com_virtuemart/themes/<тема>/templates/basket/ajaxsubmit.js – это чуть-чуть изменённый файл JavaScript-сценария, используемого в очень простом и наглядном примере для новичков “AJAX Form Submit Example” от Simone Rodriguez (большое ему спасибо).
…
self.xmlHttpReq.open ('POST', strURL, false); // false to wait for the response
self.xmlHttpReq.setRequestHeader ('Content-Type', 'application/x-www-form-urlencoded');
self.xmlHttpReq.onreadystatechange = function ()
{
if (self.xmlHttpReq.readyState == 4)
{
// Quando pronta, visualizzo la risposta del form
// updatepage (self.xmlHttpReq.responseText, responsediv);
}
else
{
// In attesa della risposta del form visualizzo il msg di attesa
// updatepage (responsemsg, responsediv);
};
};
…
function saveCartChanges – это основная JavaScript-функция, вызываемая при нажатии на новую кнопку «Сохранить изменения» и последовательно в цикле сохраняющая изменения во всех строках корзины (количестве товаров) посредством отправки изменённой формы $product['update_form'].
/administrator/components/com_virtuemart/html/basket.php
…
<input type="image" name="update" title="'.$VM_LANG->_('PHPSHOP_CART_UPDATE').'" src="'.VM_THEMEURL.'images/update_quantity_cart.png" alt="'.$VM_LANG->_('PHPSHOP_UPDATE').'" align="middle" style="display: none;" />
…