Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Add support for spell checking #942

Merged
merged 9 commits into from
Dec 20, 2014
Merged

Add support for spell checking #942

merged 9 commits into from
Dec 20, 2014

Conversation

zcbenz
Copy link
Contributor

@zcbenz zcbenz commented Dec 20, 2014

This PR adds an webFrame.setSpellCheckProvider API to set a provider for spell checking in input fields and text areas.

Example:

require('web-frame').setSpellCheckProvider("en-US", true, {
  spellCheck: function(text) {
    return !(require('spellchecker').isMisspelled(text));
  }
});

screen shot 2014-12-19 at 10 33 14 pm

Fixes #724.

zcbenz added a commit that referenced this pull request Dec 20, 2014
Add support for spell checking
@zcbenz zcbenz merged commit c0bf2fa into master Dec 20, 2014
@zcbenz zcbenz deleted the spell-check-client branch December 20, 2014 22:25
@drikin
Copy link

drikin commented Dec 24, 2014

Is it also possible to enable spellcheck inside webview tag content?

@zcbenz
Copy link
Contributor Author

zcbenz commented Dec 24, 2014

Is it also possible to enable spellcheck inside webview tag content?

You can enable it in the preload script of <webview>.

@drikin
Copy link

drikin commented Dec 27, 2014

Thanks @zcbenz
It worked well even if I was still struggling to do spell check itself. :-p

@francoisMinette
Copy link

Hi @zcbenz and @drikin

I don't manage to get this spellchecker working, even after reading the documentation about it and trying to understand what is a provider. Maybe one of you can explain with the simple example below. Also, I precise that am new to electron.

For the example I am simply using https://github.com/atom/electron/blob/master/docs/tutorial/quick-start.md with an input element in index.html file.
Thing is, I don't understand where to insert this code https://github.com/atom/electron/blob/master/docs/api/web-frame.md#webframesetspellcheckproviderlanguage-autocorrectword-provider

If I add it to main.js then when I try to run this electron app I will have : Error: Cannot find module 'web-frame'
But when I try to npm install it, it states that there is no such module.

Beside this, on the renderer, do I have to make a call of this spellCheck function and changed the result accordingly to the returned value ?

As you can see, I obviously lack of knowledge about electron and web application coding.
By any chance, someone could lead me to more documentation about what is a provider / how it is supposed to be used in such case please ?

EDIT :

I was actually using this code well, since if I log the text in the console it output the text as it should. Problem is this line return !(require('spellchecker').isMisspelled(text)); which deals with spellchecker module crashes the total application with this message : "inspected target disconnected. Once it reloads we will attach to it automatically."

I am running it on ubuntu 14.04 and I have hanspell installed.

@aggregatejeff
Copy link

Looking through the code I don't see any way to pass back alternate spellings like so to populate a context menu. Am I missing something, or has that not been enabled?

screen shot 2015-08-30 at 5 32 51 pm

@anaisbetts
Copy link
Contributor

@aggregatejeff You have to do it yourself via the Context Menu API :(

@aggregatejeff
Copy link

Thanks @paulcbetts! At least a) I'll stop banging my head against a wall, and b) a work-around is possible.

@NathanHazout
Copy link

@francoisMinette how did you solve the Error: Cannot find module 'web-frame'?

@francoisMinette
Copy link

Hi, I did not solve it. I was learning about electron at the time, but I
had to change technology for some reason so I did not continue further.
Hope you will solve it.
Le 21 déc. 2015 10:05 AM, "Nathan Hazout" notifications@github.com a
écrit :

@francoisMinette https://github.com/francoisMinette how did you solve
the Error: Cannot find module 'web-frame'?


Reply to this email directly or view it on GitHub
#942 (comment).

@aggregatejeff
Copy link

@paulcbetts I finally got around to working on this, and have made some progress. I can get spellchecker to check a word, return suggestions, and populate the context menu with those suggestions. But I'm stumped on how to pass back to spellchecker the word that was clicked on, and then how to tell the webview what to replace.

The latter seems like it can be solved through .replace(text), but getting the word clicked upon doesn't seem very simple. Do you know if there's a way to do this through electron, or do I need to write some custom javascript?

I'm happy to share my results when it works, and any help would be greatly appreciated.

@aggregatejeff
Copy link

So... I build this. It took some digging, but here's what I found:

  1. spellCheck: function(text) is called with context when an item is clicked on, so there's no need to look through the whole dom for the item
  2. it's called a lot, basically whenever anyone does anything with text in rendered window

I combined the scripts for spellchecking and context menu building into one file for ease of use:

checker = require('spellchecker');
var remote = require('remote');
var webContents = remote.getCurrentWebContents();
var Menu = remote.require('menu');
var menu = new Menu();

