@syncfusion/ej2-layouts 20.3.47 → 20.3.48

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.
@@ -0,0 +1,2711 @@
1
+ import { Component, Property, setStyleAttribute, ChildProperty, compile } from '@syncfusion/ej2-base';
2
+ import { NotifyPropertyChanges, addClass, Collection, isNullOrUndefined } from '@syncfusion/ej2-base';
3
+ import { Event, EmitType, EventHandler, selectAll, removeClass, select, Browser, detach, formatUnit } from '@syncfusion/ej2-base';
4
+ import { SanitizeHtmlHelper, extend } from '@syncfusion/ej2-base';
5
+ import { SplitterModel, PanePropertiesModel } from './splitter-model';
6
+
7
+ const ROOT: string = 'e-splitter';
8
+ const HORIZONTAL_PANE: string = 'e-splitter-horizontal';
9
+ const VERTICAL_PANE: string = 'e-splitter-vertical';
10
+ const PANE: string = 'e-pane';
11
+ const SPLIT_H_PANE: string = 'e-pane-horizontal';
12
+ const SPLIT_V_PANE: string = 'e-pane-vertical';
13
+ const SPLIT_BAR: string = 'e-split-bar';
14
+ const SPLIT_H_BAR: string = 'e-split-bar-horizontal';
15
+ const SPLIT_V_BAR: string = 'e-split-bar-vertical';
16
+ const STATIC_PANE: string = 'e-static-pane';
17
+ const SCROLL_PANE: string = 'e-scrollable';
18
+ const RESIZE_BAR: string = 'e-resize-handler';
19
+ const RESIZABLE_BAR: string = 'e-resizable-split-bar';
20
+ const SPLIT_BAR_HOVER: string = 'e-split-bar-hover';
21
+ const SPLIT_BAR_ACTIVE: string = 'e-split-bar-active';
22
+ const HIDE_HANDLER: string = 'e-hide-handler';
23
+ const SPLIT_TOUCH: string = 'e-splitter-touch';
24
+ const DISABLED: string = 'e-disabled';
25
+ const RTL: string = 'e-rtl';
26
+ const E_ICONS: string = 'e-icons';
27
+ const COLLAPSIBLE: string = 'e-collapsible';
28
+ const NAVIGATE_ARROW: string = 'e-navigate-arrow';
29
+ const ARROW_RIGHT: string = 'e-arrow-right';
30
+ const ARROW_LEFT: string = 'e-arrow-left';
31
+ const ARROW_UP: string = 'e-arrow-up';
32
+ const ARROW_DOWN: string = 'e-arrow-down';
33
+ const HIDE_ICON: string = 'e-icon-hidden';
34
+ const EXPAND_PANE: string = 'e-expanded';
35
+ const COLLAPSE_PANE: string = 'e-collapsed';
36
+ const PANE_HIDDEN: string = 'e-pane-hidden';
37
+ const RESIZABLE_PANE: string = 'e-resizable';
38
+ const LAST_BAR: string = 'e-last-bar';
39
+ const BAR_SIZE_DEFAULT: number = 1;
40
+
41
+ /**
42
+ * Interface to configure pane properties such as its content, size, min, max, resizable, collapsed and collapsible.
43
+ */
44
+ export class PaneProperties extends ChildProperty<PaneProperties> {
45
+ /**
46
+ * Configures the properties for each pane.
47
+ *
48
+ * @default ''
49
+ */
50
+ @Property()
51
+ public size: string;
52
+
53
+ /**
54
+ * Specifies whether a pane is collapsible or not collapsible.
55
+ *
56
+ * {% codeBlock src='splitter/collapsible/index.md' %}{% endcodeBlock %}
57
+ *
58
+ * @default false
59
+ */
60
+ @Property(false)
61
+ public collapsible: boolean;
62
+
63
+ /**
64
+ * Specifies whether a pane is collapsed or not collapsed at the initial rendering of splitter.
65
+ *
66
+ * {% codeBlock src='splitter/collapsed/index.md' %}{% endcodeBlock %}
67
+ *
68
+ * @default false
69
+ */
70
+ @Property(false)
71
+ public collapsed: boolean;
72
+
73
+ /**
74
+ * Specifies the value whether a pane is resizable. By default, the Splitter is resizable in all panes.
75
+ * You can disable this for any specific panes using this property.
76
+ *
77
+ * @default true
78
+ */
79
+ @Property(true)
80
+ public resizable: boolean;
81
+
82
+ /**
83
+ * Specifies the minimum size of a pane. The pane cannot be resized if it is less than the specified minimum size.
84
+ *
85
+ * @default null
86
+ */
87
+ @Property(null)
88
+ public min: string;
89
+
90
+ /**
91
+ * Specifies the maximum size of a pane. The pane cannot be resized if it is more than the specified maximum limit.
92
+ *
93
+ * @default null
94
+ */
95
+ @Property(null)
96
+ public max: string;
97
+
98
+ /**
99
+ * Specifies the content of split pane as plain text, HTML markup, or any other JavaScript controls.
100
+ *
101
+ * @default ''
102
+ * @blazorType string
103
+ */
104
+ @Property()
105
+ public content: string | HTMLElement;
106
+
107
+ /**
108
+ * Specifies the CSS class names that defines specific user-defined
109
+ * styles and themes to be appended on corresponding pane of the Splitter.
110
+ * It is used to customize the Splitter control panes.
111
+ * One or more custom CSS classes can be specified to the Splitter panes.
112
+ *
113
+ * @default ''
114
+ */
115
+ @Property('')
116
+ public cssClass: string;
117
+ }
118
+
119
+ /**
120
+ * Provides information about a SanitizeSelectors.
121
+ */
122
+ export interface SanitizeSelectors {
123
+ /** Returns the tags. */
124
+ tags?: string[]
125
+ /** Returns the attributes. */
126
+ attributes?: SanitizeRemoveAttrs[]
127
+ }
128
+
129
+ /**
130
+ * Provides information about a BeforeSanitizeHtml event.
131
+ */
132
+ export interface BeforeSanitizeHtmlArgs {
133
+ /** Illustrates whether the current action needs to be prevented or not. */
134
+ cancel?: boolean
135
+ /** It is a callback function and executed it before our inbuilt action. It should return HTML as a string.
136
+ *
137
+ * @function
138
+ * @param {string} value - Returns the value.
139
+ * @returns {string}
140
+ */
141
+ helper?: Function
142
+ /** Returns the selectors object which carrying both tags and attributes selectors to block list of cross-site scripting attack.
143
+ * Also possible to modify the block list in this event.
144
+ */
145
+ selectors?: SanitizeSelectors
146
+ }
147
+
148
+ /**
149
+ * Provides information about a SanitizeRemoveAttributes.
150
+ */
151
+ export interface SanitizeRemoveAttrs {
152
+ /** Defines the attribute name to sanitize */
153
+ attribute?: string
154
+ /** Defines the selector that sanitize the specified attributes within the selector */
155
+ selector?: string
156
+ }
157
+
158
+ /**
159
+ * Specifies a value that indicates whether to align the split panes horizontally or vertically.
160
+ */
161
+ export type Orientation = 'Horizontal' | 'Vertical';
162
+
163
+ /**
164
+ * Splitter is a layout user interface (UI) control that has resizable and collapsible split panes.
165
+ * The container can be split into multiple panes, which are oriented horizontally or vertically.
166
+ * The separator (divider) splits the panes and resizes and expands/collapses the panes.
167
+ * The splitter is placed inside the split pane to make a nested layout user interface.
168
+ *
169
+ * ```html
170
+ * <div id="splitter">
171
+ * <div> Left Pane </div>
172
+ * <div> Center Pane </div>
173
+ * <div> Right Pane </div>
174
+ * </div>
175
+ * ```
176
+ * ```typescript
177
+ * <script>
178
+ * var splitterObj = new Splitter({ width: '300px', height: '200px'});
179
+ * splitterObj.appendTo('#splitter');
180
+ * </script>
181
+ * ```
182
+ */
183
+
184
+ @NotifyPropertyChanges
185
+ export class Splitter extends Component<HTMLElement> {
186
+ private onReportWindowSize: EventListenerOrEventListenerObject;
187
+ private onMouseMoveHandler: EventListenerOrEventListenerObject;
188
+ private onMouseUpHandler: EventListenerOrEventListenerObject;
189
+ private onTouchMoveHandler: EventListenerOrEventListenerObject;
190
+ private onTouchEndHandler: EventListenerOrEventListenerObject;
191
+ private allPanes: HTMLElement[];
192
+ private paneOrder: number[];
193
+ private separatorOrder: number[];
194
+ private currentSeparator: HTMLElement;
195
+ private allBars: HTMLElement[];
196
+ private previousCoordinates: Coordinates;
197
+ private currentCoordinates: Coordinates;
198
+ private totalWidth: number;
199
+ private totalPercent: number;
200
+ private order: number;
201
+ private previousPane: HTMLElement;
202
+ private nextPane: HTMLElement;
203
+ private prevPaneIndex: number;
204
+ private previousPaneHeightWidth: string;
205
+ private updatePrePaneInPercentage: boolean;
206
+ private updateNextPaneInPercentage: boolean;
207
+ private prePaneDimenson: number;
208
+ private nextPaneDimension: number;
209
+ private panesDimensions: number[];
210
+ private border: number;
211
+ private wrapper: HTMLElement;
212
+ private wrapperParent: HTMLElement;
213
+ private sizeFlag: boolean;
214
+ // eslint-disable-next-line
215
+ private prevPaneCurrentWidth: any;
216
+ // eslint-disable-next-line
217
+ private nextPaneCurrentWidth: any;
218
+ private nextPaneIndex: number;
219
+ // eslint-disable-next-line
220
+ private nextPaneHeightWidth: any;
221
+ private validDataAttributes: string[];
222
+ private validElementAttributes: string[];
223
+ private arrow: string;
224
+ private currentBarIndex: number;
225
+ private prevBar: HTMLElement;
226
+ private nextBar: HTMLElement;
227
+ private splitInstance: PaneDetails;
228
+ private leftArrow: string;
229
+ private rightArrow: string;
230
+ private iconsDelay: number;
231
+ private templateElement: HTMLElement[];
232
+ private collapseFlag: boolean;
233
+ private expandFlag: boolean;
234
+
235
+ /**
236
+ * Specifies the height of the Splitter component that accepts both string and number values.
237
+ *
238
+ * @default '100%'
239
+ */
240
+ @Property('100%')
241
+ public height: string;
242
+
243
+ /**
244
+ * Specifies the value whether splitter panes are reordered or not .
245
+ *
246
+ * @default true
247
+ */
248
+ @Property(false)
249
+ public enableReversePanes: boolean;
250
+
251
+ /**
252
+ * Specifies the width of the Splitter control, which accepts both string and number values as width.
253
+ * The string value can be either in pixel or percentage format.
254
+ *
255
+ * @default '100%'
256
+ */
257
+ @Property('100%')
258
+ public width: string;
259
+
260
+ /**
261
+ * Enables or disables the persisting component's state between page reloads.
262
+ *
263
+ * @default false
264
+ */
265
+ @Property(false)
266
+ public enablePersistence: boolean;
267
+
268
+
269
+ /**
270
+ * Configures the individual pane behaviors such as content, size, resizable, minimum, maximum validation, collapsible and collapsed.
271
+ *
272
+ * {% codeBlock src='splitter/panesettings/index.md' %}{% endcodeBlock %}
273
+ *
274
+ * @default []
275
+ */
276
+ @Collection<PanePropertiesModel>([], PaneProperties)
277
+ public paneSettings: PanePropertiesModel[];
278
+
279
+ /**
280
+ * Specifies a value that indicates whether to align the split panes horizontally or vertically.
281
+ * * Set the orientation property as "Horizontal" to create a horizontal splitter that aligns the panes left-to-right.
282
+ * * Set the orientation property as "Vertical" to create a vertical splitter that aligns the panes top-to-bottom.
283
+ *
284
+ * {% codeBlock src='splitter/orientation/index.md' %}{% endcodeBlock %}
285
+ *
286
+ * @default Horizontal
287
+ */
288
+ @Property('Horizontal')
289
+ public orientation: Orientation;
290
+
291
+ /**
292
+ * Specifies the CSS class names that defines specific user-defined
293
+ * styles and themes to be appended on the root element of the Splitter.
294
+ * It is used to customize the Splitter control.
295
+ * One or more custom CSS classes can be specified to the Splitter.
296
+ *
297
+ * @default ''
298
+ */
299
+ @Property('')
300
+ public cssClass: string;
301
+
302
+ /**
303
+ * Specifies boolean value that indicates whether the component is enabled or disabled.
304
+ * The Splitter component does not allow to interact when this property is disabled.
305
+ *
306
+ * @default true
307
+ */
308
+ @Property(true)
309
+ public enabled: boolean;
310
+
311
+ /**
312
+ * Defines whether to allow the cross-scripting site or not.
313
+ *
314
+ * @default true
315
+ */
316
+ @Property(true)
317
+ public enableHtmlSanitizer: boolean;
318
+
319
+ /**
320
+ * Specifies the size of the separator line for both horizontal or vertical orientation.
321
+ * The separator is used to separate the panes by lines.
322
+ *
323
+ * @default null
324
+ */
325
+ @Property(null)
326
+ public separatorSize: number;
327
+
328
+ /**
329
+ * Event triggers before sanitize the value.
330
+ *
331
+ * @event 'event'
332
+ * @blazorProperty 'OnSanitizeHtml'
333
+ */
334
+ @Event()
335
+ public beforeSanitizeHtml: EmitType<BeforeSanitizeHtmlArgs>;
336
+
337
+ /**
338
+ * Triggers after creating the splitter component with its panes.
339
+ *
340
+ * @event 'event'
341
+ * @blazorProperty 'Created'
342
+ */
343
+ @Event()
344
+ public created: EmitType<Object>;
345
+ /* eslint-enable */
346
+ /**
347
+ * Triggers when the split pane is started to resize.
348
+ *
349
+ * @event 'event'
350
+ * @blazorProperty 'OnResizeStart'
351
+ */
352
+ @Event()
353
+ public resizeStart: EmitType<ResizeEventArgs>;
354
+
355
+ /**
356
+ * Triggers when a split pane is being resized.
357
+ *
358
+ * @event 'event'
359
+ * @blazorProperty 'Resizing'
360
+ */
361
+ @Event()
362
+ public resizing: EmitType<ResizingEventArgs>;
363
+
364
+ /**
365
+ * Triggers when the resizing of split pane is stopped.
366
+ *
367
+ * @event 'event'
368
+ * @blazorProperty 'OnResizeStop'
369
+ */
370
+ @Event()
371
+ public resizeStop: EmitType<ResizingEventArgs>;
372
+
373
+ /**
374
+ * Triggers when before panes get collapsed.
375
+ *
376
+ * @event 'event'
377
+ * @blazorProperty 'OnCollapse'
378
+ */
379
+ @Event()
380
+ public beforeCollapse: EmitType<BeforeExpandEventArgs>;
381
+
382
+ /**
383
+ * Triggers when before panes get expanded.
384
+ *
385
+ * @event 'event'
386
+ * @blazorProperty 'OnExpand'
387
+ */
388
+ @Event()
389
+ public beforeExpand: EmitType<BeforeExpandEventArgs>;
390
+
391
+ /**
392
+ * Triggers when after panes get collapsed.
393
+ *
394
+ * @event 'event'
395
+ * @blazorProperty 'Collapsed'
396
+ */
397
+ @Event()
398
+ public collapsed: EmitType<ExpandedEventArgs>;
399
+ protected needsID: boolean;
400
+
401
+ /**
402
+ * Triggers when after panes get expanded.
403
+ *
404
+ * @event 'event'
405
+ * @blazorProperty 'Expanded'
406
+ */
407
+ @Event()
408
+ public expanded: EmitType<ExpandedEventArgs>;
409
+
410
+ /**
411
+ * Initializes a new instance of the Splitter class.
412
+ *
413
+ * @param options - Specifies Splitter model properties as options.
414
+ * @param element - Specifies the element that is rendered as an Splitter.
415
+ */
416
+
417
+ public constructor(options?: SplitterModel, element?: string | HTMLElement) {
418
+ super(options, element);
419
+ this.needsID = true;
420
+ }
421
+
422
+ /**
423
+ * Gets called when the model property changes.The data that describes the old and new values of the property that changed.
424
+ *
425
+ * @param {SplitterModel} newProp - specifies the new property
426
+ * @param {SplitterModel} oldProp - specifies the old property
427
+ * @returns {void}
428
+ * @private
429
+ */
430
+
431
+ public onPropertyChanged(newProp: SplitterModel, oldProp: SplitterModel): void {
432
+ if (!this.element.classList.contains(ROOT)) {
433
+ return;
434
+ }
435
+ for (const prop of Object.keys(newProp)) {
436
+ switch (prop) {
437
+ case 'height':
438
+ this.setSplitterSize(this.element, newProp.height, 'height');
439
+ break;
440
+ case 'width':
441
+ this.setSplitterSize(this.element, newProp.width, 'width');
442
+ break;
443
+ case 'cssClass':
444
+ this.setCssClass(this.element, newProp.cssClass);
445
+ break;
446
+ case 'enabled':
447
+ this.isEnabled(this.enabled);
448
+ break;
449
+ case 'enableReversePanes':
450
+ this.setReversePane();
451
+ break;
452
+ case 'separatorSize':
453
+ this.setSeparatorSize(newProp.separatorSize);
454
+ break;
455
+ case 'orientation':
456
+ this.changeOrientation(newProp.orientation);
457
+ break;
458
+ case 'paneSettings': {
459
+ if (!(newProp.paneSettings instanceof Array && oldProp.paneSettings instanceof Array)) {
460
+ const paneCounts: Object[] = Object.keys(newProp.paneSettings);
461
+ for (let i: number = 0; i < paneCounts.length; i++) {
462
+ const index: number = parseInt(Object.keys(newProp.paneSettings)[i], 10);
463
+ const changedPropsCount: number = Object.keys(newProp.paneSettings[index]).length;
464
+ for (let j: number = 0; j < changedPropsCount; j++) {
465
+ const property: string = Object.keys(newProp.paneSettings[index])[j];
466
+ switch (property) {
467
+ case 'content': {
468
+ const newValue: string = Object(newProp.paneSettings[index])[property];
469
+ if (!isNullOrUndefined(newValue)) {
470
+ this.allPanes[index].innerHTML = '';
471
+ this.setTemplate(newValue, this.allPanes[index]);
472
+ }
473
+ break;
474
+ }
475
+
476
+ case 'resizable': {
477
+ const newVal: boolean = Object(newProp.paneSettings[index])[property];
478
+ this.resizableModel(index, newVal);
479
+ break;
480
+ }
481
+
482
+ case 'collapsible':
483
+ this.collapsibleModelUpdate(index);
484
+ break;
485
+
486
+ case 'collapsed':
487
+ // eslint-disable-next-line
488
+ newProp.paneSettings[index].collapsed ? this.isCollapsed(index) : this.collapsedOnchange(index);
489
+ break;
490
+
491
+ case 'cssClass':
492
+ this.setCssClass(this.allPanes[index] as HTMLElement, newProp.paneSettings[index].cssClass);
493
+ break;
494
+
495
+ case 'size': {
496
+ const newValSize: string = Object(newProp.paneSettings[index])[property];
497
+ if (newValSize !== '' && !isNullOrUndefined(newValSize)) {
498
+ this.updatePaneSize(newValSize, index);
499
+ }
500
+ break;
501
+ }
502
+ }
503
+ }
504
+ }
505
+ } else {
506
+ this.destroyPaneSettings();
507
+ this.allBars = [];
508
+ this.allPanes = [];
509
+ this.createSplitPane(this.element);
510
+ this.addSeparator(this.element);
511
+ this.getPanesDimensions();
512
+ this.setRTL(this.enableRtl);
513
+ this.isCollapsed();
514
+ }
515
+ break;
516
+ }
517
+ case 'enableRtl':
518
+ this.setRTL(newProp.enableRtl);
519
+ break;
520
+ }
521
+ }
522
+ }
523
+
524
+ private updatePaneSize(newValSize: string, index: number): void {
525
+ this.allPanes[index].style.flexBasis = newValSize;
526
+ const flexPaneIndexes: number[] = [];
527
+ let staticPaneWidth: number;
528
+ let flexCount: number = 0;
529
+ for (let i: number = 0; i < this.allPanes.length; i++) {
530
+ if (!this.paneSettings[i].size && !(this.allPanes[i].innerText === '')) {
531
+ flexPaneIndexes[flexCount] = i;
532
+ flexCount++;
533
+ } else if (this.paneSettings[i].size) {
534
+ staticPaneWidth = this.orientation === 'Horizontal' ? this.allPanes[index].offsetWidth : this.allPanes[index].offsetHeight;
535
+ }
536
+ }
537
+ staticPaneWidth = this.orientation === 'Horizontal' ? (this.allBars[0].offsetWidth * this.allBars.length) + staticPaneWidth :
538
+ (this.allBars[0].offsetHeight * this.allBars.length) + staticPaneWidth;
539
+ const flexPaneWidth: number = (this.orientation === 'Horizontal' ? this.element.offsetWidth : this.element.offsetHeight)
540
+ - staticPaneWidth - (this.border * 2);
541
+ const avgDiffWidth: number = flexPaneWidth / flexPaneIndexes.length;
542
+ for (let j: number = 0; j < flexPaneIndexes.length; j++) {
543
+ this.allPanes[flexPaneIndexes[j]].style.flexBasis = avgDiffWidth + 'px';
544
+ }
545
+ this.allPanes[index].classList.add(STATIC_PANE);
546
+ }
547
+
548
+ protected initializeValues(): void {
549
+ this.allPanes = [];
550
+ this.paneOrder = [];
551
+ this.separatorOrder = [];
552
+ this.allBars = [];
553
+ this.previousCoordinates = {};
554
+ this.currentCoordinates = {};
555
+ this.updatePrePaneInPercentage = false;
556
+ this.updateNextPaneInPercentage = false;
557
+ this.panesDimensions = [];
558
+ this.border = 0;
559
+ this.validDataAttributes = ['data-size', 'data-min', 'data-max', 'data-collapsible',
560
+ 'data-resizable', 'data-content', 'data-collapsed'];
561
+ this.validElementAttributes = ['data-orientation', 'data-width', 'data-height'];
562
+ this.iconsDelay = 300;
563
+ this.templateElement = [];
564
+ this.collapseFlag = false;
565
+ this.expandFlag = true;
566
+ }
567
+
568
+ protected preRender(): void {
569
+ this.initializeValues();
570
+ this.onReportWindowSize = this.reportWindowSize.bind(this);
571
+ this.onMouseMoveHandler = this.onMouseMove.bind(this);
572
+ this.onMouseUpHandler = this.onMouseUp.bind(this);
573
+ this.onTouchMoveHandler = this.onMouseMove.bind(this);
574
+ this.onTouchEndHandler = this.onMouseUp.bind(this);
575
+ this.wrapper = this.element.cloneNode(true) as HTMLElement;
576
+ this.wrapperParent = this.element.parentElement;
577
+ removeClass([this.wrapper], ['e-control', 'e-lib', ROOT]);
578
+ const orientation: string = this.orientation === 'Horizontal' ? HORIZONTAL_PANE : VERTICAL_PANE;
579
+ addClass([this.element], orientation);
580
+ const name: string = Browser.info.name;
581
+ const css: string = (name === 'msie') ? 'e-ie' : '';
582
+ this.setCssClass(this.element, css);
583
+ if (Browser.isDevice) {
584
+ addClass([this.element], SPLIT_TOUCH);
585
+ }
586
+ }
587
+
588
+ protected getPersistData(): string {
589
+ return this.addOnPersist(['paneSettings']);
590
+ }
591
+ /**
592
+ * Returns the current module name.
593
+ *
594
+ * @returns {string} - returns the string value
595
+ * @private
596
+ */
597
+ protected getModuleName(): string {
598
+ return 'splitter';
599
+ }
600
+
601
+ /**
602
+ * To Initialize the control rendering
603
+ *
604
+ * @returns {void}
605
+ * @private
606
+ */
607
+ public render(): void {
608
+ this.checkDataAttributes();
609
+ this.setCssClass(this.element, this.cssClass);
610
+ this.isEnabled(this.enabled);
611
+ this.setDimension(this.getHeight(this.element), this.getWidth(this.element));
612
+ this.createSplitPane(this.element);
613
+ this.addSeparator(this.element);
614
+ this.getPanesDimensions();
615
+ this.setPaneSettings();
616
+ this.setRTL(this.enableRtl);
617
+ if (this.enableReversePanes) {
618
+ this.setReversePane();
619
+ }
620
+ this.collapseFlag = true;
621
+ this.isCollapsed();
622
+ this.collapseFlag = false;
623
+ EventHandler.add(document, 'touchstart click', this.onDocumentClick, this);
624
+ this.renderComplete();
625
+ this.element.ownerDocument.defaultView.addEventListener('resize', this.onReportWindowSize, true);
626
+ EventHandler.add(this.element, 'keydown', this.onMove, this);
627
+ }
628
+
629
+ private onDocumentClick(e: Event | MouseEvent): void {
630
+ if (!(<HTMLElement>e.target).classList.contains(SPLIT_BAR) && !isNullOrUndefined(this.currentSeparator)) {
631
+ this.currentSeparator.classList.remove(SPLIT_BAR_HOVER);
632
+ this.currentSeparator.classList.remove(SPLIT_BAR_ACTIVE);
633
+ }
634
+ }
635
+
636
+ private checkPaneSize(e: MouseEvent | TouchEvent | PointerEvent | KeyboardEvent): void {
637
+ const prePaneSize: number = this.orientation === 'Horizontal' ? this.previousPane.offsetWidth : this.previousPane.offsetHeight;
638
+ const nextPaneSize: number = this.orientation === 'Horizontal' ? this.nextPane.offsetWidth : this.nextPane.offsetHeight;
639
+ const splitBarSize: number = isNullOrUndefined(this.separatorSize) ? BAR_SIZE_DEFAULT : this.separatorSize;
640
+ if ((this.previousPane.style.flexBasis.indexOf('%') > 0 || this.nextPane.style.flexBasis.indexOf('%') > 0)) {
641
+ const previousFlexBasis: number = this.updatePaneFlexBasis(this.previousPane);
642
+ const nextFlexBasis: number = this.updatePaneFlexBasis(this.nextPane);
643
+ this.totalPercent = previousFlexBasis + nextFlexBasis;
644
+ this.totalWidth = this.convertPercentageToPixel(this.totalPercent + '%');
645
+ if (e.type === 'keydown' && (!isNullOrUndefined((<KeyboardEvent>e).keyCode))) {
646
+ if (((<KeyboardEvent>e).keyCode === 39 || ((<KeyboardEvent>e).keyCode === 40)) && nextPaneSize > 0 &&
647
+ (this.getMinInPixel(this.paneSettings[this.nextPaneIndex].min) <
648
+ this.convertPercentageToPixel((nextFlexBasis - 1) + '%'))) {
649
+ this.previousPane.style.flexBasis = (previousFlexBasis + 1) + '%';
650
+ this.nextPane.style.flexBasis = (nextFlexBasis - 1) + '%';
651
+ } else if (((<KeyboardEvent>e).keyCode === 37 || ((<KeyboardEvent>e).keyCode === 38)) && prePaneSize > 0 &&
652
+ (this.getMinInPixel(this.paneSettings[this.prevPaneIndex].min) <
653
+ this.convertPercentageToPixel((previousFlexBasis - 1) + '%'))) {
654
+ this.previousPane.style.flexBasis = (previousFlexBasis - 1) + '%';
655
+ this.nextPane.style.flexBasis = (nextFlexBasis + 1) + '%';
656
+ }
657
+ }
658
+ } else {
659
+ this.totalWidth = (this.orientation === 'Horizontal') ? this.previousPane.offsetWidth + this.nextPane.offsetWidth :
660
+ this.previousPane.offsetHeight + this.nextPane.offsetHeight;
661
+ if (e.type === 'keydown' && (!isNullOrUndefined((<KeyboardEvent>e).keyCode))) {
662
+ if (((<KeyboardEvent>e).keyCode === 39 || ((<KeyboardEvent>e).keyCode === 40)) && nextPaneSize > 0 &&
663
+ (this.getMinInPixel(this.paneSettings[this.nextPaneIndex].min) < (nextPaneSize + splitBarSize))) {
664
+ this.addStaticPaneClass();
665
+ this.previousPane.style.flexBasis = (prePaneSize + splitBarSize) + 'px';
666
+ this.nextPane.style.flexBasis = (nextPaneSize < splitBarSize) ? '0px' :
667
+ (nextPaneSize - splitBarSize) + 'px';
668
+ } else if (((<KeyboardEvent>e).keyCode === 37 || ((<KeyboardEvent>e).keyCode === 38)) && prePaneSize > 0 &&
669
+ (this.getMinInPixel(this.paneSettings[this.prevPaneIndex].min) < (prePaneSize - splitBarSize))) {
670
+ this.addStaticPaneClass();
671
+ this.previousPane.style.flexBasis = (prePaneSize < splitBarSize) ? '0px' :
672
+ (prePaneSize - splitBarSize) + 'px';
673
+ this.nextPane.style.flexBasis = (nextPaneSize + splitBarSize) + 'px';
674
+ }
675
+ }
676
+ }
677
+ }
678
+
679
+ private onMove(event: KeyboardEvent): void {
680
+ if (this.allPanes.length > 1) {
681
+ const index: number = this.getSeparatorIndex(this.currentSeparator);
682
+ const isPrevpaneCollapsed: boolean = this.previousPane.classList.contains(COLLAPSE_PANE);
683
+ const isPrevpaneExpanded: boolean = this.previousPane.classList.contains(EXPAND_PANE);
684
+ const isNextpaneCollapsed: boolean = this.nextPane.classList.contains(COLLAPSE_PANE);
685
+ if (((this.orientation !== 'Horizontal' && event.keyCode === 38) || (this.orientation === 'Horizontal' &&
686
+ event.keyCode === 39) ||
687
+ (this.orientation === 'Horizontal' && event.keyCode === 37) || (this.orientation !== 'Horizontal' && event.keyCode === 40))
688
+ && (!isPrevpaneExpanded && !isNextpaneCollapsed && !isPrevpaneCollapsed || (isPrevpaneExpanded) && !isNextpaneCollapsed) &&
689
+ document.activeElement.classList.contains(SPLIT_BAR) && (this.paneSettings[index].resizable &&
690
+ this.paneSettings[index + 1].resizable)) {
691
+ event.preventDefault();
692
+ this.checkPaneSize(event);
693
+ this.triggerResizing(event);
694
+ } else if (event.keyCode === 13 && this.paneSettings[index].collapsible &&
695
+ document.activeElement.classList.contains(SPLIT_BAR) && this.currentSeparator.classList.contains(SPLIT_BAR_ACTIVE)) {
696
+ if (!this.previousPane.classList.contains(COLLAPSE_PANE)) {
697
+ this.collapse(index);
698
+ addClass([this.currentSeparator], SPLIT_BAR_ACTIVE);
699
+ } else {
700
+ this.expand(index);
701
+ addClass([this.currentSeparator], SPLIT_BAR_ACTIVE);
702
+ }
703
+ }
704
+ }
705
+ }
706
+
707
+ private getMinInPixel(minValue: string): number {
708
+ let min: number;
709
+ if (isNullOrUndefined(minValue)) { return 0; }
710
+ let paneMinRange: number = this.convertPixelToNumber(minValue.toString());
711
+ if (minValue.indexOf('%') > 0) {
712
+ paneMinRange = this.convertPercentageToPixel(minValue);
713
+ }
714
+ min = this.convertPixelToNumber((paneMinRange).toString());
715
+ return min;
716
+ }
717
+
718
+ /**
719
+ * @param {string} value - specifies the string value
720
+ * @returns {string} returns the string
721
+ * @hidden
722
+ */
723
+ public sanitizeHelper(value: string): string {
724
+ if (this.enableHtmlSanitizer) {
725
+ const item: BeforeSanitizeHtmlArgs = SanitizeHtmlHelper.beforeSanitize();
726
+ const beforeEvent: BeforeSanitizeHtmlArgs = {
727
+ cancel: false,
728
+ helper: null
729
+ };
730
+ extend(item, item, beforeEvent);
731
+ this.trigger('beforeSanitizeHtml', item);
732
+ if (item.cancel && !isNullOrUndefined(item.helper)) {
733
+ value = item.helper(value);
734
+ } else if (!item.cancel) {
735
+ value = SanitizeHtmlHelper.serializeValue(item, value);
736
+ }
737
+ }
738
+ return value;
739
+ }
740
+
741
+ private checkDataAttributes(): void {
742
+ let api: string;
743
+ let value: string | boolean;
744
+ // Element values
745
+ for (let dataIndex: number = 0; dataIndex < this.validElementAttributes.length; dataIndex++) {
746
+ value = this.element.getAttribute(this.validElementAttributes[dataIndex]);
747
+ if (!isNullOrUndefined(value)) {
748
+ api = this.removeDataPrefix(this.validElementAttributes[dataIndex]);
749
+ // eslint-disable-next-line
750
+ (this as any)[api] = value;
751
+ }
752
+ }
753
+ // Pane values
754
+ for (let paneIndex: number = 0; paneIndex < this.element.children.length; paneIndex++) {
755
+ for (let dataAttr: number = 0; dataAttr < this.validDataAttributes.length; dataAttr++) {
756
+ value = this.element.children[paneIndex].getAttribute(this.validDataAttributes[dataAttr]);
757
+ if (!isNullOrUndefined(value)) {
758
+ api = this.removeDataPrefix(this.validDataAttributes[dataAttr]);
759
+ value = (api === 'collapsible' || api === 'resizable') ? (value === 'true') : value;
760
+ if (isNullOrUndefined(this.paneSettings[paneIndex])) {
761
+ this.paneSettings[paneIndex] = {
762
+ size: '',
763
+ min: null,
764
+ max: null,
765
+ content: '',
766
+ resizable: true,
767
+ collapsible: false,
768
+ collapsed: false
769
+ };
770
+ }
771
+ // eslint-disable-next-line
772
+ let paneAPI: PanePropertiesModel = (this.paneSettings[paneIndex] as any)[api];
773
+ if (api === 'resizable' || api === 'collapsible' || api === 'collapsed') {
774
+ // eslint-disable-next-line
775
+ (this.paneSettings[paneIndex] as any)[api] = value;
776
+ }
777
+ if (isNullOrUndefined(paneAPI) || paneAPI === '') {
778
+ // eslint-disable-next-line
779
+ (this.paneSettings[paneIndex] as any)[api] = value;
780
+ }
781
+ }
782
+ }
783
+ }
784
+ }
785
+
786
+ private destroyPaneSettings(): void {
787
+ [].slice.call(this.element.children).forEach((el: HTMLElement) => {
788
+ detach(el);
789
+ });
790
+ this.restoreElem();
791
+ }
792
+
793
+ private setPaneSettings(): void {
794
+ const childCount: number = this.allPanes.length;
795
+ const paneCollection: PanePropertiesModel[] = [];
796
+ const paneValue: PanePropertiesModel = {
797
+ size: '',
798
+ min: null,
799
+ max: null,
800
+ content: '',
801
+ resizable: true,
802
+ collapsed: false,
803
+ collapsible: false,
804
+ cssClass: ''
805
+ };
806
+ for (let i: number = 0; i < childCount; i++) {
807
+ if (isNullOrUndefined(this.paneSettings[i])) {
808
+ paneCollection[i] = paneValue;
809
+ } else {
810
+ paneCollection[i] = this.paneSettings[i];
811
+ }
812
+ }
813
+ this.setProperties({ 'paneSettings': paneCollection }, true);
814
+ }
815
+
816
+ private checkArrow(paneIndex: number, targetArrow: string): HTMLElement {
817
+ return (this.allBars[paneIndex].querySelector('.' + NAVIGATE_ARROW + '.' + targetArrow));
818
+ }
819
+
820
+ private removeDataPrefix(attribute: string): string {
821
+ return attribute.slice(attribute.lastIndexOf('-') + 1);
822
+ }
823
+
824
+ private setRTL(rtl: boolean): void {
825
+ // eslint-disable-next-line
826
+ rtl ? addClass([this.element], RTL) : removeClass([this.element], RTL);
827
+ }
828
+
829
+ private setReversePane(): void {
830
+ this.allPanes = this.allPanes.reverse();
831
+ this.allBars = this.allBars.reverse();
832
+ addClass([this.allBars[this.allBars.length - 1]], LAST_BAR);
833
+ removeClass([this.allBars[0]], LAST_BAR);
834
+ this.setProperties({ 'paneSettings': this.paneSettings.reverse() }, true);
835
+ if (this.enableReversePanes) {
836
+ this.element.setAttribute('dir', 'rtl');
837
+ } else {
838
+ this.element.removeAttribute('dir');
839
+ }
840
+ }
841
+
842
+ private setSplitterSize(element: HTMLElement, size: string, property: string): void {
843
+ const style: { [key: string]: Object } = property === 'width' ? { 'width': formatUnit(size) } : { 'height': formatUnit(size) };
844
+ setStyleAttribute(element, style);
845
+ }
846
+
847
+ private getPanesDimensions(): void {
848
+ for (let index: number = 0; index < this.allPanes.length; index++) {
849
+ // eslint-disable-next-line
850
+ this.orientation === 'Horizontal' ? this.panesDimensions.push(this.allPanes[index].getBoundingClientRect().width) :
851
+ this.panesDimensions.push(this.allPanes[index].getBoundingClientRect().height);
852
+ }
853
+ }
854
+
855
+ private setCssClass(element: HTMLElement, className: string): void {
856
+ if (className) {
857
+ addClass([element], className.split(className.indexOf(',') > -1 ? ',' : ' '));
858
+ }
859
+ }
860
+
861
+ private hideResizer(target: HTMLElement): void {
862
+ addClass([select('.' + RESIZE_BAR, target)], HIDE_HANDLER);
863
+ }
864
+
865
+ private showResizer(target: HTMLElement): void {
866
+ if (!isNullOrUndefined(this.previousPane) && this.previousPane.classList.contains(RESIZABLE_PANE) &&
867
+ !isNullOrUndefined(this.nextPane) && this.nextPane.classList.contains(RESIZABLE_PANE)) {
868
+ removeClass([select('.' + RESIZE_BAR, target)], HIDE_HANDLER);
869
+ }
870
+ }
871
+
872
+ private resizableModel(index: number, newVal: boolean): void {
873
+ const paneIndex: number = (index === (this.allBars.length)) ? (index - 1) : index;
874
+ const i: number = index;
875
+ EventHandler.remove(this.allBars[paneIndex], 'mousedown', this.onMouseDown);
876
+ if (newVal) {
877
+ EventHandler.add(this.allBars[paneIndex], 'mousedown', this.onMouseDown, this);
878
+ if (this.isResizable()) {
879
+ this.showResizer(this.allBars[paneIndex]);
880
+ removeClass([select('.' + RESIZE_BAR, this.allBars[paneIndex])], HIDE_HANDLER);
881
+ this.allBars[paneIndex].classList.add(RESIZABLE_BAR);
882
+ // eslint-disable-next-line
883
+ (index === (this.allBars.length)) ? this.allPanes[index].classList.add(RESIZABLE_PANE) :
884
+ this.allPanes[paneIndex].classList.add(RESIZABLE_PANE);
885
+ this.updateResizablePanes(i);
886
+ }
887
+ } else {
888
+ this.updateResizablePanes(i);
889
+ this.hideResizer(this.allBars[paneIndex]);
890
+ this.allBars[paneIndex].classList.remove(RESIZABLE_BAR);
891
+ // eslint-disable-next-line
892
+ (index === (this.allBars.length)) ? this.allPanes[index].classList.remove(RESIZABLE_PANE) :
893
+ this.allPanes[paneIndex].classList.remove(RESIZABLE_PANE);
894
+ }
895
+ }
896
+
897
+ private collapsibleModelUpdate(index: number): void {
898
+ const paneIndex: number = index === (this.allBars.length) ? (index - 1) : index;
899
+ const arrow2: HTMLElement = (this.orientation === 'Horizontal')
900
+ ? this.checkArrow(paneIndex, ARROW_LEFT) : this.checkArrow(paneIndex, ARROW_UP);
901
+ const arrow1: HTMLElement = (this.orientation === 'Horizontal')
902
+ ? this.checkArrow(paneIndex, ARROW_RIGHT) : this.checkArrow(paneIndex, ARROW_DOWN);
903
+ this.paneCollapsible(this.allPanes[index], index);
904
+ this.updateCollapseIcons(paneIndex, arrow1, arrow2);
905
+ }
906
+
907
+ private collapseArrow(barIndex: number, arrow: string): HTMLElement {
908
+ return selectAll('.' + arrow, this.allBars[barIndex])[0];
909
+ }
910
+
911
+ private updateIsCollapsed(index: number, collapseArrow: string, lastBarArrow: string): void {
912
+ if (!isNullOrUndefined(index)) {
913
+ let targetEle: HTMLElement;
914
+ const lastBarIndex: boolean = (index === this.allBars.length);
915
+ const barIndex: number = lastBarIndex ? index - 1 : index;
916
+ if (!lastBarIndex && this.allPanes[index + 1].classList.contains(COLLAPSE_PANE) && index !== 0) {
917
+ targetEle = this.collapseArrow(barIndex - 1, lastBarArrow);
918
+ } else {
919
+ targetEle = (lastBarIndex) ? this.collapseArrow(barIndex, lastBarArrow) : this.collapseArrow(barIndex, collapseArrow);
920
+ }
921
+ targetEle.click();
922
+ }
923
+ }
924
+
925
+ private isCollapsed(index?: number): void {
926
+ if (!isNullOrUndefined(index) && this.paneSettings[index].collapsed
927
+ && isNullOrUndefined(this.allPanes[index].classList.contains(COLLAPSE_PANE))) {
928
+ return;
929
+ }
930
+ this.expandFlag = false;
931
+ if (!isNullOrUndefined(index)) {
932
+ this.collapseFlag = true;
933
+ let targetEle: HTMLElement;
934
+ const lastBarIndex: boolean = (index === this.allBars.length);
935
+ const barIndex: number = lastBarIndex ? index - 1 : index;
936
+ if (!lastBarIndex && this.allPanes[index + 1].classList.contains(COLLAPSE_PANE) && index !== 0) {
937
+ targetEle = this.collapseArrow(barIndex - 1, this.targetArrows().lastBarArrow);
938
+ } else {
939
+ targetEle = (lastBarIndex) ? this.collapseArrow(barIndex, this.targetArrows().lastBarArrow) :
940
+ this.collapseArrow(barIndex, this.targetArrows().collapseArrow);
941
+ }
942
+ const event: Object = { target: targetEle };
943
+ const eventArgs: BeforeExpandEventArgs = this.beforeAction(event as Event);
944
+ this.trigger('beforeCollapse', eventArgs, (beforeCollapseArgs: BeforeExpandEventArgs) => {
945
+ if (!beforeCollapseArgs.cancel) {
946
+ let collapsedindex: number[] = [];
947
+ collapsedindex[0] = index;
948
+ let j: number = 1;
949
+ for (let i: number = 0; i < this.allPanes.length; i++) {
950
+ if (this.allPanes[i].classList.contains(COLLAPSE_PANE)) {
951
+ collapsedindex[j] = i;
952
+ j++;
953
+ }
954
+ }
955
+ collapsedindex = collapsedindex.sort();
956
+ this.updateIsCollapsed(index, this.targetArrows().collapseArrow, this.targetArrows().lastBarArrow);
957
+ for (let i: number = 0; i < collapsedindex.length; i++) {
958
+ if (!this.allPanes[collapsedindex[i]].classList.contains(COLLAPSE_PANE)) {
959
+ this.updateIsCollapsed(collapsedindex[i], this.targetArrows().collapseArrow, this.targetArrows().lastBarArrow);
960
+ }
961
+ }
962
+ for (let i: number = collapsedindex.length; i > 0; i--) {
963
+ if (!this.allPanes[collapsedindex[i - 1]].classList.contains(COLLAPSE_PANE)) {
964
+ const targetArrow: { [key: string]: string } = this.targetArrows();
965
+ this.updateIsCollapsed(collapsedindex[i - 1], targetArrow.collapseArrow, targetArrow.lastBarArrow);
966
+ }
967
+ }
968
+ const collapseEventArgs: ExpandedEventArgs = this.afterAction(event as Event);
969
+ this.trigger('collapsed', collapseEventArgs);
970
+ this.collapseFlag = false;
971
+ }
972
+ });
973
+ } else {
974
+ for (let m: number = 0; m < this.allPanes.length; m++) {
975
+ if (!isNullOrUndefined(this.paneSettings[m]) && this.paneSettings[m].collapsed) {
976
+ this.updateIsCollapsed(m, this.targetArrows().collapseArrow, this.targetArrows().lastBarArrow);
977
+ }
978
+ }
979
+ for (let m: number = this.allPanes.length - 1; m >= 0; m--) {
980
+ if (!isNullOrUndefined(this.paneSettings[m]) && this.paneSettings[m].collapsed &&
981
+ !this.allPanes[m].classList.contains(COLLAPSE_PANE)) {
982
+ const collapseArrow: string = this.orientation === 'Horizontal' ? ARROW_RIGHT : ARROW_DOWN;
983
+ if (m !== 0) {
984
+ const targetEle: HTMLElement = this.collapseArrow(m - 1, collapseArrow);
985
+ targetEle.click();
986
+ }
987
+ if (!this.nextPane.classList.contains(COLLAPSE_PANE)) {
988
+ const targetEle: HTMLElement = this.collapseArrow(m - 1, collapseArrow);
989
+ targetEle.click();
990
+ }
991
+ }
992
+ }
993
+ }
994
+ this.expandFlag = true;
995
+ }
996
+
997
+ private targetArrows(): { [key: string]: string } {
998
+ this.splitterProperty();
999
+ return {
1000
+ collapseArrow: (this.orientation === 'Horizontal') ? ARROW_LEFT : ARROW_UP,
1001
+ lastBarArrow: (this.orientation === 'Vertical') ? ARROW_DOWN : ARROW_RIGHT
1002
+ };
1003
+ }
1004
+
1005
+ private collapsedOnchange(index: number): void {
1006
+ if (!isNullOrUndefined(this.paneSettings[index]) && !isNullOrUndefined(this.paneSettings[index].collapsed)
1007
+ && this.allPanes[index].classList.contains(COLLAPSE_PANE)) {
1008
+ this.updateIsCollapsed(index, this.targetArrows().lastBarArrow, this.targetArrows().collapseArrow);
1009
+ }
1010
+ }
1011
+
1012
+
1013
+ private isEnabled(enabled: boolean): void {
1014
+ // eslint-disable-next-line
1015
+ enabled ? removeClass([this.element], DISABLED) : addClass([this.element], DISABLED);
1016
+ }
1017
+
1018
+ private setSeparatorSize(size: number): void {
1019
+ const sizeValue: string = isNullOrUndefined(size) ? 'auto' : size + 'px';
1020
+ const separator: string = this.orientation === 'Horizontal' ? SPLIT_H_BAR : SPLIT_V_BAR;
1021
+ for (let index: number = 0; index < this.allBars.length; index++) {
1022
+ const splitBar: HTMLElement = selectAll('.' + separator, this.element)[index];
1023
+ const resizeBar: HTMLElement = selectAll('.' + RESIZE_BAR, splitBar)[0];
1024
+ if (this.orientation === 'Horizontal') {
1025
+ splitBar.style.width = sizeValue;
1026
+ if (!isNullOrUndefined(resizeBar)) {
1027
+ resizeBar.style.width = sizeValue;
1028
+ }
1029
+ } else {
1030
+ splitBar.style.height = sizeValue;
1031
+ if (!isNullOrUndefined(resizeBar)) {
1032
+ resizeBar.style.height = sizeValue;
1033
+ }
1034
+ }
1035
+ }
1036
+ }
1037
+
1038
+ private changeOrientation(orientation: Orientation): void {
1039
+ const isVertical: boolean = orientation === 'Vertical';
1040
+ this.element.classList.remove(isVertical ? HORIZONTAL_PANE : VERTICAL_PANE);
1041
+ this.element.classList.add(isVertical ? VERTICAL_PANE : HORIZONTAL_PANE);
1042
+ for (let index: number = 0; index < this.allPanes.length; index++) {
1043
+ this.allPanes[index].classList.remove(isVertical ? SPLIT_H_PANE : SPLIT_V_PANE);
1044
+ this.allPanes[index].classList.add(isVertical ? SPLIT_V_PANE : SPLIT_H_PANE);
1045
+ }
1046
+ for (let index: number = 0; index < this.allBars.length; index++) {
1047
+ detach(this.allBars[index]);
1048
+ }
1049
+ this.allBars = [];
1050
+ this.addSeparator(this.element);
1051
+ }
1052
+
1053
+ private checkSplitPane(currentBar: Element, elementIndex: number): HTMLElement {
1054
+ const paneEle: HTMLElement = this.collectPanes(currentBar.parentElement.children)[elementIndex] as HTMLElement;
1055
+ return paneEle;
1056
+ }
1057
+
1058
+ private collectPanes(childNodes: HTMLCollection): HTMLElement[] {
1059
+ const elements: HTMLElement[] = [];
1060
+ for (let i: number = 0; i < childNodes.length; i++) {
1061
+ if (childNodes[i].classList.contains(PANE)) {
1062
+ elements.push(childNodes[i] as HTMLElement);
1063
+ }
1064
+ }
1065
+ return elements;
1066
+ }
1067
+
1068
+ private getPrevPane(order: number): HTMLElement {
1069
+ return this.enableReversePanes ? this.getOrderPane(order + 1) : this.getOrderPane(order - 1);
1070
+ }
1071
+
1072
+ private getNextPane(order: number): HTMLElement {
1073
+ return this.enableReversePanes ? this.getOrderPane(order - 1) : this.getOrderPane(order + 1);
1074
+ }
1075
+
1076
+ private getOrderPane(order: number): HTMLElement {
1077
+ let pane: HTMLElement;
1078
+ for (let i: number = 0; i < this.element.children.length; i++) {
1079
+ if (parseInt((this.element.children[i] as HTMLElement).style.order, 10) === order) {
1080
+ pane = this.element.children[i] as HTMLElement;
1081
+ }
1082
+ }
1083
+ return pane;
1084
+ }
1085
+
1086
+ private getOrderIndex(order: number, type: string) : number {
1087
+ let index: number;
1088
+ let panes : HTMLElement[];
1089
+ if (type === 'pane') {
1090
+ panes = this.allPanes;
1091
+ } else {
1092
+ panes = this.allBars;
1093
+ }
1094
+ for (let i: number = 0; i < panes.length; i++) {
1095
+ if (parseInt((panes[i] as HTMLElement).style.order, 10) === order) {
1096
+ index = i;
1097
+ }
1098
+ }
1099
+ return index;
1100
+ }
1101
+
1102
+ private updateSeparatorSize(resizeHanlder: HTMLElement): void {
1103
+ const sizeValue: string = isNullOrUndefined(this.separatorSize) ? '1px' : this.separatorSize + 'px';
1104
+ // eslint-disable-next-line
1105
+ this.orientation === 'Horizontal' ? (resizeHanlder.style.width = sizeValue) : resizeHanlder.style.height = sizeValue;
1106
+ }
1107
+
1108
+ private addResizeHandler(currentBar: HTMLElement): void {
1109
+ const resizeHanlder: HTMLElement = this.createElement('div');
1110
+ addClass([resizeHanlder], [RESIZE_BAR, E_ICONS]);
1111
+ this.updateSeparatorSize(resizeHanlder);
1112
+ currentBar.appendChild(resizeHanlder);
1113
+ }
1114
+
1115
+ private getHeight(target: HTMLElement): string {
1116
+ let height: string = this.height;
1117
+ height = target.style.height !== '' && this.height === '100%' ? target.style.height : this.height;
1118
+ return height;
1119
+ }
1120
+
1121
+ private getWidth(target: HTMLElement): string {
1122
+ let width: string = this.width;
1123
+ width = target.style.width !== '' && this.width === '100%' ? target.style.width : this.width;
1124
+ return width;
1125
+ }
1126
+
1127
+ private setDimension(height: string, width: string): void {
1128
+ setStyleAttribute(this.element, { 'height': height, 'width': width });
1129
+ }
1130
+
1131
+ private updateCollapseIcons(index: number, arrow1: HTMLElement, arrow2: HTMLElement): void {
1132
+ if (!isNullOrUndefined(this.paneSettings[index])) {
1133
+ if (!isNullOrUndefined(this.paneSettings[index].collapsible)) {
1134
+ // eslint-disable-next-line
1135
+ this.paneSettings[index].collapsible ? removeClass([arrow2], [HIDE_ICON]) : addClass([arrow2], [HIDE_ICON]);
1136
+ if (!isNullOrUndefined(this.paneSettings[index + 1])) {
1137
+ // eslint-disable-next-line
1138
+ this.paneSettings[index + 1].collapsible ? removeClass([arrow1], [HIDE_ICON]) : addClass([arrow1], [HIDE_ICON]);
1139
+ }
1140
+ if (!isNullOrUndefined(this.paneSettings[index + 1])) {
1141
+ if ((this.paneSettings[index + 1].collapsible)) {
1142
+ // eslint-disable-next-line
1143
+ this.paneSettings[index + 1].collapsible ? removeClass([arrow1], [HIDE_ICON]) : addClass([arrow1], [HIDE_ICON]);
1144
+ }
1145
+ }
1146
+ }
1147
+ }
1148
+ }
1149
+
1150
+ private updateIconClass(): void {
1151
+ if (this.orientation === 'Horizontal') {
1152
+ this.leftArrow = ARROW_LEFT;
1153
+ this.rightArrow = ARROW_RIGHT;
1154
+ } else {
1155
+ this.leftArrow = ARROW_UP;
1156
+ this.rightArrow = ARROW_DOWN;
1157
+ }
1158
+ }
1159
+
1160
+ private createSeparator(i: number): HTMLElement {
1161
+ const separator: HTMLElement = this.createElement('div');
1162
+ this.allBars.push(separator);
1163
+ const arrow1: HTMLElement = this.createElement('button');
1164
+ const arrow2: HTMLElement = this.createElement('button');
1165
+ arrow1.setAttribute('tabindex', '-1');
1166
+ arrow2.setAttribute('tabindex', '-1');
1167
+ arrow1.setAttribute('aria-label', 'Toggle navigation');
1168
+ arrow2.setAttribute('aria-label', 'Toggle navigation');
1169
+ arrow1.setAttribute('type', 'button');
1170
+ arrow2.setAttribute('type', 'button');
1171
+ const size: string = isNullOrUndefined(this.separatorSize) ? '1px' : this.separatorSize + 'px';
1172
+ // eslint-disable-next-line
1173
+ const proxy: Splitter = this;
1174
+ if (this.orientation === 'Horizontal') {
1175
+ this.updateIconClass();
1176
+ addClass([arrow2], [NAVIGATE_ARROW, ARROW_LEFT, HIDE_ICON]);
1177
+ addClass([arrow1], [NAVIGATE_ARROW, ARROW_RIGHT, HIDE_ICON]);
1178
+ addClass([separator], [SPLIT_BAR, SPLIT_H_BAR]);
1179
+ separator.style.width = size;
1180
+ } else {
1181
+ addClass([arrow1], [NAVIGATE_ARROW, ARROW_DOWN, HIDE_ICON]);
1182
+ addClass([arrow2], [NAVIGATE_ARROW, ARROW_UP, HIDE_ICON]);
1183
+ addClass([separator], [SPLIT_BAR, SPLIT_V_BAR]);
1184
+ this.updateIconClass();
1185
+ separator.style.height = size;
1186
+ }
1187
+ this.addMouseActions(separator);
1188
+ separator.appendChild(arrow2);
1189
+ this.addResizeHandler(separator);
1190
+ separator.appendChild(arrow1);
1191
+ this.updateCollapseIcons(i, arrow1, arrow2);
1192
+ separator.setAttribute('tabindex', '0');
1193
+ if (this.enableReversePanes) {
1194
+ separator.setAttribute('dir', 'ltr');
1195
+ } else {
1196
+ separator.removeAttribute('dir');
1197
+ }
1198
+ separator.addEventListener('focus', () => {
1199
+ separator.classList.add(SPLIT_BAR_ACTIVE);
1200
+ proxy.currentSeparator = separator;
1201
+ proxy.getPaneDetails();
1202
+ });
1203
+ separator.addEventListener('blur', () => {
1204
+ separator.classList.remove(SPLIT_BAR_ACTIVE);
1205
+ });
1206
+ return separator;
1207
+ }
1208
+
1209
+ private updateResizablePanes(index: number): void {
1210
+ this.getPaneDetails();
1211
+ // eslint-disable-next-line
1212
+ this.isResizable() ? this.allPanes[index].classList.add(RESIZABLE_PANE) : this.allPanes[index].classList.remove(RESIZABLE_PANE);
1213
+ }
1214
+
1215
+ private addSeparator(target: HTMLElement): void {
1216
+ const childCount: number = this.allPanes.length;
1217
+ const clonedEle: HTMLCollection = <HTMLCollection>target.children;
1218
+ let separator: HTMLElement;
1219
+ let proxy: Splitter;
1220
+ for (let i: number = 0; i < childCount; i++) {
1221
+ if (i < childCount - 1) {
1222
+ separator = this.createSeparator(i);
1223
+ setStyleAttribute(<HTMLElement>separator, { 'order': (i * 2) + 1 });
1224
+ this.separatorOrder.push((i * 2) + 1);
1225
+ clonedEle[i].parentNode.appendChild(separator);
1226
+ this.currentSeparator = separator;
1227
+ separator.setAttribute('role', 'separator');
1228
+ separator.setAttribute('aria-orientation', this.orientation.toLowerCase());
1229
+ this.wireClickEvents();
1230
+ if (!isNullOrUndefined(separator)) {
1231
+ if (this.isResizable()) {
1232
+ EventHandler.add(separator, 'mousedown', this.onMouseDown, this);
1233
+ const eventName: string = (Browser.info.name === 'msie') ? 'pointerdown' : 'touchstart';
1234
+ EventHandler.add(separator, eventName, this.onMouseDown, this);
1235
+ separator.classList.add(RESIZABLE_BAR);
1236
+ this.updateResizablePanes(i);
1237
+ } else {
1238
+ addClass([select('.' + RESIZE_BAR, separator)], HIDE_HANDLER);
1239
+ }
1240
+ }
1241
+ } else {
1242
+ if (separator) {
1243
+ addClass([separator], LAST_BAR);
1244
+ }
1245
+ if (childCount > 1) {
1246
+ this.updateResizablePanes(i);
1247
+ }
1248
+ }
1249
+ }
1250
+ if (Browser.info.name === 'msie') {
1251
+ const allBar: NodeListOf<Element> = this.element.querySelectorAll('.e-splitter .e-resize-handler');
1252
+ for (let i: number = 0; i < allBar.length; i++) {
1253
+ const sepSize: number = isNullOrUndefined(this.separatorSize) ? 1 : this.separatorSize;
1254
+ (allBar[i] as HTMLElement).style.paddingLeft = sepSize / 2 + 'px';
1255
+ (allBar[i] as HTMLElement).style.paddingRight = sepSize / 2 + 'px';
1256
+ }
1257
+ }
1258
+ }
1259
+
1260
+ private isResizable(): boolean {
1261
+ let resizable: boolean = false;
1262
+ if ((!isNullOrUndefined(this.paneSettings[this.getPreviousPaneIndex()]) &&
1263
+ this.paneSettings[this.getPreviousPaneIndex()].resizable &&
1264
+ !isNullOrUndefined(this.paneSettings[this.getNextPaneIndex()]) &&
1265
+ this.paneSettings[this.getNextPaneIndex()].resizable) ||
1266
+ isNullOrUndefined(this.paneSettings[this.getNextPaneIndex()])) {
1267
+ resizable = true;
1268
+ }
1269
+
1270
+ return resizable;
1271
+ }
1272
+
1273
+ private addMouseActions(separator: HTMLElement): void {
1274
+ let sTout: ReturnType<typeof setTimeout>; let hoverTimeOut: ReturnType<typeof setTimeout>;
1275
+ separator.addEventListener('mouseenter', () => {
1276
+ /* istanbul ignore next */
1277
+ sTout = setTimeout(() => {
1278
+ addClass([separator], [SPLIT_BAR_HOVER]);
1279
+ }, this.iconsDelay);
1280
+ });
1281
+ separator.addEventListener('mouseleave', () => {
1282
+ clearTimeout(sTout);
1283
+ removeClass([separator], [SPLIT_BAR_HOVER]);
1284
+ });
1285
+ separator.addEventListener('mouseout', () => {
1286
+ clearTimeout(hoverTimeOut);
1287
+ });
1288
+ separator.addEventListener('mouseover', () => {
1289
+ /* istanbul ignore next */
1290
+ hoverTimeOut = setTimeout(() => {
1291
+ addClass([separator], [SPLIT_BAR_HOVER]);
1292
+ }, this.iconsDelay);
1293
+ });
1294
+ }
1295
+
1296
+ private getEventType(e: string): string {
1297
+ return (e.indexOf('mouse') > -1) ? 'mouse' : 'touch';
1298
+ }
1299
+
1300
+ private updateCurrentSeparator(target: HTMLElement): void {
1301
+ this.currentSeparator = this.isSeparator(target) ? target.parentElement : target;
1302
+ }
1303
+
1304
+ private isSeparator(target: HTMLElement): boolean {
1305
+ return (target.classList.contains(SPLIT_BAR) ? false : true);
1306
+ }
1307
+
1308
+ private isMouseEvent(e: MouseEvent | TouchEvent | PointerEvent | KeyboardEvent): boolean {
1309
+ let isMouse: boolean = false;
1310
+ if (this.getEventType(e.type) === 'mouse' || (!isNullOrUndefined((<PointerEvent>e).pointerType) &&
1311
+ this.getEventType((<PointerEvent>e).pointerType) === 'mouse')) {
1312
+ isMouse = true;
1313
+ }
1314
+ return isMouse;
1315
+ }
1316
+
1317
+ private updateCursorPosition(e: MouseEvent | TouchEvent | PointerEvent | KeyboardEvent, type: string): void {
1318
+ if (this.isMouseEvent(e)) {
1319
+ this.changeCoordinates({ x: (<MouseEvent>e).pageX, y: (<MouseEvent>e).pageY }, type);
1320
+ } else {
1321
+ const eventType: MouseEvent | Touch = Browser.info.name !== 'msie' ? (<TouchEvent>e).touches[0] : (<MouseEvent>e);
1322
+ this.changeCoordinates({ x: eventType.pageX, y: eventType.pageY }, type);
1323
+ }
1324
+ }
1325
+
1326
+ private changeCoordinates(coordinates: Coordinates, type: string): void {
1327
+ if (type === 'previous') {
1328
+ this.previousCoordinates = coordinates;
1329
+ } else {
1330
+ this.currentCoordinates = coordinates;
1331
+ }
1332
+ }
1333
+
1334
+ private reportWindowSize(): void {
1335
+ const paneCount: number = this.allPanes.length;
1336
+ if (!document.body.contains(this.element)) {
1337
+ document.defaultView.removeEventListener('resize', this.onReportWindowSize);
1338
+ return;
1339
+ }
1340
+ for (let i: number = 0; i < paneCount; i++) {
1341
+ if (isNullOrUndefined(this.paneSettings[i].size)) {
1342
+ this.allPanes[i].classList.remove(STATIC_PANE);
1343
+ }
1344
+ if (paneCount - 1 === i) {
1345
+ const staticPaneCount: number = this.element.querySelectorAll('.' + STATIC_PANE).length;
1346
+ if (staticPaneCount === paneCount) {
1347
+ removeClass([this.allPanes[i]], STATIC_PANE);
1348
+ }
1349
+ }
1350
+ }
1351
+ if (paneCount > 0) {
1352
+ setTimeout(() => {
1353
+ this.updateSplitterSize(true);
1354
+ }, 200);
1355
+ }
1356
+ }
1357
+
1358
+ private updateSplitterSize(iswindowResize?: boolean): void {
1359
+ let totalWidth: number = 0;
1360
+ const flexPaneIndexes: number[] = [];
1361
+ let flexCount: number = 0;
1362
+ const children: HTMLCollection = this.element.children;
1363
+ for (let i: number = 0, len: number = children.length; i < len; i++){
1364
+ totalWidth += this.orientation === 'Horizontal' ? (children[i] as HTMLElement).offsetWidth :
1365
+ (children[i] as HTMLElement).offsetHeight;
1366
+ }
1367
+ for (let j: number = 0, len: number = this.allBars.length; j < len; j++){
1368
+ totalWidth += this.orientation === 'Horizontal' ? parseInt(getComputedStyle(this.allBars[j]).marginLeft, 10) +
1369
+ parseInt(getComputedStyle(this.allBars[j]).marginLeft, 10) : parseInt(getComputedStyle(this.allBars[j]).marginTop, 10) +
1370
+ parseInt(getComputedStyle(this.allBars[j]).marginBottom, 10);
1371
+ }
1372
+ const diff: number = this.orientation === 'Horizontal' ? this.element.offsetWidth -
1373
+ ((this.border * 2) + totalWidth) :
1374
+ this.element.offsetHeight - ((this.border * 2) + totalWidth);
1375
+ for (let i: number = 0, len: number = this.allPanes.length; i < len; i++){
1376
+ if ( this.allPanes[ i ].innerText === '' ? !( this.paneSettings[ i ].size ) || !( this.allPanes[ i ].innerText === '' )
1377
+ : !( this.paneSettings[ i ].size ) && !( this.allPanes[ i ].innerText === '' ) )
1378
+ {
1379
+ flexPaneIndexes[flexCount] = i;
1380
+ flexCount++;
1381
+ }
1382
+ }
1383
+ const avgDiffWidth: number = diff / flexPaneIndexes.length;
1384
+ for ( let j: number = 0, len: number = flexPaneIndexes.length; j < len; j++){
1385
+ this.allPanes[flexPaneIndexes[j]].style.flexBasis = this.orientation === 'Horizontal' ?
1386
+ (this.allPanes[flexPaneIndexes[j]].offsetWidth + avgDiffWidth) + 'px' :
1387
+ (this.allPanes[flexPaneIndexes[j]].offsetHeight + avgDiffWidth) + 'px';
1388
+ }
1389
+ if (this.allPanes.length === 2 && iswindowResize) {
1390
+ const paneCount: number = this.allPanes.length;
1391
+ let minValue: number;
1392
+ let paneMinRange: number;
1393
+ const paneIndex: number = 0;
1394
+ let updatePane: HTMLElement;
1395
+ let flexPane: HTMLElement;
1396
+ for (let i: number = 0; i < paneCount; i++) {
1397
+ if (!isNullOrUndefined(this.paneSettings[i].min)) {
1398
+ paneMinRange = this.convertPixelToNumber((this.paneSettings[i].min).toString());
1399
+ if (this.paneSettings[i].min.indexOf('%') > 0) {
1400
+ paneMinRange = this.convertPercentageToPixel(this.paneSettings[i].min);
1401
+ }
1402
+ minValue = this.convertPixelToNumber((paneMinRange).toString());
1403
+ if ((this.orientation === 'Horizontal' ? this.allPanes[i].offsetWidth : this.allPanes[i].offsetHeight) < minValue) {
1404
+ if (i === paneIndex) {
1405
+ updatePane = this.allPanes[i];
1406
+ flexPane = this.allPanes[i + 1];
1407
+ } else {
1408
+ updatePane = this.allPanes[i];
1409
+ flexPane = this.allPanes[i - 1];
1410
+ }
1411
+ const sizeDiff: number = minValue - (this.orientation === 'Horizontal' ?
1412
+ this.allPanes[i].offsetWidth : this.allPanes[i].offsetHeight);
1413
+ const isPercent: boolean = updatePane.style.flexBasis.indexOf('%') > -1;
1414
+ let updatePaneOffset: number = this.orientation === 'Horizontal' ? updatePane.offsetWidth : updatePane.offsetHeight;
1415
+ updatePane.style.flexBasis = isPercent ? this.convertPixelToPercentage(updatePaneOffset + sizeDiff) + '%'
1416
+ : (updatePaneOffset + sizeDiff) + 'px';
1417
+ let flexPaneOffset: number = this.orientation === 'Horizontal' ? flexPane.offsetWidth : flexPane.offsetHeight;
1418
+ flexPane.style.flexBasis = flexPane.style.flexBasis.indexOf('%') > -1 ?
1419
+ this.convertPixelToPercentage(flexPaneOffset - sizeDiff) + '%' : (flexPaneOffset - sizeDiff) + 'px';
1420
+ }
1421
+ }
1422
+ }
1423
+ }
1424
+ }
1425
+
1426
+ private wireResizeEvents(): void {
1427
+ document.addEventListener('mousemove', this.onMouseMoveHandler, true);
1428
+ document.addEventListener('mouseup', this.onMouseUpHandler, true);
1429
+ const touchMoveEvent: string = (Browser.info.name === 'msie') ? 'pointermove' : 'touchmove';
1430
+ const touchEndEvent: string = (Browser.info.name === 'msie') ? 'pointerup' : 'touchend';
1431
+ document.addEventListener(touchMoveEvent, this.onTouchMoveHandler, true);
1432
+ document.addEventListener(touchEndEvent, this.onTouchEndHandler, true);
1433
+ }
1434
+
1435
+ private unwireResizeEvents(): void {
1436
+ this.element.ownerDocument.defaultView.removeEventListener('resize', this.onReportWindowSize);
1437
+ const touchMoveEvent: string = (Browser.info.name === 'msie') ? 'pointermove' : 'touchmove';
1438
+ const touchEndEvent: string = (Browser.info.name === 'msie') ? 'pointerup' : 'touchend';
1439
+ document.removeEventListener('mousemove', this.onMouseMoveHandler, true);
1440
+ document.removeEventListener('mouseup', this.onMouseUpHandler, true);
1441
+ document.removeEventListener(touchMoveEvent, this.onTouchMoveHandler, true);
1442
+ document.removeEventListener(touchEndEvent, this.onTouchEndHandler, true);
1443
+ }
1444
+
1445
+ private wireClickEvents(): void {
1446
+ EventHandler.add(this.currentSeparator, 'touchstart click', this.clickHandler, this);
1447
+ }
1448
+
1449
+ private clickHandler(e: Event): void {
1450
+ if (!(<HTMLElement>e.target).classList.contains(NAVIGATE_ARROW)) {
1451
+ const hoverBars: HTMLElement[] = selectAll('.' + ROOT + ' > .' + SPLIT_BAR + '.' + SPLIT_BAR_HOVER);
1452
+ if (hoverBars.length > 0) {
1453
+ removeClass(hoverBars, SPLIT_BAR_HOVER);
1454
+ }
1455
+ (<HTMLElement>e.target).classList.add(SPLIT_BAR_HOVER);
1456
+ }
1457
+ const icon: HTMLElement = (<HTMLElement>e.target);
1458
+ if (icon.classList.contains(ARROW_LEFT) || icon.classList.contains(ARROW_UP)) {
1459
+ this.collapseAction(e);
1460
+ }
1461
+ if (icon.classList.contains(ARROW_RIGHT) || icon.classList.contains(ARROW_DOWN)) {
1462
+ this.expandAction(e);
1463
+ }
1464
+ this.updateSplitterSize();
1465
+ }
1466
+
1467
+ private expandAction(e: Event): void {
1468
+ this.splitterDetails(e);
1469
+ const eventArgs: BeforeExpandEventArgs = this.beforeAction(e);
1470
+ if (this.expandFlag) {
1471
+ this.trigger('beforeExpand', eventArgs, (beforeExpandArgs: BeforeExpandEventArgs) => {
1472
+ if (!beforeExpandArgs.cancel) {
1473
+ this.expandPane(e);
1474
+ }
1475
+ const expandEventArgs: ExpandedEventArgs = this.afterAction(e);
1476
+ this.trigger('expanded', expandEventArgs);
1477
+ });
1478
+ } else {
1479
+ this.expandPane(e);
1480
+ }
1481
+ }
1482
+
1483
+ private expandPane(e: Event): void {
1484
+ this.removeStaticPanes();
1485
+ const collapseCount: number = this.element.querySelectorAll('.' + COLLAPSE_PANE).length;
1486
+ const flexStatus: boolean = (!this.previousPane.classList.contains(COLLAPSE_PANE) &&
1487
+ this.previousPane.classList.contains(STATIC_PANE) && !this.nextPane.classList.contains(COLLAPSE_PANE) &&
1488
+ !this.nextPane.classList.contains(EXPAND_PANE) && this.nextPane.nextElementSibling.classList.contains(PANE) &&
1489
+ !this.nextPane.nextElementSibling.classList.contains(STATIC_PANE) && !(collapseCount === this.allPanes.length - 2));
1490
+ const collapseClass: string[] = [COLLAPSE_PANE, PANE_HIDDEN];
1491
+ if (!this.previousPane.classList.contains(COLLAPSE_PANE)) {
1492
+ removeClass([this.nextPane], EXPAND_PANE);
1493
+ removeClass([this.previousPane], collapseClass);
1494
+ addClass([this.previousPane], EXPAND_PANE);
1495
+ addClass([this.nextPane], collapseClass);
1496
+ if (this.expandFlag) {
1497
+ this.updatePaneSettings(this.nextPaneIndex, true);
1498
+ }
1499
+ } else {
1500
+ removeClass([this.previousPane], collapseClass);
1501
+ removeClass([this.nextPane], EXPAND_PANE);
1502
+ if (this.expandFlag) {
1503
+ this.updatePaneSettings(this.prevPaneIndex, false);
1504
+ }
1505
+ }
1506
+ this.updateIconsOnExpand(e);
1507
+ this.previousPane.setAttribute('aria-expanded', 'true');
1508
+ this.nextPane.setAttribute('aria-expanded', 'false');
1509
+ this.updateFlexGrow(this.checkStaticPanes());
1510
+ if (flexStatus) {
1511
+ this.previousPane.classList.remove(EXPAND_PANE);
1512
+ this.previousPane.style.flexGrow = '';
1513
+ }
1514
+ }
1515
+
1516
+ private checkStaticPanes(): boolean {
1517
+ let staticPane: boolean = true;
1518
+ for (let i: number = 0; i < this.allPanes.length; i++) {
1519
+ if (!this.allPanes[i].classList.contains(COLLAPSE_PANE) && staticPane) {
1520
+ if (this.allPanes[i].classList.contains(STATIC_PANE)) {
1521
+ staticPane = true;
1522
+ } else {
1523
+ staticPane = false;
1524
+ }
1525
+ }
1526
+ }
1527
+ return staticPane;
1528
+ }
1529
+
1530
+ private updateFlexGrow(status: boolean): void {
1531
+ let collapseCount: number = 0;
1532
+ for (let j: number = 0; j < this.element.children.length; j++) {
1533
+ if (this.element.children[j].classList.contains(COLLAPSE_PANE)) {
1534
+ collapseCount = collapseCount + 1;
1535
+ }
1536
+ }
1537
+ const visiblePane: boolean = collapseCount === this.allPanes.length - 2;
1538
+ const panes: HTMLElement[] = this.allPanes;
1539
+ for (let i: number = 0; i < panes.length; i++) {
1540
+ panes[i].style.flexGrow = '';
1541
+ if (status && !this.nextPane.classList.contains(COLLAPSE_PANE)) {
1542
+ this.nextPane.style.flexGrow = '1';
1543
+ }
1544
+ if (visiblePane && this.allPanes[i].classList.contains(COLLAPSE_PANE) && this.paneSettings[i].size &&
1545
+ i !== this.allPanes.length-1) {
1546
+ panes[i].style.flexGrow = '';
1547
+ }
1548
+ if (panes[i].classList.contains(EXPAND_PANE)) {
1549
+ panes[i].style.flexGrow = '1';
1550
+ }
1551
+ else if (panes[i].classList.contains(COLLAPSE_PANE)) {
1552
+ panes[i].style.flexGrow = '0';
1553
+ }
1554
+ }
1555
+ }
1556
+
1557
+ private hideTargetBarIcon(targetBar: HTMLElement, targetArrow: string): void {
1558
+ addClass([select('.' + targetArrow, targetBar)], HIDE_ICON);
1559
+ }
1560
+
1561
+ private showTargetBarIcon(targetBar: HTMLElement, targetArrow: string): void {
1562
+ removeClass([select('.' + targetArrow, targetBar)], HIDE_ICON);
1563
+ }
1564
+
1565
+ private updateIconsOnCollapse(e: Event): void {
1566
+ this.splitterProperty();
1567
+ if (this.previousPane.classList.contains(COLLAPSE_PANE) && !this.nextPane.classList.contains(COLLAPSE_PANE)) {
1568
+ addClass([e.target as HTMLElement], HIDE_ICON);
1569
+ if (this.paneSettings[this.prevPaneIndex].collapsible) {
1570
+ this.showCurrentBarIcon();
1571
+ }
1572
+ this.resizableModel(this.currentBarIndex, false);
1573
+ if (this.previousPane.classList.contains(COLLAPSE_PANE) && !this.nextPane.classList.contains(COLLAPSE_PANE) &&
1574
+ !this.paneSettings[this.prevPaneIndex].collapsible) {
1575
+ this.hideTargetBarIcon(this.prevBar, this.rightArrow);
1576
+ }
1577
+ if (this.previousPane.previousElementSibling && !this.previousPane.previousElementSibling.classList.contains(COLLAPSE_PANE)) {
1578
+ if (this.previousPane.classList.contains(COLLAPSE_PANE) && this.paneSettings[this.prevPaneIndex].collapsible) {
1579
+ this.showTargetBarIcon(this.prevBar, this.leftArrow);
1580
+ } else if (!this.paneSettings[this.prevPaneIndex].collapsible) {
1581
+ this.hideTargetBarIcon(this.prevBar, this.leftArrow);
1582
+ }
1583
+ }
1584
+ if (!isNullOrUndefined(this.prevBar)) {
1585
+ this.resizableModel(this.currentBarIndex - 1, false);
1586
+ this.hideTargetBarIcon(this.prevBar, this.arrow);
1587
+ }
1588
+ if (!this.paneSettings[this.prevPaneIndex].collapsible) {
1589
+ this.hideTargetBarIcon(this.currentSeparator, this.rightArrow);
1590
+ }
1591
+ } else if (!this.splitInstance.prevPaneCollapsed && !this.splitInstance.nextPaneExpanded) {
1592
+ if (this.paneSettings[this.currentBarIndex].resizable) {
1593
+ this.resizableModel(this.currentBarIndex, true);
1594
+ }
1595
+ if (!this.splitInstance.nextPaneNextEle.classList.contains(COLLAPSE_PANE) &&
1596
+ this.paneSettings[this.currentBarIndex + 1].resizable) {
1597
+ this.resizableModel(this.currentBarIndex + 1, true);
1598
+ }
1599
+ if (!this.paneSettings[this.currentBarIndex].collapsible) {
1600
+ addClass([e.target as HTMLElement], HIDE_ICON);
1601
+ }
1602
+ if (this.previousPane && this.prevPaneIndex === 0 && (this.paneSettings[this.prevPaneIndex].collapsible)) {
1603
+ this.showTargetBarIcon(this.currentSeparator, this.leftArrow);
1604
+ }
1605
+ if (this.nextPane && this.nextPaneIndex === this.allPanes.length - 1 && (this.paneSettings[this.nextPaneIndex].collapsible)) {
1606
+ this.showTargetBarIcon(this.getPrevBar(this.nextPaneIndex), this.rightArrow);
1607
+ }
1608
+ if (!(this.previousPane.classList.contains(COLLAPSE_PANE)) && this.paneSettings[this.nextPaneIndex].collapsible) {
1609
+ this.showTargetBarIcon(this.currentSeparator, this.rightArrow);
1610
+ }
1611
+ if (!isNullOrUndefined(this.nextBar)) {
1612
+ if (this.nextPane.nextElementSibling && (this.nextPane.nextElementSibling.classList.contains(COLLAPSE_PANE) &&
1613
+ this.paneSettings[this.nextPaneIndex + 1].collapsible) ||
1614
+ (!this.nextPane.nextElementSibling.classList.contains(COLLAPSE_PANE) &&
1615
+ this.paneSettings[this.nextPaneIndex].collapsible)) {
1616
+ this.showTargetBarIcon(this.nextBar, this.leftArrow);
1617
+ } else if (!this.paneSettings[this.splitInstance.nextPaneIndex + 1].collapsible &&
1618
+ this.paneSettings[this.currentBarIndex]) {
1619
+ this.hideTargetBarIcon(this.nextBar, this.arrow);
1620
+ }
1621
+ }
1622
+ if (!(this.nextPaneIndex === this.allPanes.length - 1) && this.nextPane.nextElementSibling &&
1623
+ !this.nextPane.classList.contains(COLLAPSE_PANE) && !this.nextPane.nextElementSibling.classList.contains(COLLAPSE_PANE)
1624
+ && !this.paneSettings[this.nextPaneIndex + 1].collapsible) {
1625
+ this.hideTargetBarIcon(this.nextBar, this.rightArrow);
1626
+ }
1627
+ }
1628
+ }
1629
+
1630
+ private collapseAction(e: Event): void {
1631
+ this.splitterDetails(e);
1632
+ const eventArgs: BeforeExpandEventArgs = this.beforeAction(e);
1633
+ if (this.collapseFlag) {
1634
+ this.collapsePane(e);
1635
+ } else {
1636
+ this.trigger('beforeCollapse', eventArgs, (beforeCollapseArgs: BeforeExpandEventArgs) => {
1637
+ if (!beforeCollapseArgs.cancel) {
1638
+ this.collapsePane(e);
1639
+ const collapseEventArgs: ExpandedEventArgs = this.afterAction(e);
1640
+ this.trigger('collapsed', collapseEventArgs);
1641
+ }
1642
+ });
1643
+ }
1644
+ }
1645
+
1646
+ private collapsePane(e: Event): void {
1647
+ this.removeStaticPanes();
1648
+ const collapseCount: number = this.element.querySelectorAll('.' + COLLAPSE_PANE).length;
1649
+ const flexStatus: boolean = (this.previousPane.classList.contains(STATIC_PANE) &&
1650
+ !this.previousPane.classList.contains(COLLAPSE_PANE) && !this.nextPane.classList.contains(COLLAPSE_PANE) &&
1651
+ this.nextPane.nextElementSibling.classList.contains(PANE) &&
1652
+ !this.nextPane.nextElementSibling.classList.contains(STATIC_PANE) &&
1653
+ !this.nextPane.nextElementSibling.classList.contains(COLLAPSE_PANE) &&
1654
+ !(collapseCount === this.allPanes.length - 2)) || (this.nextPane.classList.contains(COLLAPSE_PANE) &&
1655
+ !this.previousPane.classList.contains(STATIC_PANE) && this.nextPane.classList.contains(STATIC_PANE));
1656
+ const collapseClass: string[] = [COLLAPSE_PANE, PANE_HIDDEN];
1657
+ if (this.nextPane.classList.contains(COLLAPSE_PANE)) {
1658
+ removeClass([this.previousPane], EXPAND_PANE);
1659
+ removeClass([this.nextPane], collapseClass);
1660
+ if (!this.collapseFlag) {
1661
+ this.updatePaneSettings(this.nextPaneIndex, false);
1662
+ }
1663
+ } else {
1664
+ removeClass([this.previousPane], EXPAND_PANE);
1665
+ removeClass([this.nextPane], collapseClass);
1666
+ addClass([this.nextPane], EXPAND_PANE);
1667
+ addClass([this.previousPane], collapseClass);
1668
+ if (!this.collapseFlag) {
1669
+ this.updatePaneSettings(this.prevPaneIndex, true);
1670
+ }
1671
+ }
1672
+ this.updateIconsOnCollapse(e);
1673
+ this.previousPane.setAttribute('aria-expanded', 'false');
1674
+ this.nextPane.setAttribute('aria-expanded', 'true');
1675
+ this.updateFlexGrow(this.checkStaticPanes());
1676
+ if (flexStatus) {
1677
+ this.nextPane.classList.remove(EXPAND_PANE);
1678
+ this.nextPane.style.flexGrow = '';
1679
+ }
1680
+ }
1681
+
1682
+ private removeStaticPanes(): void {
1683
+ for (let i: number = 0; i < this.allPanes.length; i++) {
1684
+ if (isNullOrUndefined(this.paneSettings[i].size)) {
1685
+ this.allPanes[i].classList.remove(STATIC_PANE);
1686
+ }
1687
+ }
1688
+ }
1689
+
1690
+ private beforeAction(e: Event): BeforeExpandEventArgs {
1691
+ const eventArgs: BeforeExpandEventArgs = {
1692
+ element: this.element,
1693
+ event: e,
1694
+ pane: [this.previousPane, this.nextPane],
1695
+ index: [this.prevPaneIndex, this.nextPaneIndex],
1696
+ separator: this.currentSeparator,
1697
+ cancel: false
1698
+ };
1699
+ return eventArgs;
1700
+ }
1701
+
1702
+ private updatePaneSettings(index: number, collapsed: boolean): void {
1703
+ const paneValues: PanePropertiesModel[] = this.paneSettings;
1704
+ paneValues[index].collapsed = collapsed;
1705
+ this.setProperties({ 'paneSettings': paneValues }, true);
1706
+ }
1707
+ private splitterProperty(): void {
1708
+ this.splitInstance = {
1709
+ currentBarIndex: this.currentBarIndex,
1710
+ nextPaneCollapsible: this.nextPane.classList.contains(COLLAPSIBLE),
1711
+ prevPaneCollapsible: this.previousPane.classList.contains(COLLAPSIBLE),
1712
+ prevPaneExpanded: this.previousPane.classList.contains(EXPAND_PANE),
1713
+ nextPaneExpanded: this.nextPane.classList.contains(EXPAND_PANE),
1714
+ nextPaneCollapsed: this.nextPane.classList.contains(COLLAPSE_PANE),
1715
+ prevPaneCollapsed: this.previousPane.classList.contains(COLLAPSE_PANE),
1716
+ nextPaneIndex: this.getNextPaneIndex(),
1717
+ prevPaneIndex: this.getPreviousPaneIndex(),
1718
+ nextPaneNextEle: this.nextPane.nextElementSibling as HTMLElement,
1719
+ prevPanePreEle: this.previousPane.previousElementSibling as HTMLElement
1720
+ };
1721
+ }
1722
+
1723
+ private showCurrentBarIcon(): void {
1724
+ removeClass([select('.' + this.arrow, this.currentSeparator)], HIDE_ICON);
1725
+ }
1726
+
1727
+ private updateIconsOnExpand(e: Event): void {
1728
+ this.splitterProperty();
1729
+ addClass([e.target as HTMLElement], HIDE_ICON);
1730
+ if (!this.splitInstance.prevPaneExpanded && !this.splitInstance.nextPaneCollapsed) {
1731
+ if (this.paneSettings[this.prevPaneIndex].collapsible) {
1732
+ this.showCurrentBarIcon();
1733
+ }
1734
+ if (this.paneSettings[this.nextPaneIndex].collapsible) {
1735
+ removeClass([e.target as HTMLElement], HIDE_ICON);
1736
+ }
1737
+ if (this.paneSettings[this.currentBarIndex].resizable) {
1738
+ this.resizableModel(this.currentBarIndex, true);
1739
+ }
1740
+ if (!isNullOrUndefined(this.prevBar) &&
1741
+ !this.splitInstance.prevPanePreEle.classList.contains(COLLAPSE_PANE)) {
1742
+ if (this.paneSettings[this.currentBarIndex - 1].resizable) {
1743
+ this.resizableModel(this.currentBarIndex - 1, true);
1744
+ }
1745
+ if (this.paneSettings[this.prevPaneIndex].collapsible) {
1746
+ this.showTargetBarIcon(this.prevBar, this.rightArrow);
1747
+ }
1748
+ if (!this.paneSettings[this.currentBarIndex - 1].collapsible) {
1749
+ this.hideTargetBarIcon(this.prevBar, this.arrow);
1750
+ if (this.paneSettings[this.currentBarIndex].collapsible &&
1751
+ !this.paneSettings[this.currentBarIndex + 1].collapsible) {
1752
+ this.hideTargetBarIcon(this.currentSeparator, this.rightArrow);
1753
+ }
1754
+ } else if (this.paneSettings[this.currentBarIndex].collapsible &&
1755
+ !this.paneSettings[this.currentBarIndex + 1].collapsible) {
1756
+ this.hideTargetBarIcon(this.currentSeparator, this.rightArrow);
1757
+ }
1758
+ } else {
1759
+ if (this.previousPane.previousElementSibling && this.paneSettings[this.prevPaneIndex].collapsible &&
1760
+ (this.previousPane.previousElementSibling.classList.contains(COLLAPSE_PANE) &&
1761
+ this.paneSettings[this.prevPaneIndex - 1].collapsible)) {
1762
+ this.showTargetBarIcon(this.prevBar, this.rightArrow);
1763
+ }
1764
+ if (!this.paneSettings[this.currentBarIndex + 1].collapsible) {
1765
+ this.hideTargetBarIcon(this.currentSeparator, this.rightArrow);
1766
+ }
1767
+ }
1768
+ } else if (this.splitInstance.prevPaneExpanded && this.splitInstance.nextPaneCollapsed) {
1769
+ this.resizableModel(this.currentBarIndex, false);
1770
+ this.resizableModel(this.currentBarIndex + 1, false);
1771
+ if (this.paneSettings[this.nextPaneIndex].collapsible) {
1772
+ this.showCurrentBarIcon();
1773
+ }
1774
+ if (!isNullOrUndefined(this.nextBar)) {
1775
+ this.hideTargetBarIcon(this.nextBar, this.arrow);
1776
+ }
1777
+ if (this.nextPane && this.nextPaneIndex === this.allPanes.length - 1 && (!this.paneSettings[this.nextPaneIndex].collapsible &&
1778
+ this.splitInstance.nextPaneCollapsed)) {
1779
+ this.hideTargetBarIcon(this.currentSeparator, this.arrow);
1780
+ }
1781
+ if (!(this.nextPaneIndex === this.allPanes.length - 1) && this.nextPane.nextElementSibling &&
1782
+ this.nextPane.classList.contains(COLLAPSE_PANE) &&
1783
+ !this.nextPane.nextElementSibling.classList.contains(COLLAPSE_PANE)
1784
+ && this.paneSettings[this.nextPaneIndex].collapsible) {
1785
+ this.showTargetBarIcon(this.nextBar, this.rightArrow);
1786
+ }
1787
+ }
1788
+ }
1789
+
1790
+ private afterAction(e: Event): ExpandedEventArgs {
1791
+ const eventArgs: ExpandedEventArgs = {
1792
+ element: this.element,
1793
+ event: e,
1794
+ pane: [this.previousPane, this.nextPane],
1795
+ index: [this.prevPaneIndex, this.nextPaneIndex],
1796
+ separator: this.currentSeparator
1797
+ };
1798
+ return eventArgs;
1799
+ }
1800
+
1801
+ private currentIndex(e: Event): void {
1802
+ this.currentBarIndex = this.getOrderIndex(parseInt((<HTMLElement>e.target).parentElement.style.order, 10), 'splitbar');
1803
+ }
1804
+
1805
+ private getSeparatorIndex(target?: HTMLElement): number {
1806
+ let array: HTMLElement[] = [].slice.call(this.allBars);
1807
+ array = this.enableReversePanes ? array.reverse() : array;
1808
+ return array.indexOf(target);
1809
+ }
1810
+
1811
+ private getPrevBar(currentBar: number): HTMLElement {
1812
+ const prevbar: HTMLElement = this.allBars[(currentBar - 1)];
1813
+ return prevbar;
1814
+ }
1815
+
1816
+ private getNextBar(currentBar: number): HTMLElement {
1817
+ const prevbar: HTMLElement = this.allBars[(currentBar + 1)];
1818
+ return prevbar;
1819
+ }
1820
+
1821
+ private updateBars(index: number): void {
1822
+ this.prevBar = this.getPrevBar(index);
1823
+ this.nextBar = this.getNextBar(index);
1824
+ }
1825
+
1826
+ private splitterDetails(e: Event): void {
1827
+ if (this.orientation === 'Horizontal') {
1828
+ this.arrow = (<HTMLElement>e.target).classList.contains(ARROW_LEFT) ? ARROW_RIGHT : ARROW_LEFT;
1829
+ } else {
1830
+ this.arrow = (<HTMLElement>e.target).classList.contains(ARROW_UP) ? ARROW_DOWN : ARROW_UP;
1831
+ }
1832
+ this.updateCurrentSeparator(e.target as HTMLElement);
1833
+ this.currentIndex(e);
1834
+ this.updateBars(this.currentBarIndex);
1835
+ this.getPaneDetails();
1836
+ }
1837
+
1838
+ private triggerResizing(e: MouseEvent | TouchEvent | PointerEvent | KeyboardEvent): void {
1839
+ const eventArgs: ResizingEventArgs = {
1840
+ element: this.element,
1841
+ event: e,
1842
+ pane: [this.previousPane, this.nextPane],
1843
+ index: [this.prevPaneIndex, this.nextPaneIndex],
1844
+ paneSize: [this.prePaneDimenson, this.nextPaneDimension],
1845
+ separator: this.currentSeparator
1846
+ };
1847
+ this.trigger('resizing', eventArgs);
1848
+ }
1849
+
1850
+ private onMouseDown(e: MouseEvent | TouchEvent | PointerEvent | KeyboardEvent): void {
1851
+ e.preventDefault();
1852
+ const target: HTMLElement = e.target as HTMLElement;
1853
+ if (target.classList.contains(NAVIGATE_ARROW)) {
1854
+ return;
1855
+ }
1856
+ this.updateCurrentSeparator(target);
1857
+ addClass([this.currentSeparator], SPLIT_BAR_ACTIVE);
1858
+ this.updateCursorPosition(e, 'previous');
1859
+ this.getPaneDetails();
1860
+ const eventArgs: ResizeEventArgs = {
1861
+ element: this.element,
1862
+ event: e,
1863
+ pane: [this.previousPane, this.nextPane],
1864
+ index: [this.getPreviousPaneIndex(), this.getNextPaneIndex()],
1865
+ separator: this.currentSeparator,
1866
+ cancel: false
1867
+ };
1868
+ for (let i: number = 0; i < this.element.querySelectorAll('iframe').length; i++) {
1869
+ this.element.querySelectorAll('iframe')[i].style.pointerEvents = 'none';
1870
+ }
1871
+ this.trigger('resizeStart', eventArgs, (resizeStartArgs: ResizeEventArgs) => {
1872
+ if (!resizeStartArgs.cancel) {
1873
+ this.wireResizeEvents();
1874
+ this.checkPaneSize(e);
1875
+ }
1876
+ });
1877
+ }
1878
+
1879
+ private updatePaneFlexBasis(pane: HTMLElement): number {
1880
+ let previous: number;
1881
+ if (pane.style.flexBasis.indexOf('%') > 0) {
1882
+ previous = this.removePercentageUnit(pane.style.flexBasis);
1883
+ } else {
1884
+ if (pane.style.flexBasis !== '') {
1885
+ previous = this.convertPixelToPercentage(this.convertPixelToNumber(pane.style.flexBasis));
1886
+ } else {
1887
+ const offset: number = (this.orientation === 'Horizontal') ? (pane.offsetWidth) : (pane.offsetHeight);
1888
+ previous = this.convertPixelToPercentage(offset);
1889
+ }
1890
+ }
1891
+ return previous;
1892
+ }
1893
+
1894
+ private removePercentageUnit(value: string): number {
1895
+ return parseFloat(value.slice(0, value.indexOf('%')));
1896
+ }
1897
+
1898
+ private convertPercentageToPixel(value: string, targetElement?: HTMLElement): number {
1899
+ const percentage: string = value.toString();
1900
+ let convertedValue: number;
1901
+ if (percentage.indexOf('%') > -1) {
1902
+ convertedValue = parseFloat(percentage.slice(0, percentage.indexOf('%')));
1903
+ let offsetValue: number;
1904
+ if (!isNullOrUndefined(targetElement)) {
1905
+ offsetValue = this.panesDimensions[this.allPanes.indexOf(targetElement)];
1906
+ } else {
1907
+ offsetValue = (this.orientation === 'Horizontal') ? this.element.offsetWidth : this.element.offsetHeight;
1908
+ }
1909
+ convertedValue = Math.ceil(offsetValue * (convertedValue / 100));
1910
+ } else {
1911
+ convertedValue = parseInt(percentage, 10);
1912
+ }
1913
+ return convertedValue;
1914
+ }
1915
+
1916
+ private convertPixelToPercentage(value: number): number {
1917
+ const offsetValue: number = (this.orientation === 'Horizontal') ? this.element.offsetWidth : this.element.offsetHeight;
1918
+ return (value / offsetValue) * 100;
1919
+ }
1920
+
1921
+ private convertPixelToNumber(value: string): number {
1922
+ if (value.indexOf('p') > -1) {
1923
+ return parseFloat(value.slice(0, value.indexOf('p')));
1924
+ } else {
1925
+ return parseFloat(value);
1926
+ }
1927
+ }
1928
+
1929
+ private calcDragPosition (rectValue: number, offsetValue: number): number {
1930
+ const separatorPosition: number = this.orientation === 'Horizontal' ? ( this.currentCoordinates.x - rectValue) :
1931
+ (this.currentCoordinates.y - rectValue);
1932
+ let separator: number;
1933
+ separator = separatorPosition / offsetValue;
1934
+ separator = (separator > 1) ? 1 : (separator < 0) ? 0 : separator;
1935
+ return separator * offsetValue;
1936
+ }
1937
+
1938
+ private getSeparatorPosition(e: MouseEvent | TouchEvent | PointerEvent): number {
1939
+ this.updateCursorPosition(e, 'current');
1940
+ const rectBound: number = (this.orientation === 'Horizontal') ? this.element.getBoundingClientRect().left + window.scrollX :
1941
+ this.element.getBoundingClientRect().top + window.scrollY;
1942
+ const offSet: number = (this.orientation === 'Horizontal') ? this.element.offsetWidth : this.element.offsetHeight;
1943
+ return this.calcDragPosition(rectBound, offSet);
1944
+ }
1945
+
1946
+ private getMinMax(paneIndex: number, target: HTMLElement, selection: string): number {
1947
+ const defaultVal: number = selection === 'min' ? 0 : null;
1948
+ // eslint-disable-next-line
1949
+ let paneValue: any = null;
1950
+ if (selection === 'min') {
1951
+ if (!isNullOrUndefined(this.paneSettings[paneIndex]) &&
1952
+ !isNullOrUndefined(this.paneSettings[paneIndex].min)) {
1953
+ paneValue = this.paneSettings[paneIndex].min;
1954
+ }
1955
+ } else {
1956
+ if (!isNullOrUndefined(this.paneSettings[paneIndex]) &&
1957
+ !isNullOrUndefined(this.paneSettings[paneIndex].max)) {
1958
+ paneValue = this.paneSettings[paneIndex].max;
1959
+ }
1960
+ }
1961
+ if (this.paneSettings.length > 0 && !isNullOrUndefined(this.paneSettings[paneIndex]) &&
1962
+ !isNullOrUndefined(paneValue)) {
1963
+ if (paneValue.indexOf('%') > 0) {
1964
+ paneValue = this.convertPercentageToPixel(paneValue).toString();
1965
+ }
1966
+ return this.convertPixelToNumber(paneValue);
1967
+ } else {
1968
+ return defaultVal;
1969
+ }
1970
+ }
1971
+
1972
+ private getPreviousPaneIndex(): number {
1973
+ const separatorIndex: number = this.enableReversePanes ? parseInt(this.currentSeparator.style.order, 10) + 1 :
1974
+ parseInt(this.currentSeparator.style.order, 10) - 1;
1975
+ return this.getOrderIndex(separatorIndex, 'pane');
1976
+ }
1977
+
1978
+ private getNextPaneIndex(): number {
1979
+ const separatorIndex: number = this.enableReversePanes ? parseInt(this.currentSeparator.style.order, 10) - 1 :
1980
+ parseInt(this.currentSeparator.style.order, 10) + 1;
1981
+ return this.getOrderIndex(separatorIndex, 'pane');
1982
+ }
1983
+
1984
+ private getPaneDetails(): void {
1985
+ let prevPane: HTMLElement = null;
1986
+ let nextPane: HTMLElement = null;
1987
+ this.order = parseInt(this.currentSeparator.style.order, 10);
1988
+ if (this.allPanes.length > 1) {
1989
+ prevPane = this.getPrevPane(this.order);
1990
+ nextPane = this.getNextPane(this.order);
1991
+ }
1992
+ if (prevPane && nextPane) {
1993
+ this.previousPane = prevPane;
1994
+ this.nextPane = nextPane;
1995
+ this.prevPaneIndex = this.getPreviousPaneIndex();
1996
+ this.nextPaneIndex = this.getNextPaneIndex();
1997
+ } else {
1998
+ return;
1999
+ }
2000
+ }
2001
+
2002
+ private getPaneHeight(pane: HTMLElement): string {
2003
+ return ((this.orientation === 'Horizontal') ? pane.offsetWidth.toString() :
2004
+ pane.offsetHeight.toString());
2005
+ }
2006
+
2007
+ private isValidSize(paneIndex: number): boolean {
2008
+ let isValid: boolean = false;
2009
+ if (!isNullOrUndefined(this.paneSettings[paneIndex]) &&
2010
+ !isNullOrUndefined(this.paneSettings[paneIndex].size) &&
2011
+ this.paneSettings[paneIndex].size.indexOf('%') > -1) {
2012
+ isValid = true;
2013
+ }
2014
+ return isValid;
2015
+ }
2016
+
2017
+ private getPaneDimensions(): void {
2018
+ this.previousPaneHeightWidth = (this.previousPane.style.flexBasis === '') ? this.getPaneHeight(this.previousPane) :
2019
+ this.previousPane.style.flexBasis;
2020
+ this.nextPaneHeightWidth = (this.nextPane.style.flexBasis === '') ? this.getPaneHeight(this.nextPane) :
2021
+ this.nextPane.style.flexBasis;
2022
+ if (this.isValidSize(this.prevPaneIndex)) {
2023
+ this.previousPaneHeightWidth = this.convertPercentageToPixel(this.previousPaneHeightWidth).toString();
2024
+ this.updatePrePaneInPercentage = true;
2025
+ }
2026
+ if (this.isValidSize(this.nextPaneIndex)) {
2027
+ this.nextPaneHeightWidth = this.convertPercentageToPixel(this.nextPaneHeightWidth).toString();
2028
+ this.updateNextPaneInPercentage = true;
2029
+ }
2030
+ this.prePaneDimenson = this.convertPixelToNumber(this.previousPaneHeightWidth.toString());
2031
+ this.nextPaneDimension = this.convertPixelToNumber(this.nextPaneHeightWidth.toString());
2032
+ }
2033
+
2034
+ private checkCoordinates(pageX: number, pageY: number): boolean {
2035
+ let coordinatesChanged: boolean = true;
2036
+ if ((pageX === this.previousCoordinates.x || pageY === this.previousCoordinates.y)) {
2037
+ coordinatesChanged = false;
2038
+ }
2039
+ return coordinatesChanged;
2040
+ }
2041
+
2042
+ private isCursorMoved(e: MouseEvent | TouchEvent | PointerEvent): boolean {
2043
+ let cursorMoved: boolean = true;
2044
+ if (this.getEventType(e.type) === 'mouse' || (!isNullOrUndefined((<PointerEvent>e).pointerType)) &&
2045
+ this.getEventType((<PointerEvent>e).pointerType) === 'mouse') {
2046
+ cursorMoved = this.checkCoordinates((<MouseEvent>e).pageX, (<MouseEvent>e).pageY);
2047
+ } else {
2048
+ cursorMoved = (Browser.info.name !== 'msie') ?
2049
+ this.checkCoordinates((<TouchEvent>e).touches[0].pageX, (<TouchEvent>e).touches[0].pageY) :
2050
+ this.checkCoordinates((<MouseEvent>e).pageX, (<MouseEvent>e).pageY);
2051
+ }
2052
+ return cursorMoved;
2053
+ }
2054
+
2055
+ private getBorder(): void {
2056
+ this.border = 0;
2057
+ const border: number = this.orientation === 'Horizontal' ? ((this.element.offsetWidth - this.element.clientWidth) / 2) :
2058
+ (this.element.offsetHeight - this.element.clientHeight) / 2;
2059
+ this.border = Browser.info.name !== 'chrome' ? this.border : border;
2060
+ }
2061
+
2062
+ private onMouseMove(e: MouseEvent | TouchEvent | PointerEvent): void {
2063
+ if (!this.isCursorMoved(e)) {
2064
+ return;
2065
+ }
2066
+ this.getPaneDetails();
2067
+ this.getPaneDimensions();
2068
+ this.triggerResizing(e);
2069
+ const left: number = this.validateDraggedPosition(this.getSeparatorPosition(e), this.prePaneDimenson, this.nextPaneDimension);
2070
+ let separatorNewPosition: number;
2071
+ this.getBorder();
2072
+ if (this.orientation === 'Horizontal') {
2073
+ separatorNewPosition = (this.element.getBoundingClientRect().left + left) -
2074
+ this.currentSeparator.getBoundingClientRect().left + this.border;
2075
+ } else {
2076
+ separatorNewPosition = (this.element.getBoundingClientRect().top + left) -
2077
+ this.currentSeparator.getBoundingClientRect().top + this.border;
2078
+ }
2079
+ this.nextPaneHeightWidth =
2080
+ (typeof (this.nextPaneHeightWidth) === 'string' && this.nextPaneHeightWidth.indexOf('p') > -1) ?
2081
+ this.convertPixelToNumber(this.nextPaneHeightWidth) : parseInt(this.nextPaneHeightWidth, 10);
2082
+ this.prevPaneCurrentWidth = separatorNewPosition + this.convertPixelToNumber(this.previousPaneHeightWidth);
2083
+ this.nextPaneCurrentWidth = this.nextPaneHeightWidth - separatorNewPosition;
2084
+ this.validateMinMaxValues();
2085
+ if (this.nextPaneCurrentWidth < 0) {
2086
+ this.nextPaneCurrentWidth = 0;
2087
+ }
2088
+ /* istanbul ignore next */
2089
+ if (this.prevPaneCurrentWidth < 0) {
2090
+ this.prevPaneCurrentWidth = 0;
2091
+ }
2092
+ if ((this.nextPaneCurrentWidth + this.prevPaneCurrentWidth) > this.totalWidth) {
2093
+ if (this.nextPaneCurrentWidth < this.prevPaneCurrentWidth) {
2094
+ this.prevPaneCurrentWidth = this.prevPaneCurrentWidth - ((this.nextPaneCurrentWidth + this.prevPaneCurrentWidth)
2095
+ - this.totalWidth);
2096
+ } else {
2097
+ this.nextPaneCurrentWidth = this.nextPaneCurrentWidth - ((this.nextPaneCurrentWidth + this.prevPaneCurrentWidth)
2098
+ - this.totalWidth);
2099
+ }
2100
+ }
2101
+ /* istanbul ignore next */
2102
+ if ((this.nextPaneCurrentWidth + this.prevPaneCurrentWidth) < this.totalWidth) {
2103
+ const difference: number = this.totalWidth - ((this.nextPaneCurrentWidth + this.prevPaneCurrentWidth));
2104
+ this.nextPaneCurrentWidth = this.nextPaneCurrentWidth + difference;
2105
+ }
2106
+ this.calculateCurrentDimensions();
2107
+ this.addStaticPaneClass();
2108
+ this.previousPane.style.flexBasis = this.prevPaneCurrentWidth;
2109
+ this.nextPane.style.flexBasis = this.nextPaneCurrentWidth;
2110
+ if (!(this.allPanes.length > 2)) {
2111
+ this.updateSplitterSize();
2112
+ }
2113
+ }
2114
+
2115
+ // eslint-disable-next-line
2116
+ private validateMinRange(paneIndex: number, paneCurrentWidth: number, pane: HTMLElement): number {
2117
+ let paneMinRange: string | number = null;
2118
+ let paneMinDimensions: number;
2119
+ let difference: number = 0;
2120
+ let validatedVal: number;
2121
+ if (!isNullOrUndefined(this.paneSettings[paneIndex]) && !isNullOrUndefined(this.paneSettings[paneIndex].min)) {
2122
+ paneMinRange = this.paneSettings[paneIndex].min.toString();
2123
+ }
2124
+ if (!isNullOrUndefined(paneMinRange)) {
2125
+ if ((<string>paneMinRange).indexOf('%') > 0) {
2126
+ paneMinRange = this.convertPercentageToPixel((<string>paneMinRange)).toString();
2127
+ }
2128
+ paneMinDimensions = this.convertPixelToNumber((<string>paneMinRange));
2129
+ if (paneCurrentWidth < paneMinDimensions) {
2130
+ difference = (paneCurrentWidth - paneMinDimensions) <= 0 ? 0 :
2131
+ (paneCurrentWidth - paneMinDimensions);
2132
+ this.totalWidth = this.totalWidth - difference;
2133
+ this.totalPercent = this.convertPixelToPercentage(this.totalWidth);
2134
+ validatedVal = paneMinDimensions;
2135
+ }
2136
+ }
2137
+ return isNullOrUndefined(validatedVal) ? paneCurrentWidth : validatedVal;
2138
+ }
2139
+
2140
+ // eslint-disable-next-line
2141
+ private validateMaxRange(paneIndex: number, paneCurrentWidth: number, pane: HTMLElement): number {
2142
+ let paneMaxRange: string | number = null;
2143
+ let paneMaxDimensions: number;
2144
+ let validatedVal: number;
2145
+ if (!isNullOrUndefined(this.paneSettings[paneIndex]) && !isNullOrUndefined(this.paneSettings[paneIndex].max)) {
2146
+ paneMaxRange = this.paneSettings[paneIndex].max.toString();
2147
+ }
2148
+ if (!isNullOrUndefined(paneMaxRange)) {
2149
+ if ((<string>paneMaxRange).indexOf('%') > 0) {
2150
+ paneMaxRange = this.convertPercentageToPixel(<string>paneMaxRange).toString();
2151
+ }
2152
+ paneMaxDimensions = this.convertPixelToNumber(<string>paneMaxRange);
2153
+ if (paneCurrentWidth > paneMaxDimensions) {
2154
+ this.totalWidth = this.totalWidth - (paneCurrentWidth - paneMaxDimensions);
2155
+ this.totalPercent = this.convertPixelToPercentage(this.totalWidth);
2156
+ validatedVal = paneMaxDimensions;
2157
+ }
2158
+ }
2159
+ return isNullOrUndefined(validatedVal) ? paneCurrentWidth : validatedVal;
2160
+ }
2161
+
2162
+ private validateMinMaxValues(): void {
2163
+ //validate previous pane minimum range
2164
+ this.prevPaneCurrentWidth = this.validateMinRange(this.prevPaneIndex, this.prevPaneCurrentWidth, this.previousPane);
2165
+ // Validate next pane minimum range
2166
+ this.nextPaneCurrentWidth = this.validateMinRange(this.nextPaneIndex, this.nextPaneCurrentWidth, this.nextPane);
2167
+ // validate previous pane maximum range
2168
+ this.prevPaneCurrentWidth = this.validateMaxRange(this.prevPaneIndex, this.prevPaneCurrentWidth, this.previousPane);
2169
+ // validate next pane maximum range
2170
+ this.nextPaneCurrentWidth = this.validateMaxRange(this.nextPaneIndex, this.nextPaneCurrentWidth, this.nextPane);
2171
+ }
2172
+
2173
+ private equatePaneWidths(): void {
2174
+ let difference: number;
2175
+ if ((this.prevPaneCurrentWidth + this.nextPaneCurrentWidth) > this.totalPercent) {
2176
+ difference = (this.prevPaneCurrentWidth + this.nextPaneCurrentWidth) - this.totalPercent;
2177
+ this.prevPaneCurrentWidth = this.prevPaneCurrentWidth - (difference / 2) + '%';
2178
+ this.nextPaneCurrentWidth = this.nextPaneCurrentWidth - (difference / 2) + '%';
2179
+ }
2180
+ if ((this.prevPaneCurrentWidth + this.nextPaneCurrentWidth) < this.totalPercent) {
2181
+ difference = this.totalPercent - (this.prevPaneCurrentWidth + this.nextPaneCurrentWidth);
2182
+ this.prevPaneCurrentWidth = this.prevPaneCurrentWidth + (difference / 2) + '%';
2183
+ this.nextPaneCurrentWidth = this.nextPaneCurrentWidth + (difference / 2) + '%';
2184
+ }
2185
+ }
2186
+
2187
+ private calculateCurrentDimensions(): void {
2188
+ if (this.updatePrePaneInPercentage || this.updateNextPaneInPercentage) {
2189
+ this.prevPaneCurrentWidth = Math.round(Number(Math.round(this.convertPixelToPercentage(this.prevPaneCurrentWidth)
2190
+ * 10) / 10));
2191
+ this.nextPaneCurrentWidth = Math.round(Number(Math.round(this.convertPixelToPercentage(this.nextPaneCurrentWidth)
2192
+ * 10) / 10));
2193
+ if (this.prevPaneCurrentWidth === 0) {
2194
+ this.nextPaneCurrentWidth = this.totalPercent;
2195
+ }
2196
+ if (this.nextPaneCurrentWidth === 0) {
2197
+ this.prevPaneCurrentWidth = this.totalPercent;
2198
+ }
2199
+ if (this.prevPaneCurrentWidth + this.nextPaneCurrentWidth !== this.totalPercent) {
2200
+ this.equatePaneWidths();
2201
+ } else {
2202
+ this.prevPaneCurrentWidth = this.prevPaneCurrentWidth + '%';
2203
+ this.nextPaneCurrentWidth = this.nextPaneCurrentWidth + '%';
2204
+ }
2205
+ this.prevPaneCurrentWidth = (this.updatePrePaneInPercentage) ? this.prevPaneCurrentWidth :
2206
+ this.convertPercentageToPixel(this.prevPaneCurrentWidth) + 'px';
2207
+ this.nextPaneCurrentWidth = (this.updateNextPaneInPercentage) ? this.nextPaneCurrentWidth :
2208
+ this.convertPercentageToPixel(this.nextPaneCurrentWidth) + 'px';
2209
+ this.updatePrePaneInPercentage = false;
2210
+ this.updateNextPaneInPercentage = false;
2211
+ } else {
2212
+ this.prevPaneCurrentWidth = this.prevPaneCurrentWidth + 'px';
2213
+ this.nextPaneCurrentWidth = this.nextPaneCurrentWidth + 'px';
2214
+ }
2215
+ }
2216
+
2217
+ private addStaticPaneClass(): void {
2218
+ if (!this.previousPane.classList.contains(STATIC_PANE)) {
2219
+ this.previousPane.classList.add(STATIC_PANE);
2220
+ }
2221
+ if (!this.nextPane.classList.contains(STATIC_PANE)) {
2222
+ this.nextPane.classList.add(STATIC_PANE);
2223
+ }
2224
+ }
2225
+
2226
+ private validateDraggedPosition(draggedPos: number, prevPaneHeightWidth: number, nextPaneHeightWidth: number): number {
2227
+ const separatorTopLeft: number = (this.orientation === 'Horizontal') ? this.currentSeparator.offsetLeft :
2228
+ this.currentSeparator.offsetTop;
2229
+ const prePaneRange: number = separatorTopLeft - prevPaneHeightWidth;
2230
+ const nextPaneRange: number = nextPaneHeightWidth + separatorTopLeft;
2231
+ const pane1MinSize: number = this.getMinMax(this.prevPaneIndex, this.previousPane, 'min');
2232
+ const pane2MinSize: number = this.getMinMax(this.nextPaneIndex, this.nextPane, 'min');
2233
+ const pane1MaxSize: number = this.getMinMax(this.prevPaneIndex, this.previousPane, 'max');
2234
+ const pane2MaxSize: number = this.getMinMax(this.nextPaneIndex, this.nextPane, 'max');
2235
+ let validatedSize: number = draggedPos;
2236
+ if (draggedPos > nextPaneRange - pane2MinSize) {
2237
+ validatedSize = nextPaneRange - pane2MinSize;
2238
+ } else if (draggedPos < prePaneRange + pane1MinSize) {
2239
+ validatedSize = prePaneRange + pane1MinSize;
2240
+ }
2241
+ if (!isNullOrUndefined(pane1MaxSize)) {
2242
+ if (draggedPos > prePaneRange + pane1MaxSize) {
2243
+ validatedSize = prePaneRange + pane1MaxSize;
2244
+ }
2245
+ } else if (!isNullOrUndefined(pane2MaxSize)) {
2246
+ if (draggedPos < nextPaneRange - pane2MaxSize) {
2247
+ validatedSize = nextPaneRange - pane2MaxSize;
2248
+ }
2249
+ }
2250
+ return validatedSize;
2251
+ }
2252
+
2253
+ private onMouseUp(e: MouseEvent | TouchEvent | PointerEvent): void {
2254
+ removeClass([this.currentSeparator], SPLIT_BAR_ACTIVE);
2255
+ this.unwireResizeEvents();
2256
+ const eventArgs: ResizingEventArgs = {
2257
+ event: e,
2258
+ element: this.element,
2259
+ pane: [this.previousPane, this.nextPane],
2260
+ index: [this.prevPaneIndex, this.nextPaneIndex],
2261
+ separator: this.currentSeparator,
2262
+ paneSize: [this.prePaneDimenson, this.nextPaneDimension]
2263
+ };
2264
+ for (let i: number = 0; i < this.element.querySelectorAll('iframe').length; i++) {
2265
+ this.element.querySelectorAll('iframe')[i].style.pointerEvents = 'auto';
2266
+ }
2267
+ this.trigger('resizeStop', eventArgs);
2268
+ if (this.enablePersistence) {
2269
+ const paneValues: PanePropertiesModel[] = this.paneSettings;
2270
+ paneValues[this.getPreviousPaneIndex()].size = (this.allPanes[this.getPreviousPaneIndex()] as HTMLElement).style.flexBasis;
2271
+ paneValues[this.getNextPaneIndex()].size = (this.allPanes[this.getNextPaneIndex()] as HTMLElement).style.flexBasis;
2272
+ this.setProperties({ 'paneSettings': paneValues }, true);
2273
+ }
2274
+ }
2275
+
2276
+ private panesDimension(index: number, child: HTMLElement[]): void {
2277
+ const childCount: number = child.length;
2278
+ let size: string | number;
2279
+ parseInt(<string>this.getHeight(this.element), 10);
2280
+ if (!isNullOrUndefined(this.paneSettings[index])) {
2281
+ if (!isNullOrUndefined(this.paneSettings[index].size)) {
2282
+ size = this.paneSettings[index].size;
2283
+ if (index < childCount) {
2284
+ setStyleAttribute(<HTMLElement>child[index], { 'flex-basis': size, 'order': index * 2 });
2285
+ if (index < childCount - 1 && this.paneSettings[index].size !== '') {
2286
+ addClass([child[index]], STATIC_PANE);
2287
+ } else if (!this.sizeFlag) {
2288
+ (<HTMLElement>child[index]).style.flexBasis = null;
2289
+ }
2290
+ if ((index === childCount - 1) && this.sizeFlag && this.paneSettings[index].size !== '') {
2291
+ addClass([child[index]], STATIC_PANE);
2292
+ }
2293
+ }
2294
+ } else {
2295
+ this.sizeFlag = true;
2296
+ setStyleAttribute(<HTMLElement>child[index], { 'order': index * 2 });
2297
+ }
2298
+ } else {
2299
+ setStyleAttribute(<HTMLElement>child[index], { 'order': index * 2 });
2300
+ }
2301
+ this.paneOrder.push(index * 2);
2302
+ }
2303
+
2304
+ private setTemplate(template: string | HTMLElement, toElement: HTMLElement): void {
2305
+ toElement.innerHTML = '';
2306
+ template = typeof (template) === 'string' ? this.sanitizeHelper(template) : template;
2307
+ this.templateCompile(toElement, template);
2308
+ // eslint-disable-next-line @typescript-eslint/no-explicit-any
2309
+ if ((this as any).isReact) {
2310
+ this.renderReactTemplates();
2311
+ }
2312
+ }
2313
+
2314
+ // eslint-disable-next-line
2315
+ private templateCompile(ele: HTMLElement, cnt: any): void {
2316
+ // eslint-disable-next-line
2317
+ const blazorContain: string[] = Object.keys(window) as string[];
2318
+ const tempEle: HTMLElement = this.createElement('div');
2319
+ this.compileElement(tempEle, cnt, 'content');
2320
+ if (tempEle.childNodes.length !== 0) {
2321
+ [].slice.call(tempEle.childNodes).forEach((childEle: HTMLElement): void => {
2322
+ ele.appendChild(childEle);
2323
+ });
2324
+ }
2325
+ }
2326
+
2327
+ private compileElement(ele: HTMLElement, val: string | HTMLElement, prop: string): void {
2328
+ // eslint-disable-next-line
2329
+ const blazorContain: string[] = Object.keys(window) as string[];
2330
+ if (typeof (val) === 'string') {
2331
+ if ((<string>val)[0] === '.' || (<string>val)[0] === '#') {
2332
+ const eleVal: HTMLElement = <HTMLElement>document.querySelector(<string>val);
2333
+ if (!isNullOrUndefined(eleVal)) {
2334
+ this.templateElement.push(eleVal);
2335
+ if (eleVal.style.display === 'none') {
2336
+ eleVal.style.removeProperty('display');
2337
+ }
2338
+ if (eleVal.getAttribute('style') === '') {
2339
+ eleVal.removeAttribute('style');
2340
+ }
2341
+ ele.appendChild(eleVal);
2342
+ return;
2343
+ } else {
2344
+ val = (val as string).trim();
2345
+ }
2346
+ } else {
2347
+ val = (val as string).trim();
2348
+ }
2349
+ }
2350
+ let templateFn: Function;
2351
+ if (!isNullOrUndefined((<HTMLElement>val).outerHTML)) {
2352
+ templateFn = compile((<HTMLElement>val).outerHTML);
2353
+ } else {
2354
+ templateFn = compile(val as string);
2355
+ }
2356
+ let templateFUN: HTMLElement[];
2357
+ if (!isNullOrUndefined(templateFn)) {
2358
+ templateFUN = templateFn({}, this, prop, this.element.id + 'content' + this.allPanes.length.toString(), true);
2359
+ }
2360
+ if (!isNullOrUndefined(templateFn) && templateFUN && templateFUN.length > 0) {
2361
+ [].slice.call(templateFUN).forEach((el: HTMLElement): void => {
2362
+ ele.appendChild(el);
2363
+ });
2364
+ }
2365
+ }
2366
+
2367
+ private paneCollapsible(pane: HTMLElement, index: number): void {
2368
+ // eslint-disable-next-line
2369
+ this.paneSettings[index].collapsible ? addClass([pane], COLLAPSIBLE) : removeClass([pane], COLLAPSIBLE);
2370
+ }
2371
+
2372
+ private createSplitPane(target: HTMLElement): void {
2373
+ let childCount: number = target.children.length;
2374
+ for (let i: number = 0; i < this.paneSettings.length; i++) {
2375
+ if (childCount < this.paneSettings.length) {
2376
+ const childElement: HTMLElement = this.createElement('div');
2377
+ this.element.appendChild(childElement);
2378
+ childCount = childCount + 1;
2379
+ }
2380
+ }
2381
+ childCount = target.children.length;
2382
+ const child: HTMLElement[] = [].slice.call(target.children);
2383
+ this.sizeFlag = false;
2384
+ if (childCount > 0) {
2385
+ for (let i: number = 0; i < childCount; i++) {
2386
+ // To accept only div and span element as pane
2387
+ if (child[i].nodeName === 'DIV' || child[i].nodeName === 'SPAN') {
2388
+ this.allPanes.push(<HTMLElement>child[i]);
2389
+ if (this.orientation === 'Horizontal') {
2390
+ addClass([child[i]], [PANE, SPLIT_H_PANE, SCROLL_PANE]);
2391
+ this.panesDimension(i, child);
2392
+ } else {
2393
+ addClass([child[i]], [PANE, SPLIT_V_PANE, SCROLL_PANE]);
2394
+ this.panesDimension(i, child);
2395
+ }
2396
+ if (!isNullOrUndefined(this.paneSettings[i]) && !isNullOrUndefined(this.paneSettings[i].content)) {
2397
+ this.setTemplate(this.paneSettings[i].content as string, child[i] as HTMLElement);
2398
+ }
2399
+ if (!isNullOrUndefined(this.paneSettings[i]) && this.paneSettings[i].cssClass) {
2400
+ this.setCssClass(child[i], this.paneSettings[i].cssClass);
2401
+ }
2402
+ if (!isNullOrUndefined(this.paneSettings[i])) {
2403
+ this.paneCollapsible(child[i], i);
2404
+ }
2405
+ }
2406
+ }
2407
+ }
2408
+ }
2409
+
2410
+ /**
2411
+ * expands corresponding pane based on the index is passed.
2412
+ *
2413
+ * @param { number } index - Specifies the index value of the corresponding pane to be expanded at initial rendering of splitter.
2414
+ * @returns {void}
2415
+ */
2416
+ public expand(index: number): void {
2417
+ this.collapsedOnchange(index);
2418
+ this.updatePaneSettings(index, false);
2419
+ }
2420
+
2421
+ /**
2422
+ * collapses corresponding pane based on the index is passed.
2423
+ *
2424
+ * @param { number } index - Specifies the index value of the corresponding pane to be collapsed at initial rendering of splitter.
2425
+ * @returns {void}
2426
+ */
2427
+ public collapse(index: number): void {
2428
+ this.isCollapsed(index);
2429
+ this.updatePaneSettings(index, true);
2430
+ }
2431
+
2432
+ /**
2433
+ * Removes the control from the DOM and also removes all its related events.
2434
+ *
2435
+ * @returns {void}
2436
+ */
2437
+ public destroy(): void {
2438
+ if (!this.isDestroyed) {
2439
+ super.destroy();
2440
+ EventHandler.remove(document, 'touchstart click', this.onDocumentClick);
2441
+ this.element.ownerDocument.defaultView.removeEventListener('resize', this.onReportWindowSize, true);
2442
+ while (this.element.attributes.length > 0) {
2443
+ this.element.removeAttribute(this.element.attributes[0].name);
2444
+ }
2445
+ this.element.innerHTML = this.wrapper.innerHTML;
2446
+ for (let i: number = 0; i < this.wrapper.attributes.length; i++) {
2447
+ this.element.setAttribute(this.wrapper.attributes[i].name, this.wrapper.attributes[i].value);
2448
+ }
2449
+ if (this.refreshing) {
2450
+ addClass([this.element], ['e-control', 'e-lib', ROOT]);
2451
+ this.allBars = [];
2452
+ this.allPanes = [];
2453
+ }
2454
+ this.restoreElem();
2455
+ // eslint-disable-next-line @typescript-eslint/no-explicit-any
2456
+ if ((this as any).isReact) {
2457
+ this.clearTemplate();
2458
+ }
2459
+ }
2460
+ }
2461
+
2462
+ private restoreElem(): void {
2463
+ if (this.templateElement.length > 0) {
2464
+ for (let i: number = 0; i < this.templateElement.length; i++) {
2465
+ this.templateElement[i].style.display = 'none';
2466
+ document.body.appendChild(this.templateElement[i]);
2467
+ }
2468
+ }
2469
+ }
2470
+
2471
+ private addPaneClass(pane: HTMLElement): HTMLElement {
2472
+ // eslint-disable-next-line
2473
+ this.orientation === 'Horizontal' ? addClass([pane], [PANE, SPLIT_H_PANE, SCROLL_PANE]) :
2474
+ addClass([pane], [PANE, SPLIT_V_PANE, SCROLL_PANE]);
2475
+ return pane;
2476
+ }
2477
+
2478
+ private removePaneOrders(paneClass: string): void {
2479
+ const childNodes : NodeListOf<ChildNode> = this.element.childNodes;
2480
+ const panes: HTMLElement[] = [];
2481
+ for (let i: number = 0; childNodes.length < 0; i++) {
2482
+ if ((childNodes[i] as HTMLElement).classList.contains(paneClass)) {
2483
+ panes.push(childNodes[i] as HTMLElement);
2484
+ }
2485
+ }
2486
+ for (let i: number = 0; i < panes.length; i++) {
2487
+ panes[i].style.removeProperty('order');
2488
+ }
2489
+ }
2490
+
2491
+ private setPaneOrder(): void {
2492
+ for (let i: number = 0; i < this.allPanes.length; i++) {
2493
+ this.panesDimension(i, this.allPanes);
2494
+ }
2495
+ }
2496
+
2497
+ private removeSeparator(): void {
2498
+ for (let i: number = 0; i < this.allBars.length; i++) {
2499
+ detach(this.allBars[i]);
2500
+ }
2501
+ this.allBars = [];
2502
+ }
2503
+
2504
+ private updatePanes(): void {
2505
+ this.setPaneOrder();
2506
+ this.removeSeparator();
2507
+ this.addSeparator(this.element);
2508
+ }
2509
+
2510
+ /**
2511
+ * Allows you to add a pane dynamically to the specified index position by passing the pane properties.
2512
+ *
2513
+ * @param { PanePropertiesModel } paneProperties - Specifies the pane’s properties that apply to new pane.
2514
+ * @param { number } index - Specifies the index where the pane will be inserted.
2515
+ * @returns {void}
2516
+ */
2517
+ public addPane(paneProperties: PanePropertiesModel, index: number): void {
2518
+ let newPane: HTMLElement = this.createElement('div');
2519
+ newPane = this.addPaneClass(newPane);
2520
+ index = (index > this.allPanes.length + 1) ? this.allPanes.length : index;
2521
+ const paneDetails: PanePropertiesModel = {
2522
+ size: isNullOrUndefined(paneProperties.size) ? '' : paneProperties.size,
2523
+ min: isNullOrUndefined(paneProperties.min) ? null : paneProperties.min,
2524
+ max: isNullOrUndefined(paneProperties.max) ? null : paneProperties.max,
2525
+ content: isNullOrUndefined(paneProperties.content) ? '' : paneProperties.content,
2526
+ resizable: isNullOrUndefined(paneProperties.resizable) ? true : paneProperties.resizable,
2527
+ collapsible: isNullOrUndefined(paneProperties.collapsible) ? false : paneProperties.collapsible,
2528
+ collapsed: isNullOrUndefined(paneProperties.collapsed) ? false : paneProperties.collapsed,
2529
+ cssClass: isNullOrUndefined(paneProperties.cssClass) ? '' : paneProperties.cssClass
2530
+ };
2531
+ this.paneSettings.splice(index, 0, paneDetails);
2532
+ this.setProperties({ 'paneSettings': this.paneSettings }, true);
2533
+ if (this.orientation === 'Horizontal') {
2534
+ this.element.insertBefore(newPane, this.element.querySelectorAll('.' + SPLIT_H_PANE)[index]);
2535
+ this.removePaneOrders(SPLIT_H_PANE);
2536
+ } else {
2537
+ this.element.insertBefore(newPane, this.element.querySelectorAll('.' + SPLIT_V_PANE)[index]);
2538
+ this.removePaneOrders(SPLIT_V_PANE);
2539
+ }
2540
+ this.allPanes.splice(index, 0, newPane);
2541
+ this.updatePanes();
2542
+ this.setTemplate(this.paneSettings[index].content as string, newPane);
2543
+ this.setCssClass(this.allPanes[index], paneProperties.cssClass);
2544
+ this.allPanes[this.allPanes.length - 1].classList.remove(STATIC_PANE);
2545
+ }
2546
+
2547
+ /**
2548
+ * Allows you to remove the specified pane dynamically by passing its index value.
2549
+ *
2550
+ * @param { number } index - Specifies the index value to remove the corresponding pane.
2551
+ * @returns {void}
2552
+ */
2553
+ public removePane(index: number): void {
2554
+ index = (index > this.allPanes.length + 1) ? this.allPanes.length : index;
2555
+ const elementClass: string = (this.orientation === 'Horizontal') ? SPLIT_H_PANE : SPLIT_V_PANE;
2556
+ if (isNullOrUndefined(this.element.querySelectorAll('.' + elementClass)[index])) {
2557
+ return;
2558
+ }
2559
+ detach(this.element.querySelectorAll('.' + elementClass)[index]);
2560
+ this.allPanes.splice(index, 1);
2561
+ this.removePaneOrders(elementClass);
2562
+ this.updatePanes();
2563
+ this.paneSettings.splice(index, 1);
2564
+ this.setProperties({ 'paneSettings': this.paneSettings }, true);
2565
+ if (this.allPanes.length > 0) {
2566
+ this.allPanes[this.allPanes.length - 1].classList.remove(STATIC_PANE);
2567
+ }
2568
+ }
2569
+ }
2570
+
2571
+ /**
2572
+ * Interface for accessing element coordinates
2573
+ *
2574
+ * @private
2575
+ */
2576
+
2577
+ interface Coordinates {
2578
+ /**
2579
+ * x coordinate of an element
2580
+ */
2581
+ x?: number
2582
+ /**
2583
+ * y coordinate of an element.
2584
+ */
2585
+ y?: number
2586
+ }
2587
+
2588
+ /**
2589
+ * Provides information about a Resize event.
2590
+ */
2591
+ export interface ResizeEventArgs {
2592
+ /** Contains the root element of resizing pane. */
2593
+ element?: HTMLElement
2594
+ /** Contains default event arguments. */
2595
+ event?: Event
2596
+ /** Contains the corresponding resizing pane. */
2597
+ pane?: HTMLElement[]
2598
+ /** Contains the index of resizing pane. */
2599
+ index?: number[]
2600
+ /** Contains the resizing pane’s separator element. */
2601
+ separator?: HTMLElement
2602
+ /**
2603
+ * Control the resize action whether the resize action happens continuously.
2604
+ * When you set this argument to true, resize process will be stopped.
2605
+ */
2606
+ cancel?: boolean
2607
+ }
2608
+
2609
+ /**
2610
+ * Provides information about a Resizing event.
2611
+ */
2612
+ export interface ResizingEventArgs {
2613
+ /** Contains the root element of resizing pane. */
2614
+ element?: HTMLElement
2615
+ /** Contains default event arguments. */
2616
+ event?: Event
2617
+ /** Contains a pane size when it resizes. */
2618
+ paneSize?: number[]
2619
+ /** Contains the corresponding resizing pane. */
2620
+ pane?: HTMLElement[]
2621
+ /** Contains the index of resizing pane. */
2622
+ index?: number[]
2623
+ /** Contains the resizing pane’s separator element. */
2624
+ separator?: HTMLElement
2625
+ }
2626
+
2627
+ /**
2628
+ * Provides information about a BeforeExpand event.
2629
+ */
2630
+ export interface BeforeExpandEventArgs {
2631
+ /**
2632
+ * To access root element after control created
2633
+ */
2634
+ element?: HTMLElement
2635
+ /**
2636
+ * default event arguments
2637
+ */
2638
+ event?: Event
2639
+ /**
2640
+ * To get pane elements
2641
+ */
2642
+ pane?: HTMLElement[]
2643
+ /**
2644
+ * Index of pane
2645
+ */
2646
+ index?: number[]
2647
+ /**
2648
+ * Respective split-bar element
2649
+ */
2650
+ separator?: HTMLElement
2651
+ /**
2652
+ * cancel argument
2653
+ */
2654
+ cancel?: boolean
2655
+ }
2656
+
2657
+ /**
2658
+ * Provides information about a Expanded event.
2659
+ */
2660
+ export interface ExpandedEventArgs {
2661
+ /**
2662
+ * To access root element after control created
2663
+ */
2664
+ element?: HTMLElement
2665
+ /**
2666
+ * default event arguments
2667
+ */
2668
+ event?: Event
2669
+ /**
2670
+ * To get pane elements
2671
+ */
2672
+ pane?: HTMLElement[]
2673
+ /**
2674
+ * Index of pane
2675
+ */
2676
+ index?: number[]
2677
+ /**
2678
+ * Respective split-bar element
2679
+ */
2680
+ separator?: HTMLElement
2681
+ }
2682
+
2683
+ /**
2684
+ * To maintain pane details
2685
+ *
2686
+ * @private
2687
+ */
2688
+ interface PaneDetails {
2689
+ /** to check whether the prevPane is Collapsible */
2690
+ prevPaneCollapsible?: boolean
2691
+ /** to check whether the prevPane is expanded */
2692
+ prevPaneExpanded?: boolean
2693
+ /** to check whether the nextPane is Collapsible */
2694
+ nextPaneCollapsible?: boolean
2695
+ /** to check whether the nextPane is expanded */
2696
+ nextPaneExpanded?: boolean
2697
+ /** previous pane index */
2698
+ prevPaneIndex?: number
2699
+ /** next pane index */
2700
+ nextPaneIndex?: number
2701
+ /** currentbar index */
2702
+ currentBarIndex?: number
2703
+ /** to get prevPane's previous element */
2704
+ prevPanePreEle?: HTMLElement
2705
+ /** to get nextPane's next element */
2706
+ nextPaneNextEle?: HTMLElement
2707
+ /** to check whether the nextPane is collapsed */
2708
+ nextPaneCollapsed?: boolean
2709
+ /** to check whether the previousPane is collapsed */
2710
+ prevPaneCollapsed?: boolean
2711
+ }