Skip to content

Commit

Permalink
add goshen chrome extension
Browse files Browse the repository at this point in the history
  • Loading branch information
j6k4m8 committed Sep 11, 2016
1 parent f39252d commit c237b13
Show file tree
Hide file tree
Showing 11 changed files with 431 additions and 0 deletions.
Binary file added contrib/goshen-chrome/icon.png
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
29 changes: 29 additions & 0 deletions contrib/goshen-chrome/manifest.json
@@ -0,0 +1,29 @@
{
"manifest_version": 2,

"name": "Goshen Web Translator",
"description": "Translate entire webpages with a casmacat-moses backend",
"version": "1.0",

"browser_action": {
"default_icon": "icon.png",
"default_popup": "popup/popup.html"
},
"permissions": [
"activeTab",
"storage",
"https://ajax.googleapis.com/"
],
"options_page" : "options/index.html",

"content_scripts": [{
"matches": ["http://*/*", "https://*/*", "file:///*"],
"css": ["onpage/onpage.css"],
"js": [
"onpage/onpage.js",
"onpage/goshen.js",
"onpage/chromegoshen.js"
],
"all_frames": true
}]
}
166 changes: 166 additions & 0 deletions contrib/goshen-chrome/onpage/chromegoshen.js
@@ -0,0 +1,166 @@
(function(window) {

var demo_url = "ec2-52-23-242-15.compute-1.amazonaws.com:8081";

var _goshen = window._goshen;

on = function(event, cb) {
window.addEventListener(event, cb);
}

off = function(event, cb) {
window.removeEventListener(event, cb);
}

class ChromeGoshen {
constructor() {
this.G = new _goshen.Goshen(demo_url);
console.info("Goshenjs engine loaded successfully.")
}

/**
* Begin interactive dom node selection.
*/
selectMode() {
var self = this;
var selection = [];
var previousElement = null;

var showSelection = function() {
var olds = document.querySelectorAll('._goshen-selected');
for (var i = 0; i < olds.length; i++) {
olds[i].classList.remove('_goshen-selected');
}
for (var i = 0; i < selection.length; i++) {
selection[i].classList.add('_goshen-selected');
}
};

var setSelection = function(sel) {
selection = sel;
showSelection();
};

var validParents = [
"DIV", "ARTICLE", "BLOCKQUOTE", "MAIN",
"SECTION", "UL", "OL", "DL"
];

var validChildren = [
"P", "H1", "H2", "H3", "H4", "H5", "H6", "SPAN", "DL",
"OL", "UL", "BLOCKQUOTE", "SECTION"
];

var selectSiblings = function(el) {
var firstChild = el;
var parent = el.parentNode;
while (parent && !~validParents.indexOf(parent.tagName)) {
firstChild = parent;
parent = firstChild.parentNode;
}

if (parent) {
var kids = parent.childNodes,
len = kids.length,
result = [],
i = 0;

while (kids[i] !== firstChild) { i++; }

for (; i < len; i++) {
var kid = kids[i];
if (!!~validChildren.indexOf(kid.tagName)) {
result.push(kid);
}
}
return result;

} else { return [el]; }
};

var stop = function() {
off("mouseover", mouseoverHandler);
off("mousemove", moveHandler);
off("keydown", keydownHandler);
off("keyup", keyupHandler);
off("click", clickHandler);
self.performSelectTranslation(selection);
};

var mouseoverHandler = function(ev) {
previousElement = ev.target;

if (ev.altKey) {
setSelection([ev.target]);
} else {
setSelection(selectSiblings(ev.target));
}
};

var clickHandler = function(ev) {
stop();
};

var moveHandler = function(ev) {
mouseoverHandler(ev);
off("mousemove", moveHandler);
};

var keydownHandler = function(ev) {
if (ev.keyCode === 27) {
stop();
} else if (ev.altKey && selection.length > 1) {
setSelection([selection[0]]);
}
};

var keyupHandler = function(ev) {
if (!ev.altKey && selection.length === 1) {
setSelection(selectSiblings(selection[0]));
}
};

on("mouseover", mouseoverHandler);
on("click", clickHandler);
on("mousemove", moveHandler);
on("keydown", keydownHandler);
on("keyup", keyupHandler);
}

select(contextData) {
var text;
if (contextData === undefined) {
text = window.getSelection().toString();
} else {
text = contextData.selectionText;
}
if (text.trim().length > 0) {
this.init(this.parse.string(text));
window.getSelection().removeAllRanges();
} else {
selectMode();
}
};

_chunkedTranslation(text) {
// We need to find a way to split on sentences, or long things.
var texts = text.split('.');
for (var i = 0; i < texts.length; i++) {
texts[i] = this.G.translate(texts[i]);
}
return texts.join('.');
}

performSelectTranslation(selection) {
for (var i = 0; i < selection.length; i++) {
selection[i].classList.add('_goshen-active');
selection[i].innerText = this._chunkedTranslation(selection[i].innerText);
selection[i].classList.remove('_goshen-active');
selection[i].classList.remove('_goshen-selected');
}
}
};

_goshen._cg = new ChromeGoshen();

})(this);
107 changes: 107 additions & 0 deletions contrib/goshen-chrome/onpage/goshen.js
@@ -0,0 +1,107 @@
(function (root) {

var _goshen = root._goshen;

LANGUAGES = {
English: 'en',
en: 'en',
German: 'de',
de: 'de'
}

LOCALES = {
English: 'en-US',
en: 'en-US',
German: 'de',
de: 'de'
}


serialize = function(obj) {
var str = [];
for (var p in obj) {
str.push(encodeURIComponent(p) + "=" + encodeURIComponent(obj[p]));
}
return str.join("&");
};


class MosesGoshenAdapter {
constructor(hostname, protocol, opts) {
this.hostname = hostname;
this.protocol = protocol || 'http';
}

url(suffix) {
suffix = suffix || '';
return `${this.protocol}://${this.hostname}/translate?${suffix}`;
}

translate(text, target, source, callback) {
/* Translate a string `text`, using `opts` as corequisite options.
Arguments:
text (str): The text to translate.
target (str): The language to translate to
source (str): The language to translate from
callback (function): The function to call on the translated text
Returns:
str: The translated text
*/

var requestURL = this.url(serialize({
q: text,
key: 'x',
target: target || LANGUAGES.en,
source: source || LANGUAGES.de
}));

if (!!root.Meteor && !!root.HTTP) {
var response = HTTP.call('GET', requestURL, {});
var translated = response.data;
if (callback) callback(text, translated);

} else if (!!root.XMLHttpRequest) {
var request = new XMLHttpRequest();
request.open('GET', requestURL, false);
request.send(null);

if (request.status === 200) {
var translated = root.JSON.parse(request.responseText);
if (callback) callback(text, translated);
}
}
return translated.data.translations[0].translatedText
}
}


_goshen.Goshen = class Goshen {
constructor(hostname, protocol, type, opts) {
/* Create a new Goshen object.
Arguments:
hostname (str): A protocol-less URI such as `255.255.0.0:3000`
protocol (str: 'http'): An http protocol (either 'http' or 'https')
type (class): The type of adapter to use by default.
opts (dict): Options for configuration.
The options configuration dictionary can contain
*/
type = type || MosesGoshenAdapter;
this.ga = new type(hostname, protocol, opts);
}

url(suffix) {
return this.ga.url(suffix);
}

translate(text, target, source, callback) {
/* Calls the local GoshenAdapter#translate. */
return this.ga.translate(text, target, source, callback);
}


};
})(this);
7 changes: 7 additions & 0 deletions contrib/goshen-chrome/onpage/onpage.css
@@ -0,0 +1,7 @@
._goshen-selected {
background-color: rgba(100, 250, 250, 0.2);
}

