Skip to content

Instantly share code, notes, and snippets.

@robert-nix
Last active August 29, 2015 14:22
Show Gist options
  • Select an option

  • Save robert-nix/dd5d9b0303c59e4feb7a to your computer and use it in GitHub Desktop.

Select an option

Save robert-nix/dd5d9b0303c59e4feb7a to your computer and use it in GitHub Desktop.
Korean autodictionary
###
// ==UserScript==
// @id AutoDictKr
// @name Korean Autodictionary
// @namespace https://gist.github.com/Mischanix/dd5d9b0303c59e4feb7a
// @version 3
// @author Mischanix
// @description Provides inline definitions for selected Korean text
// @include *
// @license Creative Commons CC0 (public domain)
// @run-at document-start
// @grant unsafeWindow
// @grant GM_xmlhttpRequest
// @grant GM_addStyle
// @grant GM_getResourceText
// @resource stylesheet user.css?3
// @updateURL https://gist.github.com/Mischanix/dd5d9b0303c59e4feb7a/raw/AutoDictKr.user.js
// @updateVersion 3
// ==/UserScript==
###
do ->
w = unsafeWindow or window
log = console.log.bind console
get_suggestions = (query) ->
new Promise (resolve, reject) -> GM_xmlhttpRequest
method: 'GET'
url: 'http://suggest.dic.daum.net/dic_all_ctsuggest?mod=json' +
'&code=utf_in_out&enc=utf&cate=eng&q=' + query
onload: (res) ->
body = res.responseText
result = (s.split('|')[1] for s in JSON.parse(body).items)
resolve result
onerror: reject
get_definition = (query) ->
new Promise (resolve, reject) -> GM_xmlhttpRequest
method: 'GET'
url: 'http://dic.daum.net/search.do?dic=eng&q=' + query
onload: (res) ->
url = res.finalUrl
idx = url.indexOf '?wordid='
if idx < 0
reject 'bad query'
else
id = url.substr 8 + idx
id = id.substr 0, id.indexOf '&'
resolve
id: id
result: parse_word_info res.responseText
onerror: reject
parse_word_info = (text) ->
doc = new DOMParser().parseFromString text, 'text/html'
$sections = doc.querySelectorAll '.mean_total'
for $section in $sections
$items = $section.querySelectorAll '.item'
{
title: $section.querySelector('.inner_tit').textContent.trim()
items: parse_item($item) for $item in $items
}
parse_item = ($item) ->
$examples = $item.querySelectorAll '.desc'
$sense = $item.querySelector('.txt_sense')
{
meaning: $sense?.textContent.trim()
examples: for $ex in $examples
phrase: $ex.querySelector('.txt .inner').textContent.trim()
meaning: $ex.querySelector('.trans .inner').textContent.trim()
}
enabled = false
target = w.document
$overlay = null
$title = null
$meanings = null
pointy = true
link = ''
on_key = (e) ->
if not enabled and e.shiftKey and e.charCode == 68
enabled = true
target.removeEventListener 'keypress', on_key
GM_addStyle GM_getResourceText 'stylesheet'
$overlay = target.createElement 'div'
target.body.appendChild $overlay
reset_overlay()
true
target.addEventListener 'keypress', on_key
reset_overlay = ->
$overlay.className = 'kad-bubble kad-overlay single'
if pointy
$overlay.classList.add 'pointy'
$overlay.style.width = '500px';
$overlay.style.height = '300px';
$overlay.style.zIndex = 99999;
$overlay.style.display = 'none';
$overlay.innerHTML = '<ul><li>&lt;</li><li>&gt;</li></ul>' +
'<h1></h1><ol></ol>'
$title = $overlay.querySelector('h1')
$title.addEventListener 'click', ->
window.open link, '_dict'
$meanings = $overlay.querySelector('ol')
$navs = $overlay.querySelectorAll('ul li')
$navs[0].style.mozUserSelect = 'none'
$navs[0].style.khtmlUserSelect = 'none'
$navs[0].style.webkitUserSelect = 'none'
$navs[0].style.msUserSelect = 'none'
$navs[0].style.userSelect = 'none'
$navs[0].addEventListener 'click', nav_back
$navs[1].style.mozUserSelect = 'none'
$navs[1].style.khtmlUserSelect = 'none'
$navs[1].style.webkitUserSelect = 'none'
$navs[1].style.msUserSelect = 'none'
$navs[1].style.userSelect = 'none'
$navs[1].addEventListener 'click', nav_forward
page = 0
nav_back = (e) ->
page = page - 1
show_page()
nav_forward = (e) ->
page = page + 1
show_page()
last_selection = ''
rect = null
target.addEventListener 'mouseup', (e) ->
return if not enabled
el = e.target
while el?
return if el is $overlay
el = el.parentElement
selection = target.getSelection()
text = selection.toString().trim()
show_definition(text) if last_selection isnt text
last_selection = text
hide_overlay = ->
$overlay.style.display = 'none'
curr_suggs = []
resolved = {}
pages = []
pages_complete = false
promises = []
show_definition = (query) ->
if not query
hide_overlay()
return
_rect = target.getSelection().getRangeAt(0).getBoundingClientRect()
rect =
top: _rect.top + target.body.scrollTop
left: _rect.left + target.body.scrollLeft
width: _rect.width
get_suggestions(query).then(
(suggests) ->
log 'suggestions', suggests
if suggests? and suggests.length
curr_suggs = suggests
resolved = {}
get_definition curr_suggs[0]
else
new Promise (resolve, reject) -> reject 'no results'
(e) -> log e
).then(
(res) ->
resolved[curr_suggs[0]] = true
log 'definition', res
link = 'http://dic.daum.net/word/view.do?wordid=' + res.id
page = 0
pages = res.result
promises = []
for sugg, i in curr_suggs
if i != 0
promises[i] = get_definition sugg
show_page true
(err) ->
show_error(err)
)
show_error = (message) ->
reset_overlay()
$overlay.classList.add('single')
$title.textContent = message
position_overlay()
show_page = (change_pos) ->
if not pages[page]
remaining = []
for sugg, i in curr_suggs
if not resolved[sugg]
remaining.push i
if not remaining.length
min_page = 0x10000
max_page = 0
_pages = []
for k, v of pages
if k > max_page
max_page = k
if k < min_page
min_page = k
_pages.push v
pages = _pages
page += -min_page
page += pages.length
page %= pages.length
log _pages, min_page, max_page
show_page()
return
else
log 'remaining', remaining
idx = remaining[0]
if page < pages.length
idx = remaining[remaining.length - 1]
lookup = curr_suggs[idx]
promises[idx].then(
(res) ->
resolved[lookup] = true
log '+definition', res
link = 'http://dic.daum.net/word/view.do?wordid=' + res.id
offs = 0
if page < 0
offs = 1 - res.result.length
for def, i in res.result
pages[page + offs + i] = def
show_page()
)
return
else
def = pages[page]
reset_overlay()
if curr_suggs.length > 1 or pages.length > 1
$overlay.classList.remove('single')
else
$overlay.classList.add('single')
throw 'wat' if not def or not def.items.length
$title.textContent = def.title
for item in def.items
continue if not item.meaning and not item.examples.length
$li = target.createElement 'li'
$li.textContent = item.meaning
$ul = target.createElement 'ul'
for ex in item.examples
$exli = target.createElement 'li'
$en = target.createElement 'span'
$en.textContent = ex.meaning
$kr = target.createElement 'span'
$kr.textContent = ex.phrase
$exli.appendChild $en
$exli.appendChild $kr
$ul.appendChild $exli
$li.appendChild $ul
$meanings.appendChild $li
position_overlay()
position_overlay = ->
$overlay.style.display = 'block'
actual_height = 20 + $meanings.getBoundingClientRect().bottom -
$overlay.getBoundingClientRect().top
$overlay.style.height = actual_height + 'px'
top = rect.top - actual_height - 40
left = rect.left + rect.width / 2 - 250
top = 0 if top < 0
left = 0 if left < 0
if pointy
$overlay.style.top = top + 'px'
$overlay.style.left = left + 'px'
else
throw 'wat'
null
// Generated by CoffeeScript 1.7.1
/*
// ==UserScript==
// @id AutoDictKr
// @name Korean Autodictionary
// @namespace https://gist.github.com/Mischanix/dd5d9b0303c59e4feb7a
// @version 3
// @author Mischanix
// @description Provides inline definitions for selected Korean text
// @include *
// @license Creative Commons CC0 (public domain)
// @run-at document-start
// @grant unsafeWindow
// @grant GM_xmlhttpRequest
// @grant GM_addStyle
// @grant GM_getResourceText
// @resource stylesheet user.css?3
// @updateURL https://gist.github.com/Mischanix/dd5d9b0303c59e4feb7a/raw/AutoDictKr.user.js
// @updateVersion 3
// ==/UserScript==
*/
(function() {
(function() {
var $meanings, $overlay, $title, curr_suggs, enabled, get_definition, get_suggestions, hide_overlay, last_selection, link, log, nav_back, nav_forward, on_key, page, pages, pages_complete, parse_item, parse_word_info, pointy, position_overlay, promises, rect, reset_overlay, resolved, show_definition, show_error, show_page, target, w;
w = unsafeWindow || window;
log = console.log.bind(console);
get_suggestions = function(query) {
return new Promise(function(resolve, reject) {
return GM_xmlhttpRequest({
method: 'GET',
url: 'http://suggest.dic.daum.net/dic_all_ctsuggest?mod=json' + '&code=utf_in_out&enc=utf&cate=eng&q=' + query,
onload: function(res) {
var body, result, s;
body = res.responseText;
result = (function() {
var _i, _len, _ref, _results;
_ref = JSON.parse(body).items;
_results = [];
for (_i = 0, _len = _ref.length; _i < _len; _i++) {
s = _ref[_i];
_results.push(s.split('|')[1]);
}
return _results;
})();
return resolve(result);
},
onerror: reject
});
});
};
get_definition = function(query) {
return new Promise(function(resolve, reject) {
return GM_xmlhttpRequest({
method: 'GET',
url: 'http://dic.daum.net/search.do?dic=eng&q=' + query,
onload: function(res) {
var id, idx, url;
url = res.finalUrl;
idx = url.indexOf('?wordid=');
if (idx < 0) {
return reject('bad query');
} else {
id = url.substr(8 + idx);
id = id.substr(0, id.indexOf('&'));
return resolve({
id: id,
result: parse_word_info(res.responseText)
});
}
},
onerror: reject
});
});
};
parse_word_info = function(text) {
var $item, $items, $section, $sections, doc, _i, _len, _results;
doc = new DOMParser().parseFromString(text, 'text/html');
$sections = doc.querySelectorAll('.mean_total');
_results = [];
for (_i = 0, _len = $sections.length; _i < _len; _i++) {
$section = $sections[_i];
$items = $section.querySelectorAll('.item');
_results.push({
title: $section.querySelector('.inner_tit').textContent.trim(),
items: (function() {
var _j, _len1, _results1;
_results1 = [];
for (_j = 0, _len1 = $items.length; _j < _len1; _j++) {
$item = $items[_j];
_results1.push(parse_item($item));
}
return _results1;
})()
});
}
return _results;
};
parse_item = function($item) {
var $ex, $examples, $sense;
$examples = $item.querySelectorAll('.desc');
$sense = $item.querySelector('.txt_sense');
return {
meaning: $sense != null ? $sense.textContent.trim() : void 0,
examples: (function() {
var _i, _len, _results;
_results = [];
for (_i = 0, _len = $examples.length; _i < _len; _i++) {
$ex = $examples[_i];
_results.push({
phrase: $ex.querySelector('.txt .inner').textContent.trim(),
meaning: $ex.querySelector('.trans .inner').textContent.trim()
});
}
return _results;
})()
};
};
enabled = false;
target = w.document;
$overlay = null;
$title = null;
$meanings = null;
pointy = true;
link = '';
on_key = function(e) {
if (!enabled && e.shiftKey && e.charCode === 68) {
enabled = true;
target.removeEventListener('keypress', on_key);
GM_addStyle(GM_getResourceText('stylesheet'));
$overlay = target.createElement('div');
target.body.appendChild($overlay);
reset_overlay();
return true;
}
};
target.addEventListener('keypress', on_key);
reset_overlay = function() {
var $navs;
$overlay.className = 'kad-bubble kad-overlay single';
if (pointy) {
$overlay.classList.add('pointy');
}
$overlay.style.width = '500px';
$overlay.style.height = '300px';
$overlay.style.zIndex = 99999;
$overlay.style.display = 'none';
$overlay.innerHTML = '<ul><li>&lt;</li><li>&gt;</li></ul>' + '<h1></h1><ol></ol>';
$title = $overlay.querySelector('h1');
$title.addEventListener('click', function() {
return window.open(link, '_dict');
});
$meanings = $overlay.querySelector('ol');
$navs = $overlay.querySelectorAll('ul li');
$navs[0].style.mozUserSelect = 'none';
$navs[0].style.khtmlUserSelect = 'none';
$navs[0].style.webkitUserSelect = 'none';
$navs[0].style.msUserSelect = 'none';
$navs[0].style.userSelect = 'none';
$navs[0].addEventListener('click', nav_back);
$navs[1].style.mozUserSelect = 'none';
$navs[1].style.khtmlUserSelect = 'none';
$navs[1].style.webkitUserSelect = 'none';
$navs[1].style.msUserSelect = 'none';
$navs[1].style.userSelect = 'none';
return $navs[1].addEventListener('click', nav_forward);
};
page = 0;
nav_back = function(e) {
page = page - 1;
return show_page();
};
nav_forward = function(e) {
page = page + 1;
return show_page();
};
last_selection = '';
rect = null;
target.addEventListener('mouseup', function(e) {
var el, selection, text;
if (!enabled) {
return;
}
el = e.target;
while (el != null) {
if (el === $overlay) {
return;
}
el = el.parentElement;
}
selection = target.getSelection();
text = selection.toString().trim();
if (last_selection !== text) {
show_definition(text);
}
return last_selection = text;
});
hide_overlay = function() {
return $overlay.style.display = 'none';
};
curr_suggs = [];
resolved = {};
pages = [];
pages_complete = false;
promises = [];
show_definition = function(query) {
var _rect;
if (!query) {
hide_overlay();
return;
}
_rect = target.getSelection().getRangeAt(0).getBoundingClientRect();
rect = {
top: _rect.top + target.body.scrollTop,
left: _rect.left + target.body.scrollLeft,
width: _rect.width
};
return get_suggestions(query).then(function(suggests) {
log('suggestions', suggests);
if ((suggests != null) && suggests.length) {
curr_suggs = suggests;
resolved = {};
return get_definition(curr_suggs[0]);
} else {
return new Promise(function(resolve, reject) {
return reject('no results');
});
}
}, function(e) {
return log(e);
}).then(function(res) {
var i, sugg, _i, _len;
resolved[curr_suggs[0]] = true;
log('definition', res);
link = 'http://dic.daum.net/word/view.do?wordid=' + res.id;
page = 0;
pages = res.result;
promises = [];
for (i = _i = 0, _len = curr_suggs.length; _i < _len; i = ++_i) {
sugg = curr_suggs[i];
if (i !== 0) {
promises[i] = get_definition(sugg);
}
}
return show_page(true);
}, function(err) {
return show_error(err);
});
};
show_error = function(message) {
reset_overlay();
$overlay.classList.add('single');
$title.textContent = message;
return position_overlay();
};
show_page = function(change_pos) {
var $en, $exli, $kr, $li, $ul, def, ex, i, idx, item, k, lookup, max_page, min_page, remaining, sugg, v, _i, _j, _k, _len, _len1, _len2, _pages, _ref, _ref1;
if (!pages[page]) {
remaining = [];
for (i = _i = 0, _len = curr_suggs.length; _i < _len; i = ++_i) {
sugg = curr_suggs[i];
if (!resolved[sugg]) {
remaining.push(i);
}
}
if (!remaining.length) {
min_page = 0x10000;
max_page = 0;
_pages = [];
for (k in pages) {
v = pages[k];
if (k > max_page) {
max_page = k;
}
if (k < min_page) {
min_page = k;
}
_pages.push(v);
}
pages = _pages;
page += -min_page;
page += pages.length;
page %= pages.length;
log(_pages, min_page, max_page);
show_page();
return;
} else {
log('remaining', remaining);
idx = remaining[0];
if (page < pages.length) {
idx = remaining[remaining.length - 1];
}
lookup = curr_suggs[idx];
promises[idx].then(function(res) {
var def, offs, _j, _len1, _ref;
resolved[lookup] = true;
log('+definition', res);
link = 'http://dic.daum.net/word/view.do?wordid=' + res.id;
offs = 0;
if (page < 0) {
offs = 1 - res.result.length;
}
_ref = res.result;
for (i = _j = 0, _len1 = _ref.length; _j < _len1; i = ++_j) {
def = _ref[i];
pages[page + offs + i] = def;
}
return show_page();
});
return;
}
} else {
def = pages[page];
}
reset_overlay();
if (curr_suggs.length > 1 || pages.length > 1) {
$overlay.classList.remove('single');
} else {
$overlay.classList.add('single');
}
if (!def || !def.items.length) {
throw 'wat';
}
$title.textContent = def.title;
_ref = def.items;
for (_j = 0, _len1 = _ref.length; _j < _len1; _j++) {
item = _ref[_j];
if (!item.meaning && !item.examples.length) {
continue;
}
$li = target.createElement('li');
$li.textContent = item.meaning;
$ul = target.createElement('ul');
_ref1 = item.examples;
for (_k = 0, _len2 = _ref1.length; _k < _len2; _k++) {
ex = _ref1[_k];
$exli = target.createElement('li');
$en = target.createElement('span');
$en.textContent = ex.meaning;
$kr = target.createElement('span');
$kr.textContent = ex.phrase;
$exli.appendChild($en);
$exli.appendChild($kr);
$ul.appendChild($exli);
}
$li.appendChild($ul);
$meanings.appendChild($li);
}
return position_overlay();
};
position_overlay = function() {
var actual_height, left, top;
$overlay.style.display = 'block';
actual_height = 20 + $meanings.getBoundingClientRect().bottom - $overlay.getBoundingClientRect().top;
$overlay.style.height = actual_height + 'px';
top = rect.top - actual_height - 40;
left = rect.left + rect.width / 2 - 250;
if (top < 0) {
top = 0;
}
if (left < 0) {
left = 0;
}
if (pointy) {
$overlay.style.top = top + 'px';
return $overlay.style.left = left + 'px';
} else {
throw 'wat';
}
};
return null;
})();
}).call(this);
.kad-bubble {
position: absolute;
top: 100px; left: 100px;
width: 280px;
height: 120px;
padding: 0px;
background: #ddd;
border-radius: 10px;
box-shadow: 0 0 7px 2px black;
}
.kad-bubble.pointy:after {
content: '';
position: absolute;
border-style: solid;
border-width: 20px 20px 0;
border-color: #ddd transparent;
display: block;
width: 0;
z-index: 1;
margin-left: -20px;
bottom: -20px;
left: 50%;
}
.kad-overlay {
font-family: sans-serif;
color: #333;
overflow: visible;
font-size: 16px;
line-height: normal;
}
.kad-overlay > ul {
list-style-type: none;
margin: 0;
padding: 0;
cursor: pointer;
}
.kad-overlay > ul > li {
float: left;
display: flex;
justify-content: center;
align-items: center;
width: 50%;
height: 40px;
border-bottom: 1px solid #333;
font-size: 2em;
font-weight: bold;
background: #bbb;
border-radius: 0 10px 0 0;
color: #666;
}
.kad-overlay > ul > li:hover {
background: #eee;
color: #788;
}
.kad-overlay > ul > li:first-of-type {
width: calc(50% - 1px);
border-right: 1px solid #333;
border-radius: 10px 0 0 0;
}
.kad-overlay h1 {
clear: both;
margin: 0;
padding: 0.25em 0.65em 0 0.65em;
font-size: 36px;
line-height: 1.5;
}
.kad-overlay h1:hover {
cursor: pointer;
color: #22c;
}
.kad-overlay ol {
margin-top: 0;
padding-left: 32px;
list-style-type: decimal;
}
.kad-overlay ol li {
margin: 0.5em;
}
.kad-overlay ol ul {
list-style-type: none;
padding-left: 32px;
}
.kad-overlay ol > li {
font-size: 18px;
list-style-type: decimal;
}
.kad-overlay ol ul li {
font-size: 16px;
}
.kad-overlay ol li span:nth-of-type(2) {
margin-left: 1em;
}
.kad-overlay ol li span:nth-of-type(2):before {
content: '—';
position: relative;
right: 0.5em;
}
.kad-overlay.single > ul {
display: none;
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment