Skip to content

Commit

Permalink
Add window as alias to globalThis
Browse files Browse the repository at this point in the history
Closes #60.
  • Loading branch information
TooTallNate committed Nov 10, 2023
1 parent c1e0f51 commit 06bdc88
Show file tree
Hide file tree
Showing 5 changed files with 121 additions and 79 deletions.
5 changes: 5 additions & 0 deletions .changeset/wise-birds-smoke.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
---
'nxjs-runtime': patch
---

Add `window` as alias to `globalThis`
1 change: 1 addition & 0 deletions apps/tests/src/main.ts
Original file line number Diff line number Diff line change
Expand Up @@ -6,3 +6,4 @@ import './import';
import './navigator';
import './switch';
import './wasm';
import './window';
35 changes: 35 additions & 0 deletions apps/tests/src/window.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,35 @@
import { suite } from 'uvu';
import * as assert from 'uvu/assert';

const test = suite('window');

test('instanceof', () => {
assert.equal(window instanceof Window, true);
assert.equal(globalThis instanceof Window, true);
assert.equal(globalThis === window, true);
});

test('throws illegal constructor', () => {
let err: Error | undefined;
try {
new Window();
} catch (e: any) {
err = e;
}
assert.ok(err);
assert.equal(err.message, 'Illegal constructor');
});

test('supports global events', () => {
let gotEvent = false;
addEventListener('test', (e) => {
gotEvent = true;
e.preventDefault();
});
const e = new Event('test');
dispatchEvent(e);
assert.ok(gotEvent);
assert.ok(e.defaultPrevented);
});

test.run();
81 changes: 2 additions & 79 deletions packages/runtime/src/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -128,85 +128,8 @@ function touchIsEqual(a: Touch, b: Touch) {
);
}

// Make `globalThis` inherit from `EventTarget`
Object.setPrototypeOf(globalThis, EventTarget.prototype);
EventTarget.call(globalThis);
def(
'addEventListener',
EventTarget.prototype.addEventListener.bind(globalThis)
);
def(
'removeEventListener',
EventTarget.prototype.removeEventListener.bind(globalThis)
);
def('dispatchEvent', EventTarget.prototype.dispatchEvent.bind(globalThis));

/**
* The `error` event is sent to the global scope when an unhandled error is thrown.
*
* The default behavior when this event occurs is to print the error to the screen
* using {@link console.error | `console.error()`}, and no further application code
* is executed. The user must then press the `+` button to exit the application.
* Call `event.preventDefault()` to supress this default behavior.
*
* @see https://developer.mozilla.org/docs/Web/API/Window/error_event
*/
export declare function addEventListener(
type: 'error',
callback: (event: ErrorEvent) => any,
options?: AddEventListenerOptions | boolean
): void;

/**
* The `unhandledrejection` event is sent to the global scope when a JavaScript
* Promise that has no rejection handler is rejected.
*
* The default behavior when this event occurs is to print the error to the screen
* using {@link console.error | `console.error()`}, and no further application code
* is executed. The user must then press the `+` button to exit the application.
* Call `event.preventDefault()` to supress this default behavior.
*
* @see https://developer.mozilla.org/docs/Web/API/Window/unhandledrejection_event
*/
export declare function addEventListener(
type: 'unhandledrejection',
callback: (event: PromiseRejectionEvent) => any,
options?: AddEventListenerOptions | boolean
): void;
export declare function addEventListener(
type: string,
callback: EventListenerOrEventListenerObject | null,
options?: AddEventListenerOptions | boolean
): void;

export declare function removeEventListener(
type: 'error',
callback: (ev: ErrorEvent) => any,
options?: EventListenerOptions | boolean
): void;
export declare function removeEventListener(
type: 'unhandledrejection',
callback: (ev: PromiseRejectionEvent) => any,
options?: EventListenerOptions | boolean
): void;

/**
* Removes the event listener in target's event listener list with the same type, callback, and options.
*
* @see {@link https://developer.mozilla.org/docs/Web/API/EventTarget/removeEventListener | MDN Reference}
*/
export declare function removeEventListener(
type: string,
callback: EventListenerOrEventListenerObject | null,
options?: EventListenerOptions | boolean
): void;

/**
* Dispatches a synthetic event event to target and returns true if either event's cancelable attribute value is false or its `preventDefault()` method was not invoked, and false otherwise.
*
* @see {@link https://developer.mozilla.org/docs/Web/API/EventTarget/dispatchEvent | MDN Reference}
*/
export declare function dispatchEvent(event: Event): boolean;
import './window';
export type * from './window';

$.onError((e) => {
const ev = new ErrorEvent('error', {
Expand Down
78 changes: 78 additions & 0 deletions packages/runtime/src/window.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,78 @@
import { assertInternalConstructor, def } from './utils';

export class Window extends EventTarget {
/**
* @ignore
*/
constructor() {
assertInternalConstructor(arguments);
super();
}
}
def('Window', Window);

export const window: Window & typeof globalThis = globalThis;
def('window', window);
Object.setPrototypeOf(window, Window.prototype);
EventTarget.call(window);

// Temporary band-aid since EventTarget does not default `this` to `globalThis`
def('addEventListener', window.addEventListener.bind(window));
def('removeEventListener', window.removeEventListener.bind(window));
def('dispatchEvent', window.dispatchEvent.bind(window));

/**
* The `error` event is sent to the global scope when an unhandled error is thrown.
*
* The default behavior when this event occurs is to print the error to the screen
* using {@link console.error | `console.error()`}, and no further application code
* is executed. The user must then press the `+` button to exit the application.
* Call `event.preventDefault()` to supress this default behavior.
*
* @see https://developer.mozilla.org/docs/Web/API/Window/error_event
*/
export declare function addEventListener(
type: 'error',
callback: (event: ErrorEvent) => any,
options?: AddEventListenerOptions | boolean
): void;

/**
* The `unhandledrejection` event is sent to the global scope when a JavaScript
* Promise that has no rejection handler is rejected.
*
* The default behavior when this event occurs is to print the error to the screen
* using {@link console.error | `console.error()`}, and no further application code
* is executed. The user must then press the `+` button to exit the application.
* Call `event.preventDefault()` to supress this default behavior.
*
* @see https://developer.mozilla.org/docs/Web/API/Window/unhandledrejection_event
*/
export declare function addEventListener(
type: 'unhandledrejection',
callback: (event: PromiseRejectionEvent) => any,
options?: AddEventListenerOptions | boolean
): void;
export declare function addEventListener(
type: string,
callback: EventListenerOrEventListenerObject | null,
options?: AddEventListenerOptions | boolean
): void;

/**
* Removes the event listener in target's event listener list with the same type, callback, and options.
*
* @see {@link https://developer.mozilla.org/docs/Web/API/EventTarget/removeEventListener | MDN Reference}
*/
export declare function removeEventListener(
type: string,
callback: EventListenerOrEventListenerObject | null,
options?: EventListenerOptions | boolean
): void;

/**
* Dispatches a synthetic event event to target and returns true if either event's cancelable attribute value is false or its `preventDefault()` method was not invoked, and false otherwise.
*
* @see {@link https://developer.mozilla.org/docs/Web/API/EventTarget/dispatchEvent | MDN Reference}
*/
export declare function dispatchEvent(event: Event): boolean;

0 comments on commit 06bdc88

Please sign in to comment.