UNPKG

3.63 kBJavaScriptView Raw
1"use strict";
2
3const Element = require("./Element");
4const getLocation = require("./getLocation");
5const Navigator = require("./Navigator");
6const url = require("url");
7const {atob, btoa} = require("./atobtoa");
8const {Event, CustomEvent} = require("./Events");
9const {EventEmitter} = require("events");
10const {performance} = require("perf_hooks");
11
12module.exports = function Window(resp, windowObjects = {console}, innerWidth = 760, innerHeight = 760) {
13 const emitter = new EventEmitter();
14 const navigator = Navigator(resp);
15 let location = getLocation(resp.request);
16
17 let pageXOffset = 0;
18 let pageYOffset = 0;
19
20 const window = {
21 _resize: resizeWindow,
22 addEventListener,
23 dispatchEvent,
24 matchMedia,
25 history: {
26 replaceState
27 },
28 innerHeight,
29 innerWidth,
30 location,
31 navigator,
32 removeEventListener,
33 scroll,
34 requestAnimationFrame: (callback) => {
35 callback(performance.now());
36 return 0;
37 },
38 cancelAnimationFrame: () => {},
39 get window() {
40 return this;
41 },
42 Element,
43 Event,
44 CustomEvent,
45 atob,
46 btoa,
47 ...windowObjects,
48 };
49
50 Object.defineProperty(window, "pageXOffset", {
51 get: () => pageXOffset
52 });
53
54 Object.defineProperty(window, "pageYOffset", {
55 get: () => pageYOffset
56 });
57
58 Object.defineProperty(window, "self", {
59 get: () => window
60 });
61
62 Object.defineProperty(window, "location", {
63 get: () => location,
64 set(value) {
65 const previousHref = location.href;
66 let newLocation = getLocation({url: value});
67
68 if (!newLocation.host) {
69 newLocation = getLocation({url: url.resolve(previousHref, value)});
70 }
71
72 if (previousHref + newLocation.hash !== newLocation.href) {
73 emitter.emit("unload");
74 }
75
76 location = newLocation;
77 }
78 });
79
80 return window;
81
82 function addEventListener(...args) {
83 emitter.on(...args);
84 }
85
86 function dispatchEvent(event, ...args) {
87 if (event === undefined) throw new TypeError("Failed to execute 'dispatchEvent' on 'EventTarget': 1 argument required, but only 0 present.");
88 if (typeof event === "string") {
89 return emitter.emit(event, ...args);
90 }
91
92 if (!event.type) return;
93 return emitter.emit(event.type, event);
94 }
95
96 function removeEventListener(...args) {
97 emitter.removeListener(...args);
98 }
99
100 function matchMedia(media) {
101 if (media === undefined) throw new TypeError("Failed to execute 'matchMedia' on 'Window': 1 argument required, but only 0 present.");
102 if (typeof media === "string") {
103 window.styleMedia = window.styleMedia || { type: "screen" };
104 return {
105 media,
106 matches: media === window.styleMedia.type
107 };
108 }
109 }
110
111 function replaceState(ign1, ign2, relativeUrl) {
112 const newUrl = url.parse(relativeUrl);
113 location.path = newUrl.path;
114 location.pathname = newUrl.pathname;
115 location.search = newUrl.search;
116 location.href = url.format(location);
117 }
118
119 function scroll(xCoord, yCoord) {
120 if (xCoord && typeof xCoord === "object") {
121 const {top, left} = xCoord;
122 pageYOffset = !isNaN(top) ? top : pageYOffset;
123 pageXOffset = !isNaN(left) ? left : pageXOffset;
124 } else {
125 if (xCoord !== undefined) pageXOffset = xCoord;
126 if (yCoord !== undefined) pageYOffset = yCoord;
127 }
128 dispatchEvent("scroll");
129 }
130
131 function resizeWindow(newInnerWidth, newInnerHeight) {
132 if (newInnerWidth !== undefined) {
133 window.innerWidth = newInnerWidth;
134 }
135 if (newInnerHeight !== undefined) {
136 window.innerHeight = newInnerHeight;
137 }
138 window.dispatchEvent("resize");
139 }
140};