├── spellcheck16.png ├── spellcheck19.png ├── spellcheck48.png ├── spellcheck128.png ├── spellcheck19-active.png ├── README.md ├── manifest.json ├── inject.css ├── keycodes.js ├── background.js ├── content_script.js ├── options.html └── options.js /spellcheck16.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/kyleladd/spellCheckSelection/master/spellcheck16.png -------------------------------------------------------------------------------- /spellcheck19.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/kyleladd/spellCheckSelection/master/spellcheck19.png -------------------------------------------------------------------------------- /spellcheck48.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/kyleladd/spellCheckSelection/master/spellcheck48.png -------------------------------------------------------------------------------- /spellcheck128.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/kyleladd/spellCheckSelection/master/spellcheck128.png -------------------------------------------------------------------------------- /spellcheck19-active.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/kyleladd/spellCheckSelection/master/spellcheck19-active.png -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # Spell Check Selection 2 | Chrome extension that uses a keycode or browser action to trigger checking the selected text. 3 | -------------------------------------------------------------------------------- /manifest.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "Spell Check Selection", 3 | "version": "1.0.0", 4 | "description": "Spell checks the current selection.", 5 | "permissions": [ 6 | "", 7 | "tabs", 8 | "storage" 9 | ], 10 | 11 | "background": { 12 | "scripts": [ 13 | "keycodes.js", 14 | "background.js" 15 | ] 16 | }, 17 | 18 | "browser_action": { 19 | "default_icon": "spellcheck19.png", 20 | "default_title": "Spell Check Selection" 21 | }, 22 | 23 | "options_page": "options.html", 24 | 25 | "minimum_chrome_version": "14", 26 | 27 | "content_scripts": [ 28 | { 29 | "matches": [ 30 | "" 31 | ], 32 | "all_frames": true, 33 | "js": [ 34 | "keycodes.js", 35 | "content_script.js" 36 | ], 37 | "css": [ 38 | "inject.css" 39 | ] 40 | } 41 | ], 42 | 43 | "icons": { 44 | "16": "spellcheck16.png", 45 | "48": "spellcheck48.png", 46 | "128": "spellcheck128.png" 47 | }, 48 | 49 | "manifest_version": 2 50 | } 51 | -------------------------------------------------------------------------------- /inject.css: -------------------------------------------------------------------------------- 1 | /* The Modal (background) */ 2 | .cms__modal { 3 | /*display: none;*/ /* Hidden by default */ 4 | display: block; 5 | z-index: 100000; 6 | position: fixed; /* Stay in place */ 7 | /*z-index: 1;*/ /* Sit on top */ 8 | left: 0; 9 | top: 0; 10 | width: 100%; /* Full width */ 11 | height: 100%; /* Full height */ 12 | /*overflow: auto; */ 13 | overflow:hidden; 14 | /* Enable scroll if needed */ 15 | background-color: rgb(0,0,0); /* Fallback color */ 16 | background-color: rgba(0,0,0,0.4); /* Black w/ opacity */ 17 | } 18 | .cms__modal textarea{ 19 | font-size:16px; 20 | width:100%; 21 | height:100%; 22 | box-sizing: border-box; /* For IE and modern versions of Chrome */ 23 | -moz-box-sizing: border-box; /* For Firefox */ 24 | -webkit-box-sizing: border-box; /* For Safari */ 25 | } 26 | /* Modal Content/Box */ 27 | .cms__modal_content { 28 | background-color: #fefefe; 29 | margin: 15% auto; /* 15% from the top and centered */ 30 | padding: 20px; 31 | border: 1px solid #888; 32 | width: 80%; /* Could be more or less, depending on screen size */ 33 | height:50%; 34 | } 35 | 36 | /* The Close Button */ 37 | .cms__close { 38 | /*color: #aaa;*/ 39 | color:white; 40 | position:fixed; 41 | right:0; 42 | top:0; 43 | font-size: 28px; 44 | font-weight: bold; 45 | } 46 | 47 | .cms__close:hover, 48 | .cms__close:focus { 49 | color: black; 50 | text-decoration: none; 51 | cursor: pointer; 52 | } 53 | -------------------------------------------------------------------------------- /keycodes.js: -------------------------------------------------------------------------------- 1 | /** 2 | * Copyright (c) 2011 The Chromium Authors. All rights reserved. 3 | * Use of this source code is governed by a BSD-style license that can be 4 | * found in the LICENSE file. 5 | */ 6 | 7 | var KEY_MAP = { 8 | 12: 'Clear', 9 | 14: 'Enter', 10 | 33: 'PgUp', 11 | 34: 'PgDown', 12 | 35: 'End', 13 | 36: 'Home', 14 | 37: 'Left', 15 | 38: 'Up', 16 | 39: 'Right', 17 | 40: 'Down', 18 | 45: 'Insert', 19 | 46: 'Delete', 20 | 96: 'Numpad0', 21 | 97: 'Numpad1', 22 | 98: 'Numpad2', 23 | 99: 'Numpad3', 24 | 100: 'Numpad4', 25 | 101: 'Numpad5', 26 | 102: 'Numpad6', 27 | 103: 'Numpad7', 28 | 104: 'Numpad8', 29 | 105: 'Numpad9', 30 | 106: '*', 31 | 107: 'Plus', 32 | 108: '_', 33 | 109: '-', 34 | 111: '/', 35 | 112: 'F1', 36 | 113: 'F2', 37 | 114: 'F3', 38 | 115: 'F4', 39 | 116: 'F5', 40 | 117: 'F6', 41 | 118: 'F7', 42 | 119: 'F8', 43 | 120: 'F9', 44 | 121: 'F10', 45 | 122: 'F11', 46 | 123: 'F12', 47 | 124: 'F13', 48 | 125: 'F14', 49 | 126: 'F15', 50 | 186: ';', 51 | 187: '=', 52 | 188: ',', 53 | 189: '-', 54 | 190: '.', 55 | 191: '/', 56 | 192: '`', 57 | 219: '[', 58 | 221: ']' 59 | }; 60 | 61 | var isMac = (navigator.appVersion.indexOf("Mac") != -1); 62 | 63 | function keyEventToString(evt) { 64 | var tokens = []; 65 | if (evt.ctrlKey) { 66 | tokens.push('Control'); 67 | } 68 | if (evt.altKey) { 69 | tokens.push(isMac ? 'Option' : 'Alt'); 70 | } 71 | if (evt.metaKey) { 72 | tokens.push(isMac ? 'Command' : 'Meta'); 73 | } 74 | if (evt.shiftKey) { 75 | tokens.push('Shift'); 76 | } 77 | if (evt.keyCode >= 48 && evt.keyCode <= 90) { 78 | tokens.push(String.fromCharCode(evt.keyCode)); 79 | } else if (KEY_MAP[evt.keyCode]) { 80 | tokens.push(KEY_MAP[evt.keyCode]); 81 | } else { 82 | return ''; 83 | } 84 | return tokens.join('+'); 85 | } 86 | 87 | function getDefaultKeyString() { 88 | return keyEventToString({ 89 | keyCode: 83, // 's' 90 | shiftKey: true, 91 | altKey: true, 92 | ctrlKey: true, 93 | metaKey: false}); 94 | } 95 | -------------------------------------------------------------------------------- /background.js: -------------------------------------------------------------------------------- 1 | var checkAsType; 2 | var addToContextMenu; 3 | var hotKeyCombo; 4 | 5 | // Redirect to options.html on install 6 | chrome.runtime.onInstalled.addListener(function(details){ 7 | if(details.reason == "install"){ 8 | chrome.tabs.create({url: "options.html?newinstall=yes"}); 9 | }else if(details.reason == "update"){ 10 | var thisVersion = chrome.runtime.getManifest().version; 11 | console.log("Updated from " + details.previousVersion + " to " + thisVersion + "!"); 12 | } 13 | }); 14 | // Settings 15 | chrome.storage.sync.get(['checkAsType','addToContextMenu','hotKeyCombo'], function (obj) { 16 | checkAsType = obj.checkAsType; 17 | addToContextMenu = obj.addToContextMenu; 18 | hotKeyCombo = obj.hotKeyCombo; 19 | }); 20 | 21 | chrome.storage.onChanged.addListener(function(changes, namespace) { 22 | if(typeof changes.checkAsType !== "undefined"){ 23 | checkAsType = changes.checkAsType.newValue; 24 | } 25 | if(typeof changes.addToContextMenu !== "undefined"){ 26 | addToContextMenu = changes.addToContextMenu.newValue; 27 | } 28 | if(typeof changes.hotKeyCombo !== "undefined"){ 29 | hotKeyCombo = changes.hotKeyCombo.newValue; 30 | } 31 | }); 32 | 33 | function checkSpelling(inputString) { 34 | chrome.browserAction.setIcon({path: 'spellcheck19-active.png'}); 35 | // Send API request 36 | console.log("Initiate spell checking"); 37 | console.log("input string",inputString); 38 | //Callback 39 | setTimeout(function() { 40 | chrome.browserAction.setIcon({path: 'spellcheck19.png'}); 41 | }, 1050); 42 | } 43 | 44 | function initBackground() { 45 | console.log("background script initialted."); 46 | 47 | chrome.extension.onRequest.addListener( 48 | function(request, sender, sendResponse) { 49 | console.log("request",request); 50 | if (request['init']) { 51 | sendResponse({'key': hotKeyCombo}); 52 | } else if (request['inputString']) { 53 | checkSpelling(request['inputString']); 54 | } 55 | }); 56 | 57 | chrome.browserAction.onClicked.addListener( 58 | function(tab) { 59 | // Clicked the browser action button 60 | chrome.tabs.sendRequest( 61 | tab.id, 62 | {'spellcheckSelection': true}); 63 | }); 64 | } 65 | 66 | initBackground(); 67 | -------------------------------------------------------------------------------- /content_script.js: -------------------------------------------------------------------------------- 1 | var checkKeyStr; 2 | //Get the selected text and send request to background 3 | function spellcheckSelection() { 4 | console.log("spell check selection"); 5 | var focused = document.activeElement; 6 | console.log("focused", focused); 7 | var selectedText; 8 | if (focused) { 9 | try { 10 | selectedText = focused.value.substring( 11 | focused.selectionStart, focused.selectionEnd); 12 | } catch (err) { 13 | } 14 | } 15 | if (selectedText == undefined) { 16 | var sel = window.getSelection(); 17 | var selectedText = sel.toString(); 18 | } 19 | chrome.extension.sendRequest({'inputString': selectedText}); 20 | console.log("append the element"); 21 | var body = document.getElementsByTagName("body")[0]; 22 | var input = document.createElement("textarea"); 23 | // input.cols = "80"; 24 | // input.rows = "40"; 25 | var modal = document.createElement("div"); 26 | var modal_content_container = document.createElement("div"); 27 | var modal_close = document.createElement("div"); 28 | modal.classList.add("cms__modal"); 29 | modal_content_container.classList.add("cms__modal_content"); 30 | modal_close.classList.add("cms__close"); 31 | modal_close.innerHTML = "Close"; 32 | input.value = selectedText; 33 | body.appendChild(modal); //appendChild 34 | modal.appendChild(modal_content_container); 35 | modal.appendChild(modal_close); 36 | modal_content_container.appendChild(input); 37 | input.focus(); 38 | console.log("element appended"); 39 | // document.getElementsByClassName("cms__close").onclick = function() { 40 | document.getElementsByClassName("cms__close")[0].addEventListener("click", function(){ 41 | console.log("Clicked Close"); 42 | body.removeChild(modal); 43 | }); 44 | // console.log("Clicked Close"); 45 | // body.removeChild(modal); 46 | // } 47 | } 48 | 49 | function onExtensionMessage(request) { 50 | console.log("onmessage", request); 51 | if (request['spellcheckSelection'] != undefined) { 52 | if (!document.hasFocus()) { 53 | return; 54 | } 55 | spellcheckSelection(); 56 | } else if (request['key'] != undefined) { 57 | checkKeyStr = request['key']; 58 | } 59 | } 60 | 61 | function initContentScript() { 62 | chrome.extension.onRequest.addListener(onExtensionMessage); 63 | chrome.extension.sendRequest({'init': true}, onExtensionMessage); 64 | 65 | document.addEventListener('keydown', function(evt) { 66 | if (!document.hasFocus()) { 67 | return true; 68 | } 69 | // console.log("cmon"); 70 | 71 | var keyStr = keyEventToString(evt); 72 | if (keyStr == checkKeyStr && checkKeyStr.length > 0) { 73 | spellcheckSelection(); 74 | evt.stopPropagation(); 75 | evt.preventDefault(); 76 | return false; 77 | } 78 | return true; 79 | }, false); 80 | } 81 | initContentScript(); 82 | -------------------------------------------------------------------------------- /options.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | Spell Check Selection Options 4 | 79 | 80 | 81 | 82 | 83 | 84 | 85 | 91 |
New search engine preferences saved
92 |
93 |
94 |

