browser-extension-utils 0.0.14 → 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/lib/index.d.ts CHANGED
@@ -1,34 +1,28 @@
1
+ export const doc: Document
2
+
1
3
  export function uniq(array: any[]): any[]
2
4
 
3
5
  export function toCamelCase(text: string): string
4
6
 
5
- export function $(selectors: string): HTMLElement
6
-
7
7
  export function $(
8
- element: HTMLElement | Document | string,
9
- selectors: string
10
- ): HTMLElement
11
-
12
- export function querySelector(selectors: string): HTMLElement
8
+ selectors: string,
9
+ element?: HTMLElement | Document
10
+ ): Element | undefined
13
11
 
14
12
  export function querySelector(
15
- element: HTMLElement | Document | string,
16
- selectors: string
17
- ): HTMLElement
18
-
19
- export function $$(selectors: string): HTMLElement[]
13
+ selectors: string,
14
+ element?: HTMLElement | Document
15
+ ): Element | undefined
20
16
 
21
17
  export function $$(
22
- element: HTMLElement | Document | string,
23
- selectors: string
24
- ): HTMLElement[]
25
-
26
- export function querySelectorAll(selectors: string): HTMLElement[]
18
+ selectors: string,
19
+ element?: HTMLElement | Document
20
+ ): Element[]
27
21
 
28
22
  export function querySelectorAll(
29
- element: HTMLElement | Document | string,
30
- selectors: string
31
- ): HTMLElement[]
23
+ selectors: string,
24
+ element?: HTMLElement | Document
25
+ ): Element[]
32
26
 
33
27
  export function createElement(
34
28
  tagName: string,
@@ -85,6 +79,12 @@ export function setAttributes(
85
79
  attributes: Record<string, unknown>
86
80
  ): void
87
81
 
82
+ export function addAttribute(
83
+ element: HTMLElement,
84
+ name: string,
85
+ value: string
86
+ ): void
87
+
88
88
  export type SetStyle = (
89
89
  element: HTMLElement,
90
90
  style: string | Record<string, unknown>,
@@ -105,9 +105,13 @@ export function createSetStyle(styleText: string): SetStyle
105
105
 
106
106
  export function isUrl(text: string): boolean
107
107
 
108
+ export function throttle(func: Function, delay: number): Function
109
+
108
110
  export type MenuCallback = (event?: MouseEvent | KeyboardEvent) => void
109
111
  export function registerMenuCommand(
110
112
  name: string,
111
113
  callback: MenuCallback,
112
114
  accessKey?: string
113
115
  ): void
116
+
117
+ export function extendHistoryApi(): void
package/lib/index.js CHANGED
@@ -1,4 +1,4 @@
1
- const doc = document
1
+ export const doc = document
2
2
 
3
3
  export const uniq = (array) => [...new Set(array)]
4
4
 
@@ -9,14 +9,11 @@ export const toCamelCase = function (text) {
9
9
  })
10
10
  }
11
11
 
12
- export const $ = (element, selectors) =>
13
- element && typeof element === "object"
14
- ? element.querySelector(selectors)
15
- : doc.querySelector(element)
16
- export const $$ = (element, selectors) =>
17
- element && typeof element === "object"
18
- ? [...element.querySelectorAll(selectors)]
19
- : [...doc.querySelectorAll(element)]
12
+ export const $ = (selectors, element) =>
13
+ (element || doc).querySelector(selectors)
14
+ export const $$ = (selectors, element) => [
15
+ ...(element || doc).querySelectorAll(selectors),
16
+ ]
20
17
  export const querySelector = $
21
18
  export const querySelectorAll = $$
22
19
 
