electron-findbar 0.3.1 → 0.5.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/.vscode/launch.json +1 -1
- package/README.md +23 -4
- package/index.js +93 -105
- package/package.json +3 -3
- package/test/sample.html +35 -0
- package/test/sample.js +44 -0
- package/web/app.css +16 -10
- package/web/app.js +15 -13
- package/web/findbar.html +1 -1
- package/sample.js +0 -23
- /package/{test.js → test/test.js} +0 -0
package/.vscode/launch.json
CHANGED
package/README.md
CHANGED
|
@@ -72,12 +72,13 @@ You can customize the Findbar window options using the `setWindowOptions` method
|
|
|
72
72
|
findbar.setWindowOptions({ movable: true, resizable: true, alwaysOnTop: true });
|
|
73
73
|
```
|
|
74
74
|
|
|
75
|
-
|
|
75
|
+
The findbar has a default position handler which moves the findbar to the top-right corner. To change the position handler, use the `setPositionHandler`. The position handler is called when the parent window moves or resizes and provides both the parent and findbar bounds as parameters.
|
|
76
76
|
|
|
77
77
|
```js
|
|
78
|
-
findbar.
|
|
79
|
-
|
|
80
|
-
|
|
78
|
+
findbar.setPositionHandler((parentBounds, findbarBounds) => ({
|
|
79
|
+
x: parentBounds.x + parentBounds.width - findbarBounds.width - 20,
|
|
80
|
+
y: parentBounds.y - ((findbarBounds.height / 4) | 0)
|
|
81
|
+
}));
|
|
81
82
|
```
|
|
82
83
|
|
|
83
84
|
### Opening the Findbar
|
|
@@ -166,6 +167,24 @@ app.whenReady().then(() => {
|
|
|
166
167
|
});
|
|
167
168
|
```
|
|
168
169
|
|
|
170
|
+
## IPC Events
|
|
171
|
+
|
|
172
|
+
As an alternative, the findbar can be controlled using IPC events in the `renderer` process of the `WebContents` provided during the findbar construction. Example:
|
|
173
|
+
|
|
174
|
+
```js
|
|
175
|
+
const $remote = (ipc => ({
|
|
176
|
+
getLastText: async () => ipc.invoke('electron-findbar/last-text'),
|
|
177
|
+
inputChange: (value) => { ipc.send('electron-findbar/input-change', value) },
|
|
178
|
+
previous: () => { ipc.send('electron-findbar/previous') },
|
|
179
|
+
next: () => { ipc.send('electron-findbar/next') },
|
|
180
|
+
open: () => { ipc.send('electron-findbar/open') },
|
|
181
|
+
close: () => { ipc.send('electron-findbar/close') },
|
|
182
|
+
})) (require('electron').ipcRenderer)
|
|
183
|
+
|
|
184
|
+
$remote.open()
|
|
185
|
+
$remote.inputChange('findIt')
|
|
186
|
+
```
|
|
187
|
+
|
|
169
188
|
## Notes
|
|
170
189
|
|
|
171
190
|
There are some intentional differences from the Chrome findbar, such as the horizontal margins of the divider and the input text, which has been replaced by a search input to include a clear button (the "x" on the right side).
|
package/index.js
CHANGED
|
@@ -1,5 +1,4 @@
|
|
|
1
1
|
const { BaseWindow, BrowserWindow, WebContents, BrowserWindowConstructorOptions, Rectangle } = require('electron')
|
|
2
|
-
const path = require('node:path')
|
|
3
2
|
|
|
4
3
|
class Findbar {
|
|
5
4
|
/** @type {BaseWindow} */
|
|
@@ -9,7 +8,7 @@ class Findbar {
|
|
|
9
8
|
#window
|
|
10
9
|
|
|
11
10
|
/** @type {WebContents} */
|
|
12
|
-
#
|
|
11
|
+
#findableContents
|
|
13
12
|
|
|
14
13
|
/** */
|
|
15
14
|
#matches
|
|
@@ -17,14 +16,14 @@ class Findbar {
|
|
|
17
16
|
/** @type {(findbarWindow: BrowserWindow) => void} */
|
|
18
17
|
#windowHandler
|
|
19
18
|
|
|
19
|
+
/** @type {{parentBounds: Rectangle, findbarBounds: Rectangle} => {x: number, y: number}} */
|
|
20
|
+
#positionHandler = Findbar.#setDefaultPosition
|
|
21
|
+
|
|
20
22
|
/** @type {BrowserWindowConstructorOptions} */
|
|
21
23
|
#customOptions
|
|
22
24
|
|
|
23
25
|
/** @type {string} */
|
|
24
|
-
#
|
|
25
|
-
|
|
26
|
-
/** @type {boolean} */
|
|
27
|
-
#followParent = process.platform !== 'darwin'
|
|
26
|
+
#lastText = ''
|
|
28
27
|
|
|
29
28
|
/**
|
|
30
29
|
* Workaround to fix "findInPage" bug - double-click to loop
|
|
@@ -40,30 +39,33 @@ class Findbar {
|
|
|
40
39
|
*/
|
|
41
40
|
constructor (parent, webContents) {
|
|
42
41
|
this.#parent = parent
|
|
43
|
-
this.#
|
|
42
|
+
this.#findableContents = webContents ?? parent.webContents
|
|
44
43
|
|
|
45
|
-
if (!this.#
|
|
44
|
+
if (!this.#findableContents) {
|
|
46
45
|
throw new Error('There are no searchable web contents.')
|
|
47
46
|
}
|
|
48
47
|
}
|
|
49
48
|
|
|
50
49
|
/**
|
|
51
|
-
* Open the findbar.
|
|
50
|
+
* Open the findbar. If the findbar is already opened, focus the input text.
|
|
52
51
|
*/
|
|
53
52
|
open() {
|
|
54
53
|
if (this.#window) {
|
|
55
|
-
this.#
|
|
54
|
+
this.#focusWindowAndHighlightInput()
|
|
56
55
|
return
|
|
57
56
|
}
|
|
58
57
|
this.#window = new BrowserWindow(Findbar.#mergeStandardOptions(this.#customOptions, this.#parent))
|
|
59
|
-
this.#window.webContents.
|
|
58
|
+
this.#window.webContents._findbar = this
|
|
59
|
+
this.#findableContents._findbar = this
|
|
60
60
|
|
|
61
61
|
this.#registerListeners()
|
|
62
|
-
|
|
62
|
+
|
|
63
|
+
const pos = this.#positionHandler(this.#parent.getBounds(), this.#window.getBounds())
|
|
64
|
+
this.#window.setPosition(pos.x, pos.y)
|
|
63
65
|
|
|
64
66
|
this.#windowHandler && this.#windowHandler(this.#window)
|
|
65
67
|
|
|
66
|
-
this.#window.loadFile(
|
|
68
|
+
this.#window.loadFile(`${__dirname}/web/findbar.html`)
|
|
67
69
|
}
|
|
68
70
|
|
|
69
71
|
/**
|
|
@@ -74,19 +76,21 @@ class Findbar {
|
|
|
74
76
|
}
|
|
75
77
|
|
|
76
78
|
/**
|
|
77
|
-
* Get last queried
|
|
79
|
+
* Get last queried text.
|
|
78
80
|
*/
|
|
79
|
-
|
|
80
|
-
return this.#
|
|
81
|
+
getLastText() {
|
|
82
|
+
return this.#lastText
|
|
81
83
|
}
|
|
82
84
|
|
|
83
85
|
/**
|
|
84
86
|
* Starts a request to find all matches for the text in the page.
|
|
85
87
|
* @param {string} text Value to find in page.
|
|
88
|
+
* @param {boolean | void} skipInputUpdate Skip findbar input update.
|
|
86
89
|
*/
|
|
87
|
-
startFind(text) {
|
|
88
|
-
|
|
89
|
-
|
|
90
|
+
startFind(text, skipInputUpdate) {
|
|
91
|
+
skipInputUpdate || this.#window?.webContents.send('electron-findbar/text-change', text)
|
|
92
|
+
if (this.#lastText = text) {
|
|
93
|
+
this.#findableContents.findInPage(this.#lastText, { findNext: true })
|
|
90
94
|
} else {
|
|
91
95
|
this.stopFind()
|
|
92
96
|
}
|
|
@@ -96,22 +100,16 @@ class Findbar {
|
|
|
96
100
|
* Select previous match if any.
|
|
97
101
|
*/
|
|
98
102
|
findPrevious() {
|
|
99
|
-
|
|
100
|
-
|
|
101
|
-
}
|
|
102
|
-
|
|
103
|
-
this.#searchableContents.findInPage(this.#lastValue, { forward: false })
|
|
103
|
+
this.#matches.active === 1 && (this.#fixMove = false)
|
|
104
|
+
this.#findableContents.findInPage(this.#lastText, { forward: false })
|
|
104
105
|
}
|
|
105
106
|
|
|
106
107
|
/**
|
|
107
108
|
* Select next match if any.
|
|
108
109
|
*/
|
|
109
110
|
findNext() {
|
|
110
|
-
|
|
111
|
-
|
|
112
|
-
}
|
|
113
|
-
|
|
114
|
-
this.#searchableContents.findInPage(this.#lastValue, { forward: true })
|
|
111
|
+
this.#matches.active === this.#matches.total && (this.#fixMove = true)
|
|
112
|
+
this.#findableContents.findInPage(this.#lastText, { forward: true })
|
|
115
113
|
}
|
|
116
114
|
|
|
117
115
|
/**
|
|
@@ -119,7 +117,7 @@ class Findbar {
|
|
|
119
117
|
*/
|
|
120
118
|
stopFind() {
|
|
121
119
|
this.isOpen() && this.#sendMatchesCount(0, 0)
|
|
122
|
-
this.#
|
|
120
|
+
this.#findableContents.isDestroyed() || this.#findableContents.stopFindInPage("clearSelection")
|
|
123
121
|
}
|
|
124
122
|
|
|
125
123
|
/**
|
|
@@ -158,86 +156,40 @@ class Findbar {
|
|
|
158
156
|
}
|
|
159
157
|
|
|
160
158
|
/**
|
|
161
|
-
* Set
|
|
162
|
-
*
|
|
163
|
-
* On darwin platform, the findbar follows the parent window by default. This method is set
|
|
164
|
-
* to false to not create a "move" event listener unnescessarily.
|
|
165
|
-
* @platform win32,linux
|
|
166
|
-
* @param {boolean} follow If true, the findbar will follow the parent window movement.
|
|
159
|
+
* Set a bounds handler to calculate the findbar bounds when the parent resizes.
|
|
160
|
+
* @param {{parentBounds: Rectangle, findbarBounds: Rectangle} => Rectangle} boundsHandler Bounds handler.
|
|
167
161
|
*/
|
|
168
|
-
|
|
169
|
-
this.#
|
|
170
|
-
}
|
|
171
|
-
|
|
172
|
-
/**
|
|
173
|
-
* Merge custom, defaults, and fixed options.
|
|
174
|
-
* @param {Electron.BrowserWindowConstructorOptions} options Custom options.
|
|
175
|
-
* @param {BaseWindow | void} parent Parent window, if any.
|
|
176
|
-
* @returns {Electron.BrowserWindowConstructorOptions} Merged options.
|
|
177
|
-
*/
|
|
178
|
-
static #mergeStandardOptions(options, parent) {
|
|
179
|
-
if (!options) { options = {} }
|
|
180
|
-
options.width = options.width ?? 372
|
|
181
|
-
options.height = options.height ?? 52
|
|
182
|
-
options.resizable = options.resizable ?? false
|
|
183
|
-
options.movable = options.movable ?? false
|
|
184
|
-
options.parent = parent
|
|
185
|
-
options.frame = false
|
|
186
|
-
options.transparent = true
|
|
187
|
-
options.maximizable = false
|
|
188
|
-
options.minimizable = false
|
|
189
|
-
options.skipTaskbar = true
|
|
190
|
-
options.fullscreenable = false
|
|
191
|
-
if (!options.webPreferences) { options.webPreferences = {} }
|
|
192
|
-
options.webPreferences.nodeIntegration = true
|
|
193
|
-
options.webPreferences.contextIsolation = false
|
|
194
|
-
return options
|
|
162
|
+
setBoundsHandler(boundsHandler) {
|
|
163
|
+
this.#positionHandler = boundsHandler
|
|
195
164
|
}
|
|
196
165
|
|
|
197
166
|
/**
|
|
198
167
|
* Register all event listeners.
|
|
199
168
|
*/
|
|
200
169
|
#registerListeners() {
|
|
201
|
-
const followParent = this.#followParent
|
|
202
170
|
const showCascade = () => this.#window.isVisible() || this.#window.show()
|
|
203
171
|
const hideCascade = () => this.#window.isVisible() && this.#window.hide()
|
|
204
|
-
|
|
205
|
-
|
|
206
|
-
|
|
207
|
-
const newPos = this.#parent.getPosition()
|
|
208
|
-
const diff = { x: newPos[0] - lastPos[0], y: newPos[1] - lastPos[1] }
|
|
209
|
-
lastPos = newPos
|
|
210
|
-
|
|
211
|
-
const { x, y } = this.#window.getBounds()
|
|
212
|
-
this.#window.setPosition(x + diff.x, y + diff.y)
|
|
172
|
+
const positionHandler = () => {
|
|
173
|
+
const pos = this.#positionHandler(this.#parent.getBounds(), this.#window.getBounds())
|
|
174
|
+
this.#window.setPosition(pos.x, pos.y)
|
|
213
175
|
}
|
|
214
|
-
|
|
176
|
+
|
|
215
177
|
this.#parent.prependListener('show', showCascade)
|
|
216
178
|
this.#parent.prependListener('hide', hideCascade)
|
|
217
|
-
|
|
179
|
+
this.#parent.prependListener('resize', positionHandler)
|
|
180
|
+
this.#parent.prependListener('move', positionHandler)
|
|
218
181
|
|
|
219
182
|
this.#window.once('close', () => {
|
|
220
183
|
this.#parent.off('show', showCascade)
|
|
221
184
|
this.#parent.off('hide', hideCascade)
|
|
222
|
-
|
|
185
|
+
this.#parent.off('resize', positionHandler)
|
|
186
|
+
this.#parent.off('move', positionHandler)
|
|
223
187
|
this.#window = null
|
|
224
188
|
this.stopFind()
|
|
225
189
|
})
|
|
226
190
|
|
|
227
|
-
this.#
|
|
228
|
-
this.#
|
|
229
|
-
}
|
|
230
|
-
|
|
231
|
-
/**
|
|
232
|
-
* Set default findbar position.
|
|
233
|
-
* @param {Rectangle} parentBounds
|
|
234
|
-
*/
|
|
235
|
-
#setDefaultPosition(parentBounds) {
|
|
236
|
-
const s = this.#window.getSize()
|
|
237
|
-
this.#window.setBounds({
|
|
238
|
-
x: parentBounds.x + parentBounds.width - s[0] - 20,
|
|
239
|
-
y: parentBounds.y - ((s[1] / 4) | 0)
|
|
240
|
-
})
|
|
191
|
+
this.#findableContents.prependOnceListener('destroyed', () => { this.close() })
|
|
192
|
+
this.#findableContents.prependListener('found-in-page', (_e, result) => { this.#sendMatchesCount(result.activeMatchOrdinal, result.matches) })
|
|
241
193
|
}
|
|
242
194
|
|
|
243
195
|
/**
|
|
@@ -257,31 +209,67 @@ class Findbar {
|
|
|
257
209
|
}
|
|
258
210
|
|
|
259
211
|
/**
|
|
260
|
-
*
|
|
212
|
+
* Focus the findbar and highlight the input text.
|
|
261
213
|
*/
|
|
262
|
-
#
|
|
214
|
+
#focusWindowAndHighlightInput() {
|
|
215
|
+
this.#window.focus()
|
|
263
216
|
this.#window.webContents.send('electron-findbar/input-focus')
|
|
264
217
|
}
|
|
218
|
+
|
|
219
|
+
/**
|
|
220
|
+
* Set default findbar position.
|
|
221
|
+
* @param {Rectangle} parentBounds
|
|
222
|
+
* @param {Rectangle} findbarBounds
|
|
223
|
+
* @returns {x: number, y: number} position.
|
|
224
|
+
*/
|
|
225
|
+
static #setDefaultPosition(parentBounds, findbarBounds) {
|
|
226
|
+
return {
|
|
227
|
+
x: parentBounds.x + parentBounds.width - findbarBounds.width - 20,
|
|
228
|
+
y: parentBounds.y - ((findbarBounds.height / 4) | 0)
|
|
229
|
+
}
|
|
230
|
+
}
|
|
231
|
+
|
|
232
|
+
/**
|
|
233
|
+
* Merge custom, defaults, and fixed options.
|
|
234
|
+
* @param {Electron.BrowserWindowConstructorOptions} options Custom options.
|
|
235
|
+
* @param {BaseWindow | void} parent Parent window, if any.
|
|
236
|
+
* @returns {Electron.BrowserWindowConstructorOptions} Merged options.
|
|
237
|
+
*/
|
|
238
|
+
static #mergeStandardOptions(options, parent) {
|
|
239
|
+
if (!options) { options = {} }
|
|
240
|
+
options.width = options.width ?? 372
|
|
241
|
+
options.height = options.height ?? 52
|
|
242
|
+
options.resizable = options.resizable ?? false
|
|
243
|
+
options.movable = options.movable ?? false
|
|
244
|
+
options.acceptFirstMouse = options.acceptFirstMouse ?? true
|
|
245
|
+
options.parent = parent
|
|
246
|
+
options.frame = false
|
|
247
|
+
options.transparent = true
|
|
248
|
+
options.maximizable = false
|
|
249
|
+
options.minimizable = false
|
|
250
|
+
options.skipTaskbar = true
|
|
251
|
+
options.fullscreenable = false
|
|
252
|
+
if (!options.webPreferences) { options.webPreferences = {} }
|
|
253
|
+
options.webPreferences.nodeIntegration = true
|
|
254
|
+
options.webPreferences.contextIsolation = false
|
|
255
|
+
return options
|
|
256
|
+
}
|
|
265
257
|
}
|
|
266
258
|
|
|
267
259
|
/**
|
|
268
260
|
* Define IPC events.
|
|
269
261
|
*/
|
|
270
|
-
(
|
|
271
|
-
|
|
272
|
-
|
|
273
|
-
|
|
274
|
-
|
|
275
|
-
|
|
276
|
-
|
|
277
|
-
|
|
278
|
-
ipcMain.on('electron-findbar/previous', e => e.sender.findbar.findPrevious())
|
|
279
|
-
ipcMain.on('electron-findbar/next', e => e.sender.findbar.findNext())
|
|
280
|
-
ipcMain.on('electron-findbar/close', e => {
|
|
281
|
-
const findbar = e.sender.findbar
|
|
262
|
+
(ipc => {
|
|
263
|
+
ipc.handle('electron-findbar/last-text', e => e.sender._findbar.getLastText())
|
|
264
|
+
ipc.on('electron-findbar/input-change', (e, text, skip) => e.sender._findbar.startFind(text, skip))
|
|
265
|
+
ipc.on('electron-findbar/previous', e => e.sender._findbar.findPrevious())
|
|
266
|
+
ipc.on('electron-findbar/next', e => e.sender._findbar.findNext())
|
|
267
|
+
ipc.on('electron-findbar/open', e => e.sender._findbar.open())
|
|
268
|
+
ipc.on('electron-findbar/close', e => {
|
|
269
|
+
const findbar = e.sender._findbar
|
|
282
270
|
findbar.stopFind()
|
|
283
271
|
findbar.close()
|
|
284
272
|
})
|
|
285
|
-
}) (require('electron'))
|
|
273
|
+
}) (require('electron').ipcMain)
|
|
286
274
|
|
|
287
275
|
module.exports = { Findbar }
|
package/package.json
CHANGED
|
@@ -1,11 +1,11 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "electron-findbar",
|
|
3
|
-
"version": "0.
|
|
3
|
+
"version": "0.5.0",
|
|
4
4
|
"description": "Chrome-like findbar for your Electron app.",
|
|
5
5
|
"main": "index.js",
|
|
6
6
|
"scripts": {
|
|
7
|
-
"sample": "electron sample.js",
|
|
8
|
-
"test": "node test.js"
|
|
7
|
+
"sample": "electron test/sample.js",
|
|
8
|
+
"test": "node test/test.js"
|
|
9
9
|
},
|
|
10
10
|
"repository": {
|
|
11
11
|
"type": "git",
|
package/test/sample.html
ADDED
|
@@ -0,0 +1,35 @@
|
|
|
1
|
+
<!DOCTYPE html>
|
|
2
|
+
<html>
|
|
3
|
+
<head>
|
|
4
|
+
<title>Sample</title>
|
|
5
|
+
</head>
|
|
6
|
+
<body>
|
|
7
|
+
<input type="text" oninput="$remote.inputChange(event.target.value)">
|
|
8
|
+
<button onclick="$remote.open()">Open</button>
|
|
9
|
+
<button onclick="$remote.previous()">Previous</button>
|
|
10
|
+
<button onclick="$remote.next()">Next</button>
|
|
11
|
+
<button onclick="$remote.close()">Close</button>
|
|
12
|
+
<br>
|
|
13
|
+
<span>
|
|
14
|
+
Lorem ipsum dolor sit amet, consectetur adipiscing elit. Donec volutpat massa et suscipit tincidunt. Pellentesque habitant morbi tristique senectus et netus et malesuada fames ac turpis egestas. Nam dictum massa id sapien tristique, in venenatis neque sollicitudin. Fusce accumsan augue arcu, sed rhoncus libero pretium vitae. Phasellus sed imperdiet ante. Maecenas ultrices, elit vitae aliquet tincidunt, elit enim maximus libero, id lacinia ex enim consequat justo. Sed sodales tristique augue sed maximus. Integer tincidunt mi ac arcu tempus, sed accumsan lorem bibendum. Sed in dictum nibh. Pellentesque posuere dui pulvinar sodales scelerisque. Ut nisi magna, vulputate ornare bibendum pharetra, accumsan sed tortor. Proin rhoncus interdum tincidunt. Suspendisse diam eros, ultrices eu volutpat in, vestibulum quis nunc.
|
|
15
|
+
|
|
16
|
+
Sed sit amet dapibus eros. Quisque porttitor mi a nisl pretium molestie. Praesent tellus dui, vehicula a ex sed, faucibus congue mauris. Cras dictum, sapien tempus consequat luctus, dolor magna vestibulum risus, nec blandit diam nulla eget est. Curabitur vitae posuere dolor, accumsan vulputate felis. Cras eget iaculis ante. Nulla velit felis, aliquet vitae convallis nec, vehicula et nunc. Fusce dapibus vel eros non viverra. Fusce elit arcu, tempus eu enim in, rutrum mattis justo.
|
|
17
|
+
|
|
18
|
+
Cras justo tellus, imperdiet et felis sed, iaculis varius lacus. Pellentesque posuere feugiat nisl, eu vulputate tortor. Proin volutpat tortor erat, feugiat pretium justo aliquam non. Maecenas nec neque ultricies diam rhoncus ullamcorper a vitae mauris. Integer ultricies euismod leo, nec facilisis diam volutpat et. Nulla eleifend ante egestas, imperdiet elit at, malesuada velit. Donec tincidunt eleifend libero. Integer congue pharetra scelerisque. In egestas lacus erat. Quisque aliquam massa lectus, eu semper massa ornare auctor. Cras sit amet auctor sem. Curabitur vitae tellus eu risus ultrices accumsan. Curabitur egestas eu lorem et efficitur. Sed nec turpis felis.
|
|
19
|
+
|
|
20
|
+
Suspendisse vel euismod ante. Nunc sagittis quam ut gravida pulvinar. Sed at semper nisl, eu porttitor ante. Cras vitae dolor massa. Fusce tincidunt turpis at egestas pharetra. Donec vitae vestibulum ante. Cras erat dolor, finibus vitae auctor vel, varius dictum arcu. Nam porta arcu consectetur, posuere tellus at, laoreet metus. Ut faucibus tincidunt mi placerat fermentum.
|
|
21
|
+
|
|
22
|
+
Aliquam ut pellentesque tellus, quis vulputate nisl. Phasellus vitae blandit nunc, eu sodales velit. Duis enim tellus, faucibus id arcu vitae, consectetur tempus mauris. Praesent commodo commodo dolor non malesuada. Donec sed dolor eget arcu tincidunt efficitur sit amet vel nisi. Sed consectetur tincidunt molestie. Nam at magna a odio rhoncus convallis id eu nunc. Nam luctus ut leo et viverra. Proin tempor libero vitae arcu laoreet, sed pharetra sapien rutrum. Nam nunc orci, aliquet sit amet dignissim nec, aliquet quis quam. Nulla facilisi.
|
|
23
|
+
</span>
|
|
24
|
+
<script>
|
|
25
|
+
const $remote = (ipc => ({
|
|
26
|
+
getLastText: async () => ipc.invoke('electron-findbar/last-text'),
|
|
27
|
+
inputChange: (value) => { ipc.send('electron-findbar/input-change', value) },
|
|
28
|
+
previous: () => { ipc.send('electron-findbar/previous') },
|
|
29
|
+
next: () => { ipc.send('electron-findbar/next') },
|
|
30
|
+
open: () => { ipc.send('electron-findbar/open') },
|
|
31
|
+
close: () => { ipc.send('electron-findbar/close') },
|
|
32
|
+
})) (require('electron').ipcRenderer)
|
|
33
|
+
</script>
|
|
34
|
+
</body>
|
|
35
|
+
</html>
|
package/test/sample.js
ADDED
|
@@ -0,0 +1,44 @@
|
|
|
1
|
+
const { BrowserWindow, app, Menu, MenuItem } = require('electron')
|
|
2
|
+
const { Findbar } = require('../index')
|
|
3
|
+
|
|
4
|
+
app.whenReady().then(() => {
|
|
5
|
+
const window = setupWindow()
|
|
6
|
+
const findbar = setupFindbar(window)
|
|
7
|
+
setupApplicationMenu(findbar)
|
|
8
|
+
})
|
|
9
|
+
|
|
10
|
+
function setupWindow() {
|
|
11
|
+
const window = new BrowserWindow({
|
|
12
|
+
webPreferences: {
|
|
13
|
+
nodeIntegration: true,
|
|
14
|
+
contextIsolation: false
|
|
15
|
+
}
|
|
16
|
+
})
|
|
17
|
+
window.loadFile(`${__dirname}/sample.html`)
|
|
18
|
+
return window
|
|
19
|
+
}
|
|
20
|
+
|
|
21
|
+
function setupFindbar(window) {
|
|
22
|
+
const findbar = new Findbar(window)
|
|
23
|
+
findbar.setWindowOptions({ movable: true, resizable: true })
|
|
24
|
+
findbar.setWindowHandler(win => { /* handle the findbar window */ })
|
|
25
|
+
findbar.open()
|
|
26
|
+
return findbar
|
|
27
|
+
}
|
|
28
|
+
|
|
29
|
+
function setupApplicationMenu(findbar) {
|
|
30
|
+
const appMenu = Menu.getApplicationMenu()
|
|
31
|
+
appMenu.append(new MenuItem({ label: 'Findbar', submenu: [
|
|
32
|
+
{ label: 'Open', click: () => findbar.open(), accelerator: 'CommandOrControl+F' },
|
|
33
|
+
{ label: 'Close', click: () => findbar.isOpen() && findbar.close(), accelerator: 'Esc' },
|
|
34
|
+
{ role: 'toggleDevTools', accelerator: 'CommandOrControl+Shift+I' },
|
|
35
|
+
{ label: 'Test input propagation', click: () => {
|
|
36
|
+
let count = 0
|
|
37
|
+
setInterval(() => {
|
|
38
|
+
findbar.startFind('count: ' + count++)
|
|
39
|
+
findbar.startFind('cannot show this', true)
|
|
40
|
+
}, 1000)
|
|
41
|
+
}}
|
|
42
|
+
]}))
|
|
43
|
+
Menu.setApplicationMenu(appMenu)
|
|
44
|
+
}
|
package/web/app.css
CHANGED
|
@@ -16,6 +16,9 @@ nav {
|
|
|
16
16
|
--input-color: #1f1f1f;
|
|
17
17
|
--btn-hover-color: #ccc;
|
|
18
18
|
--btn-active-color: #bbb;
|
|
19
|
+
--font-family: system-ui,-apple-system,"Segoe UI",Roboto,"Helvetica Neue","Noto Sans","Liberation Sans",Arial,sans-serif,"Apple Color Emoji","Segoe UI Emoji","Segoe UI Symbol","Noto Color Emoji";
|
|
20
|
+
--font-size: .75rem;
|
|
21
|
+
--spacing: .75rem;
|
|
19
22
|
}
|
|
20
23
|
|
|
21
24
|
@media (prefers-color-scheme: dark) {
|
|
@@ -42,19 +45,25 @@ nav {
|
|
|
42
45
|
align-items: center;
|
|
43
46
|
width: 100%;
|
|
44
47
|
height: 100%;
|
|
45
|
-
padding:
|
|
46
|
-
font-family: system-ui,-apple-system,"Segoe UI",Roboto,"Helvetica Neue","Noto Sans","Liberation Sans",Arial,sans-serif,"Apple Color Emoji","Segoe UI Emoji","Segoe UI Symbol","Noto Color Emoji";
|
|
48
|
+
padding: var(--spacing);
|
|
47
49
|
background-color: var(--bg-color);
|
|
48
50
|
color: var(--color);
|
|
49
|
-
font-size: .75rem;
|
|
50
51
|
border-radius: 10px;
|
|
51
52
|
border: 1px solid var(--border);
|
|
52
53
|
-webkit-app-region: drag;
|
|
53
54
|
}
|
|
54
55
|
|
|
55
|
-
nav >
|
|
56
|
-
|
|
57
|
-
margin-right:
|
|
56
|
+
nav > *:not(:last-child),
|
|
57
|
+
.btn-group > *:not(:last-child) {
|
|
58
|
+
margin-right: var(--spacing);
|
|
59
|
+
}
|
|
60
|
+
|
|
61
|
+
span, input {
|
|
62
|
+
font-family: var(--font-family);
|
|
63
|
+
font-size: var(--font-size);
|
|
64
|
+
}
|
|
65
|
+
|
|
66
|
+
span {
|
|
58
67
|
user-select: none;
|
|
59
68
|
}
|
|
60
69
|
|
|
@@ -62,6 +71,7 @@ input {
|
|
|
62
71
|
width: 100%;
|
|
63
72
|
background-color: transparent;
|
|
64
73
|
color: var(--input-color);
|
|
74
|
+
font-weight: 500;
|
|
65
75
|
border: none;
|
|
66
76
|
outline: none;
|
|
67
77
|
-webkit-app-region: no-drag;
|
|
@@ -77,10 +87,6 @@ input {
|
|
|
77
87
|
display: flex;
|
|
78
88
|
}
|
|
79
89
|
|
|
80
|
-
.btn-group > :not(:last-child) {
|
|
81
|
-
margin-right: .5rem;
|
|
82
|
-
}
|
|
83
|
-
|
|
84
90
|
.btn-group > div {
|
|
85
91
|
border-radius: 50%;
|
|
86
92
|
cursor: default;
|
package/web/app.js
CHANGED
|
@@ -1,14 +1,13 @@
|
|
|
1
|
-
const
|
|
2
|
-
|
|
3
|
-
|
|
4
|
-
|
|
5
|
-
|
|
6
|
-
|
|
7
|
-
|
|
8
|
-
|
|
9
|
-
|
|
10
|
-
|
|
11
|
-
}
|
|
1
|
+
const $remote = (ipc => ({
|
|
2
|
+
getLastText: async () => ipc.invoke('electron-findbar/last-text'),
|
|
3
|
+
inputChange: (value) => { ipc.send('electron-findbar/input-change', value, true) },
|
|
4
|
+
previous: () => { ipc.send('electron-findbar/previous') },
|
|
5
|
+
next: () => { ipc.send('electron-findbar/next') },
|
|
6
|
+
close: () => { ipc.send('electron-findbar/close') },
|
|
7
|
+
onMatchesChange: (listener) => { ipc.on('electron-findbar/matches', listener) },
|
|
8
|
+
onInputFocus: (listener) => { ipc.on('electron-findbar/input-focus', listener) },
|
|
9
|
+
onTextChange: (listener) => { ipc.on('electron-findbar/text-change', listener) }
|
|
10
|
+
})) (require('electron').ipcRenderer)
|
|
12
11
|
|
|
13
12
|
let canRequest = true, canMove = false
|
|
14
13
|
|
|
@@ -40,12 +39,15 @@ document.addEventListener('DOMContentLoaded', async () => {
|
|
|
40
39
|
}
|
|
41
40
|
})
|
|
42
41
|
|
|
43
|
-
$remote.onInputFocus(
|
|
42
|
+
$remote.onInputFocus(() => {
|
|
44
43
|
inputEl.setSelectionRange(0, inputEl.value.length)
|
|
45
44
|
inputEl.focus()
|
|
46
45
|
})
|
|
47
46
|
|
|
48
|
-
inputEl.value =
|
|
47
|
+
$remote.onTextChange((_, text) => { inputEl.value = text })
|
|
48
|
+
|
|
49
|
+
inputEl.value = await $remote.getLastText()
|
|
50
|
+
$remote.inputChange(inputEl.value)
|
|
49
51
|
inputEl.setSelectionRange(0, inputEl.value.length)
|
|
50
52
|
inputEl.focus()
|
|
51
53
|
})
|
package/web/findbar.html
CHANGED
|
@@ -8,7 +8,7 @@
|
|
|
8
8
|
<link rel="stylesheet" href="app.css">
|
|
9
9
|
<body>
|
|
10
10
|
<nav>
|
|
11
|
-
<input id='input' oninput="inputChange(event)" type="
|
|
11
|
+
<input id='input' oninput="inputChange(event)" type="text" spellcheck="false">
|
|
12
12
|
<span id="matches"></span>
|
|
13
13
|
<div class="divider"></div>
|
|
14
14
|
<div class="btn-group">
|
package/sample.js
DELETED
|
@@ -1,23 +0,0 @@
|
|
|
1
|
-
const { BrowserWindow, app, Menu } = require('electron')
|
|
2
|
-
const { Findbar } = require('./index')
|
|
3
|
-
|
|
4
|
-
app.whenReady().then(() => {
|
|
5
|
-
const window = new BrowserWindow()
|
|
6
|
-
window.loadURL('https://github.com/ECRomaneli/electron-findbar#readme')
|
|
7
|
-
|
|
8
|
-
const findbar = new Findbar(window)
|
|
9
|
-
findbar.setWindowOptions({ movable: !true, resizable: true })
|
|
10
|
-
findbar.setWindowHandler(win => {
|
|
11
|
-
win.webContents.openDevTools()
|
|
12
|
-
})
|
|
13
|
-
findbar.open()
|
|
14
|
-
|
|
15
|
-
const contextMenu = Menu.buildFromTemplate([
|
|
16
|
-
{ role: 'separator' },
|
|
17
|
-
{ label: 'Open findbar', click: () => findbar.open(), accelerator: 'CommandOrControl+F' },
|
|
18
|
-
{ label: 'Close findbar', click: () => findbar.isOpen() && findbar.close(), accelerator: 'Esc', registerAccelerator: true, acceleratorWorksWhenHidden: true }
|
|
19
|
-
])
|
|
20
|
-
|
|
21
|
-
Menu.setApplicationMenu(contextMenu)
|
|
22
|
-
|
|
23
|
-
})
|
|
File without changes
|