toBento / js-editor
简单的JavaScript WYSIWYG HTML编辑器,仅包含内联工具栏。
README
简单的JavaScript WYSIWYG HTML编辑器,仅包含内联工具栏。
编辑器不使用内联样式属性来设置内容样式。相反,它只使用类。这有几个优点
- 通过类轻松自定义内容
- 使用强内容安全策略(Content-Security-Policy)阻止style-src
- 限制用户保持公司设计
您可以访问docs.tobento.ch/js-editor页面进行演示。
目录
入门
浏览器支持
仅支持现代浏览器。
文档
基本用法
1. 包含JS/CSS
<link href="editor.css" rel="stylesheet" type="text/css"> <script src="editor.js" type="module"></script>
2. 注册
<!-- using div --> <div data-editor='{"id": "foo"}'></div> <!-- using textarea --> <textarea name="bar" data-editor></textarea> <!-- with specific toolbar --> <div data-editor='{"id": "baz", "toolbar": ["bold", "italic"]}'></div>
这就完成了。
您可以获取HTML代码
使用编辑器的示例
<script type="module"> import editors from 'core/editors.js'; document.addEventListener('DOMContentLoaded', (e) => { const fooEditorCode = editors.get('foo').code(); const barEditorCode = editors.get('bar').code(); }); </script>
使用事件的示例
<script type="module"> import events from 'core/events.js'; events.listen('editor.blur', (e, editor) => { const code = editor.code(); }); </script>
自定义编辑器
您可以创建一个自定义编辑器
1. 创建custom-editor.js
import editors from './core/editors.js'; import translator from './core/translator.js'; import table from './plugin/table.js'; import styles from './plugin/styles.js'; import { basic, html, clear, links } from './plugin/basic.js'; // you may add translations: translator.locale('de-CH'); // or translator.locale(document.querySelector('html').getAttribute('lang')); translator.localeFallbacks({"de-CH": "en"}); translator.add('de-CH', { "Start typing something...": "Start mit schreiben...", "Table": "Tabelle", "Add row below": "Zeile danach einfügen", "Add row above": "Zeile davor einfügen", "Delete row": "Zeile löschen", "Add column left": "Spalte links einfügen", "Add column right": "Spalte rechts einfügen", "Delete column": "Spalte löschen", "Delete table": "Tabelle löschen" }); // you may add styles: styles.add({ key: "style.fonts", title: "Font styles", options: { "Default Font": "", "Primary Font": "font-primary", "Secondary Font": "font-secondary" }, optionToClass: true }); // add plugins: editors.plugins([basic, html, clear, links, table, styles]); // editors: document.addEventListener('DOMContentLoaded', (e) => { // init the editors: editors.init(); // you may auto register editors with the data-editor attribute: editors.register(); // or you may create it manually: const editor = editors.create(document.querySelector('#editor'), { // config (optional): id: 'foo', toolbar: ['p', 'bold', 'headings'] }); });
2. 用自定义编辑器替换默认编辑器
<link href="editor.css" rel="stylesheet" type="text/css"> <!--<script src="editor.js" type="module"></script>--> <script src="custom-editor.js" type="module"></script>
可用插件
基本插件
import editors from './core/editors.js'; import { basic, html, clear, links } from 'plugin/basic.js'; editors.plugins([basic, html, clear, links]);
基本插件
basic
插件提供了以下工具栏
["p", "h1", "h2", "h3", "h4", "h5", "h6", "bold", "italic", "underline", "strike", "ol", "ul", "quote", "pre", "code", "undo", "redo"]
HTML插件
html
插件提供了以下工具栏
["sourcecode"]
清除插件
clear
插件提供了以下工具栏
["clear"]
链接插件
links
插件提供了以下工具栏
["link"]
自定义链接类
import events from './../events.js'; events.listen('toolbars.item', (item) => { if (item.key === 'link.class') { item.options = { "none": "", "default": "button", "default fit": "button fit" }; } });
表格插件
import editors from './core/editors.js'; import table from 'plugin/table.js'; editors.plugins([table]);
table
插件提供了以下工具栏
["tables"]
样式插件
样式插件向所选文本添加/删除类。
import editors from './core/editors.js'; import styles from 'plugin/styles.js'; // add your styles: styles.add({ key: "style.fonts", title: "Font styles", options: { "Default Font": "", "Primary Font": "font-primary", "Secondary Font": "font-secondary" }, optionToClass: true }); styles.add({ key: "style.text.colors", title: "Text Colors", options: { "Default Text Color": "", "Text Color Success": "text-success" }, optionToClass: true }); // add plugin: editors.plugins([styles]);
工具栏
样式key
将是您的工具栏键
["style.fonts", "style.text.colors"]
创建插件
查看plugin/table.js
或plugin/basic.js
文件以了解如何创建插件。
事件
全局事件
您可以使用可用于插件创建的事件,例如。
编辑器事件
import events from 'core/events.js'; events.listen('editors.init', (editors) => { // });
编辑器事件
示例
import events from 'core/events.js'; events.listen('editor.blur', (event, editor) => { // });
工具栏事件
示例
import events from 'core/events.js'; events.listen('toolbars.item', (item) => { if (item.key === 'link.class') { item.options = { "none": "", "default": "button", "default fit": "button fit" }; } });
工具栏事件
示例
import events from 'core/events.js'; events.listen('toolbar.build', (data) => { // customize link toolbar if (toolbar.id === 'link') { data.items = [ 'back', 'link.visit', 'link.delete', 'link.insert', '_', 'link.input', '_', 'link.window', 'link.windowLabel', '_', //'link.class' ]; } });
编辑器事件
示例
import editors from './core/editors.js'; document.addEventListener('DOMContentLoaded', (e) => { // create editors.create(document.querySelector('#editor'), { events: { click: (event, editor) => { // } } }); });
API
编辑器API
import editors from './core/editors.js';
init/register
// init the editors: editors.init(); // you may auto register editors with the data-editor attribute: editors.register();
create
创建新的编辑器。
const editor = editors.create(document.querySelector('#editor')); // with config: const editor = editors.create(document.querySelector('#editor'), { id: 'foo', toolbar: ['p', 'bold', 'headings'], events: { click: (event, editor) => { // } } });
has / get / all
if (editors.has('ID')) { const editor = editors.get('ID'); } const allEditors = editors.all();
plugin / plugins
editors.plugin({ name: 'foo', init: () => { // }, events: { // } }); editors.plugins([{name: 'foo'}, {name: 'bar'}]);
编辑器API
import editors from './core/editors.js'; const editor = editors.create(document.querySelector('#editor'));
code
获取HTML代码。
const htmlCode = editor.code();
config
使用点表示法获取配置值。
const value = editor.config('foo.bar', 'default');
其他
const id = editor.id; const el = editor.el; // editable area const selection = editor.selection; const toolbar = editor.toolbar; const events = editor.events;
事件API
import events from './core/events.js';
listen / fire
// with array params: events.listen('click', (foo, bar) => {}); events.fire('click', ['foo', 'bar']); // or with object params: events.listen('click', (obj) => {}); events.fire('click', {});
register
const listeners = { "eventName": () => { }, }; events.register(listeners);
选择API
import editors from './core/editors.js'; const editor = editors.create(document.querySelector('#editor')); const selection = editor.selection;
get
获取选定的数据
const sel = selection.get(); const text = sel.text; const element = sel.element; const tagName = sel.tagName;
getTagnames
获取选定的标签名
const tagnames = selection.getTagnames();
其他
// Saves the current selection with unwrapping a HTML <span> marker. selection.save(); // Saves the current selection without unwrapping a HTML <span> marker. selection.save(false); // Set saved selection by element. selection.setSaved(element, ''); // Get the saved selection. const sel = selection.getSaved(); // Clears the selection. Removes the marker if any. selection.clear(); // Replaces the selection marker with the node. selection.replace(node); // Replaces the sel with the node. selection.insertReplace(sel, node); // Inserts the node after the sel. selection.insertAfter(sel, node);
工具栏API
import toolbars from './core/toolbars.js';
addItem
添加一个项,稍后用于构建工具栏。
示例按钮
toolbars.addItem({ // required: key: "Foo", // a unique key text: "Foo", command: ["formatblock", "<h2>"], undo: ["formatblock", "<p>"], // or null tagname: "h2", // used for setting button active });
示例输入
toolbars.addItem({ // required: key: "email", // a unique key // optional: element: "input", // HTML element, default "button" type: "email", id: "foo", for: "id", name: "foo", title: "Type your email", placeholder: "Type...", classes: ["foo", "bar"], // options: {"name": "value"}, // for selection element. attributes: {"name": "value"}, // any additonal HTML element attributes build_default: false, // if to build on default click: (event, item, toolbar, editor) => { // do something on click }, keyup: (event, item, toolbar, editor) => { // do something on keyup } });
其他
const toolbar = toolbars.create({id: 'ID'}); if (toolbars.has('ID')) { const toolbar = toolbars.get('ID'); } // opens the toolbar if exists: toolbars.open('ID'); // closes all toolbars: toolbars.close(); // closes all toolbars except those specified: toolbars.close(["links"]);
工具栏API
import toolbars from './core/toolbars.js';
build
使用指定的项目构建工具栏。
const toolbar = toolbars.create({id: 'ID'}); toolbar.build([ 'back', 'table.delete', '_', 'table.row.below', 'table.row.above', 'table.row.delete', '_', 'table.col.left', 'table.col.right', 'table.col.delete' ]);
open / close
const toolbar = toolbars.get({id: 'ID'}); toolbar.open(); toolbar.close();
项目
const toolbar = toolbars.get({id: 'ID'}); if (toolbar.has('key')) { const item = toolbar.get('key'); } toolbar.disable('key'); toolbar.disable('key', false); // without hiding toolbar.disableExcept(['key']); toolbar.disableExcept(['key'], false); // without hiding toolbar.enable('key'); toolbar.setActive(['key']); toolbar.setActive(['a', 'p'], 'tagname'); // based on item tagname toolbar.setActive(['key', 'key', false]); // without setting others inactive toolbar.setActiveItem('key'); // set only active. toolbar.positioning(); // position to selection; toolbar.positioning(event); // position to event.pageX and event.pageY toolbar.positioning(null, 100, 200); // position to x: 100, y: 200 toolbar.positioning(null, null, null, true); // position to last position
翻译器API
import translator from './core/translator.js';
translator.locale('de-CH'); // current locale translator.localeFallbacks({"de-CH": "en"}); // add translation for the specified locale. translator.add('de-CH', { "Table": "Tabelle" }); const translated = translator.trans('Table');