@@ -94,7 +91,11 @@ export const setAttributes = (element, attributes) => {
94
91
  for (const name in attributes) {
95
92
  if (Object.hasOwn(attributes, name)) {
96
93
  const value = attributes[name]
97
- if (name === "textContent") {
94
+ if (value === undefined) {
95
+ continue
96
+ }
97
+
98
+ if (/^(value|textContent|innerText|innerHTML)$/.test(name)) {
98
99
  element[name] = value
99
100
  } else if (name === "style") {
100
101
  setStyle(element, value, true)
@@ -111,6 +112,15 @@ export const setAttributes = (element, attributes) => {
111
112
  return element
112
113
  }
113
114
 
115
+ export const addAttribute = (element, name, value) => {
116
+ const orgValue = getAttribute(element, name)
117
+ if (!orgValue) {
118
+ setAttribute(element, name, value)
119
+ } else if (!orgValue.includes(value)) {
120
+ setAttribute(element, name, orgValue + " " + value)
121
+ }
122
+ }
123
+
114
124
  export const setStyle = (element, values, overwrite) => {
115
125
  if (!element) {
116
126
  return
@@ -165,7 +175,7 @@ export const toStyleMap = (styleText) => {
165
175
  return map
166
176
  }
167
177
 
168
- export const noStyleSpace = (text) => text.replace(/\s*([^\w-!])\s*/gm, "$1")
178
+ export const noStyleSpace = (text) => text.replace(/\s*([^\w-+%!])\s*/gm, "$1")
169
179
 
170
180
  export const createSetStyle = (styleText) => {
171
181
  const styleMap = toStyleMap(styleText)
@@ -182,9 +192,56 @@ export const createSetStyle = (styleText) => {
182
192
 
183
193
  export const isUrl = (text) => /^https?:\/\//.test(text)
184
194
 
195
+ /**
196
+ *
197
+ * @param { function } func
198
+ * @param { number } delay
199
+ * @returns
200
+ */
201
+ export const throttle = (func, delay) => {
202
+ let timer = null
203
+ return function (...args) {
204
+ if (!timer) {
205
+ timer = setTimeout(() => {
206
+ func.apply(this, args)
207
+ timer = null
208
+ }, delay)
209
+ }
210
+ }
211
+ }
212
+
185
213
  if (typeof Object.hasOwn !== "function") {
186
214
  Object.hasOwn = (instance, prop) =>
187
215
  Object.prototype.hasOwnProperty.call(instance, prop)
188
216
  }
189
217
 
190
218
  export const registerMenuCommand = () => undefined
219
+
220
+ export const extendHistoryApi = () => {
221
+ // https://dirask.com/posts/JavaScript-on-location-changed-event-on-url-changed-event-DKeyZj
222
+ const pushState = history.pushState
223
+ const replaceState = history.replaceState
224
+
225
+ history.pushState = function () {
226
+ // eslint-disable-next-line prefer-rest-params
227
+ pushState.apply(history, arguments)
228
+ window.dispatchEvent(new Event("pushstate"))
229
+ window.dispatchEvent(new Event("locationchange"))
230
+ }
231
+
232
+ history.replaceState = function () {
233
+ // eslint-disable-next-line prefer-rest-params
234
+ replaceState.apply(history, arguments)
235
+ window.dispatchEvent(new Event("replacestate"))
236
+ window.dispatchEvent(new Event("locationchange"))
237
+ }
238
+
239
+ window.addEventListener("popstate", function () {
240
+ window.dispatchEvent(new Event("locationchange"))
241
+ })
242
+
243
+ // Usage example:
244
+ // window.addEventListener("locationchange", function () {
245
+ // console.log("onlocationchange event occurred!")
246
+ // })
247
+ }
package/lib/userscript.js CHANGED
@@ -1,10 +1,22 @@
1
- import { setAttributes } from "./index.js"
1
+ import {
2
+ setAttributes,
3
+ addElement as _addElement,
4
+ addStyle as _addStyle,
5
+ } from "./index.js"
2
6
 
3
7
  export * from "./index.js"
4
8
 
5
9
  // eslint-disable-next-line no-unused-expressions, n/prefer-global/process
6
10
  process.env.PLASMO_TAG === "dev" &&
7
11
  (() => {
12
+ /* eslint-disable camelcase */
13
+ console.log(
14
+ typeof GM_addElement,
15
+ typeof GM_addStyle,
16
+ typeof GM_registerMenuCommand,
17
+ typeof GM
18
+ )
19
+ /* eslint-enable camelcase */
8
20
  const functions = document.GMFunctions
9
21
  if (typeof functions === "object") {
10
22
  for (const key in functions) {
@@ -15,23 +27,34 @@ process.env.PLASMO_TAG === "dev" &&
15
27
  }
16
28
  })()
17
29
 
18
- /* eslint-disable new-cap */
19
- export const addElement = (parentNode, tagName, attributes) => {
20
- if (typeof parentNode === "string" || typeof tagName === "string") {
21
- const element = GM_addElement(parentNode, tagName, attributes)
22
- setAttributes(element, attributes)
23
- return element
24
- }
30
+ /* eslint-disable new-cap, camelcase */
31
+ export const addElement =
32
+ typeof GM_addElement === "function"
33
+ ? (parentNode, tagName, attributes) => {
34
+ if (typeof parentNode === "string" || typeof tagName === "string") {
35
+ const element = GM_addElement(parentNode, tagName)
36
+ setAttributes(element, attributes)
37
+ return element
38
+ }
25
39
 
26
- // tagName: HTMLElement
27
- setAttributes(tagName, attributes)
28
- parentNode.append(tagName)
29
- return tagName
30
- }
40
+ // tagName: HTMLElement
41
+ setAttributes(tagName, attributes)
42
+ parentNode.append(tagName)
43
+ return tagName
44
+ }
45
+ : _addElement
31
46
 
32
- export const addStyle = (styleText) => GM_addStyle(styleText)
47
+ export const addStyle =
48
+ typeof GM_addStyle === "function"
49
+ ? (styleText) => GM_addStyle(styleText)
50
+ : _addStyle
33
51
 
34
52
  // Only register menu on top frame
35
- export const registerMenuCommand = (name, callback, accessKey) =>
36
- window === top && GM_registerMenuCommand(name, callback, accessKey)
37
- /* eslint-enable new-cap */
53
+ export const registerMenuCommand = (name, callback, accessKey) => {
54
+ if (window !== top || !GM || !GM.registerMenuCommand) {
55
+ return
56
+ }
57
+
58
+ GM.registerMenuCommand(name, callback, accessKey)
59
+ }
60
+ /* eslint-enable new-cap, camelcase */
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "browser-extension-utils",
3
- "version": "0.0.14",
3
+ "version": "0.1.0",
4
4
  "description": "Utilities for developing browser extensions and userscripts",
5
5
  "type": "module",
6
6
  "main": "./lib/index.js",
@@ -29,8 +29,8 @@
29
29
  },
30
30
  "homepage": "https://github.com/PipecraftNet/browser-extension-utils#readme",
31
31
  "devDependencies": {
32
- "prettier": "^2.8.7",
33
- "xo": "^0.53.1"
32
+ "prettier": "^2.8.8",
33
+ "xo": "^0.54.2"
34
34
  },
35
35
  "files": [
36
36
  "lib/",
@@ -44,9 +44,11 @@
44
44
  "space": 2,
45
45
  "prettier": true,
46
46
  "globals": [
47
+ "GM",
47
48
  "GM_addElement",
48
49
  "GM_addStyle",
49
50
  "GM_registerMenuCommand",
51
+ "history",
50
52
  "window",
51
53
  "top",
52
54
  "document"