Build tools improvement: vite for bundling & migrate tests to TS (#128)
* rename tests to ts * setup vite & karma-vite; remove webpack; migrate test files to ts * remove redundant comment
This commit is contained in:
parent
c4d59d9f1f
commit
63efc455ea
@ -1,46 +1,15 @@
|
||||
// eslint-disable-next-line @typescript-eslint/no-var-requires
|
||||
const webpackConfig = require('./webpack.conf');
|
||||
|
||||
module.exports = (config) => {
|
||||
config.set({
|
||||
basePath: '',
|
||||
frameworks: ['jasmine'],
|
||||
plugins: ['karma-jasmine', 'karma-vite', 'karma-chrome-launcher', 'karma-sauce-launcher'],
|
||||
frameworks: ['jasmine', 'vite'],
|
||||
files: [
|
||||
'test/parchment.ts',
|
||||
'test/setup.js',
|
||||
'test/registry/*.js',
|
||||
'test/unit/linked-list.js', // Control test order
|
||||
'test/unit/registry.js',
|
||||
'test/unit/attributor.js',
|
||||
'test/unit/blot.js',
|
||||
'test/unit/parent.js',
|
||||
'test/unit/scroll.js',
|
||||
'test/unit/container.js',
|
||||
'test/unit/block.js',
|
||||
'test/unit/inline.js',
|
||||
'test/unit/embed.js',
|
||||
'test/unit/text.js',
|
||||
'test/unit/lifecycle.js',
|
||||
],
|
||||
preprocessors: {
|
||||
'test/registry/*.js': ['babel'],
|
||||
'test/parchment.ts': ['webpack'],
|
||||
},
|
||||
mime: {
|
||||
'text/x-typescript': ['ts'],
|
||||
},
|
||||
webpack: webpackConfig,
|
||||
webpackMiddleware: {
|
||||
stats: {
|
||||
assets: false,
|
||||
chunks: false,
|
||||
colors: true,
|
||||
errorDetails: true,
|
||||
hash: false,
|
||||
timings: false,
|
||||
version: false,
|
||||
{
|
||||
pattern: 'test/unit/*.ts',
|
||||
type: 'module',
|
||||
watched: false,
|
||||
served: false,
|
||||
},
|
||||
},
|
||||
],
|
||||
exclude: [],
|
||||
reporters: ['progress'],
|
||||
browsers: ['Chrome'],
|
||||
|
||||
4170
package-lock.json
generated
4170
package-lock.json
generated
File diff suppressed because it is too large
Load Diff
22
package.json
22
package.json
@ -12,29 +12,24 @@
|
||||
"src"
|
||||
],
|
||||
"devDependencies": {
|
||||
"@babel/core": "^7.17.5",
|
||||
"@microsoft/api-extractor": "^7.34.4",
|
||||
"@microsoft/api-extractor": "^7.34.6",
|
||||
"@types/node": "^18.15.11",
|
||||
"@typescript-eslint/eslint-plugin": "^5.14.0",
|
||||
"@typescript-eslint/parser": "^5.14.0",
|
||||
"babel-loader": "^8.2.3",
|
||||
"del-cli": "^4.0.1",
|
||||
"eslint": "^8.10.0",
|
||||
"eslint-config-prettier": "^8.5.0",
|
||||
"eslint-plugin-prettier": "^4.0.0",
|
||||
"jasmine-core": "^4.0.1",
|
||||
"karma": "^6.3.17",
|
||||
"jasmine-core": "^4.6.0",
|
||||
"karma": "^6.4.2",
|
||||
"karma-babel-preprocessor": "^8.0.2",
|
||||
"karma-chrome-launcher": "^3.1.1",
|
||||
"karma-jasmine": "^4.0.1",
|
||||
"karma-chrome-launcher": "^3.2.0",
|
||||
"karma-jasmine": "^5.1.0",
|
||||
"karma-sauce-launcher": "^4.3.6",
|
||||
"karma-webpack": "^5.0.0",
|
||||
"karma-vite": "^1.0.4",
|
||||
"prettier": "^2.5.1",
|
||||
"ts-loader": "^9.2.8",
|
||||
"tsd": "^0.28.1",
|
||||
"typescript": "^4.9.5",
|
||||
"webpack": "^5.70.0",
|
||||
"webpack-cli": "^4.9.2"
|
||||
"vite": "^4.2.1"
|
||||
},
|
||||
"eslintConfig": {
|
||||
"parser": "@typescript-eslint/parser",
|
||||
@ -68,9 +63,8 @@
|
||||
"url": "https://github.com/quilljs/parchment"
|
||||
},
|
||||
"scripts": {
|
||||
"build": "webpack --config webpack.conf.js",
|
||||
"build": "vite build",
|
||||
"build:types": "tsc --emitDeclarationOnly && api-extractor run && rm -rf dist/typings",
|
||||
"prebuild": "del-cli dist",
|
||||
"lint": "eslint 'src/**/*.ts'",
|
||||
"prepare": "npm run build && npm run build:types",
|
||||
"test": "karma start",
|
||||
|
||||
@ -9,7 +9,7 @@ import InlineBlot from './inline';
|
||||
class BlockBlot extends ParentBlot implements Formattable {
|
||||
public static blotName = 'block';
|
||||
public static scope = Scope.BLOCK_BLOT;
|
||||
public static tagName = 'P';
|
||||
public static tagName: string | string[] = 'P';
|
||||
public static allowedChildren: BlotConstructor[] = [
|
||||
InlineBlot,
|
||||
BlockBlot,
|
||||
|
||||
@ -29,7 +29,7 @@ class InlineBlot extends ParentBlot implements Formattable {
|
||||
public static allowedChildren: BlotConstructor[] = [InlineBlot, LeafBlot];
|
||||
public static blotName = 'inline';
|
||||
public static scope = Scope.INLINE_BLOT;
|
||||
public static tagName = 'SPAN';
|
||||
public static tagName: string | string[] = 'SPAN';
|
||||
|
||||
public static formats(domNode: HTMLElement, scroll: Root): any {
|
||||
const match = scroll.query(InlineBlot.blotName);
|
||||
|
||||
@ -1,61 +0,0 @@
|
||||
import Attributor from '../src/attributor/attributor';
|
||||
import ClassAttributor from '../src/attributor/class';
|
||||
import StyleAttributor from '../src/attributor/style';
|
||||
|
||||
import ShadowBlot from '../src/blot/abstract/shadow';
|
||||
import ParentBlot from '../src/blot/abstract/parent';
|
||||
import ContainerBlot from '../src/blot/abstract/container';
|
||||
import LeafBlot from '../src/blot/abstract/leaf';
|
||||
|
||||
import ScrollBlot from '../src/blot/scroll';
|
||||
import BlockBlot from '../src/blot/block';
|
||||
import InlineBlot from '../src/blot/inline';
|
||||
import EmbedBlot from '../src/blot/embed';
|
||||
import TextBlot from '../src/blot/text';
|
||||
|
||||
import LinkedList from '../src/collection/linked-list';
|
||||
import Registry from '../src/registry';
|
||||
import Scope from '../src/scope';
|
||||
|
||||
const TestRegistry = new Registry();
|
||||
|
||||
// @ts-expect-error
|
||||
window['Attributor'] = Attributor;
|
||||
// @ts-expect-error
|
||||
window['ClassAttributor'] = ClassAttributor;
|
||||
// @ts-expect-error
|
||||
window['StyleAttributor'] = StyleAttributor;
|
||||
|
||||
// @ts-expect-error
|
||||
window['ShadowBlot'] = ShadowBlot;
|
||||
// @ts-expect-error
|
||||
window['ParentBlot'] = ParentBlot;
|
||||
// @ts-expect-error
|
||||
window['LeafBlot'] = LeafBlot;
|
||||
// @ts-expect-error
|
||||
window['EmbedBlot'] = EmbedBlot;
|
||||
|
||||
// @ts-expect-error
|
||||
window['ScrollBlot'] = ScrollBlot;
|
||||
// @ts-expect-error
|
||||
window['ContainerBlot'] = ContainerBlot;
|
||||
// @ts-expect-error
|
||||
window['BlockBlot'] = BlockBlot;
|
||||
// @ts-expect-error
|
||||
window['InlineBlot'] = InlineBlot;
|
||||
// @ts-expect-error
|
||||
window['TextBlot'] = TextBlot;
|
||||
|
||||
// @ts-expect-error
|
||||
window['LinkedList'] = LinkedList;
|
||||
// @ts-expect-error
|
||||
window['Scope'] = Scope;
|
||||
// @ts-expect-error
|
||||
window['Registry'] = Registry;
|
||||
// @ts-expect-error
|
||||
window['TestRegistry'] = TestRegistry;
|
||||
|
||||
TestRegistry.register(ScrollBlot);
|
||||
TestRegistry.register(BlockBlot);
|
||||
TestRegistry.register(InlineBlot);
|
||||
TestRegistry.register(TextBlot);
|
||||
@ -1,27 +0,0 @@
|
||||
'use strict';
|
||||
|
||||
let Color = new StyleAttributor('color', 'color', {
|
||||
scope: Scope.INLINE_ATTRIBUTE,
|
||||
});
|
||||
|
||||
let Size = new StyleAttributor('size', 'font-size', {
|
||||
scope: Scope.INLINE_ATTRIBUTE,
|
||||
});
|
||||
|
||||
let Family = new StyleAttributor('family', 'font-family', {
|
||||
scope: Scope.INLINE_ATTRIBUTE,
|
||||
whitelist: ['Arial', 'Times New Roman'],
|
||||
});
|
||||
|
||||
let Id = new Attributor('id', 'id');
|
||||
|
||||
let Align = new StyleAttributor('align', 'text-align', {
|
||||
scope: Scope.BLOCK_ATTRIBUTE,
|
||||
whitelist: ['right', 'center'], // exclude justify to test valid but missing from whitelist
|
||||
});
|
||||
|
||||
let Indent = new ClassAttributor('indent', 'indent', {
|
||||
scope: Scope.BLOCK_ATTRIBUTE,
|
||||
});
|
||||
|
||||
TestRegistry.register(Color, Size, Family, Id, Align, Indent);
|
||||
28
test/registry/attributor.ts
Normal file
28
test/registry/attributor.ts
Normal file
@ -0,0 +1,28 @@
|
||||
import Attributor from '../../src/attributor/attributor';
|
||||
import ClassAttributor from '../../src/attributor/class';
|
||||
import StyleAttributor from '../../src/attributor/style';
|
||||
import Scope from '../../src/scope';
|
||||
|
||||
export const Color = new StyleAttributor('color', 'color', {
|
||||
scope: Scope.INLINE_ATTRIBUTE,
|
||||
});
|
||||
|
||||
export const Size = new StyleAttributor('size', 'font-size', {
|
||||
scope: Scope.INLINE_ATTRIBUTE,
|
||||
});
|
||||
|
||||
export const Family = new StyleAttributor('family', 'font-family', {
|
||||
scope: Scope.INLINE_ATTRIBUTE,
|
||||
whitelist: ['Arial', 'Times New Roman'],
|
||||
});
|
||||
|
||||
export const Id = new Attributor('id', 'id');
|
||||
|
||||
export const Align = new StyleAttributor('align', 'text-align', {
|
||||
scope: Scope.BLOCK_ATTRIBUTE,
|
||||
whitelist: ['right', 'center'], // exclude justify to test valid but missing from whitelist
|
||||
});
|
||||
|
||||
export const Indent = new ClassAttributor('indent', 'indent', {
|
||||
scope: Scope.BLOCK_ATTRIBUTE,
|
||||
});
|
||||
@ -1,7 +0,0 @@
|
||||
'use strict';
|
||||
|
||||
class HeaderBlot extends BlockBlot {}
|
||||
HeaderBlot.blotName = 'header';
|
||||
HeaderBlot.tagName = ['h1', 'h2'];
|
||||
|
||||
TestRegistry.register(HeaderBlot);
|
||||
5
test/registry/block.ts
Normal file
5
test/registry/block.ts
Normal file
@ -0,0 +1,5 @@
|
||||
import BlockBlot from '../../src/blot/block';
|
||||
|
||||
export class HeaderBlot extends BlockBlot {}
|
||||
HeaderBlot.blotName = 'header';
|
||||
HeaderBlot.tagName = ['h1', 'h2'];
|
||||
@ -1,7 +0,0 @@
|
||||
'use strict';
|
||||
|
||||
class BreakBlot extends EmbedBlot {}
|
||||
BreakBlot.blotName = 'break';
|
||||
BreakBlot.tagName = 'br';
|
||||
|
||||
TestRegistry.register(BreakBlot);
|
||||
5
test/registry/break.ts
Normal file
5
test/registry/break.ts
Normal file
@ -0,0 +1,5 @@
|
||||
import EmbedBlot from '../../src/blot/embed';
|
||||
|
||||
export class BreakBlot extends EmbedBlot {}
|
||||
BreakBlot.blotName = 'break';
|
||||
BreakBlot.tagName = 'br';
|
||||
@ -1,6 +1,7 @@
|
||||
'use strict';
|
||||
import EmbedBlot from '../../src/blot/embed';
|
||||
import Scope from '../../src/scope';
|
||||
|
||||
class ImageBlot extends EmbedBlot {
|
||||
export class ImageBlot extends EmbedBlot {
|
||||
static create(value) {
|
||||
let node = super.create(value);
|
||||
if (typeof value === 'string') {
|
||||
@ -31,7 +32,7 @@ class ImageBlot extends EmbedBlot {
|
||||
ImageBlot.blotName = 'image';
|
||||
ImageBlot.tagName = 'IMG';
|
||||
|
||||
class VideoBlot extends EmbedBlot {
|
||||
export class VideoBlot extends EmbedBlot {
|
||||
static create(value) {
|
||||
let node = super.create(value);
|
||||
if (typeof value === 'string') {
|
||||
@ -68,6 +69,3 @@ class VideoBlot extends EmbedBlot {
|
||||
VideoBlot.blotName = 'video';
|
||||
VideoBlot.scope = Scope.BLOCK_BLOT;
|
||||
VideoBlot.tagName = 'VIDEO';
|
||||
|
||||
TestRegistry.register(ImageBlot);
|
||||
TestRegistry.register(VideoBlot);
|
||||
@ -1,19 +1,17 @@
|
||||
'use strict';
|
||||
import InlineBlot from '../../src/blot/inline';
|
||||
|
||||
class AuthorBlot extends InlineBlot {}
|
||||
export class AuthorBlot extends InlineBlot {}
|
||||
AuthorBlot.blotName = 'author';
|
||||
AuthorBlot.className = 'author-blot';
|
||||
|
||||
class BoldBlot extends InlineBlot {}
|
||||
export class BoldBlot extends InlineBlot {}
|
||||
BoldBlot.blotName = 'bold';
|
||||
BoldBlot.tagName = 'STRONG';
|
||||
|
||||
class ItalicBlot extends InlineBlot {}
|
||||
export class ItalicBlot extends InlineBlot {}
|
||||
ItalicBlot.blotName = 'italic';
|
||||
ItalicBlot.tagName = 'em';
|
||||
|
||||
class ScriptBlot extends InlineBlot {}
|
||||
export class ScriptBlot extends InlineBlot {}
|
||||
ScriptBlot.blotName = 'script';
|
||||
ScriptBlot.tagName = ['sup', 'sub'];
|
||||
|
||||
TestRegistry.register(AuthorBlot, BoldBlot, ItalicBlot, ScriptBlot);
|
||||
@ -1,15 +1,13 @@
|
||||
'use strict';
|
||||
import ContainerBlot from '../../src/blot/abstract/container';
|
||||
import BlockBlot from '../../src/blot/block';
|
||||
|
||||
class ListItem extends BlockBlot {}
|
||||
export class ListItem extends BlockBlot {}
|
||||
ListItem.blotName = 'list';
|
||||
ListItem.tagName = 'LI';
|
||||
|
||||
class ListContainer extends ContainerBlot {}
|
||||
export class ListContainer extends ContainerBlot {}
|
||||
ListContainer.blotName = 'list-container';
|
||||
ListContainer.tagName = 'OL';
|
||||
|
||||
ListContainer.allowedChildren = [ListItem];
|
||||
ListItem.requiredContainer = ListContainer;
|
||||
|
||||
TestRegistry.register(ListItem);
|
||||
TestRegistry.register(ListContainer);
|
||||
@ -1,9 +0,0 @@
|
||||
beforeEach(function () {
|
||||
this.container = document.createElement('div');
|
||||
this.scroll = new ScrollBlot(TestRegistry, this.container);
|
||||
});
|
||||
|
||||
afterEach(function () {
|
||||
this.container = null;
|
||||
this.scroll = null;
|
||||
});
|
||||
54
test/setup.ts
Normal file
54
test/setup.ts
Normal file
@ -0,0 +1,54 @@
|
||||
import Registry from '../src/registry';
|
||||
|
||||
import ScrollBlot from '../src/blot/scroll';
|
||||
import BlockBlot from '../src/blot/block';
|
||||
import InlineBlot from '../src/blot/inline';
|
||||
import TextBlot from '../src/blot/text';
|
||||
import {
|
||||
AuthorBlot,
|
||||
BoldBlot,
|
||||
ItalicBlot,
|
||||
ScriptBlot,
|
||||
} from './registry/inline';
|
||||
import { Align, Color, Family, Id, Indent, Size } from './registry/attributor';
|
||||
import { HeaderBlot } from './registry/block';
|
||||
import { ImageBlot, VideoBlot } from './registry/embed';
|
||||
import { ListContainer, ListItem } from './registry/list';
|
||||
import { BreakBlot } from './registry/break';
|
||||
|
||||
const getTestRegistry = () => {
|
||||
const reg = new Registry();
|
||||
|
||||
reg.register(ScrollBlot);
|
||||
reg.register(BlockBlot);
|
||||
reg.register(InlineBlot);
|
||||
reg.register(TextBlot);
|
||||
reg.register(AuthorBlot, BoldBlot, ItalicBlot, ScriptBlot);
|
||||
|
||||
reg.register(Color, Size, Family, Id, Align, Indent);
|
||||
reg.register(HeaderBlot);
|
||||
reg.register(ImageBlot, VideoBlot);
|
||||
reg.register(ListItem, ListContainer);
|
||||
reg.register(BreakBlot);
|
||||
|
||||
return reg;
|
||||
};
|
||||
|
||||
type TestContext = {
|
||||
container: HTMLElement;
|
||||
scroll: ScrollBlot;
|
||||
registry: Registry;
|
||||
};
|
||||
|
||||
export const setupContextBeforeEach = () => {
|
||||
const ctx: TestContext = {} as TestContext;
|
||||
beforeEach(() => {
|
||||
const container = document.createElement('div');
|
||||
const registry = getTestRegistry();
|
||||
const scroll = new ScrollBlot(registry, container);
|
||||
ctx.container = container;
|
||||
ctx.scroll = scroll;
|
||||
ctx.registry = registry;
|
||||
});
|
||||
return ctx;
|
||||
};
|
||||
@ -1,8 +1,10 @@
|
||||
'use strict';
|
||||
import { setupContextBeforeEach } from '../setup';
|
||||
|
||||
describe('Attributor', function () {
|
||||
const ctx = setupContextBeforeEach();
|
||||
|
||||
it('build', function () {
|
||||
let blot = this.scroll.create('inline');
|
||||
let blot = ctx.scroll.create('inline');
|
||||
blot.domNode.style.color = 'red';
|
||||
blot.domNode.style.fontSize = '24px';
|
||||
blot.domNode.id = 'blot-test';
|
||||
@ -14,8 +16,8 @@ describe('Attributor', function () {
|
||||
});
|
||||
|
||||
it('add to inline', function () {
|
||||
let container = this.scroll.create('block');
|
||||
let boldBlot = this.scroll.create('bold');
|
||||
let container = ctx.scroll.create('block');
|
||||
let boldBlot = ctx.scroll.create('bold');
|
||||
container.appendChild(boldBlot);
|
||||
boldBlot.format('id', 'test-add');
|
||||
expect(boldBlot.domNode.id).toEqual('test-add');
|
||||
@ -24,7 +26,7 @@ describe('Attributor', function () {
|
||||
it('add multiple', function () {
|
||||
let node = document.createElement('p');
|
||||
node.innerHTML = '<em><strong>0</strong></em>';
|
||||
let container = this.scroll.create(node);
|
||||
let container = ctx.scroll.create(node);
|
||||
container.formatAt(0, 1, 'color', 'red');
|
||||
container.formatAt(0, 1, 'size', '18px');
|
||||
expect(node.innerHTML).toEqual(
|
||||
@ -33,15 +35,15 @@ describe('Attributor', function () {
|
||||
});
|
||||
|
||||
it('add to text', function () {
|
||||
let container = this.scroll.create('block');
|
||||
let textBlot = this.scroll.create('text', 'Test');
|
||||
let container = ctx.scroll.create('block');
|
||||
let textBlot = ctx.scroll.create('text', 'Test');
|
||||
container.appendChild(textBlot);
|
||||
textBlot.formatAt(0, 4, 'color', 'red');
|
||||
expect(textBlot.domNode.parentNode.style.color).toEqual('red');
|
||||
});
|
||||
|
||||
it('add existing style', function () {
|
||||
let boldBlot = this.scroll.create('bold');
|
||||
let boldBlot = ctx.scroll.create('bold');
|
||||
boldBlot.format('color', 'red');
|
||||
expect(boldBlot.domNode.style.color).toEqual('red');
|
||||
let original = boldBlot.domNode.outerHTML;
|
||||
@ -52,7 +54,7 @@ describe('Attributor', function () {
|
||||
});
|
||||
|
||||
it('replace existing class', function () {
|
||||
let blockBlot = this.scroll.create('block');
|
||||
let blockBlot = ctx.scroll.create('block');
|
||||
blockBlot.format('indent', 2);
|
||||
expect(blockBlot.domNode.classList.contains('indent-2')).toBe(true);
|
||||
blockBlot.format('indent', 3);
|
||||
@ -61,23 +63,23 @@ describe('Attributor', function () {
|
||||
});
|
||||
|
||||
it('add whitelist style', function () {
|
||||
let blockBlot = this.scroll.create('block');
|
||||
let blockBlot = ctx.scroll.create('block');
|
||||
blockBlot.format('align', 'right');
|
||||
expect(blockBlot.domNode.style.textAlign).toBe('right');
|
||||
});
|
||||
|
||||
it('add non-whitelisted style', function () {
|
||||
let blockBlot = this.scroll.create('block');
|
||||
let blockBlot = ctx.scroll.create('block');
|
||||
blockBlot.format('align', 'justify');
|
||||
expect(blockBlot.domNode.style.textAlign).toBeFalsy();
|
||||
});
|
||||
|
||||
it('unwrap', function () {
|
||||
let container = this.scroll.create('block');
|
||||
let container = ctx.scroll.create('block');
|
||||
let node = document.createElement('strong');
|
||||
node.style.color = 'red';
|
||||
node.innerHTML = '<em>01</em>23';
|
||||
let blot = this.scroll.create(node);
|
||||
let blot = ctx.scroll.create(node);
|
||||
container.appendChild(blot);
|
||||
container.formatAt(0, 4, 'bold', false);
|
||||
expect(container.domNode.innerHTML).toEqual(
|
||||
@ -86,14 +88,14 @@ describe('Attributor', function () {
|
||||
});
|
||||
|
||||
it('remove', function () {
|
||||
let container = this.scroll.create('block');
|
||||
let container = ctx.scroll.create('block');
|
||||
let node = document.createElement('strong');
|
||||
node.innerHTML = 'Bold';
|
||||
node.style.color = 'red';
|
||||
node.style.fontSize = '24px';
|
||||
container.domNode.classList.add('indent-5');
|
||||
container.domNode.id = 'test-remove';
|
||||
let boldBlot = this.scroll.create(node);
|
||||
let boldBlot = ctx.scroll.create(node);
|
||||
container.appendChild(boldBlot);
|
||||
container.formatAt(1, 2, 'color', false);
|
||||
expect(container.children.length).toEqual(3);
|
||||
@ -109,17 +111,17 @@ describe('Attributor', function () {
|
||||
});
|
||||
|
||||
it('remove nonexistent', function () {
|
||||
let container = this.scroll.create('block');
|
||||
let container = ctx.scroll.create('block');
|
||||
let node = document.createElement('strong');
|
||||
node.innerHTML = 'Bold';
|
||||
let boldBlot = this.scroll.create(node);
|
||||
let boldBlot = ctx.scroll.create(node);
|
||||
container.appendChild(boldBlot);
|
||||
boldBlot.format('color', false);
|
||||
expect(container.domNode.innerHTML).toEqual('<strong>Bold</strong>');
|
||||
});
|
||||
|
||||
it('keep class attribute after removal', function () {
|
||||
let boldBlot = this.scroll.create('bold');
|
||||
let boldBlot = ctx.scroll.create('bold');
|
||||
boldBlot.domNode.classList.add('blot');
|
||||
boldBlot.format('indent', 2);
|
||||
boldBlot.format('indent', false);
|
||||
@ -127,11 +129,11 @@ describe('Attributor', function () {
|
||||
});
|
||||
|
||||
it('move attribute', function () {
|
||||
let container = this.scroll.create('block');
|
||||
let container = ctx.scroll.create('block');
|
||||
let node = document.createElement('strong');
|
||||
node.innerHTML = 'Bold';
|
||||
node.style.color = 'red';
|
||||
let boldBlot = this.scroll.create(node);
|
||||
let boldBlot = ctx.scroll.create(node);
|
||||
container.appendChild(boldBlot);
|
||||
container.formatAt(1, 2, 'bold', false);
|
||||
expect(container.children.length).toEqual(3);
|
||||
@ -140,10 +142,10 @@ describe('Attributor', function () {
|
||||
});
|
||||
|
||||
it('wrap with inline', function () {
|
||||
let container = this.scroll.create('block');
|
||||
let container = ctx.scroll.create('block');
|
||||
let node = document.createElement('strong');
|
||||
node.style.color = 'red';
|
||||
let boldBlot = this.scroll.create(node);
|
||||
let boldBlot = ctx.scroll.create(node);
|
||||
container.appendChild(boldBlot);
|
||||
boldBlot.wrap('italic');
|
||||
expect(node.style.color).toBeFalsy();
|
||||
@ -151,10 +153,10 @@ describe('Attributor', function () {
|
||||
});
|
||||
|
||||
it('wrap with block', function () {
|
||||
let container = this.scroll.create('block');
|
||||
let container = ctx.scroll.create('block');
|
||||
let node = document.createElement('strong');
|
||||
node.style.color = 'red';
|
||||
let boldBlot = this.scroll.create(node);
|
||||
let boldBlot = ctx.scroll.create(node);
|
||||
container.appendChild(boldBlot);
|
||||
boldBlot.wrap('block');
|
||||
expect(node.style.color).toBe('red');
|
||||
@ -162,8 +164,8 @@ describe('Attributor', function () {
|
||||
});
|
||||
|
||||
it('add to block', function () {
|
||||
let container = this.scroll.create('block');
|
||||
let block = this.scroll.create('header', 'h1');
|
||||
let container = ctx.scroll.create('block');
|
||||
let block = ctx.scroll.create('header', 'h1');
|
||||
container.appendChild(block);
|
||||
block.format('align', 'right');
|
||||
expect(container.domNode.innerHTML).toBe(
|
||||
@ -176,14 +178,14 @@ describe('Attributor', function () {
|
||||
});
|
||||
|
||||
it('missing class value', function () {
|
||||
let block = this.scroll.create('block');
|
||||
let indentAttributor = this.scroll.query('indent');
|
||||
let block = ctx.scroll.create('block');
|
||||
let indentAttributor = ctx.scroll.query('indent');
|
||||
expect(indentAttributor.value(block.domNode)).toBeFalsy();
|
||||
});
|
||||
|
||||
it('removes quotes from attribute value when checking if canAdd', function () {
|
||||
let bold = this.scroll.create('bold');
|
||||
let familyAttributor = this.scroll.query('family');
|
||||
let bold = ctx.scroll.create('bold');
|
||||
let familyAttributor = ctx.scroll.query('family');
|
||||
expect(familyAttributor.canAdd(bold.domNode, 'Arial')).toBeTruthy();
|
||||
expect(
|
||||
familyAttributor.canAdd(bold.domNode, '"Times New Roman"'),
|
||||
@ -1,59 +0,0 @@
|
||||
'use strict';
|
||||
|
||||
describe('Block', function () {
|
||||
describe('format', function () {
|
||||
it('add', function () {
|
||||
let block = this.scroll.create('block');
|
||||
this.scroll.appendChild(block);
|
||||
block.format('header', 'h1');
|
||||
expect(this.scroll.domNode.innerHTML).toBe('<h1></h1>');
|
||||
expect(this.scroll.children.head.statics.blotName).toBe('header');
|
||||
expect(this.scroll.children.head.formats()).toEqual({ header: 'h1' });
|
||||
});
|
||||
|
||||
it('remove', function () {
|
||||
let block = this.scroll.create('header', 'h1');
|
||||
this.scroll.appendChild(block);
|
||||
block.format('header', false);
|
||||
expect(this.scroll.domNode.innerHTML).toBe('<p></p>');
|
||||
expect(this.scroll.children.head.statics.blotName).toBe('block');
|
||||
expect(this.scroll.children.head.formats()).toEqual({});
|
||||
});
|
||||
|
||||
it('change', function () {
|
||||
let block = this.scroll.create('block');
|
||||
let text = this.scroll.create('text', 'Test');
|
||||
block.appendChild(text);
|
||||
this.scroll.appendChild(block);
|
||||
block.format('header', 'h2');
|
||||
expect(this.scroll.domNode.innerHTML).toBe('<h2>Test</h2>');
|
||||
expect(this.scroll.children.head.statics.blotName).toBe('header');
|
||||
expect(this.scroll.children.head.formats()).toEqual({ header: 'h2' });
|
||||
expect(this.scroll.children.head.children.length).toBe(1);
|
||||
expect(this.scroll.children.head.children.head).toBe(text);
|
||||
});
|
||||
|
||||
it('split', function () {
|
||||
let block = this.scroll.create('block');
|
||||
let text = this.scroll.create('text', 'Test');
|
||||
block.appendChild(text);
|
||||
this.scroll.appendChild(block);
|
||||
let src = 'http://www.w3schools.com/html/mov_bbb.mp4';
|
||||
block.insertAt(2, 'video', src);
|
||||
expect(this.scroll.domNode.innerHTML).toBe(
|
||||
`<p>Te</p><video src="${src}"></video><p>st</p>`,
|
||||
);
|
||||
expect(this.scroll.children.length).toBe(3);
|
||||
expect(this.scroll.children.head.next.statics.blotName).toBe('video');
|
||||
});
|
||||
|
||||
it('ignore inline', function () {
|
||||
let block = this.scroll.create('header', 1);
|
||||
this.scroll.appendChild(block);
|
||||
block.format('bold', true);
|
||||
expect(this.scroll.domNode.innerHTML).toBe('<h1></h1>');
|
||||
expect(this.scroll.children.head.statics.blotName).toBe('header');
|
||||
expect(this.scroll.children.head.formats()).toEqual({ header: 'h1' });
|
||||
});
|
||||
});
|
||||
});
|
||||
61
test/unit/block.ts
Normal file
61
test/unit/block.ts
Normal file
@ -0,0 +1,61 @@
|
||||
import { setupContextBeforeEach } from '../setup';
|
||||
|
||||
describe('Block', function () {
|
||||
const ctx = setupContextBeforeEach();
|
||||
|
||||
describe('format', function () {
|
||||
it('add', function () {
|
||||
let block = ctx.scroll.create('block');
|
||||
ctx.scroll.appendChild(block);
|
||||
block.format('header', 'h1');
|
||||
expect(ctx.scroll.domNode.innerHTML).toBe('<h1></h1>');
|
||||
expect(ctx.scroll.children.head.statics.blotName).toBe('header');
|
||||
expect(ctx.scroll.children.head.formats()).toEqual({ header: 'h1' });
|
||||
});
|
||||
|
||||
it('remove', function () {
|
||||
let block = ctx.scroll.create('header', 'h1');
|
||||
ctx.scroll.appendChild(block);
|
||||
block.format('header', false);
|
||||
expect(ctx.scroll.domNode.innerHTML).toBe('<p></p>');
|
||||
expect(ctx.scroll.children.head.statics.blotName).toBe('block');
|
||||
expect(ctx.scroll.children.head.formats()).toEqual({});
|
||||
});
|
||||
|
||||
it('change', function () {
|
||||
let block = ctx.scroll.create('block');
|
||||
let text = ctx.scroll.create('text', 'Test');
|
||||
block.appendChild(text);
|
||||
ctx.scroll.appendChild(block);
|
||||
block.format('header', 'h2');
|
||||
expect(ctx.scroll.domNode.innerHTML).toBe('<h2>Test</h2>');
|
||||
expect(ctx.scroll.children.head.statics.blotName).toBe('header');
|
||||
expect(ctx.scroll.children.head.formats()).toEqual({ header: 'h2' });
|
||||
expect(ctx.scroll.children.head.children.length).toBe(1);
|
||||
expect(ctx.scroll.children.head.children.head).toBe(text);
|
||||
});
|
||||
|
||||
it('split', function () {
|
||||
let block = ctx.scroll.create('block');
|
||||
let text = ctx.scroll.create('text', 'Test');
|
||||
block.appendChild(text);
|
||||
ctx.scroll.appendChild(block);
|
||||
let src = 'http://www.w3schools.com/html/mov_bbb.mp4';
|
||||
block.insertAt(2, 'video', src);
|
||||
expect(ctx.scroll.domNode.innerHTML).toBe(
|
||||
`<p>Te</p><video src="${src}"></video><p>st</p>`,
|
||||
);
|
||||
expect(ctx.scroll.children.length).toBe(3);
|
||||
expect(ctx.scroll.children.head.next.statics.blotName).toBe('video');
|
||||
});
|
||||
|
||||
it('ignore inline', function () {
|
||||
let block = ctx.scroll.create('header', 1);
|
||||
ctx.scroll.appendChild(block);
|
||||
block.format('bold', true);
|
||||
expect(ctx.scroll.domNode.innerHTML).toBe('<h1></h1>');
|
||||
expect(ctx.scroll.children.head.statics.blotName).toBe('header');
|
||||
expect(ctx.scroll.children.head.formats()).toEqual({ header: 'h1' });
|
||||
});
|
||||
});
|
||||
});
|
||||
@ -1,25 +1,28 @@
|
||||
'use strict';
|
||||
import Registry from '../../src/registry';
|
||||
import { setupContextBeforeEach } from '../setup';
|
||||
|
||||
describe('Blot', function () {
|
||||
const ctx = setupContextBeforeEach();
|
||||
|
||||
it('offset()', function () {
|
||||
let blockNode = document.createElement('p');
|
||||
blockNode.innerHTML = '<span>01</span><em>23<strong>45</strong></em>';
|
||||
let blockBlot = this.scroll.create(blockNode);
|
||||
let blockBlot = ctx.scroll.create(blockNode);
|
||||
let boldBlot = blockBlot.children.tail.children.tail;
|
||||
expect(boldBlot.offset()).toEqual(2);
|
||||
expect(boldBlot.offset(blockBlot)).toEqual(4);
|
||||
});
|
||||
|
||||
it('detach()', function () {
|
||||
let blot = this.scroll.create('block');
|
||||
let blot = ctx.scroll.create('block');
|
||||
expect(Registry.blots.get(blot.domNode)).toEqual(blot);
|
||||
blot.detach();
|
||||
expect(Registry.blots.get(blot.domNode)).toEqual(undefined);
|
||||
});
|
||||
|
||||
it('remove()', function () {
|
||||
let blot = this.scroll.create('block');
|
||||
let text = this.scroll.create('text', 'Test');
|
||||
let blot = ctx.scroll.create('block');
|
||||
let text = ctx.scroll.create('text', 'Test');
|
||||
blot.appendChild(text);
|
||||
expect(blot.children.head).toBe(text);
|
||||
expect(blot.domNode.innerHTML).toBe('Test');
|
||||
@ -29,10 +32,10 @@ describe('Blot', function () {
|
||||
});
|
||||
|
||||
it('wrap()', function () {
|
||||
let parent = this.scroll.create('block');
|
||||
let head = this.scroll.create('bold');
|
||||
let text = this.scroll.create('text', 'Test');
|
||||
let tail = this.scroll.create('bold');
|
||||
let parent = ctx.scroll.create('block');
|
||||
let head = ctx.scroll.create('bold');
|
||||
let text = ctx.scroll.create('text', 'Test');
|
||||
let tail = ctx.scroll.create('bold');
|
||||
parent.appendChild(head);
|
||||
parent.appendChild(text);
|
||||
parent.appendChild(tail);
|
||||
@ -49,9 +52,9 @@ describe('Blot', function () {
|
||||
});
|
||||
|
||||
it('wrap() with blot', function () {
|
||||
let parent = this.scroll.create('block');
|
||||
let text = this.scroll.create('text', 'Test');
|
||||
let italic = this.scroll.create('italic');
|
||||
let parent = ctx.scroll.create('block');
|
||||
let text = ctx.scroll.create('text', 'Test');
|
||||
let italic = ctx.scroll.create('italic');
|
||||
parent.appendChild(text);
|
||||
text.wrap(italic);
|
||||
expect(parent.domNode.innerHTML).toEqual('<em>Test</em>');
|
||||
@ -1,17 +1,19 @@
|
||||
'use strict';
|
||||
import { setupContextBeforeEach } from '../setup';
|
||||
|
||||
describe('Container', function () {
|
||||
const ctx = setupContextBeforeEach();
|
||||
|
||||
beforeEach(function () {
|
||||
this.container.innerHTML = '<ol><li>1</li></ol>';
|
||||
ctx.container.innerHTML = '<ol><li>1</li></ol>';
|
||||
});
|
||||
|
||||
describe('enforceAllowedChildren()', function () {
|
||||
it('keep allowed', function () {
|
||||
const li = document.createElement('li');
|
||||
li.innerHTML = 2;
|
||||
this.scroll.domNode.firstChild.appendChild(li);
|
||||
this.scroll.update();
|
||||
expect(this.scroll.domNode.innerHTML).toEqual(
|
||||
ctx.scroll.domNode.firstChild.appendChild(li);
|
||||
ctx.scroll.update();
|
||||
expect(ctx.scroll.domNode.innerHTML).toEqual(
|
||||
'<ol><li>1</li><li>2</li></ol>',
|
||||
);
|
||||
});
|
||||
@ -19,17 +21,17 @@ describe('Container', function () {
|
||||
it('remove unallowed child', function () {
|
||||
const strong = document.createElement('strong');
|
||||
strong.innerHTML = 2;
|
||||
this.scroll.domNode.firstChild.appendChild(strong);
|
||||
this.scroll.update();
|
||||
expect(this.scroll.domNode.innerHTML).toEqual('<ol><li>1</li></ol>');
|
||||
ctx.scroll.domNode.firstChild.appendChild(strong);
|
||||
ctx.scroll.update();
|
||||
expect(ctx.scroll.domNode.innerHTML).toEqual('<ol><li>1</li></ol>');
|
||||
});
|
||||
|
||||
it('isolate block', function () {
|
||||
const header = document.createElement('h1');
|
||||
header.innerHTML = 2;
|
||||
this.scroll.domNode.firstChild.appendChild(header);
|
||||
this.scroll.update();
|
||||
expect(this.scroll.domNode.innerHTML).toEqual(
|
||||
ctx.scroll.domNode.firstChild.appendChild(header);
|
||||
ctx.scroll.update();
|
||||
expect(ctx.scroll.domNode.innerHTML).toEqual(
|
||||
'<ol><li>1</li></ol><h1>2</h1>',
|
||||
);
|
||||
});
|
||||
@ -1,16 +1,18 @@
|
||||
'use strict';
|
||||
import { setupContextBeforeEach } from '../setup';
|
||||
|
||||
describe('EmbedBlot', function () {
|
||||
const ctx = setupContextBeforeEach();
|
||||
|
||||
it('value()', function () {
|
||||
let imageBlot = this.scroll.create('image', 'favicon.ico');
|
||||
let imageBlot = ctx.scroll.create('image', 'favicon.ico');
|
||||
expect(imageBlot.value()).toEqual({
|
||||
image: 'favicon.ico',
|
||||
});
|
||||
});
|
||||
|
||||
it('deleteAt()', function () {
|
||||
let container = this.scroll.create('block');
|
||||
let imageBlot = this.scroll.create('image');
|
||||
let container = ctx.scroll.create('block');
|
||||
let imageBlot = ctx.scroll.create('image');
|
||||
container.appendChild(imageBlot);
|
||||
container.insertAt(1, '!');
|
||||
container.deleteAt(0, 1);
|
||||
@ -20,24 +22,24 @@ describe('EmbedBlot', function () {
|
||||
});
|
||||
|
||||
it('format()', function () {
|
||||
let container = this.scroll.create('block');
|
||||
let imageBlot = this.scroll.create('image');
|
||||
let container = ctx.scroll.create('block');
|
||||
let imageBlot = ctx.scroll.create('image');
|
||||
container.appendChild(imageBlot);
|
||||
imageBlot.format('alt', 'Quill Icon');
|
||||
expect(imageBlot.formats()).toEqual({ alt: 'Quill Icon' });
|
||||
});
|
||||
|
||||
it('formatAt()', function () {
|
||||
let container = this.scroll.create('block');
|
||||
let imageBlot = this.scroll.create('image');
|
||||
let container = ctx.scroll.create('block');
|
||||
let imageBlot = ctx.scroll.create('image');
|
||||
container.appendChild(imageBlot);
|
||||
container.formatAt(0, 1, 'color', 'red');
|
||||
expect(container.children.head.statics.blotName).toBe('inline');
|
||||
});
|
||||
|
||||
it('insertAt()', function () {
|
||||
let container = this.scroll.create('inline');
|
||||
let imageBlot = this.scroll.create('image');
|
||||
let container = ctx.scroll.create('inline');
|
||||
let imageBlot = ctx.scroll.create('image');
|
||||
container.appendChild(imageBlot);
|
||||
imageBlot.insertAt(0, 'image', true);
|
||||
imageBlot.insertAt(0, '|');
|
||||
@ -48,22 +50,22 @@ describe('EmbedBlot', function () {
|
||||
it('split()', function () {
|
||||
let blockNode = document.createElement('p');
|
||||
blockNode.innerHTML = '<em>Te</em><img><strong>st</strong>';
|
||||
let blockBlot = this.scroll.create(blockNode);
|
||||
let blockBlot = ctx.scroll.create(blockNode);
|
||||
let imageBlot = blockBlot.children.head.next;
|
||||
expect(imageBlot.split(0)).toBe(imageBlot);
|
||||
expect(imageBlot.split(1)).toBe(blockBlot.children.tail);
|
||||
});
|
||||
|
||||
it('index()', function () {
|
||||
let imageBlot = this.scroll.create('image');
|
||||
let imageBlot = ctx.scroll.create('image');
|
||||
expect(imageBlot.index(imageBlot.domNode, 0)).toEqual(0);
|
||||
expect(imageBlot.index(imageBlot.domNode, 1)).toEqual(1);
|
||||
expect(imageBlot.index(document.body, 1)).toEqual(-1);
|
||||
});
|
||||
|
||||
it('position()', function () {
|
||||
let container = this.scroll.create('block');
|
||||
let imageBlot = this.scroll.create('image');
|
||||
let container = ctx.scroll.create('block');
|
||||
let imageBlot = ctx.scroll.create('image');
|
||||
container.appendChild(imageBlot);
|
||||
let [node, offset] = imageBlot.position(1, true);
|
||||
expect(node).toEqual(container.domNode);
|
||||
@ -1,9 +1,11 @@
|
||||
'use strict';
|
||||
import { setupContextBeforeEach } from '../setup';
|
||||
|
||||
describe('InlineBlot', function () {
|
||||
const ctx = setupContextBeforeEach();
|
||||
|
||||
it('format addition', function () {
|
||||
let italicBlot = this.scroll.create('italic');
|
||||
italicBlot.appendChild(this.scroll.create('text', 'Test'));
|
||||
let italicBlot = ctx.scroll.create('italic');
|
||||
italicBlot.appendChild(ctx.scroll.create('text', 'Test'));
|
||||
italicBlot.formatAt(1, 2, 'bold', true);
|
||||
expect(italicBlot.domNode.outerHTML).toEqual(
|
||||
'<em>T<strong>es</strong>t</em>',
|
||||
@ -11,8 +13,8 @@ describe('InlineBlot', function () {
|
||||
});
|
||||
|
||||
it('format invalid', function () {
|
||||
let boldBlot = this.scroll.create('bold');
|
||||
boldBlot.appendChild(this.scroll.create('text', 'Test'));
|
||||
let boldBlot = ctx.scroll.create('bold');
|
||||
boldBlot.appendChild(ctx.scroll.create('text', 'Test'));
|
||||
let original = boldBlot.domNode.outerHTML;
|
||||
expect(function () {
|
||||
boldBlot.format('nonexistent', true);
|
||||
@ -21,9 +23,9 @@ describe('InlineBlot', function () {
|
||||
});
|
||||
|
||||
it('format existing', function () {
|
||||
let italicBlot = this.scroll.create('italic');
|
||||
let boldBlot = this.scroll.create('bold');
|
||||
boldBlot.appendChild(this.scroll.create('text', 'Test'));
|
||||
let italicBlot = ctx.scroll.create('italic');
|
||||
let boldBlot = ctx.scroll.create('bold');
|
||||
boldBlot.appendChild(ctx.scroll.create('text', 'Test'));
|
||||
italicBlot.appendChild(boldBlot);
|
||||
let original = italicBlot.domNode.outerHTML;
|
||||
expect(function () {
|
||||
@ -34,9 +36,9 @@ describe('InlineBlot', function () {
|
||||
});
|
||||
|
||||
it('format removal nonexistent', function () {
|
||||
let container = this.scroll.create('block');
|
||||
let italicBlot = this.scroll.create('italic');
|
||||
italicBlot.appendChild(this.scroll.create('text', 'Test'));
|
||||
let container = ctx.scroll.create('block');
|
||||
let italicBlot = ctx.scroll.create('italic');
|
||||
italicBlot.appendChild(ctx.scroll.create('text', 'Test'));
|
||||
container.appendChild(italicBlot);
|
||||
let original = italicBlot.domNode.outerHTML;
|
||||
expect(function () {
|
||||
@ -48,7 +50,7 @@ describe('InlineBlot', function () {
|
||||
it('delete + unwrap', function () {
|
||||
let node = document.createElement('p');
|
||||
node.innerHTML = '<em><strong>Test</strong></em>!';
|
||||
let container = this.scroll.create(node);
|
||||
let container = ctx.scroll.create(node);
|
||||
container.deleteAt(0, 4);
|
||||
expect(container.children.head.value()).toEqual('!');
|
||||
});
|
||||
@ -57,13 +59,13 @@ describe('InlineBlot', function () {
|
||||
let italic = document.createElement('em');
|
||||
italic.style.color = 'red';
|
||||
italic.innerHTML = '<strong>Test</strong>!';
|
||||
let blot = this.scroll.create(italic);
|
||||
let blot = ctx.scroll.create(italic);
|
||||
expect(blot.formats()).toEqual({ italic: true, color: 'red' });
|
||||
});
|
||||
|
||||
it('change', function () {
|
||||
let container = this.scroll.create('block');
|
||||
let script = this.scroll.create('script', 'sup');
|
||||
let container = ctx.scroll.create('block');
|
||||
let script = ctx.scroll.create('script', 'sup');
|
||||
container.appendChild(script);
|
||||
script.format('script', 'sub');
|
||||
expect(container.domNode.innerHTML).toEqual('<sub></sub>');
|
||||
@ -1,6 +1,13 @@
|
||||
'use strict';
|
||||
import LeafBlot from '../../src/blot/abstract/leaf';
|
||||
import ShadowBlot from '../../src/blot/abstract/shadow';
|
||||
import { HeaderBlot } from '../registry/block';
|
||||
import { ImageBlot } from '../registry/embed';
|
||||
import { BoldBlot } from '../registry/inline';
|
||||
import { setupContextBeforeEach } from '../setup';
|
||||
|
||||
describe('Lifecycle', function () {
|
||||
const ctx = setupContextBeforeEach();
|
||||
|
||||
describe('create()', function () {
|
||||
it('specific tagName', function () {
|
||||
let node = BoldBlot.create();
|
||||
@ -11,21 +18,21 @@ describe('Lifecycle', function () {
|
||||
it('array tagName index', function () {
|
||||
let node = HeaderBlot.create(2);
|
||||
expect(node).toBeTruthy();
|
||||
let blot = this.scroll.create(node);
|
||||
let blot = ctx.scroll.create(node);
|
||||
expect(blot.formats()).toEqual({ header: 'h2' });
|
||||
});
|
||||
|
||||
it('array tagName value', function () {
|
||||
let node = HeaderBlot.create('h2');
|
||||
expect(node).toBeTruthy();
|
||||
let blot = this.scroll.create(node);
|
||||
let blot = ctx.scroll.create(node);
|
||||
expect(blot.formats()).toEqual({ header: 'h2' });
|
||||
});
|
||||
|
||||
it('array tagName default', function () {
|
||||
let node = HeaderBlot.create();
|
||||
expect(node).toBeTruthy();
|
||||
let blot = this.scroll.create(node);
|
||||
let blot = ctx.scroll.create(node);
|
||||
expect(blot.formats()).toEqual({ header: 'h1' });
|
||||
});
|
||||
|
||||
@ -50,12 +57,12 @@ describe('Lifecycle', function () {
|
||||
let node = document.createElement('p');
|
||||
node.innerHTML =
|
||||
'<span style="color: red;"><strong>Te</strong><em>st</em></span>';
|
||||
let block = this.scroll.create(node);
|
||||
this.scroll.appendChild(block);
|
||||
let span = this.scroll.find(node.querySelector('span'));
|
||||
let block = ctx.scroll.create(node);
|
||||
ctx.scroll.appendChild(block);
|
||||
let span = ctx.scroll.find(node.querySelector('span'));
|
||||
span.format('color', false);
|
||||
this.scroll.optimize();
|
||||
expect(this.container.innerHTML).toEqual(
|
||||
ctx.scroll.optimize();
|
||||
expect(ctx.container.innerHTML).toEqual(
|
||||
'<p><strong>Te</strong><em>st</em></p>',
|
||||
);
|
||||
});
|
||||
@ -63,73 +70,73 @@ describe('Lifecycle', function () {
|
||||
it('unwrap recursive', function () {
|
||||
let node = document.createElement('p');
|
||||
node.innerHTML = '<em><strong>Test</strong></em>';
|
||||
let block = this.scroll.create(node);
|
||||
this.scroll.appendChild(block);
|
||||
let text = this.scroll.find(node.querySelector('strong').firstChild);
|
||||
let block = ctx.scroll.create(node);
|
||||
ctx.scroll.appendChild(block);
|
||||
let text = ctx.scroll.find(node.querySelector('strong').firstChild);
|
||||
text.deleteAt(0, 4);
|
||||
this.scroll.optimize();
|
||||
expect(this.container.innerHTML).toEqual('');
|
||||
ctx.scroll.optimize();
|
||||
expect(ctx.container.innerHTML).toEqual('');
|
||||
});
|
||||
|
||||
it('format merge', function () {
|
||||
let node = document.createElement('p');
|
||||
node.innerHTML = '<strong>T</strong>es<strong>t</strong>';
|
||||
let block = this.scroll.create(node);
|
||||
this.scroll.appendChild(block);
|
||||
let text = this.scroll.find(node.childNodes[1]);
|
||||
let block = ctx.scroll.create(node);
|
||||
ctx.scroll.appendChild(block);
|
||||
let text = ctx.scroll.find(node.childNodes[1]);
|
||||
text.formatAt(0, 2, 'bold', true);
|
||||
this.scroll.optimize();
|
||||
expect(this.container.innerHTML).toEqual('<p><strong>Test</strong></p>');
|
||||
expect(this.container.querySelector('strong').childNodes.length).toBe(1);
|
||||
ctx.scroll.optimize();
|
||||
expect(ctx.container.innerHTML).toEqual('<p><strong>Test</strong></p>');
|
||||
expect(ctx.container.querySelector('strong').childNodes.length).toBe(1);
|
||||
});
|
||||
|
||||
it('format recursive merge', function () {
|
||||
let node = document.createElement('p');
|
||||
node.innerHTML =
|
||||
'<em><strong>T</strong></em><strong>es</strong><em><strong>t</strong></em>';
|
||||
let block = this.scroll.create(node);
|
||||
this.scroll.appendChild(block);
|
||||
let target = this.scroll.find(node.childNodes[1]);
|
||||
let block = ctx.scroll.create(node);
|
||||
ctx.scroll.appendChild(block);
|
||||
let target = ctx.scroll.find(node.childNodes[1]);
|
||||
target.wrap('italic', true);
|
||||
this.scroll.optimize();
|
||||
expect(this.container.innerHTML).toEqual(
|
||||
ctx.scroll.optimize();
|
||||
expect(ctx.container.innerHTML).toEqual(
|
||||
'<p><em><strong>Test</strong></em></p>',
|
||||
);
|
||||
expect(this.container.querySelector('strong').childNodes.length).toBe(1);
|
||||
expect(ctx.container.querySelector('strong').childNodes.length).toBe(1);
|
||||
});
|
||||
|
||||
it('remove format merge', function () {
|
||||
let node = document.createElement('p');
|
||||
node.innerHTML =
|
||||
'<strong>T</strong><em><strong>es</strong></em><strong>t</strong>';
|
||||
let block = this.scroll.create(node);
|
||||
this.scroll.appendChild(block);
|
||||
let block = ctx.scroll.create(node);
|
||||
ctx.scroll.appendChild(block);
|
||||
block.formatAt(1, 2, 'italic', false);
|
||||
this.scroll.optimize();
|
||||
expect(this.container.innerHTML).toEqual('<p><strong>Test</strong></p>');
|
||||
expect(this.container.querySelector('strong').childNodes.length).toBe(1);
|
||||
ctx.scroll.optimize();
|
||||
expect(ctx.container.innerHTML).toEqual('<p><strong>Test</strong></p>');
|
||||
expect(ctx.container.querySelector('strong').childNodes.length).toBe(1);
|
||||
});
|
||||
|
||||
it('remove attribute merge', function () {
|
||||
let node = document.createElement('p');
|
||||
node.innerHTML = '<em>T</em><em style="color: red;">es</em><em>t</em>';
|
||||
let block = this.scroll.create(node);
|
||||
this.scroll.appendChild(block);
|
||||
let block = ctx.scroll.create(node);
|
||||
ctx.scroll.appendChild(block);
|
||||
block.formatAt(1, 2, 'color', false);
|
||||
this.scroll.optimize();
|
||||
expect(this.container.innerHTML).toEqual('<p><em>Test</em></p>');
|
||||
expect(this.container.querySelector('em').childNodes.length).toBe(1);
|
||||
ctx.scroll.optimize();
|
||||
expect(ctx.container.innerHTML).toEqual('<p><em>Test</em></p>');
|
||||
expect(ctx.container.querySelector('em').childNodes.length).toBe(1);
|
||||
});
|
||||
|
||||
it('format no merge attribute mismatch', function () {
|
||||
let node = document.createElement('p');
|
||||
node.innerHTML =
|
||||
'<strong>Te</strong><em><strong style="color: red;">st</strong></em>';
|
||||
let block = this.scroll.create(node);
|
||||
this.scroll.appendChild(block);
|
||||
let block = ctx.scroll.create(node);
|
||||
ctx.scroll.appendChild(block);
|
||||
block.formatAt(2, 2, 'italic', false);
|
||||
this.scroll.optimize();
|
||||
expect(this.container.innerHTML).toEqual(
|
||||
ctx.scroll.optimize();
|
||||
expect(ctx.container.innerHTML).toEqual(
|
||||
'<p><strong>Te</strong><strong style="color: red;">st</strong></p>',
|
||||
);
|
||||
});
|
||||
@ -137,41 +144,41 @@ describe('Lifecycle', function () {
|
||||
it('delete + merge', function () {
|
||||
let node = document.createElement('p');
|
||||
node.innerHTML = '<em>T</em>es<em>t</em>';
|
||||
let block = this.scroll.create(node);
|
||||
this.scroll.appendChild(block);
|
||||
let block = ctx.scroll.create(node);
|
||||
ctx.scroll.appendChild(block);
|
||||
block.deleteAt(1, 2);
|
||||
this.scroll.optimize();
|
||||
expect(this.container.innerHTML).toEqual('<p><em>Tt</em></p>');
|
||||
expect(this.container.querySelector('em').childNodes.length).toBe(1);
|
||||
ctx.scroll.optimize();
|
||||
expect(ctx.container.innerHTML).toEqual('<p><em>Tt</em></p>');
|
||||
expect(ctx.container.querySelector('em').childNodes.length).toBe(1);
|
||||
});
|
||||
|
||||
it('unwrap + recursive merge', function () {
|
||||
let node = document.createElement('p');
|
||||
node.innerHTML =
|
||||
'<strong>T</strong><em style="color: red;"><strong>es</strong></em><strong>t</strong>';
|
||||
let block = this.scroll.create(node);
|
||||
this.scroll.appendChild(block);
|
||||
let block = ctx.scroll.create(node);
|
||||
ctx.scroll.appendChild(block);
|
||||
block.formatAt(1, 2, 'italic', false);
|
||||
block.formatAt(1, 2, 'color', false);
|
||||
this.scroll.optimize();
|
||||
expect(this.container.innerHTML).toEqual('<p><strong>Test</strong></p>');
|
||||
expect(this.container.querySelector('strong').childNodes.length).toBe(1);
|
||||
ctx.scroll.optimize();
|
||||
expect(ctx.container.innerHTML).toEqual('<p><strong>Test</strong></p>');
|
||||
expect(ctx.container.querySelector('strong').childNodes.length).toBe(1);
|
||||
});
|
||||
|
||||
it('remove text + recursive merge', function () {
|
||||
let node = document.createElement('p');
|
||||
node.innerHTML = '<em>Te</em>|<em>st</em>';
|
||||
let block = this.scroll.create(node);
|
||||
this.scroll.appendChild(block);
|
||||
let block = ctx.scroll.create(node);
|
||||
ctx.scroll.appendChild(block);
|
||||
node.childNodes[1].data = '';
|
||||
this.scroll.optimize();
|
||||
expect(this.container.innerHTML).toEqual('<p><em>Test</em></p>');
|
||||
expect(this.container.firstChild.firstChild.childNodes.length).toBe(1);
|
||||
ctx.scroll.optimize();
|
||||
expect(ctx.container.innerHTML).toEqual('<p><em>Test</em></p>');
|
||||
expect(ctx.container.firstChild.firstChild.childNodes.length).toBe(1);
|
||||
});
|
||||
|
||||
it('insert default child', function () {
|
||||
HeaderBlot.defaultChild = ImageBlot;
|
||||
let blot = this.scroll.create('header');
|
||||
let blot = ctx.scroll.create('header');
|
||||
expect(blot.domNode.innerHTML).toEqual('');
|
||||
blot.optimize();
|
||||
HeaderBlot.defaultChild = undefined;
|
||||
@ -181,11 +188,11 @@ describe('Lifecycle', function () {
|
||||
|
||||
describe('update()', function () {
|
||||
beforeEach(function () {
|
||||
this.container.innerHTML =
|
||||
ctx.container.innerHTML =
|
||||
'<p><em style="color: red;"><strong>Test</strong><img>ing</em></p><p><em>!</em></p>';
|
||||
this.scroll.update();
|
||||
ctx.scroll.update();
|
||||
// [p, em, strong, text, image, text, p, em, text]
|
||||
this.descendants = this.scroll.descendants(ShadowBlot);
|
||||
this.descendants = ctx.scroll.descendants(ShadowBlot);
|
||||
this.descendants.forEach(function (blot) {
|
||||
spyOn(blot, 'update').and.callThrough();
|
||||
});
|
||||
@ -202,7 +209,7 @@ describe('Lifecycle', function () {
|
||||
});
|
||||
};
|
||||
this.checkValues = (expected) => {
|
||||
let values = this.scroll.descendants(LeafBlot).map(function (leaf) {
|
||||
let values = ctx.scroll.descendants(LeafBlot).map(function (leaf) {
|
||||
return leaf.value();
|
||||
});
|
||||
expect(values).toEqual(expected);
|
||||
@ -211,15 +218,15 @@ describe('Lifecycle', function () {
|
||||
|
||||
describe('api', function () {
|
||||
it('insert text', function () {
|
||||
this.scroll.insertAt(2, '|');
|
||||
this.scroll.optimize();
|
||||
ctx.scroll.insertAt(2, '|');
|
||||
ctx.scroll.optimize();
|
||||
this.checkValues(['Te|st', { image: true }, 'ing', '!']);
|
||||
expect(this.scroll.observer.takeRecords()).toEqual([]);
|
||||
expect(ctx.scroll.observer.takeRecords()).toEqual([]);
|
||||
});
|
||||
|
||||
it('insert embed', function () {
|
||||
this.scroll.insertAt(2, 'image', true);
|
||||
this.scroll.optimize();
|
||||
ctx.scroll.insertAt(2, 'image', true);
|
||||
ctx.scroll.optimize();
|
||||
this.checkValues([
|
||||
'Te',
|
||||
{ image: true },
|
||||
@ -228,21 +235,21 @@ describe('Lifecycle', function () {
|
||||
'ing',
|
||||
'!',
|
||||
]);
|
||||
expect(this.scroll.observer.takeRecords()).toEqual([]);
|
||||
expect(ctx.scroll.observer.takeRecords()).toEqual([]);
|
||||
});
|
||||
|
||||
it('delete', function () {
|
||||
this.scroll.deleteAt(2, 5);
|
||||
this.scroll.optimize();
|
||||
ctx.scroll.deleteAt(2, 5);
|
||||
ctx.scroll.optimize();
|
||||
this.checkValues(['Te', 'g', '!']);
|
||||
expect(this.scroll.observer.takeRecords()).toEqual([]);
|
||||
expect(ctx.scroll.observer.takeRecords()).toEqual([]);
|
||||
});
|
||||
|
||||
it('format', function () {
|
||||
this.scroll.formatAt(2, 5, 'size', '24px');
|
||||
this.scroll.optimize();
|
||||
ctx.scroll.formatAt(2, 5, 'size', '24px');
|
||||
ctx.scroll.optimize();
|
||||
this.checkValues(['Te', 'st', { image: true }, 'in', 'g', '!']);
|
||||
expect(this.scroll.observer.takeRecords()).toEqual([]);
|
||||
expect(ctx.scroll.observer.takeRecords()).toEqual([]);
|
||||
});
|
||||
});
|
||||
|
||||
@ -250,7 +257,7 @@ describe('Lifecycle', function () {
|
||||
it('change text', function () {
|
||||
let textBlot = this.descendants[3];
|
||||
textBlot.domNode.data = 'Te|st';
|
||||
this.scroll.update();
|
||||
ctx.scroll.update();
|
||||
this.checkUpdateCalls(textBlot);
|
||||
expect(textBlot.value()).toEqual('Te|st');
|
||||
});
|
||||
@ -258,17 +265,17 @@ describe('Lifecycle', function () {
|
||||
it('add/remove unknown element', function () {
|
||||
let unknownElement = document.createElement('unknownElement');
|
||||
let unknownElement2 = document.createElement('unknownElement2');
|
||||
this.scroll.domNode.appendChild(unknownElement);
|
||||
ctx.scroll.domNode.appendChild(unknownElement);
|
||||
unknownElement.appendChild(unknownElement2);
|
||||
this.scroll.domNode.removeChild(unknownElement);
|
||||
this.scroll.update();
|
||||
ctx.scroll.domNode.removeChild(unknownElement);
|
||||
ctx.scroll.update();
|
||||
this.checkValues(['Test', { image: true }, 'ing', '!']);
|
||||
});
|
||||
|
||||
it('add attribute', function () {
|
||||
let attrBlot = this.descendants[1];
|
||||
attrBlot.domNode.setAttribute('id', 'blot');
|
||||
this.scroll.update();
|
||||
ctx.scroll.update();
|
||||
this.checkUpdateCalls(attrBlot);
|
||||
expect(attrBlot.formats()).toEqual({
|
||||
color: 'red',
|
||||
@ -280,14 +287,14 @@ describe('Lifecycle', function () {
|
||||
it('add embed attribute', function () {
|
||||
let imageBlot = this.descendants[4];
|
||||
imageBlot.domNode.setAttribute('alt', 'image');
|
||||
this.scroll.update();
|
||||
ctx.scroll.update();
|
||||
this.checkUpdateCalls(imageBlot);
|
||||
});
|
||||
|
||||
it('change attributes', function () {
|
||||
let attrBlot = this.descendants[1];
|
||||
attrBlot.domNode.style.color = 'blue';
|
||||
this.scroll.update();
|
||||
ctx.scroll.update();
|
||||
this.checkUpdateCalls(attrBlot);
|
||||
expect(attrBlot.formats()).toEqual({ color: 'blue', italic: true });
|
||||
});
|
||||
@ -295,7 +302,7 @@ describe('Lifecycle', function () {
|
||||
it('remove attribute', function () {
|
||||
let attrBlot = this.descendants[1];
|
||||
attrBlot.domNode.removeAttribute('style');
|
||||
this.scroll.update();
|
||||
ctx.scroll.update();
|
||||
this.checkUpdateCalls(attrBlot);
|
||||
expect(attrBlot.formats()).toEqual({ italic: true });
|
||||
});
|
||||
@ -303,7 +310,7 @@ describe('Lifecycle', function () {
|
||||
it('add child node', function () {
|
||||
let italicBlot = this.descendants[1];
|
||||
italicBlot.domNode.appendChild(document.createTextNode('|'));
|
||||
this.scroll.update();
|
||||
ctx.scroll.update();
|
||||
this.checkUpdateCalls(italicBlot);
|
||||
this.checkValues(['Test', { image: true }, 'ing|', '!']);
|
||||
});
|
||||
@ -311,13 +318,13 @@ describe('Lifecycle', function () {
|
||||
it('add empty family', function () {
|
||||
let blockBlot = this.descendants[0];
|
||||
let boldNode = document.createElement('strong');
|
||||
let html = this.scroll.innerHTML;
|
||||
let html = ctx.scroll.innerHTML;
|
||||
boldNode.appendChild(document.createTextNode(''));
|
||||
blockBlot.domNode.appendChild(boldNode);
|
||||
this.scroll.update();
|
||||
ctx.scroll.update();
|
||||
this.checkUpdateCalls(blockBlot);
|
||||
expect(this.scroll.innerHTML).toBe(html);
|
||||
expect(this.scroll.descendants(ShadowBlot).length).toEqual(
|
||||
expect(ctx.scroll.innerHTML).toBe(html);
|
||||
expect(ctx.scroll.descendants(ShadowBlot).length).toEqual(
|
||||
this.descendants.length,
|
||||
);
|
||||
});
|
||||
@ -328,7 +335,7 @@ describe('Lifecycle', function () {
|
||||
imageBlot.domNode,
|
||||
imageBlot.domNode.previousSibling,
|
||||
);
|
||||
this.scroll.update();
|
||||
ctx.scroll.update();
|
||||
this.checkUpdateCalls(imageBlot.parent);
|
||||
this.checkValues([{ image: true }, 'Test', 'ing', '!']);
|
||||
});
|
||||
@ -339,7 +346,7 @@ describe('Lifecycle', function () {
|
||||
imageBlot.domNode.nextSibling,
|
||||
imageBlot.domNode,
|
||||
);
|
||||
this.scroll.update();
|
||||
ctx.scroll.update();
|
||||
this.checkUpdateCalls(imageBlot.parent);
|
||||
this.checkValues(['Test', 'ing', { image: true }, '!']);
|
||||
});
|
||||
@ -349,7 +356,7 @@ describe('Lifecycle', function () {
|
||||
let lastItalicBlot = this.descendants[7];
|
||||
firstBlockBlot.domNode.appendChild(lastItalicBlot.domNode);
|
||||
lastItalicBlot.domNode.innerHTML = '?';
|
||||
this.scroll.update();
|
||||
ctx.scroll.update();
|
||||
this.checkUpdateCalls([
|
||||
firstBlockBlot,
|
||||
this.descendants[6],
|
||||
@ -366,7 +373,7 @@ describe('Lifecycle', function () {
|
||||
italicBlot.domNode.insertBefore(textNode, refNode);
|
||||
italicBlot.domNode.insertBefore(imageNode, textNode);
|
||||
italicBlot.domNode.removeChild(refNode);
|
||||
this.scroll.update();
|
||||
ctx.scroll.update();
|
||||
this.checkUpdateCalls(italicBlot);
|
||||
this.checkValues(['Test', { image: true }, '|ing', '!']);
|
||||
});
|
||||
@ -375,9 +382,9 @@ describe('Lifecycle', function () {
|
||||
let textNode = this.descendants[5].domNode;
|
||||
let spanNode = document.createElement('span');
|
||||
textNode.parentNode.removeChild(textNode);
|
||||
this.scroll.domNode.lastChild.appendChild(spanNode);
|
||||
ctx.scroll.domNode.lastChild.appendChild(spanNode);
|
||||
spanNode.appendChild(textNode);
|
||||
this.scroll.update();
|
||||
ctx.scroll.update();
|
||||
this.checkValues(['Test', { image: true }, '!', 'ing']);
|
||||
});
|
||||
|
||||
@ -386,7 +393,7 @@ describe('Lifecycle', function () {
|
||||
let textNode = document.createTextNode('|');
|
||||
italicBlot.domNode.appendChild(textNode);
|
||||
italicBlot.domNode.removeChild(textNode);
|
||||
this.scroll.update();
|
||||
ctx.scroll.update();
|
||||
this.checkUpdateCalls(italicBlot);
|
||||
this.checkValues(['Test', { image: true }, 'ing', '!']);
|
||||
});
|
||||
@ -394,7 +401,7 @@ describe('Lifecycle', function () {
|
||||
it('remove child node', function () {
|
||||
let imageBlot = this.descendants[4];
|
||||
imageBlot.domNode.parentNode.removeChild(imageBlot.domNode);
|
||||
this.scroll.update();
|
||||
ctx.scroll.update();
|
||||
this.checkUpdateCalls(this.descendants[1]);
|
||||
this.checkValues(['Test', 'ing', '!']);
|
||||
});
|
||||
@ -403,7 +410,7 @@ describe('Lifecycle', function () {
|
||||
let italicBlot = this.descendants[1];
|
||||
italicBlot.domNode.color = 'blue';
|
||||
italicBlot.domNode.parentNode.removeChild(italicBlot.domNode);
|
||||
this.scroll.update();
|
||||
ctx.scroll.update();
|
||||
this.checkUpdateCalls(italicBlot.parent);
|
||||
this.checkValues(['!']);
|
||||
});
|
||||
@ -412,8 +419,8 @@ describe('Lifecycle', function () {
|
||||
let blockBlot = this.descendants[0];
|
||||
let italicBlot = this.descendants[1];
|
||||
italicBlot.domNode.color = 'blue';
|
||||
this.scroll.domNode.removeChild(blockBlot.domNode);
|
||||
this.scroll.update();
|
||||
ctx.scroll.domNode.removeChild(blockBlot.domNode);
|
||||
ctx.scroll.update();
|
||||
this.checkUpdateCalls([]);
|
||||
this.checkValues(['!']);
|
||||
});
|
||||
@ -425,7 +432,7 @@ describe('Lifecycle', function () {
|
||||
document.createTextNode('|'),
|
||||
attrBlot.domNode.childNodes[1],
|
||||
);
|
||||
this.scroll.update();
|
||||
ctx.scroll.update();
|
||||
this.checkUpdateCalls(attrBlot);
|
||||
expect(attrBlot.formats()).toEqual({ color: 'blue', italic: true });
|
||||
this.checkValues(['Test', '|', { image: true }, 'ing', '!']);
|
||||
@ -1,4 +1,4 @@
|
||||
'use strict';
|
||||
import LinkedList from '../../src/collection/linked-list';
|
||||
|
||||
describe('LinkedList', function () {
|
||||
beforeEach(function () {
|
||||
@ -12,9 +12,7 @@ describe('LinkedList', function () {
|
||||
return 0;
|
||||
},
|
||||
};
|
||||
this.a.length = this.b.length = this.c.length = function () {
|
||||
return 3;
|
||||
};
|
||||
this.a.length = this.b.length = this.c.length = () => 3;
|
||||
});
|
||||
|
||||
describe('manipulation', function () {
|
||||
@ -1,10 +1,22 @@
|
||||
'use strict';
|
||||
import LeafBlot from '../../src/blot/abstract/leaf';
|
||||
import ParentBlot from '../../src/blot/abstract/parent';
|
||||
import ShadowBlot from '../../src/blot/abstract/shadow';
|
||||
import EmbedBlot from '../../src/blot/embed';
|
||||
|
||||
import { VideoBlot } from '../registry/embed';
|
||||
import { ItalicBlot } from '../registry/inline';
|
||||
|
||||
import Registry from '../../src/registry';
|
||||
import TextBlot from '../../src/blot/text';
|
||||
import { setupContextBeforeEach } from '../setup';
|
||||
|
||||
describe('Parent', function () {
|
||||
const ctx = setupContextBeforeEach();
|
||||
|
||||
beforeEach(function () {
|
||||
let node = document.createElement('p');
|
||||
node.innerHTML = '<span>0</span><em>1<strong>2</strong><img></em>4';
|
||||
this.blot = TestRegistry.create(this.scroll, node);
|
||||
this.blot = ctx.registry.create(ctx.scroll, node);
|
||||
});
|
||||
|
||||
describe('descendants()', function () {
|
||||
@ -77,22 +89,22 @@ describe('Parent', function () {
|
||||
let node = document.createElement('p');
|
||||
node.appendChild(document.createElement('input'));
|
||||
expect(() => {
|
||||
this.scroll.create(node);
|
||||
ctx.scroll.create(node);
|
||||
}).not.toThrowError(/\[Parchment\]/);
|
||||
});
|
||||
|
||||
it('ignore added uiNode', function () {
|
||||
this.scroll.appendChild(this.blot);
|
||||
ctx.scroll.appendChild(this.blot);
|
||||
this.blot.attachUI(document.createElement('div'));
|
||||
this.scroll.update();
|
||||
expect(this.scroll.domNode.innerHTML).toEqual(
|
||||
ctx.scroll.update();
|
||||
expect(ctx.scroll.domNode.innerHTML).toEqual(
|
||||
'<p><div contenteditable="false"></div>0<em>1<strong>2</strong><img></em>4</p>',
|
||||
);
|
||||
});
|
||||
|
||||
it('allowedChildren', function () {
|
||||
this.scroll.domNode.innerHTML = '<p>A</p>B<span>C</span><p>D</p>';
|
||||
this.scroll.update();
|
||||
expect(this.scroll.domNode.innerHTML).toEqual('<p>A</p><p>D</p>');
|
||||
ctx.scroll.domNode.innerHTML = '<p>A</p>B<span>C</span><p>D</p>';
|
||||
ctx.scroll.update();
|
||||
expect(ctx.scroll.domNode.innerHTML).toEqual('<p>A</p><p>D</p>');
|
||||
});
|
||||
});
|
||||
@ -1,41 +1,50 @@
|
||||
'use strict';
|
||||
import Scope from '../../src/scope';
|
||||
import { HeaderBlot } from '../registry/block';
|
||||
import { AuthorBlot, BoldBlot, ItalicBlot } from '../registry/inline';
|
||||
|
||||
import ShadowBlot from '../../src/blot/abstract/shadow';
|
||||
import InlineBlot from '../../src/blot/inline';
|
||||
import BlockBlot from '../../src/blot/block';
|
||||
import { setupContextBeforeEach } from '../setup';
|
||||
|
||||
describe('ctx.registry', function () {
|
||||
const ctx = setupContextBeforeEach();
|
||||
|
||||
describe('TestRegistry', function () {
|
||||
describe('create()', function () {
|
||||
it('name', function () {
|
||||
let blot = TestRegistry.create(this.scroll, 'bold');
|
||||
let blot = ctx.registry.create(ctx.scroll, 'bold');
|
||||
expect(blot instanceof BoldBlot).toBe(true);
|
||||
expect(blot.statics.blotName).toBe('bold');
|
||||
});
|
||||
|
||||
it('node', function () {
|
||||
let node = document.createElement('strong');
|
||||
let blot = TestRegistry.create(this.scroll, node);
|
||||
let blot = ctx.registry.create(ctx.scroll, node);
|
||||
expect(blot instanceof BoldBlot).toBe(true);
|
||||
expect(blot.statics.blotName).toBe('bold');
|
||||
});
|
||||
|
||||
it('block', function () {
|
||||
let blot = TestRegistry.create(this.scroll, Scope.BLOCK_BLOT);
|
||||
let blot = ctx.registry.create(ctx.scroll, Scope.BLOCK_BLOT);
|
||||
expect(blot instanceof BlockBlot).toBe(true);
|
||||
expect(blot.statics.blotName).toBe('block');
|
||||
});
|
||||
|
||||
it('inline', function () {
|
||||
let blot = TestRegistry.create(this.scroll, Scope.INLINE_BLOT);
|
||||
let blot = ctx.registry.create(ctx.scroll, Scope.INLINE_BLOT);
|
||||
expect(blot instanceof InlineBlot).toBe(true);
|
||||
expect(blot.statics.blotName).toBe('inline');
|
||||
});
|
||||
|
||||
it('string index', function () {
|
||||
let blot = TestRegistry.create(this.scroll, 'header', '2');
|
||||
let blot = ctx.registry.create(ctx.scroll, 'header', '2');
|
||||
expect(blot instanceof HeaderBlot).toBe(true);
|
||||
expect(blot.formats()).toEqual({ header: 'h2' });
|
||||
});
|
||||
|
||||
it('invalid', function () {
|
||||
expect(() => {
|
||||
TestRegistry.create(this.scroll, BoldBlot);
|
||||
ctx.registry.create(ctx.scroll, BoldBlot);
|
||||
}).toThrowError(/\[Parchment\]/);
|
||||
});
|
||||
});
|
||||
@ -43,13 +52,13 @@ describe('TestRegistry', function () {
|
||||
describe('register()', function () {
|
||||
it('invalid', function () {
|
||||
expect(function () {
|
||||
TestRegistry.register({});
|
||||
ctx.registry.register({});
|
||||
}).toThrowError(/\[Parchment\]/);
|
||||
});
|
||||
|
||||
it('abstract', function () {
|
||||
expect(function () {
|
||||
TestRegistry.register(ShadowBlot);
|
||||
ctx.registry.register(ShadowBlot);
|
||||
}).toThrowError(/\[Parchment\]/);
|
||||
});
|
||||
});
|
||||
@ -58,43 +67,43 @@ describe('TestRegistry', function () {
|
||||
it('exact', function () {
|
||||
let blockNode = document.createElement('p');
|
||||
blockNode.innerHTML = '<span>01</span><em>23<strong>45</strong></em>';
|
||||
let blockBlot = TestRegistry.create(this.scroll, blockNode);
|
||||
expect(TestRegistry.find(document.body)).toBeFalsy();
|
||||
expect(TestRegistry.find(blockNode)).toBe(blockBlot);
|
||||
expect(TestRegistry.find(blockNode.querySelector('span'))).toBe(
|
||||
let blockBlot = ctx.registry.create(ctx.scroll, blockNode);
|
||||
expect(ctx.registry.find(document.body)).toBeFalsy();
|
||||
expect(ctx.registry.find(blockNode)).toBe(blockBlot);
|
||||
expect(ctx.registry.find(blockNode.querySelector('span'))).toBe(
|
||||
blockBlot.children.head,
|
||||
);
|
||||
expect(TestRegistry.find(blockNode.querySelector('em'))).toBe(
|
||||
expect(ctx.registry.find(blockNode.querySelector('em'))).toBe(
|
||||
blockBlot.children.tail,
|
||||
);
|
||||
expect(TestRegistry.find(blockNode.querySelector('strong'))).toBe(
|
||||
expect(ctx.registry.find(blockNode.querySelector('strong'))).toBe(
|
||||
blockBlot.children.tail.children.tail,
|
||||
);
|
||||
let text01 = blockBlot.children.head.children.head;
|
||||
let text23 = blockBlot.children.tail.children.head;
|
||||
let text45 = blockBlot.children.tail.children.tail.children.head;
|
||||
expect(TestRegistry.find(text01.domNode)).toBe(text01);
|
||||
expect(TestRegistry.find(text23.domNode)).toBe(text23);
|
||||
expect(TestRegistry.find(text45.domNode)).toBe(text45);
|
||||
expect(ctx.registry.find(text01.domNode)).toBe(text01);
|
||||
expect(ctx.registry.find(text23.domNode)).toBe(text23);
|
||||
expect(ctx.registry.find(text45.domNode)).toBe(text45);
|
||||
});
|
||||
|
||||
it('bubble', function () {
|
||||
let blockBlot = TestRegistry.create(this.scroll, 'block');
|
||||
let blockBlot = ctx.registry.create(ctx.scroll, 'block');
|
||||
let textNode = document.createTextNode('Test');
|
||||
blockBlot.domNode.appendChild(textNode);
|
||||
expect(TestRegistry.find(textNode)).toBeFalsy();
|
||||
expect(TestRegistry.find(textNode, true)).toEqual(blockBlot);
|
||||
expect(ctx.registry.find(textNode)).toBeFalsy();
|
||||
expect(ctx.registry.find(textNode, true)).toEqual(blockBlot);
|
||||
});
|
||||
|
||||
it('detached parent', function () {
|
||||
let blockNode = document.createElement('p');
|
||||
blockNode.appendChild(document.createTextNode('Test'));
|
||||
expect(TestRegistry.find(blockNode.firstChild)).toBeFalsy();
|
||||
expect(TestRegistry.find(blockNode.firstChild, true)).toBeFalsy();
|
||||
expect(ctx.registry.find(blockNode.firstChild)).toBeFalsy();
|
||||
expect(ctx.registry.find(blockNode.firstChild, true)).toBeFalsy();
|
||||
});
|
||||
|
||||
it('restricted parent', function () {
|
||||
let blockBlot = TestRegistry.create(this.scroll, 'block');
|
||||
let blockBlot = ctx.registry.create(ctx.scroll, 'block');
|
||||
let textNode = document.createTextNode('Test');
|
||||
blockBlot.domNode.appendChild(textNode);
|
||||
Object.defineProperty(textNode, 'parentNode', {
|
||||
@ -102,8 +111,8 @@ describe('TestRegistry', function () {
|
||||
throw new Error('Permission denied to access property "parentNode"');
|
||||
},
|
||||
});
|
||||
expect(TestRegistry.find(textNode)).toEqual(null);
|
||||
expect(TestRegistry.find(textNode, true)).toEqual(null);
|
||||
expect(ctx.registry.find(textNode)).toEqual(null);
|
||||
expect(ctx.registry.find(textNode, true)).toEqual(null);
|
||||
});
|
||||
});
|
||||
|
||||
@ -111,41 +120,41 @@ describe('TestRegistry', function () {
|
||||
it('class', function () {
|
||||
let node = document.createElement('em');
|
||||
node.setAttribute('class', 'author-blot');
|
||||
expect(TestRegistry.query(node)).toBe(AuthorBlot);
|
||||
expect(ctx.registry.query(node)).toBe(AuthorBlot);
|
||||
});
|
||||
|
||||
it('type mismatch', function () {
|
||||
let match = TestRegistry.query('italic', Scope.ATTRIBUTE);
|
||||
let match = ctx.registry.query('italic', Scope.ATTRIBUTE);
|
||||
expect(match).toBeFalsy();
|
||||
});
|
||||
|
||||
it('level mismatch for blot', function () {
|
||||
let match = TestRegistry.query('italic', Scope.BLOCK);
|
||||
let match = ctx.registry.query('italic', Scope.BLOCK);
|
||||
expect(match).toBeFalsy();
|
||||
});
|
||||
|
||||
it('level mismatch for attribute', function () {
|
||||
let match = TestRegistry.query('color', Scope.BLOCK);
|
||||
let match = ctx.registry.query('color', Scope.BLOCK);
|
||||
expect(match).toBeFalsy();
|
||||
});
|
||||
|
||||
it('either level', function () {
|
||||
let match = TestRegistry.query('italic', Scope.BLOCK | Scope.INLINE);
|
||||
let match = ctx.registry.query('italic', Scope.BLOCK | Scope.INLINE);
|
||||
expect(match).toBe(ItalicBlot);
|
||||
});
|
||||
|
||||
it('level and type match', function () {
|
||||
let match = TestRegistry.query('italic', Scope.INLINE & Scope.BLOT);
|
||||
let match = ctx.registry.query('italic', Scope.INLINE & Scope.BLOT);
|
||||
expect(match).toBe(ItalicBlot);
|
||||
});
|
||||
|
||||
it('level match and type mismatch', function () {
|
||||
let match = TestRegistry.query('italic', Scope.INLINE & Scope.ATTRIBUTE);
|
||||
let match = ctx.registry.query('italic', Scope.INLINE & Scope.ATTRIBUTE);
|
||||
expect(match).toBeFalsy();
|
||||
});
|
||||
|
||||
it('type match and level mismatch', function () {
|
||||
let match = TestRegistry.query('italic', Scope.BLOCK & Scope.BLOT);
|
||||
let match = ctx.registry.query('italic', Scope.BLOCK & Scope.BLOT);
|
||||
expect(match).toBeFalsy();
|
||||
});
|
||||
});
|
||||
@ -1,15 +1,17 @@
|
||||
'use strict';
|
||||
import { setupContextBeforeEach } from '../setup';
|
||||
|
||||
describe('scroll', function () {
|
||||
const ctx = setupContextBeforeEach();
|
||||
|
||||
describe('Scroll', function () {
|
||||
beforeEach(function () {
|
||||
this.container.innerHTML =
|
||||
ctx.container.innerHTML =
|
||||
'<p><strong>012</strong><span>34</span><em><strong>5678</strong></em></p>';
|
||||
this.scroll.update();
|
||||
ctx.scroll.update();
|
||||
});
|
||||
|
||||
describe('path()', function () {
|
||||
it('middle', function () {
|
||||
let path = this.scroll.path(7);
|
||||
let path = ctx.scroll.path(7);
|
||||
let expected = [
|
||||
['scroll', 7],
|
||||
['block', 7],
|
||||
@ -25,7 +27,7 @@ describe('Scroll', function () {
|
||||
});
|
||||
|
||||
it('between blots', function () {
|
||||
let path = this.scroll.path(5);
|
||||
let path = ctx.scroll.path(5);
|
||||
let expected = [
|
||||
['scroll', 5],
|
||||
['block', 5],
|
||||
@ -41,7 +43,7 @@ describe('Scroll', function () {
|
||||
});
|
||||
|
||||
it('inclusive', function () {
|
||||
let path = this.scroll.path(3, true);
|
||||
let path = ctx.scroll.path(3, true);
|
||||
let expected = [
|
||||
['scroll', 3],
|
||||
['block', 3],
|
||||
@ -56,7 +58,7 @@ describe('Scroll', function () {
|
||||
});
|
||||
|
||||
it('last', function () {
|
||||
let path = this.scroll.path(9);
|
||||
let path = ctx.scroll.path(9);
|
||||
let expected = [['scroll', 9]];
|
||||
expect(path.length).toEqual(expected.length);
|
||||
path.forEach(function (position, i) {
|
||||
@ -68,20 +70,20 @@ describe('Scroll', function () {
|
||||
|
||||
it('delete all', function () {
|
||||
let wrapper = document.createElement('div');
|
||||
wrapper.appendChild(this.scroll.domNode);
|
||||
this.scroll.deleteAt(0, 9);
|
||||
expect(wrapper.firstChild).toEqual(this.scroll.domNode);
|
||||
wrapper.appendChild(ctx.scroll.domNode);
|
||||
ctx.scroll.deleteAt(0, 9);
|
||||
expect(wrapper.firstChild).toEqual(ctx.scroll.domNode);
|
||||
});
|
||||
|
||||
it('detach', function (done) {
|
||||
spyOn(this.scroll, 'optimize').and.callThrough();
|
||||
this.scroll.domNode.innerHTML = 'Test';
|
||||
spyOn(ctx.scroll, 'optimize').and.callThrough();
|
||||
ctx.scroll.domNode.innerHTML = 'Test';
|
||||
setTimeout(() => {
|
||||
expect(this.scroll.optimize).toHaveBeenCalledTimes(1);
|
||||
this.scroll.detach();
|
||||
this.scroll.domNode.innerHTML = '!';
|
||||
expect(ctx.scroll.optimize).toHaveBeenCalledTimes(1);
|
||||
ctx.scroll.detach();
|
||||
ctx.scroll.domNode.innerHTML = '!';
|
||||
setTimeout(() => {
|
||||
expect(this.scroll.optimize).toHaveBeenCalledTimes(1);
|
||||
expect(ctx.scroll.optimize).toHaveBeenCalledTimes(1);
|
||||
done();
|
||||
}, 1);
|
||||
}, 1);
|
||||
@ -89,23 +91,23 @@ describe('Scroll', function () {
|
||||
|
||||
describe('scroll reference', function () {
|
||||
it('initialization', function () {
|
||||
expect(this.scroll.scroll).toEqual(this.scroll);
|
||||
this.scroll.descendants((blot) => {
|
||||
expect(blot.scroll).toEqual(this.scroll);
|
||||
expect(ctx.scroll).toEqual(ctx.scroll);
|
||||
ctx.scroll.descendants((blot) => {
|
||||
expect(blot.scroll).toEqual(ctx.scroll);
|
||||
});
|
||||
});
|
||||
|
||||
it('api change', function () {
|
||||
const blot = this.scroll.create('text', 'Test');
|
||||
this.scroll.appendChild(blot);
|
||||
expect(blot.scroll).toEqual(this.scroll);
|
||||
const blot = ctx.scroll.create('text', 'Test');
|
||||
ctx.scroll.appendChild(blot);
|
||||
expect(blot.scroll).toEqual(ctx.scroll);
|
||||
});
|
||||
|
||||
it('user change', function () {
|
||||
this.scroll.domNode.innerHTML = '<p><em>01</em>23</p>';
|
||||
this.scroll.update();
|
||||
this.scroll.descendants((blot) => {
|
||||
expect(blot.scroll).toEqual(this.scroll);
|
||||
ctx.scroll.domNode.innerHTML = '<p><em>01</em>23</p>';
|
||||
ctx.scroll.update();
|
||||
ctx.scroll.descendants((blot) => {
|
||||
expect(blot.scroll).toEqual(ctx.scroll);
|
||||
});
|
||||
});
|
||||
});
|
||||
@ -1,23 +1,26 @@
|
||||
'use strict';
|
||||
import TextBlot from '../../src/blot/text';
|
||||
import { setupContextBeforeEach } from '../setup';
|
||||
|
||||
describe('TextBlot', function () {
|
||||
const ctx = setupContextBeforeEach();
|
||||
|
||||
it('constructor(node)', function () {
|
||||
let node = document.createTextNode('Test');
|
||||
let blot = new TextBlot(this.scroll, node);
|
||||
let blot = new TextBlot(ctx.scroll, node);
|
||||
expect(blot.text).toEqual('Test');
|
||||
expect(blot.domNode.data).toEqual('Test');
|
||||
});
|
||||
|
||||
it('deleteAt() partial', function () {
|
||||
let blot = this.scroll.create('text', 'Test');
|
||||
let blot = ctx.scroll.create('text', 'Test');
|
||||
blot.deleteAt(1, 2);
|
||||
expect(blot.value()).toEqual('Tt');
|
||||
expect(blot.length()).toEqual(2);
|
||||
});
|
||||
|
||||
it('deleteAt() all', function () {
|
||||
let container = this.scroll.create('inline');
|
||||
let textBlot = this.scroll.create('text', 'Test');
|
||||
let container = ctx.scroll.create('inline');
|
||||
let textBlot = ctx.scroll.create('text', 'Test');
|
||||
container.appendChild(textBlot);
|
||||
expect(container.domNode.firstChild).toEqual(textBlot.domNode);
|
||||
textBlot.deleteAt(0, 4);
|
||||
@ -25,14 +28,14 @@ describe('TextBlot', function () {
|
||||
});
|
||||
|
||||
it('insertAt() text', function () {
|
||||
let textBlot = this.scroll.create('text', 'Test');
|
||||
let textBlot = ctx.scroll.create('text', 'Test');
|
||||
textBlot.insertAt(1, 'ough');
|
||||
expect(textBlot.value()).toEqual('Toughest');
|
||||
});
|
||||
|
||||
it('insertAt() other', function () {
|
||||
let container = this.scroll.create('inline');
|
||||
let textBlot = this.scroll.create('text', 'Test');
|
||||
let container = ctx.scroll.create('inline');
|
||||
let textBlot = ctx.scroll.create('text', 'Test');
|
||||
container.appendChild(textBlot);
|
||||
textBlot.insertAt(2, 'image', {});
|
||||
expect(textBlot.value()).toEqual('Te');
|
||||
@ -41,8 +44,8 @@ describe('TextBlot', function () {
|
||||
});
|
||||
|
||||
it('split() middle', function () {
|
||||
let container = this.scroll.create('inline');
|
||||
let textBlot = this.scroll.create('text', 'Test');
|
||||
let container = ctx.scroll.create('inline');
|
||||
let textBlot = ctx.scroll.create('text', 'Test');
|
||||
container.appendChild(textBlot);
|
||||
let after = textBlot.split(2);
|
||||
expect(textBlot.value()).toEqual('Te');
|
||||
@ -52,8 +55,8 @@ describe('TextBlot', function () {
|
||||
});
|
||||
|
||||
it('split() noop', function () {
|
||||
let container = this.scroll.create('inline');
|
||||
let textBlot = this.scroll.create('text', 'Test');
|
||||
let container = ctx.scroll.create('inline');
|
||||
let textBlot = ctx.scroll.create('text', 'Test');
|
||||
container.appendChild(textBlot);
|
||||
let before = textBlot.split(0);
|
||||
let after = textBlot.split(4);
|
||||
@ -62,8 +65,8 @@ describe('TextBlot', function () {
|
||||
});
|
||||
|
||||
it('split() force', function () {
|
||||
let container = this.scroll.create('inline');
|
||||
let textBlot = this.scroll.create('text', 'Test');
|
||||
let container = ctx.scroll.create('inline');
|
||||
let textBlot = ctx.scroll.create('text', 'Test');
|
||||
container.appendChild(textBlot);
|
||||
let after = textBlot.split(4, true);
|
||||
expect(after).not.toEqual(textBlot);
|
||||
@ -73,8 +76,8 @@ describe('TextBlot', function () {
|
||||
});
|
||||
|
||||
it('format wrap', function () {
|
||||
let container = this.scroll.create('inline');
|
||||
let textBlot = this.scroll.create('text', 'Test');
|
||||
let container = ctx.scroll.create('inline');
|
||||
let textBlot = ctx.scroll.create('text', 'Test');
|
||||
container.appendChild(textBlot);
|
||||
textBlot.formatAt(0, 4, 'bold', true);
|
||||
expect(textBlot.domNode.parentNode.tagName).toEqual('STRONG');
|
||||
@ -82,8 +85,8 @@ describe('TextBlot', function () {
|
||||
});
|
||||
|
||||
it('format null', function () {
|
||||
let container = this.scroll.create('inline');
|
||||
let textBlot = this.scroll.create('text', 'Test');
|
||||
let container = ctx.scroll.create('inline');
|
||||
let textBlot = ctx.scroll.create('text', 'Test');
|
||||
container.appendChild(textBlot);
|
||||
textBlot.formatAt(0, 4, 'bold', null);
|
||||
expect(textBlot.domNode.parentNode.tagName).toEqual('SPAN');
|
||||
@ -91,8 +94,8 @@ describe('TextBlot', function () {
|
||||
});
|
||||
|
||||
it('format split', function () {
|
||||
let container = this.scroll.create('block');
|
||||
let textBlot = this.scroll.create('text', 'Test');
|
||||
let container = ctx.scroll.create('block');
|
||||
let textBlot = ctx.scroll.create('text', 'Test');
|
||||
container.appendChild(textBlot);
|
||||
textBlot.formatAt(1, 2, 'bold', true);
|
||||
expect(container.domNode.innerHTML).toEqual('T<strong>es</strong>t');
|
||||
@ -101,13 +104,13 @@ describe('TextBlot', function () {
|
||||
});
|
||||
|
||||
it('index()', function () {
|
||||
let textBlot = this.scroll.create('text', 'Test');
|
||||
let textBlot = ctx.scroll.create('text', 'Test');
|
||||
expect(textBlot.index(textBlot.domNode, 2)).toEqual(2);
|
||||
expect(textBlot.index(document.body, 2)).toEqual(-1);
|
||||
});
|
||||
|
||||
it('position()', function () {
|
||||
let textBlot = this.scroll.create('text', 'Test');
|
||||
let textBlot = ctx.scroll.create('text', 'Test');
|
||||
let [node, offset] = textBlot.position(2);
|
||||
expect(node).toEqual(textBlot.domNode);
|
||||
expect(offset).toEqual(2);
|
||||
13
vite.config.ts
Normal file
13
vite.config.ts
Normal file
@ -0,0 +1,13 @@
|
||||
import { defineConfig } from 'vite';
|
||||
|
||||
export default defineConfig({
|
||||
build: {
|
||||
outDir: 'dist',
|
||||
lib: {
|
||||
name: 'Parchment',
|
||||
entry: './src/parchment.ts',
|
||||
formats: ['es', 'umd'],
|
||||
},
|
||||
sourcemap: true,
|
||||
},
|
||||
});
|
||||
@ -1,33 +0,0 @@
|
||||
module.exports = {
|
||||
entry: {
|
||||
parchment: './src/parchment.ts',
|
||||
},
|
||||
output: {
|
||||
filename: '[name].js',
|
||||
library: {
|
||||
name: 'Parchment',
|
||||
type: 'umd',
|
||||
},
|
||||
path: __dirname + '/dist',
|
||||
// https://github.com/webpack/webpack/issues/6525
|
||||
globalObject: `(() => {
|
||||
if (typeof self !== 'undefined') {
|
||||
return self;
|
||||
} else if (typeof window !== 'undefined') {
|
||||
return window;
|
||||
} else if (typeof global !== 'undefined') {
|
||||
return global;
|
||||
} else {
|
||||
return Function('return this')();
|
||||
}
|
||||
})()`,
|
||||
},
|
||||
resolve: {
|
||||
extensions: ['.js', '.ts'],
|
||||
},
|
||||
module: {
|
||||
rules: [{ test: /\.ts$/, use: 'ts-loader' }],
|
||||
},
|
||||
devtool: 'source-map',
|
||||
mode: 'production',
|
||||
};
|
||||
Loading…
Reference in New Issue
Block a user