Краудсорсинг
14 июня 2011

Отключаем библиотеку jQuery, встроенную в движок MediaWiki 1.16.x, и заменяем её на свежую, обновляемую и пополняемую администраторами вики

Tutorial


Как нетрудно прочесть на сайте MediaWiki, нынешняя линейка стабильных версий (1.16.x) поставляется со встроенною библиотекою jQuery, код которой лежит по адресу «skins/common/jquery.min.js». Это jQuery сравнительно старой версии (1.3.2, вышедшая в феврале 2009 года), слегка запатченная для преодоления одного из её багов, и она запускается в режиме совместимости noConflict()») таким образом, чтобы поместиться в переменную $j вместо $. Этот код jQuery не содержит никаких плагинов и является, в сущности, необязательным, подключаясь к странице только в том случае, когда код MediaWiki содержит вызов метода $wgOut->includeJQuery(). Скажем, расширение UsabilityInitiative содержит именно такой вызов на строке 128 своего файла «UsabilityInitiative.hooks.php», так что jQuery появляется в некоторых темах оформления (например, в Vector), когда расширение UsabilityInitiative подключено к вики.

Предлагаю встать на точку зрения вики-техника, то есть администратора сервера MediaWiki, имеющего прямой доступ (наподобие SSH) и возможность менять настройки вики (LocalSettings.php), доустанавливать расширения MediaWiki и проводить другие подобные действия. Какие обстоятельства могут вызвать у вики-техника MediaWiki 1.16.x стремление переменить к лучшему то положение дел, которое упомянуто в предыдущем абзаце? Каким путём уместнее всего действовать вики-технику на пути воплощения этого своего стремления?

Первотолчком такого стремления является естественное и почти неизбежное осознание того, как неудобна та необязательность появления jQuery в коде страниц, которая настроена по умолчанию. Всякий вики-техник, если он имеет достаточно досуга для размышлений, рано или поздно постигает, что простота и могущество функции $(), если бы она была всегда в распоряжении администраторов, сочиняющих скрипты для вики, всенепременно породили бы JS-код куда компактнее, чем прежний. Возьмём для примера версию от 22 мая 2011 года страницы «MediaWiki:Common.js» из россияноязычной Википедии. В ней нетрудно заметить вот какой код функции:
function editZeroSection(){
 var body = document.getElementById('bodyContent')
 if (!body) return
 var h2s = body.getElementsByTagName('H2')
 var h2 = h2s[0]
 if (!h2) return
 if (h2.parentNode.id == 'toctitle') h2 = h2s[1]
 if (!h2) return
 var span = h2.firstChild
 if (!span || span.className != 'editsection') return
 var zero = span.cloneNode(true)
 body.insertBefore(zero, body.firstChild)
 var a = zero.getElementsByTagName('a')[0]
 if (a.href.indexOf('&section=T') == -1 )  a.title = a.title.replace(/:.*$/,': 0')
 else a.title = 'Править секцию: 0'
 a.setAttribute('href', wgScript + '?title='+encodeURIComponent(wgPageName) + '&action=edit&section=0')
}
Любому поклоннику jQuery хорошо известно, как эта библиотека напрочь избавила бы авторов функции от необходимости прибегать к getElementById() и getElementsByTagName(), а также предоставила бы сокращённые аналоги некоторых других методов и полей. А ведь такая функция там не одна. Не одна и такая вики: аналогичные громоздкости нетрудно усмотреть, скажем, в версии от 28 мая 2011 года страницы «MediaWiki:Common.js» из «Абсурдопедии».

Предположим, что вики-техник обеспечил неукоснительность появления jQuery в коде страницы, последовав официальной инструкции и пополнив файл «LocalSettings.php» соответствующим кодом:
// Include jQuery
function wfIncludeJQuery() {
        global $wgOut;
        $wgOut->includeJQuery();
}
$wgExtensionFunctions[] = 'wfIncludeJQuery';
Администраторы вики, обладая правами править страницу «MediaWiki:Common.js», начали переписывать тамошние функции на jQuery, использовать $() вместо addOnloadHook(), и так далее. Какие два камня преткновения ожидают этот процесс в дальнейшем?

Во-первых, при знакомстве с историей jQuery непременно вскроется, что версия 1.3.2 (как я ужé упоминал чуть выше) появилась давненько — аж в феврале 2009 года. Постоянным читателям хабрахабровского блога jQuery и рассказывать не надо, как велико и значительно было развитие библиотеки за истекшие с той поры 2⅓ года; для всех остальных я просто приведу в пример ускорение анимации в версии 1.4.3, новые интерфейсы deferred ([1], [2]) в версии 1.5, полную поддержку IE9 в версии 1.5.1… а изменения в версии 1.4 вообще на 14 страницах излагаются.

Во-вторых, едва покончив с переводом существующих скриптов на jQ-основу, администраторы вики закономерно призадумаются о том, какие ещё возможности открываются для автоматизации (заскриптовывания) вики в лучшую сторону. Почти неизбежно при этом их знакомство с таким потрясающим инструментом, каким служат плагины jQuery, позволяющие нехитрым способом («копипастою») во мгновение ока снабжать сайт значительными, впечатляющими улучшениями. Например, достаточно добавить jQuery.ScrollTo да jQuery.LocalScroll и тотчас же сразу все внутристраничные гиперссылки можно будет снабдить зрелищной анимацией прокручивания страницы, задействовав несложный скрипт:
$(function(){
   $.localScroll({
      hash: true,
      onAfter: function(target){
         location = '#' + ( target.id || target.name );
      }
   });
});
Для вики на движке MediaWiki, с его автоматическими оглавлениями статей, такое улучшение поведения неоценимо.

