@ckeditor/ckeditor5-ui 35.2.1 → 35.3.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/package.json +31 -23
- package/src/bindings/addkeyboardhandlingforgrid.js +45 -57
- package/src/bindings/clickoutsidehandler.js +15 -21
- package/src/bindings/injectcsstransitiondisabler.js +16 -20
- package/src/bindings/preventdefault.js +6 -8
- package/src/bindings/submithandler.js +5 -7
- package/src/button/button.js +5 -0
- package/src/button/buttonview.js +220 -259
- package/src/button/switchbuttonview.js +56 -71
- package/src/colorgrid/colorgridview.js +135 -197
- package/src/colorgrid/colortileview.js +37 -47
- package/src/colorgrid/utils.js +57 -66
- package/src/componentfactory.js +79 -93
- package/src/dropdown/button/dropdownbutton.js +5 -0
- package/src/dropdown/button/dropdownbuttonview.js +44 -57
- package/src/dropdown/button/splitbuttonview.js +159 -207
- package/src/dropdown/dropdownpanelfocusable.js +5 -0
- package/src/dropdown/dropdownpanelview.js +101 -112
- package/src/dropdown/dropdownview.js +396 -438
- package/src/dropdown/utils.js +164 -213
- package/src/editableui/editableuiview.js +125 -141
- package/src/editableui/inline/inlineeditableuiview.js +44 -54
- package/src/editorui/bodycollection.js +61 -75
- package/src/editorui/boxed/boxededitoruiview.js +91 -104
- package/src/editorui/editoruiview.js +30 -39
- package/src/focuscycler.js +214 -245
- package/src/formheader/formheaderview.js +58 -70
- package/src/icon/iconview.js +145 -111
- package/src/iframe/iframeview.js +37 -49
- package/src/index.js +0 -17
- package/src/input/inputview.js +170 -198
- package/src/inputnumber/inputnumberview.js +48 -56
- package/src/inputtext/inputtextview.js +14 -18
- package/src/label/labelview.js +44 -53
- package/src/labeledfield/labeledfieldview.js +212 -235
- package/src/labeledfield/utils.js +39 -57
- package/src/labeledinput/labeledinputview.js +190 -221
- package/src/list/listitemview.js +40 -50
- package/src/list/listseparatorview.js +15 -19
- package/src/list/listview.js +94 -115
- package/src/model.js +19 -25
- package/src/notification/notification.js +151 -202
- package/src/panel/balloon/balloonpanelview.js +535 -628
- package/src/panel/balloon/contextualballoon.js +611 -732
- package/src/panel/sticky/stickypanelview.js +238 -270
- package/src/template.js +1049 -1479
- package/src/toolbar/balloon/balloontoolbar.js +337 -424
- package/src/toolbar/block/blockbuttonview.js +32 -42
- package/src/toolbar/block/blocktoolbar.js +375 -477
- package/src/toolbar/normalizetoolbarconfig.js +17 -21
- package/src/toolbar/toolbarlinebreakview.js +15 -19
- package/src/toolbar/toolbarseparatorview.js +15 -19
- package/src/toolbar/toolbarview.js +866 -1053
- package/src/tooltipmanager.js +324 -353
- package/src/view.js +389 -430
- package/src/viewcollection.js +147 -178
- package/src/button/button.jsdoc +0 -165
- package/src/dropdown/button/dropdownbutton.jsdoc +0 -22
- package/src/dropdown/dropdownpanelfocusable.jsdoc +0 -27
|
@@ -2,11 +2,9 @@
|
|
|
2
2
|
* @license Copyright (c) 2003-2022, CKSource Holding sp. z o.o. All rights reserved.
|
|
3
3
|
* For licensing, see LICENSE.md or https://ckeditor.com/legal/ckeditor-oss-license
|
|
4
4
|
*/
|
|
5
|
-
|
|
6
5
|
/**
|
|
7
6
|
* @module ui/panel/balloon/contextualballoon
|
|
8
7
|
*/
|
|
9
|
-
|
|
10
8
|
import Plugin from '@ckeditor/ckeditor5-core/src/plugin';
|
|
11
9
|
import BalloonPanelView from './balloonpanelview';
|
|
12
10
|
import View from '../../view';
|
|
@@ -15,15 +13,11 @@ import CKEditorError from '@ckeditor/ckeditor5-utils/src/ckeditorerror';
|
|
|
15
13
|
import FocusTracker from '@ckeditor/ckeditor5-utils/src/focustracker';
|
|
16
14
|
import toUnit from '@ckeditor/ckeditor5-utils/src/dom/tounit';
|
|
17
15
|
import Rect from '@ckeditor/ckeditor5-utils/src/dom/rect';
|
|
18
|
-
|
|
19
16
|
import prevIcon from '../../../theme/icons/previous-arrow.svg';
|
|
20
17
|
import nextIcon from '../../../theme/icons/next-arrow.svg';
|
|
21
|
-
|
|
22
18
|
import '../../../theme/components/panel/balloonrotator.css';
|
|
23
19
|
import '../../../theme/components/panel/fakepanel.css';
|
|
24
|
-
|
|
25
|
-
const toPx = toUnit( 'px' );
|
|
26
|
-
|
|
20
|
+
const toPx = toUnit('px');
|
|
27
21
|
/**
|
|
28
22
|
* Provides the common contextual balloon for the editor.
|
|
29
23
|
*
|
|
@@ -61,473 +55,394 @@ const toPx = toUnit( 'px' );
|
|
|
61
55
|
* @extends module:core/plugin~Plugin
|
|
62
56
|
*/
|
|
63
57
|
export default class ContextualBalloon extends Plugin {
|
|
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
|
-
|
|
137
|
-
|
|
138
|
-
|
|
139
|
-
|
|
140
|
-
|
|
141
|
-
|
|
142
|
-
|
|
143
|
-
|
|
144
|
-
|
|
145
|
-
|
|
146
|
-
|
|
147
|
-
|
|
148
|
-
|
|
149
|
-
|
|
150
|
-
|
|
151
|
-
|
|
152
|
-
|
|
153
|
-
|
|
154
|
-
|
|
155
|
-
|
|
156
|
-
|
|
157
|
-
|
|
158
|
-
|
|
159
|
-
|
|
160
|
-
|
|
161
|
-
|
|
162
|
-
|
|
163
|
-
|
|
164
|
-
|
|
165
|
-
|
|
166
|
-
|
|
167
|
-
|
|
168
|
-
|
|
169
|
-
|
|
170
|
-
|
|
171
|
-
|
|
172
|
-
|
|
173
|
-
|
|
174
|
-
|
|
175
|
-
|
|
176
|
-
|
|
177
|
-
|
|
178
|
-
|
|
179
|
-
|
|
180
|
-
|
|
181
|
-
|
|
182
|
-
|
|
183
|
-
|
|
184
|
-
|
|
185
|
-
|
|
186
|
-
|
|
187
|
-
|
|
188
|
-
|
|
189
|
-
|
|
190
|
-
|
|
191
|
-
|
|
192
|
-
|
|
193
|
-
|
|
194
|
-
|
|
195
|
-
|
|
196
|
-
|
|
197
|
-
|
|
198
|
-
|
|
199
|
-
|
|
200
|
-
|
|
201
|
-
|
|
202
|
-
|
|
203
|
-
|
|
204
|
-
|
|
205
|
-
|
|
206
|
-
|
|
207
|
-
|
|
208
|
-
|
|
209
|
-
|
|
210
|
-
|
|
211
|
-
|
|
212
|
-
|
|
213
|
-
|
|
214
|
-
|
|
215
|
-
|
|
216
|
-
|
|
217
|
-
|
|
218
|
-
|
|
219
|
-
|
|
220
|
-
|
|
221
|
-
|
|
222
|
-
|
|
223
|
-
|
|
224
|
-
|
|
225
|
-
|
|
226
|
-
|
|
227
|
-
|
|
228
|
-
|
|
229
|
-
|
|
230
|
-
|
|
231
|
-
|
|
232
|
-
|
|
233
|
-
|
|
234
|
-
|
|
235
|
-
|
|
236
|
-
|
|
237
|
-
|
|
238
|
-
|
|
239
|
-
|
|
240
|
-
|
|
241
|
-
|
|
242
|
-
|
|
243
|
-
|
|
244
|
-
|
|
245
|
-
|
|
246
|
-
|
|
247
|
-
|
|
248
|
-
|
|
249
|
-
|
|
250
|
-
|
|
251
|
-
|
|
252
|
-
|
|
253
|
-
|
|
254
|
-
|
|
255
|
-
|
|
256
|
-
|
|
257
|
-
|
|
258
|
-
|
|
259
|
-
|
|
260
|
-
|
|
261
|
-
|
|
262
|
-
|
|
263
|
-
|
|
264
|
-
|
|
265
|
-
|
|
266
|
-
|
|
267
|
-
|
|
268
|
-
|
|
269
|
-
|
|
270
|
-
|
|
271
|
-
|
|
272
|
-
|
|
273
|
-
|
|
274
|
-
|
|
275
|
-
|
|
276
|
-
|
|
277
|
-
|
|
278
|
-
|
|
279
|
-
|
|
280
|
-
|
|
281
|
-
|
|
282
|
-
|
|
283
|
-
|
|
284
|
-
|
|
285
|
-
|
|
286
|
-
|
|
287
|
-
|
|
288
|
-
|
|
289
|
-
|
|
290
|
-
|
|
291
|
-
|
|
292
|
-
|
|
293
|
-
|
|
294
|
-
|
|
295
|
-
|
|
296
|
-
|
|
297
|
-
|
|
298
|
-
|
|
299
|
-
|
|
300
|
-
|
|
301
|
-
|
|
302
|
-
|
|
303
|
-
|
|
304
|
-
|
|
305
|
-
|
|
306
|
-
|
|
307
|
-
|
|
308
|
-
|
|
309
|
-
|
|
310
|
-
|
|
311
|
-
|
|
312
|
-
|
|
313
|
-
|
|
314
|
-
|
|
315
|
-
|
|
316
|
-
|
|
317
|
-
|
|
318
|
-
|
|
319
|
-
|
|
320
|
-
|
|
321
|
-
|
|
322
|
-
|
|
323
|
-
|
|
324
|
-
|
|
325
|
-
|
|
326
|
-
|
|
327
|
-
|
|
328
|
-
|
|
329
|
-
|
|
330
|
-
|
|
331
|
-
|
|
332
|
-
|
|
333
|
-
|
|
334
|
-
|
|
335
|
-
|
|
336
|
-
|
|
337
|
-
|
|
338
|
-
|
|
339
|
-
|
|
340
|
-
|
|
341
|
-
|
|
342
|
-
|
|
343
|
-
|
|
344
|
-
|
|
345
|
-
|
|
346
|
-
|
|
347
|
-
|
|
348
|
-
|
|
349
|
-
|
|
350
|
-
|
|
351
|
-
|
|
352
|
-
|
|
353
|
-
|
|
354
|
-
|
|
355
|
-
|
|
356
|
-
|
|
357
|
-
|
|
358
|
-
|
|
359
|
-
|
|
360
|
-
|
|
361
|
-
|
|
362
|
-
|
|
363
|
-
|
|
364
|
-
|
|
365
|
-
|
|
366
|
-
|
|
367
|
-
|
|
368
|
-
|
|
369
|
-
|
|
370
|
-
|
|
371
|
-
|
|
372
|
-
|
|
373
|
-
|
|
374
|
-
|
|
375
|
-
|
|
376
|
-
|
|
377
|
-
|
|
378
|
-
|
|
379
|
-
|
|
380
|
-
|
|
381
|
-
|
|
382
|
-
|
|
383
|
-
|
|
384
|
-
|
|
385
|
-
|
|
386
|
-
|
|
387
|
-
|
|
388
|
-
|
|
389
|
-
|
|
390
|
-
|
|
391
|
-
|
|
392
|
-
|
|
393
|
-
|
|
394
|
-
|
|
395
|
-
|
|
396
|
-
|
|
397
|
-
|
|
398
|
-
|
|
399
|
-
|
|
400
|
-
|
|
401
|
-
|
|
402
|
-
|
|
403
|
-
|
|
404
|
-
|
|
405
|
-
|
|
406
|
-
|
|
407
|
-
|
|
408
|
-
|
|
409
|
-
|
|
410
|
-
|
|
411
|
-
|
|
412
|
-
|
|
413
|
-
|
|
414
|
-
|
|
415
|
-
|
|
416
|
-
|
|
417
|
-
|
|
418
|
-
|
|
419
|
-
|
|
420
|
-
|
|
421
|
-
|
|
422
|
-
|
|
423
|
-
|
|
424
|
-
|
|
425
|
-
|
|
426
|
-
|
|
427
|
-
|
|
428
|
-
|
|
429
|
-
|
|
430
|
-
|
|
431
|
-
|
|
432
|
-
|
|
433
|
-
|
|
434
|
-
|
|
435
|
-
|
|
436
|
-
|
|
437
|
-
|
|
438
|
-
|
|
439
|
-
|
|
440
|
-
|
|
441
|
-
|
|
442
|
-
|
|
443
|
-
|
|
444
|
-
|
|
445
|
-
|
|
446
|
-
|
|
447
|
-
|
|
448
|
-
|
|
449
|
-
|
|
450
|
-
|
|
451
|
-
this._showPrevStack();
|
|
452
|
-
} );
|
|
453
|
-
|
|
454
|
-
return view;
|
|
455
|
-
}
|
|
456
|
-
|
|
457
|
-
/**
|
|
458
|
-
* @private
|
|
459
|
-
* @returns {module:ui/view~View}
|
|
460
|
-
*/
|
|
461
|
-
_createFakePanelsView() {
|
|
462
|
-
const view = new FakePanelsView( this.editor.locale, this.view );
|
|
463
|
-
|
|
464
|
-
view.bind( 'numberOfPanels' ).to( this, '_numberOfStacks', this, '_singleViewMode', ( number, isSingleViewMode ) => {
|
|
465
|
-
const showPanels = !isSingleViewMode && number >= 2;
|
|
466
|
-
|
|
467
|
-
return showPanels ? Math.min( number - 1, 2 ) : 0;
|
|
468
|
-
} );
|
|
469
|
-
|
|
470
|
-
view.listenTo( this.view, 'change:top', () => view.updatePosition() );
|
|
471
|
-
view.listenTo( this.view, 'change:left', () => view.updatePosition() );
|
|
472
|
-
|
|
473
|
-
this.editor.ui.view.body.add( view );
|
|
474
|
-
|
|
475
|
-
return view;
|
|
476
|
-
}
|
|
477
|
-
|
|
478
|
-
/**
|
|
479
|
-
* Sets the view as the content of the balloon and attaches the balloon using position
|
|
480
|
-
* options of the first view.
|
|
481
|
-
*
|
|
482
|
-
* @private
|
|
483
|
-
* @param {Object} data Configuration.
|
|
484
|
-
* @param {module:ui/view~View} [data.view] The view to show in the balloon.
|
|
485
|
-
* @param {String} [data.balloonClassName=''] Additional class name which will be added to the {@link #view balloon}.
|
|
486
|
-
* @param {Boolean} [data.withArrow=true] Whether the {@link #view balloon} should be rendered with an arrow.
|
|
487
|
-
*/
|
|
488
|
-
_showView( { view, balloonClassName = '', withArrow = true, singleViewMode = false } ) {
|
|
489
|
-
this.view.class = balloonClassName;
|
|
490
|
-
this.view.withArrow = withArrow;
|
|
491
|
-
|
|
492
|
-
this._rotatorView.showView( view );
|
|
493
|
-
this.visibleView = view;
|
|
494
|
-
this.view.pin( this._getBalloonPosition() );
|
|
495
|
-
this._fakePanelsView.updatePosition();
|
|
496
|
-
|
|
497
|
-
if ( singleViewMode ) {
|
|
498
|
-
this._singleViewMode = true;
|
|
499
|
-
}
|
|
500
|
-
}
|
|
501
|
-
|
|
502
|
-
/**
|
|
503
|
-
* Returns position options of the last view in the stack.
|
|
504
|
-
* This keeps the balloon in the same position when the view is changed.
|
|
505
|
-
*
|
|
506
|
-
* @private
|
|
507
|
-
* @returns {module:utils/dom/position~Options}
|
|
508
|
-
*/
|
|
509
|
-
_getBalloonPosition() {
|
|
510
|
-
let position = Array.from( this._visibleStack.values() ).pop().position;
|
|
511
|
-
|
|
512
|
-
if ( position ) {
|
|
513
|
-
// Use the default limiter if none has been specified.
|
|
514
|
-
if ( !position.limiter ) {
|
|
515
|
-
// Don't modify the original options object.
|
|
516
|
-
position = Object.assign( {}, position, {
|
|
517
|
-
limiter: this.positionLimiter
|
|
518
|
-
} );
|
|
519
|
-
}
|
|
520
|
-
|
|
521
|
-
// Don't modify the original options object.
|
|
522
|
-
position = Object.assign( {}, position, {
|
|
523
|
-
viewportOffsetConfig: this.editor.ui.viewportOffset
|
|
524
|
-
} );
|
|
525
|
-
}
|
|
526
|
-
|
|
527
|
-
return position;
|
|
528
|
-
}
|
|
58
|
+
/**
|
|
59
|
+
* @inheritDoc
|
|
60
|
+
*/
|
|
61
|
+
constructor(editor) {
|
|
62
|
+
super(editor);
|
|
63
|
+
/**
|
|
64
|
+
* The {@link module:utils/dom/position~Options#limiter position limiter}
|
|
65
|
+
* for the {@link #view balloon}, used when no `limiter` has been passed into {@link #add}
|
|
66
|
+
* or {@link #updatePosition}.
|
|
67
|
+
*
|
|
68
|
+
* By default, a function that obtains the farthest DOM
|
|
69
|
+
* {@link module:engine/view/rooteditableelement~RootEditableElement}
|
|
70
|
+
* of the {@link module:engine/view/document~Document#selection}.
|
|
71
|
+
*
|
|
72
|
+
* @member {module:utils/dom/position~Options#limiter} #positionLimiter
|
|
73
|
+
*/
|
|
74
|
+
this.positionLimiter = () => {
|
|
75
|
+
const view = this.editor.editing.view;
|
|
76
|
+
const viewDocument = view.document;
|
|
77
|
+
const editableElement = viewDocument.selection.editableElement;
|
|
78
|
+
if (editableElement) {
|
|
79
|
+
return view.domConverter.mapViewToDom(editableElement.root);
|
|
80
|
+
}
|
|
81
|
+
return null;
|
|
82
|
+
};
|
|
83
|
+
/**
|
|
84
|
+
* The currently visible view or `null` when there are no views in any stack.
|
|
85
|
+
*
|
|
86
|
+
* @readonly
|
|
87
|
+
* @observable
|
|
88
|
+
* @member {module:ui/view~View|null} #visibleView
|
|
89
|
+
*/
|
|
90
|
+
this.set('visibleView', null);
|
|
91
|
+
/**
|
|
92
|
+
* The common balloon panel view.
|
|
93
|
+
*
|
|
94
|
+
* @readonly
|
|
95
|
+
* @member {module:ui/panel/balloon/balloonpanelview~BalloonPanelView} #view
|
|
96
|
+
*/
|
|
97
|
+
this.view = new BalloonPanelView(editor.locale);
|
|
98
|
+
editor.ui.view.body.add(this.view);
|
|
99
|
+
editor.ui.focusTracker.add(this.view.element);
|
|
100
|
+
/**
|
|
101
|
+
* The map of views and their stacks.
|
|
102
|
+
*
|
|
103
|
+
* @private
|
|
104
|
+
* @type {Map.<module:ui/view~View,Set>}
|
|
105
|
+
*/
|
|
106
|
+
this._viewToStack = new Map();
|
|
107
|
+
/**
|
|
108
|
+
* The map of IDs and stacks.
|
|
109
|
+
*
|
|
110
|
+
* @private
|
|
111
|
+
* @type {Map.<String,Set>}
|
|
112
|
+
*/
|
|
113
|
+
this._idToStack = new Map();
|
|
114
|
+
/**
|
|
115
|
+
* A total number of all stacks in the balloon.
|
|
116
|
+
*
|
|
117
|
+
* @private
|
|
118
|
+
* @readonly
|
|
119
|
+
* @observable
|
|
120
|
+
* @member {Number} #_numberOfStacks
|
|
121
|
+
*/
|
|
122
|
+
this.set('_numberOfStacks', 0);
|
|
123
|
+
/**
|
|
124
|
+
* A flag that controls the single view mode.
|
|
125
|
+
*
|
|
126
|
+
* @private
|
|
127
|
+
* @readonly
|
|
128
|
+
* @observable
|
|
129
|
+
* @member {Boolean} #_singleViewMode
|
|
130
|
+
*/
|
|
131
|
+
this.set('_singleViewMode', false);
|
|
132
|
+
/**
|
|
133
|
+
* Rotator view embedded in the contextual balloon.
|
|
134
|
+
* Displays the currently visible view in the balloon and provides navigation for switching stacks.
|
|
135
|
+
*
|
|
136
|
+
* @private
|
|
137
|
+
* @type {module:ui/panel/balloon/contextualballoon~RotatorView}
|
|
138
|
+
*/
|
|
139
|
+
this._rotatorView = this._createRotatorView();
|
|
140
|
+
/**
|
|
141
|
+
* Displays fake panels under the balloon panel view when multiple stacks are added to the balloon.
|
|
142
|
+
*
|
|
143
|
+
* @private
|
|
144
|
+
* @type {module:ui/view~View}
|
|
145
|
+
*/
|
|
146
|
+
this._fakePanelsView = this._createFakePanelsView();
|
|
147
|
+
}
|
|
148
|
+
/**
|
|
149
|
+
* @inheritDoc
|
|
150
|
+
*/
|
|
151
|
+
static get pluginName() {
|
|
152
|
+
return 'ContextualBalloon';
|
|
153
|
+
}
|
|
154
|
+
/**
|
|
155
|
+
* @inheritDoc
|
|
156
|
+
*/
|
|
157
|
+
destroy() {
|
|
158
|
+
super.destroy();
|
|
159
|
+
this.view.destroy();
|
|
160
|
+
this._rotatorView.destroy();
|
|
161
|
+
this._fakePanelsView.destroy();
|
|
162
|
+
}
|
|
163
|
+
/**
|
|
164
|
+
* Returns `true` when the given view is in one of the stacks. Otherwise returns `false`.
|
|
165
|
+
*
|
|
166
|
+
* @param {module:ui/view~View} view
|
|
167
|
+
* @returns {Boolean}
|
|
168
|
+
*/
|
|
169
|
+
hasView(view) {
|
|
170
|
+
return Array.from(this._viewToStack.keys()).includes(view);
|
|
171
|
+
}
|
|
172
|
+
/**
|
|
173
|
+
* Adds a new view to the stack and makes it visible if the current stack is visible
|
|
174
|
+
* or it is the first view in the balloon.
|
|
175
|
+
*
|
|
176
|
+
* @param {Object} data The configuration of the view.
|
|
177
|
+
* @param {String} [data.stackId='main'] The ID of the stack that the view is added to.
|
|
178
|
+
* @param {module:ui/view~View} [data.view] The content of the balloon.
|
|
179
|
+
* @param {module:utils/dom/position~Options} [data.position] Positioning options.
|
|
180
|
+
* @param {String} [data.balloonClassName] An additional CSS class added to the {@link #view balloon} when visible.
|
|
181
|
+
* @param {Boolean} [data.withArrow=true] Whether the {@link #view balloon} should be rendered with an arrow.
|
|
182
|
+
* @param {Boolean} [data.singleViewMode=false] Whether the view should be the only visible view even if other stacks were added.
|
|
183
|
+
*/
|
|
184
|
+
add(data) {
|
|
185
|
+
if (this.hasView(data.view)) {
|
|
186
|
+
/**
|
|
187
|
+
* Trying to add configuration of the same view more than once.
|
|
188
|
+
*
|
|
189
|
+
* @error contextualballoon-add-view-exist
|
|
190
|
+
*/
|
|
191
|
+
throw new CKEditorError('contextualballoon-add-view-exist', [this, data]);
|
|
192
|
+
}
|
|
193
|
+
const stackId = data.stackId || 'main';
|
|
194
|
+
// If new stack is added, creates it and show view from this stack.
|
|
195
|
+
if (!this._idToStack.has(stackId)) {
|
|
196
|
+
this._idToStack.set(stackId, new Map([[data.view, data]]));
|
|
197
|
+
this._viewToStack.set(data.view, this._idToStack.get(stackId));
|
|
198
|
+
this._numberOfStacks = this._idToStack.size;
|
|
199
|
+
if (!this._visibleStack || data.singleViewMode) {
|
|
200
|
+
this.showStack(stackId);
|
|
201
|
+
}
|
|
202
|
+
return;
|
|
203
|
+
}
|
|
204
|
+
const stack = this._idToStack.get(stackId);
|
|
205
|
+
if (data.singleViewMode) {
|
|
206
|
+
this.showStack(stackId);
|
|
207
|
+
}
|
|
208
|
+
// Add new view to the stack.
|
|
209
|
+
stack.set(data.view, data);
|
|
210
|
+
this._viewToStack.set(data.view, stack);
|
|
211
|
+
// And display it if is added to the currently visible stack.
|
|
212
|
+
if (stack === this._visibleStack) {
|
|
213
|
+
this._showView(data);
|
|
214
|
+
}
|
|
215
|
+
}
|
|
216
|
+
/**
|
|
217
|
+
* Removes the given view from the stack. If the removed view was visible,
|
|
218
|
+
* the view preceding it in the stack will become visible instead.
|
|
219
|
+
* When there is no view in the stack, the next stack will be displayed.
|
|
220
|
+
* When there are no more stacks, the balloon will hide.
|
|
221
|
+
*
|
|
222
|
+
* @param {module:ui/view~View} view A view to be removed from the balloon.
|
|
223
|
+
*/
|
|
224
|
+
remove(view) {
|
|
225
|
+
if (!this.hasView(view)) {
|
|
226
|
+
/**
|
|
227
|
+
* Trying to remove the configuration of the view not defined in the stack.
|
|
228
|
+
*
|
|
229
|
+
* @error contextualballoon-remove-view-not-exist
|
|
230
|
+
*/
|
|
231
|
+
throw new CKEditorError('contextualballoon-remove-view-not-exist', [this, view]);
|
|
232
|
+
}
|
|
233
|
+
const stack = this._viewToStack.get(view);
|
|
234
|
+
if (this._singleViewMode && this.visibleView === view) {
|
|
235
|
+
this._singleViewMode = false;
|
|
236
|
+
}
|
|
237
|
+
// When visible view will be removed we need to show a preceding view or next stack
|
|
238
|
+
// if a view is the only view in the stack.
|
|
239
|
+
if (this.visibleView === view) {
|
|
240
|
+
if (stack.size === 1) {
|
|
241
|
+
if (this._idToStack.size > 1) {
|
|
242
|
+
this._showNextStack();
|
|
243
|
+
}
|
|
244
|
+
else {
|
|
245
|
+
this.view.hide();
|
|
246
|
+
this.visibleView = null;
|
|
247
|
+
this._rotatorView.hideView();
|
|
248
|
+
}
|
|
249
|
+
}
|
|
250
|
+
else {
|
|
251
|
+
this._showView(Array.from(stack.values())[stack.size - 2]);
|
|
252
|
+
}
|
|
253
|
+
}
|
|
254
|
+
if (stack.size === 1) {
|
|
255
|
+
this._idToStack.delete(this._getStackId(stack));
|
|
256
|
+
this._numberOfStacks = this._idToStack.size;
|
|
257
|
+
}
|
|
258
|
+
else {
|
|
259
|
+
stack.delete(view);
|
|
260
|
+
}
|
|
261
|
+
this._viewToStack.delete(view);
|
|
262
|
+
}
|
|
263
|
+
/**
|
|
264
|
+
* Updates the position of the balloon using the position data of the first visible view in the stack.
|
|
265
|
+
* When new position data is given, the position data of the currently visible view will be updated.
|
|
266
|
+
*
|
|
267
|
+
* @param {module:utils/dom/position~Options} [position] position options.
|
|
268
|
+
*/
|
|
269
|
+
updatePosition(position) {
|
|
270
|
+
if (position) {
|
|
271
|
+
this._visibleStack.get(this.visibleView).position = position;
|
|
272
|
+
}
|
|
273
|
+
this.view.pin(this._getBalloonPosition());
|
|
274
|
+
this._fakePanelsView.updatePosition();
|
|
275
|
+
}
|
|
276
|
+
/**
|
|
277
|
+
* Shows the last view from the stack of a given ID.
|
|
278
|
+
*
|
|
279
|
+
* @param {String} id
|
|
280
|
+
*/
|
|
281
|
+
showStack(id) {
|
|
282
|
+
this.visibleStack = id;
|
|
283
|
+
const stack = this._idToStack.get(id);
|
|
284
|
+
if (!stack) {
|
|
285
|
+
/**
|
|
286
|
+
* Trying to show a stack that does not exist.
|
|
287
|
+
*
|
|
288
|
+
* @error contextualballoon-showstack-stack-not-exist
|
|
289
|
+
*/
|
|
290
|
+
throw new CKEditorError('contextualballoon-showstack-stack-not-exist', this);
|
|
291
|
+
}
|
|
292
|
+
if (this._visibleStack === stack) {
|
|
293
|
+
return;
|
|
294
|
+
}
|
|
295
|
+
this._showView(Array.from(stack.values()).pop());
|
|
296
|
+
}
|
|
297
|
+
/**
|
|
298
|
+
* Returns the stack of the currently visible view.
|
|
299
|
+
*
|
|
300
|
+
* @private
|
|
301
|
+
* @type {Set}
|
|
302
|
+
*/
|
|
303
|
+
get _visibleStack() {
|
|
304
|
+
return this._viewToStack.get(this.visibleView);
|
|
305
|
+
}
|
|
306
|
+
/**
|
|
307
|
+
* Returns the ID of the given stack.
|
|
308
|
+
*
|
|
309
|
+
* @private
|
|
310
|
+
* @param {Set} stack
|
|
311
|
+
* @returns {String}
|
|
312
|
+
*/
|
|
313
|
+
_getStackId(stack) {
|
|
314
|
+
const entry = Array.from(this._idToStack.entries()).find(entry => entry[1] === stack);
|
|
315
|
+
return entry[0];
|
|
316
|
+
}
|
|
317
|
+
/**
|
|
318
|
+
* Shows the last view from the next stack.
|
|
319
|
+
*
|
|
320
|
+
* @private
|
|
321
|
+
*/
|
|
322
|
+
_showNextStack() {
|
|
323
|
+
const stacks = Array.from(this._idToStack.values());
|
|
324
|
+
let nextIndex = stacks.indexOf(this._visibleStack) + 1;
|
|
325
|
+
if (!stacks[nextIndex]) {
|
|
326
|
+
nextIndex = 0;
|
|
327
|
+
}
|
|
328
|
+
this.showStack(this._getStackId(stacks[nextIndex]));
|
|
329
|
+
}
|
|
330
|
+
/**
|
|
331
|
+
* Shows the last view from the previous stack.
|
|
332
|
+
*
|
|
333
|
+
* @private
|
|
334
|
+
*/
|
|
335
|
+
_showPrevStack() {
|
|
336
|
+
const stacks = Array.from(this._idToStack.values());
|
|
337
|
+
let nextIndex = stacks.indexOf(this._visibleStack) - 1;
|
|
338
|
+
if (!stacks[nextIndex]) {
|
|
339
|
+
nextIndex = stacks.length - 1;
|
|
340
|
+
}
|
|
341
|
+
this.showStack(this._getStackId(stacks[nextIndex]));
|
|
342
|
+
}
|
|
343
|
+
/**
|
|
344
|
+
* Creates a rotator view.
|
|
345
|
+
*
|
|
346
|
+
* @private
|
|
347
|
+
* @returns {module:ui/panel/balloon/contextualballoon~RotatorView}
|
|
348
|
+
*/
|
|
349
|
+
_createRotatorView() {
|
|
350
|
+
const view = new RotatorView(this.editor.locale);
|
|
351
|
+
const t = this.editor.locale.t;
|
|
352
|
+
this.view.content.add(view);
|
|
353
|
+
// Hide navigation when there is only a one stack & not in single view mode.
|
|
354
|
+
view.bind('isNavigationVisible').to(this, '_numberOfStacks', this, '_singleViewMode', (value, isSingleViewMode) => {
|
|
355
|
+
return !isSingleViewMode && value > 1;
|
|
356
|
+
});
|
|
357
|
+
// Update balloon position after toggling navigation.
|
|
358
|
+
view.on('change:isNavigationVisible', () => (this.updatePosition()), { priority: 'low' });
|
|
359
|
+
// Update stacks counter value.
|
|
360
|
+
view.bind('counter').to(this, 'visibleView', this, '_numberOfStacks', (visibleView, numberOfStacks) => {
|
|
361
|
+
if (numberOfStacks < 2) {
|
|
362
|
+
return '';
|
|
363
|
+
}
|
|
364
|
+
const current = Array.from(this._idToStack.values()).indexOf(this._visibleStack) + 1;
|
|
365
|
+
return t('%0 of %1', [current, numberOfStacks]);
|
|
366
|
+
});
|
|
367
|
+
view.buttonNextView.on('execute', () => {
|
|
368
|
+
// When current view has a focus then move focus to the editable before removing it,
|
|
369
|
+
// otherwise editor will lost focus.
|
|
370
|
+
if (view.focusTracker.isFocused) {
|
|
371
|
+
this.editor.editing.view.focus();
|
|
372
|
+
}
|
|
373
|
+
this._showNextStack();
|
|
374
|
+
});
|
|
375
|
+
view.buttonPrevView.on('execute', () => {
|
|
376
|
+
// When current view has a focus then move focus to the editable before removing it,
|
|
377
|
+
// otherwise editor will lost focus.
|
|
378
|
+
if (view.focusTracker.isFocused) {
|
|
379
|
+
this.editor.editing.view.focus();
|
|
380
|
+
}
|
|
381
|
+
this._showPrevStack();
|
|
382
|
+
});
|
|
383
|
+
return view;
|
|
384
|
+
}
|
|
385
|
+
/**
|
|
386
|
+
* @private
|
|
387
|
+
* @returns {module:ui/view~View}
|
|
388
|
+
*/
|
|
389
|
+
_createFakePanelsView() {
|
|
390
|
+
const view = new FakePanelsView(this.editor.locale, this.view);
|
|
391
|
+
view.bind('numberOfPanels').to(this, '_numberOfStacks', this, '_singleViewMode', (number, isSingleViewMode) => {
|
|
392
|
+
const showPanels = !isSingleViewMode && number >= 2;
|
|
393
|
+
return showPanels ? Math.min(number - 1, 2) : 0;
|
|
394
|
+
});
|
|
395
|
+
view.listenTo(this.view, 'change:top', () => view.updatePosition());
|
|
396
|
+
view.listenTo(this.view, 'change:left', () => view.updatePosition());
|
|
397
|
+
this.editor.ui.view.body.add(view);
|
|
398
|
+
return view;
|
|
399
|
+
}
|
|
400
|
+
/**
|
|
401
|
+
* Sets the view as the content of the balloon and attaches the balloon using position
|
|
402
|
+
* options of the first view.
|
|
403
|
+
*
|
|
404
|
+
* @private
|
|
405
|
+
* @param {Object} data Configuration.
|
|
406
|
+
* @param {module:ui/view~View} [data.view] The view to show in the balloon.
|
|
407
|
+
* @param {String} [data.balloonClassName=''] Additional class name which will be added to the {@link #view balloon}.
|
|
408
|
+
* @param {Boolean} [data.withArrow=true] Whether the {@link #view balloon} should be rendered with an arrow.
|
|
409
|
+
*/
|
|
410
|
+
_showView({ view, balloonClassName = '', withArrow = true, singleViewMode = false }) {
|
|
411
|
+
this.view.class = balloonClassName;
|
|
412
|
+
this.view.withArrow = withArrow;
|
|
413
|
+
this._rotatorView.showView(view);
|
|
414
|
+
this.visibleView = view;
|
|
415
|
+
this.view.pin(this._getBalloonPosition());
|
|
416
|
+
this._fakePanelsView.updatePosition();
|
|
417
|
+
if (singleViewMode) {
|
|
418
|
+
this._singleViewMode = true;
|
|
419
|
+
}
|
|
420
|
+
}
|
|
421
|
+
/**
|
|
422
|
+
* Returns position options of the last view in the stack.
|
|
423
|
+
* This keeps the balloon in the same position when the view is changed.
|
|
424
|
+
*
|
|
425
|
+
* @private
|
|
426
|
+
* @returns {module:utils/dom/position~Options}
|
|
427
|
+
*/
|
|
428
|
+
_getBalloonPosition() {
|
|
429
|
+
let position = Array.from(this._visibleStack.values()).pop().position;
|
|
430
|
+
if (position) {
|
|
431
|
+
// Use the default limiter if none has been specified.
|
|
432
|
+
if (!position.limiter) {
|
|
433
|
+
// Don't modify the original options object.
|
|
434
|
+
position = Object.assign({}, position, {
|
|
435
|
+
limiter: this.positionLimiter
|
|
436
|
+
});
|
|
437
|
+
}
|
|
438
|
+
// Don't modify the original options object.
|
|
439
|
+
position = Object.assign({}, position, {
|
|
440
|
+
viewportOffsetConfig: this.editor.ui.viewportOffset
|
|
441
|
+
});
|
|
442
|
+
}
|
|
443
|
+
return position;
|
|
444
|
+
}
|
|
529
445
|
}
|
|
530
|
-
|
|
531
446
|
/**
|
|
532
447
|
* Rotator view is a helper class for the {@link module:ui/panel/balloon/contextualballoon~ContextualBalloon ContextualBalloon}.
|
|
533
448
|
* It is used for displaying the last view from the current stack and providing navigation buttons for switching stacks.
|
|
@@ -536,269 +451,233 @@ export default class ContextualBalloon extends Plugin {
|
|
|
536
451
|
* @extends module:ui/view~View
|
|
537
452
|
*/
|
|
538
453
|
class RotatorView extends View {
|
|
539
|
-
|
|
540
|
-
|
|
541
|
-
|
|
542
|
-
|
|
543
|
-
|
|
544
|
-
|
|
545
|
-
|
|
546
|
-
|
|
547
|
-
|
|
548
|
-
|
|
549
|
-
|
|
550
|
-
|
|
551
|
-
|
|
552
|
-
|
|
553
|
-
|
|
554
|
-
|
|
555
|
-
|
|
556
|
-
|
|
557
|
-
|
|
558
|
-
|
|
559
|
-
|
|
560
|
-
|
|
561
|
-
|
|
562
|
-
|
|
563
|
-
|
|
564
|
-
|
|
565
|
-
|
|
566
|
-
|
|
567
|
-
|
|
568
|
-
|
|
569
|
-
|
|
570
|
-
|
|
571
|
-
|
|
572
|
-
|
|
573
|
-
|
|
574
|
-
|
|
575
|
-
|
|
576
|
-
|
|
577
|
-
|
|
578
|
-
|
|
579
|
-
|
|
580
|
-
|
|
581
|
-
|
|
582
|
-
|
|
583
|
-
|
|
584
|
-
|
|
585
|
-
|
|
586
|
-
|
|
587
|
-
|
|
588
|
-
|
|
589
|
-
|
|
590
|
-
|
|
591
|
-
|
|
592
|
-
|
|
593
|
-
|
|
594
|
-
|
|
595
|
-
|
|
596
|
-
|
|
597
|
-
|
|
598
|
-
|
|
599
|
-
|
|
600
|
-
|
|
601
|
-
|
|
602
|
-
|
|
603
|
-
|
|
604
|
-
|
|
605
|
-
|
|
606
|
-
|
|
607
|
-
|
|
608
|
-
|
|
609
|
-
|
|
610
|
-
|
|
611
|
-
|
|
612
|
-
|
|
613
|
-
|
|
614
|
-
|
|
615
|
-
|
|
616
|
-
|
|
617
|
-
|
|
618
|
-
|
|
619
|
-
|
|
620
|
-
|
|
621
|
-
|
|
622
|
-
|
|
623
|
-
|
|
624
|
-
|
|
625
|
-
|
|
626
|
-
|
|
627
|
-
|
|
628
|
-
|
|
629
|
-
|
|
630
|
-
|
|
631
|
-
|
|
632
|
-
|
|
633
|
-
|
|
634
|
-
|
|
635
|
-
|
|
636
|
-
|
|
637
|
-
|
|
638
|
-
|
|
639
|
-
|
|
640
|
-
|
|
641
|
-
|
|
642
|
-
|
|
643
|
-
|
|
644
|
-
|
|
645
|
-
|
|
646
|
-
|
|
647
|
-
|
|
648
|
-
|
|
649
|
-
|
|
650
|
-
|
|
651
|
-
|
|
652
|
-
|
|
653
|
-
|
|
654
|
-
|
|
655
|
-
|
|
656
|
-
|
|
657
|
-
|
|
658
|
-
|
|
659
|
-
|
|
660
|
-
|
|
661
|
-
|
|
662
|
-
|
|
663
|
-
|
|
664
|
-
|
|
665
|
-
|
|
666
|
-
|
|
667
|
-
|
|
668
|
-
|
|
669
|
-
* Creates a navigation button view.
|
|
670
|
-
*
|
|
671
|
-
* @private
|
|
672
|
-
* @param {String} label The button label.
|
|
673
|
-
* @param {String} icon The button icon.
|
|
674
|
-
* @returns {module:ui/button/buttonview~ButtonView}
|
|
675
|
-
*/
|
|
676
|
-
_createButtonView( label, icon ) {
|
|
677
|
-
const view = new ButtonView( this.locale );
|
|
678
|
-
|
|
679
|
-
view.set( {
|
|
680
|
-
label,
|
|
681
|
-
icon,
|
|
682
|
-
tooltip: true
|
|
683
|
-
} );
|
|
684
|
-
|
|
685
|
-
return view;
|
|
686
|
-
}
|
|
454
|
+
/**
|
|
455
|
+
* @inheritDoc
|
|
456
|
+
*/
|
|
457
|
+
constructor(locale) {
|
|
458
|
+
super(locale);
|
|
459
|
+
const t = locale.t;
|
|
460
|
+
const bind = this.bindTemplate;
|
|
461
|
+
/**
|
|
462
|
+
* Defines whether navigation is visible or not.
|
|
463
|
+
*
|
|
464
|
+
* @member {Boolean} #isNavigationVisible
|
|
465
|
+
*/
|
|
466
|
+
this.set('isNavigationVisible', true);
|
|
467
|
+
/**
|
|
468
|
+
* Used for checking if a view is focused or not.
|
|
469
|
+
*
|
|
470
|
+
* @type {module:utils/focustracker~FocusTracker}
|
|
471
|
+
*/
|
|
472
|
+
this.focusTracker = new FocusTracker();
|
|
473
|
+
/**
|
|
474
|
+
* Navigation button for switching the stack to the previous one.
|
|
475
|
+
*
|
|
476
|
+
* @type {module:ui/button/buttonview~ButtonView}
|
|
477
|
+
*/
|
|
478
|
+
this.buttonPrevView = this._createButtonView(t('Previous'), prevIcon);
|
|
479
|
+
/**
|
|
480
|
+
* Navigation button for switching the stack to the next one.
|
|
481
|
+
*
|
|
482
|
+
* @type {module:ui/button/buttonview~ButtonView}
|
|
483
|
+
*/
|
|
484
|
+
this.buttonNextView = this._createButtonView(t('Next'), nextIcon);
|
|
485
|
+
/**
|
|
486
|
+
* A collection of the child views that creates the rotator content.
|
|
487
|
+
*
|
|
488
|
+
* @readonly
|
|
489
|
+
* @type {module:ui/viewcollection~ViewCollection}
|
|
490
|
+
*/
|
|
491
|
+
this.content = this.createCollection();
|
|
492
|
+
this.setTemplate({
|
|
493
|
+
tag: 'div',
|
|
494
|
+
attributes: {
|
|
495
|
+
class: [
|
|
496
|
+
'ck',
|
|
497
|
+
'ck-balloon-rotator'
|
|
498
|
+
],
|
|
499
|
+
'z-index': '-1'
|
|
500
|
+
},
|
|
501
|
+
children: [
|
|
502
|
+
{
|
|
503
|
+
tag: 'div',
|
|
504
|
+
attributes: {
|
|
505
|
+
class: [
|
|
506
|
+
'ck-balloon-rotator__navigation',
|
|
507
|
+
bind.to('isNavigationVisible', value => value ? '' : 'ck-hidden')
|
|
508
|
+
]
|
|
509
|
+
},
|
|
510
|
+
children: [
|
|
511
|
+
this.buttonPrevView,
|
|
512
|
+
{
|
|
513
|
+
tag: 'span',
|
|
514
|
+
attributes: {
|
|
515
|
+
class: [
|
|
516
|
+
'ck-balloon-rotator__counter'
|
|
517
|
+
]
|
|
518
|
+
},
|
|
519
|
+
children: [
|
|
520
|
+
{
|
|
521
|
+
text: bind.to('counter')
|
|
522
|
+
}
|
|
523
|
+
]
|
|
524
|
+
},
|
|
525
|
+
this.buttonNextView
|
|
526
|
+
]
|
|
527
|
+
},
|
|
528
|
+
{
|
|
529
|
+
tag: 'div',
|
|
530
|
+
attributes: {
|
|
531
|
+
class: 'ck-balloon-rotator__content'
|
|
532
|
+
},
|
|
533
|
+
children: this.content
|
|
534
|
+
}
|
|
535
|
+
]
|
|
536
|
+
});
|
|
537
|
+
}
|
|
538
|
+
/**
|
|
539
|
+
* @inheritDoc
|
|
540
|
+
*/
|
|
541
|
+
render() {
|
|
542
|
+
super.render();
|
|
543
|
+
this.focusTracker.add(this.element);
|
|
544
|
+
}
|
|
545
|
+
/**
|
|
546
|
+
* @inheritDoc
|
|
547
|
+
*/
|
|
548
|
+
destroy() {
|
|
549
|
+
super.destroy();
|
|
550
|
+
this.focusTracker.destroy();
|
|
551
|
+
}
|
|
552
|
+
/**
|
|
553
|
+
* Shows a given view.
|
|
554
|
+
*
|
|
555
|
+
* @param {module:ui/view~View} view The view to show.
|
|
556
|
+
*/
|
|
557
|
+
showView(view) {
|
|
558
|
+
this.hideView();
|
|
559
|
+
this.content.add(view);
|
|
560
|
+
}
|
|
561
|
+
/**
|
|
562
|
+
* Hides the currently displayed view.
|
|
563
|
+
*/
|
|
564
|
+
hideView() {
|
|
565
|
+
this.content.clear();
|
|
566
|
+
}
|
|
567
|
+
/**
|
|
568
|
+
* Creates a navigation button view.
|
|
569
|
+
*
|
|
570
|
+
* @private
|
|
571
|
+
* @param {String} label The button label.
|
|
572
|
+
* @param {String} icon The button icon.
|
|
573
|
+
* @returns {module:ui/button/buttonview~ButtonView}
|
|
574
|
+
*/
|
|
575
|
+
_createButtonView(label, icon) {
|
|
576
|
+
const view = new ButtonView(this.locale);
|
|
577
|
+
view.set({
|
|
578
|
+
label,
|
|
579
|
+
icon,
|
|
580
|
+
tooltip: true
|
|
581
|
+
});
|
|
582
|
+
return view;
|
|
583
|
+
}
|
|
687
584
|
}
|
|
688
|
-
|
|
689
585
|
// Displays additional layers under the balloon when multiple stacks are added to the balloon.
|
|
690
586
|
//
|
|
691
587
|
// @private
|
|
692
588
|
// @extends module:ui/view~View
|
|
693
589
|
class FakePanelsView extends View {
|
|
694
|
-
|
|
695
|
-
|
|
696
|
-
|
|
697
|
-
|
|
698
|
-
|
|
699
|
-
|
|
700
|
-
|
|
701
|
-
|
|
702
|
-
|
|
703
|
-
|
|
704
|
-
|
|
705
|
-
|
|
706
|
-
|
|
707
|
-
|
|
708
|
-
|
|
709
|
-
|
|
710
|
-
|
|
711
|
-
|
|
712
|
-
|
|
713
|
-
|
|
714
|
-
|
|
715
|
-
|
|
716
|
-
|
|
717
|
-
|
|
718
|
-
|
|
719
|
-
|
|
720
|
-
|
|
721
|
-
|
|
722
|
-
|
|
723
|
-
|
|
724
|
-
|
|
725
|
-
|
|
726
|
-
|
|
727
|
-
|
|
728
|
-
|
|
729
|
-
|
|
730
|
-
|
|
731
|
-
|
|
732
|
-
|
|
733
|
-
|
|
734
|
-
|
|
735
|
-
|
|
736
|
-
|
|
737
|
-
|
|
738
|
-
|
|
739
|
-
|
|
740
|
-
|
|
741
|
-
|
|
742
|
-
|
|
743
|
-
|
|
744
|
-
|
|
745
|
-
|
|
746
|
-
|
|
747
|
-
|
|
748
|
-
|
|
749
|
-
|
|
750
|
-
|
|
751
|
-
|
|
752
|
-
|
|
753
|
-
|
|
754
|
-
|
|
755
|
-
|
|
756
|
-
|
|
757
|
-
|
|
758
|
-
|
|
759
|
-
|
|
760
|
-
|
|
761
|
-
|
|
762
|
-
|
|
763
|
-
|
|
764
|
-
|
|
765
|
-
|
|
766
|
-
|
|
767
|
-
|
|
768
|
-
|
|
769
|
-
|
|
770
|
-
|
|
771
|
-
|
|
772
|
-
|
|
773
|
-
|
|
774
|
-
|
|
775
|
-
|
|
776
|
-
|
|
777
|
-
|
|
778
|
-
|
|
779
|
-
|
|
780
|
-
|
|
781
|
-
|
|
782
|
-
|
|
783
|
-
|
|
784
|
-
|
|
785
|
-
|
|
786
|
-
|
|
787
|
-
const view = this.content.last;
|
|
788
|
-
|
|
789
|
-
this.content.remove( view );
|
|
790
|
-
this.deregisterChild( view );
|
|
791
|
-
view.destroy();
|
|
792
|
-
}
|
|
793
|
-
}
|
|
794
|
-
|
|
795
|
-
// Updates coordinates of fake panels.
|
|
796
|
-
updatePosition() {
|
|
797
|
-
if ( this.numberOfPanels ) {
|
|
798
|
-
const { top, left } = this._balloonPanelView;
|
|
799
|
-
const { width, height } = new Rect( this._balloonPanelView.element );
|
|
800
|
-
|
|
801
|
-
Object.assign( this, { top, left, width, height } );
|
|
802
|
-
}
|
|
803
|
-
}
|
|
590
|
+
// @inheritDoc
|
|
591
|
+
constructor(locale, balloonPanelView) {
|
|
592
|
+
super(locale);
|
|
593
|
+
const bind = this.bindTemplate;
|
|
594
|
+
// Fake panels top offset.
|
|
595
|
+
//
|
|
596
|
+
// @observable
|
|
597
|
+
// @member {Number} #top
|
|
598
|
+
this.set('top', 0);
|
|
599
|
+
// Fake panels left offset.
|
|
600
|
+
//
|
|
601
|
+
// @observable
|
|
602
|
+
// @member {Number} #left
|
|
603
|
+
this.set('left', 0);
|
|
604
|
+
// Fake panels height.
|
|
605
|
+
//
|
|
606
|
+
// @observable
|
|
607
|
+
// @member {Number} #height
|
|
608
|
+
this.set('height', 0);
|
|
609
|
+
// Fake panels width.
|
|
610
|
+
//
|
|
611
|
+
// @observable
|
|
612
|
+
// @member {Number} #width
|
|
613
|
+
this.set('width', 0);
|
|
614
|
+
// Number of rendered fake panels.
|
|
615
|
+
//
|
|
616
|
+
// @observable
|
|
617
|
+
// @member {Number} #numberOfPanels
|
|
618
|
+
this.set('numberOfPanels', 0);
|
|
619
|
+
// Collection of the child views which creates fake panel content.
|
|
620
|
+
//
|
|
621
|
+
// @readonly
|
|
622
|
+
// @type {module:ui/viewcollection~ViewCollection}
|
|
623
|
+
this.content = this.createCollection();
|
|
624
|
+
// Context.
|
|
625
|
+
//
|
|
626
|
+
// @private
|
|
627
|
+
// @type {module:ui/panel/balloon/balloonpanelview~BalloonPanelView}
|
|
628
|
+
this._balloonPanelView = balloonPanelView;
|
|
629
|
+
this.setTemplate({
|
|
630
|
+
tag: 'div',
|
|
631
|
+
attributes: {
|
|
632
|
+
class: [
|
|
633
|
+
'ck-fake-panel',
|
|
634
|
+
bind.to('numberOfPanels', number => number ? '' : 'ck-hidden')
|
|
635
|
+
],
|
|
636
|
+
style: {
|
|
637
|
+
top: bind.to('top', toPx),
|
|
638
|
+
left: bind.to('left', toPx),
|
|
639
|
+
width: bind.to('width', toPx),
|
|
640
|
+
height: bind.to('height', toPx)
|
|
641
|
+
}
|
|
642
|
+
},
|
|
643
|
+
children: this.content
|
|
644
|
+
});
|
|
645
|
+
this.on('change:numberOfPanels', (evt, name, next, prev) => {
|
|
646
|
+
if (next > prev) {
|
|
647
|
+
this._addPanels(next - prev);
|
|
648
|
+
}
|
|
649
|
+
else {
|
|
650
|
+
this._removePanels(prev - next);
|
|
651
|
+
}
|
|
652
|
+
this.updatePosition();
|
|
653
|
+
});
|
|
654
|
+
}
|
|
655
|
+
// @private
|
|
656
|
+
// @param {Number} number
|
|
657
|
+
_addPanels(number) {
|
|
658
|
+
while (number--) {
|
|
659
|
+
const view = new View();
|
|
660
|
+
view.setTemplate({ tag: 'div' });
|
|
661
|
+
this.content.add(view);
|
|
662
|
+
this.registerChild(view);
|
|
663
|
+
}
|
|
664
|
+
}
|
|
665
|
+
// @private
|
|
666
|
+
// @param {Number} number
|
|
667
|
+
_removePanels(number) {
|
|
668
|
+
while (number--) {
|
|
669
|
+
const view = this.content.last;
|
|
670
|
+
this.content.remove(view);
|
|
671
|
+
this.deregisterChild(view);
|
|
672
|
+
view.destroy();
|
|
673
|
+
}
|
|
674
|
+
}
|
|
675
|
+
// Updates coordinates of fake panels.
|
|
676
|
+
updatePosition() {
|
|
677
|
+
if (this.numberOfPanels) {
|
|
678
|
+
const { top, left } = this._balloonPanelView;
|
|
679
|
+
const { width, height } = new Rect(this._balloonPanelView.element);
|
|
680
|
+
Object.assign(this, { top, left, width, height });
|
|
681
|
+
}
|
|
682
|
+
}
|
|
804
683
|
}
|