Развитие блога не прекращается ни на минуту (ну почти). На этот раз я сделал meta-теги в заголовке страницы для Facebook. Теперь, если добавить ссылку на мой блог, то в блок в Facebook попадет начало поста. Кстати, совершенно внезапно, вконтактик тоже правильно стал отображать описание, что не может не радовать.
В очередной раз впечатлился выразительностью Хаскеля: cколько всего можно написать одной строчкой. Вот, например, кусочек из свеженаписанного:
getDescription :: Node -> Text
getDescription = maybe emptyDescription
(until (not . T.null) (\_ -> emptyDescription) . getDescription') .
findChild (checkMainDiv . current) . fromNode
getDescription' :: Cursor -> Text
getDescription' = cutDescription . transformDescription .
T.intercalate " " . map nodeText . filter checkParagraph .
maybe [] siblings . firstChild
Можете сравнить с примерной калькой на JavaScript:
var getDescription_ = function (cursor) {
var fc = firstChild(cursor)
return cutDescription(transformDescription(
(fc ? siblings(fc) : []).filter(checkParagraph).map(nodeText).join(" ")
));
}
var getDescription = function (node) {
var mainDiv = findChild(function (cursor) {
return checkMainDiv(current(cursor))
}, fromNode(node));
return mainDiv ? getDescription_(mainDiv) || emptyDescription : emptyDescription;
}
Хотя да, и в JS есть своя прелесть.
Когда я опубликовал предыдущий пост и решил добавить ссылку на него в Google+, я обратил внимание на то, что Google выбирает не тот текст со страницы, который я хотел бы видеть. Ну кому интересно каждый раз смотреть на облако тегов?
В итоге я решил разобраться и попытаться указать гуглу (а может и еще кому) нужный кусок. С гуглом получилось, с другими пока нет. И заодно я поднял целый пласт недостающих знаний по HTML5, а именно Microdata. Я, конечно, не раз встречал это слово в спецификации, но никак не мог сообразить, где именно это может использоваться.
Итак, представляю вашему вниманию HTML Microdata. Эта спецификация отвечает за дополнительную семантическию разметку страницы. Но для начала разберемся, что такое семантическая разметка. Как подсказывает нам википедия, семантика — серия научных дисциплин и концепций о смысловой интерпретации в различных символьных системах. Таким образом, семантическая разметка — это способ придания смысла кускам страницы.
Как вы, должно быть, знаете, в HTML5 появился целый набор специальных тегов для семантичекой разметки. Например, header
пригодится, чтобы объявить кусок страницы заголовком, а article
— статьей, новостью или чем-то подобным. Но что, если нам нужно точнее указывать значение элементов на странице? Например, вот это — имя автора статьи, рядом список ключевых слов, а потом еще какая-то информация, которая к статье относится весьма опосредованно. Зачем? Ну мы-то визуально всё это различим, а вот поисковики и скрипты на всяких сайтах наверняка нет. И вот в этом случае придется иметь дело с Microdata.
По спецификации у нас есть буквально несколько дополнительных атрибутов для тегов — itemscope
, itemtype
и itemprop
. Но сами по себе эти атрибуты никакой семантики не добавляют. Создатели спецификации решили, что не дело им указывать какие типы/значения могут быть у контента. Оно и правильно, пусть другие этим занимаются. Так ведь нашлось кому заняться: в 2011 году Google, Bing и Yahoo объединились, чтобы создать список типов данных на странице, а еще через некоторое время к ним присоединился Яндекс. Так что теперь у нас есть Schema.org, прошу любить и жаловать.
Теперь можно со спокойной душой добавить всякой семантической красоты на свою страницу и наслаждаться жизнью. Практически весь специализированный вывод на страницах результатов поисковиков получается благодаря этой разметке. Скажу честно, это не единственный способ, есть еще microformats, но, по утверждению того же Google, предпочтительно использовать Microdata, т.к. этот формат гораздо более гибкий. Кстати, у Google и Яндекса есть инструменты для тестирования подобной разметки: раз и два.
Ладно, может, это всё и никому не нужная ерунда, но по крайней мере у меня получилось указать Google+, какая именно часть страницы является статьей и что нужно показывать.
А еще хочется бросить камень в огород сказать пару слов по поводу Facebook. Эти ребята решили выделиться: для поддержки Facebook нужно использовать свой формат данных — Open Graph. И использовать его нужно только одним заранее определенным способом: с помощью добавления тегов meta
в заголовок страницы. Придется, видимо, подумать, как это сделать, если я хочу красивое описание у ссылок на мой сайт в Facebook.
Пример использования Microdata можно посмотреть прям тут (Ctrl+U в хроме или Firefox). Вопросы и пожелания — добро пожаловать в комментарии.
Делюсь с вами кусочком из своей практики, который может кому-нибудь пригодиться. Лично я был бы рад найти подобный пост на просторах интернета, когда столкнулся с этой проблемой.
Итак, задача: с помощью XmlHttpRequest получать бинарные данные с сервера. Ну как-то так получилось, что нужно скачивать сжатый с помощью gzip xml-файл с сервера и выбирать из него некоторый набор данных.
Первая важная вещь, которая понадобится, — это метод overrideMimeType
у объекта XMLHttpRequest. Этот метод позволяет переопределить тип получаемых с сервера данных. И даже существует специальная кодировка, которая специально была задумана для приема бинарных данных — x-user-defined
(мы помним, что XMLHttpRequest автоматически преобразует все принятые данные в юникод). Поэтому простое добавление следующей строчки должно сделать большую часть работы.
xhr.overrideMimeType('text/plain; charset=x-user-defined');
Мозг, натренированный jQuery, выдает кусок кода практически сразу:
$.ajax({
url: url,
beforeSend: function(xhr) {
xhr.overrideMimeType(
'text/plain; charset=x-user-defined'
);
},
success: successHandler,
error: errorHandler
});
А вот с Google Closure Library не всё так просто. Там нет никаких beforeSend
, и если посмотреть в документацию, то нужная функция выглядит следующим образом:
goog.net.XhrIo.send(url, opt_callback, opt_method, opt_content, opt_headers, opt_timeoutInterval)
Только один callback, который срабатывает на complete, данные, заголовки, таймаут. Не густо. Но если посмотреть в код этой функции, то можно обнаружить, что на самом деле это прокси для объекта goog.net.XhrIo
. Но goog.net.XhrIo
тоже не конструирует XMLHttpRequest. Вместо этого использует фабрику для создания запросов, что, кстати, логично, но больше Java-way чем JS-way. Ну да ладно. Получается, чтобы вклинить вызов overrideMimeType
, нужно сделать свою фабрику с блекджеком, например, вот так:
my.net.BinaryXmlHttpFactory = function () {
goog.base(this);
};
goog.inherits(my.net.BinaryXmlHttpFactory, goog.net.DefaultXmlHttpFactory);
my.net.BinaryXmlHttpFactory.prototype.createInstance = function () {
var xhr = goog.base(this, "createInstance");
xhr.overrideMimeType('text/plain; charset=x-user-defined');
return xhr;
};
Теперь дело осталось за малым: инициализировать goog.net.XhrIo
c новой фабрикой и выполнить запрос:
var xhrIo = new goog.net.XhrIo(new my.net.BinaryXmlHttpFactory());
goog.events.listen(xhrIo, goog.net.EventType.SUCCESS, successHandler);
goog.events.listen(xhrIo, [goog.net.EventType.ERROR, goog.net.EventType.ABORT], errorHandler);
xhrIo.send(url);
Вот и всё. Сразу оговорюсь, что всё это не будет работать в Internet Explorer, т.к. там нужна своя особая магия для получения бинарных данных, в отличие от остальных, где остаток действий выглядит довольно просто:
var res = '';
for (var i = 0; i < data.length; ++i) {
var code = data.charCodeAt(i);
res += String.fromCharCode(code & 0xff);
}
Надеюсь, что кому-то этот пост поможет и направит мысли в правильную сторону.
Сегодня я обратил внимание на такую конструкцию в JavaScript: void 0
. И вдруг понял, что я не знаю, для чего на самом деле нужно слово void
. То, что void 0
используется как эквивалент undefined
, я догадывался, но не более. Так вот, раскрываю всем (и в том числе себе) глаза. Оператор void
используется для изменения результата любого выражения на undefined
. Как-то так получилось, что сейчас применений для этого слова почти не осталось, кроме сокращения записи undefined на целых 3 байта. Хотя на MDN написано, что void
может использоваться в URI-схеме 'javascript:
', чтобы избежать замены станицы результатом выполнения этого выражения. Да, так и есть. Проверил: если сделать ссылку <a href=”javascript: ‘Hello world’”>Click!</a>
, то после нажатия на нее, вся страница будет заменена на «Hello world». Но не во всех браузерах: Chrome выпилил этот пережиток прошлого из своих исходников, так что полагаться на эту возможность нельзя.
Вот и получаем в итоге два практически бесполезных куска знаний: void
и принцип работы схемы javascript:
.
Как вы, может быть, заметили (или же поднимите глаза вверх и увидите прямо сейчас), на сайте появился новый раздел «Фильмы». По большей части он выполняет информационную функцию: список просмотренных мною фильмов и моя оценка по десятибалльной шкале, как на IMDb.
Может, этот список поможет кому-нибудь определиться с фильмом, который стоит глянуть, ну или хотя бы порадует глаз красивыми постерами. Смотрите, изучайте, оставляйте комментарии.
Пара слов о реализации. Я уже как-то упоминал, что практически вся информация в блоге предcтавлена в виде markdown, и этот раздел не исключение. В админке я задаю простой ненумерованный список, который уже после загрузки страницы с помощью JavaScript преобразуется в то, что хочется увидеть. Получается так называемый graceful degradation, и страница выглядит вполне адекватно в своем первоначальном виде. Таким образом, те, у кого JavaScript напрочь отсутствует, не увидят абракадабру. Сама идея верстки этого раздела была позаимствована у Сергея Чикуёнка. Этот способ позволяет мне рисовать переменное количество блоков в строке в зависимости от ширины экрана — вроде как таблица, только лучше. Главная идея этого способа в том, чтобы элементам проставить display: inline-block
, и затем расположить их относительно строки вверху (vertical-align: top
) и внизу (vertical-align: bottom
).
UPD: Пост устарел.