Добавляем ссылки на страницы сайта в CKEDITOR 4

в 9:30, , рубрики: ckeditor, javascript, web-разработка, Веб-разработка, метки: , ,

Доброго времени суток, читатель!

Очень часто приходится писать мини CMS для разных проектов. Обосновано это, в большей степени, человеческой ленью. Поэтому в такие проекты часто добавляю очень удобный редактор CKEDITOR. И часто заказчики просят сделать удобный функционал для добавление ссылок на материалы сайта. В сети есть много описаний подобного процесса, но большинство рассчитаны на версии < 4. Недавно столкнулся с необходимостью внедрения данной функции в редактор.
Если тебе, дорогой читатель, интересно как это реализовать, милости прошу под кат.

Постановка задачи

Делая CMS даже малых размеров, очень часто приходится давать инструменты, позволяющие обойтись без программистов и верстальщиков, для размещения материалов на сайте. С одной стороны, можно просто вставить редактор и рассказать, каким образом обрезать ссылки из адресной строки, чтобы все работало. Но, как это часто бывает, исполнитель меняется или забывает как это делается.
Поэтому будем добавлять функционал для простого добавления ссылок на разделы/материалы CMS.
Что же мы хотим иметь в конечном итоге? Мы хотим иметь простой способ выбора материала для генерации ссылки на него. Сделаем это с помощью выпадающего списка.

Первый шаг

Будем считать, что мы уже загрузили архив с CKEDITOR и распаковали в папку с проектом (для удобства будем считать, что это папка Scripts). Таким образом, у наш редактор лежит по пути /Scripts/ckeditor

Что дальше?

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

Немного теории

Практически во всех мануалах, посвященных данной проблеме, авторы создают скрытый input и «запихивают» в него данные. Но это не является безоговорочным способом. Мы вполне можем объявить глобальную переменную, в которую будут помещаться данные, и на ее основе инициализировать список. Я не буду особенно углубляться в такие дебри, так как это никак не связано с темой статьи, поэтому просто опишу вариант, показанный в других мануалах.
Одной из особенностей списка, передаваемого в качестве параметра является то, что он должен быть JSON объектом и представлять собой массив строковых массивов.
Таким образом конечный объект будет примерно таким:

[['Главная','/index.html'],['Галерея','/images.html'],['Контакты','/about.html'].....]

Каким образом формировать такой список решать разработчику. Ограничений нет.
Осталось только добавить на страницу контейнер, в который мы положим наш список. Давайте создадим скрытый input, который будет выглядеть примерно так:

    <input type="hidden" id="localPageList" value="[['Главная','/index.html'],['Галерея','/images.html'],['Контакты','/about.html'].....]" />

Вот мы и подготовили данные для работы.

Идем дальше

Вот теперь мы полезем в скрипты. Первым делом откроем скрипт, который создает диалог выбора ссылки /Scripts/ckeditor/plugins/link/dialog/link.js
Находим слова

id: "linkType", type: "select"

(скрипт минифицирован, поэтому искать не очень удобно. я его отформатировал, для большего удобства работы)
и добавляем следующие строки

return {
        title: b.title, minWidth: 350, minHeight: 230, contents: [{
            id: "info", label: b.info, title: b.info, elements: [{
                id: "linkType",
                type: "select",
                label: b.type,
                "default": "localPage",
                items: [
                    [b.toUrl, "url"],
                    [b.localPage, 'localPage'],
                    [b.toAnchor, "anchor"],
                    [b.toEmail, "email"]],
                onChange: function () {
                    var a =
                    this.getDialog(), b = ["urlOptions", "localPageOptions", "anchorOptions", "emailOptions"], c = this.getValue(), d = a.definition.getContents("upload"), d = d && d.hidden; if (c == "url") { n.config.linkShowTargetTab && a.showPage("target"); d || a.showPage("upload") } else { a.hidePage("target"); d || a.hidePage("upload") } for (d = 0; d < b.length; d++) { var e = a.getContentElement("info", b[d]); if (e) { e = e.getElement().getParent().getParent(); b[d] == c + "Options" ? e.show() : e.hide() } } a.layout()
                }, setup: function (a) { a.type && this.setValue(a.type) }, commit: function (a) {
                    a.type =
                    this.getValue()
                }
            },
//Наш тип ссылок
            {
                type: 'vbox',
                id: 'localPageOptions',
                children: [
                {
                    type: 'select',
                    label: 'Страница сайта',
                    id: 'localPage', //Название "типа ссылки". Оно нам еще понадобится
                    title: 'Выберите страницу сайта, на которую хотите ссылаться',
                    items: eval(document.getElementById("localPageList").value), //берем данные из input'а localPageList
                    setup: function (data) {
                        if (data.localPage)
                            this.setValue(data.localPage);
                    },
                    commit: function (data) {
                        if (!data.localPage)
                            data.localPage = {};
                        data.localPage = this.getValue();
                    }
                }]
            },
//#Наш тип ссылок

Надеюсь, что здесь все понятно.

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

Открываем новый тип ссылки в диалоге

Для того, чтобы созданный тип ссылки появился в диалоге, мы должны добавить его в список инициализации.
Ищем следующую строку кода:

b = ["urlOptions", "anchorOptions", "emailOptions"]

и добавляем в нее строку «localPageOptions», чтобы получилось так:

b = ["urlOptions", "localPageOptions", "anchorOptions", "emailOptions"]

Теперь, запустив редактор и открыв диалог ссылок мы видим… мы видим пункт «undefined».
«Вот это облом»! — подумал я, когда впервые увидел это.
Но, покопавшись немного в коде я понял, что диалог пытается найти название для нашего типа в файлах локализации. И не найдя ничего просто присваивает undefined переменной, которая должна хранить название. Решаем эту проблему добавлением всего одной строчки кода в файл/файлы(если вы используете несколько локализаций).

Правка локализации

Открываем файл /Scripts/ckeditor/lang/ru.js (en.js для английской локализации).
Выполняем поиск по словам:

"title": "Ссылка" //для русской локализации
"title": "Link"      //для английской локализации

и через запятую добавляем строку:

"localPageList": "Страница сайта" //для русской локализации
"localPageList": "Local page"          //для английской локализации

где localPageList- название нашего типа ссылок, указанного как параметр id

Вместо заключения

Не тривиальная на первый взгляд задача отняла у меня 1,5-2 часа времени. Все мануалы, которые были найдены мной в сети, написаны для CKEDITOR версии 2 и 3. В четвертой версии многое изменилось и пришлось исследовать код, чтобы адаптировать под новый API. Такой опыт полезен, но иногда бывает очень нужно сделать все быстро.
Поэтому надеюсь, что мой пост оказался кому-нибудь полезным.

Автор: ParaPilot

Источник

Поделиться

* - обязательные к заполнению поля