Во фреймворке CodeIgniter нет встроенных средств для подключение JS файлов, а такой скрипт необходим практически каждому приложению. Допустим у вас есть 2 отображения, которые генерируют некоторый HTML код средствами JQuery, и допустим, эти отображения должны быть не на всех страницах сайта, а только на нескольких. Можно подключить JQuery в макете сайта, но так он будет загружаться даже для тех страниц сайта, где он не используется.
Итак, я создаю а приложении папку js и записываю в ней файл js/jquery/jquery.min.js, обратите внимание в файле отсутствует номер версии Jquery, это необходимо для того чтобы обновление этой библиотеки делать простой заменой файла на сервере. Не претендую на то, что этот подход единственный верный, кто-то может предпочесть хранить все версии библиотек на серевере и переключаться между версии через конфигурацию, но мне кажется это излишним, на практике я еще не сталкивался с задачей, где бы это было бы актуально.
Алгоритм работы должен быть примерно такой: приложение генерирует страницу и запоминает какие JS файлы требуется подключить к макету, и после того как страница полностью создана, в её определенную часть добавляются нужные JS файлы и после этого страница отправляется в браузер.
Задачу можно разделить на следующие этапы:
- запоминание всех используемых на странице js файлов
- перехват HTML кода страницы перед отправкой её в браузер
- вывод списка JS файлов в нужном месте страницы
Чтобы запомнить список всех файлов из разных мест приложения я использую класс конфигурации. Добавить значение в массив конфигурации из любого места приложения можно так:
[code] get_instance()->config->config['key'] = 'value'; [/code]
В отображении и контроллере можно использовать переменную $this:
[code] $this->config->config['key'] = 'value'; [/code]
Перед добавлением файла в список файлов, требуется проверка, а не был ли такой файл уже добавлен, поэтому эту операцию лучше оформить во вспомогательную функцию (хелпер). Также, будет не лишним предусмотреть то, что добавляться может как локальный файл относительно FCPATH, так и файл из интернета по полному пути.
Вот что у меня вышло: [code] if (function_exists('js') === FALSE) { function js($file, $base_url = TRUE, $params = array()) { $ci = & get_instance();
if ($base_url != FALSE)
{
if (function_exists('base_url') === FALSE)
{
$ci->load->helper('url');
}
$file = base_url().ltrim($file, '/');
}
if (isset($ci->config->config['js'][$file]) === FALSE)
{
$ci->config->config['js'][$file] = $params;
}
else
{
$ci->config->config['js'][$file] = array_merge(
$params,
$ci->config->config['js'][$file]
);
}
}
} [/code]
В функцию js можно передать 3 параметра:
- путь к файлу скрипта включающий название файла
- признак того, передан относительный путь или абсолютный
- дополнительные параметры
Имена дополнительных параметров на данном этапе не важны, но это должен быть одноуровневый ассоциативный массив.
После добавления хелпера в автозаргузку приложения, у нас появляется возможность в любом месте приложения сообщить ему о необходимости подключения JS файла.
Переходим к следующему пункту: после формирования всего кода страницы нужно в нужном месте вставить список файлов. Для начала, нужное место нужно как-то определить в шаблоне сайта, пусть это будет псевдотег [JS]. За перехват отображения отвечает хук display_override. Включим хуки в конфигурации приложения, и в конфигурацию хуков добавим:
[code] $hook['display_override'][] = array( 'function' => 'js_hook', 'filename' => 'js_hook.php', 'filepath' => 'hooks' ); [/code]
Теперь переходим к следующему этапу, собственно замена псевдотега JS на список файлов, не вижу смысла плодить лишних файлов в прокте, поэтому это происходит прямо в хуке:
[code] if (function_exists('js_hook') === FALSE) { function js_hook() { $ci = & get_instance();
$return = '';
if (isset($ci->config->config['js']) === TRUE)
{
foreach($ci->config->config['js'] as $js => $params)
{
if (isset($params['language']) === TRUE)
{
$language = $params['language'];
}
else
{
$language = 'JavaScript';
}
if (isset($params['type']) === TRUE)
{
$type = $params['type'];
}
else
{
$type = 'text/javascript';
}
$return .= '<'
.'script language="'
.$language
.'" type="'.$type
.'" src="'
.$js.'">'
.'<'
.'/'
.'script'
.'>'
."\n";
unset($ci->config->config['js'][$js]);
}
if (count($ci->config->config['js']) == 0)
{
unset($ci->config->config['js']);
}
}
$ci->output->set_output(
str_replace(
'[JS]',
$return,
$ci->output->get_output()
)
);
}
} [/code]
Почти всё (но не всё). Было определено событие на отправку страницы в браузер и теперь самой отправки не происходит, а вместо этого выполнятся очередь хуков (в данном случае очередь из одного хука). Добавим в конец очереди свой хук на отправку страницы в браузер:
[code] $hook['display_override'][] = array( 'function' => 'display_hook', 'filename' => 'display_hook.php', 'filepath' => 'hooks' ); [/code]
Сам хук:
[code] if (function_exists('display_hook') === FALSE) { function display_hook() { $ci = & get_instance();
$ci->output->_display();
}
} [/code]
Теперь можно подключать к приложению клиентские скрипты:
[code] js('js/jquery/jquery.min.js'); [/code]
Пожелания по доработке системы приветствуются.
22.09.2010