ASP.NET MVC: Редактируем Html в CKEditor через Knockout
Сайтостроение | создано: 04.02.2013 | опубликовано: 04.02.2013 | обновлено: 13.01.2024 | просмотров: 12988 | всего комментариев: 11
В этой статье при помощи Knockout будем редактировать Html-код в WYSIWYG редакторе CKeditor.
Введение
Редактирование html-кода достаточно тривиальная задача. Если учесть, что количество WYSIWYG-редакторов в сети огромное количество, то единственным объяснением, почему именно взят именно CKeditor это то, что я с ним работаю уже более 6 лет, а еще этот редактор может в загружать файлы (например, картинок или флэш) на сервер (правда для этого используется модуль CKFinder).
Тестовый проект
Сразу к делу. Создаю новый проект. Mvc будет 4-ый, .Net пусть будет 4.5, потому как это не принципиально для Knockout. После того как проект создала Visual Studio запускаю команду обновления всех nuget-пакетов. Теперь когда проект почти готов, надо бы загрузить и установить сам редактор CKEditor. Иду по ссылки и качаю последнюю версию (на момент написания статьи версия 4.0.1). Распаковываю архив и (для экономии времени) закидываю всю папку ckeditor в корень проекта. По идеи можно было бы "почистить" немного папку, удалив файлы примера и ненужные плагины, а еще файлы справки (всё равно их никто не читает).
Классы и формы
Создаю новый класс, который будет использоваться… Не будет у меня никаких классов, ибо цель данной статьи показать другое. Ставим новый nuget-пакет, который называется JsSite:
PM> install-package jssite Successfully installed 'JsSite 0.3.0'. Successfully added 'JsSite 0.3.0' to CKEditor_Knockout. PM>
После установки этого пакета, в папке Scripts появилась еще одна папка App. В этот папке набор полезных файликов (немного описания можно найти в статье), которые я сделал, чтобы ускорить разработку проектов такого типа как этот. Просто и быстро. Далее...
Для начала удаляю содержание представления (view) в Home/Index.cshtml, потому что буду писать новую разметку под Knockout. А теперь немного кода на JavaScript.
/// <reference path="../knockout-2.2.1.debug.js" /> /// <reference path="site.services.js" /> /// <reference path="site.controls.js" /> /// <reference path="site.core.js" /> $(function () { "use strict"; site.vm.homeIndex = function () { var meta = new site.fw.Metadata("Демонстрация редактирования HTML", "Данный CKEditor используется в связке с Knockout. Дополнительные инструкции в статье.", "http://www.calabonga.net/blog/post/107"), title = ko.observable("Этот текст редактируется!"), html = title, save = function () { alert("Сохранилось! " + html()); }; return { title: title, save: save, meta: meta, html: html }; }(); ko.applyBindings(site.vm.homeIndex); });
В строке 6 создается viewModel для страницы, а в строке 24 осуществляется привязка.
В строке 10 создаем поле, которое я и собираюсь редактировать. А 11-ой я создаю временную переменную, дальше будет понятно.
Теперь немного много разметки. Вся форма (представление Index) целиком:
@{ ViewBag.Title = "Home Page"; } <h1 data-bind="text: meta.title"></h1> <p> <span data-bind="text: meta.description"></span> <a data-bind="attr: {href: meta.helplink}"> <img style="border: 0" src="~/Images/help.png" alt="" /></a> </p> <p><span data-bind="html: title"></span></p> <p> <input id="html" name="html" data-bind="ckeditor: html" type="text" value=" " /> </p> <p> <button data-bind="click: save">сохранить</button> </p> @section scripts { <script src="~/ckeditor/ckeditor.js"></script> <script src="~/Scripts/knockout-2.2.1.js"></script> <script src="~/Scripts/app/site.bindingHandlers.js"></script> <script src="~/Scripts/app/site.core.js"></script> <script src="~/Scripts/app/site.controls.js"></script> <script src="~/Scripts/app/site.services.js"></script> <script src="~/Scripts/app/site.vm.homeIndex.js"></script> }
Ключевыми строчками кода является 13 (прекрасный номер для главной строки, не правда ли?) и строчка номер 23. В 13-ой посмотрите на атрибут data-bind и, соответственно, на ckeditor (код может скачать и посмотреть). В 24 строке как раз, тот самый custom binding.
Запускаем
Отобразился редактор – уже хорошо! Попробуем чего-нибудь написать в редакторе:
Работает!
Заключение
В качестве заключения хочется сказать следующее. У меня задача была редактировать только свойства типа ko.observable(), поэтому я сделал свойство html в моделе и делаю привязку к нему.
Редактировать простой текст простого свойства из Literal Object не получится.
Комментарии к статье (11)
Салабонга, подскажи пожайлуста как увязать CKEidtitor c моделью.
EF для вьюхи генерирует код эдитора
@Html.EditorFor(model => model.Field)
как сделать, чтоб из
<input id="html" name="html" data-bind="ckeditor: html" type="text" value=" " />
текст отправлялся в model.Field
Всё очень просто, камаз:
добавляешь ссылки на скрипты:
<script src="@Url.Content("~/ckeditor/ckeditor.js")"></script>
в разметке ставишь так:
<div class="editor-field"> @Html.TextAreaFor(model => model.Content, new { @class = "editor", id = "editorSmall" })<br /> @Html.ValidationMessageFor(model => model.Content) </div>
и скрипты для подключения к разметке:
var editorel = $('#editorSmall').val(); if (editorel != undefined) { var editor = CKEDITOR.replace('editorSmall', { toolbar: [['Bold', 'Italic', 'Underline', 'Strike']] }); $('form').submit(function (e) { for (instance in CKEDITOR.instances) { CKEDITOR.instances[instance].updateElement(); } var content = unescape(CKEDITOR.instances.editorSmall.getData()); if ($('form').valid() && content.length > 0) { return true; } else { alert('Кажется, есть ошибки при заполнении формы!'); return false; } }); }
почему-то у меня не получилось, сделал всё как вы написали только остались непонятки со скриптом для подключения к разметке.. засовывал его и ваши .js файлы в папке app и подключал отдельным файлом, и даже вешал на страницу внутри тега <script>
я всё понял, спасибо огромнейшее))
кстати нашёл совсем тривилаьное решение
<script type="text/javascript">
CKEDITOR.replace('Content');
CKEDITOR.editorConfig = function (config) {
ignoreEmptyParagraph = true;
};
</script>
CKEDITOR.replace('Content');
прекрасно работает, вот только если потребуется "поиграться" с валидацией, придется воспользоваться тем методом, что предложил я... :)
Добрый день!
Ваш код не работает, если на странице много ckeditor'ов. Подскажите пожалуйста как исправить код ko.bindingHandlers.ckeditor ?
Я вообще не очень понимаю, что означает эта строчка:
options.editor = CKEDITOR.replace(element, options);
точнее зачем она нужна, зачем так сохранять эдитор?
rhot, Честно говоря, я не ставил перед собой задачу отображать на странице более одного редактора. Я запустил, проверил, действительно, не работает! На данный момент, к сожалению не располагаю достаточным количеством времени, чтобы заняться проблемой. Но как только, так сразу.
rhot, CKEDITOR.replace(element, options); - он заменяет textarea с id = element на ckeditor, то есть елы ты хошеь много ckeditorов, тебе нужно написать заменитель на каждый id контролла.
rhot
Вы всё правильно сделали поправив код. Дело в том что я хранил настройки в одном месте для всех инстансов, у меня не стояло задачи "иметь много на странице". Убрав этот функционал, вы "разрешили" использовать несколько инстансов на одной странице. Всё правильно.
Спасибо за пост.
Хочу добавить, чтобы бинд был "двустороний" и сразу подтягивался текст в редактор, то в bindingHandlers в update нужно дописать:
CKEDITOR.instances[element.id].setData(value);