kopia lustrzana https://github.com/wagtail/wagtail
Refactor Draftail JS plugin API to be more similar to the rich text features registry API
rodzic
f31bbba3e6
commit
e59863f903
|
@ -16,9 +16,8 @@ Object {
|
|||
"entityTypes": Array [
|
||||
Object {
|
||||
"block": [Function],
|
||||
"decorator": undefined,
|
||||
"source": [Function],
|
||||
"type": "Image",
|
||||
"type": "IMAGE",
|
||||
},
|
||||
],
|
||||
"inlineStyles": Array [],
|
||||
|
|
|
@ -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,
|
||||
|
|
|
@ -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,
|
||||
});
|
||||
|
|
|
@ -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,
|
||||
};
|
||||
|
|
|
@ -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);
|
||||
});
|
||||
});
|
||||
|
|
|
@ -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 that’s it! All of this setup will finally produce the following HTML on the site’s front-end:
|
||||
|
||||
|
|
|
@ -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);
|
||||
|
|
|
@ -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();
|
||||
});
|
||||
});
|
||||
|
|
|
@ -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'],
|
||||
|
|
|
@ -90,8 +90,6 @@ def register_document_feature(features):
|
|||
'type': 'DOCUMENT',
|
||||
'icon': 'doc-full',
|
||||
'description': ugettext('Document'),
|
||||
'source': 'ModalWorkflowSource',
|
||||
'decorator': 'Document',
|
||||
})
|
||||
)
|
||||
|
||||
|
|
|
@ -54,8 +54,6 @@ def register_embed_feature(features):
|
|||
'type': 'EMBED',
|
||||
'icon': 'media',
|
||||
'description': _('Embed'),
|
||||
'source': 'ModalWorkflowSource',
|
||||
'block': 'EmbedBlock',
|
||||
})
|
||||
)
|
||||
|
||||
|
|
|
@ -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'],
|
||||
|
|
Ładowanie…
Reference in New Issue