toBento/js-editor

简单的JavaScript WYSIWYG HTML编辑器,仅包含内联工具栏。

安装: 5

依赖: 0

建议者: 0

安全性: 0

星级: 0

关注者: 1

分支: 0

开放问题: 0

语言:JavaScript

1.0.0 2024-02-27 13:49 UTC

This package is auto-updated.

Last update: 2024-09-27 15:10:04 UTC


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.jsplugin/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');

鸣谢