наверное, вначале стоит пояснить, что такое PubSubHubbub. Эта технология была придумана недавно как замена веб-пингам, позволяющим оповестить всех заинтересованных, что у вас в блоге появилась новая запись. Для этого при добавлении записи нужно было отправить http-запрос на один или несколько специализированных серверов, которые дальше сами рассылали уведомления всем подписавшимся. PubSubHubbub развивает эту идею дальше, добавляя в этот запрос само содержимое поста, так что заинтересованные сайты не ломятся все сразу в ваш блог, чтобы скачать фид и вынуть из него новый текст. Однако для большего нашего удобства работает и старый механизм: достаточно «пингануть» подходящий сервер, и он сам скачает фид, извлечёт из него пост, и разошлёт его подписчикам
кратко процесс можно описать так:
вы добавляете запись
ваш блог отправляет серверу сообщение «в таком-то фиде новое содержимое»
сервер скачивает фид и находит в нём новый пост
сервер отправляет всем подписанным на обновления этого фида новый пост
итак, что нужно сделать для подключения вашего блога на django к этой радости? Во-первых, выбрать PubSubHubbub-сервер. Я сам пока знаю только один: http://pubsubhubbub.appspot.com/. Пропишем его в настройках (settings.py):
после этого нужно в методе сохранения записи (тут я не могу давать конкретику, потому что не знаю внутренностей вашего блога) добавить собственно отправку оповещения:
from pubsubhubbub_publish import publish
publish(settings.PUSH_URL, u'http://your.blog/feed.url')
но это самый простой вариант, мне хочется оповещать ещё и об обновлениях в фидах тегов:
from pubsubhubbub_publish import publish
from django.core.urlresolvers import reverse as reverse
params = [settings.PUSH_URL, u'http://your.blog/feed.url']
params.extend(map(lambda tag: 'http://your.blog%s' % (reverse('tag_feed', args=[tag])), tags))
publish(*params)
теперь остался последний шаг: нужно добавить в сам фид информацию о том, за ним можно следить при помощи PuSH. Вообще-то это должно делаться очень просто — добавлением в него вот такой строчки:
но в django для фидов используется навороченный Syndication Framework, поэтому придётся унаследоваться от стандартного класса отрисовки фида Atom1Feed и добавить строчку вот таким образом:
после этого в определениях классов фидов нужно заменить feed_type = Atom1Feed на feed_type = PubSubHubbubEnabledFeed
всё, добавление PuSH завершено! Пройдёт некоторое время, пока заинтересованные сайты узнают, что ваши фиды транслируют обновления таким способом, и после этого новые записи будут появляться на них практически моментально
ну а если вам хочется свести код минимуму, то наверное link можно прописать в фиде вручную, и вместо вызова метода publish просто отправлять на сервер запрос с параметрами hub.mode=publish&hub.url=yourfeedurls
я уже писал о том, что в опере код user javascript может быть исполнен в разное время в зависимости от расширения файла. Впрочем, многим скриптам нужно запускаться только тогда, когда весь DOM уже загружен. С привязкой к событиям load и DOMContentLoaded у меня не всегда всё было гладко (как выяснилось, из-за глупых опечаток), поэтому сейчас мне захотелось досконально разобраться, какой из вариантов привязки лучше всего использовать.
итак, я быстро набросал простенький html и два почти идентичных скрипта: test.js и test.user.js, отличающихся только расширением и строчкой идентификации внутри. В пустом профиле оперы я положил скрипты в папку userjs, и открыл сам документ. Вот что появилось после этого в консоли:
test.js: start
html: end of head
html: end of body
test.js: document.DOMContentLoaded (capture)
test.js: document.DOMContentLoaded
test.js: window.DOMContentLoaded (capture)
test.js: window.DOMContentLoaded
test.user.js: start
test.js: document.load (capture)
test.js: document.load
html: document.onload
test.user.js: document.load (capture)
test.user.js: document.load
test.js: window.load (capture)
test.js: window.load
html: body.onload
test.user.js: window.load (capture)
test.user.js: window.load
какие из этого можно сделать выводы?
нет смысла использовать window.opera.addEventListener для таких событий: ни один из вариантов с ним не сработал
как и было заявлено, родной опере формат .js (в отличие от «приблудного» от greasemonkey .user.js) исполняется до начала парсинга документа и, соответственно, до события DOMContentLoaded. Поэтому в скриптах лучше всего использовать вызов document.addEventListener('DOMContentLoaded', handler, true), не забывая про последний параметр, как нередко делал я : )
код из файлов .user.js исполняется до события load на документе, поэтому в них можно использовать document.addEventListener('load', …), но наверняка можно обойтись и без него
подозреваю, что порядок событий load, назначенных разными способами, представляет интерес только для разработчиков браузеров, вынужденных трудиться над совместимостью. Кое-что в нём логично, что-то удивительно (например, body.onload идёт после document.load и даже window.load). Впрочем, теоретически это исследование может помочь несчастному, занимающемуся поддержкой кривого кода, но мне хочется верить, что проблем с этим ни у кого не возникнет : )
в prototype.js используется не совсем очевидный способ работы с исключениями, возникающими при обработке аякс-запросов: по умолчанию они подавляются и не попадают в консоль ошибок вообще. Чтобы их видеть, нужно добавлять в параметры запросов
onException: function logException(request, exception) {
// handle exception
}
Однако при этом может возникнуть коллизия с другой фичей фреймворка: автоматическим исполнением пришедшего с сервера яваскрипта. По умолчанию установлено evalJS: true, и если в заголовках обнаружится что-то вроде Content-Type: text/javascript, прототайп попробует исполнить тело ответа как код, словит исключение, и передаст его в onException.
бороться с этим явлением можно двумя способами: либо добавлять в параметры каждого аякс-запроса evalJS: false, либо отдавать json с Content-Type: application/json. Первый способ просто непрактичен — некрасиво и где-нибудь наверняка забудется. Второй иногда невозможен…
недавно обнаружил довольно интересную надстройку над CSS, добавляющую в синтаксис много вкусностей. Как следует из заголовка, называется она SASS, или syntactically awesome stylesheets, и представляет собой маленькую программу на руби.
за примерам сахара лучше идти на сайт, но я их коротко перечислю:
переменные
параметризованные функции
вложенные стили
автоматическая сборка из модулей с минимизацией
и прочее : )
поскольку CSS — декларативный язык, такие инструменты для него подходят очень хорошо
несколько месяцев назад я писал, как можно делать аддоны для оперы. К сожалению, тогда выводы были неутешительны. Но с тех пор появилась Opera Unite, в которой эти проблемы были решены, и теперь мы можем полноценно работать с файлами на диске!
встречайте: UJS Manager service. Он работает таким образом: вы устанавливаете в свою Opera Unite новый сервис, которому даёте доступ к папке юзерскриптов, а веб-интерфейс этого сервиса переносите на сайдбар оперы — и вуаля! У вас есть панель управления юзерскриптами прямо в интерфейсе!
сейчас сервис может ещё не очень многое, хотя одна киллер-фича у него есть: установка нового скрипта одним кликом! Окрываете скрипт в браузере, и вверху страницы появляется сообщение «UJS Manager detected script file. It can be installed as a user script.» с кнопкой «Install User Script».
хочу сотрудничать с автором, и добавить менеджеру некоторые другие фичи, типа блокирования скрипта на определённом сайте и редактирования его прямо в браузере
заодно можно нечто подобное соорудить для пользовательских стилей