UNPKG

reactronic-dom

Version:

Reactronic DOM - Transactional Reactive Front-End Development Framework

184 lines (183 loc) 8.49 kB
var __decorate = (this && this.__decorate) || function (decorators, target, key, desc) { var c = arguments.length, r = c < 3 ? target : desc === null ? desc = Object.getOwnPropertyDescriptor(target, key) : desc, d; if (typeof Reflect === "object" && typeof Reflect.decorate === "function") r = Reflect.decorate(decorators, target, key, desc); else for (var i = decorators.length - 1; i >= 0; i--) if (d = decorators[i]) r = (c < 3 ? d(r) : c > 3 ? d(target, key, r) : d(target, key)) || r; return c > 3 && r && Object.defineProperty(target, key, r), r; }; var __metadata = (this && this.__metadata) || function (k, v) { if (typeof Reflect === "object" && typeof Reflect.metadata === "function") return Reflect.metadata(k, v); }; import { options, transaction, LoggingLevel } from 'reactronic'; import { objectHasMember } from '../../core/Utils'; import { grabElementDataList, SymDataForSensor } from './DataForSensor'; import { HtmlElementSensor } from './HtmlElementSensor'; export class FocusSensor extends HtmlElementSensor { constructor(windowSensor) { super(undefined, windowSensor); this.activeData = undefined; this.oldActiveData = undefined; this.contextElementDataList = []; } setActiveData(data, debugHint = '') { var _a, _b; if (data !== this.activeData) { const activeData = this.activeData; if (activeData !== undefined && objectHasMember(activeData, 'isFocused')) { activeData.isFocused = false; (_a = activeData.onFocusOut) === null || _a === void 0 ? void 0 : _a.call(activeData, this); } if (data !== undefined) { if (objectHasMember(data, 'isFocused')) { data.isFocused = true; (_b = data.onFocusIn) === null || _b === void 0 ? void 0 : _b.call(data, this); } } this.oldActiveData = activeData; this.activeData = data; } } listen(element, enabled = true) { const existing = this.sourceElement; if (element !== existing) { if (existing) { existing.removeEventListener('focusin', this.onFocusIn.bind(this), { capture: true }); existing.removeEventListener('focusout', this.onFocusOut.bind(this), { capture: true }); existing.removeEventListener('mousedown', this.onMouseDown.bind(this), { capture: true }); } this.sourceElement = element; if (element && enabled) { element.addEventListener('focusin', this.onFocusIn.bind(this), { capture: true }); element.addEventListener('focusout', this.onFocusOut.bind(this), { capture: true }); element.addEventListener('mousedown', this.onMouseDown.bind(this), { capture: true }); } } } reset() { this.preventDefault = false; this.stopPropagation = false; this.revision++; } onFocusIn(e) { this.doFocusIn(e); this.setPreventDefaultAndStopPropagation(e); } onFocusOut(e) { this.doFocusOut(e); this.setPreventDefaultAndStopPropagation(e); } onMouseDown(e) { this.doMouseDown(e); } doFocusIn(e) { var _a; const path = e.composedPath(); const { dataList: focusDataList, activeData: focusActiveData, window } = grabElementDataList(path, SymDataForSensor, 'focus', this.elementDataList, false, e => document.activeElement === e); this.elementDataList = focusDataList; this.setActiveData(focusActiveData); (_a = this.windowSensor) === null || _a === void 0 ? void 0 : _a.setActiveWindow(window); const { dataList: contextDataList } = grabElementDataList(path, SymDataForSensor, 'context', this.contextElementDataList, true); this.contextElementDataList = toggleContextRefs(this, this.contextElementDataList, contextDataList); this.reset(); } doFocusOut(e) { var _a; const isLosingFocus = e.relatedTarget === null; if (isLosingFocus) { const path = e.composedPath(); const { dataList } = grabElementDataList(path, SymDataForSensor, 'focus', this.elementDataList, true); this.elementDataList = dataList; const filteredElementDataList = dataList.filter(x => x !== this.activeData); if (filteredElementDataList.length > 0) { this.trySetFocus(filteredElementDataList[0], ' └─'); } else { const defaultData = this.getDefaultSensorData(); if ((defaultData === null || defaultData === void 0 ? void 0 : defaultData.focus) !== undefined) { this.trySetFocus(defaultData.focus, ' └─'); } else { this.setActiveData(undefined); } (_a = this.windowSensor) === null || _a === void 0 ? void 0 : _a.setActiveWindow(defaultData === null || defaultData === void 0 ? void 0 : defaultData.window); } this.contextElementDataList = toggleContextRefs(this, this.contextElementDataList, []); this.reset(); } else { } } doMouseDown(e) { var _a, _b; const path = e.composedPath(); const isFirstElementFocusable = ((_b = (_a = path[0]) === null || _a === void 0 ? void 0 : _a.tabIndex) !== null && _b !== void 0 ? _b : -1) >= 0; if (path.length > 0 && !isFirstElementFocusable) { const { dataList } = grabElementDataList(path, SymDataForSensor, 'focus', this.elementDataList, true); this.elementDataList = dataList; if (dataList.length > 0) { this.trySetFocus(dataList[0], '└─'); e.preventDefault(); } const { dataList: contextDataList } = grabElementDataList(path, SymDataForSensor, 'context', this.contextElementDataList, true); this.contextElementDataList = toggleContextRefs(this, this.contextElementDataList, contextDataList); this.reset(); } else { } } trySetFocus(candidateData, indent = '') { if (candidateData !== undefined && objectHasMember(candidateData, 'isFocused')) { candidateData.isFocused = true; } } } __decorate([ transaction, __metadata("design:type", Function), __metadata("design:paramtypes", [Object, String]), __metadata("design:returntype", void 0) ], FocusSensor.prototype, "setActiveData", null); __decorate([ transaction, __metadata("design:type", Function), __metadata("design:paramtypes", [Object, Boolean]), __metadata("design:returntype", void 0) ], FocusSensor.prototype, "listen", null); __decorate([ transaction, options({ logging: LoggingLevel.Off }), __metadata("design:type", Function), __metadata("design:paramtypes", [FocusEvent]), __metadata("design:returntype", void 0) ], FocusSensor.prototype, "doFocusIn", null); __decorate([ transaction, __metadata("design:type", Function), __metadata("design:paramtypes", [FocusEvent]), __metadata("design:returntype", void 0) ], FocusSensor.prototype, "doFocusOut", null); __decorate([ transaction, options({ logging: LoggingLevel.Off }), __metadata("design:type", Function), __metadata("design:paramtypes", [MouseEvent]), __metadata("design:returntype", void 0) ], FocusSensor.prototype, "doMouseDown", null); function toggleContextRefs(focusSensor, existing, updated) { if (updated !== existing) { existing.forEach(x => { var _a; if (objectHasMember(x, 'contextToggle') && x.contextToggle && x.contextToggle.valueOn !== x.contextToggle.valueOff) x.contextToggle.value = x.contextToggle.valueOff; if (objectHasMember(x, 'onContextOut')) (_a = x.onContextOut) === null || _a === void 0 ? void 0 : _a.call(x, focusSensor); }); updated.forEach(x => { var _a; if (objectHasMember(x, 'contextToggle') && x.contextToggle) x.contextToggle.value = x.contextToggle.valueOn; if (objectHasMember(x, 'onContextIn')) (_a = x.onContextIn) === null || _a === void 0 ? void 0 : _a.call(x, focusSensor); }); } return updated; }