├── .gitignore ├── assets └── example.gif ├── .npmignore ├── postcss.config.js ├── tsconfig.json ├── .github └── workflows │ └── npm-publish.yml ├── src ├── index.css └── index.js ├── vite.config.js ├── LICENSE ├── package.json ├── README.md └── yarn.lock /.gitignore: -------------------------------------------------------------------------------- 1 | node_modules/* 2 | npm-debug.log 3 | .idea/ 4 | .DS_Store 5 | dist 6 | -------------------------------------------------------------------------------- /assets/example.gif: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/editor-js/list-legacy/HEAD/assets/example.gif -------------------------------------------------------------------------------- /.npmignore: -------------------------------------------------------------------------------- 1 | .idea/ 2 | assets/ 3 | src/ 4 | vite.config.js 5 | postcss.config.js 6 | yarn.lock 7 | -------------------------------------------------------------------------------- /postcss.config.js: -------------------------------------------------------------------------------- 1 | module.exports = { 2 | plugins: [ 3 | require('postcss-nested-ancestors'), 4 | require('postcss-nested'), 5 | ], 6 | }; 7 | -------------------------------------------------------------------------------- /tsconfig.json: -------------------------------------------------------------------------------- 1 | { 2 | "include": ["src/**/*"], 3 | "compilerOptions": { 4 | "allowJs": true, 5 | "declaration": true, 6 | "emitDeclarationOnly": true, 7 | "outDir": "dist", 8 | } 9 | } 10 | -------------------------------------------------------------------------------- /.github/workflows/npm-publish.yml: -------------------------------------------------------------------------------- 1 | name: Publish package to NPM 2 | 3 | on: 4 | push: 5 | branches: 6 | - master 7 | 8 | jobs: 9 | publish-and-notify: 10 | uses: codex-team/github-workflows/.github/workflows/npm-publish-and-notify-reusable.yml@main 11 | secrets: 12 | NPM_TOKEN: ${{ secrets.NPM_TOKEN }} 13 | CODEX_BOT_NOTIFY_EDITORJS_PUBLIC_CHAT: ${{ secrets.CODEX_BOT_NOTIFY_EDITORJS_PUBLIC_CHAT }} 14 | -------------------------------------------------------------------------------- /src/index.css: -------------------------------------------------------------------------------- 1 | .cdx-list { 2 | margin: 0; 3 | padding-left: 40px; 4 | outline: none; 5 | 6 | &__item { 7 | padding: 5.5px 0 5.5px 3px; 8 | line-height: 1.6em; 9 | } 10 | 11 | &--unordered { 12 | list-style: disc; 13 | } 14 | 15 | &--ordered { 16 | list-style: decimal; 17 | } 18 | 19 | &-settings { 20 | display: flex; 21 | 22 | .cdx-settings-button { 23 | width: 50%; 24 | } 25 | } 26 | } 27 | -------------------------------------------------------------------------------- /vite.config.js: -------------------------------------------------------------------------------- 1 | import path from "path"; 2 | import cssInjectedByJsPlugin from "vite-plugin-css-injected-by-js"; 3 | import * as pkg from "./package.json"; 4 | import dts from 'vite-plugin-dts'; 5 | 6 | const NODE_ENV = process.argv.mode || "development"; 7 | const VERSION = pkg.version; 8 | 9 | export default { 10 | build: { 11 | copyPublicDir: false, 12 | lib: { 13 | entry: path.resolve(__dirname, "src", "index.js"), 14 | name: "List", 15 | fileName: "list", 16 | }, 17 | }, 18 | define: { 19 | NODE_ENV: JSON.stringify(NODE_ENV), 20 | VERSION: JSON.stringify(VERSION), 21 | }, 22 | 23 | plugins: [cssInjectedByJsPlugin(), dts({tsconfigPath: './tsconfig.json'})], 24 | }; 25 | -------------------------------------------------------------------------------- /LICENSE: -------------------------------------------------------------------------------- 1 | MIT License 2 | 3 | Copyright (c) 2018 CodeX 4 | 5 | Permission is hereby granted, free of charge, to any person obtaining a copy 6 | of this software and associated documentation files (the "Software"), to deal 7 | in the Software without restriction, including without limitation the rights 8 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 9 | copies of the Software, and to permit persons to whom the Software is 10 | furnished to do so, subject to the following conditions: 11 | 12 | The above copyright notice and this permission notice shall be included in all 13 | copies or substantial portions of the Software. 14 | 15 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 16 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 17 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 18 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 19 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 20 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 21 | SOFTWARE. 22 | -------------------------------------------------------------------------------- /package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "@editorjs/list", 3 | "version": "1.10.0", 4 | "keywords": [ 5 | "codex editor", 6 | "list", 7 | "editor.js", 8 | "editorjs" 9 | ], 10 | "description": "List Tool for Editor.js", 11 | "license": "MIT", 12 | "repository": "https://github.com/editor-js/list", 13 | "files": [ 14 | "dist" 15 | ], 16 | "main": "./dist/list.umd.js", 17 | "module": "./dist/list.mjs", 18 | "types": "./dist/index.d.ts", 19 | "exports": { 20 | ".": { 21 | "import": "./dist/list.mjs", 22 | "require": "./dist/list.umd.js", 23 | "types": "./dist/index.d.ts" 24 | } 25 | }, 26 | "scripts": { 27 | "dev": "vite", 28 | "build": "vite build" 29 | }, 30 | "author": { 31 | "name": "CodeX", 32 | "email": "team@codex.so" 33 | }, 34 | "devDependencies": { 35 | "postcss-nested": "^4.2.1", 36 | "postcss-nested-ancestors": "^2.0.0", 37 | "typescript": "^5.5.3", 38 | "vite": "^4.5.0", 39 | "vite-plugin-css-injected-by-js": "^3.3.0", 40 | "vite-plugin-dts": "^3.9.1" 41 | }, 42 | "dependencies": { 43 | "@codexteam/icons": "^0.0.4" 44 | } 45 | } 46 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | ![](https://badgen.net/badge/Editor.js/v2.0/blue) 2 | 3 | # List Tool for Editor.js 4 | 5 | > [!IMPORTANT] 6 | > This repository is deprecated and is no longer supported. 7 | Take a look at a new repository [List tool](https://github.com/editor-js/list) with more functionality and compatibility with old data. 8 | 9 | ![](assets/example.gif) 10 | 11 | ## Installation 12 | 13 | Get the package 14 | 15 | ```shell 16 | yarn add @editorjs/list 17 | ``` 18 | 19 | Include module at your application 20 | 21 | ```javascript 22 | import List from "@editorjs/list"; 23 | ``` 24 | 25 | Optionally, you can load this tool from CDN [JsDelivr CDN](https://cdn.jsdelivr.net/npm/@editorjs/list@latest) 26 | 27 | ## Usage 28 | 29 | Add the List Tool to the `tools` property of the Editor.js initial config. 30 | 31 | ```javascript 32 | import EditorJS from '@editorjs/editorjs'; 33 | import List from '@editorjs/list'; 34 | 35 | var editor = EditorJS({ 36 | // ... 37 | tools: { 38 | ... 39 | list: { 40 | class: List, 41 | inlineToolbar: true, 42 | config: { 43 | defaultStyle: 'unordered' 44 | } 45 | }, 46 | }, 47 | }); 48 | ``` 49 | 50 | ## Config Params 51 | 52 | | Field | Type | Description | 53 | | ------------ | -------- | -------------------------------------------------------------- | 54 | | defaultStyle | `string` | type of a list: `ordered` or `unordered`, default is `ordered` | 55 | 56 | ## Tool's settings 57 | 58 | ![](https://capella.pics/bf5a42e4-1350-499d-a728-493b0fcaeda4.jpg) 59 | 60 | You can choose list`s type. 61 | 62 | ## Output data 63 | 64 | | Field | Type | Description | 65 | | ----- | ---------- | ---------------------------------------- | 66 | | style | `string` | type of a list: `ordered` or `unordered` | 67 | | items | `string[]` | the array of list's items | 68 | 69 | ```json 70 | { 71 | "type" : "list", 72 | "data" : { 73 | "style" : "unordered", 74 | "items" : [ 75 | "This is a block-styled editor", 76 | "Clean output data", 77 | "Simple and powerful API" 78 | ] 79 | } 80 | }, 81 | ``` 82 | 83 | ## I18n support 84 | 85 | This tool supports the [i18n api](https://editorjs.io/i18n-api). 86 | To localize UI labels, put this object to your i18n dictionary under the `tools` section: 87 | 88 | ```json 89 | "list": { 90 | "Ordered": "Нумерованный", 91 | "Unordered": "Маркированный" 92 | } 93 | ``` 94 | 95 | See more instructions about Editor.js internationalization here: [https://editorjs.io/internationalization](https://editorjs.io/internationalization) 96 | -------------------------------------------------------------------------------- /src/index.js: -------------------------------------------------------------------------------- 1 | /** 2 | * Build styles 3 | */ 4 | import './index.css'; 5 | 6 | import { IconListBulleted, IconListNumbered } from '@codexteam/icons' 7 | 8 | /** 9 | * @typedef {import('@editorjs/editorjs').PasteEvent} PasteEvent 10 | */ 11 | 12 | /** 13 | * @typedef {object} ListData 14 | * @property {string} style - can be ordered or unordered 15 | * @property {Array} items - li elements 16 | */ 17 | 18 | /** 19 | * @typedef {object} ListConfig 20 | * @description Tool's config from Editor 21 | * @property {string} defaultStyle — ordered or unordered 22 | */ 23 | 24 | /** 25 | * List Tool for the Editor.js 2.0 26 | */ 27 | export default class List { 28 | /** 29 | * Notify core that read-only mode is supported 30 | * 31 | * @returns {boolean} 32 | */ 33 | static get isReadOnlySupported() { 34 | return true; 35 | } 36 | 37 | /** 38 | * Allow to use native Enter behaviour 39 | * 40 | * @returns {boolean} 41 | * @public 42 | */ 43 | static get enableLineBreaks() { 44 | return true; 45 | } 46 | 47 | /** 48 | * Get Tool toolbox settings 49 | * icon - Tool icon's SVG 50 | * title - title to show in toolbox 51 | * 52 | * @returns {{icon: string, title: string}} 53 | */ 54 | static get toolbox() { 55 | return { 56 | icon: IconListBulleted, 57 | title: 'List', 58 | }; 59 | } 60 | 61 | /** 62 | * Render plugin`s main Element and fill it with saved data 63 | * 64 | * @param {object} params - tool constructor options 65 | * @param {ListData} params.data - previously saved data 66 | * @param {object} params.config - user config for Tool 67 | * @param {object} params.api - Editor.js API 68 | * @param {boolean} params.readOnly - read-only mode flag 69 | */ 70 | constructor({ data, config, api, readOnly }) { 71 | /** 72 | * HTML nodes 73 | * 74 | * @private 75 | */ 76 | this._elements = { 77 | wrapper: null, 78 | }; 79 | 80 | this.api = api; 81 | this.readOnly = readOnly; 82 | 83 | this.settings = [ 84 | { 85 | name: 'unordered', 86 | label: this.api.i18n.t('Unordered'), 87 | icon: IconListBulleted, 88 | default: config.defaultStyle === 'unordered' || false, 89 | }, 90 | { 91 | name: 'ordered', 92 | label: this.api.i18n.t('Ordered'), 93 | icon: IconListNumbered, 94 | default: config.defaultStyle === 'ordered' || true, 95 | }, 96 | ]; 97 | 98 | /** 99 | * Tool's data 100 | * 101 | * @type {ListData} 102 | */ 103 | this._data = { 104 | style: this.settings.find((tune) => tune.default === true).name, 105 | items: [], 106 | }; 107 | 108 | this.data = data; 109 | } 110 | 111 | /** 112 | * Returns list tag with items 113 | * 114 | * @returns {Element} 115 | * @public 116 | */ 117 | render() { 118 | this._elements.wrapper = this.makeMainTag(this._data.style); 119 | 120 | // fill with data 121 | if (this._data.items.length) { 122 | this._data.items.forEach((item) => { 123 | this._elements.wrapper.appendChild(this._make('li', this.CSS.item, { 124 | innerHTML: item, 125 | })); 126 | }); 127 | } else { 128 | this._elements.wrapper.appendChild(this._make('li', this.CSS.item)); 129 | } 130 | 131 | if (!this.readOnly) { 132 | // detect keydown on the last item to escape List 133 | this._elements.wrapper.addEventListener('keydown', (event) => { 134 | const [ENTER, BACKSPACE] = [13, 8]; // key codes 135 | 136 | switch (event.keyCode) { 137 | case ENTER: 138 | this.getOutofList(event); 139 | break; 140 | case BACKSPACE: 141 | this.backspace(event); 142 | break; 143 | } 144 | }, false); 145 | } 146 | 147 | return this._elements.wrapper; 148 | } 149 | 150 | /** 151 | * @returns {ListData} 152 | * @public 153 | */ 154 | save() { 155 | return this.data; 156 | } 157 | 158 | /** 159 | * Allow List Tool to be converted to/from other block 160 | * 161 | * @returns {{export: Function, import: Function}} 162 | */ 163 | static get conversionConfig() { 164 | return { 165 | /** 166 | * To create exported string from list, concatenate items by dot-symbol. 167 | * 168 | * @param {ListData} data - list data to create a string from thats 169 | * @returns {string} 170 | */ 171 | export: (data) => { 172 | return data.items.join('. '); 173 | }, 174 | /** 175 | * To create a list from other block's string, just put it at the first item 176 | * 177 | * @param {string} string - string to create list tool data from that 178 | * @returns {ListData} 179 | */ 180 | import: (string) => { 181 | return { 182 | items: [ string ], 183 | style: 'unordered', 184 | }; 185 | }, 186 | }; 187 | } 188 | 189 | /** 190 | * Sanitizer rules 191 | * 192 | * @returns {object} 193 | */ 194 | static get sanitize() { 195 | return { 196 | style: {}, 197 | items: { 198 | br: true, 199 | }, 200 | }; 201 | } 202 | 203 | /** 204 | * Settings 205 | * 206 | * @public 207 | * @returns {Array} 208 | */ 209 | renderSettings() { 210 | return this.settings.map(item => ({ 211 | ...item, 212 | isActive: this._data.style === item.name, 213 | closeOnActivate: true, 214 | onActivate: () => this.toggleTune(item.name) 215 | })) 216 | } 217 | 218 | /** 219 | * On paste callback that is fired from Editor 220 | * 221 | * @param {PasteEvent} event - event with pasted data 222 | */ 223 | onPaste(event) { 224 | const list = event.detail.data; 225 | 226 | this.data = this.pasteHandler(list); 227 | } 228 | 229 | /** 230 | * List Tool on paste configuration 231 | * 232 | * @public 233 | */ 234 | static get pasteConfig() { 235 | return { 236 | tags: ['OL', 'UL', 'LI'], 237 | }; 238 | } 239 | 240 | /** 241 | * Creates main