Merge branch 'next' into fix_split_custom_event
2
.github/FUNDING.yml
vendored
|
|
@ -1,5 +1,5 @@
|
|||
# These are supported funding model platforms
|
||||
|
||||
github: neSpecc
|
||||
patreon: editorjs
|
||||
open_collective: editorjs
|
||||
custom: https://codex.so/donate
|
||||
17
.github/workflows/cypress.yml
vendored
|
|
@ -3,16 +3,13 @@ on: [pull_request]
|
|||
jobs:
|
||||
firefox:
|
||||
runs-on: ubuntu-latest
|
||||
container:
|
||||
image: cypress/browsers:node14.17.0-chrome88-ff89
|
||||
options: --user 1001
|
||||
steps:
|
||||
- uses: actions/setup-node@v3
|
||||
with:
|
||||
node-version: 16
|
||||
- uses: actions/checkout@v2
|
||||
- uses: actions/checkout@v3
|
||||
- run: yarn ci:pull_paragraph
|
||||
- uses: cypress-io/github-action@v2
|
||||
- uses: cypress-io/github-action@v5
|
||||
with:
|
||||
config: video=false
|
||||
browser: firefox
|
||||
|
|
@ -23,22 +20,22 @@ jobs:
|
|||
- uses: actions/setup-node@v3
|
||||
with:
|
||||
node-version: 16
|
||||
- uses: actions/checkout@v2
|
||||
- uses: actions/checkout@v3
|
||||
- run: yarn ci:pull_paragraph
|
||||
- uses: cypress-io/github-action@v2
|
||||
- uses: cypress-io/github-action@v5
|
||||
with:
|
||||
config: video=false
|
||||
browser: chrome
|
||||
build: yarn build
|
||||
edge:
|
||||
runs-on: windows-latest
|
||||
runs-on: ubuntu-latest
|
||||
steps:
|
||||
- uses: actions/setup-node@v3
|
||||
with:
|
||||
node-version: 16
|
||||
- uses: actions/checkout@v2
|
||||
- uses: actions/checkout@v3
|
||||
- run: yarn ci:pull_paragraph
|
||||
- uses: cypress-io/github-action@v2
|
||||
- uses: cypress-io/github-action@v5
|
||||
with:
|
||||
config: video=false
|
||||
browser: edge
|
||||
|
|
|
|||
28
.npmignore
|
|
@ -1,22 +1,6 @@
|
|||
.idea
|
||||
.github
|
||||
docs
|
||||
example
|
||||
src
|
||||
test
|
||||
.babelrc
|
||||
.editorconfig
|
||||
.eslintignore
|
||||
.eslintrc
|
||||
.git
|
||||
.gitmodules
|
||||
.jshintrc
|
||||
.postcssrc.yml
|
||||
.stylelintrc
|
||||
CODEOWNERS
|
||||
cypress.json
|
||||
tsconfig.json
|
||||
tslint.json
|
||||
webpack.config.js
|
||||
yarn.lock
|
||||
devserver.js
|
||||
*
|
||||
!/dist/**/*
|
||||
!/types/**/*
|
||||
!/LICENSE
|
||||
!/README.md
|
||||
!/package.json
|
||||
|
|
|
|||
19
cypress.config.ts
Normal file
|
|
@ -0,0 +1,19 @@
|
|||
import { defineConfig } from 'cypress';
|
||||
|
||||
export default defineConfig({
|
||||
env: {
|
||||
NODE_ENV: 'test',
|
||||
},
|
||||
fixturesFolder: 'test/cypress/fixtures',
|
||||
screenshotsFolder: 'test/cypress/screenshots',
|
||||
videosFolder: 'test/cypress/videos',
|
||||
e2e: {
|
||||
// We've imported your old cypress plugins here.
|
||||
// You may want to clean this up later by importing these.
|
||||
setupNodeEvents(on, config) {
|
||||
return require('./test/cypress/plugins/index.ts')(on, config);
|
||||
},
|
||||
specPattern: 'test/cypress/tests/**/*.cy.{js,jsx,ts,tsx}',
|
||||
supportFile: 'test/cypress/support/index.ts',
|
||||
},
|
||||
});
|
||||
11
cypress.json
|
|
@ -1,11 +0,0 @@
|
|||
{
|
||||
"env": {
|
||||
"NODE_ENV": "test"
|
||||
},
|
||||
"fixturesFolder": "test/cypress/fixtures",
|
||||
"integrationFolder": "test/cypress/tests",
|
||||
"screenshotsFolder": "test/cypress/screenshots",
|
||||
"videosFolder": "test/cypress/videos",
|
||||
"supportFile": "test/cypress/support/index.ts",
|
||||
"pluginsFile": "test/cypress/plugins/index.ts"
|
||||
}
|
||||
|
|
@ -5,8 +5,14 @@
|
|||
- `Refactoring` — Popover class refactored.
|
||||
- `Improvement` — *Toolbox* — Number of `close()` method calls optimized.
|
||||
- `Improvement` — The `onChange` callback won't be triggered only if all mutations contain nodes with the `data-mutation-free` attributes.
|
||||
- `Fix` — Resolve compiler error from importing the BlockToolData type
|
||||
- `Fix` — Resolved a problem when document was being scrolled to the beginning after moving up a Block above the viewport
|
||||
- `Fix` — Resolve compiler error from importing the BlockToolData type.
|
||||
- `Fix` — Resolved a problem when document was being scrolled to the beginning after moving up a Block above the viewport.
|
||||
- `Improvement` — Package size reduced by removing redundant files.
|
||||
- `Fix`- Several bugs caused by random browser extensions.
|
||||
- `Improvement` — *Dependencies* — Upgrade TypeScript to v5.
|
||||
- `Fix` — *ToolsAPI* — `pasteConfig` getter with `false` value could be used to disable paste handling by Editor.js core. Could be useful if your tool has its own paste handler.
|
||||
- `Improvement` — *Dependencies* — Upgrade Cypress to v12, upgrade related libraries to latest versions.
|
||||
- `CI` — Use Ubuntu container for Edge tests runner.
|
||||
|
||||
### 2.26.5
|
||||
|
||||
|
|
@ -47,6 +53,7 @@
|
|||
- `Improvement` — *CodeStyle* — [CodeX ESLint Config](https://github.com/codex-team/eslint-config) has bee updated. All ESLint/Spelling issues resolved
|
||||
- `Improvement` — *ToolsAPI* — The `icon` property of the `toolbox` getter became optional.
|
||||
|
||||
|
||||
### 2.25.0
|
||||
|
||||
- `New` — *Tools API* — Introducing new feature — toolbox now can have multiple entries for one tool! <br>
|
||||
|
|
|
|||
|
|
@ -180,7 +180,7 @@ this.api.notifier.show({
|
|||
});
|
||||
```
|
||||
|
||||

|
||||

|
||||
|
||||
|
||||
Check out [`codex-notifier` package page](https://github.com/codex-team/js-notifier) on GitHub to find docs, params and examples.
|
||||
|
|
@ -203,8 +203,6 @@ After executing the `destroy` method, editor inctance becomes an empty object. T
|
|||
|
||||
Methods for showing Tooltip helper near your elements. Parameters are the same as in [CodeX Tooltips](http://github.com/codex-team/codex.tooltips) lib.
|
||||
|
||||

|
||||
|
||||
#### Show
|
||||
|
||||
Method shows tooltip with custom content on passed element
|
||||
|
|
|
|||
BIN
docs/assets/01a55381-46cd-47c7-b92e-34765434f2ca.jpg
Normal file
|
After Width: | Height: | Size: 328 KiB |
BIN
docs/assets/14fcdbe4-d6eb-41d4-b66e-e0e86ccf1a4b.jpg
Normal file
|
After Width: | Height: | Size: 8.3 KiB |
BIN
docs/assets/57267bab-f2f0-411b-a9d1-69abee6abab5.jpg
Normal file
|
After Width: | Height: | Size: 77 KiB |
BIN
docs/assets/6c1f708b-a30c-4ffd-a427-5b59a1a472e0.jpg
Normal file
|
After Width: | Height: | Size: 404 KiB |
BIN
docs/assets/796de9eb-bbe0-485c-bc8f-9a4cb76641b7.jpg
Normal file
|
After Width: | Height: | Size: 12 KiB |
BIN
docs/assets/79ce946a-d636-41cd-aa96-d3bc5ecfde03.jpg
Normal file
|
After Width: | Height: | Size: 58 KiB |
BIN
docs/assets/7ccbcfcd-1c49-4674-bea7-71021468a1bd.jpg
Normal file
|
After Width: | Height: | Size: 137 KiB |
|
|
@ -33,7 +33,7 @@ There is a [workflow](.github/workflows/publish-package-to-npm.yml) that fired o
|
|||
|
||||
Use target version changelog as a description.
|
||||
|
||||

|
||||

|
||||
|
||||
Then you can publish the release and wait for package publishing via action.
|
||||
|
||||
|
|
@ -44,7 +44,7 @@ This package version will be published to NPM with default `latest` tag.
|
|||
If you want to publish release candidate version, use suffix `-rc.*` for package
|
||||
version in package.json file and in tag on releases page. Workflow will detect it and mark a release as "pre-release".
|
||||
|
||||

|
||||

|
||||
|
||||
This package version will be published to NPM with `next` tag.
|
||||
|
||||
|
|
|
|||
|
|
@ -129,8 +129,6 @@ Read more about Sanitizer configuration at the [Tools#sanitize](tools.md#sanitiz
|
|||
You can pass your Tool's title via `title` static getter. It can be used, for example, in the Tooltip with
|
||||
icon description that appears by hover.
|
||||
|
||||

|
||||
|
||||
```ts
|
||||
export default class BoldInlineTool implements InlineTool {
|
||||
/**
|
||||
|
|
|
|||
|
|
@ -410,7 +410,7 @@ static get sanitize() {
|
|||
|
||||
Editor.js has a Conversion Toolbar that allows user to convert one Block to another.
|
||||
|
||||

|
||||

|
||||
|
||||
1. You can add ability to your Tool to be converted. Specify «export» property of `conversionConfig`.
|
||||
2. You can add ability to convert other Tools to your Tool. Specify «import» property of `conversionConfig`.
|
||||
|
|
|
|||
|
|
@ -17,12 +17,12 @@ So how to use the Editor after [Installation](installation.md).
|
|||
|
||||
- Select text fragment and apply a style or insert a link from the Inline Toolbar
|
||||
|
||||

|
||||

|
||||
|
||||
- Use «three-dots» button on the right to open Block Settings. From here, you can move and delete a Block
|
||||
or apply Tool's settings, if it provided. For example, set a Heading level or List style.
|
||||
|
||||

|
||||

|
||||
|
||||
## Shortcuts
|
||||
|
||||
|
|
|
|||
|
|
@ -1 +1 @@
|
|||
Subproject commit 4a94a1592a500ebb6cc570fa1d6216a149b541a0
|
||||
Subproject commit 3cc506758440ac3f1bc83008a6ef75813b6386c3
|
||||
14
package.json
|
|
@ -1,6 +1,6 @@
|
|||
{
|
||||
"name": "@editorjs/editorjs",
|
||||
"version": "2.27.0-rc.1",
|
||||
"version": "2.27.0-rc.4",
|
||||
"description": "Editor.js — Native JS, based on API and Open Source",
|
||||
"main": "dist/editor.js",
|
||||
"types": "./types/index.d.ts",
|
||||
|
|
@ -48,8 +48,8 @@
|
|||
"@babel/register": "^7.9.0",
|
||||
"@babel/runtime": "^7.9.2",
|
||||
"@codexteam/shortcuts": "^1.1.1",
|
||||
"@cypress/code-coverage": "^3.9.2",
|
||||
"@cypress/webpack-preprocessor": "^5.6.0",
|
||||
"@cypress/code-coverage": "^3.10.1",
|
||||
"@cypress/webpack-preprocessor": "^5.17.0",
|
||||
"@editorjs/code": "^2.7.0",
|
||||
"@editorjs/delimiter": "^1.2.0",
|
||||
"@editorjs/header": "^2.7.0",
|
||||
|
|
@ -64,8 +64,8 @@
|
|||
"core-js": "3.6.5",
|
||||
"css-loader": "^3.5.3",
|
||||
"cssnano": "^4.1.10",
|
||||
"cypress": "^6.8.0",
|
||||
"cypress-intellij-reporter": "^0.0.6",
|
||||
"cypress": "^12.9.0",
|
||||
"cypress-intellij-reporter": "^0.0.7",
|
||||
"eslint": "^8.28.0",
|
||||
"eslint-config-codex": "^1.7.1",
|
||||
"eslint-loader": "^4.0.2",
|
||||
|
|
@ -83,9 +83,9 @@
|
|||
"rimraf": "^3.0.2",
|
||||
"stylelint": "^13.3.3",
|
||||
"terser-webpack-plugin": "^2.3.6",
|
||||
"ts-loader": "^7.0.1",
|
||||
"ts-loader": "^8.4.0",
|
||||
"tslint": "^6.1.1",
|
||||
"typescript": "3.8.3",
|
||||
"typescript": "^5.0.2",
|
||||
"webpack": "^4.43.0",
|
||||
"webpack-cli": "^3.3.11"
|
||||
},
|
||||
|
|
|
|||
|
|
@ -153,6 +153,11 @@ export default class Block extends EventsDispatcher<BlockEvents> {
|
|||
*/
|
||||
private cachedInputs: HTMLElement[] = [];
|
||||
|
||||
/**
|
||||
* We'll store a reference to the tool's rendered element to access it later
|
||||
*/
|
||||
private toolRenderedElement: HTMLElement | null = null;
|
||||
|
||||
/**
|
||||
* Tool class instance
|
||||
*/
|
||||
|
|
@ -553,23 +558,7 @@ export default class Block extends EventsDispatcher<BlockEvents> {
|
|||
* @returns {HTMLElement}
|
||||
*/
|
||||
public get pluginsContent(): HTMLElement {
|
||||
const blockContentNodes = this.holder.querySelector(`.${Block.CSS.content}`);
|
||||
|
||||
if (blockContentNodes && blockContentNodes.childNodes.length) {
|
||||
/**
|
||||
* Editors Block content can contain different Nodes from extensions
|
||||
* We use DOM isExtensionNode to ignore such Nodes and return first Block that does not match filtering list
|
||||
*/
|
||||
for (let child = blockContentNodes.childNodes.length - 1; child >= 0; child--) {
|
||||
const contentNode = blockContentNodes.childNodes[child];
|
||||
|
||||
if (!$.isExtensionNode(contentNode)) {
|
||||
return contentNode as HTMLElement;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return null;
|
||||
return this.toolRenderedElement;
|
||||
}
|
||||
|
||||
/**
|
||||
|
|
@ -825,7 +814,12 @@ export default class Block extends EventsDispatcher<BlockEvents> {
|
|||
contentNode = $.make('div', Block.CSS.content),
|
||||
pluginsContent = this.toolInstance.render();
|
||||
|
||||
contentNode.appendChild(pluginsContent);
|
||||
/**
|
||||
* Saving a reference to plugin's content element for guaranteed accessing it later
|
||||
*/
|
||||
this.toolRenderedElement = pluginsContent;
|
||||
|
||||
contentNode.appendChild(this.toolRenderedElement);
|
||||
|
||||
/**
|
||||
* Block Tunes might wrap Block's content node to provide any UI changes
|
||||
|
|
|
|||
|
|
@ -550,20 +550,6 @@ export default class Dom {
|
|||
return element;
|
||||
}
|
||||
|
||||
/**
|
||||
* Method checks passed Node if it is some extension Node
|
||||
*
|
||||
* @param {Node} node - any node
|
||||
* @returns {boolean}
|
||||
*/
|
||||
public static isExtensionNode(node: Node): boolean {
|
||||
const extensions = [
|
||||
'GRAMMARLY-EXTENSION',
|
||||
];
|
||||
|
||||
return node && extensions.includes(node.nodeName);
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns true if element is anchor (is A tag)
|
||||
*
|
||||
|
|
|
|||
|
|
@ -346,6 +346,10 @@ export default class Paste extends Module {
|
|||
* @param tool - BlockTool object
|
||||
*/
|
||||
private getTagsConfig(tool: BlockTool): void {
|
||||
if (tool.pasteConfig === false) {
|
||||
return;
|
||||
}
|
||||
|
||||
const tagsOrSanitizeConfigs = tool.pasteConfig.tags || [];
|
||||
const toolTags = [];
|
||||
|
||||
|
|
@ -387,6 +391,10 @@ export default class Paste extends Module {
|
|||
* @param tool - BlockTool object
|
||||
*/
|
||||
private getFilesConfig(tool: BlockTool): void {
|
||||
if (tool.pasteConfig === false) {
|
||||
return;
|
||||
}
|
||||
|
||||
const { files = {} } = tool.pasteConfig;
|
||||
let { extensions, mimeTypes } = files;
|
||||
|
||||
|
|
@ -428,7 +436,11 @@ export default class Paste extends Module {
|
|||
* @param tool - BlockTool object
|
||||
*/
|
||||
private getPatternsConfig(tool: BlockTool): void {
|
||||
if (!tool.pasteConfig.patterns || _.isEmpty(tool.pasteConfig.patterns)) {
|
||||
if (
|
||||
tool.pasteConfig === false ||
|
||||
!tool.pasteConfig.patterns ||
|
||||
_.isEmpty(tool.pasteConfig.patterns)
|
||||
) {
|
||||
return;
|
||||
}
|
||||
|
||||
|
|
@ -602,7 +614,10 @@ export default class Paste extends Module {
|
|||
break;
|
||||
}
|
||||
|
||||
const { tags: tagsOrSanitizeConfigs } = tool.pasteConfig;
|
||||
/**
|
||||
* Returns empty array if there is no paste config
|
||||
*/
|
||||
const { tags: tagsOrSanitizeConfigs } = tool.pasteConfig || { tags: [] };
|
||||
|
||||
/**
|
||||
* Reduce the tags or sanitize configs to a single array of sanitize config.
|
||||
|
|
|
|||
|
|
@ -158,7 +158,7 @@ export default class BlockTool extends BaseTool<IBlockTool> {
|
|||
* Returns Tool paste configuration
|
||||
*/
|
||||
public get pasteConfig(): PasteConfig {
|
||||
return this.constructable[InternalBlockToolSettings.PasteConfig] || {};
|
||||
return this.constructable[InternalBlockToolSettings.PasteConfig] ?? {};
|
||||
}
|
||||
|
||||
/**
|
||||
|
|
|
|||
|
|
@ -70,7 +70,7 @@ Cypress.Commands.add('paste', {
|
|||
* Usage:
|
||||
* cy.get('div').copy().then(data => {})
|
||||
*/
|
||||
Cypress.Commands.add('copy', { prevSubject: true }, async (subject) => {
|
||||
Cypress.Commands.add('copy', { prevSubject: true }, (subject) => {
|
||||
const clipboardData: {[type: string]: any} = {};
|
||||
|
||||
const copyEvent = Object.assign(new Event('copy', {
|
||||
|
|
@ -87,7 +87,7 @@ Cypress.Commands.add('copy', { prevSubject: true }, async (subject) => {
|
|||
|
||||
subject[0].dispatchEvent(copyEvent);
|
||||
|
||||
return clipboardData;
|
||||
return cy.wrap(clipboardData);
|
||||
});
|
||||
|
||||
/**
|
||||
|
|
@ -96,7 +96,7 @@ Cypress.Commands.add('copy', { prevSubject: true }, async (subject) => {
|
|||
* Usage:
|
||||
* cy.get('div').cut().then(data => {})
|
||||
*/
|
||||
Cypress.Commands.add('cut', { prevSubject: true }, async (subject) => {
|
||||
Cypress.Commands.add('cut', { prevSubject: true }, (subject) => {
|
||||
const clipboardData: {[type: string]: any} = {};
|
||||
|
||||
const copyEvent = Object.assign(new Event('cut', {
|
||||
|
|
@ -113,7 +113,7 @@ Cypress.Commands.add('cut', { prevSubject: true }, async (subject) => {
|
|||
|
||||
subject[0].dispatchEvent(copyEvent);
|
||||
|
||||
return clipboardData;
|
||||
return cy.wrap(clipboardData);
|
||||
});
|
||||
|
||||
/**
|
||||
|
|
@ -121,10 +121,10 @@ Cypress.Commands.add('cut', { prevSubject: true }, async (subject) => {
|
|||
*
|
||||
* @param data — data to render
|
||||
*/
|
||||
Cypress.Commands.add('render', { prevSubject: true }, async (subject: EditorJS, data: OutputData): Promise<EditorJS> => {
|
||||
await subject.render(data);
|
||||
Cypress.Commands.add('render', { prevSubject: true }, (subject: EditorJS, data: OutputData) => {
|
||||
subject.render(data);
|
||||
|
||||
return subject;
|
||||
return cy.wrap(subject);
|
||||
});
|
||||
|
||||
|
||||
|
|
|
|||
6
test/cypress/support/index.d.ts
vendored
|
|
@ -31,7 +31,7 @@ declare global {
|
|||
* @usage
|
||||
* cy.get('div').copy().then(data => {})
|
||||
*/
|
||||
copy(): Chainable<{ [type: string]: any }>;
|
||||
copy(): Chainable<Subject>;
|
||||
|
||||
/**
|
||||
* Cut command to dispatch cut event on subject
|
||||
|
|
@ -39,14 +39,14 @@ declare global {
|
|||
* @usage
|
||||
* cy.get('div').cut().then(data => {})
|
||||
*/
|
||||
cut(): Chainable<{ [type: string]: any }>;
|
||||
cut(): Chainable<Subject>;
|
||||
|
||||
/**
|
||||
* Calls EditorJS API render method
|
||||
*
|
||||
* @param data — data to render
|
||||
*/
|
||||
render(data: OutputData): Chainable<EditorJS>;
|
||||
render(data: OutputData): Chainable<Subject>;
|
||||
|
||||
/**
|
||||
* Select passed text in element
|
||||
|
|
|
|||
|
|
@ -1,6 +1,8 @@
|
|||
import Header from '@editorjs/header';
|
||||
import Image from '@editorjs/simple-image';
|
||||
import * as _ from '../../../src/components/utils';
|
||||
import EditorJS, { BlockTool, BlockToolData } from '../../../types';
|
||||
import $ from '../../../src/components/dom';
|
||||
|
||||
describe('Copy pasting from Editor', function () {
|
||||
beforeEach(function () {
|
||||
|
|
@ -13,7 +15,7 @@ describe('Copy pasting from Editor', function () {
|
|||
});
|
||||
|
||||
afterEach(function () {
|
||||
if (this.editorInstance) {
|
||||
if (this.editorInstance && this.editorInstance.destroy) {
|
||||
this.editorInstance.destroy();
|
||||
}
|
||||
});
|
||||
|
|
@ -139,6 +141,72 @@ describe('Copy pasting from Editor', function () {
|
|||
.get('img', { timeout: 10000 })
|
||||
.should('have.attr', 'src', 'https://codex.so/public/app/img/external/codex2x.png');
|
||||
});
|
||||
|
||||
it('should not prevent default behaviour if block\'s paste config equals false', function () {
|
||||
/**
|
||||
* Destroy default Editor to render custom one with different tools
|
||||
*/
|
||||
cy.get('@editorInstance')
|
||||
.then((editorInstance: unknown) => (editorInstance as EditorJS).destroy());
|
||||
|
||||
const onPasteStub = cy.stub().as('onPaste');
|
||||
|
||||
/**
|
||||
* Tool with disabled preventing default behavior of onPaste event
|
||||
*/
|
||||
class BlockToolWithPasteHandler implements BlockTool {
|
||||
public static pasteConfig = false;
|
||||
|
||||
/**
|
||||
* Render block
|
||||
*/
|
||||
public render(): HTMLElement {
|
||||
const block = $.make('div', 'ce-block-with-disabled-prevent-default', {
|
||||
contentEditable: 'true',
|
||||
});
|
||||
|
||||
block.addEventListener('paste', onPasteStub);
|
||||
|
||||
return block;
|
||||
}
|
||||
|
||||
/**
|
||||
* Save data method
|
||||
*/
|
||||
public save(): BlockToolData {
|
||||
return {};
|
||||
}
|
||||
}
|
||||
|
||||
cy.createEditor({
|
||||
tools: {
|
||||
blockToolWithPasteHandler: BlockToolWithPasteHandler,
|
||||
},
|
||||
}).as('editorInstanceWithBlockToolWithPasteHandler');
|
||||
|
||||
cy.get('@editorInstanceWithBlockToolWithPasteHandler')
|
||||
.render({
|
||||
blocks: [
|
||||
{
|
||||
type: 'blockToolWithPasteHandler',
|
||||
data: {},
|
||||
},
|
||||
],
|
||||
});
|
||||
|
||||
cy.get('@editorInstanceWithBlockToolWithPasteHandler')
|
||||
.get('div.ce-block-with-disabled-prevent-default')
|
||||
.click()
|
||||
.paste({
|
||||
// eslint-disable-next-line @typescript-eslint/naming-convention
|
||||
'text/plain': 'Hello',
|
||||
});
|
||||
|
||||
cy.get('@onPaste')
|
||||
.should('have.been.calledWithMatch', {
|
||||
defaultPrevented: false,
|
||||
});
|
||||
});
|
||||
});
|
||||
|
||||
context('copying', function () {
|
||||
37
test/cypress/tests/modules/Saver.cy.ts
Normal file
|
|
@ -0,0 +1,37 @@
|
|||
import type EditorJS from '../../../../types/index';
|
||||
|
||||
describe('Saver module', function () {
|
||||
describe('save()', function () {
|
||||
it('should correctly save block if there are some 3rd party (eg. browser extensions) nodes inserted into the layout', function () {
|
||||
cy.createEditor({
|
||||
data: {
|
||||
blocks: [
|
||||
{
|
||||
type: 'paragraph',
|
||||
data: {
|
||||
text: 'The block with some text',
|
||||
},
|
||||
},
|
||||
],
|
||||
},
|
||||
}).then((editor: EditorJS) => {
|
||||
/**
|
||||
* Add some node just like browser extensions doing
|
||||
*/
|
||||
const extensionNode = document.createElement('extension-node');
|
||||
|
||||
cy.get('[data-cy=editorjs]')
|
||||
.find('.ce-block__content')
|
||||
.then((blockContent) => {
|
||||
blockContent.append(extensionNode);
|
||||
})
|
||||
.then(async () => {
|
||||
const savedData = await editor.save();
|
||||
|
||||
expect(savedData.blocks.length).to.equal(1);
|
||||
expect(savedData.blocks[0].data.text).to.equal('The block with some text');
|
||||
});
|
||||
});
|
||||
});
|
||||
});
|
||||
});
|
||||
|
|
@ -253,10 +253,36 @@ describe('BlockTool', () => {
|
|||
expect(tool.conversionConfig).to.be.deep.eq(options.constructable.conversionConfig);
|
||||
});
|
||||
|
||||
it('.pasteConfig should return correct value', () => {
|
||||
const tool = new BlockTool(options as any);
|
||||
describe('.pasteConfig', () => {
|
||||
it('should return correct value', () => {
|
||||
const tool = new BlockTool(options as any);
|
||||
|
||||
expect(tool.pasteConfig).to.be.deep.eq(options.constructable.pasteConfig);
|
||||
expect(tool.pasteConfig).to.be.deep.eq(options.constructable.pasteConfig);
|
||||
});
|
||||
|
||||
it('should return false if `false` value was provided', () => {
|
||||
const optionsWithDisabledPaste = {
|
||||
...options,
|
||||
constructable: class extends (options.constructable as any) {
|
||||
public static pasteConfig = false;
|
||||
},
|
||||
};
|
||||
const tool = new BlockTool(optionsWithDisabledPaste as any);
|
||||
|
||||
expect(tool.pasteConfig).to.be.deep.eq(optionsWithDisabledPaste.constructable.pasteConfig);
|
||||
});
|
||||
|
||||
it('should return empty object if getter isn\'t provided', () => {
|
||||
const optionsWithoutPasteConfig = {
|
||||
...options,
|
||||
constructable: class extends (options.constructable as any) {
|
||||
public static pasteConfig = undefined;
|
||||
},
|
||||
};
|
||||
const tool = new BlockTool(optionsWithoutPasteConfig as any);
|
||||
|
||||
expect(tool.pasteConfig).to.be.deep.eq({});
|
||||
});
|
||||
});
|
||||
|
||||
context('.enabledInlineTools', () => {
|
||||
11
types/configs/paste-config.d.ts
vendored
|
|
@ -1,9 +1,9 @@
|
|||
import { SanitizerConfig } from "./sanitizer-config";
|
||||
import { SanitizerConfig } from './sanitizer-config';
|
||||
|
||||
/**
|
||||
* Tool onPaste configuration object
|
||||
*/
|
||||
export interface PasteConfig {
|
||||
interface PasteConfigSpecified {
|
||||
/**
|
||||
* Array of tags Tool can substitute.
|
||||
*
|
||||
|
|
@ -22,7 +22,7 @@ export interface PasteConfig {
|
|||
* Object of string patterns Tool can substitute.
|
||||
* Key is your internal key and value is RegExp
|
||||
*
|
||||
* @type {{[key: string]: Regexp}}
|
||||
* @type {{[key: string]: RegExp}}
|
||||
*/
|
||||
patterns?: {[key: string]: RegExp};
|
||||
|
||||
|
|
@ -31,3 +31,8 @@ export interface PasteConfig {
|
|||
*/
|
||||
files?: {extensions?: string[], mimeTypes?: string[]};
|
||||
}
|
||||
|
||||
/**
|
||||
* Alias for PasteConfig with false
|
||||
*/
|
||||
export type PasteConfig = PasteConfigSpecified | false;
|
||||
|
|
|
|||