// set the initial context menu so that a context menu exists even before spellcheck is called
var template = [
  {
    label: 'Select All',
    selector: 'selectAll:'
  }
];
menu = Menu.buildFromTemplate(template);

webFrame.setSpellCheckProvider("en-US", false, {
  spellCheck: function(text) {
  // if spellcheck is being called, we're dealing with text, so add text functions to the context menu template
    template.unshift(
          {
            label: 'Undo',
            selector: 'undo:'
          },
          {
            label: 'Redo',
            selector: 'redo:'
          },
          {
            type: 'separator'
          },
          {
            label: 'Cut',
            selector: 'cut:'
          },
          {
            label: 'Copy',
            selector: 'copy:'
          },
          {
            label: 'Paste',
            selector: 'paste:'
          }
    );

switch (text) {
      //prevent checker from showing contractions as errors
      case 'ain':
      case 'couldn':
      case 'didn':
      case 'doesn':
      case 'hadn':
      case 'hasn':
      case 'mightn':
      case 'mustn':
      case 'needn':
      case 'oughtn':
      case 'shan':
      case 'shouldn':
      case 'wasn':
      case 'weren':
      case 'wouldn':  
        return checker.isMisspelled(text);
      default:
        if (checker.isMisspelled(text)) {          
          //if this is a misspelling, get suggestions
          var options = checker.getCorrectionsForMisspelling(text);
          // get the number of suggestions if any
          var numSuggestions = options.length ? options.length : 0;
          // restrict it to 3 suggestions
          var maxItems = numSuggestions > 3 ? 3 : numSuggestions;
          var lastSuggestion = null;
          // if there are suggestions
          if (maxItems > 0) {
            for (var i = maxItems-1; i >= 0; i--) {
              var item = options[i];
              template.unshift({ label: item, click: function(menuItem, browserWindow) 
                {
                    webContents.replaceMisspelling(menuItem.label);
                } 
              });
            }
            lastSuggestion = maxItems;
            template.splice(lastSuggestion,0,{type: 'separator'});
          } else {
            // no suggestions found
            template.unshift({ label: 'no suggestions', click: function() { } })
            lastSuggestion = maxItems + 1;
            template.splice(lastSuggestion,0,{type: 'separator'});
          }
        }
        // build the new template for the context menu
        menu = Menu.buildFromTemplate(template);
        //reset the template object
          template = [
          {
            label: 'Select All',
            selector: 'selectAll:'
          }
        ];

        return !checker.isMisspelled(text);
    }
  }
});

// on right click.....
window.addEventListener('contextmenu', function(e){
  // use current menu, probably the one that was built the last time spellcheck ran
  menu.popup(remote.getCurrentWindow());
  // build a new one with only select all in it
  menu = Menu.buildFromTemplate(template);  
}, false);

@crimsoncor
Copy link

@aggregatejeff So I've got the set-up that you've outlined here working, but I've noticed an issue and I was wondering if you (or someone else) had come up with a workaround.

When the spellcheck function runs, it builds out the menu. If you then right-click somewhere in the text area that is whitespace, it still shows the menu with the list of misspelled words, but selecting one won't trigger the replacement (since you did not click on top of the misspelled word). Conversely, if you right-click on a misspelled word twice, the replacement menu will be empty the second time. This all has to do with the mismatch between when the spell-checker runs and when the pop-up menu is shown. I'm not enough of a javascript expert to figure out how to reconcile those two states. Ideally it seems like you would want to query if there is currently a misspelled word under the mouse when creating the pop-up menu and build the context menu if there is.

@ccnokes
Copy link
Contributor

ccnokes commented Feb 24, 2016

For people brought here by google or elsewhere and looking for a simple solution to this, electron-editor-context-menu fixes the bugs pointed out by @crimsoncor and is based on the gist provided by @aggregatejeff . It's been working for me thus far.

@crimsoncor
Copy link

I fixed this issue by figuring out how to get the currently highlighted word on a right-click event and then generating the spell-check menu directly in the eventListener function. Meant to come back and add a note on that and it just slipped my mind. But it has been working great.

@aggregatejeff
Copy link

And my apologies for not noticing the question, but as suggested, I continued to iterate and improved the above using getSelection(), and a few other tweaks.

@adam-lynch
Copy link
Contributor

Is there any plans to improve the context menu stuff? Would be nice if we didn't have to implement that ourselves.

@noahbenham
Copy link

It's very surprising this hasn't been implemented already. Any updates on native spell checking functionality without manually implementing context menu behavior?

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

Successfully merging this pull request may close these issues.

Native spell check in input fields
10 participants