Refactor Draftail JS plugin API to be more similar to the rich text features registry API

pull/4261/head
Thibaud Colas 2018-02-08 00:01:32 +02:00 zatwierdzone przez Matt Westcott
rodzic f31bbba3e6
commit e59863f903
12 zmienionych plików z 73 dodań i 107 usunięć

Wyświetl plik

@ -16,9 +16,8 @@ Object {
"entityTypes": Array [
Object {
"block": [Function],
"decorator": undefined,
"source": [Function],
"type": "Image",
"type": "IMAGE",
},
],
"inlineStyles": Array [],

Wyświetl plik

@ -46,13 +46,12 @@ export const initEditor = (fieldName, options) => {
const inlineStyles = options.inlineStyles || [];
let entityTypes = options.entityTypes || [];
entityTypes = entityTypes.map(wrapWagtailIcon).map(type =>
Object.assign(type, {
source: registry.getSource(type.source),
decorator: registry.getDecorator(type.decorator),
block: registry.getBlock(type.block),
})
);
entityTypes = entityTypes.map(wrapWagtailIcon).map((type) => {
const plugin = registry.getPlugin(type.type);
// Override the properties defined in the JS plugin: Python should be the source of truth.
return Object.assign({}, plugin, type);
});
const enableHorizontalRule = options.enableHorizontalRule ? {
description: STRINGS.HORIZONTAL_LINE,

Wyświetl plik

@ -45,17 +45,15 @@ describe('Draftail', () => {
field.value = 'null';
document.body.appendChild(field);
registry.registerSources({
ModalWorkflowSource: () => {},
});
registry.registerBlocks({
ImageBlock: () => {},
registry.registerPlugin({
type: 'IMAGE',
source: () => {},
block: () => {},
});
initEditor('test', {
entityTypes: [
{ type: 'Image', source: 'ModalWorkflowSource', block: 'ImageBlock' },
{ type: 'IMAGE' },
],
enableHorizontalRule: true,
});

Wyświetl plik

@ -1,22 +1,14 @@
const registry = {
decorators: {},
blocks: {},
sources: {},
const plugins = {};
const registerPlugin = (plugin) => {
plugins[plugin.type] = plugin;
return plugins;
};
const registerDecorators = (decorators) => Object.assign(registry.decorators, decorators);
const registerBlocks = (blocks) => Object.assign(registry.blocks, blocks);
const registerSources = (sources) => Object.assign(registry.sources, sources);
const getDecorator = name => registry.decorators[name];
const getBlock = name => registry.blocks[name];
const getSource = name => registry.sources[name];
const getPlugin = (type) => plugins[type];
export default {
registerDecorators,
registerBlocks,
registerSources,
getDecorator,
getBlock,
getSource,
registerPlugin,
getPlugin,
};

Wyświetl plik

@ -1,39 +1,15 @@
import registry from './registry';
describe('registry', () => {
describe('sources', () => {
it('works', () => {
expect(registry.getSource('UndefinedSource')).not.toBeDefined();
it('works', () => {
const plugin = {
type: 'TEST',
source: null,
decorator: null,
};
registry.registerSources({
TestSource: null,
});
expect(registry.getSource('TestSource')).toBe(null);
});
});
describe('decorators', () => {
it('works', () => {
expect(registry.getDecorator('UndefinedDecorator')).not.toBeDefined();
registry.registerDecorators({
TestDecorator: null,
});
expect(registry.getDecorator('TestDecorator')).toBe(null);
});
});
describe('blocks', () => {
it('works', () => {
expect(registry.getBlock('UndefinedBlock')).not.toBeDefined();
registry.registerBlocks({
TestBlock: null,
});
expect(registry.getBlock('TestBlock')).toBe(null);
});
expect(registry.getPlugin('TEST')).not.toBeDefined();
registry.registerPlugin(plugin);
expect(registry.getPlugin('TEST')).toBe(plugin);
});
});

Wyświetl plik

@ -175,8 +175,6 @@ In order to achieve this, we start with registering the rich text feature like f
'type': type_,
'label': '$',
'description': 'Stock',
'source': 'StockSource',
'decorator': 'Stock'
}
features.register_editor_plugin(
@ -282,14 +280,8 @@ We define the source component:
}
}
window.draftail.registerSources({
StockSource: StockSource,
});
This source component uses data and callbacks provided by `Draftail <https://github.com/springload/draftail>`_.
It also uses dependencies from global variables – see :ref:`extending_clientside_components`.
Note how after the source declaration it is then registered for Draftail to know about it.
We then create the decorator component:
@ -307,12 +299,17 @@ We then create the decorator component:
}, props.children);
};
window.draftail.registerDecorators({
Stock: Stock,
});
This is a straightforward React component. It does not use JSX since we do not want to have to use a build step for our JavaScript. It uses ES6 syntax – this would not work in IE11 unless it was converted back to ES5 with a build step.
This is a straightforward React component. It does not use JSX since we do not want to have to use a build step for our JavaScript. It uses ES6 syntax – this would not work in IE11 unless it was converted back to ES5.
We also have to register this with Draftail.
Finally, we register the JS components of our plugin:
.. code-block:: javascript
window.draftail.registerPlugin({
type: 'STOCK',
source: StockSource,
decorator: Stock,
});
And thats it! All of this setup will finally produce the following HTML on the sites front-end:

Wyświetl plik

@ -9,22 +9,36 @@ import {
} from '../../../../../client/src/components/Draftail/index';
/**
* Expose as a global, and register the built-in entities.
* Entry point loaded when the Draftail editor is in use.
*/
const draftail = registry;
window.draftail = registry;
window.draftail.initEditor = initEditor;
// Expose Draftail as a global, with the initEditor function.
draftail.initEditor = initEditor;
window.draftail = draftail;
window.draftail.registerSources({
ModalWorkflowSource,
});
// Plugins for the built-in entities.
const plugins = [
{
type: 'DOCUMENT',
source: ModalWorkflowSource,
decorator: Document,
},
{
type: 'LINK',
source: ModalWorkflowSource,
decorator: Link,
},
{
type: 'IMAGE',
source: ModalWorkflowSource,
block: ImageBlock,
},
{
type: 'EMBED',
source: ModalWorkflowSource,
block: EmbedBlock,
},
];
window.draftail.registerDecorators({
Link,
Document,
});
window.draftail.registerBlocks({
ImageBlock,
EmbedBlock,
});
plugins.forEach(draftail.registerPlugin);

Wyświetl plik

@ -6,10 +6,9 @@ describe('draftail.entry', () => {
});
it('has defaults registered', () => {
expect(window.draftail.getSource('ModalWorkflowSource')).toBeDefined();
expect(window.draftail.getDecorator('Link')).toBeDefined();
expect(window.draftail.getDecorator('Document')).toBeDefined();
expect(window.draftail.getBlock('ImageBlock')).toBeDefined();
expect(window.draftail.getBlock('EmbedBlock')).toBeDefined();
expect(window.draftail.getPlugin('LINK')).toBeDefined();
expect(window.draftail.getPlugin('DOCUMENT')).toBeDefined();
expect(window.draftail.getPlugin('IMAGE')).toBeDefined();
expect(window.draftail.getPlugin('EMBED')).toBeDefined();
});
});

Wyświetl plik

@ -430,8 +430,6 @@ def register_core_features(features):
'type': 'LINK',
'icon': 'link',
'description': ugettext('Link'),
'source': 'ModalWorkflowSource',
'decorator': 'Link',
# We want to enforce constraints on which links can be pasted into rich text.
# Keep only the attributes Wagtail needs.
'attributes': ['url', 'id', 'parentId'],

Wyświetl plik

@ -90,8 +90,6 @@ def register_document_feature(features):
'type': 'DOCUMENT',
'icon': 'doc-full',
'description': ugettext('Document'),
'source': 'ModalWorkflowSource',
'decorator': 'Document',
})
)

Wyświetl plik

@ -54,8 +54,6 @@ def register_embed_feature(features):
'type': 'EMBED',
'icon': 'media',
'description': _('Embed'),
'source': 'ModalWorkflowSource',
'block': 'EmbedBlock',
})
)

Wyświetl plik

@ -89,8 +89,6 @@ def register_image_feature(features):
'type': 'IMAGE',
'icon': 'image',
'description': ugettext('Image'),
'source': 'ModalWorkflowSource',
'block': 'ImageBlock',
# We do not want users to be able to copy-paste hotlinked images into rich text.
# Keep only the attributes Wagtail needs.
'attributes': ['id', 'src', 'alt', 'format'],