Опубликован: 22.10.2016 | Уровень: для всех | Доступ: платный
Лекция 3:

Редактирование на странице и CSS

< Лекция 2 || Лекция 3: 1234 || Лекция 4 >

Редактирование WYSIWYG (копируем текст из Word'а)

Обычно при словах "визуальный редактор" мы сразу вспоминаем многомегабайтные чудовища, название которых как бы в насмешку начинается с "tiny...". Но мы-то пытаемся сделать настоящее tiny. Поэтому начнём с простого: если человек скопирует текст из Ворда и вставит в поле textarea, то при сохранении всё форматирование пропадёт. Ладно ещё пропадёт жирность, но ведь не будет ни абзацев, ни таблиц, ни списков... сплошной массив текста. Самое большее, что мы можем сделать в этом случае для сохранения структуры, – при выводе на сайте отображать разрывы строк с помощью nl2br.

Пара килобайт javascript может довольно существенно улучшить положение. Во-первых, добавим в форму редактирования элемент div с атрибутом contenteditable и сделаем его основным для редактирования. При любых изменениях текста в нём, будем передавать его innerHTML в скрытое по умолчанию поле textarea.

Во-вторых, добавим сразу кнопку "Код HTML", которая по желанию пользователя будет отображать скрытое поле (чтоб можно было всё контролировать).

В-третьих, у нас проблема на сервере: не будем же мы, в самом деле, разрешать какие угодно тэги – пусть не намеренная диверсия, но пользователи склонны по глупости затаскивать на сайт чужой вредоносный код (в том числе javascript). Либо форматирование может измениться непредсказуемо, мало ли всякого мусора скрыто в невидимых тэгах!

Поэтому перечисляем всё, что разрешено, явно и сохраняем, а все остальные тэги уничтожаем strip_tags (либо ещё хуже для парных тэгов типа script – уничтожаем их и всё, что между ними). Работа, как ни странно, не очень сложная, вся уместилась в одной функции validate_html. Ну, и список тэгов уже выносим в отдельный файл конфигурации (назовём его config.php http://nichtig.ru/05.1/config.php.txt ) – вот откуда разрастание кода берётся.

В-четвёртых, у нас проблема с настройками полей: в одном поле (например, html1) нам нужен html, в другом же (например, title) он категорически опасен. В идеале надо составлять список всех полей всех таблиц и добавлять в конфигурацию описания (тем более что там не только об html-е вопросы будут). Именно так и делаем: добавляем в файл config.php раздел 'fields' и записываем туда, в частности, что поле html1 в таблице mypages имеет тип "21", что перед выводом в браузер заставит Php а) вывести поле (не пропускать) и б) разрешить редактирование (и отображение) html-кода.

В функции validate_html записано, в частности, правило: если тип поля "больше нуля", пропускать html (пропускать только то, что мы перечислили явно в файле config.php).

Ещё мы по особому обрабатываем при выводе на сайте поля, начинающиеся с букв "img" – создаём элемент img и присваиваем ему src равный значению поля (приблизительно – так как надо ещё путь к папке с картинками указать).

Теперь мы можем копировать текст из других программ (rtf, html) и вставлять в поле редактирования. В основном форматирование не испортится (сохранятся таблицы, разделение на абзацы, заголовки и подзаголовки...). Но часть непосредственного оформления будет уничтожена – например, переданного через атрибут style или через устаревшие тэги font. Это часть идеологии нашей CMS: всё оформление мы стараемся делать через внешний файл CSS, описывая в нём классы, – тогда страницы сайта будут более-менее единообразными, в одном стиле.

Для описанных изменений создадим "субверсию" 05.1 http://nichtig.ru/05.1/ - она отличается от версии 05 только размером файла site.js (он стал на 5 килобайт длиннее). Не забудьте для просмотра функций работы редактора авторизоваться на сайте на странице 05.1/?edit http://nichtig.ru/05.1/?edit с именем admin и паролем admin.

Редактирование WYSIWYG (форматируем HTML кнопочками)

