UNPKG

@ux-aspects/ux-aspects

Version:

Open source user interface framework for building modern, responsive, mobile big data applications

183 lines 33.5 kB
import { LiveAnnouncer } from '@angular/cdk/a11y'; import { ChangeDetectionStrategy, ChangeDetectorRef, Component, inject } from '@angular/core'; import { merge, Subject } from 'rxjs'; import { takeUntil } from 'rxjs/operators'; import { DateRangeOptions } from '../../date-range-picker/date-range-picker.directive'; import { DateRangePicker, DateRangeService } from '../../date-range-picker/date-range.service'; import { DatePickerHeaderEvent, DateTimePickerService } from '../date-time-picker.service'; import { isDateAfter, isDateBefore } from '../date-time-picker.utils'; import { MonthViewService } from './month-view.service'; import * as i0 from "@angular/core"; import * as i1 from "../../../directives/accessibility/focus-indicator/focus-indicator.directive"; import * as i2 from "../../../directives/accessibility/focus-indicator/focus-indicator-origin/focus-indicator-origin.directive"; import * as i3 from "../../../directives/focus-if/focus-if.directive"; import * as i4 from "@angular/common"; export class MonthViewComponent { /** Determine if we are in range selection mode */ get _isRangeMode() { return !!this._rangeOptions; } /** Determine if this picker is the start picker */ get _isRangeStart() { return this._isRangeMode && this._rangeOptions.picker === DateRangePicker.Start; } /** Determine if this picker is the end picker */ get _isRangeEnd() { return this._isRangeMode && this._rangeOptions.picker === DateRangePicker.End; } get _rangeStart() { return this._isRangeMode && this._rangeService ? this._rangeService.start : null; } get _rangeEnd() { return this._isRangeMode && this._rangeService ? this._rangeService.end : null; } get _minMonth() { return this._datePicker.min$.value ? new Date(this._datePicker.min$.value.getFullYear(), this._datePicker.min$.value.getMonth()) : null; } get _maxMonth() { return this._datePicker.max$.value ? new Date(this._datePicker.max$.value.getFullYear(), this._datePicker.max$.value.getMonth()) : null; } constructor() { this.monthService = inject(MonthViewService); this._datePicker = inject(DateTimePickerService); this._liveAnnouncer = inject(LiveAnnouncer); this._changeDetector = inject(ChangeDetectorRef); this._rangeService = inject(DateRangeService, { optional: true }); this._rangeOptions = inject(DateRangeOptions, { optional: true }); this._onDestroy = new Subject(); this._datePicker.headerEvent$.pipe(takeUntil(this._onDestroy)) .subscribe(event => event === DatePickerHeaderEvent.Next ? this.next() : this.previous()); if (this._rangeService) { this._rangeService.onRangeChange.pipe(takeUntil(this._onDestroy)).subscribe(() => this._changeDetector.detectChanges()); } // if the currently focused item is disabled then choose a month that isn't disabled if (this.monthService.focused$.value) { if (this.getDisabled(this.monthService.focused$.value)) { for (const row of this.monthService.grid$.value) { for (const column of row) { if (!this.getDisabled(column)) { this.monthService.setFocus(column.month, column.year); return; } } } } } } ngAfterViewInit() { // update on min/max changes merge(this._datePicker.min$, this._datePicker.max$).pipe(takeUntil(this._onDestroy)) .subscribe(() => this._changeDetector.detectChanges()); } ngOnDestroy() { this._onDestroy.next(); this._onDestroy.complete(); } /** Get the disabled state of a month */ getDisabled(item) { const date = new Date(item.year, item.month); // if we are not in range mode then it will always be enabled if (this._isRangeMode) { // if we are range start and dates are after the range end then they should also be disabled if (this._isRangeStart && !this._rangeStart && this._rangeEnd && isDateAfter(date, new Date(this._rangeEnd.getFullYear(), this._rangeEnd.getMonth()))) { return true; } // if we are range end and dates are before the range start then they should also be disabled if (this._isRangeEnd && !this._rangeEnd && this._rangeStart && isDateBefore(date, new Date(this._rangeStart.getFullYear(), this._rangeStart.getMonth()))) { return true; } } if (this._minMonth && isDateBefore(date, this._minMonth)) { return true; } if (this._maxMonth && isDateAfter(date, this._maxMonth)) { return true; } return false; } /** * Go to the previous year */ previous() { this._datePicker.setViewportYear(this._datePicker.year$.value - 1); } /** * Go to the next year */ next() { this._datePicker.setViewportYear(this._datePicker.year$.value + 1); } /** * Select a month in the calendar * @param month the index of the month to select */ select(month) { this._datePicker.setViewportMonth(month); // show the day picker this._datePicker.goToChildMode(); } focusMonth(item, monthOffset) { let targetMonth = item.month + monthOffset; let targetYear = item.year; if (targetMonth < 0) { targetMonth += 12; targetYear -= 1; } if (targetMonth >= 12) { targetMonth -= 12; targetYear += 1; } this.monthService.setFocus(targetMonth, targetYear); } trackRowByFn(index) { return index; } trackMonthByFn(_index, item) { return `${item.month} ${item.year}`; } getTabbable(item) { const focused = this.monthService.focused$.value; const grid = this.monthService.grid$.value; // if there is a focused month check if this is it if (focused) { // check if the focused month is visible const isFocusedMonthVisible = !!grid.find(row => !!row.find(_item => _item.month === focused.month && _item.year === focused.year)); if (isFocusedMonthVisible) { return focused.month === item.month && focused.year === item.year; } } // if there is no focusable month then check if there is a selected month const isSelectedMonthVisible = !!grid.find(row => !!row.find(month => month.isActiveMonth)); if (isSelectedMonthVisible) { return item.isActiveMonth; } // otherwise find the first non-disabled month for (const row of grid) { for (const column of row) { if (!this.getDisabled(column)) { return item === column; } } } return false; } /** Announce the date when we focus on a date */ announceRangeMode() { if (this._isRangeMode) { this._liveAnnouncer.announce(this._isRangeStart ? this._rangeService.startPickerAriaLabel : this._rangeService.endPickerAriaLabel); } } shouldFocus(item) { const focused = this.monthService.focused$.value; if (focused) { return focused.month === item.month && focused.year === item.year; } } static { this.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "18.2.12", ngImport: i0, type: MonthViewComponent, deps: [], target: i0.ɵɵFactoryTarget.Component }); } static { this.ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "17.0.0", version: "18.2.12", type: MonthViewComponent, selector: "ux-date-time-picker-month-view", providers: [MonthViewService], ngImport: i0, template: "<div class=\"calendar\" role=\"grid\">\n @for (row of monthService.grid$ | async; track trackRowByFn($index)) {\n <div class=\"calendar-row\" role=\"row\">\n @for (item of row; track trackMonthByFn($index, item)) {\n <button type=\"button\"\n uxFocusIndicator\n uxFocusIndicatorOrigin\n [programmaticFocusIndicator]=\"true\"\n role=\"gridcell\"\n class=\"calendar-item\"\n [focusIf]=\"shouldFocus(item)\"\n [disabled]=\"getDisabled(item)\"\n [tabindex]=\"getTabbable(item) ? 0 : -1\"\n [attr.aria-label]=\"item.name + ' ' + item.year\"\n [attr.aria-selected]=\"item.isActiveMonth\"\n [class.active]=\"item.isActiveMonth && !getDisabled(item)\"\n [class.current]=\"item.isCurrentMonth\"\n (click)=\"select(item.month); $event.stopPropagation()\"\n (focus)=\"announceRangeMode()\"\n (keydown.ArrowLeft)=\"focusMonth(item, -1); $event.preventDefault()\"\n (keydown.ArrowRight)=\"focusMonth(item, 1); $event.preventDefault()\"\n (keydown.ArrowUp)=\"focusMonth(item, -4); $event.preventDefault()\"\n (keydown.ArrowDown)=\"focusMonth(item, 4); $event.preventDefault()\">\n {{ item.name }}\n </button>\n }\n </div>\n }\n</div>\n", dependencies: [{ kind: "directive", type: i1.FocusIndicatorDirective, selector: "[uxFocusIndicator]", inputs: ["checkChildren", "mouseFocusIndicator", "touchFocusIndicator", "keyboardFocusIndicator", "programmaticFocusIndicator"], outputs: ["indicator"], exportAs: ["ux-focus-indicator"] }, { kind: "directive", type: i2.FocusIndicatorOriginDirective, selector: "[uxFocusIndicatorOrigin]" }, { kind: "directive", type: i3.FocusIfDirective, selector: "[focusIf]", inputs: ["focusIfDelay", "focusIfScroll", "focusIf"] }, { kind: "pipe", type: i4.AsyncPipe, name: "async" }], changeDetection: i0.ChangeDetectionStrategy.OnPush }); } } i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "18.2.12", ngImport: i0, type: MonthViewComponent, decorators: [{ type: Component, args: [{ selector: 'ux-date-time-picker-month-view', providers: [MonthViewService], changeDetection: ChangeDetectionStrategy.OnPush, template: "<div class=\"calendar\" role=\"grid\">\n @for (row of monthService.grid$ | async; track trackRowByFn($index)) {\n <div class=\"calendar-row\" role=\"row\">\n @for (item of row; track trackMonthByFn($index, item)) {\n <button type=\"button\"\n uxFocusIndicator\n uxFocusIndicatorOrigin\n [programmaticFocusIndicator]=\"true\"\n role=\"gridcell\"\n class=\"calendar-item\"\n [focusIf]=\"shouldFocus(item)\"\n [disabled]=\"getDisabled(item)\"\n [tabindex]=\"getTabbable(item) ? 0 : -1\"\n [attr.aria-label]=\"item.name + ' ' + item.year\"\n [attr.aria-selected]=\"item.isActiveMonth\"\n [class.active]=\"item.isActiveMonth && !getDisabled(item)\"\n [class.current]=\"item.isCurrentMonth\"\n (click)=\"select(item.month); $event.stopPropagation()\"\n (focus)=\"announceRangeMode()\"\n (keydown.ArrowLeft)=\"focusMonth(item, -1); $event.preventDefault()\"\n (keydown.ArrowRight)=\"focusMonth(item, 1); $event.preventDefault()\"\n (keydown.ArrowUp)=\"focusMonth(item, -4); $event.preventDefault()\"\n (keydown.ArrowDown)=\"focusMonth(item, 4); $event.preventDefault()\">\n {{ item.name }}\n </button>\n }\n </div>\n }\n</div>\n" }] }], ctorParameters: () => [] }); //# sourceMappingURL=data:application/json;base64,eyJ2ZXJzaW9uIjozLCJmaWxlIjoibW9udGgtdmlldy5jb21wb25lbnQuanMiLCJzb3VyY2VSb290IjoiIiwic291cmNlcyI6WyIuLi8uLi8uLi8uLi8uLi8uLi9zcmMvY29tcG9uZW50cy9kYXRlLXRpbWUtcGlja2VyL21vbnRoLXZpZXcvbW9udGgtdmlldy5jb21wb25lbnQudHMiLCIuLi8uLi8uLi8uLi8uLi8uLi9zcmMvY29tcG9uZW50cy9kYXRlLXRpbWUtcGlja2VyL21vbnRoLXZpZXcvbW9udGgtdmlldy5jb21wb25lbnQuaHRtbCJdLCJuYW1lcyI6W10sIm1hcHBpbmdzIjoiQUFBQSxPQUFPLEVBQUUsYUFBYSxFQUFFLE1BQU0sbUJBQW1CLENBQUM7QUFDbEQsT0FBTyxFQUFpQix1QkFBdUIsRUFBRSxpQkFBaUIsRUFBRSxTQUFTLEVBQUUsTUFBTSxFQUFhLE1BQU0sZUFBZSxDQUFDO0FBQ3hILE9BQU8sRUFBRSxLQUFLLEVBQUUsT0FBTyxFQUFFLE1BQU0sTUFBTSxDQUFDO0FBQ3RDLE9BQU8sRUFBRSxTQUFTLEVBQUUsTUFBTSxnQkFBZ0IsQ0FBQztBQUMzQyxPQUFPLEVBQUUsZ0JBQWdCLEVBQUUsTUFBTSxxREFBcUQsQ0FBQztBQUN2RixPQUFPLEVBQUUsZUFBZSxFQUFFLGdCQUFnQixFQUFFLE1BQU0sNENBQTRDLENBQUM7QUFDL0YsT0FBTyxFQUFFLHFCQUFxQixFQUFFLHFCQUFxQixFQUFFLE1BQU0sNkJBQTZCLENBQUM7QUFDM0YsT0FBTyxFQUFFLFdBQVcsRUFBRSxZQUFZLEVBQUUsTUFBTSwyQkFBMkIsQ0FBQztBQUN0RSxPQUFPLEVBQW1DLGdCQUFnQixFQUFFLE1BQU0sc0JBQXNCLENBQUM7Ozs7OztBQVF6RixNQUFNLE9BQU8sa0JBQWtCO0lBYzNCLGtEQUFrRDtJQUNsRCxJQUFJLFlBQVk7UUFDWixPQUFPLENBQUMsQ0FBQyxJQUFJLENBQUMsYUFBYSxDQUFDO0lBQ2hDLENBQUM7SUFFRCxtREFBbUQ7SUFDbkQsSUFBSSxhQUFhO1FBQ2IsT0FBTyxJQUFJLENBQUMsWUFB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akIsQ0FBQztJQUVELGdEQUFnRDtJQUNoRCxpQkFBaUI7UUFDYixJQUFJLElBQUksQ0FBQyxZQUFZLEVBQUUsQ0FBQztZQUNwQixJQUFJLENBQUMsY0FBYyxDQUFDLFFBQVEsQ0FBQyxJQUFJLENBQUMsYUFBYSxDQUFDLENBQUMsQ0FBQyxJQUFJLENBQUMsYUFBYSxDQUFDLG9CQUFvQixDQUFDLENBQUMsQ0FBQyxJQUFJLENBQUMsYUFBYSxDQUFDLGtCQUFrQixDQUFDLENBQUM7UUFDdkksQ0FBQztJQUNMLENBQUM7SUFFRCxXQUFXLENBQUMsSUFBbUI7UUFDM0IsTUFBTSxPQUFPLEdBQUcsSUFBSSxDQUFDLFlBQVksQ0FBQyxRQUFRLENBQUMsS0FBSyxDQUFDO1FBRWpELElBQUksT0FBTyxFQUFFLENBQUM7WUFDVixPQUFPLE9BQU8sQ0FBQyxLQUFLLEtBQUssSUFBSSxDQUFDLEtBQUssSUFBSSxPQUFPLENBQUMsSUFBSSxLQUFLLElBQUksQ0FBQyxJQUFJLENBQUM7UUFDdEUsQ0FBQztJQUNMLENBQUM7K0dBak5RLGtCQUFrQjttR0FBbEIsa0JBQWtCLHlEQUhoQixDQUFDLGdCQUFnQixDQUFDLDBCQ2JqQyw4eUNBNkJBOzs0RkRiYSxrQkFBa0I7a0JBTjlCLFNBQVM7K0JBQ0ksZ0NBQWdDLGFBRS9CLENBQUMsZ0JBQWdCLENBQUMsbUJBQ1osdUJBQXVCLENBQUMsTUFBTSIsInNvdXJjZXNDb250ZW50IjpbImltcG9ydCB7IExpdmVBbm5vdW5jZXIgfSBmcm9tICdAYW5ndWxhci9jZGsvYTExeSc7XG5pbXBvcnQgeyBBZnRlclZpZXdJbml0LCBDaGFuZ2VEZXRlY3Rpb25TdHJhdGVneSwgQ2hhbmdlRGV0ZWN0b3JSZWYsIENvbXBvbmVudCwgaW5qZWN0LCBPbkRlc3Ryb3kgfSBmcm9tICdAYW5ndWxhci9jb3JlJztcbmltcG9ydCB7IG1lcmdlLCBTdWJqZWN0IH0gZnJvbSAncnhqcyc7XG5pbXBvcnQgeyB0YWtlVW50aWwgfSBmcm9tICdyeGpzL29wZXJhdG9ycyc7XG5pbXBvcnQgeyBEYXRlUmFuZ2VPcHRpb25zIH0gZnJvbSAnLi4vLi4vZGF0ZS1yYW5nZS1waWNrZXIvZGF0ZS1yYW5nZS1waWNrZXIuZGlyZWN0aXZlJztcbmltcG9ydCB7IERhdGVSYW5nZVBpY2tlciwgRGF0ZVJhbmdlU2VydmljZSB9IGZyb20gJy4uLy4uL2RhdGUtcmFuZ2UtcGlja2VyL2RhdGUtcmFuZ2Uuc2VydmljZSc7XG5pbXBvcnQgeyBEYXRlUGlja2VySGVhZGVyRXZlbnQsIERhdGVUaW1lUGlja2VyU2VydmljZSB9IGZyb20gJy4uL2RhdGUtdGltZS1waWNrZXIuc2VydmljZSc7XG5pbXBvcnQgeyBpc0RhdGVBZnRlciwgaXNEYXRlQmVmb3JlIH0gZnJvbSAnLi4vZGF0ZS10aW1lLXBpY2tlci51dGlscyc7XG5pbXBvcnQgeyBGb2N1c2VkTW9udGhJdGVtLCBNb250aFZpZXdJdGVtLCBNb250aFZpZXdTZXJ2aWNlIH0gZnJvbSAnLi9tb250aC12aWV3LnNlcnZpY2UnO1xuXG5AQ29tcG9uZW50KHtcbiAgICBzZWxlY3RvcjogJ3V4LWRhdGUtdGltZS1waWNrZXItbW9udGgtdmlldycsXG4gICAgdGVtcGxhdGVVcmw6ICcuL21vbnRoLXZpZXcuY29tcG9uZW50Lmh0bWwnLFxuICAgIHByb3ZpZGVyczogW01vbnRoVmlld1NlcnZpY2VdLFxuICAgIGNoYW5nZURldGVjdGlvbjogQ2hhbmdlRGV0ZWN0aW9uU3RyYXRlZ3kuT25QdXNoXG59KVxuZXhwb3J0IGNsYXNzIE1vbnRoVmlld0NvbXBvbmVudCBpbXBsZW1lbnRzIEFmdGVyVmlld0luaXQsIE9uRGVzdHJveSB7XG4gICAgcmVhZG9ubHkgbW9udGhTZXJ2aWNlID0gaW5qZWN0KE1vbnRoVmlld1NlcnZpY2UpO1xuXG4gICAgcHJpdmF0ZSByZWFkb25seSBfZGF0ZVBpY2tlciA9IGluamVjdChEYXRlVGltZVBpY2tlclNlcnZpY2UpO1xuXG4gICAgcHJpdmF0ZSByZWFkb25seSBfbGl2ZUFubm91bmNlciA9IGluamVjdChMaXZlQW5ub3VuY2VyKTtcblxuICAgIHByaXZhdGUgcmVhZG9ubHkgX2NoYW5nZURldGVjdG9yID0gaW5qZWN0KENoYW5nZURldGVjdG9yUmVmKTtcblxuICAgIHByaXZhdGUgcmVhZG9ubHkgX3JhbmdlU2VydmljZSA9IGluamVjdChEYXRlUmFuZ2VTZXJ2aWNlLCB7IG9wdGlvbmFsOiB0cnVlfSk7XG5cbiAgICBwcml2YXRlIHJlYWRvbmx5IF9yYW5nZU9wdGlvbnMgPSBpbmplY3QoRGF0ZVJhbmdlT3B0aW9ucywgeyBvcHRpb25hbDogdHJ1ZX0pO1xuXG5cbiAgICAvKiogRGV0ZXJtaW5lIGlmIHdlIGFyZSBpbiByYW5nZSBzZWxlY3Rpb24gbW9kZSAqL1xuICAgIGdldCBfaXNSYW5nZU1vZGUoKTogYm9vbGVhbiB7XG4gICAgICAgIHJldHVybiAhIXRoaXMuX3JhbmdlT3B0aW9ucztcbiAgICB9XG5cbiAgICAvKiogRGV0ZXJtaW5lIGlmIHRoaXMgcGlja2VyIGlzIHRoZSBzdGFydCBwaWNrZXIgKi9cbiAgICBnZXQgX2lzUmFuZ2VTdGFydCgpOiBib29sZWFuIHtcbiAgICAgICAgcmV0dXJuIHRoaXMuX2lzUmFuZ2VNb2RlICYmIHRoaXMuX3JhbmdlT3B0aW9ucy5waWNrZXIgPT09IERhdGVSYW5nZVBpY2tlci5TdGFydDtcbiAgICB9XG5cbiAgICAvKiogRGV0ZXJtaW5lIGlmIHRoaXMgcGlja2VyIGlzIHRoZSBlbmQgcGlja2VyICovXG4gICAgZ2V0IF9pc1JhbmdlRW5kKCk6IGJvb2xlYW4ge1xuICAgICAgICByZXR1cm4gdGhpcy5faXNSYW5nZU1vZGUgJiYgdGhpcy5fcmFuZ2VPcHRpb25zLnBpY2tlciA9PT0gRGF0ZVJhbmdlUGlja2VyLkVuZDtcbiAgICB9XG5cbiAgICBnZXQgX3JhbmdlU3RhcnQoKTogRGF0ZSB8IG51bGwge1xuICAgICAgICByZXR1cm4gdGhpcy5faXNSYW5nZU1vZGUgJiYgdGhpcy5fcmFuZ2VTZXJ2aWNlID8gdGhpcy5fcmFuZ2VTZXJ2aWNlLnN0YXJ0IDogbnVsbDtcbiAgICB9XG5cbiAgICBnZXQgX3JhbmdlRW5kKCk6IERhdGUgfCBudWxsIHtcbiAgICAgICAgcmV0dXJuIHRoaXMuX2lzUmFuZ2VNb2RlICYmIHRoaXMuX3JhbmdlU2VydmljZSA/IHRoaXMuX3JhbmdlU2VydmljZS5lbmQgOiBudWxsO1xuICAgIH1cblxuICAgIGdldCBfbWluTW9udGgoKTogRGF0ZSB8IG51bGwge1xuICAgICAgICByZXR1cm4gdGhpcy5fZGF0ZVBpY2tlci5taW4kLnZhbHVlID8gbmV3IERhdGUodGhpcy5fZGF0ZVBpY2tlci5taW4kLnZhbHVlLmdldEZ1bGxZZWFyKCksIHRoaXMuX2RhdGVQaWNrZXIubWluJC52YWx1ZS5nZXRNb250aCgpKSA6IG51bGw7XG4gICAgfVxuXG4gICAgZ2V0IF9tYXhNb250aCgpOiBEYXRlIHwgbnVsbCB7XG4gICAgICAgIHJldHVybiB0aGlzLl9kYXRlUGlja2VyLm1heCQudmFsdWUgPyBuZXcgRGF0ZSh0aGlzLl9kYXRlUGlja2VyLm1heCQudmFsdWUuZ2V0RnVsbFllYXIoKSwgdGhpcy5fZGF0ZVBpY2tlci5tYXgkLnZhbHVlLmdldE1vbnRoKCkpIDogbnVsbDtcbiAgICB9XG5cbiAgICBwcml2YXRlIHJlYWRvbmx5IF9vbkRlc3Ryb3kgPSBuZXcgU3ViamVjdDx2b2lkPigpO1xuXG4gICAgY29uc3RydWN0b3IoKSB7XG5cbiAgICAgICAgdGhpcy5fZGF0ZVBpY2tlci5oZWFkZXJFdmVudCQucGlwZSh0YWtlVW50aWwodGhpcy5fb25EZXN0cm95KSlcbiAgICAgICAgICAgIC5zdWJzY3JpYmUoZXZlbnQgPT4gZXZlbnQgPT09IERhdGVQaWNrZXJIZWFkZXJFdmVudC5OZXh0ID8gdGhpcy5uZXh0KCkgOiB0aGlzLnByZXZpb3VzKCkpO1xuXG4gICAgICAgIGlmICh0aGlzLl9yYW5nZVNlcnZpY2UpIHtcbiAgICAgICAgICAgIHRoaXMuX3JhbmdlU2VydmljZS5vblJhbmdlQ2hhbmdlLnBpcGUodGFrZVVudGlsKHRoaXMuX29uRGVzdHJveSkpLnN1YnNjcmliZSgoKSA9PiB0aGlzLl9jaGFuZ2VEZXRlY3Rvci5kZXRlY3RDaGFuZ2VzKCkpO1xuICAgICAgICB9XG5cbiAgICAgICAgLy8gaWYgdGhlIGN1cnJlbnRseSBmb2N1c2VkIGl0ZW0gaXMgZGlzYWJsZWQgdGhlbiBjaG9vc2UgYSBtb250aCB0aGF0IGlzbid0IGRpc2FibGVkXG4gICAgICAgIGlmICh0aGlzLm1vbnRoU2VydmljZS5mb2N1c2VkJC52YWx1ZSkge1xuICAgICAgICAgICAgaWYgKHRoaXMuZ2V0RGlzYWJsZWQodGhpcy5tb250aFNlcnZpY2UuZm9jdXNlZCQudmFsdWUpKSB7XG4gICAgICAgICAgICAgICAgZm9yIChjb25zdCByb3cgb2YgdGhpcy5tb250aFNlcnZpY2UuZ3JpZCQudmFsdWUpIHtcbiAgICAgICAgICAgICAgICAgICAgZm9yIChjb25zdCBjb2x1bW4gb2Ygcm93KSB7XG4gICAgICAgICAgICAgICAgICAgICAgICBpZiAoIXRoaXMuZ2V0RGlzYWJsZWQoY29sdW1uKSkge1xuICAgICAgICAgICAgICAgICAgICAgICAgICAgIHRoaXMubW9udGhTZXJ2aWNlLnNldEZvY3VzKGNvbHVtbi5tb250aCwgY29sdW1uLnllYXIpO1xuICAgICAgICAgICAgICAgICAgICAgICAgICAgIHJldHVybjtcbiAgICAgICAgICAgICAgICAgICAgICAgIH1cbiAgICAgICAgICAgICAgICAgICAgfVxuICAgICAgICAgICAgICAgIH1cbiAgICAgICAgICAgIH1cbiAgICAgICAgfVxuICAgIH1cblxuICAgIG5nQWZ0ZXJWaWV3SW5pdCgpOiB2b2lkIHtcbiAgICAgICAgLy8gdXBkYXRlIG9uIG1pbi9tYXggY2hhbmdlc1xuICAgICAgICBtZXJnZSh0aGlzLl9kYXRlUGlja2VyLm1pbiQsIHRoaXMuX2RhdGVQaWNrZXIubWF4JCkucGlwZSh0YWtlVW50aWwodGhpcy5fb25EZXN0cm95KSlcbiAgICAgICAgICAgIC5zdWJzY3JpYmUoKCkgPT4gdGhpcy5fY2hhbmdlRGV0ZWN0b3IuZGV0ZWN0Q2hhbmdlcygpKTtcbiAgICB9XG5cbiAgICBuZ09uRGVzdHJveSgpOiB2b2lkIHtcbiAgICAgICAgdGhpcy5fb25EZXN0cm95Lm5leHQoKTtcbiAgICAgICAgdGhpcy5fb25EZXN0cm95LmNvbXBsZXRlKCk7XG4gICAgfVxuXG4gICAgLyoqIEdldCB0aGUgZGlzYWJsZWQgc3RhdGUgb2YgYSBtb250aCAqL1xuICAgIGdldERpc2FibGVkKGl0ZW06IE1vbnRoVmlld0l0ZW0gfCBGb2N1c2VkTW9udGhJdGVtKTogYm9vbGVhbiB7XG5cbiAgICAgICAgY29uc3QgZGF0ZSA9IG5ldyBEYXRlKGl0ZW0ueWVhciwgaXRlbS5tb250aCk7XG5cbiAgICAgICAgLy8gaWYgd2UgYXJlIG5vdCBpbiByYW5nZSBtb2RlIHRoZW4gaXQgd2lsbCBhbHdheXMgYmUgZW5hYmxlZFxuICAgICAgICBpZiAodGhpcy5faXNSYW5nZU1vZGUpIHtcblxuICAgICAgICAgICAgLy8gaWYgd2UgYXJlIHJhbmdlIHN0YXJ0IGFuZCBkYXRlcyBhcmUgYWZ0ZXIgdGhlIHJhbmdlIGVuZCB0aGVuIHRoZXkgc2hvdWxkIGFsc28gYmUgZGlzYWJsZWRcbiAgICAgICAgICAgIGlmICh0aGlzLl9pc1JhbmdlU3RhcnQgJiYgIXRoaXMuX3JhbmdlU3RhcnQgJiYgdGhpcy5fcmFuZ2VFbmQgJiYgaXNEYXRlQWZ0ZXIoZGF0ZSwgbmV3IERhdGUodGhpcy5fcmFuZ2VFbmQuZ2V0RnVsbFllYXIoKSwgdGhpcy5fcmFuZ2VFbmQuZ2V0TW9udGgoKSkpKSB7XG4gICAgICAgICAgICAgICAgcmV0dXJuIHRydWU7XG4gICAgICAgICAgICB9XG5cbiAgICAgICAgICAgIC8vIGlmIHdlIGFyZSByYW5nZSBlbmQgYW5kIGRhdGVzIGFyZSBiZWZvcmUgdGhlIHJhbmdlIHN0YXJ0IHRoZW4gdGhleSBzaG91bGQgYWxzbyBiZSBkaXNhYmxlZFxuICAgICAgICAgICAgaWYgKHRoaXMuX2lzUmFuZ2VFbmQgJiYgIXRoaXMuX3JhbmdlRW5kICYmIHRoaXMuX3JhbmdlU3RhcnQgJiYgaXNEYXRlQmVmb3JlKGRhdGUsIG5ldyBEYXRlKHRoaXMuX3JhbmdlU3RhcnQuZ2V0RnVsbFllYXIoKSwgdGhpcy5fcmFuZ2VTdGFydC5nZXRNb250aCgpKSkpIHtcbiAgICAgICAgICAgICAgICByZXR1cm4gdHJ1ZTtcbiAgICAgICAgICAgIH1cbiAgICAgICAgfVxuXG4gICAgICAgIGlmICh0aGlzLl9taW5Nb250aCAmJiBpc0RhdGVCZWZvcmUoZGF0ZSwgdGhpcy5fbWluTW9udGgpKSB7XG4gICAgICAgICAgICByZXR1cm4gdHJ1ZTtcbiAgICAgICAgfVxuXG4gICAgICAgIGlmICh0aGlzLl9tYXhNb250aCAmJiBpc0RhdGVBZnRlcihkYXRlLCB0aGlzLl9tYXhNb250aCkpIHtcbiAgICAgICAgICAgIHJldHVybiB0cnVlO1xuICAgICAgICB9XG5cbiAgICAgICAgcmV0dXJuIGZhbHNlO1xuICAgIH1cblxuICAgIC8qKlxuICAgICAqIEdvIHRvIHRoZSBwcmV2aW91cyB5ZWFyXG4gICAgICovXG4gICAgcHJldmlvdXMoKTogdm9pZCB7XG4gICAgICAgIHRoaXMuX2RhdGVQaWNrZXIuc2V0Vmlld3BvcnRZZWFyKHRoaXMuX2RhdGVQaWNrZXIueWVhciQudmFsdWUgLSAxKTtcbiAgICB9XG5cbiAgICAvKipcbiAgICAgKiBHbyB0byB0aGUgbmV4dCB5ZWFyXG4gICAgICovXG4gICAgbmV4dCgpOiB2b2lkIHtcbiAgICAgICAgdGhpcy5fZGF0ZVBpY2tlci5zZXRWaWV3cG9ydFllYXIodGhpcy5fZGF0ZVBpY2tlci55ZWFyJC52YWx1ZSArIDEpO1xuICAgIH1cblxuICAgIC8qKlxuICAgICAqIFNlbGVjdCBhIG1vbnRoIGluIHRoZSBjYWxlbmRhclxuICAgICAqIEBwYXJhbSBtb250aCB0aGUgaW5kZXggb2YgdGhlIG1vbnRoIHRvIHNlbGVjdFxuICAgICAqL1xuICAgIHNlbGVjdChtb250aDogbnVtYmVyKTogdm9pZCB7XG4gICAgICAgIHRoaXMuX2RhdGVQaWNrZXIuc2V0Vmlld3BvcnRNb250aChtb250aCk7XG5cbiAgICAgICAgLy8gc2hvdyB0aGUgZGF5IHBpY2tlclxuICAgICAgICB0aGlzLl9kYXRlUGlja2VyLmdvVG9DaGlsZE1vZGUoKTtcbiAgICB9XG5cbiAgICBmb2N1c01vbnRoKGl0ZW06IE1vbnRoVmlld0l0ZW0sIG1vbnRoT2Zmc2V0OiBudW1iZXIpOiB2b2lkIHtcbiAgICAgICAgbGV0IHRhcmdldE1vbnRoID0gaXRlbS5tb250aCArIG1vbnRoT2Zmc2V0O1xuICAgICAgICBsZXQgdGFyZ2V0WWVhciA9IGl0ZW0ueWVhcjtcblxuICAgICAgICBpZiAodGFyZ2V0TW9udGggPCAwKSB7XG4gICAgICAgICAgICB0YXJnZXRNb250aCArPSAxMjtcbiAgICAgICAgICAgIHRhcmdldFllYXIgLT0gMTtcbiAgICAgICAgfVxuXG4gICAgICAgIGlmICh0YXJnZXRNb250aCA+PSAxMikge1xuICAgICAgICAgICAgdGFyZ2V0TW9udGggLT0gMTI7XG4gICAgICAgICAgICB0YXJnZXRZZWFyICs9IDE7XG4gICAgICAgIH1cblxuICAgICAgICB0aGlzLm1vbnRoU2VydmljZS5zZXRGb2N1cyh0YXJnZXRNb250aCwgdGFyZ2V0WWVhcik7XG4gICAgfVxuXG4gICAgdHJhY2tSb3dCeUZuKGluZGV4OiBudW1iZXIpOiBudW1iZXIge1xuICAgICAgICByZXR1cm4gaW5kZXg7XG4gICAgfVxuXG4gICAgdHJhY2tNb250aEJ5Rm4oX2luZGV4OiBudW1iZXIsIGl0ZW06IE1vbnRoVmlld0l0ZW0pOiBzdHJpbmcge1xuICAgICAgICByZXR1cm4gYCR7aXRlbS5tb250aH0gJHtpdGVtLnllYXJ9YDtcbiAgICB9XG5cbiAgICBnZXRUYWJiYWJsZShpdGVtOiBNb250aFZpZXdJdGVtKTogYm9vbGVhbiB7XG4gICAgICAgIGNvbnN0IGZvY3VzZWQgPSB0aGlzLm1vbnRoU2VydmljZS5mb2N1c2VkJC52YWx1ZTtcbiAgICAgICAgY29uc3QgZ3JpZCA9IHRoaXMubW9udGhTZXJ2aWNlLmdyaWQkLnZhbHVlO1xuXG4gICAgICAgIC8vIGlmIHRoZXJlIGlzIGEgZm9jdXNlZCBtb250aCBjaGVjayBpZiB0aGlzIGlzIGl0XG4gICAgICAgIGlmIChmb2N1c2VkKSB7XG5cbiAgICAgICAgICAgIC8vIGNoZWNrIGlmIHRoZSBmb2N1c2VkIG1vbnRoIGlzIHZpc2libGVcbiAgICAgICAgICAgIGNvbnN0IGlzRm9jdXNlZE1vbnRoVmlzaWJsZSA9ICEhZ3JpZC5maW5kKHJvdyA9PiAhIXJvdy5maW5kKF9pdGVtID0+IF9pdGVtLm1vbnRoID09PSBmb2N1c2VkLm1vbnRoICYmIF9pdGVtLnllYXIgPT09IGZvY3VzZWQueWVhcikpO1xuXG4gICAgICAgICAgICBpZiAoaXNGb2N1c2VkTW9udGhWaXNpYmxlKSB7XG4gICAgICAgICAgICAgICAgcmV0dXJuIGZvY3VzZWQubW9udGggPT09IGl0ZW0ubW9udGggJiYgZm9jdXNlZC55ZWFyID09PSBpdGVtLnllYXI7XG4gICAgICAgICAgICB9XG4gICAgICAgIH1cblxuICAgICAgICAvLyBpZiB0aGVyZSBpcyBubyBmb2N1c2FibGUgbW9udGggdGhlbiBjaGVjayBpZiB0aGVyZSBpcyBhIHNlbGVjdGVkIG1vbnRoXG4gICAgICAgIGNvbnN0IGlzU2VsZWN0ZWRNb250aFZpc2libGUgPSAhIWdyaWQuZmluZChyb3cgPT4gISFyb3cuZmluZChtb250aCA9PiBtb250aC5pc0FjdGl2ZU1vbnRoKSk7XG5cbiAgICAgICAgaWYgKGlzU2VsZWN0ZWRNb250aFZpc2libGUpIHtcbiAgICAgICAgICAgIHJldHVybiBpdGVtLmlzQWN0aXZlTW9udGg7XG4gICAgICAgIH1cblxuICAgICAgICAvLyBvdGhlcndpc2UgZmluZCB0aGUgZmlyc3Qgbm9uLWRpc2FibGVkIG1vbnRoXG4gICAgICAgIGZvciAoY29uc3Qgcm93IG9mIGdyaWQpIHtcbiAgICAgICAgICAgIGZvciAoY29uc3QgY29sdW1uIG9mIHJvdykge1xuICAgICAgICAgICAgICAgIGlmICghdGhpcy5nZXREaXNhYmxlZChjb2x1bW4pKSB7XG4gICAgICAgICAgICAgICAgICAgIHJldHVybiBpdGVtID09PSBjb2x1bW47XG4gICAgICAgICAgICAgICAgfVxuICAgICAgICAgICAgfVxuICAgICAgICB9XG5cbiAgICAgICAgcmV0dXJuIGZhbHNlO1xuICAgIH1cblxuICAgIC8qKiBBbm5vdW5jZSB0aGUgZGF0ZSB3aGVuIHdlIGZvY3VzIG9uIGEgZGF0ZSAqL1xuICAgIGFubm91bmNlUmFuZ2VNb2RlKCk6IHZvaWQge1xuICAgICAgICBpZiAodGhpcy5faXNSYW5nZU1vZGUpIHtcbiAgICAgICAgICAgIHRoaXMuX2xpdmVBbm5vdW5jZXIuYW5ub3VuY2UodGhpcy5faXNSYW5nZVN0YXJ0ID8gdGhpcy5fcmFuZ2VTZXJ2aWNlLnN0YXJ0UGlja2VyQXJpYUxhYmVsIDogdGhpcy5fcmFuZ2VTZXJ2aWNlLmVuZFBpY2tlckFyaWFMYWJlbCk7XG4gICAgICAgIH1cbiAgICB9XG5cbiAgICBzaG91bGRGb2N1cyhpdGVtOiBNb250aFZpZXdJdGVtKTogYm9vbGVhbiB7XG4gICAgICAgIGNvbnN0IGZvY3VzZWQgPSB0aGlzLm1vbnRoU2VydmljZS5mb2N1c2VkJC52YWx1ZTtcblxuICAgICAgICBpZiAoZm9jdXNlZCkge1xuICAgICAgICAgICAgcmV0dXJuIGZvY3VzZWQubW9udGggPT09IGl0ZW0ubW9udGggJiYgZm9jdXNlZC55ZWFyID09PSBpdGVtLnllYXI7XG4gICAgICAgIH1cbiAgICB9XG59XG4iLCI8ZGl2IGNsYXNzPVwiY2FsZW5kYXJcIiByb2xlPVwiZ3JpZFwiPlxuICBAZm9yIChyb3cgb2YgbW9udGhTZXJ2aWNlLmdyaWQkIHwgYXN5bmM7IHRyYWNrIHRyYWNrUm93QnlGbigkaW5kZXgpKSB7XG4gICAgPGRpdiBjbGFzcz1cImNhbGVuZGFyLXJvd1wiIHJvbGU9XCJyb3dcIj5cbiAgICAgIEBmb3IgKGl0ZW0gb2Ygcm93OyB0cmFjayB0cmFja01vbnRoQnlGbigkaW5kZXgsIGl0ZW0pKSB7XG4gICAgICAgIDxidXR0b24gdHlwZT1cImJ1dHRvblwiXG4gICAgICAgICAgdXhGb2N1c0luZGljYXRvclxuICAgICAgICAgIHV4Rm9jdXNJbmRpY2F0b3JPcmlnaW5cbiAgICAgICAgICBbcHJvZ3JhbW1hdGljRm9jdXNJbmRpY2F0b3JdPVwidHJ1ZVwiXG4gICAgICAgICAgcm9sZT1cImdyaWRjZWxsXCJcbiAgICAgICAgICBjbGFzcz1cImNhbGVuZGFyLWl0ZW1cIlxuICAgICAgICAgIFtmb2N1c0lmXT1cInNob3VsZEZvY3VzKGl0ZW0pXCJcbiAgICAgICAgICBbZGlzYWJsZWRdPVwiZ2V0RGlzYWJsZWQoaXRlbSlcIlxuICAgICAgICAgIFt0YWJpbmRleF09XCJnZXRUYWJiYWJsZShpdGVtKSA/IDAgOiAtMVwiXG4gICAgICAgICAgW2F0dHIuYXJpYS1sYWJlbF09XCJpdGVtLm5hbWUgKyAnICcgKyBpdGVtLnllYXJcIlxuICAgICAgICAgIFthdHRyLmFyaWEtc2VsZWN0ZWRdPVwiaXRlbS5pc0FjdGl2ZU1vbnRoXCJcbiAgICAgICAgICBbY2xhc3MuYWN0aXZlXT1cIml0ZW0uaXNBY3RpdmVNb250aCAmJiAhZ2V0RGlzYWJsZWQoaXRlbSlcIlxuICAgICAgICAgIFtjbGFzcy5jdXJyZW50XT1cIml0ZW0uaXNDdXJyZW50TW9udGhcIlxuICAgICAgICAgIChjbGljayk9XCJzZWxlY3QoaXRlbS5tb250aCk7ICRldmVudC5zdG9wUHJvcGFnYXRpb24oKVwiXG4gICAgICAgICAgKGZvY3VzKT1cImFubm91bmNlUmFuZ2VNb2RlKClcIlxuICAgICAgICAgIChrZXlkb3duLkFycm93TGVmdCk9XCJmb2N1c01vbnRoKGl0ZW0sIC0xKTsgJGV2ZW50LnByZXZlbnREZWZhdWx0KClcIlxuICAgICAgICAgIChrZXlkb3duLkFycm93UmlnaHQpPVwiZm9jdXNNb250aChpdGVtLCAxKTsgJGV2ZW50LnByZXZlbnREZWZhdWx0KClcIlxuICAgICAgICAgIChrZXlkb3duLkFycm93VXApPVwiZm9jdXNNb250aChpdGVtLCAtNCk7ICRldmVudC5wcmV2ZW50RGVmYXVsdCgpXCJcbiAgICAgICAgICAoa2V5ZG93bi5BcnJvd0Rvd24pPVwiZm9jdXNNb250aChpdGVtLCA0KTsgJGV2ZW50LnByZXZlbnREZWZhdWx0KClcIj5cbiAgICAgICAgICB7eyBpdGVtLm5hbWUgfX1cbiAgICAgICAgPC9idXR0b24+XG4gICAgICB9XG4gICAgPC9kaXY+XG4gIH1cbjwvZGl2PlxuIl19