diff --git a/CHANGELOG b/CHANGELOG new file mode 100644 index 0000000..f2580c4 --- /dev/null +++ b/CHANGELOG @@ -0,0 +1,10 @@ +1.1 2012-03-15 +--------------- +Load default settings if none exists. + + + + +1.0 2012-03-15 +--------------- +First public release. diff --git a/LICENSE b/LICENSE new file mode 100644 index 0000000..fd30595 --- /dev/null +++ b/LICENSE @@ -0,0 +1,23 @@ +Copyright (c) 2012, Ching Chow +All rights reserved. + +Redistribution and use in source and binary forms, with or without modification, +are permitted provided that the following conditions are met: + + * Redistributions of source code must retain the above copyright notice, + this list of conditions and the following disclaimer. + + * Redistributions in binary form must reproduce the above copyright notice, + this list of conditions and the following disclaimer in the documentation + and/or other materials provided with the distribution. + +THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND +ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED +WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE +DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR +ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES +(INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; +LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON +ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT +(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS +SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. diff --git a/README b/README new file mode 100644 index 0000000..3f9bf13 --- /dev/null +++ b/README @@ -0,0 +1,10 @@ +Lookup Assistant is an extension for the Google Chrome web browser that enables +a user to perform search and other operations on highlighted text via the +right-click menu. An options page allows customization of the menu to perform +nearly any type of lookup operation for almost any website the user desires. +Custom settings are saved using HTML5 local storage. + +* Simple and unobtrusive user interface. +* User customizable menus. + +Available for free in the Chrome Web Store. diff --git a/background.html b/background.html new file mode 100644 index 0000000..94be966 --- /dev/null +++ b/background.html @@ -0,0 +1,43 @@ + + + + + + + Lookup Assistant + + + + + + + + diff --git a/chrome.png b/chrome.png new file mode 100644 index 0000000..3ae2d44 Binary files /dev/null and b/chrome.png differ diff --git a/html5.png b/html5.png new file mode 100644 index 0000000..4e869d7 Binary files /dev/null and b/html5.png differ diff --git a/javascript.png b/javascript.png new file mode 100644 index 0000000..7b5ffab Binary files /dev/null and b/javascript.png differ diff --git a/json.gif b/json.gif new file mode 100644 index 0000000..3bb55c8 Binary files /dev/null and b/json.gif differ diff --git a/manifest.json b/manifest.json new file mode 100644 index 0000000..f079f17 --- /dev/null +++ b/manifest.json @@ -0,0 +1,15 @@ +{ + "name": "Lookup Assistant", + "version": "1.1", + + "description": "Lookup highlighted text.", + "icons": { + "16": "monocle_16.png", + "48": "monocle_48.png", + "128": "monocle_128.png" + }, + + "background_page": "background.html", + "options_page": "options.html", + "permissions": ["contextMenus", "tabs"] +} diff --git a/monocle_128.png b/monocle_128.png new file mode 100644 index 0000000..1c94c3d Binary files /dev/null and b/monocle_128.png differ diff --git a/monocle_16.png b/monocle_16.png new file mode 100644 index 0000000..3610c88 Binary files /dev/null and b/monocle_16.png differ diff --git a/monocle_48.png b/monocle_48.png new file mode 100644 index 0000000..e958c0b Binary files /dev/null and b/monocle_48.png differ diff --git a/monocle_promo.png b/monocle_promo.png new file mode 100644 index 0000000..8b4f745 Binary files /dev/null and b/monocle_promo.png differ diff --git a/options.html b/options.html new file mode 100644 index 0000000..5323936 --- /dev/null +++ b/options.html @@ -0,0 +1,282 @@ + + + + + + + Lookup Assistant Menu Editor + + + + +

Lookup Assistant Menu Editor

+ + +
+ + + +             + +

 

+ + + +
+ +

Help

+ +

I. Buttons

+ +
    +
  1. Save: Save settings into local storage.
     
  2. + +
  3. Load: Retrieve settings from local storage.
     
  4. + +
  5. Exec: Execute the current settings shown in the text area without saving.
     
  6. + +
  7. Wipe: Delete settings from local storage. Once deleted, an opportunity will be given to + restore the default settings.
     
  8. +
+ +

II. Editing

+ +
    +
  1. Syntax: Lookup Assistant requires specific formatting for each of its entries. + This is done using standard JSON.
     
  2. + +
  3. Overview: Whitespace (spaces, tabs, and newlines) doesn't matter, and can be + used to make things clearer and more readable. Lookup Assistant has three types: link, + menu, and separator. A menu can contain any of the three types. These must all be + contained within a pair of brackets. With the exception of a key's value, everything + should be typed in lowercase. Key-value pairs are explained below. +

    + High-level View of Menu Formatting: +
    +[
    +    link,
    +    separator,
    +    menu
    +        link,
    +        link
    +]
    +
    + Format and details of each type are explained below.
     
  4. + +
  5. Link: This is the most common type. A link tells Lookup Assistant + where it should go and how it should get there. It's written in this format: +
    +{
    +    "type": "link",
    +    "open": "tab",
    +    "title": "Google",
    +    "address": "http://www.google.com/search?q=%s"
    +}
    +
    + The opening and closing brace are required. Each item must be quoted, each key (the item + to the left of the colon) and its value (the item to the right) must be separated by a + colon, and a comma separates each key-value pair. An explanation of each key follows. +

    + "type": This specifies the type. It can be "link", "menu", or "separator". You would, + of course, use "link" for links. However, this key is optional. The default behavior + is "link" if it's omitted. +

    + "open": This determines how Lookup Assistant behaves when one of its links is clicked. + It can be one of three values: "tab", "window", or "incognito". This key is optional. + The default type is "tab" if it's omitted. +

    + "title": The name for this link. +

    + "address": The URL with a search token (%s). The search token will ultimately be replaced + by the highlighted text. To find out where the search token goes in a URL, go to a website + and perform a search to see what the URL looks like. Copy the URL and replace the search + term with the token. Some sites have very long and complex search URLs and may require + some effort.
     
  6. + +
  7. Menu: This type is used for grouping and organization. A menu can contain any + type, even itself. It looks like this: +
    +{
    +    "type": "menu",
    +    "title": "Additional Links",
    +    "entry": []
    +}
    +
    + Regarding braces, quotes, and commas, the same rules apply here as they did with the link + type. The "type" and "title" keys also work the same way as they did for links, except + "type" is not optional here. +

    + The new key is "entry", and the value is a pair of brackets. What's place between them + will determine what appears in this menu. Links, separators, and even additional menus + are all valid. See the link and separator section for proper formatting.
     
  8. + +
  9. Separator: The simplest type. A separator only has a single key-value pair. + Like menus, specifying the type is required. It looks like this: +
    +{
    +    "type": "separator"
    +}
    +
    + Separators will not appear if there is nothing to separate.
     
  10. +
+ +

III. Examples

+ +
    +
  1. One Link: +
    +[
    +    { "type": "link", "open": "tab", "title": "Google", "address": "http://www.google.com/search?q=%s" }
    +]
    +
  2. + +
  3. Three Links + Separator: +
    +[
    +    { "title": "Google", "address": "http://www.google.com/search?q=%s" },
    +    { "title": "Google Images", "address": "http://www.google.com/search?tbm=isch&q=%s" },
    +    { "type": "separator" },
    +    { "title": "Wikipedia", "address": "http://www.wikipedia.org/wiki/%s" }
    +]
    +
    + You can see in this example that commas not only separate pairs, but they separate the + types as well.
     
  4. + +
  5. Two Links + Separator + Menu with Two Links: +
    +[
    +    { "title": "Google", "address": "http://www.google.com/search?q=%s" },
    +    { "title": "Google Images", "address": "http://www.google.com/search?tbm=isch&q=%s" },
    +    { "type": "separator" },
    +    { "type": "menu", "title": "Menu 1", "entry":
    +        [
    +            { "title": "Amazon", "address": "http://www.amazon.com/s/field-keywords=%s" },
    +            { "title": "eBay", "address": "http://www.ebay.com/sch/i.html?_nkw=%s" }
    +        ]
    +    }
    +]
    +
  6. + +
  7. One Link + Menu with a Menu, Each with One Link: +
    +[
    +    { "type": "menu", "title": "Menu 1", "entry":
    +        [
    +            { "type": "menu", "title": "Menu 2", "entry":
    +                [
    +                    { "title": "Amazon", "address": "http://www.amazon.com/s/field-keywords=%s" }
    +                ]
    +            },
    +            { "title": "Wikipedia", "address": "http://www.wikipedia.org/wiki/%s" }
    +        ]
    +    },
    +    { "title": "Google", "address": "http://www.google.com/search?q=%s" }
    +]
    +
    + Having many nested menus can get quite confusing!
     
  8. +
+ +

IV. Errors

+ +
    +
  1. SyntaxError: This error means there's something wrong with the JSON formatting. + Here are two common syntax errors and what they mean: +

    + + Checklist: + +
    + A good way to avoid these errors is to make small incremental changes and test them with + the exec button. Try not to make large changes all at once because it'll be hard to + pinpoint the source of the error.
     
  2. + +
  3. Missing Property: This error means something was left out. e.g. Failure to + provide an address for the link type.
     
  4. + +
  5. Unknown Type: This error means something other than link, menu, or separator + was specified as the type. Spelling errors will cause this error, as will improper + casing. i.e. link is not the same as Link.
     
  6. +
+ +

V. Contact

+ +
    +
  1. Website: smwst.tumblr.com
     
  2. +
+ +
+ +
+Copyright (c) 2012, smwst
+All rights reserved.
+
+Redistribution and use in source and binary forms, with or without modification,
+are permitted provided that the following conditions are met:
+
+    * Redistributions of source code must retain the above copyright notice,
+      this list of conditions and the following disclaimer.
+
+    * Redistributions in binary form must reproduce the above copyright notice,
+      this list of conditions and the following disclaimer in the documentation
+      and/or other materials provided with the distribution.
+
+THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
+ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
+WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
+DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR
+ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
+(INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
+LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON
+ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
+SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+
+ +
+ +
+ + +   + +     + + + + diff --git a/screenshot_01.png b/screenshot_01.png new file mode 100644 index 0000000..7cfc16e Binary files /dev/null and b/screenshot_01.png differ diff --git a/screenshot_02.png b/screenshot_02.png new file mode 100644 index 0000000..d825178 Binary files /dev/null and b/screenshot_02.png differ diff --git a/screenshot_03.png b/screenshot_03.png new file mode 100644 index 0000000..7f813df Binary files /dev/null and b/screenshot_03.png differ diff --git a/scripts.js b/scripts.js new file mode 100644 index 0000000..57593c6 --- /dev/null +++ b/scripts.js @@ -0,0 +1,300 @@ +// global abatement +var LUA = {}; + +// this array contains an object for each menu entry +// links have three properties: address, id, and title +// menus have two properties: id and title +// separators are not included +LUA.entry = []; + +// lookup the address of a given entry id, and replace the search token +LUA.entry.getAddress = function (id, highlightedText) { + "use strict"; + var i, + currency = /^(\d{1,3}(\,\d{3})*|\d+)(\.\d{1,2})?$/, + stripped = highlightedText.trim(); + if (currency.test(stripped)) { + stripped = stripped.replace(/[,]/g, ""); + } + for (i = 0; i < LUA.entry.length; i += 1) { + if (LUA.entry[i].id === id) { + return LUA.entry[i].address.replace("%s", stripped); + } + } +}; + +// lookup the id of a given entry title +LUA.entry.getId = function (title) { + "use strict"; + var i; + for (i = 0; i < LUA.entry.length; i += 1) { + if (LUA.entry[i].title === title) { + return LUA.entry[i].id; + } + } +}; + +// create various menu items +LUA.create = { + link: function (address, open, title, parent) { + "use strict"; + LUA.entry.push({ + address: address, + id: chrome.contextMenus.create({ + contexts: ["selection"], + onclick: (open === "window") ? LUA.open.window : + (open === "incognito") ? LUA.open.incognito : LUA.open.tab, + parentId: LUA.entry.getId(parent), + title: title + }), + title: title + }); + }, + menu: function (title, parent) { + "use strict"; + LUA.entry.push({ + id: chrome.contextMenus.create({ + contexts: ["selection"], + parentId: LUA.entry.getId(parent), + title: title + }), + title: title + }); + }, + separator: function (parent) { + "use strict"; + chrome.contextMenus.create({ + contexts: ["selection"], + parentId: LUA.entry.getId(parent), + type: "separator" + }); + } +}; + +// perform the lookup +LUA.open = { + tab: function (info, tab) { + "use strict"; + chrome.tabs.create({ + url: LUA.entry.getAddress(info.menuItemId, info.selectionText) + }); + }, + window: function (info, tab) { + "use strict"; + chrome.windows.create({ + url: LUA.entry.getAddress(info.menuItemId, info.selectionText) + }); + }, + incognito: function (info, tab) { + "use strict"; + chrome.windows.create({ + url: LUA.entry.getAddress(info.menuItemId, info.selectionText), + incognito: true + }); + } +}; + +// these buttons are for options.html and they manage local storage +LUA.button = { + save: function () { + "use strict"; + document.getElementById("status").innerHTML = " "; + if (confirm("Save current settings?")) { + LUA.settings.current = document.getElementById("editor").value; + localStorage.setItem("LUA_Settings", LUA.settings.current); + document.getElementById("status").innerHTML = "Settings saved."; + } + }, + load: function () { + "use strict"; + document.getElementById("status").innerHTML = " "; + if (confirm("Load saved settings?")) { + LUA.settings.current = localStorage.getItem("LUA_Settings"); + document.getElementById("editor").value = LUA.settings.current; + document.getElementById("status").innerHTML = "Settings restored."; + } + }, + exec: function () { + "use strict"; + document.getElementById("status").innerHTML = " "; + LUA.settings.clearMenu(); + LUA.settings.current = document.getElementById("editor").value; + if (LUA.settings.current.trim()) { // do not parse if there is no input + chrome.extension.sendRequest( + { + data: LUA.settings.current + }, + function (error) { + if (error.name) { + document.getElementById("status").innerHTML = "" + + error.name + ": " + error.message + + (error.code ? "

Near Location: " + error.code : ""); + } else { + document.getElementById("status").innerHTML = "No errors."; + } + } + ); + } + }, + wipe: function () { + "use strict"; + document.getElementById("status").innerHTML = " "; + if (confirm("Delete saved settings?")) { + LUA.settings.clearMenu(); + LUA.settings.current = ""; + localStorage.removeItem("LUA_Settings"); + document.getElementById("status").innerHTML = "Saved settings wiped!"; + if (confirm("Restore default settings?")) { + LUA.settings.current = LUA.settings.defaultSettings(); + document.getElementById("editor").value = LUA.settings.current; + document.getElementById("status").innerHTML = "Default settings restored."; + } + } + } +}; + +// settings management +LUA.settings = { + current: "", + clearMenu: function () { + "use strict"; + chrome.contextMenus.removeAll(); + LUA.entry.length = 0; + }, + parse: function (data, parent) { + "use strict"; + var i; + for (i = 0; i < data.length; i += 1) { + switch (data[i].type) { + case undefined: // fall through + case "link": + if (!data[i].title) { + throw { + name: "Missing Property", + message: "Title required for links.", + code: JSON.stringify(data[i]) + }; + } + if (!data[i].address) { + throw { + name: "Missing Property", + message: "Address required for links.", + code: JSON.stringify(data[i]) + }; + } + LUA.create.link(data[i].address, data[i].open, data[i].title, parent); + break; + case "menu": + if (!data[i].title) { + throw { + name: "Missing Property", + message: "Title required for menus.", + code: JSON.stringify(data[i]) + }; + } + if (!data[i].entry) { + throw { + name: "Missing Property", + message: "Entry required for menus.", + code: JSON.stringify(data[i]) + }; + } + LUA.create.menu(data[i].title, parent); + LUA.settings.parse(data[i].entry, data[i].title); + break; + case "separator": + LUA.create.separator(parent); + break; + default: + throw { + name: "Unknown Type", + message: "Valid types are link, menu, and separator.", + code: JSON.stringify(data[i]) + }; + } + } + }, + defaultSettings: function () { + "use strict"; + var settings = + "[ \n" + + " { \"title\": \"Google\", \"address\": \"http://www.google.com/search?q=%s\" }, \n" + + " { \"title\": \"Google Images\", \"address\": \"http://www.google.com/search?tbm=isch&q=%s\" }, \n" + + " \n" + + " { \"type\": \"menu\", \"title\": \"More Searches\", \"entry\": \n" + + " [ \n" + + " { \"title\": \"Bing\", \"address\": \"http://www.bing.com/search?q=%s\" }, \n" + + " { \"title\": \"Yahoo!\", \"address\": \"http://search.yahoo.com/search?p=%s\" } \n" + + " ] \n" + + " }, \n" + + " \n" + + " { \"type\": \"separator\" }, \n" + + " \n" + + " { \"title\": \"Dictionary.com\", \"address\": \"http://dictionary.reference.com/browse/%s\" }, \n" + + " { \"title\": \"Thesaurus.com\", \"address\": \"http://thesaurus.com/browse/%s\" }, \n" + + " { \"title\": \"Urban Dictionary\", \"address\": \"http://www.urbandictionary.com/define.php?term=%s\" }, \n" + + " { \"title\": \"Wikipedia\", \"address\": \"http://www.wikipedia.org/wiki/%s\" }, \n" + + " \n" + + " { \"type\": \"separator\" }, \n" + + " \n" + + " { \"title\": \"Amazon\", \"address\": \"http://www.amazon.com/s/field-keywords=%s\" }, \n" + + " { \"title\": \"eBay\", \"address\": \"http://www.ebay.com/sch/i.html?_nkw=%s\" }, \n" + + " \n" + + " { \"type\": \"separator\" }, \n" + + " \n" + + " { \"title\": \"YouTube\", \"address\": \"http://www.youtube.com/results?search_query=%s\" }, \n" + + " { \"title\": \"YouTube (VideoID)\", \"address\": \"http://www.youtube.com/watch?v=%s\" }, \n" + + " { \"title\": \"EndlessVideo (VideoID)\", \"address\": \"http://www.endlessvideo.com/watch?v=%s\" }, \n" + + " \n" + + " { \"type\": \"separator\" }, \n" + + " \n" + + " { \"type\": \"menu\", \"title\": \"To English\", \"entry\": \n" + + " [ \n" + + " { \"title\": \"Chinese\", \"address\": \"http://translate.google.com/#zh-CN|en|%s\" }, \n" + + " { \"title\": \"Japanese\", \"address\": \"http://translate.google.com/#ja|en|%s\" }, \n" + + " { \"title\": \"Korean\", \"address\": \"http://translate.google.com/#ko|en|%s\" } \n" + + " ] \n" + + " }, \n" + + " { \"type\": \"menu\", \"title\": \"From English\", \"entry\": \n" + + " [ \n" + + " { \"title\": \"Chinese (Simplified)\", \"address\": \"http://translate.google.com/#en|zh-CN|%s\" }, \n" + + " { \"title\": \"Chinese (Traditional)\", \"address\": \"http://translate.google.com/#en|zh-TW|%s\" }, \n" + + " { \"title\": \"Japanese\", \"address\": \"http://translate.google.com/#en|ja|%s\" }, \n" + + " { \"title\": \"Korean\", \"address\": \"http://translate.google.com/#en|ko|%s\" } \n" + + " ] \n" + + " }, \n" + + " \n" + + " { \"type\": \"separator\" }, \n" + + " \n" + + " { \"type\": \"menu\", \"title\": \"To USD\", \"entry\": \n" + + " [ \n" + + " { \"title\": \"CAD: Canadian Dollar\", \"address\": \"http://www.google.com/finance/converter?a=%s&from=CAD&to=USD\" },\n" + + " { \"title\": \"CNY: Chinese Yuan\", \"address\": \"http://www.google.com/finance/converter?a=%s&from=CNY&to=USD\" },\n" + + " { \"title\": \"GBP: British Pound Sterling\", \"address\": \"http://www.google.com/finance/converter?a=%s&from=GBP&to=USD\" },\n" + + " { \"title\": \"EUR: Euro\", \"address\": \"http://www.google.com/finance/converter?a=%s&from=EUR&to=USD\" },\n" + + " { \"title\": \"JPY: Japanese Yen\", \"address\": \"http://www.google.com/finance/converter?a=%s&from=JPY&to=USD\" },\n" + + " { \"title\": \"KRW: South Korean Won\", \"address\": \"http://www.google.com/finance/converter?a=%s&from=KRW&to=USD\" } \n" + + " ] \n" + + " }, \n" + + " { \"type\": \"menu\", \"title\": \"From USD\", \"entry\": \n" + + " [ \n" + + " { \"title\": \"CAD: Canadian Dollar\", \"address\": \"http://www.google.com/finance/converter?a=%s&from=USD&to=CAD\" },\n" + + " { \"title\": \"CNY: Chinese Yuan\", \"address\": \"http://www.google.com/finance/converter?a=%s&from=USD&to=CNY\" },\n" + + " { \"title\": \"GBP: British Pound Sterling\", \"address\": \"http://www.google.com/finance/converter?a=%s&from=USD&to=GBP\" },\n" + + " { \"title\": \"EUR: Euro\", \"address\": \"http://www.google.com/finance/converter?a=%s&from=USD&to=EUR\" },\n" + + " { \"title\": \"JPY: Japanese Yen\", \"address\": \"http://www.google.com/finance/converter?a=%s&from=USD&to=JPY\" },\n" + + " { \"title\": \"KRW: South Korean Won\", \"address\": \"http://www.google.com/finance/converter?a=%s&from=USD&to=KRW\" } \n" + + " ] \n" + + " }, \n" + + " \n" + + " { \"type\": \"separator\" }, \n" + + " \n" + + " { \"type\": \"menu\", \"title\": \"Schemes\", \"entry\": \n" + + " [ \n" + + " { \"title\": \"mailto\", \"address\": \"mailto:%s\" } \n" + + " ] \n" + + " } \n" + + "] \n"; + return settings.replace(/ +\n/g, "\n"); + } +};