@kudoai/chatgpt.js 3.4.0 → 3.6.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/LICENSE.md +1 -1
- package/README.md +153 -86
- package/chatgpt.js +91 -76
- package/dist/chatgpt.min.js +4 -4
- package/docs/README.md +153 -86
- package/docs/SECURITY.md +16 -18
- package/docs/USERGUIDE.md +19 -5
- package/package.json +9 -6
- package/starters/chrome/LICENSE.md +3 -3
- package/starters/chrome/docs/README.md +5 -5
- package/starters/chrome/docs/SECURITY.md +3 -5
- package/starters/chrome/extension/components/icons.js +4 -5
- package/starters/chrome/extension/components/modals.js +98 -65
- package/starters/chrome/extension/content.js +41 -47
- package/starters/chrome/extension/icons/faded/icon128.png +0 -0
- package/starters/chrome/extension/icons/faded/icon16.png +0 -0
- package/starters/chrome/extension/icons/faded/icon32.png +0 -0
- package/starters/chrome/extension/icons/faded/icon64.png +0 -0
- package/starters/chrome/extension/lib/chatgpt.js +91 -76
- package/starters/chrome/extension/lib/dom.js +70 -11
- package/starters/chrome/extension/lib/settings.js +8 -9
- package/starters/chrome/extension/manifest.json +2 -5
- package/starters/chrome/extension/popup/controller.js +18 -16
- package/starters/chrome/extension/popup/index.html +1 -1
- package/starters/chrome/extension/popup/style.css +26 -13
- package/starters/chrome/extension/service-worker.js +7 -4
- package/starters/chrome/images/icons/question-mark/icon16.png +0 -0
- package/starters/chrome/images/icons/question-mark/icon512.png +0 -0
- package/starters/docs/LICENSE.md +21 -1
- package/starters/docs/README.md +19 -6
- package/starters/greasemonkey/LICENSE.md +3 -3
- package/starters/greasemonkey/chatgpt.js-greasemonkey-starter.user.js +5 -6
- package/starters/greasemonkey/docs/README.md +1 -1
- package/starters/greasemonkey/docs/SECURITY.md +3 -5
- /package/starters/greasemonkey/{media → assets}/images/icons/robot/icon48.png +0 -0
- /package/starters/greasemonkey/{media → assets}/images/icons/robot/icon64.png +0 -0
- /package/starters/greasemonkey/{media → assets}/images/screenshots/chatgpt-userscript-on.png +0 -0
package/docs/USERGUIDE.md
CHANGED
|
@@ -1,8 +1,8 @@
|
|
|
1
1
|
<div align="center">
|
|
2
2
|
|
|
3
3
|
<picture>
|
|
4
|
-
<source type="image/png" media="(prefers-color-scheme: dark)" srcset="https://
|
|
5
|
-
<img width=700 src="https://
|
|
4
|
+
<source type="image/png" media="(prefers-color-scheme: dark)" srcset="https://assets.chatgptjs.org/images/logos/chatgpt.js/with-reflection/darkmode.png?v=e638eac">
|
|
5
|
+
<img width=700 src="https://assets.chatgptjs.org/images/logos/chatgpt.js/with-reflection/lightmode.png?v=e638eac">
|
|
6
6
|
</picture>
|
|
7
7
|
|
|
8
8
|
**chatgpt.js** is a powerful JavaScript library that allows for super easy interaction w/ the ChatGPT DOM.
|
|
@@ -58,6 +58,7 @@
|
|
|
58
58
|
- [getResponseFromAPI `async`](#getresponsefromapi-async)
|
|
59
59
|
- [getResponseFromDOM](#getresponsefromdom)
|
|
60
60
|
- [isIdle `async`](#isidle-async)
|
|
61
|
+
- [isTyping](#istyping)
|
|
61
62
|
- [regenerate](#regenerate)
|
|
62
63
|
- [resend `async`](#resend-async)
|
|
63
64
|
- [scrollToBottom](#scrolltobottom)
|
|
@@ -159,7 +160,7 @@
|
|
|
159
160
|
|
|
160
161
|
```js
|
|
161
162
|
(async () => {
|
|
162
|
-
await import('https://cdn.jsdelivr.net/npm/@kudoai/chatgpt.js@3.
|
|
163
|
+
await import('https://cdn.jsdelivr.net/npm/@kudoai/chatgpt.js@3.6.0/dist/chatgpt.min.js');
|
|
163
164
|
// Your code here...
|
|
164
165
|
})();
|
|
165
166
|
```
|
|
@@ -168,7 +169,7 @@
|
|
|
168
169
|
|
|
169
170
|
```js
|
|
170
171
|
var xhr = new XMLHttpRequest();
|
|
171
|
-
xhr.open('GET', 'https://cdn.jsdelivr.net/npm/@kudoai/chatgpt.js@3.
|
|
172
|
+
xhr.open('GET', 'https://cdn.jsdelivr.net/npm/@kudoai/chatgpt.js@3.6.0/dist/chatgpt.min.js');
|
|
172
173
|
xhr.onload = function () {
|
|
173
174
|
if (xhr.status === 200) {
|
|
174
175
|
var chatgptJS = document.createElement('script');
|
|
@@ -190,7 +191,7 @@ function yourCode() {
|
|
|
190
191
|
|
|
191
192
|
```js
|
|
192
193
|
...
|
|
193
|
-
// @require https://cdn.jsdelivr.net/npm/@kudoai/chatgpt.js@3.
|
|
194
|
+
// @require https://cdn.jsdelivr.net/npm/@kudoai/chatgpt.js@3.6.0/dist/chatgpt.min.js
|
|
194
195
|
// ==/UserScript==
|
|
195
196
|
|
|
196
197
|
// Your code here...
|
|
@@ -929,6 +930,18 @@ Example code:
|
|
|
929
930
|
})();
|
|
930
931
|
```
|
|
931
932
|
|
|
933
|
+
### isTyping
|
|
934
|
+
|
|
935
|
+
Returns a boolean value. `true` if ChatGPT is generating a response, `false` otherwise.
|
|
936
|
+
|
|
937
|
+
Example code:
|
|
938
|
+
|
|
939
|
+
```js
|
|
940
|
+
console.log(`ChatGPT is ${!chatgpt.isTyping() ? 'not' : ''} typing`)
|
|
941
|
+
```
|
|
942
|
+
|
|
943
|
+
###### _See also: [`isIdle`](#isidle-async)_
|
|
944
|
+
|
|
932
945
|
### regenerate
|
|
933
946
|
|
|
934
947
|
Regenerates ChatGPT's response.
|
|
@@ -1023,6 +1036,7 @@ Available options:
|
|
|
1023
1036
|
- `voice`: A number representing the index of voices available on the user device.
|
|
1024
1037
|
- `pitch`: A float representing the pitch of the speech. From `0` to `2`.
|
|
1025
1038
|
- `speed`: A float representing the speed of the speech. From `0.1` to `10`.
|
|
1039
|
+
- `onend`: A callback function invoked when speech finishes playing.
|
|
1026
1040
|
|
|
1027
1041
|
Example code:
|
|
1028
1042
|
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@kudoai/chatgpt.js",
|
|
3
|
-
"version": "3.
|
|
3
|
+
"version": "3.6.0",
|
|
4
4
|
"description": "Client-side JavaScript library for ChatGPT",
|
|
5
5
|
"author": {
|
|
6
6
|
"name": "KudoAI & contributors",
|
|
@@ -67,12 +67,15 @@
|
|
|
67
67
|
"bugs": "https://github.com/KudoAI/chatgpt.js/issues",
|
|
68
68
|
"devDependencies": {
|
|
69
69
|
"@adamlui/minify.js": "^1.8.5",
|
|
70
|
-
"@adamlui/scss-to-css": "^1.10.
|
|
71
|
-
"@eslint/
|
|
72
|
-
"@eslint/
|
|
73
|
-
"@
|
|
70
|
+
"@adamlui/scss-to-css": "^1.10.24",
|
|
71
|
+
"@eslint/css": "^0.2.0",
|
|
72
|
+
"@eslint/json": "^0.10.0",
|
|
73
|
+
"@eslint/markdown": "^6.2.2",
|
|
74
|
+
"@html-eslint/eslint-plugin": "^0.33.1",
|
|
75
|
+
"@html-eslint/parser": "^0.33.0",
|
|
76
|
+
"@stylistic/eslint-plugin-js": "^3.0.1",
|
|
74
77
|
"docsify-cli": "^4.4.4",
|
|
75
|
-
"eslint": "^9.
|
|
78
|
+
"eslint": "^9.19.0",
|
|
76
79
|
"eslint-plugin-import": "^2.31.0",
|
|
77
80
|
"eslint-plugin-regexp": "^2.7.0",
|
|
78
81
|
"eslint-plugin-yml": "^1.16.0",
|
|
@@ -1,8 +1,8 @@
|
|
|
1
1
|
<div align="center">
|
|
2
2
|
<h6>
|
|
3
3
|
<picture>
|
|
4
|
-
<source type="image/svg+xml" media="(prefers-color-scheme: dark)" srcset="https://
|
|
5
|
-
|
|
4
|
+
<source type="image/svg+xml" media="(prefers-color-scheme: dark)" srcset="https://assets.chatgptjs.org/images/icons/earth/white/icon32.svg?v=e638eac">
|
|
5
|
+
<img height=14 src="https://assets.chatgptjs.org/images/icons/earth/black/icon32.svg?v=e638eac">
|
|
6
6
|
</picture>
|
|
7
7
|
English |
|
|
8
8
|
<a href="docs/zh-cn/LICENSE.md">简体中文</a> |
|
|
@@ -22,7 +22,7 @@
|
|
|
22
22
|
|
|
23
23
|
# 🏛️ MIT License
|
|
24
24
|
|
|
25
|
-
**Copyright © 2023–
|
|
25
|
+
**Copyright © 2023–2025 [KudoAI](https://github.com/KudoAI) & contributors**
|
|
26
26
|
|
|
27
27
|
Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the following conditions:
|
|
28
28
|
|
|
@@ -3,8 +3,8 @@
|
|
|
3
3
|
<div align="center">
|
|
4
4
|
<h6>
|
|
5
5
|
<picture>
|
|
6
|
-
<source type="image/svg+xml" media="(prefers-color-scheme: dark)" srcset="https://
|
|
7
|
-
|
|
6
|
+
<source type="image/svg+xml" media="(prefers-color-scheme: dark)" srcset="https://assets.chatgptjs.org/images/icons/earth/white/icon32.svg?v=e638eac">
|
|
7
|
+
<img height=14 src="https://assets.chatgptjs.org/images/icons/earth/black/icon32.svg?v=e638eac">
|
|
8
8
|
</picture>
|
|
9
9
|
English |
|
|
10
10
|
<a href="zh-cn#readme">简体中文</a> |
|
|
@@ -22,7 +22,7 @@
|
|
|
22
22
|
</h6>
|
|
23
23
|
</div>
|
|
24
24
|
|
|
25
|
-
# <img height=21 src="https://
|
|
25
|
+
# <img height=21 src="https://assets.chatgptjs.org/images/icons/platforms/chrome/icon32.png?v=e638eac"> chatgpt.js-chrome-starter
|
|
26
26
|
|
|
27
27
|
<h3>A starting point for developing your own Chrome extension using <a href="https://github.com/KudoAI/chatgpt.js">chatgpt.js</a></h3>
|
|
28
28
|
|
|
@@ -81,13 +81,13 @@ These are some of the extensions featured by Google that use chatgpt.js:
|
|
|
81
81
|
|
|
82
82
|
|
|
83
83
|
<a href="https://chatgptinfinity.com" target="_blank" rel="noopener">
|
|
84
|
-
<img width=777 src="https://
|
|
84
|
+
<img width=777 src="https://assets.chatgptinfinity.com/images/tiles/marquee/tile-1400x560.png?v=34b428b">
|
|
85
85
|
</a>
|
|
86
86
|
|
|
87
87
|
<p><br>
|
|
88
88
|
|
|
89
89
|
<a href="https://chatgptwidescreen.com" target="_blank" rel="noopener">
|
|
90
|
-
<img width=777 src="https://
|
|
90
|
+
<img width=777 src="https://assets.chatgptwidescreen.com/images/tiles/marquee/tile-1400x560.png?v=4c5d018">
|
|
91
91
|
</a>
|
|
92
92
|
|
|
93
93
|
</div>
|
|
@@ -1,8 +1,8 @@
|
|
|
1
1
|
<div align="right">
|
|
2
2
|
<h6>
|
|
3
3
|
<picture>
|
|
4
|
-
<source type="image/svg+xml" media="(prefers-color-scheme: dark)" srcset="https://
|
|
5
|
-
|
|
4
|
+
<source type="image/svg+xml" media="(prefers-color-scheme: dark)" srcset="https://assets.chatgptjs.org/images/icons/earth/white/icon32.svg?v=e638eac">
|
|
5
|
+
<img height=14 src="https://assets.chatgptjs.org/images/icons/earth/black/icon32.svg?v=e638eac">
|
|
6
6
|
</picture>
|
|
7
7
|
English |
|
|
8
8
|
<a href="https://github.com/KudoAI/chatgpt.js-chrome-starter/blob/main/docs/zh-cn/SECURITY.md">简体中文</a> |
|
|
@@ -12,6 +12,4 @@
|
|
|
12
12
|
|
|
13
13
|
# 🛡️ Security Policy
|
|
14
14
|
|
|
15
|
-
If you find a vulnerability, please
|
|
16
|
-
|
|
17
|
-
Pull requests are also welcome, but for safety reasons, send an email to <security@kudoai.com> and wait for a response before making it public.
|
|
15
|
+
If you find a vulnerability, please follow the reporting instructions @ https://tidelift.com/security
|
|
@@ -1,10 +1,9 @@
|
|
|
1
1
|
// Requires lib/dom.js
|
|
2
2
|
|
|
3
3
|
window.icons = {
|
|
4
|
-
|
|
5
|
-
|
|
6
|
-
|
|
7
|
-
for (const name in dependencies) this[name] = dependencies[name] }
|
|
4
|
+
imports: {
|
|
5
|
+
import(deps) { // { app }
|
|
6
|
+
for (const depName in deps) this[depName] = deps[depName] }
|
|
8
7
|
},
|
|
9
8
|
|
|
10
9
|
create({ name, size = 16, width, height, ...additionalAttrs }) {
|
|
@@ -27,6 +26,6 @@ window.icons = {
|
|
|
27
26
|
|
|
28
27
|
questionMark: {
|
|
29
28
|
type: 'png',
|
|
30
|
-
get src() { return `${icons.
|
|
29
|
+
get src() { return `${icons.imports.app.urls.assetHost}@b5551ac/images/icons/question-mark/icon16.png` }
|
|
31
30
|
}
|
|
32
31
|
};
|
|
@@ -2,27 +2,89 @@
|
|
|
2
2
|
|
|
3
3
|
window.modals = {
|
|
4
4
|
stack: [], // of types of undismissed modals
|
|
5
|
+
get class() { return `${this.imports.app.cssPrefix}-modal` },
|
|
5
6
|
|
|
6
|
-
|
|
7
|
-
import(
|
|
8
|
-
for (const
|
|
7
|
+
imports: {
|
|
8
|
+
import(deps) { // { app, env }
|
|
9
|
+
for (const depName in deps) this[depName] = deps[depName] }
|
|
10
|
+
},
|
|
11
|
+
|
|
12
|
+
alert(title = '', msg = '', btns = '', checkbox = '', width = '') { // generic one from chatgpt.alert()
|
|
13
|
+
const alertID = chatgpt.alert(title, msg, btns, checkbox, width),
|
|
14
|
+
alert = document.getElementById(alertID).firstChild
|
|
15
|
+
this.init(alert) // add classes + rising particles bg
|
|
16
|
+
return alert
|
|
9
17
|
},
|
|
10
18
|
|
|
11
19
|
open(modalType) {
|
|
12
|
-
this.stack.unshift(modalType) // add to stack
|
|
13
20
|
const modal = this[modalType]() // show modal
|
|
14
|
-
|
|
15
|
-
modal
|
|
16
|
-
dom.fillStarryBG(modal) // fill BG w/ rising stars
|
|
21
|
+
this.stack.unshift(modalType) // add to stack
|
|
22
|
+
this.init(modal) // add classes + rising particles bg
|
|
17
23
|
this.observeRemoval(modal, modalType) // to maintain stack for proper nav
|
|
18
24
|
},
|
|
19
25
|
|
|
26
|
+
init(modal) {
|
|
27
|
+
if (!modal) return // to support non-div this.open()s
|
|
28
|
+
if (!this.styles) this.stylize() // to init/append stylesheet
|
|
29
|
+
modal.classList.add('no-user-select', this.class) ; modal.parentNode.classList.add(`${this.class}-bg`)
|
|
30
|
+
dom.addRisingParticles(modal)
|
|
31
|
+
},
|
|
32
|
+
|
|
33
|
+
stylize() {
|
|
34
|
+
if (!this.styles) {
|
|
35
|
+
this.styles = dom.create.elem('style') ; this.styles.id = `${this.class}-styles`
|
|
36
|
+
document.head.append(this.styles)
|
|
37
|
+
}
|
|
38
|
+
this.styles.innerText = (
|
|
39
|
+
`.no-user-select {
|
|
40
|
+
user-select: none ; -webkit-user-select: none ; -moz-user-select: none ; -ms-user-select: none }`
|
|
41
|
+
+ `.${this.class} {` // modals
|
|
42
|
+
+ 'font-family: -apple-system, system-ui, BlinkMacSystemFont, Segoe UI, Roboto,'
|
|
43
|
+
+ 'Oxygen-Sans, Ubuntu, Cantarell, Helvetica Neue, sans-serif ;'
|
|
44
|
+
+ 'padding: 20px 25px 24px 25px !important ; font-size: 20px ;'
|
|
45
|
+
+ `color: ${ this.imports.env.ui.scheme == 'dark' ? 'white' : 'black' } !important ;`
|
|
46
|
+
+ `background-image: linear-gradient(180deg, ${
|
|
47
|
+
this.imports.env.ui.scheme == 'dark' ? '#99a8a6 -200px, black 200px'
|
|
48
|
+
: '#b6ebff -296px, white 171px' }) }`
|
|
49
|
+
+ `.${this.class} [class*=modal-close-btn] {`
|
|
50
|
+
+ 'position: absolute !important ; float: right ; top: 14px !important ; right: 16px !important ;'
|
|
51
|
+
+ 'cursor: pointer ; width: 33px ; height: 33px ; border-radius: 20px }'
|
|
52
|
+
+ `.${this.class} [class*=modal-close-btn] svg { height: 10px }`
|
|
53
|
+
+ `.${this.class} [class*=modal-close-btn] path {`
|
|
54
|
+
+ `${ this.imports.env.ui.scheme == 'dark' ? 'stroke: white ; fill: white'
|
|
55
|
+
: 'stroke: #9f9f9f ; fill: #9f9f9f' }}`
|
|
56
|
+
+ ( this.imports.env.ui.scheme == 'dark' ? // invert dark mode hover paths
|
|
57
|
+
`.${this.class} [class*=modal-close-btn]:hover path { stroke: black ; fill: black }` : '' )
|
|
58
|
+
+ `.${this.class} [class*=modal-close-btn]:hover { background-color: #f2f2f2 }` // hover underlay
|
|
59
|
+
+ `.${this.class} [class*=modal-close-btn] svg { margin: 11.5px }` // center SVG for hover underlay
|
|
60
|
+
+ `.${this.class} a {`
|
|
61
|
+
+ `color: #${ this.imports.env.ui.scheme == 'dark' ? '00cfff' : '1e9ebb' } !important }`
|
|
62
|
+
+ `.${this.class} h2 { font-weight: bold }`
|
|
63
|
+
+ `.${this.class} button {`
|
|
64
|
+
+ '--btn-transition: transform 0.1s ease-in-out, box-shadow 0.1s ease-in-out ;'
|
|
65
|
+
+ 'font-size: 14px ; text-transform: uppercase ;' // shrink/uppercase labels
|
|
66
|
+
+ 'border-radius: 0 !important ;' // square borders
|
|
67
|
+
+ 'transition: var(--btn-transition) ;' // smoothen hover fx
|
|
68
|
+
+ '-webkit-transition: var(--btn-transition) ; -moz-transition: var(--btn-transition) ;'
|
|
69
|
+
+ '-o-transition: var(--btn-transition) ; -ms-transition: var(--btn-transition) ;'
|
|
70
|
+
+ 'cursor: pointer !important ;' // add finger cursor
|
|
71
|
+
+ `border: 1px solid ${ this.imports.env.ui.scheme == 'dark' ? 'white' : 'black' } !important ;`
|
|
72
|
+
+ 'padding: 8px !important ; min-width: 102px }' // resize
|
|
73
|
+
+ `.${this.class} button:hover {` // add zoom, re-scheme
|
|
74
|
+
+ 'transform: scale(1.055) ; color: black !important ;'
|
|
75
|
+
+ `background-color: #${ this.imports.env.ui.scheme == 'dark' ? '00cfff' : '9cdaff' } !important }`
|
|
76
|
+
+ ( !this.imports.env.browser.isMobile ?
|
|
77
|
+
`.${this.class} .modal-buttons { margin-left: -13px !important }` : '' )
|
|
78
|
+
+ `.about-em { color: ${ this.imports.env.ui.scheme == 'dark' ? 'white' : 'green' } !important }`
|
|
79
|
+
)
|
|
80
|
+
},
|
|
81
|
+
|
|
20
82
|
observeRemoval(modal, modalType) { // to maintain stack for proper nav
|
|
21
83
|
const modalBG = modal.parentNode
|
|
22
84
|
new MutationObserver(([mutation], obs) => {
|
|
23
85
|
mutation.removedNodes.forEach(removedNode => { if (removedNode == modalBG) {
|
|
24
86
|
if (this.stack[0] == modalType) { // new modal not launched, implement nav back logic
|
|
25
|
-
this.stack.shift() // remove this modal type from stack
|
|
87
|
+
this.stack.shift() // remove this modal type from stack 1st
|
|
26
88
|
const prevModalType = this.stack[0]
|
|
27
89
|
if (prevModalType) { // open it
|
|
28
90
|
this.stack.shift() // remove type from stack since re-added on open
|
|
@@ -34,73 +96,44 @@ window.modals = {
|
|
|
34
96
|
}).observe(modalBG.parentNode, { childList: true, subtree: true })
|
|
35
97
|
},
|
|
36
98
|
|
|
37
|
-
dragHandlers: {
|
|
38
|
-
mousedown(event) { // find modal, attach listeners, init XY offsets
|
|
39
|
-
if (event.button != 0) return // prevent non-left-click drag
|
|
40
|
-
if (getComputedStyle(event.target).cursor == 'pointer') return // prevent drag on interactive elems
|
|
41
|
-
modals.dragHandlers.draggableElem = event.currentTarget
|
|
42
|
-
modals.dragHandlers.draggableElem.style.cursor = 'grabbing'
|
|
43
|
-
event.preventDefault(); // prevent sub-elems like icons being draggable
|
|
44
|
-
['mousemove', 'mouseup'].forEach(event => document.addEventListener(event, modals.dragHandlers[event]))
|
|
45
|
-
const draggableElemRect = modals.dragHandlers.draggableElem.getBoundingClientRect()
|
|
46
|
-
modals.dragHandlers.offsetX = event.clientX - draggableElemRect.left +21
|
|
47
|
-
modals.dragHandlers.offsetY = event.clientY - draggableElemRect.top +12
|
|
48
|
-
},
|
|
49
|
-
|
|
50
|
-
mousemove(event) { // drag modal
|
|
51
|
-
if (modals.dragHandlers.draggableElem) {
|
|
52
|
-
const newX = event.clientX - modals.dragHandlers.offsetX,
|
|
53
|
-
newY = event.clientY - modals.dragHandlers.offsetY
|
|
54
|
-
Object.assign(modals.dragHandlers.draggableElem.style, { left: `${newX}px`, top: `${newY}px` })
|
|
55
|
-
}
|
|
56
|
-
},
|
|
57
|
-
|
|
58
|
-
mouseup() { // remove listeners, reset modals.dragHandlers.draggableElem
|
|
59
|
-
modals.dragHandlers.draggableElem.style.cursor = 'inherit';
|
|
60
|
-
['mousemove', 'mouseup'].forEach(event =>
|
|
61
|
-
document.removeEventListener(event, modals.dragHandlers[event]))
|
|
62
|
-
modals.dragHandlers.draggableElem = null
|
|
63
|
-
}
|
|
64
|
-
},
|
|
65
|
-
|
|
66
99
|
about() {
|
|
67
100
|
|
|
68
|
-
// Init styles
|
|
69
|
-
const headingStyle = 'font-size: 1.15rem',
|
|
70
|
-
pStyle = 'position: relative ; left: 3px',
|
|
71
|
-
pBrStyle = 'position: relative ; left: 4px ',
|
|
72
|
-
aStyle = 'color: ' + ( chatgpt.isDarkMode() ? '#c67afb' : '#8325c4' ) // purple
|
|
73
|
-
|
|
74
|
-
// Init buttons
|
|
75
|
-
const modalBtns = [
|
|
76
|
-
function getSupport(){ modals.safeWinOpen(`${modals.dependencies.app.urls.gitHub}/issues`) },
|
|
77
|
-
function rateUs() { modals.safeWinOpen(`${modals.dependencies.app.urls.gitHub}/discussions`) },
|
|
78
|
-
function moreAiExtensions(){ modals.safeWinOpen(modals.dependencies.app.urls.relatedExtensions) }
|
|
79
|
-
]
|
|
80
|
-
|
|
81
101
|
// Show modal
|
|
82
|
-
const aboutModal = this.
|
|
83
|
-
`${this.
|
|
84
|
-
|
|
85
|
-
+ `<
|
|
86
|
-
|
|
87
|
-
|
|
88
|
-
|
|
89
|
-
|
|
90
|
-
|
|
91
|
-
|
|
92
|
-
|
|
93
|
-
|
|
102
|
+
const aboutModal = this.alert(
|
|
103
|
+
`${this.imports.app.symbol} ${chrome.runtime.getManifest().name}`, // title
|
|
104
|
+
'🧠 Author: ' // msg
|
|
105
|
+
+ `<a href="${this.imports.app.author.url}">${this.imports.app.author.name}</a> `
|
|
106
|
+
+ `& <a href="${this.imports.app.urls.contributors}">contributors</a>\n`
|
|
107
|
+
+ `🏷️ Version: <span class="about-em">${this.imports.app.version}</span>\n`
|
|
108
|
+
+ '📜 Open source code: '
|
|
109
|
+
+ `<a href="${this.imports.app.urls.gitHub}" target="_blank" rel="nopener">`
|
|
110
|
+
+ this.imports.app.urls.gitHub + '</a>\n'
|
|
111
|
+
+ '⚡ Powered by: '
|
|
112
|
+
+ `<a href="${this.imports.app.urls.chatgptJS}" target="_blank" rel="noopener">chatgpt.js</a>`,
|
|
113
|
+
[ function getSupport(){}, function rateUs(){}, function moreAiExtensions(){} ], // button labels
|
|
114
|
+
'', 656 // modal width
|
|
94
115
|
)
|
|
95
116
|
|
|
96
117
|
// Format text
|
|
97
|
-
aboutModal.querySelector('h2').style.cssText =
|
|
98
|
-
|
|
118
|
+
aboutModal.querySelector('h2').style.cssText = (
|
|
119
|
+
'text-align: center ; font-size: 51px ; line-height: 46px ; padding: 15px 0' )
|
|
120
|
+
aboutModal.querySelector('p').style.cssText = (
|
|
121
|
+
'text-align: center ; overflow-wrap: anywhere ;'
|
|
122
|
+
+ `margin: ${ this.imports.env.browser.isPortrait ? '6px 0 -16px' : '3px 0 0' }` )
|
|
99
123
|
|
|
100
124
|
// Hack buttons
|
|
101
125
|
aboutModal.querySelector('.modal-buttons').style.justifyContent = 'center'
|
|
102
126
|
aboutModal.querySelectorAll('button').forEach(btn => {
|
|
103
|
-
btn.style.cssText = '
|
|
127
|
+
btn.style.cssText = 'height: 55px ; min-width: 136px ; text-align: center'
|
|
128
|
+
|
|
129
|
+
// Replace buttons w/ clones that don't dismiss modal
|
|
130
|
+
const btnClone = btn.cloneNode(true)
|
|
131
|
+
btn.parentNode.replaceChild(btnClone, btn) ; btn = btnClone
|
|
132
|
+
btn.onclick = () => this.safeWinOpen(
|
|
133
|
+
btn.textContent == 'Get Support' ? `${modals.imports.app.urls.gitHub}/issues`
|
|
134
|
+
: btn.textContent == 'Rate Us' ? `${modals.imports.app.urls.gitHub}/discussions`
|
|
135
|
+
: modals.imports.app.urls.relatedExtensions
|
|
136
|
+
)
|
|
104
137
|
|
|
105
138
|
// Prepend emoji
|
|
106
139
|
if (/support/i.test(btn.textContent))
|
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
// NOTE: This script relies on the powerful chatgpt.js library @ https://chatgpt.js.org
|
|
2
|
-
// © 2023–
|
|
2
|
+
// © 2023–2025 KudoAI & contributors under the MIT license
|
|
3
3
|
|
|
4
4
|
(async () => {
|
|
5
5
|
|
|
@@ -8,18 +8,22 @@
|
|
|
8
8
|
await import(chrome.runtime.getURL(resource))
|
|
9
9
|
|
|
10
10
|
// Init ENV context
|
|
11
|
-
const env = { browser: { isMobile: chatgpt.browser.isMobile() }}
|
|
11
|
+
const env = { browser: { isMobile: chatgpt.browser.isMobile() }, ui: { scheme: getScheme() }}
|
|
12
|
+
env.browser.isPortrait = env.browser.isMobile && (window.innerWidth < window.innerHeight)
|
|
12
13
|
|
|
13
14
|
// Import APP data
|
|
14
15
|
const { app } = await chrome.storage.sync.get('app')
|
|
15
|
-
|
|
16
|
+
|
|
17
|
+
// Export DEPENDENCIES to imported resources
|
|
18
|
+
dom.imports.import({ env }) // for env.ui.scheme
|
|
19
|
+
modals.imports.import({ app, env }) // for app data + env.ui.scheme
|
|
16
20
|
|
|
17
21
|
// Add CHROME MSG listener
|
|
18
22
|
chrome.runtime.onMessage.addListener(req => { // from service-worker.js + popup/index.html
|
|
19
23
|
if (req.action == 'notify')
|
|
20
24
|
notify(...['msg', 'pos', 'notifDuration', 'shadow'].map(arg => req.options[arg]))
|
|
21
25
|
else if (req.action == 'alert')
|
|
22
|
-
|
|
26
|
+
modals.alert(...['title', 'msg', 'btns', 'checkbox', 'width'].map(arg => req.options[arg]))
|
|
23
27
|
else if (req.action == 'showAbout') chatgpt.isLoaded().then(() => { modals.open('about') })
|
|
24
28
|
else if (req.action == 'syncConfigToUI') syncConfigToUI(req.options)
|
|
25
29
|
})
|
|
@@ -27,7 +31,7 @@
|
|
|
27
31
|
// Init SETTINGS
|
|
28
32
|
await settings.load(Object.keys(settings.controls), 'skipAlert')
|
|
29
33
|
|
|
30
|
-
// Define
|
|
34
|
+
// Define FUNCTIONS
|
|
31
35
|
|
|
32
36
|
function notify(msg, pos = '', notifDuration = '', shadow = '') {
|
|
33
37
|
|
|
@@ -36,27 +40,27 @@
|
|
|
36
40
|
if (foundState) msg = msg.replace(foundState, '')
|
|
37
41
|
|
|
38
42
|
// Show notification
|
|
39
|
-
|
|
40
|
-
shadow || chatgpt.isDarkMode() ? '' : 'shadow' )
|
|
43
|
+
chatgpt.notify(`${app.symbol} ${msg}`, pos, notifDuration, shadow || env.ui.scheme == 'dark' ? '' : 'shadow')
|
|
41
44
|
const notif = document.querySelector('.chatgpt-notif:last-child')
|
|
42
45
|
|
|
43
46
|
// Append styled state word
|
|
44
47
|
if (foundState) {
|
|
48
|
+
const stateStyles = {
|
|
49
|
+
on: {
|
|
50
|
+
light: 'color: #5cef48 ; text-shadow: rgba(255,250,169,0.38) 2px 1px 5px',
|
|
51
|
+
dark: 'color: #5cef48 ; text-shadow: rgb(55, 255, 0) 3px 0 10px'
|
|
52
|
+
},
|
|
53
|
+
off: {
|
|
54
|
+
light: 'color: #ef4848 ; text-shadow: rgba(255,169,225,0.44) 2px 1px 5px',
|
|
55
|
+
dark: 'color: #ef4848 ; text-shadow: rgba(255, 116, 116, 0.87) 3px 0 9px'
|
|
56
|
+
}
|
|
57
|
+
}
|
|
45
58
|
const styledStateSpan = document.createElement('span')
|
|
46
|
-
styledStateSpan.style.cssText =
|
|
47
|
-
foundState == 'OFF' ? '#ef4848 ; text-shadow: rgba(255, 169, 225, 0.44) 2px 1px 5px'
|
|
48
|
-
: '#5cef48 ; text-shadow: rgba(255, 250, 169, 0.38) 2px 1px 5px' }`
|
|
59
|
+
styledStateSpan.style.cssText = stateStyles[foundState.toLowerCase()][env.ui.scheme]
|
|
49
60
|
styledStateSpan.append(foundState) ; notif.append(styledStateSpan)
|
|
50
61
|
}
|
|
51
62
|
}
|
|
52
63
|
|
|
53
|
-
function siteAlert(title = '', msg = '', btns = '', checkbox = '', width = '') {
|
|
54
|
-
const alertID = chatgpt.alert(title, msg, btns, checkbox, width)
|
|
55
|
-
return document.getElementById(alertID).firstChild
|
|
56
|
-
}
|
|
57
|
-
|
|
58
|
-
// Define SYNC function
|
|
59
|
-
|
|
60
64
|
async function syncConfigToUI(options) { // eslint-disable-line
|
|
61
65
|
await settings.load('extensionDisabled', Object.keys(settings.controls)) // load from Chrome storage to content.js config
|
|
62
66
|
if (config.extensionDisabled) {
|
|
@@ -70,49 +74,29 @@
|
|
|
70
74
|
}
|
|
71
75
|
}
|
|
72
76
|
|
|
77
|
+
function getScheme() {
|
|
78
|
+
return document.documentElement.className
|
|
79
|
+
|| (window.matchMedia?.('(prefers-color-scheme: dark)')?.matches ? 'dark' : 'light')
|
|
80
|
+
}
|
|
81
|
+
|
|
73
82
|
// Run MAIN routine
|
|
74
83
|
|
|
75
84
|
chatgpt.printAllFunctions() // to console
|
|
76
85
|
|
|
77
86
|
// CHILL a bit if your hacks depend on delayed DOM content
|
|
78
87
|
await chatgpt.isLoaded()
|
|
79
|
-
await new Promise(resolve => setTimeout(resolve, 500)) // sleep .5s
|
|
80
|
-
|
|
81
|
-
// Add/update TWEAKS style
|
|
82
|
-
const tweaksStyleUpdated = 1732627011377 // timestamp of last edit for this file's tweaksStyle
|
|
83
|
-
let tweaksStyle = document.getElementById('tweaks-style') // try to select existing style (from your other extensions)
|
|
84
|
-
if (!tweaksStyle || parseInt(tweaksStyle.getAttribute('last-updated')) < tweaksStyleUpdated) {
|
|
85
|
-
if (!tweaksStyle) { // outright missing, create/id/attr/append it first
|
|
86
|
-
tweaksStyle = dom.create.elem('style', {
|
|
87
|
-
id: 'tweaks-style', 'last-updated': tweaksStyleUpdated.toString() })
|
|
88
|
-
document.head.append(tweaksStyle)
|
|
89
|
-
}
|
|
90
|
-
tweaksStyle.innerText = (
|
|
91
|
-
'[class$="-modal"] { z-index: 13456 ; position: absolute }' // to be click-draggable
|
|
92
|
-
+ ( chatgpt.isDarkMode() ? '.chatgpt-modal > div { border: 1px solid white }' : '' )
|
|
93
|
-
+ '.chatgpt-modal button {'
|
|
94
|
-
+ 'font-size: 0.77rem ; text-transform: uppercase ;' // shrink/uppercase labels
|
|
95
|
-
+ 'border-radius: 0 !important ;' // square borders
|
|
96
|
-
+ 'transition: transform 0.1s ease-in-out, box-shadow 0.1s ease-in-out ;' // smoothen hover fx
|
|
97
|
-
+ 'cursor: pointer !important ;' // add finger cursor
|
|
98
|
-
+ 'padding: 5px !important ; min-width: 102px }' // resize
|
|
99
|
-
+ '.chatgpt-modal button:hover {' // add zoom, re-scheme
|
|
100
|
-
+ 'transform: scale(1.055) ; color: black !important ;'
|
|
101
|
-
+ `background-color: #${ chatgpt.isDarkMode() ? '00cfff' : '9cdaff' } !important }`
|
|
102
|
-
+ ( !env.browser.isMobile ? '.modal-buttons { margin-left: -13px !important }' : '' )
|
|
103
|
-
)
|
|
104
|
-
}; // eslint-disable-line
|
|
88
|
+
await new Promise(resolve => setTimeout(resolve, 500)); // sleep .5s
|
|
105
89
|
|
|
106
|
-
// Add
|
|
107
|
-
['
|
|
90
|
+
// Add RISING PARTICLES styles for modals
|
|
91
|
+
['gray', 'white'].forEach(color => document.head.append(
|
|
108
92
|
dom.create.elem('link', { rel: 'stylesheet',
|
|
109
|
-
href: `https://assets.aiwebextensions.com/styles/
|
|
93
|
+
href: `https://assets.aiwebextensions.com/styles/rising-particles/dist/${color}.min.css?v=727feff`
|
|
110
94
|
})))
|
|
111
95
|
|
|
112
96
|
if (config.extensionDisabled) return
|
|
113
97
|
|
|
114
98
|
if (!config.skipAlert) // alert to extension load
|
|
115
|
-
|
|
99
|
+
modals.alert('≫ ChatGPT extension loaded! 🚀', // title
|
|
116
100
|
'Success! Press Ctrl+Shift+J to view all chatgpt.js methods.', // msg
|
|
117
101
|
function getHelp() { // button
|
|
118
102
|
chrome.tabs.create({ url: `${app.urls.gitHub}/issues` }) },
|
|
@@ -120,6 +104,16 @@
|
|
|
120
104
|
settings.save('skipAlert', !config.skipAlert) }
|
|
121
105
|
)
|
|
122
106
|
|
|
107
|
+
// Monitor SCHEME PREF CHANGES to update modal colors + env.ui.scheme for your use
|
|
108
|
+
new MutationObserver(handleSchemePrefChange).observe( // for site scheme pref changes
|
|
109
|
+
document.documentElement, { attributes: true, attributeFilter: ['class'] })
|
|
110
|
+
window.matchMedia('(prefers-color-scheme: dark)').addEventListener( // for browser/system scheme pref changes
|
|
111
|
+
'change', () => requestAnimationFrame(handleSchemePrefChange))
|
|
112
|
+
function handleSchemePrefChange() {
|
|
113
|
+
const displayedScheme = getScheme()
|
|
114
|
+
if (env.ui.scheme != displayedScheme) { env.ui.scheme = displayedScheme ; modals.stylize() }
|
|
115
|
+
}
|
|
116
|
+
|
|
123
117
|
// Your code here...
|
|
124
118
|
// Your code here...
|
|
125
119
|
// Your code here...
|
|
Binary file
|
|
Binary file
|
|
Binary file
|
|
Binary file
|