@ima/core
Version:
IMA.js framework for isomorphic javascript application
211 lines (210 loc) • 6.38 kB
JavaScript
import { Window } from './Window';
/**
* Client-side implementation of the {@link Window} utility API.
*/ export class ClientWindow extends Window {
#scopedListeners = new WeakMap();
static get $dependencies() {
return [];
}
/**
* @inheritDoc
*/ isClient() {
return true;
}
/**
* @inheritDoc
*/ isCookieEnabled() {
return navigator.cookieEnabled;
}
/**
* @inheritDoc
*/ hasSessionStorage() {
try {
if (window.sessionStorage) {
const sessionKey = 'IMA.jsTest';
sessionStorage.setItem(sessionKey, '1');
sessionStorage.removeItem(sessionKey);
return true;
}
} catch (error) {
if ($Debug) {
console.warn('Session Storage is not accessible!', error);
}
return false;
}
return false;
}
/**
* @inheritDoc
*/ setTitle(title) {
document.title = title;
}
/**
* @inheritDoc
*/ getWindow() {
return window;
}
/**
* @inheritDoc
*/ getDocument() {
return document;
}
/**
* @inheritDoc
*/ getScrollX() {
const { pageXOffset } = window;
const pageOffsetSupported = pageXOffset !== undefined;
const isCSS1Compatible = (document.compatMode || '') === 'CSS1Compat';
return pageOffsetSupported ? pageXOffset : isCSS1Compatible ? document.documentElement.scrollLeft : document.body.scrollLeft;
}
/**
* @inheritDoc
*/ getScrollY() {
const { pageYOffset } = window;
const pageOffsetSupported = pageYOffset !== undefined;
const isCSS1Compatible = (document.compatMode || '') === 'CSS1Compat';
return pageOffsetSupported ? pageYOffset : isCSS1Compatible ? document.documentElement.scrollTop : document.body.scrollTop;
}
/**
* @inheritDoc
*/ scrollTo(x, y) {
window.scrollTo(x, y);
}
/**
* @inheritDoc
*/ getDomain() {
return window.location.protocol + '//' + window.location.host;
}
/**
* @inheritDoc
*/ getHost() {
return window.location.host;
}
/**
* @inheritDoc
*/ getPath() {
return window.location.pathname + window.location.search;
}
/**
* @inheritDoc
*/ getUrl() {
return window.location.href;
}
/**
* @inheritDoc
*/ getBody() {
return document.body;
}
/**
* @inheritDoc
*/ getElementById(id) {
return document.getElementById(id);
}
/**
* @inheritDoc
*/ getHistoryState() {
return window.history.state;
}
/**
* @inheritDoc
*/ querySelector(selector) {
return document.querySelector(selector);
}
/**
* @inheritDoc
*/ querySelectorAll(selector) {
return document.querySelectorAll(selector);
}
/**
* @inheritDoc
*/ redirect(url) {
window.location.href = url;
}
/**
* @inheritDoc
*/ pushState(state, title, url) {
if (window.history.pushState) {
window.history.pushState(state, title, url);
}
}
/**
* @inheritDoc
*/ replaceState(state, title, url) {
if (window.history.replaceState) {
window.history.replaceState(state, title, url);
}
}
/**
* @inheritDoc
*/ createCustomEvent(name, options) {
return new CustomEvent(name, options);
}
/**
* @inheritDoc
*/ bindEventListener(eventTarget, event, listener, options = false, scope) {
if (!eventTarget.addEventListener) {
return;
}
let scopedListener;
if (scope) {
scopedListener = this._findScopedListener(eventTarget, event, listener, options, scope);
if (!scopedListener) {
scopedListener = listener.bind(scope);
// Add scoped listener
if (!this.#scopedListeners.has(eventTarget)) {
this.#scopedListeners.set(eventTarget, new Map());
}
const scopedListeners = this.#scopedListeners.get(eventTarget);
scopedListeners.set([
event,
listener,
this._getListenerCapture(options),
scope
], scopedListener);
}
}
eventTarget.addEventListener(event, scopedListener ?? listener, options);
}
/**
* @inheritDoc
*/ unbindEventListener(eventTarget, event, listener, options = false, scope) {
if (!eventTarget.addEventListener) {
return;
}
let scopedListener;
if (scope) {
scopedListener = this._findScopedListener(eventTarget, event, listener, options, scope, true);
if ($Debug && !scopedListener) {
console.warn('ima.core.window.ClientWindow.unbindEventListener(): the provided ' + `listener '${listener}' is not registered for the ` + `specified event '${event}' and scope '${scope}'. Check ` + `your workflow.`, {
event,
listener,
scope
});
}
}
eventTarget.removeEventListener(event, scopedListener ?? listener, options);
}
_findScopedListener(eventTarget, event, listener, options, scope, remove = false) {
if (!this.#scopedListeners.has(eventTarget)) {
return;
}
const scopedListeners = this.#scopedListeners.get(eventTarget);
for (const key of scopedListeners.keys()){
const [scopedEvent, scopedListener, scopedCapture, scopedScope] = key;
if (event === scopedEvent && listener === scopedListener && this._getListenerCapture(options) === scopedCapture && scope === scopedScope) {
const usedListener = scopedListeners.get(key);
if (remove) {
scopedListeners.delete(key);
if (!scopedListeners.size) {
this.#scopedListeners.delete(eventTarget);
}
}
return usedListener;
}
}
}
_getListenerCapture(options) {
return typeof options === 'boolean' ? options : options.capture ?? false;
}
}
//# sourceMappingURL=ClientWindow.js.map