Мы видим: на этом этапе ход событий неумолимо подталкивает вики-техника к тому, чтобы создать файл (лучше всего — один файл, чтобы не тратилось время на лишние запросы к серверу), содержащий и новую версию библиотеки jQuery, и все желаемые плагины к ней. Сгодится ли «skins/common/jquery.min.js» на роль такого файла? Мало вероятно, и на то есть две причины. Во-первых, как известно, любой переход на новую версию MediaWiki (даже с версии 1.16.x на версию 1.16.x+1) сопряжён с записыванием новых файлов поверх старых — малейшая невнимательность обновляющего может привести к тому, что файл «skins/common/jquery.min.js» будет вновь заменён версией jQuery, поставляемой с MediaWiki (1.3.2, без плагинов). Во-вторых, вообще не очень-то логично поручать обновление jQuery и плагинов вики-технику и требовать для этого прав прямого доступа к вики-серверу, раз уж многие другие джаваскрипты MediaWiki (такие, как вышеупомянутый «MediaWiki:Common.js», например) может править любой администратор через интерфейс самóй вики, к тому же снабжённый удобной встроенной системою контроля версий и просмотра разности правок. Получается, что логичнее было бы и jQuery, вместе со всеми уместными в конкретной вики плагинами, разместить на странице с именем «MediaWiki:jQuery.js», да на том успокоиться.

Достижимо ли такое размещение в техническом отношении? Да, вполне достижимо; для него достаточно только убрать из файла «LocalSettings.php» тот код с вызовом метода includeJQuery(), который был туда добавлен на предыдущем этапе — а вместо него подключить вызов такого расширения MediaWiki, которое обеспечивало бы подключение скрипта «MediaWiki:jQuery.js», да вдобавок выкусывало бы вызов скрипта «skins/common/jquery.min.js» на тот случай, если вызов метода includeJQuery() всё же поступит от какого-нибудь другого расширения.

Задача о сочинении такого кода расширения MediaWiki, который подключил бы «MediaWiki:jQuery.js» к каждой странице вики, давно решена мною — ответ её (код его) выглядит следующим образом (включая лицензию MIT):
<?php
/*
 * jQuery.php - Adds jQuery script to the <head> . . . </head> 
 * @author Mithgol the Webmaster
 * @version 0.2
 * @copyright Copyright (C) 2010 Mithgol the Webmaster
 * @license The MIT License - http://www.opensource.org/licenses/mit-license.php
 * ---------------------------------------------------------------------------------------
 * Copyright (c) 2010 Mithgol the Webmaster
 *
 * Permission is hereby granted, free of charge, to any person obtaining a copy
 * of this software and associated documentation files (the "Software"), to deal
 * in the Software without restriction, including without limitation the rights to
 * use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of
 * the Software, and to permit persons to whom the Software is furnished to do
 * so, subject to the following conditions:
 *
 * The above copyright notice and this permission notice shall be included in all
 * copies or substantial portions of the Software.
 *
 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
 * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES
 * OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
 * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT
 * HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,
 * WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
 * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
 * OTHER DEALINGS IN THE SOFTWARE.
 * -----------------------------------------------------------------------
 * Version notes:
 *    version 0.2:
 *       erase MediaWiki's internal jQuery call, which lacks plugins
 *    version 0.1:
 *       initial release
 * -----------------------------------------------------------------------
*/
 
# Confirm MW environment
if (defined('MEDIAWIKI')) {
 
# Credits
$wgExtensionCredits['other'][] = array(
    'name'        => 'jQuery',
    'author'      => 'Mithgol the Webmaster',
    'url'         => 'http://traditio.ru/wiki/JQuery_%D0%B4%D0%BB%D1%8F_MediaWiki',
    'description' => 'Adds jQuery to the list of scripts (HEAD element).',
    'version'     => '0.2'
);
 
function jQueryMyHook( &$output, &$skin ) {
   $output->mScripts = "\t\t".
                       '<script type="text/javascript" src="/w/index.php?title=MediaWiki:jQuery.js&action=raw&ctype=text/javascript"></script>'.
                       "\n" . preg_replace('/<script src="\/w\/skins\/common\/jquery\.min\.js\?\d+"><\/script>/', '<!-- jQuery double, erased -->', $output->mScripts);
   return true;
}
 
$wgHooks['BeforePageDisplay'][] = 'jQueryMyHook';
 
} # End MW Environment wrapper
?>
Обратите внимание, что выкусыватель файла «skins/common/jquery.min.js» учитывает манеру MediaWiki прибавлять «?» и число к URLу скрипта.

При наполнении файла «MediaWiki:jQuery.js» уместно обеспечить обратную совместимость с «skins/common/jquery.min.js» по формату имени jQuery. Для этой цели вполне достаточно поместить в файл «MediaWiki:jQuery.js» дополнительно вот какой код:
/*   По меньшей мере два скрипта MediaWiki:
 *      1)  /skins/common/edit.js
 *      2)  /skins/common/preview.js
 *   полагаются на то, что jQuery можно вызвать переменною $j.
 *   Так не разочаруем же их:
*/
$j=$;
Очевидно, надеюсь, что этот синоним должен создаваться после кода самóй библиотеки jQuery.

Вышеприведённое расширение внедрено в русской вики-энциклопедии «Традиция» в 2010 году и успело на деле всецело доказать свою пригодность. Некоторые из тех улучшений и удобств, созданных скриптами, которые употребление jQuery в MediaWiki делает возможным, заслуживают, пожалуй, отдельных блогозаписей на Хабрахабре, но нынешний рассказ мой окончен.
+10
1,4k 8
Комментарии 13