Подключение JS файлов в CodeIgniter

Во фреймворке 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