Imperavi Redactor — визуальный редактор для Yii Framework 1.1 / Студия Виталия Комлева, разработка веб-сайтов Харьков

Imperavi Redactor — визуальный редактор для Yii Framework 1.1

Веб-дизайн и аналитика

Imperavi Redactor — один из лучших WYSIWYG-редакторов на jQuery.

В процессе проектирования панели управления для одного из своих ранних проектов я был поставлен перед вопросом выбора визуального редактора. Критерии были примерно следующие: легкий (в то время интернет-соединение было не ахти какое быстрое), без тормозов в работе и «случайных» сбоев с потерей текста, функциональный и красивый. Топовые на тот момент FCKEditor и TinyMCE казались мне похожими на неандертальцев: большие, неповоротливые, страшные. Впрочем, прямых конкурентов у них практически не было: большинство решений кое-как справлялись с разметкой, но вопрос загрузки изображений и файлов деликатно обходили стороной.

Найденный мной Imperavi Redactor был не то, чтобы сильно удобнее, но однозначно красивее как WYSIWYG-монстров, так и маленьких редакторов. Впрочем, со временем команда разработчиков более чем восполнила недостаток функционала. На сегодняшний день этот инструмент позволяет:

  • создавать основную разметку текста (жирный, курсив, подчеркивание, списки, выравнивание, таблицы, ссылки)
  • загружать в текст изображения
  • загружать файлы
  • помимо базовых функций есть большая база расширений-плагинов, которая постоянно пополняется

На данный момент скрипт является платным, однако сообщество разработчиков Yii Framework приобрело OEM-лицензию, которая позволяет пользоваться редактором в Yii-проектах.

Как установить Imperavi Redactor?

После скачивания расширения распаковываем его в папку protected/extensions/.

Далее, в проекте импортируем расширение в конфигурационном файле или подключаем виджет на странице:

Yii::import('ext.imperavi-redactor-widget.ImperaviRedactorWidget');

Вызываем виджет:

$this->widget('ImperaviRedactorWidget', array(
    // Можно использовать для атрибута модели  
    'model' => $my_model,
    'attribute' => 'my_field',
    // или для обычного текстового поля
    'name' => 'my_input_name',
    // Больше опций на <a href="http://imperavi.com/redactor/docs/">http://imperavi.com/redactor/docs/</a>
    'options' => array(
        'lang' => 'ru',
        'toolbar' => false,
        'iframe' => true,
        'css' => 'wym.css',
    ),
));

Более подробно об этом рассказано на странице расширения.

Как настроить загрузку изображений и файлов?

Помимо настройки визуального редактора понадобится также добавить функционал обработки данных в контроллер. Imperavi Redactor позволяет как загрузить изображение, так и выбрать его из списка уже загруженных. Рассмотрим первый вариант.

Настраиваем виджет:

$this->widget('ImperaviRedactorWidget', array(
    'selector' => '.redactor',
    'options' => array(     
        'imageGetJson' => Yii::app()->createAbsoluteUrl('/site/imageGetJson'),
        'imageUpload' => Yii::app()->createAbsoluteUrl('/site/imageUpload'),
        'clipboardUploadUrl' => Yii::app()->createAbsoluteUrl('/site/imageUpload'),
        'fileUpload' => Yii::app()->createAbsoluteUrl('/site/fileUpload')
    )
));

Создаем экшн в контроллере, например в SiteController, при этом не забывая о политике безопасности:

public function accessRules() {
    return array(
        array('allow',
            'actions'=>array('index'),
            'users'=>array('*'),
        ),
        array('allow',
            'actions'=>array('imageUpload', 'imageGetJson', 'fileUpload'),
            'users'=>array('admin'),
        ),
        array('deny',
            'users'=>array('*'),
        ),
    );
}

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

При загрузке изображения я советую сразу делать и превью, чтобы выдавать его в списке загруженных. Сам экшн загрузки изображения actionImageUpload может выглядеть так:

public function actionImageUpload() {
    $image=CUploadedFile::getInstanceByName('file');
    $filename = 'a_'.date('YmdHis').'_'.substr(md5(time()), 0, rand(7, 13)).'.'.$image->extensionName;
    $path = dirname(__FILE__).'/../../resources/articles/'.$filename;
    $image->saveAs(dirname(__FILE__).'/../../resources/articles/'.$filename);
    $image_open = Yii::app()->image->load(dirname(__FILE__).'/../../resources/articles/'.$filename);
    if (isset($image_open)) {
        if ($image_open->width > $image_open->height) $dim = Image::HEIGHT; else $dim = Image::WIDTH;
        $image_open->resize(100, 100, $dim)->crop(100, 100);
        $image_open->save(dirname(__FILE__).'/../../resources/articles/thumbs/'.$filename);
    }
    $array = array(
        'filelink' => Yii::app()->request->hostInfo.'/resources/articles/'.$filename,
        'filename' => $filename
    );
    echo stripslashes(json_encode($array));
}

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

public function actionFileUpload() {
    $file=CUploadedFile::getInstanceByName('file');
    $filename = md5(time()).'.'.$file->extensionName;
    $path = dirname(__FILE__).'/../../resources/articles/'.$filename;
    copy($_FILES['file']['tmp_name'], $path);
    $array = array(
        'filelink' => Yii::app()->request->hostInfo.'/resources/articles/'.$filename,
        'filename' => $filename
    );
    echo stripslashes(json_encode($array));
}

При формировании списка загруженных изображений воспользуемся папкой с превью, которые мы бережно генерировали при загрузке:

public function actionImageGetJson() {
    $dir = dirname(__FILE__).'/../../resources/articles/thumbs/';
    $files = array();
    if (is_dir($dir)) {
        if ($dh = opendir($dir)) {
            while (($file = readdir($dh)) !== false) {
                if ($file != '.' && $file != '..')
                    $files[] = array(
                        'thumb' => Yii::app()->request->hostInfo.'/resources/articles/thumbs/'.$file,
                        'image' => Yii::app()->request->hostInfo.'/resources/articles/'.$file,
                        'title' => $file,
                    );
            }
            closedir($dh);
        }
    }
    echo json_encode($files);
}

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

Полезным будет не просто загружать на сервер все, что присылается из визуального редактора. Изображения зачастую можно (и нужно) ужимать до более-менее адекватного размера. Обычно 1500 пикселей по большей стороне хватает с головой, тогда как клиент может грузить на сайт исходник фотографии размерами 4000х3000 пикселей.

Интересным будет также вопрос хранения названий файлов в понятном виде: приятнее скачивать файл «Прайсы за 21.10.2014.xls», чем какой-нибудь «20141021150314_4fsedf9sdfs.xls». Но хранить в папке «разношерстную» компанию таких «прайсов» тоже не лучший вариант, особенно когда начинается разное «Прайсы за 21.10.2014 (1).xls», «Прайсы за 21.10.2014 (2).xls» и так далее. У кого есть хорошее решение, которое дает универсальность переименованных файлов и удобство человекопонятных названий — дайте знать.