Contenteditable – текстовый редактор
https://snipp.ru/php/contenteditable
Если добавить атрибут contenteditable к элементу, его содержимое становится доступно для редактирования пользователю, а с использованием JS и JQuery можно сделать простой WYSIWYG редактор.
<div class="editor" contenteditable="true"></div>
JS-метод document.execCommand(сommand, showDefaultUI, аrgument)
применяет команды к элементу с атрибутом contenteditable
, который находится в фокусе. Т.к. нет единого стандарта, логика команд может отличатся в разных браузерах так и их поддержка, описание команд на https://developer.mozilla.org.
Проверить доступность команды можно методом queryCommandSupported(сommand)
.
var enable = document.queryCommandSupported('paste'); if (enable) { ... }
Поддержка команд в браузере:
backColor | heading | justifyLeft |
bold | hiliteColor | justifyRight |
contentReadOnly | increaseFontSize | outdent |
copy | indent | paste |
createLink | insertBrOnReturn | redo |
cut | insertHorizontalRule | removeFormat |
decreaseFontSize | insertHTML | selectAll |
delete | insertImage | strikeThrough |
enableInlineTableEditing | insertOrderedList | subscript |
enableObjectResizing | insertUnorderedList | superscript |
fontName | insertParagraph | underline |
fontSize | insertText | undo |
foreColor | italic | unlink |
formatBlock | justifyCenter | useCSS |
forwardDelete | justifyFull | styleWithCSS |
Жирный
Включает и отключает у выделенного текста жирное начертание тегом <b>
, IE использует тег <strong>
.
document.execCommand('bold', false, null);
Курсив
Тег <i>
, IE использует <em>
.
document.execCommand('italic', false, null);
Подчеркнутый
Тег <u>
.
document.execCommand('underline', false, null);
Перечёркнутый
Тег <strike>
.
document.execCommand('strikethrough', false, null);
Верхний индекс
Тег <sup>
.
document.execCommand('superscript', false, null);
Нижний индекс
Тег <sub>
.
document.execCommand('subscript', false, null);
Маркированный список
Тег <ul>
.
document.execCommand('insertUnorderedList', false, null);
Нумерованный список
Тег <ol>
.
document.execCommand('insertOrderedList', false, null);
Заголовки, параграф, цитата и т.д.
formatBlock
добавляет блочный тег вокруг выделенного текста.
document.execCommand('formatBlock', false, 'h1'); document.execCommand('formatBlock', false, 'h2'); document.execCommand('formatBlock', false, 'h3'); document.execCommand('formatBlock', false, 'p'); document.execCommand('formatBlock', false, 'blockquote'); document.execCommand('formatBlock', false, 'div');
Горизонтальная линия
Тег <hr>
.
document.execCommand('insertHorizontalRule', false, null);
Изображение
var url = prompt('Введите адрес изображения', ''); document.execCommand('insertImage', false, url);
Ссылка
var url = prompt('Введите URL', ''); document.execCommand('CreateLink', false, url);
Удаление ссылки:
document.execCommand('unlink', false, null);
Вставка текста
var text = prompt('Введите текст', ''); document.execCommand('insertText', false, text);
Вставка HTML
var html = prompt('Введите HTML код', ''); document.execCommand('insertHTML', false, html);
С помощью insertHTML
можно обернуть выделенный текст тегом, например <pre>
:
document.execCommand('insertHTML', false, '<pre>' + document.getSelection().toString() + '</pre>');
Выравнивание текста
Добавляет родительскому блоку CSS-свойство text-align
.
По левому краю:
document.execCommand('justifyLeft', false, null);
По центру:
document.execCommand('justifyCenter', false, null);
По правому краю:
document.execCommand('justifyRight', false, null);
По ширине:
document.execCommand('justifyFull', false, null);
Шрифты
По умолчанию команды установки шрифта добавляются тегом <font>
c атрибутами face
, size
, color
, что не очень хорошо.
Команда styleWithCSS
переключает режим, в место семантических тегов добавляются <span style="...">
.
После установки шрифта нужно переключить styleWithCSS
обратно т.к. он распространяется на другие теги (<b>
, <i>
, <s>
и т.д.).
Название шрифта
document.execCommand('styleWithCSS', false, true); document.execCommand('fontName', false, 'monospace'); document.execCommand('styleWithCSS', false, false);
Размер:
Размер шрифта задаётся в условных единицах (1-7), в режиме styleWithCSS
некоторые браузеры используют font-size: xx-small
, x-small
, small
, medium
, large
, x-large
, xx-large
.
document.execCommand('styleWithCSS', false, true); document.execCommand('fontSize', false, '5'); document.execCommand('styleWithCSS', false, false);
Цвет:
document.execCommand('styleWithCSS', false, true); document.execCommand('foreColor', false, '#eeeeee'); document.execCommand('styleWithCSS', false, false);
Фон:
document.execCommand('styleWithCSS', false, true); document.execCommand('hiliteColor', false, 'orange'); document.execCommand('styleWithCSS', false, false);
Undo и Redo
Отмена последнего действия, Ctrl + z.
document.execCommand('undo', false, null);
Повтор последнего действия, Ctrl + y.
document.execCommand('redo', false, null);
Выделить всё
document.execCommand('selectAll', false, null);
Удаление выделенного
document.execCommand('delete', false, null);
Очистить стили
Удаляет инлайновые теги и атрибуты style
, все блочные теги остаются.
document.execCommand('removeFormat', false, null);
Вырезать
document.execCommand('cut', false, null);
Копировать
document.execCommand('copy', false, null);
<link href="/font-awesome.min.css" rel="stylesheet"> <script src="/jquery.min.js"></script> <div class="toolbar"> <a href="#" class="toolbar-b fas fa-bold" title="Жирный"></a> <a href="#" class="toolbar-i fas fa-italic" title="Курсив"></a> <a href="#" class="toolbar-u fas fa-underline" title="Подчёркнутый"></a> <a href="#" class="toolbar-s fas fa-strikethrough" title="Зачёркнутый"></a> <a href="#" class="toolbar-sup fas fa-superscript" title="Верхний индекс"></a> <a href="#" class="toolbar-sub fas fa-subscript" title="Нижний индекс"></a> <a href="#" class="toolbar-ul fas fa-list-ul" title="Маркированный список"></a> <a href="#" class="toolbar-ol fas fa-list-ol" title="Нумерованный список"></a> <a href="#" class="toolbar-p" title="Параграф">p</a> <a href="#" class="toolbar-h1" title="Заголовок">H1</a> <a href="#" class="toolbar-hr" title="Горизонтальная линия">hr</a> <a href="#" class="toolbar-blockquote fas fa-quote-right" title="Цитата"></a> <a href="#" class="toolbar-img far fa-image" title="Изображение"></a> <a href="#" class="toolbar-a fas fa-link" title="Ссылка"></a> <a href="#" class="toolbar-unlink fas fa-unlink" title="Удаление ссылки"></a> <a href="#" class="toolbar-html" title="Вставить html">HTML</a> <a href="#" class="toolbar-text" title="Вставить текст">Text</a> <br> <a href="#" class="toolbar-left fas fa-align-left" title="по левому краю"></a> <a href="#" class="toolbar-center fas fa-align-center" title="по центру"></a> <a href="#" class="toolbar-right fas fa-align-right" title="по правому краю"></a> <a href="#" class="toolbar-justify fas fa-align-justify" title="по ширине"></a> <select class="toolbar-font"> <option selected="selected" disabled="disabled">Шрифт</option> <option value="arial">Arial</option> <option value="Courier New">Courier New</option> <option value="georgia">Georgia</option> <option value="impact">Impact</option> <option value="roboto">Tahoma</option> <option value="Times New Roman">Times New Roman</option> <option value="verdana">Verdana</option> </select> <select class="toolbar-size"> <option selected="selected" disabled="disabled">Размер</option> <option value="1">10px</option> <option value="2">12px</option> <option value="3">14px</option> <option value="4">16px</option> <option value="5">18px</option> <option value="6">21px</option> <option value="7">26px</option> </select> <span>Цвет</span> <input class="toolbar-color" type="color" value="#ff0000"> <span>Фон</span> <input class="toolbar-bg" type="color" value="#ffff00"> <br> <a href="#" class="toolbar-undo fas fa-undo" title="Отмена"></a> <a href="#" class="toolbar-redo fas fa-redo" title="Повтор"></a> <a href="#" class="toolbar-delete far fa-trash-alt" title="Удалить"></a> <a href="#" class="toolbar-selectAll">Выделить всё</a> <a href="#" class="toolbar-removeFormat">Очистить стили</a> <a href="#" class="toolbar-cut fas fa-cut" title="Вырезать"></a> <a href="#" class="toolbar-copy fas fa-copy" title="Копировать"></a> </div> <div class="editor" contenteditable="true">...</div>
В большинстве браузерах при нажатии на Enter, новая строка начнется с преведущего блочного элемента (p, li, blockquote).
Если редактор был пуст, то вставится <div>
, в место него можно использовать <p>
вызвав команду:
document.execCommand('defaultParagraphSeparator', false, 'p');
Если редактору сделать display: inline-block
, то будут вставляться только <br>
.
В contenteditable клавиша Tab не добавляет отступ, а переключает фокус на следующий элемент. Включить табуляцию можно, добавив CSS-свойство white-space: pre-wrap
чтобы начали выводится пробельные символы, но при этом переносы строк тоже заработают.
.editor { white-space: pre-wrap; tab-size: 3; /* Ширина табуляции */ }
И обработчик нажатия клавиши на JQuery:
$('body').on('keydown', '.editor', function(e){ if (e.keyCode === 9) { e.preventDefault(); var editor = this; var doc = editor.ownerDocument.defaultView; var sel = doc.getSelection(); var range = sel.getRangeAt(0); var tabNode = document.createTextNode("\t"); range.insertNode(tabNode); range.setStartAfter(tabNode); range.setEndAfter(tabNode); sel.removeAllRanges(); sel.addRange(range); } });
Результат:
При вставки текста из буфера переносятся все стили и теги скопированные из HTML страницы или Word файла, это можно предотвратить очисткой:
function escape_text(text) { var map = {'&': '&', '<': '<', '>': '>', '"': '"', "'": '''}; return text.replace(/[&<>"']/g, function(m) { return map[m]; }); } $('body').on('paste', '.editor', function(e){ e.preventDefault(); var text = (e.originalEvent || e).clipboardData.getData('text/plain'); document.execCommand('insertHtml', false, escape_text(text)); });
<div class="editor" contenteditable="true" placeholder="Введите текст"></div>
.editor[placeholder]:empty:before { content: attr(placeholder); color: #555; } .editor[placeholder]:empty:focus:before { content: ''; }
$('body').on('focusout', '.editor', function() { var element = $(this); if (!element.text().replace(' ', '').length) { element.empty(); } });
Показать исходный код можно заменив <div>
на <textarea>
.
<input type="checkbox" id="toggle-editor"> Показать исходный код <div contenteditable="true" class="editor"> ... </div>
textarea.editor { display: block; width: 100%; box-sizing: border-box; white-space: pre-wrap; }
$('#toggle-editor').click(function(){ var target = $('.editor'); if ($(this).is(':checked')){ target.replaceWith('<textarea class="editor">' + target.html() + '</textarea>'); } else { target.replaceWith('<div contenteditable="true" class="editor">' + target.val() + '</div>'); } });
Для отправки текста вместе с формой нужно добавить скрытый <textarea>
, при событии отправки формы скидывать в него содержимое редактора.
<form id="form" method="post" action=""> <div class="editor" contenteditable="true">...</div> <textarea id="textarea" name="text" style="dispalay: none;"></textarea> <input type="supmit" value="Отправить"> </form>
$('#form').on('submit', function(){ $('#textarea').val($('.editor').html()); return true; });
Auto-Saving
To make the editor more user-friendly, we should add auto-saving. The first method automatically saves your work every five seconds.
You can also save the changes on every keydown
event.
In this tutorial, I'm sticking with the latter method. You are free to trigger auto-save based on any event that seems appropriate in your projects.
Retrieving Saved Content
If you make changes to any of the elements in the previous demo and reload the page, you will notice that the changes you made are gone. This is because there is no code in place to retrieve the saved data. Once the content has been saved in localStorage
, we need to retrieve it later when a user visits the webpage again.
The code above checks if the title, author, or content already exist in localStorage
. If they do, we set the innerHTML
of the respective elements to the retrieved values.
Creating the Editor
To create the inline editor, you need to have the ability to change the value of the contentEditable
attribute whenever a user decides to edit something.
While toggling the contentEditable
attribute, it is necessary to know what value the attribute holds currently. To accomplish that, you can use the isContentEditable
property. If isContentEditable
returns true
for an element, then the element is currently editable—otherwise it is not. We will use this property shortly to determine the state of various elements in our document.
First, we need to create a directory called contenteditable-editor. Inside that, create a new file called index.html. You can use this as a skeleton for your HTML file.
The first step in building the editor is the creation of a button to toggle editing and some editable elements. Inside the <body>
element, put this:
Each element that we intend to keep editable needs to have its own unique Id
. This will be helpful when we have to save the changes or retrieve them later to replace the text inside each element.
The following JavaScript code handles all the editing and saving.
You can put this code in a <script>
tag at the bottom of the <body>
tag. We use querySelectorAll()
to store all the editable elements in a variable. This method returns a NodeList
which contains all the elements in our document that are matched by specified selectors. This way, it's easier to keep track of editable elements with one variable. For instance, the title of our document can be accessed by using editables[0]
, which is what we will do next.
Next, we add an event listener to our button's click event. Every time a user clicks on the Edit Document button, we check if the title is editable. If it is not editable, we set the contentEditable
property on each of the editable elements to true
. Moreover, the text 'Edit Document'
changes to 'Save Changes'
. After users have made some edits, they can click on the 'Save Changes'
button and the changes made can be saved permanently.
If the title is editable, we set the contentEditable
property on each of the editable elements to false. At this point, we can also save the content of our document on the server to retrieve later or synchronize the changes to a copy that exists somewhere else. In this tutorial, I am going to save everything in localStorage
instead. When saving the value in localStorage
, I am using the Id
of each element to make sure that I don't overwrite anything.
Комментариев нет:
Отправить комментарий