/
pagebreakediting.js
136 lines (112 loc) · 4.1 KB
/
pagebreakediting.js
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
/**
* @license Copyright (c) 2003-2021, CKSource - Frederico Knabben. All rights reserved.
* For licensing, see LICENSE.md or https://ckeditor.com/legal/ckeditor-oss-license
*/
/**
* @module page-break/pagebreakediting
*/
import { Plugin } from 'ckeditor5/src/core';
import { toWidget } from 'ckeditor5/src/widget';
import PageBreakCommand from './pagebreakcommand';
import '../theme/pagebreak.css';
/**
* The page break editing feature.
*
* @extends module:core/plugin~Plugin
*/
export default class PageBreakEditing extends Plugin {
/**
* @inheritDoc
*/
static get pluginName() {
return 'PageBreakEditing';
}
/**
* @inheritDoc
*/
init() {
const editor = this.editor;
const schema = editor.model.schema;
const t = editor.t;
const conversion = editor.conversion;
schema.register( 'pageBreak', {
isObject: true,
allowWhere: '$block'
} );
conversion.for( 'dataDowncast' ).elementToElement( {
model: 'pageBreak',
view: ( modelElement, { writer } ) => {
const divElement = writer.createContainerElement( 'div', {
class: 'page-break',
// If user has no `.ck-content` styles, it should always break a page during print.
style: 'page-break-after: always'
} );
// For a rationale of using span inside a div see:
// https://github.com/ckeditor/ckeditor5-page-break/pull/1#discussion_r328934062.
const spanElement = writer.createContainerElement( 'span', {
style: 'display: none'
} );
writer.insert( writer.createPositionAt( divElement, 0 ), spanElement );
return divElement;
}
} );
conversion.for( 'editingDowncast' ).elementToElement( {
model: 'pageBreak',
view: ( modelElement, { writer } ) => {
const label = t( 'Page break' );
const viewWrapper = writer.createContainerElement( 'div' );
const viewLabelElement = writer.createRawElement(
'span',
{ class: 'page-break__label' },
function( domElement ) {
domElement.innerText = t( 'Page break' );
}
);
writer.addClass( 'page-break', viewWrapper );
writer.insert( writer.createPositionAt( viewWrapper, 0 ), viewLabelElement );
return toPageBreakWidget( viewWrapper, writer, label );
}
} );
conversion.for( 'upcast' )
.elementToElement( {
view: element => {
// For upcast conversion it's enough if we check for element style and verify if it's empty
// or contains only hidden span element.
const hasPageBreakBefore = element.getStyle( 'page-break-before' ) == 'always';
const hasPageBreakAfter = element.getStyle( 'page-break-after' ) == 'always';
if ( !hasPageBreakBefore && !hasPageBreakAfter ) {
return;
}
// The "page break" div accepts only single child or no child at all.
if ( element.childCount == 1 ) {
const viewSpan = element.getChild( 0 );
// The child must be the "span" element that is not displayed.
if ( !viewSpan.is( 'element', 'span' ) || viewSpan.getStyle( 'display' ) != 'none' ) {
return;
}
} else if ( element.childCount > 1 ) {
return;
}
return { name: true };
},
model: 'pageBreak',
// This conversion must be checked before <br> conversion because some editors use
// <br style="page-break-before:always"> as a page break marker.
converterPriority: 'high'
} );
editor.commands.add( 'pageBreak', new PageBreakCommand( editor ) );
}
}
// Converts a given {@link module:engine/view/element~Element} to a page break widget:
// * Adds a {@link module:engine/view/element~Element#_setCustomProperty custom property} allowing to
// recognize the page break widget element.
// * Calls the {@link module:widget/utils~toWidget} function with the proper element's label creator.
//
// @param {module:engine/view/element~Element} viewElement
// @param {module:engine/view/downcastwriter~DowncastWriter} writer An instance of the view writer.
// @param {String} label The element's label.
// @returns {module:engine/view/element~Element}
function toPageBreakWidget( viewElement, writer, label ) {
writer.setCustomProperty( 'pageBreak', true, viewElement );
return toWidget( viewElement, writer, { label } );
}