electron-findbar 2.0.1 → 3.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/README.md +88 -26
- package/index.js +95 -26
- package/package.json +1 -1
package/README.md
CHANGED
|
@@ -44,7 +44,7 @@ const Findbar = require('electron-findbar')
|
|
|
44
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:
|
|
45
45
|
|
|
46
46
|
```js
|
|
47
|
-
// 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.
|
|
48
48
|
const findbar = Findbar.from(browserWindow)
|
|
49
49
|
```
|
|
50
50
|
|
|
@@ -55,10 +55,10 @@ Alternatively, you can provide a custom `WebContents` as the second parameter. I
|
|
|
55
55
|
const findbar = Findbar.from(baseWindow, webContents)
|
|
56
56
|
```
|
|
57
57
|
|
|
58
|
-
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:
|
|
59
59
|
|
|
60
60
|
```js
|
|
61
|
-
// Create or retrieve the findbar associated to the webContents.
|
|
61
|
+
// Create or retrieve the findbar associated to the webContents.
|
|
62
62
|
const findbar = Findbar.from(webContents)
|
|
63
63
|
```
|
|
64
64
|
|
|
@@ -146,9 +146,20 @@ app.whenReady().then(() => {
|
|
|
146
146
|
})
|
|
147
147
|
```
|
|
148
148
|
|
|
149
|
-
###
|
|
149
|
+
### Keyboard Shortcuts
|
|
150
150
|
|
|
151
|
-
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.
|
|
152
163
|
|
|
153
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.
|
|
154
165
|
|
|
@@ -157,27 +168,35 @@ The Findbar component can be controlled using keyboard shortcuts. Below are two
|
|
|
157
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:
|
|
158
169
|
|
|
159
170
|
```js
|
|
160
|
-
|
|
161
|
-
|
|
162
|
-
|
|
163
|
-
|
|
164
|
-
|
|
165
|
-
|
|
166
|
-
|
|
167
|
-
|
|
168
|
-
|
|
169
|
-
|
|
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
|
|
170
186
|
}
|
|
171
|
-
|
|
172
|
-
|
|
173
|
-
|
|
174
|
-
|
|
175
|
-
|
|
176
|
-
|
|
177
|
-
|
|
178
|
-
|
|
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
|
+
}
|
|
179
199
|
}
|
|
180
|
-
}
|
|
181
200
|
})
|
|
182
201
|
```
|
|
183
202
|
|
|
@@ -198,12 +217,12 @@ appMenu.append(new MenuItem({
|
|
|
198
217
|
submenu: [
|
|
199
218
|
{
|
|
200
219
|
label: 'Find in Page',
|
|
201
|
-
click: () => Findbar.from(parent)
|
|
220
|
+
click: () => Findbar.from(parent).open(),
|
|
202
221
|
accelerator: 'CommandOrControl+F'
|
|
203
222
|
},
|
|
204
223
|
{
|
|
205
224
|
label: 'Close Find',
|
|
206
|
-
click: () => Findbar.from(parent)
|
|
225
|
+
click: () => Findbar.from(parent).close(),
|
|
207
226
|
accelerator: 'Esc'
|
|
208
227
|
}
|
|
209
228
|
]
|
|
@@ -308,6 +327,49 @@ FindbarRemote.open()
|
|
|
308
327
|
FindbarRemote.inputChange('findIt')
|
|
309
328
|
```
|
|
310
329
|
|
|
330
|
+
## Changing the Parent Window
|
|
331
|
+
|
|
332
|
+
There are scenarios where you might need to change the parent window.
|
|
333
|
+
|
|
334
|
+
### Using updateParentWindow
|
|
335
|
+
|
|
336
|
+
The `updateParentWindow` method allows you to change the parent window while preserving the findbar instance and its state:
|
|
337
|
+
|
|
338
|
+
```javascript
|
|
339
|
+
// Create a findbar for the initial window
|
|
340
|
+
const findbar = Findbar.from(oldWindow, webContents)
|
|
341
|
+
|
|
342
|
+
// Later, when you need to change the parent:
|
|
343
|
+
findbar.updateParentWindow(newWindow)
|
|
344
|
+
```
|
|
345
|
+
|
|
346
|
+
This approach keeps the same findbar instance connected to the same webContents, but changes which window it's attached to. The findbar will close immediately.
|
|
347
|
+
|
|
348
|
+
### Using detach
|
|
349
|
+
|
|
350
|
+
Alternatively, the `detach` method disconnects a findbar instance from its webContents, allowing you to create a new instance in the next `Findbar.from` call:
|
|
351
|
+
|
|
352
|
+
```javascript
|
|
353
|
+
// Get the existing findbar
|
|
354
|
+
const oldFindbar = Findbar.fromIfExists(webContents)
|
|
355
|
+
|
|
356
|
+
// Detach it to free the association
|
|
357
|
+
if (oldFindbar) {
|
|
358
|
+
oldFindbar.detach()
|
|
359
|
+
}
|
|
360
|
+
|
|
361
|
+
// Now create a new findbar with a different parent
|
|
362
|
+
const newFindbar = Findbar.from([newWindow, ]webContents)
|
|
363
|
+
```
|
|
364
|
+
|
|
365
|
+
This approach is useful when you want to completely reset the findbar's configuration or when moving between very different window configurations.
|
|
366
|
+
|
|
367
|
+
### Important Considerations
|
|
368
|
+
|
|
369
|
+
- If the findbar is currently open when you change the parent window, it will automatically close.
|
|
370
|
+
- Window options and handlers will be preserved when using `updateParentWindow`.
|
|
371
|
+
- After calling `detach`, the old findbar instance can no longer be used.
|
|
372
|
+
|
|
311
373
|
## Author
|
|
312
374
|
|
|
313
375
|
Created by [Emerson Capuchi Romaneli](https://github.com/ECRomaneli) (@ECRomaneli).
|
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) {
|
|
@@ -73,8 +74,10 @@ class Findbar {
|
|
|
73
74
|
}
|
|
74
75
|
|
|
75
76
|
this.#findableContents._findbar = this
|
|
77
|
+
|
|
78
|
+
this.#findableContents.once('destroyed', () => { this.detach() })
|
|
76
79
|
}
|
|
77
|
-
|
|
80
|
+
|
|
78
81
|
/**
|
|
79
82
|
* Open the findbar. If the findbar is already opened, focus the input text.
|
|
80
83
|
* @returns {void}
|
|
@@ -92,7 +95,6 @@ class Findbar {
|
|
|
92
95
|
this.#registerListeners()
|
|
93
96
|
|
|
94
97
|
this.#windowHandler && this.#windowHandler(this.#window)
|
|
95
|
-
|
|
96
98
|
this.#window.loadFile(`${__dirname}/web/findbar.html`)
|
|
97
99
|
}
|
|
98
100
|
|
|
@@ -101,10 +103,30 @@ class Findbar {
|
|
|
101
103
|
* @returns {void}
|
|
102
104
|
*/
|
|
103
105
|
close() {
|
|
104
|
-
if (
|
|
105
|
-
|
|
106
|
-
|
|
107
|
-
|
|
106
|
+
if (this.#window && !this.#window.isDestroyed()) {
|
|
107
|
+
this.#window.close()
|
|
108
|
+
}
|
|
109
|
+
}
|
|
110
|
+
|
|
111
|
+
/**
|
|
112
|
+
* Detach the findbar from the web contents and close it if opened. After detaching, the findbar instance will be unusable.
|
|
113
|
+
* @returns {void}
|
|
114
|
+
*/
|
|
115
|
+
detach() {
|
|
116
|
+
this.close()
|
|
117
|
+
this.#findableContents._findbar = void 0
|
|
118
|
+
if (this.#window) { this.#window.webContents._findbar = void 0 }
|
|
119
|
+
}
|
|
120
|
+
|
|
121
|
+
/**
|
|
122
|
+
* Update the parent window of the findbar.
|
|
123
|
+
* @param {BaseWindow} [newParent] - The new parent window. If not provided, the parent will be set to the window containing the web contents.
|
|
124
|
+
* @returns {void}
|
|
125
|
+
*/
|
|
126
|
+
updateParentWindow(newParent) {
|
|
127
|
+
if (this.#parent === newParent) { return }
|
|
128
|
+
this.close()
|
|
129
|
+
this.#parent = newParent ?? Findbar.#getBaseWindowFromWebContents(this.#findableContents)
|
|
108
130
|
}
|
|
109
131
|
|
|
110
132
|
/**
|
|
@@ -235,6 +257,32 @@ class Findbar {
|
|
|
235
257
|
this.#boundsHandler = boundsHandler
|
|
236
258
|
}
|
|
237
259
|
|
|
260
|
+
#registerKeyboardShortcuts(event, input) {
|
|
261
|
+
if (input.meta || input.control || input.alt) { return }
|
|
262
|
+
|
|
263
|
+
const key = input.key.toLowerCase()
|
|
264
|
+
|
|
265
|
+
if (input.shift) {
|
|
266
|
+
if (key === 'enter') {
|
|
267
|
+
this.findPrevious()
|
|
268
|
+
event.preventDefault()
|
|
269
|
+
}
|
|
270
|
+
return;
|
|
271
|
+
}
|
|
272
|
+
|
|
273
|
+
if (key === 'enter') {
|
|
274
|
+
this.findNext()
|
|
275
|
+
event.preventDefault()
|
|
276
|
+
return;
|
|
277
|
+
}
|
|
278
|
+
|
|
279
|
+
if (key === 'escape') {
|
|
280
|
+
if (this.isOpen()) {
|
|
281
|
+
this.close()
|
|
282
|
+
event.preventDefault()
|
|
283
|
+
}
|
|
284
|
+
}
|
|
285
|
+
}
|
|
238
286
|
/**
|
|
239
287
|
* @param {Electron.FindInPageOptions} options
|
|
240
288
|
*/
|
|
@@ -269,7 +317,7 @@ class Findbar {
|
|
|
269
317
|
this.#parent.prependListener('move', boundsHandler)
|
|
270
318
|
}
|
|
271
319
|
|
|
272
|
-
this.#window.once('
|
|
320
|
+
this.#window.once('closed', () => {
|
|
273
321
|
if (this.#parent && !this.#parent.isDestroyed()) {
|
|
274
322
|
this.#parent.off('show', showCascade)
|
|
275
323
|
this.#parent.off('hide', hideCascade)
|
|
@@ -281,6 +329,7 @@ class Findbar {
|
|
|
281
329
|
})
|
|
282
330
|
|
|
283
331
|
this.#window.prependOnceListener('ready-to-show', () => { this.#window.show() })
|
|
332
|
+
this.#window.webContents.prependListener('before-input-event', this.#registerKeyboardShortcuts.bind(this))
|
|
284
333
|
|
|
285
334
|
this.#findableContents.prependOnceListener('destroyed', () => { this.close() })
|
|
286
335
|
this.#findableContents.prependListener('found-in-page', (_e, result) => { this.#sendMatchesCount(result.activeMatchOrdinal, result.matches) })
|
|
@@ -310,6 +359,24 @@ class Findbar {
|
|
|
310
359
|
this.#window.webContents.send('electron-findbar/input-focus')
|
|
311
360
|
}
|
|
312
361
|
|
|
362
|
+
/**
|
|
363
|
+
* Retrieve web contents from a BrowserWindow or BaseWindow.
|
|
364
|
+
* @param {BrowserWindow | BaseWindow} window
|
|
365
|
+
* @returns {WebContents | undefined} The web contents if any.
|
|
366
|
+
*/
|
|
367
|
+
static #retrieveWebContents(window) {
|
|
368
|
+
return window.webContents ?? window.contentView?.children[0]
|
|
369
|
+
}
|
|
370
|
+
|
|
371
|
+
/**
|
|
372
|
+
* Get the parent window from web contents.
|
|
373
|
+
* @param {WebContents} cont
|
|
374
|
+
* @returns {BaseWindow | undefined} Parent window if any.
|
|
375
|
+
*/
|
|
376
|
+
static #getBaseWindowFromWebContents(cont) {
|
|
377
|
+
return BaseWindow.getAllWindows().find(win => win.webContents === cont || win.contentView.children.some(child => child.webContents === cont))
|
|
378
|
+
}
|
|
379
|
+
|
|
313
380
|
/**
|
|
314
381
|
* Set default findbar position.
|
|
315
382
|
* @param {Rectangle} parentBounds
|
|
@@ -358,25 +425,25 @@ class Findbar {
|
|
|
358
425
|
* If no findbar instance exists, it will return a new one linked to the web contents.
|
|
359
426
|
*
|
|
360
427
|
* @overload
|
|
361
|
-
* @param {
|
|
362
|
-
*
|
|
428
|
+
* @param {WebContents} webContents Findable web contents. The parent window will be defined by using BaseWindow.getAllWindows() and
|
|
429
|
+
* matching the webContents with the webContents of the window or its contentView children.
|
|
363
430
|
* @returns {Findbar} The findbar instance if it exists.
|
|
431
|
+
* @throws {Error} If no webContents is provided.
|
|
364
432
|
*
|
|
365
433
|
* @overload
|
|
366
|
-
* @param {
|
|
434
|
+
* @param {BrowserWindow} browserWindow Parent window.
|
|
435
|
+
* @param {WebContents} [customWebContents] Custom findable web contents. If not provided, the browserWindow.webContents will be used.
|
|
367
436
|
* @returns {Findbar} The findbar instance if it exists.
|
|
368
|
-
*
|
|
369
|
-
*
|
|
437
|
+
*
|
|
370
438
|
* @overload
|
|
371
439
|
* @param {BaseWindow} baseWindow Parent window.
|
|
372
|
-
* @param {WebContents} webContents
|
|
440
|
+
* @param {WebContents} [webContents] Custom findable web contents. If not provided, the win.contentView.children[0] will be used.
|
|
373
441
|
* @returns {Findbar} The findbar instance if it exists.
|
|
374
442
|
* @throws {Error} If no webContents is provided.
|
|
375
443
|
*/
|
|
376
444
|
static from(windowOrWebContents, customWebContents) {
|
|
377
|
-
|
|
378
|
-
|
|
379
|
-
|
|
445
|
+
const webContents = isFindable(windowOrWebContents) ? windowOrWebContents : customWebContents ?? Findbar.#retrieveWebContents(windowOrWebContents)
|
|
446
|
+
if (!webContents) { throw new Error('[Findbar] There are no searchable web contents.') }
|
|
380
447
|
return webContents._findbar || new Findbar(windowOrWebContents, customWebContents)
|
|
381
448
|
}
|
|
382
449
|
|
|
@@ -386,7 +453,9 @@ class Findbar {
|
|
|
386
453
|
* @returns {Findbar | undefined} The findbar instance if it exists, otherwise undefined.
|
|
387
454
|
*/
|
|
388
455
|
static fromIfExists(windowOrWebContents) {
|
|
389
|
-
|
|
456
|
+
const webContents = isFindable(windowOrWebContents) ? windowOrWebContents : Findbar.#retrieveWebContents(windowOrWebContents)
|
|
457
|
+
if (!webContents) { throw new Error('[Findbar] There are no searchable web contents.') }
|
|
458
|
+
return webContents._findbar
|
|
390
459
|
}
|
|
391
460
|
}
|
|
392
461
|
|