2009-10-19

FCKeditor + Pylons

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

Все это распрекрасно, с одним маленьким НО - он не готов для прикручивания к пилонам. Нет, конечно разработчики учли присутствие на белом свете языка Python (в наличии также коннекторы для asp, aspx, cfm, lasso, perl, php). Но только как wsgi. Через mod_python, cgi - пожалуйста, все почти готово. А для меня - не очень. Поискав в интернете ответ, так и не нашел толкового пошагового решения. Потому, набив кучу шишек, представляю мое HowTo:

Как прикрутить FCKeditor к Pylons, пошаговое руководство

Создадим проект, к примеру "myapp":

$ paster create -t pylons myapp
$ cd myapp

Идем на http://ckeditor.com/download и скачиваем последнюю версию FCKeditor. Вероятно, новее уже не будет, потому что разработчики переключились на новые продукты - CKeditor и CKFinder, которые по сути - редактор и менеджер файлов по отдельности. Кстати, другой известный WYSIWYG редактор, TinyMCE, идет подобной дорогой (у него нет поддержки Python, кстати). И я бы выбрал этот новенький, красивенький CKeditor, если бы не одно обстоятельство - разработчики тоже не сделали поддержки для Python. Может быть появится попозже. Может быть я сам как-нибудь займусь и перепишу коннектор для него. Может быть. А пока - продолжим.

Извлечем из архива папку fckeditor в myapp/public/

Создадим шаблон myapp/templates/index.mako вот такого вида:

#coding:utf8
<html>
<head>
    <title>FCKEditor</title>
    <script type="text/javascript" src="/ckeditor/ckeditor.js"></script>
</head>
<body>
<script type="text/javascript" src="/fckeditor/fckeditor.js"></script>
    <form action="" method="post" target="_self">
        <input type='hidden' name='body' id='body' value='Hello World' />

        <script type="text/javascript">
            var oFCKeditor = new FCKeditor() ;
            oFCKeditor.BasePath = '/fckeditor/';
            oFCKeditor.ToolbarSet='Default'
            oFCKeditor.Height    = 300 ;
            oFCKeditor.InstanceName = 'body' ;
            oFCKeditor.Create() ;
        </script>
    </form>
</body>
</html>

Удалим файл myapp/public/index.html
Создадим контроллер index:

 $ paster controller index

В контроллере myapp/controller/index.py в классе IndexController укажем отобразить вышесозданный шаблон:

class IndexController(BaseController):
    def index(self):
        return render("/index.mako")


Пропишем путь в myapp/config/routing.py для корня нашего сайта:

    # CUSTOM ROUTES HERE
    map.connect('/',controller='index',action='index')

Запустим сервер:

$ paster serve --reload development.ini

Теперь в нашем любимом браузере по адресу localhost:5000 видим - редактор уже присутствует. И он работает, получить данные при нажатии кнопки сохранения можно через request.POST['body'].
Вам больше ничего и не надо? Тогда заканчиваем читать здесь. А мне еще нужно осуществить загрузку файлов на сайт и просмотр их на сервере.

Создадим контроллер fckeditor, в который будем направлять запросы редактора на просмотр и загрузку файлов:


$ paster controller fckeditor

Добавим в файл myapp/config/routing.py пути роутинга, чтобы приложение обращалось не к файлам в своем базовом каталоге, а к нашему контроллеру. По умолчанию, в файлах конфигурации FCKeditor все настроено на работу с php.


    # CUSTOM ROUTES HERE
    map.connect('/fckeditor/editor/filemanager/connectors/php/*path_info', controller='fckeditor')
    map.connect('/',controller='index',action='index')

В файле myapp/controllers/fckeditor.py перед объявлением класса добавим путь к нашим файлам Python-коннекторов, идущих в комплекте с FCKeditor, и импортируем из них нужные классы.

import sys
sys.path.append("/media/disk/Projects/myapp/myapp/public/fckeditor/editor/filemanager/connectors/py")
from connector import FCKeditorConnector
from upload import FCKeditorQuickUpload


Также не забудьте удалить или переименовать папку myapp/public/fckeditor/editor/filemanager/connectors/php, иначе пилоны найдут эту папку и предпочтут брать файлы оттуда, игнорируя правило, прописанное в routing.py

Теперь, собственно, класс FckeditorController из myapp/controllers/fckeditor.py

class FckeditorController(BaseController):
    def __call__(self,environ,start_response):
        id=environ['wsgiorg.routing_args'][1]['path_info']
        if id=='connector.php':
            environ['SCRIPT_FILENAME'] = 'connector.py'
            conn = FCKeditorConnector(environ)
        elif id == 'upload.php':
            environ['SCRIPT_FILENAME'] = "upload.py"
            conn = FCKeditorQuickUpload(environ)
        else:
            start_response ("200 Ok", [('Content-Type','text/html')])
            yield "Unknown page requested: "
            yield environ['SCRIPT_NAME']
            return
        data = conn.doResponse()
        start_response ("200 Ok", conn.headers)
        yield str(data)


Для нашего удобства настроим myapp/public/fckeditor/fckconfig.js. Пусть Интерфейс будет русским!

FCKConfig.AutoDetectLanguage    = false ;
FCKConfig.DefaultLanguage        = 'ru' ;

Добавим в настройках development.ini каталог для загрузок и хранения файлов:

[DEFAULT]
static_store = %(here)s/myapp/public/upload

Если вы сами не создадите эту папку - Pylons умница сделает это за вас.
Теперь немного пошаманим в настройках коннектора
myapp/public/fckeditor/editor/filemanager/connectors/py/config.py

Enabled = True
UserFilesPath = '/upload/'
from pylons import config
UserFilesAbsolutePath = config['static_store']+'/'


И наконец, последний штрих - внесем парочку измененеий в файл
myapp/public/fckeditor/editor/filemanager/connectors/py/fckcommands.py
а именно в класс UploadFileCommandMixin:

class UploadFileCommandMixin (object):
    from pylons import request
    # Заменить if self.request.has_key("NewFile"): на
    if request.POST.has_key("NewFile"):
        # Заменить newFile = self.request.get("NewFile", "") на
        newFile = request.POST["NewFile"]

Вот вроде и всё. Теперь на стартовой странице будет виден редактор на русском языке, который может работать с загружаемыми файлами. Надеюсь, кому-нибудь помогут мои мытарства.

2009-10-02

Как подружить Pidgin и Facebook

По состоянию на 1 октября 2009 года, стандартные пакеты из репозитария не позволяют подключаться к Facebook-чату, выдает ошибку соединения или неправильный логин-пароль. Как лечить:
Раз: http://mirror.ne.gov/ubuntu/pool/universe/j/json-glib/libjson-glib-1.0-0_0.7.6-0ubuntu1_i386.deb
Два: http://pidgin-facebookchat.googlecode.com/files/pidgin-facebookchat-1.61.deb
Это просто обновленные пакеты, которых пока нет в репозитариях.
Устанавливаем их по порядку, запускаем Pidgin, создаем аккаунт типа Facebook-чат - и плагин начинает работать. Чудеса!