When to check selection

95 |
    96 |
  1. 97 | Click on the 98 | Spell Check Selection 99 | button in the toolbar ↗ 100 |
  2. 101 |
  3. 102 | Use "Check Selection's Spelling" from within the context menu 103 |
  4. 104 |
  5. 105 | Check text as you type 106 |
  6. 107 |
  7. 108 | Use this hot key: 109 |
  8. 110 |
111 |
112 |
113 | 114 | 115 | 116 | -------------------------------------------------------------------------------- /options.js: -------------------------------------------------------------------------------- 1 | var checkbox_settings; 2 | var hotKeyElement; 3 | var checkboxSettingsCaller = function() { 4 | var id = this.id; 5 | var value; 6 | console.log(id); 7 | if(this.getAttribute("type")=="checkbox"){ 8 | if(this.checked){ 9 | value = true; 10 | } 11 | else{ 12 | value = false; 13 | } 14 | } 15 | console.log("saving options",this.id); 16 | console.log("saving options",this); 17 | console.log("saving options",value); 18 | save_options(this.id, this, value); 19 | }; 20 | function save_options(key, element, value){ 21 | var options = {}; 22 | options[key] = value; 23 | console.log("options",options); 24 | chrome.storage.sync.set(options, function() { 25 | restore_options(); 26 | }); 27 | } 28 | 29 | // Restores select box and checkbox state using the preferences 30 | // stored in chrome.storage. 31 | function restore_options() { 32 | console.log("restoring options"); 33 | chrome.storage.sync.get({ 34 | checkAsType: true, 35 | addToContextMenu: true, 36 | hotKeyCombo: getDefaultKeyString() 37 | }, function(items) { 38 | updateDisplay(items); 39 | }); 40 | } 41 | 42 | function updateDisplay(items){ 43 | console.log("updating display", items); 44 | updateCheckBoxes(items); 45 | hotKeyElement.value = items.hotKeyCombo; 46 | var status = document.getElementById('status'); 47 | addClass(status, 'updated'); 48 | status.textContent = 'Preferences saved.'; 49 | setTimeout(function() { 50 | status.textContent = ''; 51 | removeClass(status, 'updated'); 52 | }, 1050); 53 | } 54 | 55 | function updateCheckBoxes(items){ 56 | console.log("updating checkboxes", items); 57 | console.log("checkboxes", checkbox_settings); 58 | for (var i = 0; i < checkbox_settings.length; i++) { 59 | var id = checkbox_settings[i].getAttribute("id"); 60 | console.log(items); 61 | console.log(id); 62 | console.log(id in items); 63 | console.log(items[id]); 64 | if(id in items){ 65 | if(items[id]===true){ 66 | document.getElementById(id).checked = true; 67 | } 68 | else{ 69 | document.getElementById(id).checked = false; 70 | } 71 | } 72 | else if (id != null){ 73 | document.getElementById(id).checked = false; 74 | } 75 | } 76 | } 77 | function addClass(element, classNameToAdd) { 78 | element.classList.add(classNameToAdd); 79 | } 80 | 81 | function removeClass(element, classNameToRemove) { 82 | element.classList.remove(classNameToRemove); 83 | } 84 | 85 | function load() { 86 | checkbox_settings = document.getElementsByClassName('c_sp_s_cb_setting'); 87 | hotKeyElement = document.getElementById('hotKeyCombo'); 88 | restore_options(); 89 | // Add checkbox settings listeners 90 | for (i = 0; i < checkbox_settings.length; i++) { 91 | checkbox_settings[i].addEventListener('click', checkboxSettingsCaller, false); 92 | } 93 | 94 | hotKeyElement.addEventListener('keydown', function(evt) { 95 | switch (evt.keyCode) { 96 | case 27: // Escape 97 | evt.stopPropagation(); 98 | evt.preventDefault(); 99 | hotKeyElement.blur(); 100 | return false; 101 | case 8: // Backspace 102 | case 46: // Delete 103 | evt.stopPropagation(); 104 | evt.preventDefault(); 105 | hotKeyElement.value = ''; 106 | localStorage['checkKey'] = ''; 107 | // sendKeyToAllTabs(''); 108 | windocheckKeyeyStr = ''; 109 | return false; 110 | case 9: // Tab 111 | return false; 112 | case 16: // Shift 113 | case 17: // Control 114 | case 18: // Alt/Option 115 | case 91: // Meta/Command 116 | evt.stopPropagation(); 117 | evt.preventDefault(); 118 | return false; 119 | } 120 | var keyStr = keyEventToString(evt); 121 | if (keyStr) { 122 | hotKeyElement.value = keyStr; 123 | save_options(hotKeyElement.id, hotKeyElement, hotKeyElement.value); 124 | } 125 | evt.stopPropagation(); 126 | evt.preventDefault(); 127 | return false; 128 | }, true); 129 | } 130 | 131 | document.addEventListener('DOMContentLoaded', load); 132 | --------------------------------------------------------------------------------