._goshen-selected._goshen-active {
background-color: rgba(250, 100, 250, 0.2);
}
25 changes: 25 additions & 0 deletions contrib/goshen-chrome/onpage/onpage.js
@@ -0,0 +1,25 @@
// This is run inside the scope of a page, and so we have direct access to the
// page's HTML from here.

(function (window) {

if (typeof window._goshen !== 'undefined') {
console.warn("_goshen unable to initialize!");
return;
} else {
window._goshen = {};
}

// We can now request the contents of window.

window.addEventListener('keyup', function(ev) {
// This is a bit heavy-handed, and we almost assuredly don't need to be
// capturing every keyup event. But it's lightweight, and serves as a
// decent proof of concept.
if (ev.altKey && ev.keyCode == 84) {
// They pressed Alt+T. Call _goshen's get-text function!
window._goshen._cg.selectMode();
}
});

})(this);
10 changes: 10 additions & 0 deletions contrib/goshen-chrome/options/index.html
@@ -0,0 +1,10 @@
<!DOCTYPE html>
<html>
<head>
<meta charset="utf-8">
<title>Goshen Options</title>
</head>
<body>

</body>
</html>
44 changes: 44 additions & 0 deletions contrib/goshen-chrome/popup/popup.html
@@ -0,0 +1,44 @@
<html>
<head>
<script src="../vendor/ustr.min.js"></script>
<!-- <script src="https://ajax.googleapis.com/ajax/libs/jquery/1.10.2/jquery.min.js"></script> -->
<script src="popup.js"></script>
<link rel="stylesheet/less" type="text/css" href="style.less" />
<script src="../vendor/less.js"></script>
</head>
<body style="width: 400px">
<div class="container">
<h1>Goshen Translator</h1>
<p>
Goshen uses <code>python-mt-server</code> and <code>moses</code> to
translate webpage text. For more information, see the repository
on <a href="https://github.com/j6k4m8/en600.468-final/">GitHub</a>.
</p>
<hr>
<div class="dropdown-container from-container">
<h2>Translate from:</h2>
<select class="from-select">
<!-- <option value="English">English</option> -->
<!-- <option value="French">French</option> -->
<option value="German">German</option>
</select>
</div>
<div class="dropdown-container to-container">
<h2>Translate to:</h2>
<select class="to-select">
<option value="English">English</option>
<!-- <option value="French">French</option> -->
<!-- <option value="German">German</option> -->
</select>
</div>
<hr>
<p>
To translate the webpage, press the <kbd>Alt</kbd>+<kbd>T</kbd>
keychord and mouse over the element(s) that you want to queue for
translation. Click to begin the translation &mdash; the selected
elements will turn blue to indicate that they're queued.
</p>
<!-- <button type="button" style="float: right;" class="js-translate">Translate</button> -->
</div>
</body>
</html>
Empty file.

0 comments on commit c237b13

Please sign in to comment.