reactronic-dom
Version:
Reactronic DOM - Transactional Reactive Front-End Development Framework
184 lines (183 loc) • 8.49 kB
JavaScript
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;
}