electron-findbar 2.0.0 → 3.0.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/README.md +46 -30
- package/index.js +87 -25
- package/package.json +1 -1
package/README.md
CHANGED
|
@@ -1,8 +1,5 @@
|
|
|
1
1
|
<p align='center'>
|
|
2
|
-
<a href="https://github.com/ECRomaneli/
|
|
3
|
-
<img src="https://i.postimg.cc/sXwqJP59/findbar-v2-light.png" alt='Findbar Light Theme'>
|
|
4
|
-
<img src="https://i.postimg.cc/j26XXRVV/findbar-v2-dark.png" alt='Findbar Dark Theme'>
|
|
5
|
-
</a>
|
|
2
|
+
<a href="https://github.com/ECRomaneli/electron-findbar" style='text-decoration:none'><img src="https://i.postimg.cc/sXwqJP59/findbar-v2-light.png" alt='Findbar Light Theme'><img src="https://i.postimg.cc/j26XXRVV/findbar-v2-dark.png" alt='Findbar Dark Theme'></a>
|
|
6
3
|
</p>
|
|
7
4
|
<p align='center'>
|
|
8
5
|
Chrome-like findbar for your Electron application
|
|
@@ -47,7 +44,7 @@ const Findbar = require('electron-findbar')
|
|
|
47
44
|
You can pass a `BrowserWindow` instance as a single parameter to use it as the parent window. The `BrowserWindow.WebContents` will be used as the findable content:
|
|
48
45
|
|
|
49
46
|
```js
|
|
50
|
-
// Create or retrieve the findbar associated to the browserWindow.webContents. If a new findbar is created, the browserWindow is used as parent.
|
|
47
|
+
// Create or retrieve the findbar associated to the browserWindow.webContents or baseWindow.contentView.children[0]. If a new findbar is created, the browserWindow is used as parent.
|
|
51
48
|
const findbar = Findbar.from(browserWindow)
|
|
52
49
|
```
|
|
53
50
|
|
|
@@ -58,10 +55,10 @@ Alternatively, you can provide a custom `WebContents` as the second parameter. I
|
|
|
58
55
|
const findbar = Findbar.from(baseWindow, webContents)
|
|
59
56
|
```
|
|
60
57
|
|
|
61
|
-
Is also possible to create a findbar
|
|
58
|
+
Is also possible to create a findbar providing only the web contents. The BaseWindow.getAllWindows() will be used to query for the parent window:
|
|
62
59
|
|
|
63
60
|
```js
|
|
64
|
-
// Create or retrieve the findbar associated to the webContents.
|
|
61
|
+
// Create or retrieve the findbar associated to the webContents.
|
|
65
62
|
const findbar = Findbar.from(webContents)
|
|
66
63
|
```
|
|
67
64
|
|
|
@@ -149,9 +146,20 @@ app.whenReady().then(() => {
|
|
|
149
146
|
})
|
|
150
147
|
```
|
|
151
148
|
|
|
152
|
-
###
|
|
149
|
+
### Keyboard Shortcuts
|
|
153
150
|
|
|
154
|
-
The Findbar component can be controlled using keyboard shortcuts.
|
|
151
|
+
The Findbar component can be controlled using keyboard shortcuts. The following shortcuts are available by default:
|
|
152
|
+
|
|
153
|
+
| Shortcut | Description |
|
|
154
|
+
|----------|-------------|
|
|
155
|
+
| Enter | Move to next match |
|
|
156
|
+
| Shift+Enter | Move to previous match |
|
|
157
|
+
| Esc | Close the findbar |
|
|
158
|
+
|
|
159
|
+
|
|
160
|
+
### Configuring Other Shortcuts
|
|
161
|
+
|
|
162
|
+
Below are two implementation approaches to help you integrate search functionality seamlessly into your application's user experience.
|
|
155
163
|
|
|
156
164
|
**Note:** The following examples demonstrate only the ideal (happy path) scenarios. For production use, make sure to thoroughly validate all inputs and handle edge cases appropriately.
|
|
157
165
|
|
|
@@ -160,27 +168,35 @@ The Findbar component can be controlled using keyboard shortcuts. Below are two
|
|
|
160
168
|
The `before-input-event` approach allows you to capture keyboard events directly in the main process before they're processed by the web contents, giving you precise control:
|
|
161
169
|
|
|
162
170
|
```js
|
|
163
|
-
|
|
164
|
-
|
|
165
|
-
|
|
166
|
-
|
|
167
|
-
|
|
168
|
-
|
|
169
|
-
|
|
170
|
-
|
|
171
|
-
|
|
172
|
-
|
|
171
|
+
webContents.on('before-input-event', (event, input) => {
|
|
172
|
+
if (input.shift || input.alt) { return }
|
|
173
|
+
|
|
174
|
+
const key = input.key.toLowerCase()
|
|
175
|
+
|
|
176
|
+
// Detect Ctrl+F (Windows/Linux) or Command+F (macOS)
|
|
177
|
+
if (input.control || input.meta) {
|
|
178
|
+
if (key === 'f') {
|
|
179
|
+
// Prevent default behavior
|
|
180
|
+
event.preventDefault()
|
|
181
|
+
|
|
182
|
+
// Access and open the findbar
|
|
183
|
+
Findbar.from(webContents).open()
|
|
184
|
+
}
|
|
185
|
+
return
|
|
173
186
|
}
|
|
174
|
-
|
|
175
|
-
|
|
176
|
-
|
|
177
|
-
|
|
178
|
-
|
|
179
|
-
|
|
180
|
-
|
|
181
|
-
|
|
187
|
+
|
|
188
|
+
// Handle Escape key to close the findbar
|
|
189
|
+
if (key === 'escape') {
|
|
190
|
+
const findbar = Findbar.fromIfExists(webContents)
|
|
191
|
+
|
|
192
|
+
if (findbar?.isOpen()) {
|
|
193
|
+
// Prevent default behavior
|
|
194
|
+
event.preventDefault()
|
|
195
|
+
|
|
196
|
+
// Close the findbar
|
|
197
|
+
findbar.close()
|
|
198
|
+
}
|
|
182
199
|
}
|
|
183
|
-
}
|
|
184
200
|
})
|
|
185
201
|
```
|
|
186
202
|
|
|
@@ -201,12 +217,12 @@ appMenu.append(new MenuItem({
|
|
|
201
217
|
submenu: [
|
|
202
218
|
{
|
|
203
219
|
label: 'Find in Page',
|
|
204
|
-
click: () => Findbar.from(parent)
|
|
220
|
+
click: () => Findbar.from(parent).open(),
|
|
205
221
|
accelerator: 'CommandOrControl+F'
|
|
206
222
|
},
|
|
207
223
|
{
|
|
208
224
|
label: 'Close Find',
|
|
209
|
-
click: () => Findbar.from(parent)
|
|
225
|
+
click: () => Findbar.from(parent).close(),
|
|
210
226
|
accelerator: 'Esc'
|
|
211
227
|
}
|
|
212
228
|
]
|
package/index.js
CHANGED
|
@@ -44,28 +44,29 @@ class Findbar {
|
|
|
44
44
|
* Configure the findbar and link to the web contents.
|
|
45
45
|
*
|
|
46
46
|
* @overload
|
|
47
|
+
* @param {WebContents} webContents Findable web contents. The parent window will be defined by using BaseWindow.getAllWindows() and
|
|
48
|
+
* matching the webContents with the webContents of the window or its contentView children.
|
|
49
|
+
* @returns {Findbar} The findbar instance if it exists.
|
|
50
|
+
* @throws {Error} If no webContents is provided.
|
|
51
|
+
*
|
|
52
|
+
* @overload
|
|
47
53
|
* @param {BrowserWindow} browserWindow Parent window.
|
|
48
|
-
* @param {WebContents} [customWebContents] Custom findable web contents. If not provided, the
|
|
54
|
+
* @param {WebContents} [customWebContents] Custom findable web contents. If not provided, the browserWindow.webContents will be used.
|
|
49
55
|
* @returns {Findbar} The findbar instance if it exists.
|
|
50
56
|
*
|
|
51
57
|
* @overload
|
|
52
58
|
* @param {BaseWindow} baseWindow Parent window.
|
|
53
|
-
* @param {WebContents} webContents
|
|
54
|
-
* @returns {Findbar} The findbar instance if it exists.
|
|
55
|
-
* @throws {Error} If no webContents is provided.
|
|
56
|
-
* *
|
|
57
|
-
* @overload
|
|
58
|
-
* @param {WebContents} webContents Findable web contents. The parent window will be undefined.
|
|
59
|
+
* @param {WebContents} [webContents] Custom findable web contents. If not provided, the win.contentView.children[0] will be used.
|
|
59
60
|
* @returns {Findbar} The findbar instance if it exists.
|
|
60
61
|
* @throws {Error} If no webContents is provided.
|
|
61
62
|
*/
|
|
62
63
|
constructor (parent, webContents) {
|
|
63
64
|
if (isFindable(parent)) {
|
|
64
|
-
this.#parent = void 0
|
|
65
65
|
this.#findableContents = parent
|
|
66
|
+
this.#parent = Findbar.#getBaseWindowFromWebContents(this.#findableContents)
|
|
66
67
|
} else {
|
|
67
68
|
this.#parent = parent
|
|
68
|
-
this.#findableContents = webContents ?? parent
|
|
69
|
+
this.#findableContents = webContents ?? Findbar.#retrieveWebContents(parent)
|
|
69
70
|
}
|
|
70
71
|
|
|
71
72
|
if (!this.#findableContents) {
|
|
@@ -74,7 +75,7 @@ class Findbar {
|
|
|
74
75
|
|
|
75
76
|
this.#findableContents._findbar = this
|
|
76
77
|
}
|
|
77
|
-
|
|
78
|
+
|
|
78
79
|
/**
|
|
79
80
|
* Open the findbar. If the findbar is already opened, focus the input text.
|
|
80
81
|
* @returns {void}
|
|
@@ -92,7 +93,6 @@ class Findbar {
|
|
|
92
93
|
this.#registerListeners()
|
|
93
94
|
|
|
94
95
|
this.#windowHandler && this.#windowHandler(this.#window)
|
|
95
|
-
|
|
96
96
|
this.#window.loadFile(`${__dirname}/web/findbar.html`)
|
|
97
97
|
}
|
|
98
98
|
|
|
@@ -101,10 +101,25 @@ class Findbar {
|
|
|
101
101
|
* @returns {void}
|
|
102
102
|
*/
|
|
103
103
|
close() {
|
|
104
|
-
if (
|
|
105
|
-
|
|
106
|
-
|
|
107
|
-
|
|
104
|
+
if (this.#window && !this.#window.isDestroyed()) {
|
|
105
|
+
this.#window.close()
|
|
106
|
+
}
|
|
107
|
+
}
|
|
108
|
+
|
|
109
|
+
/**
|
|
110
|
+
* Detach the findbar from the web contents and close it if opened. After detaching, the findbar instance will be unusable.
|
|
111
|
+
* @returns {void}
|
|
112
|
+
*/
|
|
113
|
+
detach() {
|
|
114
|
+
this.close()
|
|
115
|
+
this.#findableContents._findbar = void 0
|
|
116
|
+
if (this.#window) { this.#window.webContents._findbar = void 0 }
|
|
117
|
+
}
|
|
118
|
+
|
|
119
|
+
setTheme(theme) {
|
|
120
|
+
if (this.#window && !this.#window.isDestroyed()) {
|
|
121
|
+
this.#window.webContents.send('electron-findbar/set-theme', theme)
|
|
122
|
+
}
|
|
108
123
|
}
|
|
109
124
|
|
|
110
125
|
/**
|
|
@@ -235,6 +250,32 @@ class Findbar {
|
|
|
235
250
|
this.#boundsHandler = boundsHandler
|
|
236
251
|
}
|
|
237
252
|
|
|
253
|
+
#registerKeyboardShortcuts(event, input) {
|
|
254
|
+
if (input.meta || input.control || input.alt) { return }
|
|
255
|
+
|
|
256
|
+
const key = input.key.toLowerCase()
|
|
257
|
+
|
|
258
|
+
if (input.shift) {
|
|
259
|
+
if (key === 'enter') {
|
|
260
|
+
this.findPrevious()
|
|
261
|
+
event.preventDefault()
|
|
262
|
+
}
|
|
263
|
+
return;
|
|
264
|
+
}
|
|
265
|
+
|
|
266
|
+
if (key === 'enter') {
|
|
267
|
+
this.findNext()
|
|
268
|
+
event.preventDefault()
|
|
269
|
+
return;
|
|
270
|
+
}
|
|
271
|
+
|
|
272
|
+
if (key === 'escape') {
|
|
273
|
+
if (this.isOpen()) {
|
|
274
|
+
this.close()
|
|
275
|
+
event.preventDefault()
|
|
276
|
+
}
|
|
277
|
+
}
|
|
278
|
+
}
|
|
238
279
|
/**
|
|
239
280
|
* @param {Electron.FindInPageOptions} options
|
|
240
281
|
*/
|
|
@@ -281,6 +322,7 @@ class Findbar {
|
|
|
281
322
|
})
|
|
282
323
|
|
|
283
324
|
this.#window.prependOnceListener('ready-to-show', () => { this.#window.show() })
|
|
325
|
+
this.#window.webContents.prependListener('before-input-event', this.#registerKeyboardShortcuts.bind(this))
|
|
284
326
|
|
|
285
327
|
this.#findableContents.prependOnceListener('destroyed', () => { this.close() })
|
|
286
328
|
this.#findableContents.prependListener('found-in-page', (_e, result) => { this.#sendMatchesCount(result.activeMatchOrdinal, result.matches) })
|
|
@@ -310,6 +352,24 @@ class Findbar {
|
|
|
310
352
|
this.#window.webContents.send('electron-findbar/input-focus')
|
|
311
353
|
}
|
|
312
354
|
|
|
355
|
+
/**
|
|
356
|
+
* Retrieve web contents from a BrowserWindow or BaseWindow.
|
|
357
|
+
* @param {BrowserWindow | BaseWindow} window
|
|
358
|
+
* @returns {WebContents | undefined} The web contents if any.
|
|
359
|
+
*/
|
|
360
|
+
static #retrieveWebContents(window) {
|
|
361
|
+
return window.webContents ?? window.contentView?.children[0]
|
|
362
|
+
}
|
|
363
|
+
|
|
364
|
+
/**
|
|
365
|
+
* Get the parent window from web contents.
|
|
366
|
+
* @param {WebContents} cont
|
|
367
|
+
* @returns {BaseWindow | undefined} Parent window if any.
|
|
368
|
+
*/
|
|
369
|
+
static #getBaseWindowFromWebContents(cont) {
|
|
370
|
+
return BaseWindow.getAllWindows().find(win => win.webContents === cont || win.contentView.children.some(child => child.webContents === cont))
|
|
371
|
+
}
|
|
372
|
+
|
|
313
373
|
/**
|
|
314
374
|
* Set default findbar position.
|
|
315
375
|
* @param {Rectangle} parentBounds
|
|
@@ -358,25 +418,25 @@ class Findbar {
|
|
|
358
418
|
* If no findbar instance exists, it will return a new one linked to the web contents.
|
|
359
419
|
*
|
|
360
420
|
* @overload
|
|
361
|
-
* @param {
|
|
362
|
-
*
|
|
421
|
+
* @param {WebContents} webContents Findable web contents. The parent window will be defined by using BaseWindow.getAllWindows() and
|
|
422
|
+
* matching the webContents with the webContents of the window or its contentView children.
|
|
363
423
|
* @returns {Findbar} The findbar instance if it exists.
|
|
424
|
+
* @throws {Error} If no webContents is provided.
|
|
364
425
|
*
|
|
365
426
|
* @overload
|
|
366
|
-
* @param {
|
|
427
|
+
* @param {BrowserWindow} browserWindow Parent window.
|
|
428
|
+
* @param {WebContents} [customWebContents] Custom findable web contents. If not provided, the browserWindow.webContents will be used.
|
|
367
429
|
* @returns {Findbar} The findbar instance if it exists.
|
|
368
|
-
*
|
|
369
|
-
*
|
|
430
|
+
*
|
|
370
431
|
* @overload
|
|
371
432
|
* @param {BaseWindow} baseWindow Parent window.
|
|
372
|
-
* @param {WebContents} webContents
|
|
433
|
+
* @param {WebContents} [webContents] Custom findable web contents. If not provided, the win.contentView.children[0] will be used.
|
|
373
434
|
* @returns {Findbar} The findbar instance if it exists.
|
|
374
435
|
* @throws {Error} If no webContents is provided.
|
|
375
436
|
*/
|
|
376
437
|
static from(windowOrWebContents, customWebContents) {
|
|
377
|
-
|
|
378
|
-
|
|
379
|
-
|
|
438
|
+
const webContents = isFindable(windowOrWebContents) ? windowOrWebContents : customWebContents ?? Findbar.#retrieveWebContents(windowOrWebContents)
|
|
439
|
+
if (!webContents) { throw new Error('[Findbar] There are no searchable web contents.') }
|
|
380
440
|
return webContents._findbar || new Findbar(windowOrWebContents, customWebContents)
|
|
381
441
|
}
|
|
382
442
|
|
|
@@ -386,7 +446,9 @@ class Findbar {
|
|
|
386
446
|
* @returns {Findbar | undefined} The findbar instance if it exists, otherwise undefined.
|
|
387
447
|
*/
|
|
388
448
|
static fromIfExists(windowOrWebContents) {
|
|
389
|
-
|
|
449
|
+
const webContents = isFindable(windowOrWebContents) ? windowOrWebContents : Findbar.#retrieveWebContents(windowOrWebContents)
|
|
450
|
+
if (!webContents) { throw new Error('[Findbar] There are no searchable web contents.') }
|
|
451
|
+
return webContents._findbar
|
|
390
452
|
}
|
|
391
453
|
}
|
|
392
454
|
|