Как же без кнопочек Ж(ирный) ,К(урсив) (под)Ч(ёркнутый)? Считается, что они нужны в каждом визуальном редакторе, они – первое, что пытается нажать пользователь. Но мы начнём с более насущного, с более крупных блоков – например, с добавления рамок таблице. Вот мы вставили на сайт таблицу из Ворда (на стр. 4 – http://nichtig.ru/05.1/?id=4), но в Ворде она была красивая, с рамочками, а на сайте они пропали (во всяком случае, после нашей серверной обработки – удаления потенциально опасных тэгов и атрибутов).

Первое, что надо сделать, – описать класс для таблицы с рамочками в site.css. Назовём этот класс "border". Ну, и класс для заголовка таблицы тоже понадобится (tHead). Затем надо преодолеть соблазн оформить ВСЕ таблицы на сайте по умолчанию классом border (может, оно на данном этапе и правильно, но всё равно ведь понадобятся разное оформление для разных типов таблиц).

Второе – как-то указать, отметить таблицу в нашем contenteditable, чтобы при щелчке по кнопке "Рамки таблицы" рамки появлялись именно у конкретной таблицы. Надо как-то "лоцировать" место, где мы находимся в редактируемом тексте. По событиям мыши и клавиатуры (то есть при любой активности пользователя, связанной с редактируемым текстом) будем запускать специально написанную нами для этого javascript функцию Editor.locate и сохранять значение текущего html-элемента в какой-нибудь переменной. А при щелчке по кнопкам форматирования уже использовать значение этой переменной (а не что попало).

Дальше – ясно: ищем вверх по DOM-дереву (если не знаете, что такое DOM, почитайте спецификации W3C) элемент "Таблица" (но не выше нашего редактируемого элемента "contenteditable" – с помощью функции findParent) и назначаем ему класс border. Точнее, делаем кнопку переключателем: если класс уже назначен таблице, он удаляется. Благо, такая функция переключения классов CSS уже у нас в запасе имеется (называется tc – от "ToggleClass"):

function tc(el, cl1, cl2) {
	cl2 = cl2 || null;
	if (hc(el.className, cl1)) cc(el, cl2, cl1)
	else cc(el, cl1, cl2)
}

Дальше по аналогии можно добавить несколько кнопок типа h3, ol, ul...

Javascript в нашей CMS работает без использования какого-либо фреймворка. Но есть несколько функций, сокращающих синтаксис. Например, последовательность функций ac(ce('div')), вызванная в таком виде, вернёт элемент div, присоединённый к элементу body. В ней можно указать второй параметр, и тогда вновь созданный элемент будет присоединяться к указанному в этом параметре элементу-контейнеру. А если делать то же на встроенных функциях (native) код будет выглядеть так:

document.body.appendChild(document.createElement('div'))

Это не фреймворк, мы просто делаем код короче и логически проще. А также используем несколько очень нужных в работе, но отсутствующих в javascript функций типа cc (changeClass), hc (haseClass), buildElement... Вы тоже можете их использовать, и при желании понять, как они работают (наблюдая за их поведением в работе сайта).

У нас нет сейчас цели глубоко изучить Javascript, предполагается, что вы с ним знакомы хотя бы на таком уровне, чтобы понимать разницу в синтаксисе значка "." (точка) в Php и Javascript. Но для веб-разработки Javascript крайне важен; изучайте его; сейчас это легко можно делать в интернете. Не на любом сайте. Начните с http://dklab.ru/chicken/nablas/38.html (Дмитрий Котеров), и закончите сайтом http://javascript.ru/ (Илья Кантор). Сейчас уже трудно найти офлайн-справочник по javascript Юрия Лукача, иначе он был бы первым в списке (хоть и устарел во многом, потому что браузеры сильно изменились).

< Лекция 2 || Лекция 3: 1234 || Лекция 4 >
Михаил Гутентог
Михаил Гутентог

Этот курс ( Практикум по разработке CMS ) создавался, когда у PHP была версия 5.3 или 5.4. Со временем какие-то функции PHP устаревают (mysql, each), какие-то начинают работать по-другому (empty). Пожалуйста, следите за изменениями в PHP по сайту php.net!

Александр Мельников
Александр Мельников

Изучаю курс "Практикум по созданию CMS" в листинге 4.3

$n = count($_GET); if ($n > 0) { $param = each($_GET); // самое простое: пропускаем только первый параметр if ($n > 1 || !isset($valid[$param['key']])) { _404(); }

При попытке просмотра в браузере получаю ошибку: Deprecated: The each() function is deprecated.  И не пойму как исправить ситуацию.

Елена Суханова
Елена Суханова
Россия, Москва, МИЭТ, 2011
Анастасия Щитова
Анастасия Щитова
Россия, Москва, ФГБОУ ВО "Московский государственный юридический университет имени О.Е. Кутафина (МГЮА)", 2016