Ecosyste.ms: Awesome

An open API service indexing awesome lists of open source software.

Awesome Lists | Featured Topics | Projects

https://github.com/rhysd/electron-in-page-search

Module to introduce Electron's native in-page search avoiding pitfalls
https://github.com/rhysd/electron-in-page-search

electron page search

Last synced: 3 days ago
JSON representation

Module to introduce Electron's native in-page search avoiding pitfalls

Awesome Lists containing this project

README

        

In-Page Search for Electron Applications
========================================
[![npm version](https://badge.fury.io/js/electron-in-page-search.svg)](https://www.npmjs.com/package/electron-in-page-search)
[![Build Status on Travis CI](https://travis-ci.org/rhysd/electron-in-page-search.svg?branch=master)](https://travis-ci.org/rhysd/electron-in-page-search)
[![Build Status on AppVeyor](https://ci.appveyor.com/api/projects/status/k80y8ccgpbt1ba57?svg=true)](https://ci.appveyor.com/project/rhysd/electron-in-page-search)

This package provides Chrome's native in-page search feature to Electron applications.
Electron exposes Chrome's native API to JavaScript. But native in-page search API has
some pitfalls and stateful. So this package wraps it and provide provide more easy,
pitfall-free APIs.

![screenshot](https://github.com/rhysd/ss/blob/master/electron-in-page-search/main.gif?raw=true)

In-page search can be used for browser window or webview (`BrowserWindow` instance or
`` tag) in Electron app. You can use only one function for both of them
in renderer process.

```javascript
// Pass current browser window's WebContents instance
const searchInWindow = searchInPage(remote.getCurrentWebContents());

// Pass instance
const searchInWebview = searchInPage(document.getElementById('my-webview'));

// Open inner window made with for in-page search

// Search some text in the browser window
searchInWindow.openSearchWindow();

// Search some text in the webview
searchInWebview.openSearchWindow();
```

This package works cross platform (macOS, Linux and Windows) with running CI on them
(Travis CI for macOS and Linux, AppVeyor for Windows).

## Installation

```
$ npm install --save electron-in-page-search
```

## Examples

Two examples are added. So please see the code of working app there.

- [Search in browser window](example/browser-window)
- [Search in ``](example/webview)

You can try them by cloning this repository.

```
$ git clone https://github.com/rhysd/electron-in-page-search.git
$ cd electron-in-page-search
$ npm install
$ npm run build
$ npm run example # Run browser window example
$ cd example/webview/
$ npm start # Run webview example
```

You can also see [the real world example](https://github.com/rhysd/Chromenu).

To know APIs for this package, you can see [TypeScript's type definitions](index.d.ts).

## Usage

When you want to use in-page search in app, call `searchInPage` function to create an `InPageSearch` instance.

```javascript
import searchInPage from 'electron-in-page-search';
// or
const searchInPage = require('electron-in-page-search').default;

import {remote} from 'electron';

const inPageSearch = searchInPage(remote.getCurrentWebContents());

document.getElementById('some-button').addEventListener('click', () => {
inPageSearch.openSearchWindow();
});
```

When calling `searchInPage`, it creates a `` element for search window.
This `` can avoid that in-page search finds the text in the search window.

The webview has a class property `electron-in-page-search-window search-inactive` by default.
Then `openSearchWindow` is called, the webview has a class property `electron-in-page-search-window search-active`
while searching. So you can styling the search window webview by CSS like below:

```css
.electron-in-page-search-window {
width: 300px;
height: 36px;
background-color: white;
}

.electron-in-page-search-window.search-inactive {
visibility: hidden;
}

.electron-in-page-search-window.search-active {
visibility: visible;
}
```

You can control background color of search window by adding `background-color`
(in above, `white` is specified). You can customize CSS further (please see below
'Customization' section).

Please see [example's style](example/browser-window/style.css) for live example.

The search window contains 'back' button, 'forward' button, 'close' button and query form.
Application users can input a query and click them (or press enter key in the form) to start
the in-page search.
Repeating to press enter key or clicking 'back'/'forward' buttons moves a focus on hit words.
Finally the users can close a search window by clicking 'close' button to stop the search.

After a search window closing, the window's class property will be `electron-in-page-search-window search-inactive`
again.

The search window `` is mounted to `document.body` (or an element specified with `searchWindowParent` option).
When you want to destroy `InPageSearch` instance, please ensure to call `.finalize()` method.
It will unmount the search window `` from DOM.

## Development

### Debugging

If you want to see a DevTools of search window, please pass `openDevToolsOfSearchWindow`
property to `searchInPage` function as below.

```javascript
searchInPage(webContents, { openDevToolsOfSearchWindow: true });
```

It opens the DevTools with detach mode.

And this package also supports logging. When `$ELECTRON_IN_PAGE_SEARCH_DEBUG` environment
variable is not empty, it outputs logs with `console.log` in rendrer process.

### TypeScript

This package is written in [TypeScript](https://github.com/Microsoft/TypeScript) and ready for TypeScript.
You need not to prepare type definition file for this package because [index.d.ts](index.d.ts) is
already in this package.

```typescript
import searchInPage, {InPageSearch} from 'electron-in-page-search';

let search: InPageSearch;
const elem = document.createElement('webview');
elem.src = 'https://example.com';

document.getElementById('main').appendChild(elem);
elem.on('dom-ready', () => {
search = searchInPage(elem);
});

document.getElementById('search-button').addEventListener('click', () => {
if (search) {
search.openSearchWindow();
}
});
```

### My Environment

I'm testing this package with below OS

- macOS 10.12, OS X 10.11.6
- Ubuntu Linux 16.04 LTS
- Windows 8.1

## Customization

### Use my own CSS for search window

If you want to use a default search window but don't want to use a default CSS,
you can use your own CSS file.

e.g.

```javascript
const path = require('path');

searchInPage(webview, {
customCssPath: path.join(__dirname, 'my_awesome_styles.css')
});
```

Below is a list of `class` property of each parts in search window.
Please write your CSS styles for below classes.

| class name | description | element |
|-------------------------|-----------------------------|-----------|
| `inpage-search-body` | Body of whole search window | `

` |
| `inpage-search-input` | Query form | `` |
| `inpage-search-matches` | 'N/M' search count | `
` |
| `inpage-search-back` | 'back' button | `
` |
| `inpage-search-forward` | 'forward' button | `
` |
| `inpage-search-close` | 'close' button | `
` |

### Use my own HTML for search window

If you want to control the whole search window, you can pass a path to your own HTML file.

```javascript
const path = require('path');

searchInPage(webview, {
customCssPath: path.join(__dirname, 'my_awesome_styles.css'),
customSearchWindowHtmlPath: path.join(__dirname, 'my_awesome_search_window.html')
});
```

electron-in-page-search package injects `` tag to setup IPC messaging between
a search window `<webview>` and a renderer process. It finds each elements and
sets listeners through class names.

So you need to maintain above class names also in your own search window HTML.

### Lifetime hooks for search

`InPageSearch` instance (returned from `searchInPage`) extends `EventEmitter`.
It emits some events on some timings.
You can hook them to execute your code at some points.

Below is a list of hook names.

| hook name | description | listener args |
|---------------|------------------------------------------|-------------------------------------------|
| 'open' | On window opened | `()` |
| 'start' | On in-page search started | `(query: string)` |
| 'next' | On finding next match | `(query: string, forward: boolean)` |
| 'focus-input' | On focusing on search window | `()` |
| 'found' | On some word matched to the search query | `(activeMatch: number, allMatch: number)` |

### Animation for search window

You can use CSS animation for animation of search window. If you don't want to animate a search window
when the webview is mounted, please use `search-firstpaint` class name as below:

```css
.electron-in-page-search-window.search-firstpaint {
visibility: hidden;
}

.electron-in-page-search-window.search-inactive {
animation-duration: 0.2s;
animation-name: yourAwesomeAnimationOnClosing;
}

.electron-in-page-search-window.search-active {
animation-duration: 0.2s;
animation-name: yourAwesomeAnimationOnOpening;
}
```

The `search-firstpaint` class will be removed when opening search window at first.

### Preload a search window

`InPageSearch` instance delays creating `<webview>` element for a search window
until first `openSearchWindow` is called at first.
This is better in terms of memory efficiency because `<webview>` forks a new process.

If you want to load a search window in advance, please set `preloadSearchWindow: true`
to the second argument of `searchInPage()` call.

## License

[Distributed under the MIT License](./LICENSE)