Installations
npm install @akilli/editor
Developer Guide
Typescript
No
Module System
ESM, UMD
Node Version
23.4.0
NPM Version
11.0.0
Releases
Contributors
Unable to fetch Contributors
Languages
JavaScript (93.82%)
CSS (5.77%)
Shell (0.41%)
Developer
akilli
Download Statistics
Total Downloads
23,018
Last Day
11
Last Week
56
Last Month
212
Last Year
2,756
GitHub Statistics
14 Stars
1,616 Commits
2 Forks
2 Watching
1 Branches
1 Contributors
Bundle Size
66.00 kB
Minified
14.26 kB
Minified + Gzipped
Package Meta Information
Latest Version
5.2.7
Package Id
@akilli/editor@5.2.7
Unpacked Size
98.64 kB
Size
31.38 kB
File Count
6
NPM Version
11.0.0
Node Version
23.4.0
Publised On
27 Jan 2025
Total Downloads
Cumulative downloads
Total Downloads
23,018
Last day
266.7%
11
Compared to previous day
Last week
273.3%
56
Compared to previous week
Last month
-55%
212
Compared to previous month
Last year
-58.3%
2,756
Compared to previous year
Daily Downloads
Weekly Downloads
Monthly Downloads
Yearly Downloads
Dev Dependencies
3
akilli editor
A HTML standards-compliant and dependency-free rich text editor.
Demo
https://akilli.github.io/editor/demo
Development
Use the editor source version directly or the bundled and minified dist version of it. If you use the source version all changes in the code take effect immediately, whereas the dist version needs to be rebuild with
npm run build
The demo offers both versions and can be started with either
npm start
or
docker compose up -d
In both cases the demo is accessible at http://localhost:20000/demo/index.html
Info
The editor consists of a main toolbar, a formatbar, a focusbar and a content area.
The focusbar contains the buttons to align, sort and delete a focusable element. Which buttons are shown depends on the elements tag configuration (see below).
The formatbar contains the buttons to format the text inside an editable element, p.e. bold, italic, link or any other text-level element and is hidden or shown depending on the current selection.
The main toolbar contains the buttons to insert a widget into the content area, p.e. paragraph, heading, lists, media elements, tables, sections and more.
Each widgets itself usually consists of one or more editables that allow adding and maybe formatting text. The Block
plugin is an exception to this, as it provides the possibility to add non-editable and optionally previewable
placeholder blocks into the editor content that will later be somehow replaced by your application (p.e. a CMS).
The features of each element (p.e. like alignable, deletable, editable, focusable, navigable, sortable, etc) as well as the allowed attributes and child elements are configured by the tag configuration.
Be aware of the fact that nesting of text-level elements is deliberately disallowed by both the default tag
configuration and the Editor.format()
method. If you are not happy with this restriction, adjust the tag configuration
and override the format()
method in your Editor
subclass.
Features
Toolbar navigation
Once a toolbar button is focused, use the ArrowLeft
, ArrowRight
, Home
and End
keys to navigate among the
buttons.
Navigable elements
If one navigable element is focused, you can use the ArrowUp
, ArrowDown
, Home
and End
keys to navigate among
the sibling elements.
Enter
key handling
After adding the first widget into the content area, you can also use the Enter
key to add a new one. In most cases
this will be a new paragraph. Depending on the widget, this new paragraph will be created inside the widget itself or on
top-level.
Within lists the Enter
key will add a new list item. Within tables it's either a new row or new column, depending on
wheter a row or a column currently is focused.
Backspace
key handling
Certain editable elements like p. e. paragraphs and headings remove themselves if they contain no text and the
Backspace
key is pressed. Other (pseudo) elements like p. e. table rows and colums do the same.
Sortable elements
You can reorder sortable elements either by drag'n'drop or by keyboard shortcuts. Note that not all elements are configured to be sortable, p.e. the summary element within the details widget will always be the first child element.
You can move the sortable element before its previous or after its next sibling or to first or last position by
combining the Control
key with one of the ArrowUp
, ArrowDown
, Home
or End
keys.
Deletable elements
You can delete a deletable element by combining the Control
key with the Delete
key. Inside editable elements, you
can also use the Backspace
key, if the editable is empty. Note that not all elements are configured to be deletable,
p.e. the details widget will not allow to delete the summary element unless it is the only child in which case
deleting the summary element will delete the whole details widget.
Alignable elements
Figure widgets like blockquote, table or media elements allow changing alignment by adding or removing the CSS
class left
, center
or right
. This is done by combining the Shift
key with the ArrowLeft
(left
)
, ArrowDown
(center
) or ArrowRight
(right
) or ArrowUp
(removes CSS classes) keys.
Text-level elements
Each formatting command registers a keyboard shortcut in the form Alt
+ Shift
+ a letter. If you hover a formatbar
button for such a text-level element, the actual keyboard shortcut will be shown. Using such a shortcut will execute the
corresponding command.
In addition to that, you can also doubleclick on a text-level element to execute the corresponding command.
In both cases, executing the command will either open the corresponding dialog in case the elements allows attributes or remove the formatting text-level element.
Usage
1import Editor from './dist/editor.js'; 2 3/** 4 * Configuration options 5 */ 6const config = { 7 /** 8 * Base plugin 9 */ 10 base: { 11 /** 12 * Overrides default browser dialog window options 13 * 14 * @see Dom.#browser 15 * @type {Object.<string, string>} 16 */ 17 browser: {}, 18 19 /** 20 * Converts one HTML element to another 21 * 22 * @see ContentFilter.#convert 23 * @type {Object.<string, string>} 24 */ 25 filter: {}, 26 27 /** 28 * Language for i18n 29 * 30 * @see Plugin._i18n 31 * @type {string|undefined} 32 */ 33 lang: undefined, 34 35 /** 36 * Names of the built-in plugins to load or disable 37 * 38 * - if empty, all built-in plugins are loaded 39 * - if not empty and `pluginsDisabled` is not set, only given plugins and their dependencies are loaded 40 * - if not empty and `pluginsDisabled` is set, all given plugins are disabled that are no dependencies 41 * 42 * @see Editor.init 43 * @see Editor.defaultConfig 44 * @type {string[]} 45 */ 46 plugins: [], 47 48 /** 49 * The state of this flag will affect the way the `plugins` array is used 50 * 51 * @see Editor.init 52 * @type {boolean} 53 */ 54 pluginsDisabled: false, 55 }, 56 57 /** 58 * Audio plugin 59 */ 60 audio: { 61 /** 62 * URL to audio browser 63 * 64 * If browser URL is provided, an audio browser dialog is used to insert new audio elements instead of the 65 * default audio dialog that provides just a simple form to set the src attribute. 66 * 67 * @see AudioDialog.constructor 68 * @type {string|undefined} 69 */ 70 browser: undefined, 71 }, 72 73 /** 74 * Block plugin 75 */ 76 block: { 77 /** 78 * URL to block API including the placeholder {id}, p.e. '/api/{id}.html' 79 * 80 * The placeholder {id} will be replaced by the value of the block element's id attribute and then a GET request 81 * will be sent to the resulting URL, p.e. if the block API URL is configured to '/api/{id}.html' and the block 82 * element's id attribute is 1, an GET request is sent to '/api/1.html'. The block API must only return the HTML 83 * content for the preview if the block with the requested ID exists. 84 * 85 * @see BlockListener.insertappblock 86 * @type {string|undefined} 87 */ 88 api: undefined, 89 90 /** 91 * URL to block browser 92 * 93 * If browser URL is provided, a block browser dialog is used to insert new block elements instead of the 94 * default block dialog that provides just a simple form to set the id attribute. 95 * 96 * @see BlockDialog.constructor 97 * @type {string|undefined} 98 */ 99 browser: undefined, 100 101 /** 102 * Comma-separated list of URLs to CSS files that should be included by the autonomous custom block element 103 * 104 * @see BlockListener.insertappblock 105 * @type {string|undefined} 106 */ 107 css: undefined, 108 }, 109 110 /** 111 * Iframe plugin 112 */ 113 iframe: { 114 /** 115 * URL to iframe browser 116 * 117 * If browser URL is provided, an iframe browser dialog is used to insert new iframe elements instead of the 118 * default iframe dialog that provides just a simple form to set the src, width and height attributes. 119 * 120 * @see IframeDialog.constructor 121 * @type {string|undefined} 122 */ 123 browser: undefined, 124 }, 125 126 /** 127 * Image plugin 128 */ 129 image: { 130 /** 131 * URL to image browser 132 * 133 * If browser URL is provided, an image browser dialog is used to insert new image elements instead of the 134 * default image dialog that provides just a simple form to set the src, alt, width and height attributes. 135 * 136 * @see ImageDialog.constructor 137 * @type {string|undefined} 138 */ 139 browser: undefined, 140 }, 141 142 /** 143 * Video plugin 144 */ 145 video: { 146 /** 147 * URL to video browser 148 * 149 * If browser URL is provided, a video browser dialog is used to insert new video elements instead of the 150 * default video dialog that provides just a simple form to set the src, width and height attributes. 151 * 152 * @see VideoDialog.constructor 153 * @type {string|undefined} 154 */ 155 browser: undefined, 156 }, 157}; 158 159document.addEventListener('DOMContentLoaded', () => { 160 const rte = document.getElementById('rte'); 161 const editor = Editor.create(rte, config); 162 console.log(editor); 163});
Browser integration
As described in the configuration options in above's Usage example, some plugins (currently all media element plugins and the block element plugin) offer the possibilty to configure a browser URL. If browser URL is provided, a browser window with that location will be opened instead of the simple form dialog used by default.
The editor does not provide a browser integration itself, but a simple and minimal API to integrate your own browser implementation.
You can implement your browser as you wish, the only requirement is that your browser notifies the editor by posting a message when an item is selected, p.e. for the image plugin something like
1window.opener.postMessage({
2 alt: 'Alternative Text',// optional
3 height: '300',// optional
4 id: 'image-1', // optional, can be used as regular id attribute and/or p. e. a reference to the image in the DB
5 src: '/url/to/media',// required
6 width: '400',// optional
7}, window.opener.origin);
The examples for the other browsers differ only in the keys the plugin considers:
- the iframe and video plugins require
src
and additionally acceptheight
,width
andid
- the audio plugin requires
src
and additionally acceptsid
- the block plugin only requires and accepts
id
You can also use this API for your own plugins and define the type and structure of the message to your likings, p.e. use a simple string if you are only interested in one value, an object or an array.
Your browser implementation will receive existing values of the currently selected element as URL.searchParams
if the
plugin supports updating already inserted elements. Currently neither the media element plugins nor the block element
plugin do.
No vulnerabilities found.
Reason
no dangerous workflow patterns detected
Reason
no binaries found in the repo
Reason
license file detected
Details
- Info: project has a license file: license.md:0
- Info: FSF or OSI recognized license: MIT License: license.md:0
Reason
0 existing vulnerabilities detected
Reason
detected GitHub workflow tokens with excessive permissions
Details
- Warn: jobLevel 'contents' permission set to 'write': .github/workflows/release.yml:10
- Warn: no topLevel permission defined: .github/workflows/release.yml:1
Reason
7 commit(s) and 0 issue activity found in the last 90 days -- score normalized to 5
Reason
Found 0/30 approved changesets -- score normalized to 0
Reason
no SAST tool detected
Details
- Warn: no pull requests merged into dev branch
Reason
no effort to earn an OpenSSF best practices badge detected
Reason
security policy file not detected
Details
- Warn: no security policy file detected
- Warn: no security file to analyze
- Warn: no security file to analyze
- Warn: no security file to analyze
Reason
project is not fuzzed
Details
- Warn: no fuzzer integrations found
Reason
dependency not pinned by hash detected -- score normalized to 0
Details
- Warn: GitHub-owned GitHubAction not pinned by hash: .github/workflows/release.yml:12: update your workflow using https://app.stepsecurity.io/secureworkflow/akilli/editor/release.yml/master?enable=pin
- Warn: third-party GitHubAction not pinned by hash: .github/workflows/release.yml:13: update your workflow using https://app.stepsecurity.io/secureworkflow/akilli/editor/release.yml/master?enable=pin
- Warn: npmCommand not pinned by hash: release:23
- Warn: npmCommand not pinned by hash: release:27
- Info: 0 out of 1 GitHub-owned GitHubAction dependencies pinned
- Info: 0 out of 1 third-party GitHubAction dependencies pinned
- Info: 0 out of 2 npmCommand dependencies pinned
Reason
branch protection not enabled on development/release branches
Details
- Warn: branch protection not enabled for branch 'master'
Score
4.8
/10
Last Scanned on 2025-02-03
The Open Source Security Foundation is a cross-industry collaboration to improve the security of open source software (OSS). The Scorecard provides security health metrics for open source projects.
Learn More