rhysd / electron-in-page-search

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

Geek Repo:Geek Repo

Github PK Tool:Github PK Tool

In-Page Search for Electron Applications

npm version Build Status on Travis CI Build Status on AppVeyor

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

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

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

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

// Open inner window made with <webview> 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.

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.

To know APIs for this package, you can see TypeScript's type definitions.

Usage

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

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 <webview> element for search window. This <webview> 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:

.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 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 <webview> 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 <webview> from DOM.

Development

Debugging

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

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 and ready for TypeScript. You need not to prepare type definition file for this package because index.d.ts is already in this package.

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.

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 <div>
inpage-search-input Query form <input>
inpage-search-matches 'N/M' search count <div>
inpage-search-back 'back' button <div>
inpage-search-forward 'forward' button <div>
inpage-search-close 'close' button <div>

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.

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 <script> 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:

.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

About

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

License:MIT License


Languages

Language:TypeScript 57.3%Language:HTML 31.5%Language:JavaScript 5.3%Language:CSS 5.0%Language:Ruby 0.9%