@syncfusion/ej2-layouts 29.2.4 → 30.1.37

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