pagebreakediting.js 4.0 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121
  1. /**
  2. * @license Copyright (c) 2003-2019, CKSource - Frederico Knabben. All rights reserved.
  3. * For licensing, see LICENSE.md or https://ckeditor.com/legal/ckeditor-oss-license
  4. */
  5. /**
  6. * @module page-break/pagebreakediting
  7. */
  8. import Plugin from '@ckeditor/ckeditor5-core/src/plugin';
  9. import PageBreakCommand from './pagebreakcommand';
  10. import { toWidget } from '@ckeditor/ckeditor5-widget/src/utils';
  11. import first from '@ckeditor/ckeditor5-utils/src/first';
  12. import '../theme/pagebreak.css';
  13. /**
  14. * The page break editing feature.
  15. *
  16. * @extends module:core/plugin~Plugin
  17. */
  18. export default class PageBreakEditing extends Plugin {
  19. /**
  20. * @inheritDoc
  21. */
  22. init() {
  23. const editor = this.editor;
  24. const schema = editor.model.schema;
  25. const t = editor.t;
  26. const conversion = editor.conversion;
  27. schema.register( 'pageBreak', {
  28. isObject: true,
  29. allowWhere: '$block'
  30. } );
  31. conversion.for( 'dataDowncast' ).elementToElement( {
  32. model: 'pageBreak',
  33. view: ( modelElement, viewWriter ) => {
  34. const divElement = viewWriter.createContainerElement( 'div', {
  35. class: 'page-break',
  36. // If user has no `.ck-content` styles, it should always break a page during print.
  37. style: 'page-break-after: always'
  38. } );
  39. // For a rationale of using span inside a div see:
  40. // https://github.com/ckeditor/ckeditor5-page-break/pull/1#discussion_r328934062.
  41. const spanElement = viewWriter.createContainerElement( 'span', {
  42. style: 'display: none'
  43. } );
  44. viewWriter.insert( viewWriter.createPositionAt( divElement, 0 ), spanElement );
  45. return divElement;
  46. }
  47. } );
  48. conversion.for( 'editingDowncast' ).elementToElement( {
  49. model: 'pageBreak',
  50. view: ( modelElement, viewWriter ) => {
  51. const label = t( 'Page break' );
  52. const viewWrapper = viewWriter.createContainerElement( 'div' );
  53. const viewLabelElement = viewWriter.createContainerElement( 'span' );
  54. const innerText = viewWriter.createText( t( 'Page break' ) );
  55. viewWriter.addClass( 'page-break', viewWrapper );
  56. viewWriter.setCustomProperty( 'pageBreak', true, viewWrapper );
  57. viewWriter.addClass( 'page-break__label', viewLabelElement );
  58. viewWriter.insert( viewWriter.createPositionAt( viewWrapper, 0 ), viewLabelElement );
  59. viewWriter.insert( viewWriter.createPositionAt( viewLabelElement, 0 ), innerText );
  60. return toPageBreakWidget( viewWrapper, viewWriter, label );
  61. }
  62. } );
  63. conversion.for( 'upcast' )
  64. .elementToElement( {
  65. view: element => {
  66. // The "page break" div must have specified value for the 'page-break-after' definition and single child only.
  67. if ( !element.is( 'div' ) || element.getStyle( 'page-break-after' ) != 'always' || element.childCount != 1 ) {
  68. return;
  69. }
  70. const viewSpan = first( element.getChildren() );
  71. // The child must be the "span" element that is not displayed and has a space inside.
  72. if ( !viewSpan.is( 'span' ) || viewSpan.getStyle( 'display' ) != 'none' || viewSpan.childCount != 1 ) {
  73. return;
  74. }
  75. const text = first( viewSpan.getChildren() );
  76. if ( !text.is( 'text' ) || text.data !== ' ' ) {
  77. return;
  78. }
  79. return { name: true };
  80. },
  81. model: 'pageBreak'
  82. } );
  83. editor.commands.add( 'pageBreak', new PageBreakCommand( editor ) );
  84. }
  85. }
  86. // Converts a given {@link module:engine/view/element~Element} to a page break widget:
  87. // * Adds a {@link module:engine/view/element~Element#_setCustomProperty custom property} allowing to
  88. // recognize the page break widget element.
  89. // * Calls the {@link module:widget/utils~toWidget} function with the proper element's label creator.
  90. //
  91. // @param {module:engine/view/element~Element} viewElement
  92. // @param {module:engine/view/downcastwriter~DowncastWriter} writer An instance of the view writer.
  93. // @param {String} label The element's label.
  94. // @returns {module:engine/view/element~Element}
  95. function toPageBreakWidget( viewElement, writer, label ) {
  96. writer.setCustomProperty( 'pageBreak', true, viewElement );
  97. return toWidget( viewElement, writer, { label } );
  98. }