Подключаем FCKeditor к CodeIgniter

Владимир | | CodeIgniter, PHP, Web разработка.

fckeditor codeigniter

FCKeditor, на мой взгляд, один из лучших online редакторов. И в теории его можно подключить практически к любому сайту, независимо от того какой движок/фреймворк/CMS используется.

Но, естественно, всегда существует несколько нюансов, которые немного усложняют жизнь 🙂

В этой статье речь пойдет о том как подключить этот редактор к сайту использующему PHP фреймворк CodeIgniter. Вообще-то я нашел довольно много статей и рекомендаций на эту тему, но в большинстве из них предлагается скопировать файлы редактора в папки библиотек или плагинов, а, на мой взгляд, это не правильно.

Дело вот в чем. Плагины и библиотеки (пользовательские) обычно находятся в папке application, которая не обязательно должна находиться внутри DOCUMENT_ROOT. Точнее, с точки зрения безопасности, эту папку лучше убрать за пределы DOCUMENT_ROOT чтобы исключить любую возможность прямого доступа к скриптам сайта (т.е. скрипты будут доступны только через index.php).

Но FCKeditor содержит файлы картинок, стилей и т.п., к которым нужно обеспечить прямой доступ. Т.е. его нужно разместить внутри DOCUMENT_ROOT.

Как оказалось, обойти эту проблему совсем не сложно.

Прежде всего, рассмотрим структуру папок сайта.

index.php
system/
fckeditor/
images/
css/
libs/

Как видите, в корне сайта (DOCUMENT_ROOT) находятся главный контроллер (index.php), папки system, fckeditor (с редактором) и другие папки с картинками, CSS стилями, библиотеками и т.п.

Папка application по-умолчанию находится внутри system, но ее можно спокойно перенести.

Подключаем редактор

Прежде всего, создадим файл настроек (application/config/fckeditor.php)

<?php
//путь к FCKeditor относительно корня сайта (папки, в которой находится index.php)
$config['fckeditor_path'] = 'fckeditor/';
//URL FCKeditor относительно корня сайта (параметра $config['base_url'])
$config['fckeditor_url'] = 'fckeditor/';
//имя редактора
$config['fckeditor_name'] = 'MyFCKeditor';
//высота редактора
$config['fckeditor_height'] = 300;
?>

Объяснять тут в общем-то нечего. Главное правильно указать параметры fckeditor_path и fckeditor_url.

Теперь создадим файл библиотеки, который будет подключать редактор (/application/libraries/fcke.php).

<?php
if ( ! defined('BASEPATH')) exit('No direct script access allowed');
/**
 * Эта библиотека подключает редактор FCKeditor
 *
 * @version 0.1
 * @link http://www.simplecoding.org
 * @author Стаценко Владимир <vova_33@gala.net>
 */
class FCKe {
	
	private $editor = null;
	
	function FCKe() {
		$CI = &get_instance();
		//читаем данные из конфига
		$CI->config->load('fckeditor');
		$fcke_url = $CI->config->item('base_url').$CI->config->item('fckeditor_url');
		$fcke_path = substr(FCPATH, 0, strrpos(FCPATH, DIRECTORY_SEPARATOR) + 1)
			.$CI->config->item('fckeditor_path');
		include_once($fcke_path.'fckeditor.php');
		$this->editor = new FCKeditor($CI->config->item('fckeditor_name'));
		$this->editor->BasePath = $fcke_url;
		$this->editor->Height = $CI->config->item('fckeditor_height');
	}

	function __call($method, $arguments) {
		return call_user_func_array(array($this->editor, $method), $arguments);
	}
}
/* End of file fckeditor.php */
/* Location: ./system/application/libraries/fckeditor/fckeditor.php */

Разберем этот код подробнее.

В конструкторе мы читаем параметры из конфига, загружаем файл fckeditor.php и создаем объект редактора (FCKeditor).

Параметр fckeditor_path используется при загрузке файла fckeditor.php (строка 21). А с помощью fckeditor_url задаем URL папки редактора (строка 23).

Доступ к методам редактора обеспечивает метод __call.

Проще говоря, мы написали оболочку, которая загружает редактор и обеспечивает доступ ко всем его методам.

Теперь использовать редактор не сложнее чем любую другую библиотеку CodeIgniter.

В контроллере загружаем библиотеку:

$this->load->library('fcke');

И сразу же можем создать редактор.

$this->fcke->Create();

Как видите, метод Create() редактора вызывается через объект fcke, т.е. нашу библиотеку.

Примечание. Редактор должен находится внутри формы. Атрибут action указывает какому скрипту будет отправлен текст, введенный в редактор.

Небольшое дополнение. Метод Create() сразу же отправляет код редактора браузеру, т.е. его нужно вызывать из представления. В общем-то, ничего страшного, но это нарушение MVC модели. Если хотите этого избежать используйте метод CreateHtml() в контроллере. Он возвращает HTML код редактора, который затем можно передать представлению. Например:

в контроллере:

$this->load->library('fcke');
$pageData['editor'] = $this->fcke->CreateHtml();
$this->load->view('my_view', $pageData);

в представлении:

<?php
echo $editor;
?>

В общем, подключить редактор не сложно.

