@ouroboros/browser 0.1.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/hash.js ADDED
@@ -0,0 +1,195 @@
1
+ /**
2
+ * Hash
3
+ *
4
+ * JS Library to manage hash values
5
+ *
6
+ * @author Chris Nasr <chris@ouroboroscoding.com>
7
+ * @copyright Ouroboros Coding Inc.
8
+ * @created 2018-12-09
9
+ */
10
+ // Generic modules
11
+ import { clone, empty, isObject, parseQuery } from '@ouroboros/tools';
12
+ // name regex
13
+ const nameRE = /^[a-zA-Z_]+$/;
14
+ // Callbacks
15
+ const dCallbacks = {};
16
+ // Values
17
+ let dHash = {};
18
+ /**
19
+ * Hash Changed
20
+ *
21
+ * Called when the location hash has been altered, notifies any watchers of
22
+ * hash values changing
23
+ *
24
+ * @name _hashChanged
25
+ * @access private
26
+ * @return {void}
27
+ */
28
+ function _hashChanged() {
29
+ // Store the current hash
30
+ const old = clone(dHash);
31
+ // Re-parse the current location hash
32
+ dHash = parseQuery(window.location.hash.substring(1));
33
+ // If there are dCallbacks
34
+ if (!empty(dCallbacks)) {
35
+ // Check each watch
36
+ for (const name in dCallbacks) {
37
+ // If the value didn't exist and now it does, or it did exist
38
+ // and now it doesn't, or the values don't match
39
+ if ((!(name in old) && name in dHash) ||
40
+ (name in old && !(name in dHash)) ||
41
+ old[name] !== dHash[name]) {
42
+ // Go through each callback and call it
43
+ for (const f of dCallbacks[name]) {
44
+ f(dHash[name] || null);
45
+ }
46
+ }
47
+ }
48
+ }
49
+ }
50
+ /**
51
+ * Init
52
+ *
53
+ * Initialises the internal hash by fetching and parsing the current
54
+ * location hash
55
+ *
56
+ * @name init
57
+ * @access public
58
+ * @return {void}
59
+ */
60
+ function init() {
61
+ // Track changes
62
+ window.addEventListener("hashchange", _hashChanged);
63
+ // Parse the current location hash
64
+ dHash = parseQuery(window.location.hash.substring(1));
65
+ }
66
+ /**
67
+ * Get
68
+ *
69
+ * Returns a hash name
70
+ *
71
+ * @name get
72
+ * @access public
73
+ * @static
74
+ * @param {string} name The name to look for
75
+ * @param {string?} defaultReturn The value to return if the name isn't found
76
+ * @return {string | null}
77
+ */
78
+ function get(name, defaultReturn) {
79
+ // If the name is invalid
80
+ if (!nameRE.test(name)) {
81
+ throw new Error('Invalid Hash name');
82
+ }
83
+ // If there is a value for the name
84
+ if (typeof dHash[name] !== 'undefined') {
85
+ return dHash[name];
86
+ }
87
+ // Else, return the default
88
+ else {
89
+ return defaultReturn === undefined ? null : defaultReturn;
90
+ }
91
+ }
92
+ /**
93
+ * Set
94
+ *
95
+ * Sets a specific name
96
+ *
97
+ * @name set
98
+ * @access public
99
+ * @param {string | object} name The name to set, or an object of name/value pairs
100
+ * @param {string?} value The value to set the name to
101
+ */
102
+ function set(name, value) {
103
+ // If the name is not an object
104
+ if (!isObject(name)) {
105
+ // If the value is not defined
106
+ if (typeof value === 'undefined') {
107
+ value = '';
108
+ }
109
+ // Set the value
110
+ name = { [name]: value };
111
+ }
112
+ // Make a copy of the current hash
113
+ const copy = clone(dHash);
114
+ // Go through each name
115
+ for (const n of Object.keys(name)) {
116
+ // If the name is invalid
117
+ if (!nameRE.test(n)) {
118
+ throw new Error('Invalid Hash name: ' + n);
119
+ }
120
+ // If we got null, delete the name
121
+ if (name[n] === null) {
122
+ delete copy[n];
123
+ }
124
+ // Else, set the new value
125
+ else {
126
+ copy[n] = name[n];
127
+ }
128
+ }
129
+ // Init an array to store the parts
130
+ const temp = [];
131
+ // Go through each name
132
+ for (const k of Object.keys(copy)) {
133
+ temp.push(k + '=' + copy[k]);
134
+ }
135
+ // Reset the window location hash
136
+ window.location.hash = temp.join('&');
137
+ }
138
+ /**
139
+ * Subscribe
140
+ *
141
+ * Adds a callback for a specific name which will be called if the name is
142
+ * added, deleted, or changed
143
+ *
144
+ * @name subscribe
145
+ * @access public
146
+ * @param {string} name The name of the value to watch
147
+ * @param {function} callback The function to call when the value changes
148
+ * @return {void}
149
+ */
150
+ function subscribe(name, callback) {
151
+ // If we already have the name
152
+ if (name in dCallbacks) {
153
+ // Go through the callbacks associated with the name
154
+ for (const f of dCallbacks[name]) {
155
+ // If we already have the callback there's no need to store it
156
+ if (f === callback) {
157
+ return;
158
+ }
159
+ }
160
+ }
161
+ // Else if we don't have any callbacks for the name
162
+ else {
163
+ dCallbacks[name] = [];
164
+ }
165
+ // Add the callback to the dCallbacks
166
+ dCallbacks[name].push(callback);
167
+ }
168
+ /**
169
+ * Unsubscribe
170
+ *
171
+ * Removes a callback from the dCallbacks
172
+ *
173
+ * @name unsubscribe
174
+ * @access public
175
+ * @param {string} name The name of the value to stop watching
176
+ * @param {function} callback The callback to remove
177
+ * @return {void}
178
+ */
179
+ function unsubscribe(name, callback) {
180
+ // If we have the name
181
+ if (name in dCallbacks) {
182
+ // Go through the callbacks associated with the name
183
+ for (let i = 0; i < dCallbacks[name].length; ++i) {
184
+ // If we find the callback
185
+ if (dCallbacks[name][i] === callback) {
186
+ // Remove it
187
+ dCallbacks[name].splice(i, 1);
188
+ return;
189
+ }
190
+ }
191
+ }
192
+ }
193
+ // Default export
194
+ const hash = { init, get, set, subscribe, unsubscribe };
195
+ export default hash;
package/hash.ts ADDED
@@ -0,0 +1,239 @@
1
+ /**
2
+ * Hash
3
+ *
4
+ * JS Library to manage hash values
5
+ *
6
+ * @author Chris Nasr <chris@ouroboroscoding.com>
7
+ * @copyright Ouroboros Coding Inc.
8
+ * @created 2018-12-09
9
+ */
10
+
11
+ // Generic modules
12
+ import { clone, empty, isObject, parseQuery } from '@ouroboros/tools';
13
+
14
+ // Callback type
15
+ type Callback = (value: string | null) => {};
16
+
17
+ // name regex
18
+ const nameRE = /^[a-zA-Z_]+$/;
19
+
20
+ // Callbacks
21
+ const dCallbacks: Record<string, Callback[]> = {};
22
+
23
+ // Values
24
+ let dHash: Record<string, string> = {};
25
+
26
+ /**
27
+ * Hash Changed
28
+ *
29
+ * Called when the location hash has been altered, notifies any watchers of
30
+ * hash values changing
31
+ *
32
+ * @name _hashChanged
33
+ * @access private
34
+ * @return {void}
35
+ */
36
+ function _hashChanged(): void {
37
+
38
+ // Store the current hash
39
+ const old = clone(dHash);
40
+
41
+ // Re-parse the current location hash
42
+ dHash = parseQuery(window.location.hash.substring(1));
43
+
44
+ // If there are dCallbacks
45
+ if(!empty(dCallbacks)) {
46
+
47
+ // Check each watch
48
+ for(const name in dCallbacks) {
49
+
50
+ // If the value didn't exist and now it does, or it did exist
51
+ // and now it doesn't, or the values don't match
52
+ if((!(name in old) && name in dHash) ||
53
+ (name in old && !(name in dHash)) ||
54
+ old[name] !== dHash[name]) {
55
+
56
+ // Go through each callback and call it
57
+ for(const f of dCallbacks[name]) {
58
+ f(dHash[name] || null);
59
+ }
60
+ }
61
+ }
62
+ }
63
+ }
64
+
65
+ /**
66
+ * Init
67
+ *
68
+ * Initialises the internal hash by fetching and parsing the current
69
+ * location hash
70
+ *
71
+ * @name init
72
+ * @access public
73
+ * @return {void}
74
+ */
75
+ function init(): void {
76
+
77
+ // Track changes
78
+ window.addEventListener("hashchange", _hashChanged);
79
+
80
+ // Parse the current location hash
81
+ dHash = parseQuery(window.location.hash.substring(1));
82
+ }
83
+
84
+ /**
85
+ * Get
86
+ *
87
+ * Returns a hash name
88
+ *
89
+ * @name get
90
+ * @access public
91
+ * @static
92
+ * @param {string} name The name to look for
93
+ * @param {string?} defaultReturn The value to return if the name isn't found
94
+ * @return {string | null}
95
+ */
96
+ function get(name: string, defaultReturn?: string): string | null {
97
+
98
+ // If the name is invalid
99
+ if(!nameRE.test(name)) {
100
+ throw new Error('Invalid Hash name');
101
+ }
102
+
103
+ // If there is a value for the name
104
+ if(typeof dHash[name] !== 'undefined') {
105
+ return dHash[name];
106
+ }
107
+
108
+ // Else, return the default
109
+ else {
110
+ return defaultReturn === undefined ? null : defaultReturn;
111
+ }
112
+ }
113
+
114
+ /**
115
+ * Set
116
+ *
117
+ * Sets a specific name
118
+ *
119
+ * @name set
120
+ * @access public
121
+ * @param {string | object} name The name to set, or an object of name/value pairs
122
+ * @param {string?} value The value to set the name to
123
+ */
124
+ function set(name: string | object, value?: string) {
125
+
126
+ // If the name is not an object
127
+ if(!isObject(name)) {
128
+
129
+ // If the value is not defined
130
+ if(typeof value === 'undefined') {
131
+ value = '';
132
+ }
133
+
134
+ // Set the value
135
+ name = {[name as string]: value}
136
+ }
137
+
138
+ // Make a copy of the current hash
139
+ const copy = clone(dHash);
140
+
141
+ // Go through each name
142
+ for(const n of Object.keys(name)) {
143
+
144
+ // If the name is invalid
145
+ if(!nameRE.test(n)) {
146
+ throw new Error('Invalid Hash name: ' + n);
147
+ }
148
+
149
+ // If we got null, delete the name
150
+ if(name[n as keyof object] === null) {
151
+ delete copy[n];
152
+ }
153
+ // Else, set the new value
154
+ else {
155
+ copy[n] = name[n as keyof object];
156
+ }
157
+ }
158
+
159
+ // Init an array to store the parts
160
+ const temp: string[] = [];
161
+
162
+ // Go through each name
163
+ for(const k of Object.keys(copy)) {
164
+ temp.push(k + '=' + copy[k]);
165
+ }
166
+
167
+ // Reset the window location hash
168
+ window.location.hash = temp.join('&');
169
+ }
170
+
171
+ /**
172
+ * Subscribe
173
+ *
174
+ * Adds a callback for a specific name which will be called if the name is
175
+ * added, deleted, or changed
176
+ *
177
+ * @name subscribe
178
+ * @access public
179
+ * @param {string} name The name of the value to watch
180
+ * @param {function} callback The function to call when the value changes
181
+ * @return {void}
182
+ */
183
+ function subscribe(name: string, callback: Callback): void {
184
+
185
+ // If we already have the name
186
+ if(name in dCallbacks) {
187
+
188
+ // Go through the callbacks associated with the name
189
+ for(const f of dCallbacks[name]) {
190
+
191
+ // If we already have the callback there's no need to store it
192
+ if(f === callback) {
193
+ return;
194
+ }
195
+ }
196
+ }
197
+
198
+ // Else if we don't have any callbacks for the name
199
+ else {
200
+ dCallbacks[name] = [];
201
+ }
202
+
203
+ // Add the callback to the dCallbacks
204
+ dCallbacks[name].push(callback);
205
+ }
206
+
207
+ /**
208
+ * Unsubscribe
209
+ *
210
+ * Removes a callback from the dCallbacks
211
+ *
212
+ * @name unsubscribe
213
+ * @access public
214
+ * @param {string} name The name of the value to stop watching
215
+ * @param {function} callback The callback to remove
216
+ * @return {void}
217
+ */
218
+ function unsubscribe(name: string, callback: Callback): void {
219
+
220
+ // If we have the name
221
+ if(name in dCallbacks) {
222
+
223
+ // Go through the callbacks associated with the name
224
+ for(let i = 0; i < dCallbacks[name].length; ++i) {
225
+
226
+ // If we find the callback
227
+ if(dCallbacks[name][i] === callback) {
228
+
229
+ // Remove it
230
+ dCallbacks[name].splice(i, 1);
231
+ return;
232
+ }
233
+ }
234
+ }
235
+ }
236
+
237
+ // Default export
238
+ const hash = { init, get, set, subscribe, unsubscribe };
239
+ export default hash;
package/index.d.ts ADDED
@@ -0,0 +1,4 @@
1
+ export { default as clipboard } from './clipboard';
2
+ export { default as cookies } from './cookies';
3
+ export { default as hash } from './hash';
4
+ export { default as pageVisibility } from './pageVisibility';
package/index.js ADDED
@@ -0,0 +1,4 @@
1
+ export { default as clipboard } from './clipboard';
2
+ export { default as cookies } from './cookies';
3
+ export { default as hash } from './hash';
4
+ export { default as pageVisibility } from './pageVisibility';
package/index.ts ADDED
@@ -0,0 +1,4 @@
1
+ export { default as clipboard } from './clipboard';
2
+ export { default as cookies } from './cookies';
3
+ export { default as hash } from './hash';
4
+ export { default as pageVisibility } from './pageVisibility';
package/package.json ADDED
@@ -0,0 +1,38 @@
1
+ {
2
+ "name": "@ouroboros/browser",
3
+ "version": "0.1.0",
4
+ "description": "Package to handle common browser functionality.",
5
+ "main": "index.js",
6
+ "types": "index.d.ts",
7
+ "scripts": {
8
+ "build": "tslint -p tsconfig.json && tsc",
9
+ "clean": "rm *.js *.d.ts",
10
+ "test": "echo \"Error: no test specified.\" && exit 1"
11
+ },
12
+ "repository": {
13
+ "type": "git",
14
+ "url": "git+https://github.com/ouroboroscoding/browser-js.git"
15
+ },
16
+ "keywords": [
17
+ "javascript",
18
+ "browser",
19
+ "clipboard",
20
+ "cookies",
21
+ "hash",
22
+ "page visibility"
23
+ ],
24
+ "author": "Chris Nasr <chris@ouroboroscoding.com>",
25
+ "license": "MIT",
26
+ "bugs": {
27
+ "url": "https://github.com/ouroboroscoding/browser-js/issues"
28
+ },
29
+ "devDependencies": {
30
+ "tslint": "^6.1.3",
31
+ "tslint-config-prettier": "^1.18.0",
32
+ "typescript": "^4.8.3"
33
+ },
34
+ "dependencies": {
35
+ "@ouroboros/tools": "^0.1.0"
36
+ },
37
+ "peerDependencies": {}
38
+ }
@@ -0,0 +1,48 @@
1
+ /**
2
+ * Page Visibility
3
+ *
4
+ * Library/Namespace containing various functions to track page visibility
5
+ *
6
+ * @author Chris Nasr <chris@ouroboroscoding.com>
7
+ * @copyright Ouroboros Coding Inc.
8
+ * @created 2018-08-01
9
+ */
10
+ type Callback = (...args: any[]) => {};
11
+ /**
12
+ * Get
13
+ *
14
+ * Returns the current state of visibility
15
+ *
16
+ * @name get
17
+ * @access public
18
+ * @return {object | false}
19
+ */
20
+ export declare function get(): object | false;
21
+ /**
22
+ * Subscribe
23
+ *
24
+ * Track changes on page visibility
25
+ *
26
+ * @name subscribe
27
+ * @access public
28
+ * @param {function} callback Function to call on visibility changes
29
+ * @return {boolean}
30
+ */
31
+ export declare function subscribe(callback: Callback): boolean;
32
+ /**
33
+ * Ubsubscribe
34
+ *
35
+ * Stop tracking changes in page visibility
36
+ *
37
+ * @name unsubscribe
38
+ * @access public
39
+ * @param {function} callback
40
+ * @return {boolean}
41
+ */
42
+ export declare function unsubscribe(callback: Callback): boolean;
43
+ declare const pageVisibility: {
44
+ get: typeof get;
45
+ subscribe: typeof subscribe;
46
+ unsubscribe: typeof unsubscribe;
47
+ };
48
+ export default pageVisibility;
@@ -0,0 +1,132 @@
1
+ /**
2
+ * Page Visibility
3
+ *
4
+ * Library/Namespace containing various functions to track page visibility
5
+ *
6
+ * @author Chris Nasr <chris@ouroboroscoding.com>
7
+ * @copyright Ouroboros Coding Inc.
8
+ * @created 2018-08-01
9
+ */
10
+ // Init the visibility property name and event values
11
+ let bVis = false;
12
+ const dVis = {
13
+ property: 'hidden',
14
+ event: 'visibilitychange',
15
+ state: 'visibilityState'
16
+ };
17
+ const lCallbacks = [];
18
+ // Figure out the name of the visibility property and event
19
+ // Valid browser prefixes
20
+ const lPrefixes = ['moz', 'ms', 'o', 'webkit'];
21
+ // If a prefix is required
22
+ if ('hidden' in document) {
23
+ bVis = true;
24
+ }
25
+ // Else, loop through the prefixes
26
+ else {
27
+ for (const prefix of lPrefixes) {
28
+ // If the prefixes version exists
29
+ if ((prefix + 'Hidden') in document) {
30
+ dVis.property = prefix + 'Hidden';
31
+ dVis.event = prefix + 'visibilitychange';
32
+ dVis.state = prefix + 'VisibilityState';
33
+ bVis = true;
34
+ break;
35
+ }
36
+ }
37
+ }
38
+ /**
39
+ * Track
40
+ *
41
+ * The actual function passed to the event so that we only have one event listener
42
+ *
43
+ * @name track
44
+ * @access private
45
+ * @return {void}
46
+ */
47
+ function track() {
48
+ // Call the callbacks and pass them bool and state values
49
+ for (const f of lCallbacks) {
50
+ f(document[dVis.property], document[dVis.state]);
51
+ }
52
+ }
53
+ /**
54
+ * Get
55
+ *
56
+ * Returns the current state of visibility
57
+ *
58
+ * @name get
59
+ * @access public
60
+ * @return {object | false}
61
+ */
62
+ export function get() {
63
+ // If the library is available
64
+ if (bVis) {
65
+ return {
66
+ property: document[dVis.property],
67
+ state: document[dVis.state]
68
+ };
69
+ }
70
+ else {
71
+ console.error('Page Visibility API not available');
72
+ return false;
73
+ }
74
+ }
75
+ /**
76
+ * Subscribe
77
+ *
78
+ * Track changes on page visibility
79
+ *
80
+ * @name subscribe
81
+ * @access public
82
+ * @param {function} callback Function to call on visibility changes
83
+ * @return {boolean}
84
+ */
85
+ export function subscribe(callback) {
86
+ // If the Page Visibility API is not available
87
+ if (bVis === false) {
88
+ console.error('Page Visibility API not available');
89
+ return false;
90
+ }
91
+ // Save the callback for later
92
+ lCallbacks.push(callback);
93
+ // Attach an event listener if this is our first event
94
+ if (lCallbacks.length === 1) {
95
+ document.addEventListener(dVis.event, track);
96
+ }
97
+ // Return ok
98
+ return true;
99
+ }
100
+ /**
101
+ * Ubsubscribe
102
+ *
103
+ * Stop tracking changes in page visibility
104
+ *
105
+ * @name unsubscribe
106
+ * @access public
107
+ * @param {function} callback
108
+ * @return {boolean}
109
+ */
110
+ export function unsubscribe(callback) {
111
+ // If the Page Visibility API is not available
112
+ if (bVis === false) {
113
+ console.error('Page Visibility API not available');
114
+ return false;
115
+ }
116
+ // Find the index of the callback
117
+ const iIndex = lCallbacks.indexOf(callback);
118
+ // If it exists
119
+ if (iIndex > -1) {
120
+ // Remove the callback
121
+ lCallbacks.splice(iIndex, 1);
122
+ // Remove event listener if we have no more callbacks
123
+ if (lCallbacks.length === 0) {
124
+ document.removeEventListener(dVis.event, track);
125
+ }
126
+ }
127
+ // Return ok
128
+ return true;
129
+ }
130
+ // Default export
131
+ const pageVisibility = { get, subscribe, unsubscribe };
132
+ export default pageVisibility;