Как один мужик Calendar Widget починял

Те, кто программировал календарь для показа на вебе (и вообще в программах) знает, какая это мучительная задача. Тут и високосные годы и заполненные/не заполненные недели и много всего разного.

В то же время, иметь календарик в блоге — приятно, особенно если он не сильно пустой. По счастью, авторы Movable Type дают готовый Calendar Widget, который даже работает. И я даже им долгое время пользовался, но полного счастья не было:

  • Календарик - одинаковый на всех страницах. Включая, например, архив за ноябрь прошлого года. Хотя разумнее в архиве за прошлые месяцы показывать календарь за эти месяцы.
  • А если быть точным, то календарик на странице отвечает моменту ее генерации. Для архива за прошлый месяц - это будет дата последней записи за тот месяц, другими словами там будет правильный календарь пока вы не перегенерируете страницу.
Одним словом, бардак. Впрочем, есть средства его починить, но сначала нужно поставить задачу.

Требования к календарю

Календарь должен висеть ровно, а то "неаккуратненько". Требований набралось много:
  • За какую дату показывать календарь ? Ну, очевидно, за разную для разных типов страниц:
    1. Главная страница: календарь за месяц, когда была сделана последняя опубликованная запись.
    2. Архивы по рубрикам, авторам и прочие архивы без привязки к дате: календарь за месяц последней записи.
    3. Архивы по дате (месяц, неделя, день): календарь за тот месяц, который описывает архив (для недельного архива возможны разночтения, впрочем недельными архивами я не пользуюсь).
    4. Отдельная запись: календарь за тот месяц, которым датирована запись.
  • Ссылки с дней календаря должны вести на:
    • конкретную запись, если запись за это число одна;
    • список записей за этот день, если записей больше одной.
  • В заголовке календаря хочется иметь навигацию на следующий-предыдущий месяц, естественно если в эти месяцы были записи. Идеально, конечно, перескакивать через пустые месяцы.

Стандартный Calendar Widget ни одному из этих требований не удовлетворяет. Будем его чинить.

Попытка 1: только встроенные средства

Сначала читаем документацию:
month - An optional attribute that specifies the calendar month and year the tagset is to generate. The value must be in YYYYMM format. The month attribute also recognizes two special values. Given a value of "last," the calendar will be generated for the previous month from the current date. Using a value of "this" will generate a calendar for the current month.

The default behavior is to generate a monthly calendar based on the archive in context. When used in the context of an archive type other then "Category," the calendar will be generated for the month in which the archive falls.

Чешем репу. Зачем, казалось бы, нужен month="this" если это 'default behavior' ?
Эксперименты показали, впрочем, что разработчики придумали это не зря, а вот авторы документации явно не понимали о чем пишут:

  • <Calendar month="this"> в контексте архива генерирует календарь для месяца, за который архив, а во всех остальных контекстах производит ошибку.
  • Просто <Calendar"> во всех контекстах генерирует календарь за текущий месяц.
Таким образом, нам нужен довольно развесистый MTIf, зависящий от типа архива и включающий в себя весь календарный блок. Немного Cut-and-paste и готово.

Требование о ссылке с даты в разные места удовлетворяется легко, если в счетчике записей для архива больше чем 1, то делаем ссылку на суточный архив, в противном случае - на запись.

С навигацией в случае архива все элементарно, есть готовые блоки MTArchiveNext/MTArchivePrevious, для главной страницы приходится немножко извернуться с циклом.

Результат этих упражнений можно скачать тут:

widget-calendar.mtml
, насколько я способен сообразить, это максимум, который можно сделать стандартными средствами MT4.x

Остались невыполнеными несколько существенных требований:

  • Календарь в индивидуальной записи будет иметь время генерации файла. Т.е. последнего комментария или перегенерации всего блога. То же относится, собственно, ко всем страницам кроме архива по дате. Неаккуратненько.
  • В ряде случаев мы будем иметь пустой календарь, ни одна из дат никуда не ссылается. Особенно легко получить такое на динамических страницах в первых числах месяца.
В обоих случаях это одна и та же проблема: нам нужно сгенерировать календарь за конкретную дату (данной записи или последней записи блога) и у нас даже есть для этого метод: <Calendar month="YYYYMM">.... но в качестве значения атрибута в MT можно подставить только константу, вставить туда вызов MTGetVar или чего-то подобного не получится.

Попытка 2: использование MTTagInvoke

Понятно, что я не первый, кто столкнулся с проблемой подстановки динамических значений в атрибуты тегов MT. И лечение уже существует, это плагин MTTagInvoke. Несмотря на зубодробительный синтаксис, задачу динамической подстановки плагин решает. А дальше мы решаем две оставшиеся задачки:
  • Вызываем Calendar с динамической подстановкой месяца.
  • Ищем текущий месяц записи и находим ссылки на предыдущий-следующий месяцы.

Результат моих упражнений можно скачать отсюда:

widget-calendar-super.mtml
.

Использование:

  1. Поставить MTTagInvoke.
  2. Зайти в Design->Templates->Widgets->Calendar, убрать старый темплейт и вставить мой.
  3. Использовать Calendar Widget в Widget sets.
Прочие особенности:
  • Рассчитано на темплейты от Movable Type 4
  • Названия дней недели переведены на русский.
  • Подразумевается, что Daily Archives создаются, проверка на это не делается.
Новый прекрасный календарь вы можете лицезреть на этом сайте.

Comments

Мне казалось я где-то у тебя, то ли тут, то ли в ЖЖ видел упоминание, что при каких то условиях можно получить enterprise лицензию на MT на 3 что ли пользователя бесплатно. Не подскажешь где? Или я что-то путаю?

И еще - у меня два блога на одной инсталляции MT (бесплатная 4.01) версия. Каждой в шаблоны забил этот твой виджет, так такое впечатление что при репаблише сразу обоих блогов в один попадает календарь из второго, не сталкивался?

А зачем enterprise ? Чем текущая нехороша ?

Проблем с репаблишем не видел, тестировался на нескольких блогах (был тестовый, внутри боевого)

Вот кстати, реплай я писал вроде к твоему ответу, а "подвесился" он к моему ...

А, понятно, предварительный просмотр "виноват", в нем нет даже поля "In reply" ...

Я тут вернулся к этой теме ... Вобщем у меня все стало нормально, после того как я заменил просто "/" на <$mt:BlogArchiveURL$> в том месте, где делается ссылка на день (т.е. больше одного поста в сутки).

Гы. "потерялся" таг ... Там было "заменил "/" на ArchieveBlogUrl.

А как в бесплатной версии включить Daily-Archive? :) Либо я тормоз, либо оно разрешено только в enterprise. Не, можно попробовать и хакнуть, но некрасиво как-то ...

А вот у меня почему-то вот такая фигня ... "Будем искать" (с) Хотя, сейчас вроде бы нормально отрисовался, правда в этот раз я сильно по-отдельности блоги репаблишил (в офлайне) ...

Да, а то сразу забыл (:) - спасибо тебе за виджет. Я только его слегка "прилизал", а то у меня все как-то цифири "разбегались" - убрал &nbsp вокруг названий дней недели, а табличке поставил style="text-align:center;border-spacing:4px;"

Да так и включить:
Templates - Archive Templates - Entry Listing - создать daily mapping

У меня же включено, а версия - обычная бесплатная (даже не релиз, а rc2, лень переставлять).

Превьюху - починю, если не забуду