Если у вас есть замечания или вопросы, буду рад на них ответить. Пишите, комментарии открыты!

  • Taral

    Ооо спасибо! Давненько не было тут статей про CodeIgniter. А жаль. Прочитаю с огромный удовольствием

  • Taral

    Ооо спасибо! Давненько не было тут статей про CodeIgniter. А жаль. Прочитаю с огромный удовольствием

  • Dark Preacher

    Большое спасибо Владимир!
    Я давно читаю ваш блог — всё понятно, доступно и грамотно изложено.
    Эта статья не исключение — читал о разных методах подключения редактора к CI, один из них через JS, который не подходил мне, а это просто идеальное решение для меня.

    • Спасибо большое!

      Только стало интересно почему не подошел метод с JS? Без поддержки JS в браузере FCKEditor сам по себе работать не будет.

      • Dark Preacher

        Просто не люблю когда сначала показывается textarea, а потом расползается и преобразуется в редактор — можно сказать, что это мои личные, эстетические предпочтения =)
        Кстати я немного расширил библиотеку, чтобы можно было на лету устанавливать размеры редактора и назначать разные тулбары.

        • Тулбары — это интересно 🙂
          У меня было несколько идей по поводу их настройки из CI, но добавлять их я не стал, т.к. необходимости не было, а настроек становится значительно больше. (Если кратко — думал просто добавить перечень элементов в конфиг).

          Вы не где не выкладывали ваш вариант? Было бы интересно взглянуть 🙂

        • Dark Preacher

          Я извиняюсь, возможно немного неточно выразился =)
          Я не формирую тулбары в контроллере, тулбары заранее сформированны в конфиге FCK, а в контроллере я только устанавливаю массив опций вроде
          $options = array(
          'toolbar' => 'base',
          'width' => '400px',
          'name' => 'announce'
          );
          Дальше всё это передаётся в библиотеку, в которой и обрабатывается, обычно подобная конструкция мне нужна для формирования формы (извиняюсь за тавтологию) добавления/редактирования новостей, когда надо заполнить анонс с минимальными возможностями оформления и полный вид новости.

        • Ясно, спасибо за пояснения.
          Похоже, конфиг самого редактора действительно будет лучшим вариантом.

  • Dark Preacher

    Большое спасибо Владимир!
    Я давно читаю ваш блог — всё понятно, доступно и грамотно изложено.
    Эта статья не исключение — читал о разных методах подключения редактора к CI, один из них через JS, который не подходил мне, а это просто идеальное решение для меня.

    • Спасибо большое!

      Только стало интересно почему не подошел метод с JS? Без поддержки JS в браузере FCKEditor сам по себе работать не будет.

      • Dark Preacher

        Просто не люблю когда сначала показывается textarea, а потом расползается и преобразуется в редактор — можно сказать, что это мои личные, эстетические предпочтения =)
        Кстати я немного расширил библиотеку, чтобы можно было на лету устанавливать размеры редактора и назначать разные тулбары.

        • Тулбары — это интересно 🙂
          У меня было несколько идей по поводу их настройки из CI, но добавлять их я не стал, т.к. необходимости не было, а настроек становится значительно больше. (Если кратко — думал просто добавить перечень элементов в конфиг).

          Вы не где не выкладывали ваш вариант? Было бы интересно взглянуть 🙂

        • Dark Preacher

          Я извиняюсь, возможно немного неточно выразился =)
          Я не формирую тулбары в контроллере, тулбары заранее сформированны в конфиге FCK, а в контроллере я только устанавливаю массив опций вроде
          $options = array(
          'toolbar' => 'base',
          'width' => '400px',
          'name' => 'announce'
          );
          Дальше всё это передаётся в библиотеку, в которой и обрабатывается, обычно подобная конструкция мне нужна для формирования формы (извиняюсь за тавтологию) добавления/редактирования новостей, когда надо заполнить анонс с минимальными возможностями оформления и полный вид новости.

        • Ясно, спасибо за пояснения.
          Похоже, конфиг самого редактора действительно будет лучшим вариантом.

  • Такой вопрос возник а к чему может привести присутствие FCKeditor внутри DOCUMENT_ROOT?
    Имеет ли практический смысл его вынос за структуру сайта? Теоретически все понятно, во избежание потенциальных проблем лучше вынести, а вот практически, прецеденты были?

    • >> присутствие FCKeditor внутри DOCUMENT_ROOT

      FCKeditor в этом примере находится как раз внутри DOCUMENT_ROOT, т.к. в дистрибутиве есть файлы, которые должны загружаться браузером (картинки, стили и т.д.). За пределы DOCUMENT_ROOT я предлагаю вынести системные файлы CI (папки system или application или обе).

      Прецедентов (лично у меня) не было.

      Но это ни о чем не говорит 😉

      Вынос файлов за DOCUMENT_ROOT — это в основном страховка от собственных ошибок.

      Например, в начале системных файлов CI есть код, который блокирует прямой доступ.
      if (!defined('BASEPATH')) exit('No direct script access allowed');

      Если вы пишите собственную библиотеку или хелпер и забудете его вставить, то может возникнуть уязвимость (в зависимости от остального кода).

  • Такой вопрос возник а к чему может привести присутствие FCKeditor внутри DOCUMENT_ROOT?
    Имеет ли практический смысл его вынос за структуру сайта? Теоретически все понятно, во избежание потенциальных проблем лучше вынести, а вот практически, прецеденты были?

    • >> присутствие FCKeditor внутри DOCUMENT_ROOT

      FCKeditor в этом примере находится как раз внутри DOCUMENT_ROOT, т.к. в дистрибутиве есть файлы, которые должны загружаться браузером (картинки, стили и т.д.). За пределы DOCUMENT_ROOT я предлагаю вынести системные файлы CI (папки system или application или обе).

      Прецедентов (лично у меня) не было.

      Но это ни о чем не говорит 😉

      Вынос файлов за DOCUMENT_ROOT — это в основном страховка от собственных ошибок.

      Например, в начале системных файлов CI есть код, который блокирует прямой доступ.
      if (!defined('BASEPATH')) exit('No direct script access allowed');

      Если вы пишите собственную библиотеку или хелпер и забудете его вставить, то может возникнуть уязвимость (в зависимости от остального кода).

  • Big_Shark

    А разве переменная $BasePath создана не для того чтобы казать где лежит внешние оформления сайта?
    Системные файлы ложим туда куда и обычна проста сразу после загрузки класса переопределяем перменную $BasePath на нужную нам и вродебы все)
    P.S. Сам не пробывал проста решил найти более легкий путь чем автор!

    • Честно говоря, не понял.
      Я устанавливаю BasePath (второй листинг сверху, строка 23).

      • Big_Shark

        Все верно но тогда разве проста недостаточно положить php файлы FCKeditor в папку с либрами и после загрузки его указывать BasePath
        веть тогда смысл в написании доп библеотеки как у вас проподает!

        • По требованиям CI в файле библиотеки должен быть объявлен класс с именем, которое совпадает с названием файла.
          У FCKEditor это не так. Класс FCKeditor находится в файлах fckeditor_php4.php и fckeditor_php5.php. А код в файле fckeditor.php просто проверяет версию PHP и загружает подходящую версию.
          Можно «поиграться» с названиями, например, переименовать fckeditor_php5.php в fckeditor.php.
          Но могут быть проблемы при переходе на новые версии редактора.
          В общем, небольшая оболочка в виде библиотеки мне кажется удобнее.

        • Big_Shark

          Тут мне кажеться на любителя)
          Яб файл переименовал и не парился)

        • Согласен.
          Файл переименовать быстрее… Хотя, в любом случае нужно лезть в исходники 😉

        • В файлах fckeditor_php4.php и fckeditor.php в данном случае нет надобности, поскольку class FCKe использует метод __call, что возможно только в php 5

        • Согласен, но переименовывать все равно придется.

        • Павел

          Можно ли использовать неограниченное количество редакторов на странице ?

        • По-идее можно. Создайте редактор с другим именем
          new FCKeditor($CI->config->item('fckeditor_name'));
          Правда я всегда для таких целей использовал tinymce, его настраивать проще. При создании можно сразу указать, что редакторы должны создаваться, например, для всех textarea на странице.

  • Big_Shark

    А разве переменная $BasePath создана не для того чтобы казать где лежит внешние оформления сайта?
    Системные файлы ложим туда куда и обычна проста сразу после загрузки класса переопределяем перменную $BasePath на нужную нам и вродебы все)
    P.S. Сам не пробывал проста решил найти более легкий путь чем автор!

    • Честно говоря, не понял.
      Я устанавливаю BasePath (второй листинг сверху, строка 23).

      • Big_Shark

        Все верно но тогда разве проста недостаточно положить php файлы FCKeditor в папку с либрами и после загрузки его указывать BasePath
        веть тогда смысл в написании доп библеотеки как у вас проподает!

        • По требованиям CI в файле библиотеки должен быть объявлен класс с именем, которое совпадает с названием файла.
          У FCKEditor это не так. Класс FCKeditor находится в файлах fckeditor_php4.php и fckeditor_php5.php. А код в файле fckeditor.php просто проверяет версию PHP и загружает подходящую версию.
          Можно «поиграться» с названиями, например, переименовать fckeditor_php5.php в fckeditor.php.
          Но могут быть проблемы при переходе на новые версии редактора.
          В общем, небольшая оболочка в виде библиотеки мне кажется удобнее.

        • Big_Shark

          Тут мне кажеться на любителя)
          Яб файл переименовал и не парился)

        • Согласен.
          Файл переименовать быстрее… Хотя, в любом случае нужно лезть в исходники 😉

        • В файлах fckeditor_php4.php и fckeditor.php в данном случае нет надобности, поскольку class FCKe использует метод __call, что возможно только в php 5

        • Согласен, но переименовывать все равно придется.

        • Павел

          Можно ли использовать неограниченное количество редакторов на странице ?

        • По-идее можно. Создайте редактор с другим именем
          new FCKeditor($CI->config->item('fckeditor_name'));
          Правда я всегда для таких целей использовал tinymce, его настраивать проще. При создании можно сразу указать, что редакторы должны создаваться, например, для всех textarea на странице.

  • KomarBang

    Отличное решение…

  • KomarBang

    Отличное решение…

  • KomarBang

    CreateHtml() — очень удачное решение.. без этого метода было бы плохо))

  • KomarBang

    CreateHtml() — очень удачное решение.. без этого метода было бы плохо))

  • в каким образом без CreateHtml() можно обойтись?

    • Использовать метод Create(). Он сразу отправляет редактор браузеру.

  • в каким образом без CreateHtml() можно обойтись?

    • Использовать метод Create(). Он сразу отправляет редактор браузеру.

  • Когда-то у меня тоже стояла такая задача, но ни одно из решений в интеренте мне не подошло.
    В итоге придумал свой способ.
    Что мне ненравиться в СI, так это мешанина представления и контроллера. К примеру хелперы по идее недолжны подключаться в контроллере, но у игнайтера — это нормально. Собачки в коде — это плохо — у игнайтера хорошо. Когда-то пол часа потратил на отладку приложения на игнайтере, пока не полез в код и не повытирал собачки.
    Короче с недавних пор ненравиться мне игнайтер. Вообще я пишу всегда на symfony, но она негодится для маленьких проектов. Поэтому с недавних пор отдаю предпочтение не CI а написанному на его базе Kohana. Там намного более грамотный код.
    Редактор — это проблема представления, поэтому выход вижу только один- написать хелпер, который возвращает javaScript. При необходимости можно сделать хелпер кастамский, т.е передавать в качестве аргументов высоту и т.д. И ненадо ничего усложнять, как это сделано тут http://erum.ru/article/9.
    там чувак вывернул кишки из чего только мог.
    А располагаться эдитор должен только в одном месте — в корне сайта (как у Володи).Любое другое решение считаю — идиотизмом.
    P.S:Почему только среди php-шников столько неграмотности????!!!!

    • KomarBang

      По поводу подключения хелперов в контроллере…

      Как мне кажется это логично, что хелперы подключаются через контроллер. На то он и «контроллер»!

      А вооообще CI просто дает возможность подключения и там и там, а где подключать — это уже ваше решение. Хорошо, что есть выбор 🙂

      • Это еще одна мешанина в CI. Хелпер должен всегда генерить html или javaScript. Его дело это представление. То что в игнайтере хелперы работают с файлами — идиотизм. Это прерогатива библиотек.
        Посмотрите хоть на один грамотный фреймверк (Symfony and Zend).

        Честно говоря, работать с библиотекой мне кажется удобнее. Хотя, конечно, нужно написать хелпер и сравнить.

        Библиотека — это бизнес логика

        Эта фраза была бы уместнее в комментариях к той статье. Во всяком случае автор мог бы ответить.

        Мне не интересно его переубеждать.

        Опять же, спорное заявление. Например, если редактор используется только для админ панели, то логично разместить его в папке, доступ к которой ограничен (а это не обязательно в корне сайта).

        А зачем к нему ограничивать доступ.

        • Это еще одна мешанина в CI

          Может быть, но что будет если разработчики эту мешанину уберут? Станет CI эффективнее/быстрее/стабильнее? Вряд ли. Ведь только названия изменятся. Код будет тем же самым. Зато наверняка посыпятся жалобы от разработчиков.

          Вобщем, хелпер и библиотека — это только названия, условности. Главное — код, который за ними стоит.

          Я, конечно, понимаю, что было бы очень не плохо если бы все придерживались единой терминологии, но вносить изменения в движок только ради названий — это ИМХО перебор.

          А зачем к нему ограничивать доступ

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

    • >> хелперы

      Вопрос очень спорный:
      1) Form helper — создает html код (представление)
      2) File helper — работа с файлами (модель)
      3) Хелперы можно загружать через autoload в этом случае они скорее напоминают стандартные функции PHP и отнести их к контроллеру, модели и представлению сложно (во всяком случае для меня).

      >> Kohana и собачки

      Ничего против не имею, но сам с необходимостью вытирать собачки не сталкивался

      >> выход вижу только один- написать хелпер

      Честно говоря, работать с библиотекой мне кажется удобнее. Хотя, конечно, нужно написать хелпер и сравнить.

      >> чувак вывернул кишки

      Эта фраза была бы уместнее в комментариях к той статье. Во всяком случае автор мог бы ответить.
      Кроме того, предложенное им решение работает, к тому же там очень подробно описаны настройки. В общем, статья интересная.

      >> располагаться эдитор должен только в одном месте

      Опять же, спорное заявление. Например, если редактор используется только для админ панели, то логично разместить его в папке, доступ к которой ограничен (а это не обязательно в корне сайта).

      >> P.S.

      Это вопрос риторический 🙂
      Неграмотных разработчиков (также как и грамотных и талантливых) везде хватает. Врядли существует точная статистика.
      Хотя языки вроде С++ и Java страхуют от некоторых ошибок (например, за счет строгой типизации).

    • >там чувак вывернул кишки из чего только мог.
      1. хм. Учебный пример. К тому же два варианта — в одном вообще ни строчки php кода.
      2. я вообще считаю что вставка js непосредственно в HTML может быть оправдана только в исключительных случаях. Например в учебных примерах. В остальных такие вещи как визивиг или валидация должны подцепляться AJAXом. Но это отдельная тема.

      >А располагаться эдитор должен только в одном месте — в не сайта (как у Володи).
      >Любое другое решение считаю — идиотизмом
      Идиотизм — абсолютизировать любое техническое решение.

      • Идиотизм — абсолютизировать любое техническое решение

        Это правильно. Идеальных решений не существует и всегда лучше попробовать несколько вариантов и выбрать наиболее подходящий в данной ситуации.

        должны подцепляться AJAXом. Но это отдельная тема.

        Хотелось бы почитать статью на эту тему 😉
        По-моему использование AJAX может создать дополнительные задержки и не всегда они оправданны… без примера сложно что-то сказать.

        • >По-моему использование AJAX ….без примера сложно что-то сказать.
          Все в том же контексте. Имхо большая часть функций админки должна выносится непосредственно на фронтофис (за исключением каких-то отдельных функций). В этом случае либо iframe либо ajax.
          А экономия очень простая. Она даже не на трафике, а на трудозатратах по администрированию сайта. Юзабельность повышается на порядок.

        • Насчет админки и трудозатрат полностью согласен. С той же админкой WP 2.7 работать гораздо быстрее в основном за счет ajax.
          Но все равно мне не понятно почему подключение WYSIWYG редактора должно выполняться ajax'ом? Если редактор используется постоянно, то лучше сразу подключить его к странице.

        • > Но все равно мне не понятно почему подключение WYSIWYG
          > редактора должно выполняться ajax'ом?
          На примере того же блога — на одну операцию по редактированию текстов приходится десяток операций по управлению откликами (удаление спама, добавление редакторских откликов, управление тегами и т.п.). Спрашивается — нафига в этом случае постоянно грузить визивиг, а к нему еще десяток прибабахов?

        • Но ведь WYSIWYG будет подключаться только один раз, для формы редактирования поста. Для удаления спама он не нужен.

          Но кажется я понял о чем речь 🙂 В админке WP форма быстрого редактирования комментариев подключается AJAX'ом.

        • C большим опозданием, но смог оформить в виде текста:
          http://erum.ru/article/38 — подключение jwysiwyg
          http://erum.ru/article/39 — превращение jwysiwyg в FCK

        • Спасибо! Интересные статьи получились.

  • Когда-то у меня тоже стояла такая задача, но ни одно из решений в интеренте мне не подошло.
    В итоге придумал свой способ.
    Что мне ненравиться в СI, так это мешанина представления и контроллера. К примеру хелперы по идее недолжны подключаться в контроллере, но у игнайтера — это нормально. Собачки в коде — это плохо — у игнайтера хорошо. Когда-то пол часа потратил на отладку приложения на игнайтере, пока не полез в код и не повытирал собачки.
    Короче с недавних пор ненравиться мне игнайтер. Вообще я пишу всегда на symfony, но она негодится для маленьких проектов. Поэтому с недавних пор отдаю предпочтение не CI а написанному на его базе Kohana. Там намного более грамотный код.
    Редактор — это проблема представления, поэтому выход вижу только один- написать хелпер, который возвращает javaScript. При необходимости можно сделать хелпер кастамский, т.е передавать в качестве аргументов высоту и т.д. И ненадо ничего усложнять, как это сделано тут http://erum.ru/article/9.
    там чувак вывернул кишки из чего только мог.
    А располагаться эдитор должен только в одном месте — в корне сайта (как у Володи).Любое другое решение считаю — идиотизмом.
    P.S:Почему только среди php-шников столько неграмотности????!!!!

    • KomarBang

      По поводу подключения хелперов в контроллере…

      Как мне кажется это логично, что хелперы подключаются через контроллер. На то он и «контроллер»!

      А вооообще CI просто дает возможность подключения и там и там, а где подключать — это уже ваше решение. Хорошо, что есть выбор 🙂

      • Это еще одна мешанина в CI. Хелпер должен всегда генерить html или javaScript. Его дело это представление. То что в игнайтере хелперы работают с файлами — идиотизм. Это прерогатива библиотек.
        Посмотрите хоть на один грамотный фреймверк (Symfony and Zend).

        Честно говоря, работать с библиотекой мне кажется удобнее. Хотя, конечно, нужно написать хелпер и сравнить.

        Библиотека — это бизнес логика

        Эта фраза была бы уместнее в комментариях к той статье. Во всяком случае автор мог бы ответить.

        Мне не интересно его переубеждать.

        Опять же, спорное заявление. Например, если редактор используется только для админ панели, то логично разместить его в папке, доступ к которой ограничен (а это не обязательно в корне сайта).

        А зачем к нему ограничивать доступ.

        • Это еще одна мешанина в CI

          Может быть, но что будет если разработчики эту мешанину уберут? Станет CI эффективнее/быстрее/стабильнее? Вряд ли. Ведь только названия изменятся. Код будет тем же самым. Зато наверняка посыпятся жалобы от разработчиков.

          Вобщем, хелпер и библиотека — это только названия, условности. Главное — код, который за ними стоит.

          Я, конечно, понимаю, что было бы очень не плохо если бы все придерживались единой терминологии, но вносить изменения в движок только ради названий — это ИМХО перебор.

          А зачем к нему ограничивать доступ

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

    • >> хелперы

      Вопрос очень спорный:
      1) Form helper — создает html код (представление)
      2) File helper — работа с файлами (модель)
      3) Хелперы можно загружать через autoload в этом случае они скорее напоминают стандартные функции PHP и отнести их к контроллеру, модели и представлению сложно (во всяком случае для меня).

      >> Kohana и собачки

      Ничего против не имею, но сам с необходимостью вытирать собачки не сталкивался

      >> выход вижу только один- написать хелпер

      Честно говоря, работать с библиотекой мне кажется удобнее. Хотя, конечно, нужно написать хелпер и сравнить.

      >> чувак вывернул кишки

      Эта фраза была бы уместнее в комментариях к той статье. Во всяком случае автор мог бы ответить.
      Кроме того, предложенное им решение работает, к тому же там очень подробно описаны настройки. В общем, статья интересная.

      >> располагаться эдитор должен только в одном месте

      Опять же, спорное заявление. Например, если редактор используется только для админ панели, то логично разместить его в папке, доступ к которой ограничен (а это не обязательно в корне сайта).

      >> P.S.

      Это вопрос риторический 🙂
      Неграмотных разработчиков (также как и грамотных и талантливых) везде хватает. Врядли существует точная статистика.
      Хотя языки вроде С++ и Java страхуют от некоторых ошибок (например, за счет строгой типизации).

    • >там чувак вывернул кишки из чего только мог.
      1. хм. Учебный пример. К тому же два варианта — в одном вообще ни строчки php кода.
      2. я вообще считаю что вставка js непосредственно в HTML может быть оправдана только в исключительных случаях. Например в учебных примерах. В остальных такие вещи как визивиг или валидация должны подцепляться AJAXом. Но это отдельная тема.

      >А располагаться эдитор должен только в одном месте — в не сайта (как у Володи).
      >Любое другое решение считаю — идиотизмом
      Идиотизм — абсолютизировать любое техническое решение.

      • Идиотизм — абсолютизировать любое техническое решение

        Это правильно. Идеальных решений не существует и всегда лучше попробовать несколько вариантов и выбрать наиболее подходящий в данной ситуации.

        должны подцепляться AJAXом. Но это отдельная тема.

        Хотелось бы почитать статью на эту тему 😉
        По-моему использование AJAX может создать дополнительные задержки и не всегда они оправданны… без примера сложно что-то сказать.

        • >По-моему использование AJAX ….без примера сложно что-то сказать.
          Все в том же контексте. Имхо большая часть функций админки должна выносится непосредственно на фронтофис (за исключением каких-то отдельных функций). В этом случае либо iframe либо ajax.
          А экономия очень простая. Она даже не на трафике, а на трудозатратах по администрированию сайта. Юзабельность повышается на порядок.

        • Насчет админки и трудозатрат полностью согласен. С той же админкой WP 2.7 работать гораздо быстрее в основном за счет ajax.
          Но все равно мне не понятно почему подключение WYSIWYG редактора должно выполняться ajax'ом? Если редактор используется постоянно, то лучше сразу подключить его к странице.

        • > Но все равно мне не понятно почему подключение WYSIWYG
          > редактора должно выполняться ajax'ом?
          На примере того же блога — на одну операцию по редактированию текстов приходится десяток операций по управлению откликами (удаление спама, добавление редакторских откликов, управление тегами и т.п.). Спрашивается — нафига в этом случае постоянно грузить визивиг, а к нему еще десяток прибабахов?

        • Но ведь WYSIWYG будет подключаться только один раз, для формы редактирования поста. Для удаления спама он не нужен.

          Но кажется я понял о чем речь 🙂 В админке WP форма быстрого редактирования комментариев подключается AJAX'ом.

        • C большим опозданием, но смог оформить в виде текста:
          http://erum.ru/article/38 — подключение jwysiwyg
          http://erum.ru/article/39 — превращение jwysiwyg в FCK

        • Спасибо! Интересные статьи получились.

  • До инициализации класса библиотеки CI пытается сам загрузить файл конфигурации, имя которого соответствует имени класса. Соответственно, конфигурационный файл можно было назвать fcke и отказаться от его загрузки в конструкторе. Или есть какие-либо ограничения?

    • Честно говоря, раньше не слышал об этой возможности. И к тому же у меня не работает. В общем, мне проще явно загрузить файл.

      • Да, действительно, не работает. Я просто когда копался «во внутренностях» CI в классе Loader обнаружил следующее:
        function _ci_init_class($class, $prefix = '', $config = FALSE)
        {
        $class = strtolower($class);

        // Is there an associated config file for this class?
        if ($config === NULL)
        {
        if (file_exists(APPPATH.'config/'.$class.EXT))
        {
        include_once(APPPATH.'config/'.$class.EXT);
        }
        }
        ...
        }

        В памяти отложилось, что происходит загрузка конфига. Вот и подумал, что загруженные данные попадают в «глобальный» массив, до данных которого можно «достучаться» используя $CI->config->item()

        Интересно, тогда для чего разработчики предусмотрели такую возможность. Разве только для загрузки констант.

  • До инициализации класса библиотеки CI пытается сам загрузить файл конфигурации, имя которого соответствует имени класса. Соответственно, конфигурационный файл можно было назвать fcke и отказаться от его загрузки в конструкторе. Или есть какие-либо ограничения?

    • Честно говоря, раньше не слышал об этой возможности. И к тому же у меня не работает. В общем, мне проще явно загрузить файл.

      • Да, действительно, не работает. Я просто когда копался «во внутренностях» CI в классе Loader обнаружил следующее:
        function _ci_init_class($class, $prefix = '', $config = FALSE)
        {
        $class = strtolower($class);

        // Is there an associated config file for this class?
        if ($config === NULL)
        {
        if (file_exists(APPPATH.'config/'.$class.EXT))
        {
        include_once(APPPATH.'config/'.$class.EXT);
        }
        }
        ...
        }

        В памяти отложилось, что происходит загрузка конфига. Вот и подумал, что загруженные данные попадают в «глобальный» массив, до данных которого можно «достучаться» используя $CI->config->item()

        Интересно, тогда для чего разработчики предусмотрели такую возможность. Разве только для загрузки констант.

  • В данном случае для класса FCKe нужно еще добавить следующий метод:

    function __set($name, $value)
    {
    $this->editor->$name = $value;
    }

    иначе как передавать значение в текстовое поле?

    • Полностью согласен. Присвоить значение свойству класса через __call не получится.
      Правда, проблему можно решить по-другому. Например, если нужно вставлять предварительно подготовленные фрагменты текста в редактор, то лучше сделать это с помощью JavaScript, чем перегружать страницу и вставлять этот текст на стороне сервера.

      • Владимир, объясните, пожалуйста, чем лучше. Вот, к примеру:
        $this->fcke->Value = $data['text'];
        $data['editor'] = $this->fcke->CreateHtml();

        Получили данные из модели, передали значение в редактор, получили код редактора и передаем в представление. О какой перезагрузки страницы идет речь?

        • >> О какой перезагрузки страницы идет речь?

          Прошу прощения, не удачно написал предыдущий комментарий.

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

          Т.е. посетитель нажимает на кнопку в интерфейсе — в редакторе появляется текст.
          Эту функцию лучше реализовать на JS (при необходимости подгрузить данные через AJAX).
          А при создании страницы с редактором просто оставить пустое поле.

  • В данном случае для класса FCKe нужно еще добавить следующий метод:

    function __set($name, $value)
    {
    $this->editor->$name = $value;
    }

    иначе как передавать значение в текстовое поле?

    • Полностью согласен. Присвоить значение свойству класса через __call не получится.
      Правда, проблему можно решить по-другому. Например, если нужно вставлять предварительно подготовленные фрагменты текста в редактор, то лучше сделать это с помощью JavaScript, чем перегружать страницу и вставлять этот текст на стороне сервера.

      • Владимир, объясните, пожалуйста, чем лучше. Вот, к примеру:
        $this->fcke->Value = $data['text'];
        $data['editor'] = $this->fcke->CreateHtml();

        Получили данные из модели, передали значение в редактор, получили код редактора и передаем в представление. О какой перезагрузки страницы идет речь?

        • >> О какой перезагрузки страницы идет речь?

          Прошу прощения, не удачно написал предыдущий комментарий.

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

          Т.е. посетитель нажимает на кнопку в интерфейсе — в редакторе появляется текст.
          Эту функцию лучше реализовать на JS (при необходимости подгрузить данные через AJAX).
          А при создании страницы с редактором просто оставить пустое поле.

  • Делаеться это так:
    Заливаеться редактор в корень проекта и в system/helpers/form_helper.php пишеться ф-я fcke()
    Это на быструю руку, вообще пользовательские хелперы туда лучше не писать.

    function fcke($name='FCKeditor1',$basePath='/fckeditor/',$width='600px',$height='400px')
    {
    $out=''."n";
    $out.='';
    $out.='var oFCKeditor = new FCKeditor(''.$name.'');'."n";
    $out.='oFCKeditor.BasePath = "'.$basePath.'";'."n";
    $out.='oFCKeditor.Width = "'.$width.'";';
    $out.='oFCKeditor.Height = "'.$height.'";';
    $out.='oFCKeditor.Create();
    ';
    return $out;
    }

    Вот и все дело с концом все очень просто. Пишеться за 30 сек.И удобно подключать.

    • Эх, Валерий, вы меня опередили ) Точно такое же решение хотел предложить. Единственное не нужно редактировать файл system/helpers/form_helper.php, гораздо лучше создать хелпер в директории application с именем MY_form_helper.php (это по умолчанию). CI, в этом случае, при загрузке хелпера form, сначала загрузит файл MY_form_helper.php, а затем form_helper.php

  • Делаеться это так:
    Заливаеться редактор в корень проекта и в system/helpers/form_helper.php пишеться ф-я fcke()
    Это на быструю руку, вообще пользовательские хелперы туда лучше не писать.

    function fcke($name='FCKeditor1',$basePath='/fckeditor/',$width='600px',$height='400px')
    {
    $out=''."\n";
    $out.='';
    $out.='var oFCKeditor = new FCKeditor(\''.$name.'\');'."\n";
    $out.='oFCKeditor.BasePath = "'.$basePath.'";'."\n";
    $out.='oFCKeditor.Width = "'.$width.'";';
    $out.='oFCKeditor.Height = "'.$height.'";';
    $out.='oFCKeditor.Create();
    ';
    return $out;
    }

    Вот и все дело с концом все очень просто. Пишеться за 30 сек.И удобно подключать.

    • Эх, Валерий, вы меня опередили ) Точно такое же решение хотел предложить. Единственное не нужно редактировать файл system/helpers/form_helper.php, гораздо лучше создать хелпер в директории application с именем MY_form_helper.php (это по умолчанию). CI, в этом случае, при загрузке хелпера form, сначала загрузит файл MY_form_helper.php, а затем form_helper.php

  • защита от XSS на вашем сайте порезала мне комент.

  • защита от XSS на вашем сайте порезала мне комент.

  • Вот ссылка на статью на мой блог

  • Вот ссылка на статью на мой блог

  • Тоже вариант. И, согласен, он короче моего.
    В вашем примере используется JavaScript подключение, я использовал вариант с PHP.
    В общем-то ни тот, ни другой вариант особых преимуществ не дает (оба стандартные и библиотеки для них входят в дистрибутив редактора).
    Просто мне не очень нравиться генерировать JS код на PHP, особенно когда без этого можно обойтись 🙂

  • Тоже вариант. И, согласен, он короче моего.
    В вашем примере используется JavaScript подключение, я использовал вариант с PHP.
    В общем-то ни тот, ни другой вариант особых преимуществ не дает (оба стандартные и библиотеки для них входят в дистрибутив редактора).
    Просто мне не очень нравиться генерировать JS код на PHP, особенно когда без этого можно обойтись 🙂

  • Pingback: Лучший RSS канал для манимейкеров | Affiliate Marketing: Инструкция по применению.()

  • Просто мне не очень нравиться генерировать JS код на PHP, особенно когда без этого можно обойтись 🙂

    Согласен, но когда идет речь о выбросе кода как единой логической единицы, то можно. А преимущество есть — редактор это логика представления, и писать что-то в бизнес логике для вывода редактора неправильно [1],[2].
    ———————-
    [1]Мартин Фаулер.»Архитектура корпоративного программного обеспечения».
    [2]Мартин Фаулер.Рефаткоринг.

    • >> редактор это логика представления

      Согласен, вы правы. Но представьте ситуацию. Есть контроллер с несколькими методами, каждый из которых создает представление с редактором. В соответствии с паттерном, вы должны вызвать хелпер в каждом из этих представлений, а это — дублирование кода. Можно вызвать этот же хелпер в конструкторе и присвоить код какой-нибудь переменной, которую потом выводить в представлении.

      • Не пойму про что вы говорите. Хелпер я запускаю в шаблоне и подключаю его там же.В контроллер я вообще не лезу.Почитайте внимательно ссылку на мой блог.

        В соответствии с паттерном, вы должны вызвать хелпер

        О каком паттерне идет речь я вообще непойму.

        И никакого дублирования кода нет, накрайняк подключаю в конструкторе хелпер (а вообще правильно в шаблоне каждый раз), но в переменную загонять нет вообще смысла. Во-первых зачем ее все время передавать в шаблоны (на каждой странице). Во-вторых а если я захочу где-то вывести редактор с другими насторойками, что тогда? В -третьих — какая разница что писать в шаблоне так echo var или так echo fcke()

        • О каком паттерне идет речь

          MVC

          накрайняк подключаю в конструкторе хелпер (а вообще правильно в шаблоне каждый раз)

          Как раз об этом и речь. Правильно в представлении, а удобнее — в конструкторе контроллера.

          Согласен, разницы между echo var или так echo fcke() нет. Но если пример будет немного сложнее и нужно будет настраивать редактор (вызвать его методы), и эти настройки будут одинаковы для разных страниц шаблона, то удобнее выполнить этот код один раз в конструкторе.

          а если я захочу где-то вывести редактор с другими насторойками

          Создавать как обычно, т.е. использовать конструктор имеет смысл если редактор не меняется.

          Честно говоря, мне понравился ваш вариант, и, может быть, я буду им пользоваться… как минимум буду иметь ввиду 🙂
          Просто я хочу сказать, что бывают ситуации, когда строгое соблюдение методологий и паттернов (того же MVC) усложняет код. Этот пример не очень удачный, т.к. слишком простой и выигрыш заключается всего в паре строк кода (если он вообще есть).

  • Просто мне не очень нравиться генерировать JS код на PHP, особенно когда без этого можно обойтись 🙂

    Согласен, но когда идет речь о выбросе кода как единой логической единицы, то можно. А преимущество есть — редактор это логика представления, и писать что-то в бизнес логике для вывода редактора неправильно [1],[2].
    ———————-
    [1]Мартин Фаулер.»Архитектура корпоративного программного обеспечения».
    [2]Мартин Фаулер.Рефаткоринг.

    • >> редактор это логика представления

      Согласен, вы правы. Но представьте ситуацию. Есть контроллер с несколькими методами, каждый из которых создает представление с редактором. В соответствии с паттерном, вы должны вызвать хелпер в каждом из этих представлений, а это — дублирование кода. Можно вызвать этот же хелпер в конструкторе и присвоить код какой-нибудь переменной, которую потом выводить в представлении.

      • Не пойму про что вы говорите. Хелпер я запускаю в шаблоне и подключаю его там же.В контроллер я вообще не лезу.Почитайте внимательно ссылку на мой блог.

        В соответствии с паттерном, вы должны вызвать хелпер

        О каком паттерне идет речь я вообще непойму.

        И никакого дублирования кода нет, накрайняк подключаю в конструкторе хелпер (а вообще правильно в шаблоне каждый раз), но в переменную загонять нет вообще смысла. Во-первых зачем ее все время передавать в шаблоны (на каждой странице). Во-вторых а если я захочу где-то вывести редактор с другими насторойками, что тогда? В -третьих — какая разница что писать в шаблоне так echo var или так echo fcke()

        • О каком паттерне идет речь

          MVC

          накрайняк подключаю в конструкторе хелпер (а вообще правильно в шаблоне каждый раз)

          Как раз об этом и речь. Правильно в представлении, а удобнее — в конструкторе контроллера.

          Согласен, разницы между echo var или так echo fcke() нет. Но если пример будет немного сложнее и нужно будет настраивать редактор (вызвать его методы), и эти настройки будут одинаковы для разных страниц шаблона, то удобнее выполнить этот код один раз в конструкторе.

          а если я захочу где-то вывести редактор с другими насторойками

          Создавать как обычно, т.е. использовать конструктор имеет смысл если редактор не меняется.

          Честно говоря, мне понравился ваш вариант, и, может быть, я буду им пользоваться… как минимум буду иметь ввиду 🙂
          Просто я хочу сказать, что бывают ситуации, когда строгое соблюдение методологий и паттернов (того же MVC) усложняет код. Этот пример не очень удачный, т.к. слишком простой и выигрыш заключается всего в паре строк кода (если он вообще есть).

  • Я тут немного поворчать хочу.

    А как у FCKeditor с корректностью кода? Просто попользовавшись визуальным редактором в WordPress, я несколько негативно отношусь ко всем визуальным редактором и пользуюсь невизуальным 🙂

    На мой взгляд, это достаточно удобно и всегда уверен, что получишь именно то, что хочешь.

  • Я тут немного поворчать хочу.

    А как у FCKeditor с корректностью кода? Просто попользовавшись визуальным редактором в WordPress, я несколько негативно отношусь ко всем визуальным редактором и пользуюсь невизуальным 🙂

    На мой взгляд, это достаточно удобно и всегда уверен, что получишь именно то, что хочешь.

  • Aderba

    Здравствуйте подскажите пожалуйста как мне достать введенное значение из FCKEditor только в javascript?
    Сейчас как он работает так что вводим какие-то данные потом по нажатию submit, эти данные как-то заносятся в скрытое поля а потом уже передаются, так вот мне нужно достать данные из FCKEditor до того как нажата submit…подскажите пожалуйста как быть. Спасибо!

    • Поле редактора представляет собой iframe, который находится внутри другого iframe 🙂
      Т.е. вам нужно посмотреть разметку вашей страницы и вытянуть содержимое нужного iframe.
      Но разве не проще сделать плагин к редактору (свою кнопку)?

  • Aderba

    Здравствуйте подскажите пожалуйста как мне достать введенное значение из FCKEditor только в javascript?
    Сейчас как он работает так что вводим какие-то данные потом по нажатию submit, эти данные как-то заносятся в скрытое поля а потом уже передаются, так вот мне нужно достать данные из FCKEditor до того как нажата submit…подскажите пожалуйста как быть. Спасибо!

    • Поле редактора представляет собой iframe, который находится внутри другого iframe 🙂
      Т.е. вам нужно посмотреть разметку вашей страницы и вытянуть содержимое нужного iframe.
      Но разве не проще сделать плагин к редактору (свою кнопку)?

  • Be3

    Здравствуйте.
    Каким образом можно подключить 2ой редактор на странице ?
    Судя по коду, такая возможность не предусмотрена.

    • Be3

      Спасибо, разобрался, через __set +)

  • Be3

    Здравствуйте.
    Каким образом можно подключить 2ой редактор на странице ?
    Судя по коду, такая возможность не предусмотрена.

    • Be3

      Спасибо, разобрался, через __set +)

  • немного изменил хелпер
    http://php-velosiped.org.ua/2008/12/01/139.html
    теперь мне кажеться что это единственный правильный способ

    • Я смотрю по комментариям, вроде этот пост уже обсуждали…
      Я так понял убрана генерация JS? Это правильное решение 😉

      единственный правильный способ

      Не уверен 🙂 Хелпер, конечно, получился короткий и выглядит красиво, только что делать если потребуется доступ к методам $oFCKeditor?

      P.S. Сразу признаю, что в 99% случаев эти методы не используются 🙂

  • немного изменил хелпер
    http://php-velosiped.org.ua/2008/12/01/139.html
    теперь мне кажеться что это единственный правильный способ

    • Я смотрю по комментариям, вроде этот пост уже обсуждали…
      Я так понял убрана генерация JS? Это правильное решение 😉

      единственный правильный способ

      Не уверен 🙂 Хелпер, конечно, получился короткий и выглядит красиво, только что делать если потребуется доступ к методам $oFCKeditor?

      P.S. Сразу признаю, что в 99% случаев эти методы не используются 🙂

  • Не уверен 🙂 Хелпер, конечно, получился короткий и выглядит красиво, только что делать если потребуется доступ к методам $oFCKeditor?

    мы тогда модифицируем хелпер

  • Не уверен 🙂 Хелпер, конечно, получился короткий и выглядит красиво, только что делать если потребуется доступ к методам $oFCKeditor?

    мы тогда модифицируем хелпер

  • Владимир. Не совсем уловил разницу в $config['fckeditor_path'] и $config['fckeditor_path']. fckeditor.php обычно всегда лежит в папке с fckeditor. Ну да ладно.
    Следовал инструкции. Однако во фрейме, где должен появляться редактор, у меня «404 — страница не найдена».
    в конфигах
    $config['fckeditor_path'] = 'fckeditor/';
    $config['fckeditor_path'] = 'fckeditor/';

    редактор лежит по адресу http://www.site.ru/fckeditor
    В хтаксесс изменения внесены.

    PS С сайта оч не удобно копировать исходник ((

    • Во-первых надо так $config['fckeditor_path'] = '/fckeditor/';
      А во-вторых есть лучший способ сдесь http://php-velosiped.org.ua/2008/12/01/139.html

    • Вы, наверное, имели ввиду config['fckeditor_path'] и config['fckeditor_url']. Согласен, в большинстве случаев они совпадают, поэтому можно использовать и одну настройку.

      Я отправил вам почтой архив с рабочим примером, чтобы можно было сравнить настройки.

  • Владимир. Не совсем уловил разницу в $config['fckeditor_path'] и $config['fckeditor_path']. fckeditor.php обычно всегда лежит в папке с fckeditor. Ну да ладно.
    Следовал инструкции. Однако во фрейме, где должен появляться редактор, у меня «404 — страница не найдена».
    в конфигах
    $config['fckeditor_path'] = 'fckeditor/';
    $config['fckeditor_path'] = 'fckeditor/';

    редактор лежит по адресу http://www.site.ru/fckeditor
    В хтаксесс изменения внесены.

    PS С сайта оч не удобно копировать исходник ((

    • Во-первых надо так $config['fckeditor_path'] = '/fckeditor/';
      А во-вторых есть лучший способ сдесь http://php-velosiped.org.ua/2008/12/01/139.html

    • Вы, наверное, имели ввиду config['fckeditor_path'] и config['fckeditor_url']. Согласен, в большинстве случаев они совпадают, поэтому можно использовать и одну настройку.

      Я отправил вам почтой архив с рабочим примером, чтобы можно было сравнить настройки.

  • а как в таком варианте передать:
    $oFCKeditor->Value

  • а как в таком варианте передать:
    $oFCKeditor->Value

  • oFCKeditor->Value

    как это работает в вашем примере?

    • Насколько я понял, это вопрос к комментарию Валерия.
      Свойство Value позволяет записать текст в редактор, только использовать его нужно немного по другому.
      Например, так:
      $out.='oFCKeditor.Value = "Some text";';

  • oFCKeditor->Value

    как это работает в вашем примере?

    • Насколько я понял, это вопрос к комментарию Валерия.
      Свойство Value позволяет записать текст в редактор, только использовать его нужно немного по другому.
      Например, так:
      $out.='oFCKeditor.Value = "Some text";';

  • Evgeniyzaritskiy

    Не парьтесь ребята читайте с офф сайта как правильно конектить
    http://codeigniter.com/wiki/FCKeditor/

  • Test

    TESTTESTTESTTESTTESTTESTTESTTESTTESTTESTTESTTESTTESTTESTTESTTESTTESTTESTTESTTESTTESTTESTTESTTESTTESTTESTTESTTESTTESTTESTTESTTESTTESTTESTTESTTESTTESTTESTTESTTESTTESTTESTTESTTESTTESTTESTTESTTESTTESTTESTTESTTESTTESTTESTTESTTESTTESTTESTTESTTESTTESTTESTTESTTESTTESTTESTTESTTESTTESTTESTTESTTESTTESTTESTTESTTESTTESTTESTTESTTESTTESTTESTTESTTESTTESTTESTTESTTEST

  • Nursultan_k

    Извените? у вас изходников небудет? очень помоглобы!)

    • К сожалению, нет. Но, в любом случае, их пришлось бы немного переписать. Эта статья написана более 3-х лет назад.