index.js 4.0 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125
  1. import React from 'react';
  2. import ReactDOM from 'react-dom';
  3. import { DraftailEditor } from 'draftail';
  4. import { IS_IE11, STRINGS } from '../../config/wagtailConfig';
  5. import Icon from '../Icon/Icon';
  6. export { default as Link } from './decorators/Link';
  7. export { default as Document } from './decorators/Document';
  8. export { default as ImageBlock } from './blocks/ImageBlock';
  9. export { default as EmbedBlock } from './blocks/EmbedBlock';
  10. export { default as ModalWorkflowSource } from './sources/ModalWorkflowSource';
  11. import EditorFallback from './EditorFallback/EditorFallback';
  12. // 1024x1024 SVG path rendering of the "↵" character, that renders badly in MS Edge.
  13. const BR_ICON = 'M.436 633.471l296.897-296.898v241.823h616.586V94.117h109.517v593.796H297.333v242.456z';
  14. /**
  15. * Registry for client-side code of Draftail plugins.
  16. */
  17. const PLUGINS = {};
  18. const registerPlugin = (plugin) => {
  19. PLUGINS[plugin.type] = plugin;
  20. return PLUGINS;
  21. };
  22. /**
  23. * Wraps a style/block/entity type’s icon with an icon font implementation,
  24. * so Draftail can use icon fonts in its toolbar.
  25. */
  26. export const wrapWagtailIcon = type => {
  27. const isIconFont = type.icon && typeof type.icon === 'string';
  28. if (isIconFont) {
  29. return Object.assign(type, {
  30. icon: <Icon name={type.icon} />,
  31. });
  32. }
  33. return type;
  34. };
  35. /**
  36. * Initialises the DraftailEditor for a given field.
  37. * @param {string} selector
  38. * @param {Object} options
  39. * @param {Element} currentScript
  40. */
  41. const initEditor = (selector, options, currentScript) => {
  42. // document.currentScript is not available in IE11. Use a fallback instead.
  43. const context = currentScript ? currentScript.parentNode : document.body;
  44. // If the field is not in the current context, look for it in the whole body.
  45. // Fallback for sequence.js jQuery eval-ed scripts running in document.head.
  46. const field = context.querySelector(selector) || document.body.querySelector(selector);
  47. const editorWrapper = document.createElement('div');
  48. editorWrapper.className = 'Draftail-Editor__wrapper';
  49. editorWrapper.setAttribute('data-draftail-editor-wrapper', true);
  50. field.parentNode.appendChild(editorWrapper);
  51. const serialiseInputValue = rawContentState => {
  52. field.rawContentState = rawContentState;
  53. field.value = JSON.stringify(rawContentState);
  54. };
  55. const blockTypes = options.blockTypes || [];
  56. const inlineStyles = options.inlineStyles || [];
  57. let entityTypes = options.entityTypes || [];
  58. entityTypes = entityTypes.map(wrapWagtailIcon).map((type) => {
  59. const plugin = PLUGINS[type.type];
  60. // Override the properties defined in the JS plugin: Python should be the source of truth.
  61. return Object.assign({}, plugin, type);
  62. });
  63. const enableHorizontalRule = options.enableHorizontalRule ? {
  64. description: STRINGS.HORIZONTAL_LINE,
  65. } : false;
  66. const rawContentState = JSON.parse(field.value);
  67. field.rawContentState = rawContentState;
  68. const editorRef = (ref) => {
  69. // Bind editor instance to its field so it can be accessed imperatively elsewhere.
  70. field.draftailEditor = ref;
  71. };
  72. const editor = (
  73. <EditorFallback field={field}>
  74. <DraftailEditor
  75. ref={editorRef}
  76. rawContentState={rawContentState}
  77. onSave={serialiseInputValue}
  78. placeholder={STRINGS.WRITE_HERE}
  79. spellCheck={true}
  80. enableLineBreak={{
  81. description: STRINGS.LINE_BREAK,
  82. icon: BR_ICON,
  83. }}
  84. showUndoControl={{ description: STRINGS.UNDO }}
  85. showRedoControl={{ description: STRINGS.REDO }}
  86. maxListNesting={4}
  87. // Draft.js + IE 11 presents some issues with pasting rich text. Disable rich paste there.
  88. stripPastedStyles={IS_IE11}
  89. {...options}
  90. blockTypes={blockTypes.map(wrapWagtailIcon)}
  91. inlineStyles={inlineStyles.map(wrapWagtailIcon)}
  92. entityTypes={entityTypes}
  93. enableHorizontalRule={enableHorizontalRule}
  94. />
  95. </EditorFallback>
  96. );
  97. ReactDOM.render(editor, editorWrapper);
  98. };
  99. export default {
  100. initEditor,
  101. registerPlugin,
  102. };