Программирование
Упрощенная корзина для Drupal Commerce
Некоторых по вполне логичным причинам не устраивает стандартный блок корзины в Drupal Commerce. Хочется не выводить все понапиханные в нее товары, а вывести только, скажем, одну строку. В которой должно быть только число товаров в корзине и сумма, на которую набрано. Ну и ссылки на саму корзину и оформление товара.
Вот php-код с реализацией такой укороченной корзины. Его надо вставить в блок.
global $user;
$order = commerce_cart_order_load($user->uid);
if (empty($order) || empty($order->commerce_line_items)) {
print t('Your shopping cart is empty.');
return;
}
$wrapper = entity_metadata_wrapper('commerce_order', $order);
$line_items = $wrapper->commerce_line_items;
$total = commerce_line_items_total($line_items);
$quantity = commerce_line_items_quantity($line_items, commerce_product_line_item_types());
?>
<p>
<?php
print t('Your shopping cart contains <span class="shopping-cart-items-count">!items</span> on <span class="shopping-cart-money-total">!money</span> total', array('!items' => format_plural($quantity, '1 product', '@count products'), '!money' => commerce_currency_format($total['amount'], $total['currency_code'])));
?>
</p>
<p>
<?php
print l(t('Cart'), 'cart') . ' ' . l(t('Checkout'), 'checkout');
?>
</p>
Обращаю внимание — число товаров в корзине переведено правильным, годным образом, через
format_plural(). HTML-разметку блока можно менять как нравится.
А о том, как обновлять этот новый блок по AJAX-у — напишу позже.
Управляем заголовками вкладок
В декабре рассказывал о том, как распихать поля, отображаемые в нодах, по красивым вкладкам с помощью модуля Field Group. В одной из вкладок были, в частности, размещены комментарии к ноде и форма добавления новых комментариев.
А теперь возникла нужда управлять заголовком вкладки, в зависимости от наличия комментариев к ноде. Делается это так:
* Implements hook_field_group_pre_render_alter().
*
* @param Array $elements by address.
* @param Object $group The Field group info.
*/
function mymodule_field_group_pre_render_alter(& $element, $group, & $form) {
if ($element['#title'] == 'Comments') {
$node = $element['comments']['#node'];
if ($node->comment_count == 0) {
$element['#title'] = t('Be first to leave a comment!');
} else {
$element['#title'] = t('Comments (!count)', array('!count' => $node->comment_count));
}
}
}
Аналогичным образом можно управлять заголовками любых других вкладок или иных видов групп полей Field Group.
Решение, кстати, дополнительно ценно тем, что благодаря великолепной документированности opensource-проектов потратил на написание этих десяти строчек — несколько часов.
Drupal 7 и jQuery.once()
Некоторое время назад писал про Drupal.behaviors и jQuery в «шестерке». Там, как мы помним, чтобы одни и те же действия не выполнялись над элементами многократно, нужно было использовать контекст, а также присваивать и проверять наличие спец. класса. В общем, вот так:
$('.module-class-object:not(.module-class-processed)', context).each(function () {
$(this).addClass('module-class-processed');
// Do things
});
};
Как нетрудно догадаться, для каждого нового «поведения» этот код надо копировать (что не очень хорошо).
В Drupal 7, однако, стало гораздо удобнее: в него интегрирована новая функция jQuery — once(). Она умеет присваивать спец. классы и проверять их наличие сама. Вот так:
Drupal.behaviors.myBehavior = {
attach: function (context, settings) {
$('div.my_behavior').once(function () {
//этот код выполнится только раз для каждого div.my_behavior, независимо от числа запусков Drupal.attachBehaviors()
});
}
};
}
Прогресс, как говорится, налицо.
Единственный недостаток (если это можно считать недостатком) once() — объекту, возвращаемому селектором $(...), должно быть можно присвоить CSS-класс. То есть запись $(document).once(...) результатов не даст. А вот запись $('body').once(...) — даст.
Порт модуля user titles
Сегодня закончил порт модуля user titles в Drupal 7. По факту — добавил результат в соответствующий issue на drupal.org.
Порту подвергся основной модуль, без контрибов. Впрочем, контрибы там меньше чем по 1КБ каждый, так что если будет желание — проблем возникнуть не должно. Также не тестировал работу тайтлов-изображений (они мне сейчас просто не нужны), но код также портирован, так что если какие проблемы с картинками будут — пишите, посмотрю.
В остальном же модуль работает, титулы показывает. Выкладываю, естественно, в dev-версии, поскольку кроме меня его еще никто не тестировал. Да и вообще, надеюсь что релиз сделает уже изначальный разработчик модуля, а не я.
В процессе портирования, кстати, посчастливилось поработать с новомодным DB API. API прекрасен, одна строчка SQL-запроса средней сложности превращается в десять строчек нового кода. Правда, более понятного, да.
Файл с модулем добавлен к заметке, качайте, пользуйтесь на здоровье.
Ссылку на основного спонсора порта добавлю сюда позже, когда проект будет открыт.
upd: архив с модулем обновлен. Изменения:
— исправлен небольшой баг в hook_user_view();
— админка модуля перенесена в Configuration→People;
— добавлен порт контриб-модуля ut_userpoints (то есть интеграция с модулем userpoints) за авторством boran.
Про браузеры, файлы, безопасность и JavaScript
В современных браузерах, безусловно, очень много внимания разработчики уделяют безопасности. Настолько много, что иногда ум за разум заходит.
Так, например, есть известный элемент HTML <input type="file" />, предназначенный для открытия пользователем файла у себя в компьютере, предположительно — для последующей его отправки на сервер. Когда пользователь нажимает кнопочку Browse и выбирает в стандартном диалоге операционной системы нужный файл — полный путь к нему немедленно появляется в поле слева от кнопочки. Однако если мы вдруг захотим обратиться к полю input с целью получить этот самый полный путь через JavaScript, система безопасности современного браузера тут же покажет нам современную фигу. И вместо полного пути возвратит только имя файла.
А я вот хочу чтоб в браузере пользователь мог проигрывать локальные видео-файлы. И для выбора проигрываемого файла отлично подходит диалог из элемента input. Но нет — тут, оказывается, дыра в безопасности, дескать, я так по полному пути могу делать всякое нехорошее с файлами и директориями. Правда, при этом я могу создать обычный текстбокс <input type="text" /> и попросить пользователя ввести полный путь к файлу туда. Причем, причин вводить путь к файлу у пользователя будет столько же, сколько выбирать его в диалоге. Разве что это гораздо неудобнее выбора файла в диалоге. А делать с файлом всякое я смогу все равно (кроме, пожалуй, его загрузки на сервер).
В интернетах тут и там встречаются всякие хитрые хаки и читы, помогающие вытащить-таки из файлового диалога полный путь к выбранному файлу. Однако они а) разные для разных браузеров; б) хаки и читы — то есть, быстро закрываются разработчиками браузеров.
Через это вопрос к общественности: знает ли кто какой-нибудь плагинчик jQuery или иное средство для вызова системного диалога «Открыть файл» без использования <input type="file" />, но с возможностью получения полного пути к выбранному файлу? Поделитесь, а.
Также подойдет возможность увязать <input type="file" /> с объектом на странице, чтобы, типа, они сами, без меня, «безопасно» путями обменивались. Но это наверно из разряда фантастики.
Снова про звук, Linux, Qt и на этот раз — Phonon
Вообще, я ОС Линукс люблю и по возможности работаю именно в нем (но пропагандой пингвинов обычно не занимаюсь). И KDE люблю тоже. Но есть во всей этой кухне одна особенность, которая бесила меня всегда до мозга костей.
Вот, например, в ОС Windows можно было одновременно слушать музыку и, скажем, играть в игры — то есть, воспроизводить звук из разных источников параллельно — очень-очень давно. Десять лет точно. И дело не в том, что в Луниксе — нельзя. Можно, конечно. Но как-то так сложилось, что звуковая система в нем лицом повернута к самому Луниксу. А к пользователю — тем, что с оборотной стороны лица находится. Со всеми этими фронтэндами, бэкэндами, промежуточными демонами, альсами, оссами, пульсаудио, консольными плеерами и звуковыми библиотеками, разработчики пускаются во все все тяжкие, но годы проходят, а свести все это к приличному виду, чтоб хотя бы из коробки работало без конфликтов, — не получается.
Работа с потоками в Qt
Обнаружил добротную и длинную статью в двух частях о работе с потоками и параллельном программировании в Qt:
Легкость создания и запуска потоков в Qt, в сочетании с некоторым незнанием стилей программирования (особенно асинхронного сетевого программирования, в сочетании с концепцией сигналов и слотов в Qt) и/или привычками, приобретенными во время использования других инструментариев или языков, обычно приводят к тому, что люди стреляют себе в ногу. Кроме того, поддержка потоков в Qt – это палка о двух концах: когда создание многопоточных приложений для вас становится очень простым, в это же момент добавляется определенное количество особенностей (особенно когда дело доходит до взаимодействия с QObject), о которых вы должны знать.
Целью данного документа не является научить вас использовать потоки, делать правильную блокировку, использовать параллельность и писать масштабируемые программы. Вместо этого, эта небольшая статья введет пользователей в курс многопоточности в Qt 4, для того чтобы избежать наиболее распространенных ошибок и помочь им разрабатывать код, одновременно и более надежный, и имеющий лучшую структуру.
Потоки, cобытия и объекты QObject (Часть 1)
Потоки, cобытия и объекты QObject (Часть 2)
Толково.
Про защищенные веб-приложения
Если кто еще не видел, вот толковая заметка с дюжиной фундаментальных советов на тему безопасности веб-приложений. Там и про SQL Injection, и про XSS, и про CSRF, и про всякое другое.
12 навыков создания защищенных веб-приложений
Полезно, в чем-то познавательно.
- ‹ следующие заметки
- архив за год
- предыдущие заметки ›