Как Интегрировать Ckeditor В Angularjs

Доброго времени суток уважаемые хабровчане.

Активно пользуюсь уже несколько месяцев.

AngularJS в одном из рабочих проектов.

Я не буду петь «хвалебные песни» или превозносить эти рамки, потому что идеальных вещей не бывает (и, наверное, было бы очень скучно жить в мире с такими вещами, которые не оставляют возможности преодолевать свои недостатки своим «творчеством»).

»).

Скажу лишь несколько слов о результатах: идеология AngularJS очень хорошо справляется с организацией кода и предоставляет волшебный инструмент Directives. Кстати, недавно была заметка про CornerJS , в котором директивы вынесены в центр технологий, а на Google I/O в этом году проскочила новость о возможной поддержке пользовательские элементы (не просто теги, а сложные html-компоненты, встроенные в страницу).

На следующем этапе разработки встал вопрос об интеграции с продвинутым WYSIWYG-редактором и мой взгляд сразу упал на ckEditor , так как я уже несколько раз использовал его в проектах на базе DotNetNuke и впечатления были очень положительные (или, скажем по-другому: серьезных недостатков в компоненте обнаружено не было, а интеграция заняла считанные часы).

Умоляя Google помочь с магией интеграции, я получил несколько ссылок на Stackoverflow и другие частные блоги, где решение всех проблем — событие.

пастастате а директива в целом выглядит просто и доступно:

  
   

app.directive('ckEditor', [function () { return { require: 'ЭngModel', link: function ($scope, elm, attr, ngModel) { var ck = CKEDITOR.replace(elm[0]); ck.on('pasteState', function () { $scope.$apply(function () { ngModel.$setViewValue(ck.getData()); }); }); ngModel.$render = function (value) { ck.setData(ngModel.$modelValue); }; } }; }]);

Но после очередного мэйлстоуна и деплоя заказчик стал замечать, что иногда редактируемый текст не полностью сохраняется или компонент даже вылетает с Access Violation, в случае с ранними версиями InternetExplorer(< 9).

The problem was reproduced, ideal conditions were obtained and I went to look for a solution to the problem. Перечитав еще раз документацию и поковыряв страницу для общей картины, я пришел к выводу, что это событие прекрасно работает с клавиатурой, но полностью игнорирует вставку элементов (будь то текст, картинки и т.п.

) из включенных плагинов.

Сразу было решено искать новое мероприятие, носившее более глобальный характер.

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

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

изменять на уровне нативного API (возможно, они просто интегрировали вышеупомянутый плагин в ядро; я, честно говоря, не следил за историей).

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

Наученный горьким опытом неожиданно возникнуть окна для IE < 9 (IE splits the execution of different windows into different threads with a complete reset of cookies, etc.) I came to the conclusion that the problem is in the iframe component and the sequence of creating and accessing it inside ckEditor itself, as well as the life cycle объем в AngularJS. Проблема связана с тем, что метод CKEDITOR.replace(.

) в старом IE работает асинхронно и «освобождая» контекст выполнения AngularJS пытается привязать модель и вызвать setData , который пытается получить доступ к iframe, который еще не готов, что вызывает нарушение прав доступа.

Ничего «лучше» или «надёжнее», чем очередь, я придумать не смог, поэтому в результате получился следующий код директивы:

app.directive('ckEditor', [function () { return { require: 'ЭngModel', restrict: 'C', link: function (scope, elm, attr, model) { var isReady = false; var data = []; var ck = CKEDITOR.replace(elm[0]); function setData() { if (!data.length) { return; } var d = data.splice(0, 1); ck.setData(d[0] || '<span></span>', function () { setData(); isReady = true; }); } ck.on('instanceReady', function (e) { if (model) { setData(); } }); elm.bind('$destroy', function () { ck.destroy(false); }); if (model) { ck.on('change', function () { scope.$apply(function () { var data = ck.getData(); if (data == '<span></span>') { data = null; } model.$setViewValue(data); }); }); model.$render = function (value) { if (model.$viewValue === undefined) { model.$setViewValue(null); model.$viewValue = null; } data.push(model.$viewValue); if (isReady) { isReady = false; setData(); } }; } } }; }]);

В коде есть неоднозначные моменты, связанные со значениями очереди и model.$viewValue (в частности, это были попытки бороться с зависанием компонентов в модальных диалогах, что решалось патчем модального компонента twitter bootstrap, но это уже другая история ).

Также я не до конца раскрыл моменты, связанные с setData(.

,callback), который по сути является одним из механизмов синхронизации, но мне кажется, что в этом контексте код выглядит информативно и будет заменять слова.

Выслушаю предложения и критику по поводу данного подхода.

P.S. Рабочий пример того, что я получил http://jsfiddle.net/jWANb/2/ Рабочий пример того, что рекомендуют в Интернете http://jsfiddle.net/fvApg/1/ Попробуйте вставить изображение во второй пример и посмотрите на «результат html».

Будет ясно, что контекст не изменился.

Теги: #angularjs #CKEditor #WYSIWYG #разработка веб-сайтов #JavaScript #angular

Вместе с данным постом часто просматривают: