При написании плагинов для ckeditor'а, часто возникает задача: необходимо получить выделенную пользователем информацию, а в некоторых случая произвести манипуляцию с ней. Если необходим просто выделенный текст, то тут все просто. У объекта editor есть метод getSelection(), он возвращает объект, который помимо полной информации о выделенном тексте содержит еще метод getSelectedText(). В простейшем случае в плагине это бы выглядело так:
CKEDITOR.plugins.add('pluginname',{ init: function(editor){ alert(editor.getSelection().getSelectedText()) } });
Надеюсь Вам понятно, что плагин работать не будет. Это псевдокод. При инициализации плагина, никакой текст не выделен.
А как же насчет html кода, для работы необходим именно он.
Я уже проводил изыскания по этому поводу ранее, с выделенным текстом можно и нужно работать. Но только в API редактора таких методов, увы, нет. Вновь берем в руки молоток редактор и ваяем свой велосипед. Метод подсмотрен на одном из формуов
function getSelectionHTML(selection){ var range = (document.all ? selection.createRange() : selection.getRangeAt(selection.rangeCount - 1).cloneRange()); if (document.all){ return range.htmlText; }else{ var clonedSelection = range.cloneContents(); var div = document.createElement('div'); div.appendChild(clonedSelection); return div.innerHTML; } }
Берем выделенную часть html кода в виде htmlFragment. У API ckeditor'а есть своя кроссбраузерная надстройка над этим объектом. Далее если это Internet Explorer, то у него есть поле htmlText у объекта типа range. При этом - это «нативный» range, не тот который возвращает метод selection.getRanges().
Если это не Internet Explorer, а любой другой браузер, то используются методы копирования фрагмента кода cloneContents, затем этот фрагмент закидывается в div, и уже у него берется внутреннее содержимое.. Вот такие костыли. Пол веба на этом работает, скажу я Вам.
Это не единственный способ получить содержимое выделенного фрагмента. Приведу еще одну реализацию:
CKEDITOR.editor.prototype.getSelectedHtml = function(){ var selection = this.getSelection(); if( selection ){ var bookmarks = selection.createBookmarks(), range = selection.getRanges()[ 0 ], fragment = range.clone().cloneContents(); selection.selectBookmarks( bookmarks ); var retval = "", childList = fragment.getChildren(), childCount = childList.count(); for ( var i = 0; i < childCount; i++ ){ var child = childList.getItem( i ); retval += ( child.getOuterHtml? child.getOuterHtml() : child.getText() ); } return retval; } };
Тут более хитрый костыль. Мы добавили редактору метод getSelectedHtml, и далее а плагине можно уже использовать его напрямую. Примерно так:
CKEDITOR.plugins.add('pluginname',{ init: function(editor){ alert(editor.getSelectedHtml()) } });
Опять псевдокод. Но это ведь не статья про то, как писать плагины на ckeditor. Метод описанный выше кстати не просто удобней, он еще и не создает лишних div блоков. А просто перебирает выделенный фрагмент по его потомкам.
selection.getRanges()[ 0 ] - если кому не понятно, то по некоторой логике (в некоторых браузерах), при нажатии ctrl, можно перенести курсор в другое место, и выделить там другую часть страницы и получить несколько выделений. Этого нам не надо, сколько я не пытался, повторить такое мне не удалось. Так что берем только самое первое.
bookmarks = selection.createBookmarks()- насколько я понял, необходимо для плагинов undo и redo. Если Вы вдруг, каким-то мистическим образом смогли изменить html код в странице, то плагин undo поможет Вам вернуть все на место.
Почему мистическим? Потому, что если Вам это удалось, то Вы наверняка уже владелец виллы в Барселоне, и яхты, там же, и вообще Вы очень успешный человек. Я говорю так, потому, что заработать на яхту и виллу задача весьма нетривиальная, как и заменить незакрытый тег. Подумайте сами, пользователь может выделать на странице все, что угодно. К примеру часть параграфа, захватив закрывающий </p>
. Но не захватив открывающий. Как себя должна вести себя замена, известно наверно только всевышнему.
Максимум, который мне удалось достичь - это метод editor.insertHtml('html').
В обычном случае, метод просто вставляет в страницу код, но если часть страницы выделено, то метод произведет ее замену. Работает это все мягко говоря странно. Я бы сказал, что в сложносочиненных страницах, с таблицами, оно работает не так, как хотелось бы.
Если Вам все же захотелось сделать прямую замену, читаем мою старую статью или используем готовый код. CKEditor заботливо предоставляет нам метод getNative у selection. Дальше работаем, с этим объектом исходя из методов браузера. Все понятно? Если нет, пишите в комментах вопросы, я объясню.