├── .gitignore
├── .vscode
└── settings.json
├── LICENSE
├── README.md
├── background.html
├── background
├── dict.coffee
├── dict.js
├── dict_resources.coffee
├── dict_resources.js
├── dictwindow.coffee
├── dictwindow.js
├── ext.coffee
├── ext.js
├── main.coffee
├── main.js
├── message.coffee
├── message.js
├── plain-lookup.coffee
├── plain-lookup.js
├── setting.coffee
├── setting.js
├── storage.coffee
└── storage.js
├── bower.json
├── build
└── fairy-dict.crx
├── content
├── inject-fontello.css
├── inject.coffee
├── inject.css
└── inject.js
├── css
├── 91dict.css
├── apidict.css
├── baidu-dict.css
├── bing.css
├── bing.less
├── bootstrap-theme.css
├── bootstrap.css
├── cambridgeenglish.css
├── cambridgeenglish.less
├── collins.css
├── collins.less
├── dict-cn.css
├── dict-cn.less
├── dictheader.css
├── dictheader.less
├── dictionary-com.css
├── dictionary-com.less
├── eudic.css
├── eudic.less
├── font-awesome.css
├── hjenglish.css
├── iciba.css
├── iciba.less
├── longmanenglish.css
├── longmanenglish.less
├── macmilland.css
├── macmilland.less
├── merriamwebster.css
├── merriamwebster.less
├── options.css
├── options.less
├── oxfordlearner.css
├── oxfordlearner.less
├── oxfordliving.css
├── oxfordliving.less
├── urban.css
├── urban.less
├── youdao.css
├── youdao.less
└── zdic.css
├── dict.coffee
├── dict.js
├── fonts
├── FontAwesome.otf
├── fairydict-font.woff
├── fontawesome-webfont.eot
├── fontawesome-webfont.svg
├── fontawesome-webfont.ttf
├── fontawesome-webfont.woff
├── fontawesome-webfont.woff2
├── glyphicons-halflings-regular.eot
├── glyphicons-halflings-regular.svg
├── glyphicons-halflings-regular.ttf
└── glyphicons-halflings-regular.woff
├── helper.coffee
├── helper.js
├── images
├── books-128.png
├── books-48.png
├── books-96.png
├── books-b-48.png
├── books-b-96.png
├── gplus32.png
├── tom.jpg
├── twitter32.jpg
└── wordpress32.jpg
├── js
├── bootstrap.js
├── ion.sound.js
├── jquery-1.10.2.js
├── jquery.scoped.js
└── starrr.js
├── loader.coffee
├── loader.js
├── manifest.json
├── needsharebutton.min.css
├── needsharebutton.min.js
├── option
├── option.coffee
└── option.js
├── options.html
├── pack.sh
├── readme_images
├── 2.png
├── 3.png
├── 4.png
└── 5.png
├── template
├── apidict.html
├── apidict.js
└── header.html
├── utils.coffee
└── utils.js
/.gitignore:
--------------------------------------------------------------------------------
1 | node_modules
2 | bower_components
3 |
4 |
--------------------------------------------------------------------------------
/.vscode/settings.json:
--------------------------------------------------------------------------------
1 | {
2 | "coffeescript.compile": {
3 | "bare": true,
4 | "sourceMap": false
5 | }
6 | }
7 |
--------------------------------------------------------------------------------
/README.md:
--------------------------------------------------------------------------------
1 | **Important: 此扩展的升级版 [Dictionaries](https://github.com/revir/dictionaries) 已发布, 添加了管理单词表和词典列表的功能, 支持日语查询, 还有更多的功能和设置, 欢迎去下载使用 [Dictionaries](https://github.com/revir/dictionaries). FairyDict 将不再更新!**
2 |
3 | ----
4 |
5 | *8月11日更新:新增百度、汉典等汉语词典;快速查词的显示框位置可以设置了!*
6 |
7 | *7月8日更新:期待的鼠标悬停取词的功能终于来了。*
8 |
9 | *7月6日更新:快速查词添加了音标和自动发音功能。*
10 |
11 | *7月5日更新:增强快速查词体验,增加了一个设置项,点击图标可以打开查词典的窗口了。*
12 |
13 | *6月28日更新:新增快速查词功能,选中单词后在鼠标附近显示词义。可设置开关。*
14 |
15 | *5月5日更新: 重新排好了Toolbar上的元素,布局更整洁了。金山词霸替换成了网页版。*
16 |
17 | *5月2日更新: 已添加大量常见的在线词典,包括欧陆词典, Longman, Oxford, Cambridge, Merriam-webster, Collins, Macmilland 等等。还增加了一个设置: 鼠标取词时可以选择必须按住一个按键(Ctrl, Shift, Alt 等)。*
18 |
19 |
20 | # Fairy Dict
21 |
22 | 查词典的 chrome extension, 方便中国人阅读英文网站,我自己每天都依赖它,功能和使用体验上我尽量做得更好, 欢迎大家提供反馈。
23 |
24 | # 安装地址
25 |
26 | * [chrome web store](https://chrome.google.com/webstore/detail/fairydict/gpdpcfgfmgkmljmhhnedefdaadgehaah)
27 |
28 | # Feature
29 |
30 | * 支持多种词典,金山词霸、海词、必应,Urban, Dictionary.com, Longman, Oxford, Cambridge, Merriam-webster, Collins, Macmilland 等几乎所有的在线词典;理论上可以支持所有在线词典;
31 | * 支持鼠标取词、键盘快捷键查词、鼠标右键查词等查询方式;
32 | * 支持快速查词功能,选中单词后在鼠标附近显示词义;
33 | * 历史记录保存,自动同步;
34 | * 窗口大小可自动记忆;
35 |
36 | # TODO
37 |
38 | * 支持更多词典,目前通过请求网页的方式可以支持几乎所有在线词典,还可以添加 Google,Bing 等翻译;
39 | * 目前的历史记录最多仅保存200个,受限于 chrome storage 的容量限制,如需保存更多,需要搭建服务器,或者保存至有道等网站的生词本里;
40 | * 卡片式单词记忆;
41 |
42 | # FAQ
43 |
44 | 1. 怎样鼠标取词?
45 | 在 Chrome 浏览器上,用鼠标双击选中单词,或按住左键拖动选择一段,等你鼠标松开后(触发了 mouseup event)才会查询。
46 |
47 | 2. 安装后怎么没有反应?
48 | 安装后必须刷新一下页面才可以取词,一般来说 Chrome extension 都这样。但无需重启浏览器。
49 | 有极少数网站可能无法用鼠标或快捷键取词,可以试试鼠标右键。
50 | 更改了快捷键设置后页面也需要刷新一下才会生效。
51 |
52 | 3. 弹窗太烦了,可以关闭吗?
53 | 点击 FairyDict 的图标(一般在浏览器右上角处)即可 打开/关闭 鼠标取词, 还可以在选项里设置必须按住一个功能键才能鼠标取词。默认安装后鼠标取词是开的。
54 |
55 | 4. 窗口太大了,可以小一点吗?
56 | 窗口大小可以拖动,改变大小后,只要你再查一个单词,这个设置就记住了,请不要问为什么还要“再查一个单词”哦 ~
57 |
58 | 5. 360,腾讯,搜狗浏览器可以安装吗?
59 | 只要是 Chromium 内核的浏览器,通过[本地下载](https://github.com/revir/FairyDict/raw/master/build/fairy-dict.crx) CRX 文件,拖到浏览器的扩展页面里,应该是可以用的,如果不能用,请向我反馈。
60 |
61 | 6. 能支持我喜欢的**词典吗?
62 | 告诉我词典名字,只要网上有 Web 版就能加进来。
63 |
64 |
65 | # Screenshot
66 | 
67 | 
68 | 
69 | 
70 |
--------------------------------------------------------------------------------
/background.html:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 | Background Main
6 |
7 |
8 |
9 |
10 |
11 |
12 |
--------------------------------------------------------------------------------
/background/dict.coffee:
--------------------------------------------------------------------------------
1 | define ["jquery",
2 | "utils"], ($, utils)->
3 | console.log "[dict] init"
4 |
5 | allDicts = [{
6 | 'dictName': "必应词典",
7 | 'windowUrl': 'http://cn.bing.com/dict/search?q=',
8 | 'windowUrlMatch': '[^\\w]q=([^&]+)',
9 | "resources": {
10 | styles: ['css/bing.css']
11 | }
12 | }, {
13 | 'dictName': '金山词霸',
14 | 'windowUrl': 'http://www.iciba.com/',
15 | 'windowUrlMatch': 'iciba.com/([^&]+)',
16 | "resources": {
17 | styles: ['css/iciba.css']
18 | }
19 | # 'entry': 'Iciba',
20 | # 'baseUrl': 'http://dict-co.iciba.com/api/dictionary.php',
21 | # 'queryType': 'get',
22 | # 'params': {
23 | # 'key': '0AAE477DB66EC58D12E1451877045CA5'
24 | # },
25 | # 'queryKey': 'w'
26 | }, {
27 | 'dictName': '有道词典',
28 | 'entry': 'youdao',
29 | 'windowUrl': 'http://dict.youdao.com/w/eng/',
30 | 'windowUrlMatch': '/eng/([^&/?]+)'
31 | "resources": {
32 | styles: ['css/youdao.css']
33 | }
34 | }, {
35 | 'dictName': '海词词典',
36 | 'entry': 'dict-cn',
37 | 'windowUrl': 'http://dict.cn/',
38 | 'windowUrlMatch': 'dict.cn/([^&/?]+)'
39 | "resources": {
40 | styles: ['css/dict-cn.css']
41 | }
42 | }, {
43 | 'dictName': '沪江词典',
44 | 'entry': 'hjenglish',
45 | 'windowUrl': 'https://dict.hjenglish.com/w/',
46 | 'windowUrlMatch': '/w/([^&/?]+)'
47 | "resources": {
48 | styles: ['css/hjenglish.css']
49 | }
50 | }, {
51 | 'dictName': '人人词典',
52 | 'entry': '91dict',
53 | 'windowUrl': 'http://www.91dict.com/words?w=',
54 | 'windowUrlMatch': '[^\\w]w=([^&]+)'
55 | "resources": {
56 | styles: ['css/91dict.css']
57 | }
58 | }, {
59 | 'dictName': '欧陆词典',
60 | 'entry': 'eudic',
61 | 'windowUrl': 'https://dict.eudic.net/dicts/en/',
62 | 'windowUrlMatch': '/en/([^&/?]+)'
63 | "resources": {
64 | styles: ['css/eudic.css']
65 | }
66 | }, {
67 | 'dictName': '汉典',
68 | 'entry': 'zdic',
69 | 'windowUrl': 'http://www.zdic.net/search/?c=3&q=',
70 | 'windowUrlMatch': '[^\\w]q=([^&]+)'
71 | "resources": {
72 | styles: ['css/zdic.css']
73 | }
74 | }, {
75 | 'dictName': '百度词典(汉语)',
76 | 'entry': 'baidu-dict',
77 | 'windowUrl': 'http://dict.baidu.com/s?wd=',
78 | 'windowUrlMatch': '[^\\w]wd=([^&]+)'
79 | "resources": {
80 | styles: ['css/baidu-dict.css']
81 | }
82 | }, {
83 | 'dictName': 'Oxford Learner',
84 | 'entry': 'OxfordLearner',
85 | 'windowUrl': 'http://www.oxfordlearnersdictionaries.com/definition/english/'
86 | 'windowUrlMatch': '/english/([^&/?]+)'
87 | "resources": {
88 | styles: ['css/oxfordlearner.css']
89 | }
90 | }, {
91 | 'dictName': 'Oxford Living Dictionaries',
92 | 'entry': 'Oxfordliving',
93 | 'windowUrl': 'https://en.oxforddictionaries.com/definition/'
94 | 'windowUrlMatch': '/definition/([^&/?]+)'
95 | "resources": {
96 | styles: ['css/oxfordliving.css']
97 | }
98 | }, {
99 | 'dictName': 'Cambridge English'
100 | 'entry': 'CambridgeEnglish'
101 | 'windowUrl': 'http://dictionary.cambridge.org/dictionary/english/'
102 | 'windowUrlMatch': '/english/([^&/?]+)',
103 | "resources": {
104 | styles: ['css/cambridgeenglish.css']
105 | }
106 | }, {
107 | 'dictName': 'Longman English'
108 | 'entry': 'LongmanEnglish'
109 | 'windowUrl': 'http://www.ldoceonline.com/dictionary/'
110 | 'windowUrlMatch': '/dictionary/([^&/?]+)',
111 | "resources": {
112 | styles: ['css/longmanenglish.css']
113 | }
114 | }, {
115 | 'dictName': 'Urban Dictionary',
116 | 'windowUrl': 'http://zh.urbandictionary.com/define.php?term=',
117 | 'windowUrlMatch': '[^\\w]term=([^&]+)',
118 | "resources": {
119 | styles: ['css/urban.css']
120 | }
121 | }, {
122 | 'dictName': 'Dictionary.com',
123 | 'windowUrl': 'http://www.dictionary.com/browse/',
124 | 'windowUrlMatch': '/browse/([^&/?]+)',
125 | "resources": {
126 | styles: ['css/dictionary-com.css']
127 | }
128 | }, {
129 | 'dictName': 'Thesaurus.com',
130 | 'windowUrl': 'http://www.thesaurus.com/browse/',
131 | 'windowUrlMatch': '/browse/([^&/?]+)',
132 | "resources": {
133 | styles: ['css/dictionary-com.css']
134 | }
135 | }, {
136 | 'dictName': 'Macmilland Dictionary',
137 | 'windowUrl': 'http://www.macmillandictionary.com/dictionary/british/',
138 | 'windowUrlMatch': '/british/([^&/?]+)',
139 | "resources": {
140 | styles: ['css/macmilland.css']
141 | }
142 | }, {
143 | 'dictName': 'Merriam-webster Dictionary',
144 | 'windowUrl': 'https://www.merriam-webster.com/dictionary/',
145 | 'windowUrlMatch': '/dictionary/([^&/?]+)',
146 | "resources": {
147 | styles: ['css/merriamwebster.css']
148 | }
149 | }, {
150 | 'dictName': 'Merriam-webster Thesaurus',
151 | 'windowUrl': 'https://www.merriam-webster.com/thesaurus/',
152 | 'windowUrlMatch': '/thesaurus/([^&/?]+)',
153 | "resources": {
154 | styles: ['css/merriamwebster.css']
155 | }
156 | }, {
157 | 'dictName': 'Collins English Dictionary',
158 | 'windowUrl': 'https://www.collinsdictionary.com/dictionary/english/',
159 | 'windowUrlMatch': '/english/([^&/?]+)',
160 | "resources": {
161 | styles: ['css/collins.css']
162 | }
163 | }, {
164 | 'dictName': 'Collins English Thesaurus',
165 | 'windowUrl': 'https://www.collinsdictionary.com/dictionary/english-thesaurus/',
166 | 'windowUrlMatch': '/english-thesaurus/([^&/?]+)',
167 | "resources": {
168 | styles: ['css/collins.css']
169 | }
170 | }, {
171 | 'dictName': 'Easton\'s 1897 Bible Dictionary',
172 | 'entry': 'Aonaware',
173 | 'baseUrl': 'http://services.aonaware.com/DictService/DictService.asmx/DefineInDict',
174 | 'queryType': 'post',
175 | 'params': {
176 | 'dictId': 'easton'
177 | },
178 | 'queryKey': 'word'
179 | }]
180 |
181 | dictManager =
182 | allDicts: allDicts,
183 | getDict: (dictName)->
184 | dict = allDicts.find (d)->
185 | d.dictName == dictName
186 | return dict or allDicts[0]
187 |
188 | getDictResources: (dictName)->
189 | dict = @getDict(dictName)
190 | if dict.windowUrl
191 | # web dict
192 | return dict.resources
193 |
194 | getWordFromUrl: (url, dictName)->
195 | dict = @getDict(dictName)
196 | if dict.windowUrlMatch
197 | m = new RegExp(dict.windowUrlMatch)
198 | s = url?.match(m)?[1]
199 | if s
200 | s = s.replace(/[+_]/g, ' ')
201 | return decodeURI(s)
202 | return
203 |
204 | query: (word, dictName)->
205 | dfd = $.Deferred()
206 | dict = @getDict(dictName)
207 | params = $.extend(true, {}, dict.params)
208 | params[dict.queryKey] = word if dict.queryKey
209 | url = dict.baseUrl if dict.baseUrl
210 | url = dict.headerUrl + encodeURI(word) if dict.headerUrl
211 | if url
212 | return $[dict.queryType || 'get'](url, params, null, 'text').then (res)=>
213 | return {html: @['parse' + dict.entry](res)}
214 | else if dict.windowUrl
215 | return dfd.resolve {windowUrl: dict.windowUrl.replace('', word)}
216 | else
217 | return dfd.resolve({html: @['parse' + dict.entry](word)})
218 |
219 | queryWordPain: (word) ->
220 | url = "http://xtk.azurewebsites.net/BingDictService.aspx?Word=#{word}&Samples=false"
221 | return $.get(url)
222 |
223 | parseAonaware: (text)->
224 | xml = $.parseXML(text)
225 | return '' + $('Definitions WordDefinition', xml).text() + '
'
226 | parseIciba: (text)->
227 | d = $(document.createElement('div'))
228 | xml = $.parseXML(text)
229 | d.append('')
230 | $('ps', xml).each (index, el)->
231 | t = $(el).text()
232 | audio = $(el).next('pron').text()
233 | n = '' + t + ' ' + '    ' + ''
234 | $('h4', d).append(n)
235 |
236 | $('pos', xml).each (i, el)->
237 | m = $(el).next('acceptation').text()
238 | s = '' + $(el).text() + '' + m + '' + '
'
239 | d.append(s)
240 |
241 | $('orig, fy', xml).each (i, el)->
242 | m = $(el).next('trans').text()
243 | s = '' + $(el).text() + '
'
244 | s2 = '' + m + '
'
245 | d.append(s)
246 | d.append(s2)
247 |
248 | return d.html()
249 |
250 | parseWebster: (text)->
251 | wrapper = $(document.createElement('div'))
252 | wrapper.addClass('webster')
253 | xml = $.parseXML(text)
254 | $('entry', xml).each (index, entry)->
255 | entryId = $(entry).attr('id')
256 | wrapper.append('
')
257 | d = $('div[entry]', wrapper).last()
258 |
259 | pro = $('pr', entry).text()
260 |
261 | soundEl = $('sound', entry)
262 | audio = $('wav', soundEl).text()
263 | wpr = $('wpr', soundEl).text()
264 |
265 | baseUrl = 'http://media.merriam-webster.com/soundc11/'
266 | subp = audio[0]
267 | ms = audio.match(/^bix|^gg|^\d+/)
268 | if ms
269 | subp = ms[0]
270 |
271 | url = baseUrl + subp + '/' + audio
272 |
273 |
274 | n = '' +entryId+
275 | '' +
276 | '' + pro +
277 | ' ' +
278 | ' ' + wpr +
279 | '    
'
280 | d.append(n)
281 |
282 | et = $('et', entry).html()
283 | n2 = ''+et+'
'
284 | d.append(n2)
285 |
286 | $(entry).children('def').each (j, defEl)->
287 | vt = $('vt', defEl).text()
288 | date = $('date', defEl).text()
289 | d.append(''+vt+', '+date + '
')
290 | $('sn', defEl).each (k, snEl)->
291 | sntext = $(snEl).nextUtil('sn').text()
292 | d.append(''+sntext+'
')
293 |
294 | return wrapper.htm()
295 |
296 |
297 | return dictManager
298 |
--------------------------------------------------------------------------------
/background/dict.js:
--------------------------------------------------------------------------------
1 | // Generated by CoffeeScript 1.10.0
2 | define(["jquery", "utils"], function($, utils) {
3 | var allDicts, dictManager;
4 | console.log("[dict] init");
5 | allDicts = [
6 | {
7 | 'dictName': "必应词典",
8 | 'windowUrl': 'http://cn.bing.com/dict/search?q=',
9 | 'windowUrlMatch': '[^\\w]q=([^&]+)',
10 | "resources": {
11 | styles: ['css/bing.css']
12 | }
13 | }, {
14 | 'dictName': '金山词霸',
15 | 'windowUrl': 'http://www.iciba.com/',
16 | 'windowUrlMatch': 'iciba.com/([^&]+)',
17 | "resources": {
18 | styles: ['css/iciba.css']
19 | }
20 | }, {
21 | 'dictName': '有道词典',
22 | 'entry': 'youdao',
23 | 'windowUrl': 'http://dict.youdao.com/w/eng/',
24 | 'windowUrlMatch': '/eng/([^&/?]+)',
25 | "resources": {
26 | styles: ['css/youdao.css']
27 | }
28 | }, {
29 | 'dictName': '海词词典',
30 | 'entry': 'dict-cn',
31 | 'windowUrl': 'http://dict.cn/',
32 | 'windowUrlMatch': 'dict.cn/([^&/?]+)',
33 | "resources": {
34 | styles: ['css/dict-cn.css']
35 | }
36 | }, {
37 | 'dictName': '沪江词典',
38 | 'entry': 'hjenglish',
39 | 'windowUrl': 'https://dict.hjenglish.com/w/',
40 | 'windowUrlMatch': '/w/([^&/?]+)',
41 | "resources": {
42 | styles: ['css/hjenglish.css']
43 | }
44 | }, {
45 | 'dictName': '人人词典',
46 | 'entry': '91dict',
47 | 'windowUrl': 'http://www.91dict.com/words?w=',
48 | 'windowUrlMatch': '[^\\w]w=([^&]+)',
49 | "resources": {
50 | styles: ['css/91dict.css']
51 | }
52 | }, {
53 | 'dictName': '欧陆词典',
54 | 'entry': 'eudic',
55 | 'windowUrl': 'https://dict.eudic.net/dicts/en/',
56 | 'windowUrlMatch': '/en/([^&/?]+)',
57 | "resources": {
58 | styles: ['css/eudic.css']
59 | }
60 | }, {
61 | 'dictName': '汉典',
62 | 'entry': 'zdic',
63 | 'windowUrl': 'http://www.zdic.net/search/?c=3&q=',
64 | 'windowUrlMatch': '[^\\w]q=([^&]+)',
65 | "resources": {
66 | styles: ['css/zdic.css']
67 | }
68 | }, {
69 | 'dictName': '百度词典(汉语)',
70 | 'entry': 'baidu-dict',
71 | 'windowUrl': 'http://dict.baidu.com/s?wd=',
72 | 'windowUrlMatch': '[^\\w]wd=([^&]+)',
73 | "resources": {
74 | styles: ['css/baidu-dict.css']
75 | }
76 | }, {
77 | 'dictName': 'Oxford Learner',
78 | 'entry': 'OxfordLearner',
79 | 'windowUrl': 'http://www.oxfordlearnersdictionaries.com/definition/english/',
80 | 'windowUrlMatch': '/english/([^&/?]+)',
81 | "resources": {
82 | styles: ['css/oxfordlearner.css']
83 | }
84 | }, {
85 | 'dictName': 'Oxford Living Dictionaries',
86 | 'entry': 'Oxfordliving',
87 | 'windowUrl': 'https://en.oxforddictionaries.com/definition/',
88 | 'windowUrlMatch': '/definition/([^&/?]+)',
89 | "resources": {
90 | styles: ['css/oxfordliving.css']
91 | }
92 | }, {
93 | 'dictName': 'Cambridge English',
94 | 'entry': 'CambridgeEnglish',
95 | 'windowUrl': 'http://dictionary.cambridge.org/dictionary/english/',
96 | 'windowUrlMatch': '/english/([^&/?]+)',
97 | "resources": {
98 | styles: ['css/cambridgeenglish.css']
99 | }
100 | }, {
101 | 'dictName': 'Longman English',
102 | 'entry': 'LongmanEnglish',
103 | 'windowUrl': 'http://www.ldoceonline.com/dictionary/',
104 | 'windowUrlMatch': '/dictionary/([^&/?]+)',
105 | "resources": {
106 | styles: ['css/longmanenglish.css']
107 | }
108 | }, {
109 | 'dictName': 'Urban Dictionary',
110 | 'windowUrl': 'http://zh.urbandictionary.com/define.php?term=',
111 | 'windowUrlMatch': '[^\\w]term=([^&]+)',
112 | "resources": {
113 | styles: ['css/urban.css']
114 | }
115 | }, {
116 | 'dictName': 'Dictionary.com',
117 | 'windowUrl': 'http://www.dictionary.com/browse/',
118 | 'windowUrlMatch': '/browse/([^&/?]+)',
119 | "resources": {
120 | styles: ['css/dictionary-com.css']
121 | }
122 | }, {
123 | 'dictName': 'Thesaurus.com',
124 | 'windowUrl': 'http://www.thesaurus.com/browse/',
125 | 'windowUrlMatch': '/browse/([^&/?]+)',
126 | "resources": {
127 | styles: ['css/dictionary-com.css']
128 | }
129 | }, {
130 | 'dictName': 'Macmilland Dictionary',
131 | 'windowUrl': 'http://www.macmillandictionary.com/dictionary/british/',
132 | 'windowUrlMatch': '/british/([^&/?]+)',
133 | "resources": {
134 | styles: ['css/macmilland.css']
135 | }
136 | }, {
137 | 'dictName': 'Merriam-webster Dictionary',
138 | 'windowUrl': 'https://www.merriam-webster.com/dictionary/',
139 | 'windowUrlMatch': '/dictionary/([^&/?]+)',
140 | "resources": {
141 | styles: ['css/merriamwebster.css']
142 | }
143 | }, {
144 | 'dictName': 'Merriam-webster Thesaurus',
145 | 'windowUrl': 'https://www.merriam-webster.com/thesaurus/',
146 | 'windowUrlMatch': '/thesaurus/([^&/?]+)',
147 | "resources": {
148 | styles: ['css/merriamwebster.css']
149 | }
150 | }, {
151 | 'dictName': 'Collins English Dictionary',
152 | 'windowUrl': 'https://www.collinsdictionary.com/dictionary/english/',
153 | 'windowUrlMatch': '/english/([^&/?]+)',
154 | "resources": {
155 | styles: ['css/collins.css']
156 | }
157 | }, {
158 | 'dictName': 'Collins English Thesaurus',
159 | 'windowUrl': 'https://www.collinsdictionary.com/dictionary/english-thesaurus/',
160 | 'windowUrlMatch': '/english-thesaurus/([^&/?]+)',
161 | "resources": {
162 | styles: ['css/collins.css']
163 | }
164 | }, {
165 | 'dictName': 'Easton\'s 1897 Bible Dictionary',
166 | 'entry': 'Aonaware',
167 | 'baseUrl': 'http://services.aonaware.com/DictService/DictService.asmx/DefineInDict',
168 | 'queryType': 'post',
169 | 'params': {
170 | 'dictId': 'easton'
171 | },
172 | 'queryKey': 'word'
173 | }
174 | ];
175 | dictManager = {
176 | allDicts: allDicts,
177 | getDict: function(dictName) {
178 | var dict;
179 | dict = allDicts.find(function(d) {
180 | return d.dictName === dictName;
181 | });
182 | return dict || allDicts[0];
183 | },
184 | getDictResources: function(dictName) {
185 | var dict;
186 | dict = this.getDict(dictName);
187 | if (dict.windowUrl) {
188 | return dict.resources;
189 | }
190 | },
191 | getWordFromUrl: function(url, dictName) {
192 | var dict, m, ref, s;
193 | dict = this.getDict(dictName);
194 | if (dict.windowUrlMatch) {
195 | m = new RegExp(dict.windowUrlMatch);
196 | s = url != null ? (ref = url.match(m)) != null ? ref[1] : void 0 : void 0;
197 | if (s) {
198 | s = s.replace(/[+_]/g, ' ');
199 | return decodeURI(s);
200 | }
201 | }
202 | },
203 | query: function(word, dictName) {
204 | var dfd, dict, params, url;
205 | dfd = $.Deferred();
206 | dict = this.getDict(dictName);
207 | params = $.extend(true, {}, dict.params);
208 | if (dict.queryKey) {
209 | params[dict.queryKey] = word;
210 | }
211 | if (dict.baseUrl) {
212 | url = dict.baseUrl;
213 | }
214 | if (dict.headerUrl) {
215 | url = dict.headerUrl + encodeURI(word);
216 | }
217 | if (url) {
218 | return $[dict.queryType || 'get'](url, params, null, 'text').then((function(_this) {
219 | return function(res) {
220 | return {
221 | html: _this['parse' + dict.entry](res)
222 | };
223 | };
224 | })(this));
225 | } else if (dict.windowUrl) {
226 | return dfd.resolve({
227 | windowUrl: dict.windowUrl.replace('', word)
228 | });
229 | } else {
230 | return dfd.resolve({
231 | html: this['parse' + dict.entry](word)
232 | });
233 | }
234 | },
235 | queryWordPain: function(word) {
236 | var url;
237 | url = "http://xtk.azurewebsites.net/BingDictService.aspx?Word=" + word + "&Samples=false";
238 | return $.get(url);
239 | },
240 | parseAonaware: function(text) {
241 | var xml;
242 | xml = $.parseXML(text);
243 | return '' + $('Definitions WordDefinition', xml).text() + '
';
244 | },
245 | parseIciba: function(text) {
246 | var d, xml;
247 | d = $(document.createElement('div'));
248 | xml = $.parseXML(text);
249 | d.append('');
250 | $('ps', xml).each(function(index, el) {
251 | var audio, n, t;
252 | t = $(el).text();
253 | audio = $(el).next('pron').text();
254 | n = '' + t + ' ' + '    ' + '';
255 | return $('h4', d).append(n);
256 | });
257 | $('pos', xml).each(function(i, el) {
258 | var m, s;
259 | m = $(el).next('acceptation').text();
260 | s = '' + $(el).text() + '' + m + '' + '
';
261 | return d.append(s);
262 | });
263 | $('orig, fy', xml).each(function(i, el) {
264 | var m, s, s2;
265 | m = $(el).next('trans').text();
266 | s = '' + $(el).text() + '
';
267 | s2 = '' + m + '
';
268 | d.append(s);
269 | return d.append(s2);
270 | });
271 | return d.html();
272 | },
273 | parseWebster: function(text) {
274 | var wrapper, xml;
275 | wrapper = $(document.createElement('div'));
276 | wrapper.addClass('webster');
277 | xml = $.parseXML(text);
278 | $('entry', xml).each(function(index, entry) {
279 | var audio, baseUrl, d, entryId, et, ms, n, n2, pro, soundEl, subp, url, wpr;
280 | entryId = $(entry).attr('id');
281 | wrapper.append('
');
282 | d = $('div[entry]', wrapper).last();
283 | pro = $('pr', entry).text();
284 | soundEl = $('sound', entry);
285 | audio = $('wav', soundEl).text();
286 | wpr = $('wpr', soundEl).text();
287 | baseUrl = 'http://media.merriam-webster.com/soundc11/';
288 | subp = audio[0];
289 | ms = audio.match(/^bix|^gg|^\d+/);
290 | if (ms) {
291 | subp = ms[0];
292 | }
293 | url = baseUrl + subp + '/' + audio;
294 | n = '' + entryId + '' + '' + pro + ' ' + ' ' + wpr + '    
';
295 | d.append(n);
296 | et = $('et', entry).html();
297 | n2 = '' + et + '
';
298 | d.append(n2);
299 | return $(entry).children('def').each(function(j, defEl) {
300 | var date, vt;
301 | vt = $('vt', defEl).text();
302 | date = $('date', defEl).text();
303 | d.append('' + vt + ', ' + date + '
');
304 | return $('sn', defEl).each(function(k, snEl) {
305 | var sntext;
306 | sntext = $(snEl).nextUtil('sn').text();
307 | return d.append('' + sntext + '
');
308 | });
309 | });
310 | });
311 | return wrapper.htm();
312 | }
313 | };
314 | return dictManager;
315 | });
316 |
--------------------------------------------------------------------------------
/background/dict_resources.coffee:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/revir/FairyDict/ac7722ceda402af1cf420cf7077a06c341e5d5d9/background/dict_resources.coffee
--------------------------------------------------------------------------------
/background/dict_resources.js:
--------------------------------------------------------------------------------
1 | // Generated by CoffeeScript 1.10.0
2 |
3 |
--------------------------------------------------------------------------------
/background/dictwindow.coffee:
--------------------------------------------------------------------------------
1 | define ["jquery",
2 | "utils",
3 | "background/setting",
4 | "background/dict.js",
5 | "background/storage"], ($, utils, setting, dict, storage)->
6 | console.log "[dictwindow] init"
7 | defaultWindowUrl = chrome.extension.getURL('template/apidict.html')
8 | updateWindowDfd = null
9 | injectContentDfd = null
10 | dictInitedDfd = null
11 | windowType = 'popup'
12 |
13 | dictWindowManager =
14 | w: null
15 | tid: null
16 | url: null
17 | word: null
18 | open: ()->
19 | dfd = $.Deferred()
20 |
21 | # bugfix: dont know how why, windowWidth and windowHeight are saved as number, need integer here.
22 | width = parseInt(setting.getValue('windowWidth'))
23 | height = parseInt(setting.getValue('windowHeight'))
24 | left = Math.round((screen.width / 2) - (width / 2))
25 | top = Math.round((screen.height / 2) - (height / 2))
26 | url = 'http://blog.riverrun.xyz/fairydict.html'
27 | if !@w
28 | @beforeUpdateUrl()
29 | chrome.windows.create({
30 | url: defaultWindowUrl,
31 | # url: 'http://cn.bing.com/dict/search?q=elephant',
32 | type: windowType,
33 | width: width,
34 | height: height,
35 | left: left,
36 | top: top
37 | }, (win)=>
38 | @w = win
39 | @tid = @w.tabs[0].id
40 | @url = defaultWindowUrl
41 | dfd.resolve()
42 | )
43 | else
44 | chrome.windows.update(dictWindowManager.w.id, {
45 | focused: true
46 | })
47 | dfd.resolve()
48 |
49 | return dfd
50 |
51 | sendMessage: (msg)->
52 | chrome.tabs.sendMessage(@tid, msg) if @tid
53 |
54 | lookup: (text)->
55 | dictName = setting.getValue('dictionary')
56 | @open().done ()=>
57 | if text
58 | @sendMessage({type: 'querying', text})
59 | @queryDict(text, dictName)
60 |
61 | queryDict: (text, dictName, inHistory)->
62 | @word = text
63 | if not inHistory
64 | @sendMessage({type: 'history', history: storage.history})
65 |
66 | console.log "[dictwindow] query #{@word} from #{dictName}"
67 | dict.query(text, dictName).then @sendQueryResult.bind(this)
68 |
69 | saveWindowSize: ()->
70 | chrome.windows.get @w.id, null, (w)=>
71 | if w?.width and w?.height
72 | if Math.abs(w.width-setting.getValue('windowWidth')) > 10 or Math.abs(w.height-setting.getValue('windowHeight')) > 10
73 | console.log "[dictwindow] update window size: #{w.width} * #{w.height}"
74 | setting.setValue 'windowWidth', w.width
75 | setting.setValue 'windowHeight', w.height
76 |
77 | sendQueryResult: (result)->
78 | @saveWindowSize()
79 | item = storage.isInHistory(@word)
80 | if result
81 | udfd = @updateUrl(result.windowUrl or defaultWindowUrl)
82 |
83 | $.when(updateWindowDfd, dictInitedDfd, udfd).then ()=>
84 | console.log "[dictwindow] send query result"
85 | @sendMessage({
86 | type: 'queryResult',
87 | result: result,
88 | text: @word,
89 | inHistory: item?,
90 | rating: item?[@word]})
91 |
92 | # if @word is a long sentence, don't keep in history
93 | if not item and @word.split(/\s+/).length <= 5
94 | storage.addHistory(@word)
95 |
96 | injectResources: ()->
97 | styles = [
98 | "css/bootstrap.css",
99 | "bower_components/angular-ui/build/angular-ui.css",
100 | "bower_components/angular-bootstrap/ui-bootstrap-csp.css",
101 | "css/font-awesome.css",
102 | "css/dictheader.css"
103 | ]
104 | scripts = [
105 | 'bower_components/jquery/dist/jquery.js',
106 | 'bower_components/underscore/underscore.js',
107 | "bower_components/angular/angular.js",
108 | "bower_components/angular-ui/build/angular-ui.js",
109 | "bower_components/angular-sanitize/angular-sanitize.js",
110 | "bower_components/angular-bootstrap/ui-bootstrap.js",
111 | "utils.js",
112 | "js/starrr.js",
113 | "loader.js",
114 | "dict.js"
115 | ]
116 |
117 | inject = (t, files, index)=>
118 | files ?= []
119 | index ?= 0
120 | dfd = $.Deferred()
121 | file = files[index]
122 | if file and t and @tid
123 | console.log "[dictwindow] inject #{file}"
124 | chrome.tabs[t] @tid, {file: file}, ()=>
125 | inject(t, files, index+1).then ()=>
126 | dfd.resolve()
127 | else
128 | dfd.resolve()
129 | return dfd
130 |
131 | res = dict.getDictResources(setting.getValue('dictionary'))
132 |
133 | # chrome-extension:// can't inject files, permission denied.
134 | if @url.indexOf('chrome-extension://') == 0
135 | return inject(null)
136 |
137 | return inject('insertCSS', res?.styles).then ()=>
138 | return inject('insertCSS', styles).then ()=>
139 | return inject('executeScript', scripts).then ()=>
140 | return inject('executeScript', res?.scripts)
141 |
142 | updateUrl: (url)->
143 | outDfd = $.Deferred()
144 | if url and @url != url
145 | console.log "[dictwindow] update url: #{url}"
146 | @url = url
147 | @beforeUpdateUrl().then ()=>
148 | console.log "[dictwindow] updated url: #{url}"
149 | outDfd.resolve(true)
150 | chrome.tabs.update @tid, {url, active: true}
151 | return outDfd
152 | else
153 | return outDfd.resolve(false)
154 |
155 | beforeUpdateUrl: ()->
156 | injectContentDfd = $.Deferred((dfd)=>
157 | dfd.then ()=>
158 | return @injectResources().then ()=>
159 | updateWindowDfd?.resolve()
160 | )
161 | dictInitedDfd = $.Deferred()
162 | updateWindowDfd = $.Deferred()
163 | return updateWindowDfd
164 |
165 | onContentInjected: (url, tabId)->
166 | console.log "[dictwindow] manifest's content scripts injected from url: #{url}"
167 | if injectContentDfd?.state() == 'pending'
168 | injectContentDfd.resolve()
169 |
170 | # page was reloaded.
171 | else if url and tabId == @tid
172 | d = setting.getValue('dictionary')
173 | w = dict.getWordFromUrl(url, d)
174 | @url = url
175 | if w
176 | @word = w
177 | else
178 | w = @word
179 |
180 | dictInitedDfd = $.Deferred()
181 | updateWindowDfd = $.Deferred()
182 | console.log "[dictwindow] reload #{w} url #{url}"
183 |
184 | @injectResources().then ()=>
185 | if @url == defaultWindowUrl
186 | dict.query(@word, d).then @sendQueryResult.bind(@)
187 | else
188 | @sendQueryResult()
189 | updateWindowDfd.resolve()
190 |
191 | onDictInited: ()->
192 | console.log "[dictwindow] dict inited"
193 | dictInitedDfd?.resolve()
194 | @sendMessage({type: 'history', history: storage.history})
195 |
196 |
197 | chrome.windows.onRemoved.addListener (wid)->
198 | if dictWindowManager.w?.id == wid
199 | dictWindowManager.w = null
200 | dictWindowManager.tid = null
201 | updateWindowDfd = null
202 | injectContentDfd = null
203 | dictInitedDfd = null
204 |
205 | # chrome.tabs.onUpdated.addListener (tabId, info)->
206 | # if dictWindowManager.tid == tabId
207 | # dictWindowManager.onReload(info.url)
208 |
209 |
210 | return dictWindowManager
211 |
--------------------------------------------------------------------------------
/background/dictwindow.js:
--------------------------------------------------------------------------------
1 | // Generated by CoffeeScript 1.10.0
2 | define(["jquery", "utils", "background/setting", "background/dict.js", "background/storage"], function($, utils, setting, dict, storage) {
3 | var defaultWindowUrl, dictInitedDfd, dictWindowManager, injectContentDfd, updateWindowDfd, windowType;
4 | console.log("[dictwindow] init");
5 | defaultWindowUrl = chrome.extension.getURL('template/apidict.html');
6 | updateWindowDfd = null;
7 | injectContentDfd = null;
8 | dictInitedDfd = null;
9 | windowType = 'popup';
10 | dictWindowManager = {
11 | w: null,
12 | tid: null,
13 | url: null,
14 | word: null,
15 | open: function() {
16 | var dfd, height, left, top, url, width;
17 | dfd = $.Deferred();
18 | width = parseInt(setting.getValue('windowWidth'));
19 | height = parseInt(setting.getValue('windowHeight'));
20 | left = Math.round((screen.width / 2) - (width / 2));
21 | top = Math.round((screen.height / 2) - (height / 2));
22 | url = 'http://blog.riverrun.xyz/fairydict.html';
23 | if (!this.w) {
24 | this.beforeUpdateUrl();
25 | chrome.windows.create({
26 | url: defaultWindowUrl,
27 | type: windowType,
28 | width: width,
29 | height: height,
30 | left: left,
31 | top: top
32 | }, (function(_this) {
33 | return function(win) {
34 | _this.w = win;
35 | _this.tid = _this.w.tabs[0].id;
36 | _this.url = defaultWindowUrl;
37 | return dfd.resolve();
38 | };
39 | })(this));
40 | } else {
41 | chrome.windows.update(dictWindowManager.w.id, {
42 | focused: true
43 | });
44 | dfd.resolve();
45 | }
46 | return dfd;
47 | },
48 | sendMessage: function(msg) {
49 | if (this.tid) {
50 | return chrome.tabs.sendMessage(this.tid, msg);
51 | }
52 | },
53 | lookup: function(text) {
54 | var dictName;
55 | dictName = setting.getValue('dictionary');
56 | return this.open().done((function(_this) {
57 | return function() {
58 | if (text) {
59 | _this.sendMessage({
60 | type: 'querying',
61 | text: text
62 | });
63 | return _this.queryDict(text, dictName);
64 | }
65 | };
66 | })(this));
67 | },
68 | queryDict: function(text, dictName, inHistory) {
69 | this.word = text;
70 | if (!inHistory) {
71 | this.sendMessage({
72 | type: 'history',
73 | history: storage.history
74 | });
75 | }
76 | console.log("[dictwindow] query " + this.word + " from " + dictName);
77 | return dict.query(text, dictName).then(this.sendQueryResult.bind(this));
78 | },
79 | saveWindowSize: function() {
80 | return chrome.windows.get(this.w.id, null, (function(_this) {
81 | return function(w) {
82 | if ((w != null ? w.width : void 0) && (w != null ? w.height : void 0)) {
83 | if (Math.abs(w.width - setting.getValue('windowWidth')) > 10 || Math.abs(w.height - setting.getValue('windowHeight')) > 10) {
84 | console.log("[dictwindow] update window size: " + w.width + " * " + w.height);
85 | setting.setValue('windowWidth', w.width);
86 | return setting.setValue('windowHeight', w.height);
87 | }
88 | }
89 | };
90 | })(this));
91 | },
92 | sendQueryResult: function(result) {
93 | var item, udfd;
94 | this.saveWindowSize();
95 | item = storage.isInHistory(this.word);
96 | if (result) {
97 | udfd = this.updateUrl(result.windowUrl || defaultWindowUrl);
98 | }
99 | return $.when(updateWindowDfd, dictInitedDfd, udfd).then((function(_this) {
100 | return function() {
101 | console.log("[dictwindow] send query result");
102 | _this.sendMessage({
103 | type: 'queryResult',
104 | result: result,
105 | text: _this.word,
106 | inHistory: item != null,
107 | rating: item != null ? item[_this.word] : void 0
108 | });
109 | if (!item && _this.word.split(/\s+/).length <= 5) {
110 | return storage.addHistory(_this.word);
111 | }
112 | };
113 | })(this));
114 | },
115 | injectResources: function() {
116 | var inject, res, scripts, styles;
117 | styles = ["css/bootstrap.css", "bower_components/angular-ui/build/angular-ui.css", "bower_components/angular-bootstrap/ui-bootstrap-csp.css", "css/font-awesome.css", "css/dictheader.css"];
118 | scripts = ['bower_components/jquery/dist/jquery.js', 'bower_components/underscore/underscore.js', "bower_components/angular/angular.js", "bower_components/angular-ui/build/angular-ui.js", "bower_components/angular-sanitize/angular-sanitize.js", "bower_components/angular-bootstrap/ui-bootstrap.js", "utils.js", "js/starrr.js", "loader.js", "dict.js"];
119 | inject = (function(_this) {
120 | return function(t, files, index) {
121 | var dfd, file;
122 | if (files == null) {
123 | files = [];
124 | }
125 | if (index == null) {
126 | index = 0;
127 | }
128 | dfd = $.Deferred();
129 | file = files[index];
130 | if (file && t && _this.tid) {
131 | console.log("[dictwindow] inject " + file);
132 | chrome.tabs[t](_this.tid, {
133 | file: file
134 | }, function() {
135 | return inject(t, files, index + 1).then(function() {
136 | return dfd.resolve();
137 | });
138 | });
139 | } else {
140 | dfd.resolve();
141 | }
142 | return dfd;
143 | };
144 | })(this);
145 | res = dict.getDictResources(setting.getValue('dictionary'));
146 | if (this.url.indexOf('chrome-extension://') === 0) {
147 | return inject(null);
148 | }
149 | return inject('insertCSS', res != null ? res.styles : void 0).then((function(_this) {
150 | return function() {
151 | return inject('insertCSS', styles).then(function() {
152 | return inject('executeScript', scripts).then(function() {
153 | return inject('executeScript', res != null ? res.scripts : void 0);
154 | });
155 | });
156 | };
157 | })(this));
158 | },
159 | updateUrl: function(url) {
160 | var outDfd;
161 | outDfd = $.Deferred();
162 | if (url && this.url !== url) {
163 | console.log("[dictwindow] update url: " + url);
164 | this.url = url;
165 | this.beforeUpdateUrl().then((function(_this) {
166 | return function() {
167 | console.log("[dictwindow] updated url: " + url);
168 | return outDfd.resolve(true);
169 | };
170 | })(this));
171 | chrome.tabs.update(this.tid, {
172 | url: url,
173 | active: true
174 | });
175 | return outDfd;
176 | } else {
177 | return outDfd.resolve(false);
178 | }
179 | },
180 | beforeUpdateUrl: function() {
181 | injectContentDfd = $.Deferred((function(_this) {
182 | return function(dfd) {
183 | return dfd.then(function() {
184 | return _this.injectResources().then(function() {
185 | return updateWindowDfd != null ? updateWindowDfd.resolve() : void 0;
186 | });
187 | });
188 | };
189 | })(this));
190 | dictInitedDfd = $.Deferred();
191 | updateWindowDfd = $.Deferred();
192 | return updateWindowDfd;
193 | },
194 | onContentInjected: function(url, tabId) {
195 | var d, w;
196 | console.log("[dictwindow] manifest's content scripts injected from url: " + url);
197 | if ((injectContentDfd != null ? injectContentDfd.state() : void 0) === 'pending') {
198 | return injectContentDfd.resolve();
199 | } else if (url && tabId === this.tid) {
200 | d = setting.getValue('dictionary');
201 | w = dict.getWordFromUrl(url, d);
202 | this.url = url;
203 | if (w) {
204 | this.word = w;
205 | } else {
206 | w = this.word;
207 | }
208 | dictInitedDfd = $.Deferred();
209 | updateWindowDfd = $.Deferred();
210 | console.log("[dictwindow] reload " + w + " url " + url);
211 | return this.injectResources().then((function(_this) {
212 | return function() {
213 | if (_this.url === defaultWindowUrl) {
214 | dict.query(_this.word, d).then(_this.sendQueryResult.bind(_this));
215 | } else {
216 | _this.sendQueryResult();
217 | }
218 | return updateWindowDfd.resolve();
219 | };
220 | })(this));
221 | }
222 | },
223 | onDictInited: function() {
224 | console.log("[dictwindow] dict inited");
225 | if (dictInitedDfd != null) {
226 | dictInitedDfd.resolve();
227 | }
228 | return this.sendMessage({
229 | type: 'history',
230 | history: storage.history
231 | });
232 | }
233 | };
234 | chrome.windows.onRemoved.addListener(function(wid) {
235 | var ref;
236 | if (((ref = dictWindowManager.w) != null ? ref.id : void 0) === wid) {
237 | dictWindowManager.w = null;
238 | dictWindowManager.tid = null;
239 | updateWindowDfd = null;
240 | injectContentDfd = null;
241 | return dictInitedDfd = null;
242 | }
243 | });
244 | return dictWindowManager;
245 | });
246 |
--------------------------------------------------------------------------------
/background/ext.coffee:
--------------------------------------------------------------------------------
1 | define ["jquery",
2 | "utils",
3 | "background/setting"], ($, utils, setting)->
4 | console.log "[ext] init"
5 |
6 | return {
7 | setBrowserIcon: (enable)->
8 | title = 'FairyDict: 已打开鼠标取词功能'
9 | imgPath = 'images/books-96.png'
10 | if !enable
11 | title = 'FairyDict: 已关闭鼠标取词功能'
12 | imgPath = 'images/books-96.png'
13 |
14 | chrome.browserAction.setTitle({
15 | title: title
16 | })
17 | chrome.browserAction.setIcon({
18 | path: imgPath
19 | })
20 | }
21 |
--------------------------------------------------------------------------------
/background/ext.js:
--------------------------------------------------------------------------------
1 | define(["jquery", "utils", "background/setting"], function($, utils, setting) {
2 | console.log("[ext] init");
3 | return {
4 | setBrowserIcon: function(enable) {
5 | var imgPath, title;
6 | title = 'FairyDict: 已打开鼠标取词功能';
7 | imgPath = 'images/books-96.png';
8 | if (!enable) {
9 | title = 'FairyDict: 已关闭鼠标取词功能';
10 | imgPath = 'images/books-96.png';
11 | }
12 | chrome.browserAction.setTitle({
13 | title: title
14 | });
15 | return chrome.browserAction.setIcon({
16 | path: imgPath
17 | });
18 | }
19 | };
20 | });
21 |
--------------------------------------------------------------------------------
/background/main.coffee:
--------------------------------------------------------------------------------
1 | require.config({
2 | baseUrl: ""
3 | paths:
4 | "jquery": "bower_components/jquery/dist/jquery",
5 | "utils": "utils"
6 | shim:
7 | utils:
8 | "exports": "utils"
9 |
10 | })
11 |
12 | require ["jquery",
13 | "utils",
14 | "background/setting",
15 | "background/ext",
16 | "background/storage",
17 | "background/dictwindow.js",
18 | "background/message.js"], ($, utils, setting, ext, storage, dictWindow, message)->
19 |
20 | onClickedContextMenu = (info, tab)->
21 | if info.selectionText
22 | dictWindow.lookup(info.selectionText)
23 |
24 | chrome.browserAction.onClicked.addListener (tab)->
25 | if setting.getValue('browserActionType') == 'openDictWindow'
26 | return dictWindow.lookup()
27 |
28 | b = !setting.getValue('enableMinidict')
29 | setting.setValue('enableMinidict', b)
30 | ext.setBrowserIcon(b)
31 |
32 | setting.init().done (c)->
33 | ext.setBrowserIcon(c.enableMinidict)
34 |
35 | storage.init()
36 |
37 | chrome.contextMenus.create {
38 | title: "使用 FairyDict 查询 '%s'",
39 | contexts: ["selection"],
40 | onclick: onClickedContextMenu
41 | }
42 |
43 |
--------------------------------------------------------------------------------
/background/main.js:
--------------------------------------------------------------------------------
1 | // Generated by CoffeeScript 1.10.0
2 | require.config({
3 | baseUrl: "",
4 | paths: {
5 | "jquery": "bower_components/jquery/dist/jquery",
6 | "utils": "utils"
7 | },
8 | shim: {
9 | utils: {
10 | "exports": "utils"
11 | }
12 | }
13 | });
14 |
15 | require(["jquery", "utils", "background/setting", "background/ext", "background/storage", "background/dictwindow.js", "background/message.js"], function($, utils, setting, ext, storage, dictWindow, message) {
16 | var onClickedContextMenu;
17 | onClickedContextMenu = function(info, tab) {
18 | if (info.selectionText) {
19 | return dictWindow.lookup(info.selectionText);
20 | }
21 | };
22 | chrome.browserAction.onClicked.addListener(function(tab) {
23 | var b;
24 | if (setting.getValue('browserActionType') === 'openDictWindow') {
25 | return dictWindow.lookup();
26 | }
27 | b = !setting.getValue('enableMinidict');
28 | setting.setValue('enableMinidict', b);
29 | return ext.setBrowserIcon(b);
30 | });
31 | setting.init().done(function(c) {
32 | return ext.setBrowserIcon(c.enableMinidict);
33 | });
34 | storage.init();
35 | return chrome.contextMenus.create({
36 | title: "使用 FairyDict 查询 '%s'",
37 | contexts: ["selection"],
38 | onclick: onClickedContextMenu
39 | });
40 | });
41 |
--------------------------------------------------------------------------------
/background/message.coffee:
--------------------------------------------------------------------------------
1 | define ["jquery",
2 | "utils",
3 | "background/setting",
4 | "background/ext",
5 | "background/storage",
6 | "background/dict.js",
7 | "background/plain-lookup.js",
8 | "background/dictwindow.js"], ($, utils, setting, ext, storage, dict, plainLookup, dictWindow)->
9 | console.log "[message] init"
10 |
11 | chrome.runtime.onMessage.addListener (request, sender, sendResponse)->
12 | if request.type == 'getJson'
13 | utils.getJson(request.url, request.data).then ((res)->
14 | sendResponse(res)), sendResponse
15 | else if request.type == 'postJson'
16 | utils.postJson(request.url, request.data).then ((res)->
17 | sendResponse(res)), sendResponse
18 | else if request.type == 'look up'
19 | if request.means == 'mouse'
20 | if not setting.getValue('enableMinidict')
21 | return true
22 |
23 | dictWindow.lookup(request.text)
24 |
25 | else if request.type == 'look up pain'
26 | res = dict.getDict('必应词典')
27 | url = res.windowUrl.replace('', request.text)
28 | plainLookup.parseBing(url).then sendResponse, sendResponse
29 |
30 | else if request.type == 'query'
31 | setting.setValue('dictionary', request.dictionary) if request.dictionary
32 | dictWindow.queryDict(request.text, request.dictionary, request.inHistory)
33 |
34 | else if request.type == 'dictionary'
35 | dictionary = setting.getValue('dictionary')
36 | history = storage.history
37 | sendResponse {allDicts: dict.allDicts, dictionary, history}
38 | dictWindow.onDictInited()
39 |
40 | else if request.type == 'setting'
41 | sendResponse setting.configCache
42 |
43 | else if request.type == 'save setting'
44 | setting.setValue(request.key, request.value)
45 | if request.key == 'enableMinidict'
46 | ext.setBrowserIcon request.value
47 |
48 | else if request.type == 'rating'
49 | storage.addRating request.text, request.value
50 |
51 | else if request.type == 'deleteHistory'
52 | storage.deleteHistory(request.text)
53 |
54 | else if request.type == 'injected'
55 | dictWindow.onContentInjected(request.url, sender.tab.id)
56 |
57 | # sendResponse becomes invalid when the event listener returns,
58 | # unless you return true from the event listener to indicate you wish to send a response asynchronously
59 | return true
60 |
--------------------------------------------------------------------------------
/background/message.js:
--------------------------------------------------------------------------------
1 | define(["jquery", "utils", "background/setting", "background/ext", "background/storage", "background/dict.js", "background/plain-lookup.js", "background/dictwindow.js"], function($, utils, setting, ext, storage, dict, plainLookup, dictWindow) {
2 | console.log("[message] init");
3 | return chrome.runtime.onMessage.addListener(function(request, sender, sendResponse) {
4 | var dictionary, history, res, url;
5 | if (request.type === 'getJson') {
6 | utils.getJson(request.url, request.data).then((function(res) {
7 | return sendResponse(res);
8 | }), sendResponse);
9 | } else if (request.type === 'postJson') {
10 | utils.postJson(request.url, request.data).then((function(res) {
11 | return sendResponse(res);
12 | }), sendResponse);
13 | } else if (request.type === 'look up') {
14 | if (request.means === 'mouse') {
15 | if (!setting.getValue('enableMinidict')) {
16 | return true;
17 | }
18 | }
19 | dictWindow.lookup(request.text);
20 | } else if (request.type === 'look up pain') {
21 | res = dict.getDict('必应词典');
22 | url = res.windowUrl.replace('', request.text);
23 | plainLookup.parseBing(url).then(sendResponse, sendResponse);
24 | } else if (request.type === 'query') {
25 | if (request.dictionary) {
26 | setting.setValue('dictionary', request.dictionary);
27 | }
28 | dictWindow.queryDict(request.text, request.dictionary, request.inHistory);
29 | } else if (request.type === 'dictionary') {
30 | dictionary = setting.getValue('dictionary');
31 | history = storage.history;
32 | sendResponse({
33 | allDicts: dict.allDicts,
34 | dictionary,
35 | history
36 | });
37 | dictWindow.onDictInited();
38 | } else if (request.type === 'setting') {
39 | sendResponse(setting.configCache);
40 | } else if (request.type === 'save setting') {
41 | setting.setValue(request.key, request.value);
42 | if (request.key === 'enableMinidict') {
43 | ext.setBrowserIcon(request.value);
44 | }
45 | } else if (request.type === 'rating') {
46 | storage.addRating(request.text, request.value);
47 | } else if (request.type === 'deleteHistory') {
48 | storage.deleteHistory(request.text);
49 | } else if (request.type === 'injected') {
50 | dictWindow.onContentInjected(request.url, sender.tab.id);
51 | }
52 | // sendResponse becomes invalid when the event listener returns,
53 | // unless you return true from the event listener to indicate you wish to send a response asynchronously
54 | return true;
55 | });
56 | });
57 |
--------------------------------------------------------------------------------
/background/plain-lookup.coffee:
--------------------------------------------------------------------------------
1 | define ["jquery",
2 | "background/dictwindow.js"], ($, dictWindow)->
3 |
4 | # most: 这个单词的 E-E 词典有 gl_none 这个 class;
5 | # 词组: 查询词组时没有音标,只有发音;
6 | # 网络词汇可能只有 web 释义,没有发音,如: https://cn.bing.com/dict/search?q=wantonly
7 | # 中文词: 查询结果上部是英文翻译,E-E 的地方却是 cn-cn, 如: https://cn.bing.com/dict/search?q=%E5%A4%A7%E5%8D%8A
8 | parseBing = (url) ->
9 | res = await $.get(url)
10 | nodes = $(res)
11 |
12 | prons = {
13 | ame: nodes.find('.hd_area .hd_prUS').text(),
14 | ameAudio: nodes.find('.hd_area .hd_prUS').next('.hd_tf').html()?.match(/https:.*?\.mp3/)[0]
15 | bre: nodes.find('.hd_area .hd_pr').text(),
16 | breAudio: nodes.find('.hd_area .hd_pr').next('.hd_tf').html()?.match(/https:.*?\.mp3/)[0]
17 | }
18 |
19 | enDefs = []
20 | eeNodes = nodes.find('#homoid tr.def_row')
21 | eeNodes.each (i, el) ->
22 | enDefs.push({
23 | pos: $(el).find('.pos').text(),
24 | def: $(el).find('.def_fl .de_li1')
25 | # https://cn.bing.com/dict/search?q=most 这个单词有 gl_none 的特例;
26 | .filter(() -> !$(this).parent().hasClass('gl_none'))
27 | .toArray().map (item) -> item.innerText
28 | })
29 |
30 | cnDefs = []
31 | defsNodes = nodes.find('.qdef ul')
32 | defsNodes.find('.pos').each (i, el) ->
33 | cnDefs.push({
34 | pos: $(el).text(),
35 | def: $(el).next().text()
36 | })
37 |
38 | # console.log prons, enDefs, cnDefs
39 | return {en: enDefs, cn: cnDefs, prons}
40 |
41 | # message.on 'look up plain', ({text})->
42 | # res = await dictWindow.queryDict(text, '必应词典', false)
43 | # parseBing(res.windowUrl)
44 |
45 | return {parseBing}
46 |
47 |
48 | # parseBing('https://cn.bing.com/dict/search?q=most')
--------------------------------------------------------------------------------
/background/plain-lookup.js:
--------------------------------------------------------------------------------
1 | define(["jquery", "background/dictwindow.js"], function($, dictWindow) {
2 | var parseBing;
3 | // most: 这个单词的 E-E 词典有 gl_none 这个 class;
4 | // 词组: 查询词组时没有音标,只有发音;
5 | // 网络词汇可能只有 web 释义,没有发音,如: https://cn.bing.com/dict/search?q=wantonly
6 | // 中文词: 查询结果上部是英文翻译,E-E 的地方却是 cn-cn, 如: https://cn.bing.com/dict/search?q=%E5%A4%A7%E5%8D%8A
7 | parseBing = async function(url) {
8 | var cnDefs, defsNodes, eeNodes, enDefs, nodes, prons, ref, ref1, res;
9 | res = (await $.get(url));
10 | nodes = $(res);
11 | prons = {
12 | ame: nodes.find('.hd_area .hd_prUS').text(),
13 | ameAudio: (ref = nodes.find('.hd_area .hd_prUS').next('.hd_tf').html()) != null ? ref.match(/https:.*?\.mp3/)[0] : void 0,
14 | bre: nodes.find('.hd_area .hd_pr').text(),
15 | breAudio: (ref1 = nodes.find('.hd_area .hd_pr').next('.hd_tf').html()) != null ? ref1.match(/https:.*?\.mp3/)[0] : void 0
16 | };
17 | enDefs = [];
18 | eeNodes = nodes.find('#homoid tr.def_row');
19 | eeNodes.each(function(i, el) {
20 | return enDefs.push({
21 | pos: $(el).find('.pos').text(),
22 | // https://cn.bing.com/dict/search?q=most 这个单词有 gl_none 的特例;
23 | def: $(el).find('.def_fl .de_li1').filter(function() {
24 | return !$(this).parent().hasClass('gl_none');
25 | }).toArray().map(function(item) {
26 | return item.innerText;
27 | })
28 | });
29 | });
30 | cnDefs = [];
31 | defsNodes = nodes.find('.qdef ul');
32 | defsNodes.find('.pos').each(function(i, el) {
33 | return cnDefs.push({
34 | pos: $(el).text(),
35 | def: $(el).next().text()
36 | });
37 | });
38 | return {
39 | // console.log prons, enDefs, cnDefs
40 | en: enDefs,
41 | cn: cnDefs,
42 | prons
43 | };
44 | };
45 | // message.on 'look up plain', ({text})->
46 | // res = await dictWindow.queryDict(text, '必应词典', false)
47 | // parseBing(res.windowUrl)
48 | return {parseBing};
49 | });
50 |
51 | // parseBing('https://cn.bing.com/dict/search?q=most')
52 |
53 |
54 | //# sourceMappingURL=plain-lookup.js.map
55 | //# sourceURL=coffeescript
--------------------------------------------------------------------------------
/background/setting.coffee:
--------------------------------------------------------------------------------
1 | define ["jquery",
2 | "utils"], ($, utils)->
3 |
4 | setting =
5 | configCache: {
6 | windowWidth: 630,
7 | windowHeight: 700,
8 |
9 | enableSelectionOnMouseMove: false,
10 | enableSelectionSK1: true,
11 | selectionSK1: 'Meta',
12 | selectionTimeout: 500,
13 |
14 | enablePlainLookup: true,
15 | enableAmeAudio: false,
16 | enableBreAudio: false,
17 | enablePlainSK1: false,
18 | plainSK1: 'Meta',
19 |
20 | enableMinidict: false,
21 | enableMouseSK1: false,
22 | mouseSK1: 'Ctrl',
23 | openSK1: 'Ctrl',
24 | openSK2: 'Shift'
25 | openKey: 'X',
26 |
27 | browserActionType: 'openDictWindow',
28 |
29 | prevDictSK1: 'Ctrl',
30 | prevDictKey: 'ArrowLeft',
31 | nextDictSK1: 'Ctrl',
32 | nextDictKey: 'ArrowRight',
33 | prevHistorySK1: 'Alt',
34 | prevHistoryKey: 'ArrowLeft',
35 | nextHistorySK1: 'Alt',
36 | nextHistoryKey: 'ArrowRight'
37 | dictionary: ''
38 |
39 | upgradeNotice: false
40 | }
41 |
42 | init: ()->
43 | dfd = $.Deferred()
44 | chrome.storage.sync.get @configCache, (obj)=>
45 | @configCache = obj
46 | chrome.storage.sync.set(obj)
47 | dfd.resolve(obj)
48 |
49 | if not obj.upgradeNotice
50 | chrome.runtime.openOptionsPage()
51 |
52 | return dfd
53 |
54 | setValue: (key, value)->
55 | if @configCache[key] != value
56 | @configCache[key] = value
57 | chrome.storage.sync.set(@configCache);
58 | return value
59 |
60 | getValue: (key, defaultValue)->
61 | v = @configCache[key]
62 | v ?= defaultValue
63 | return v
64 |
65 | return setting
66 |
--------------------------------------------------------------------------------
/background/setting.js:
--------------------------------------------------------------------------------
1 | // Generated by CoffeeScript 2.4.1
2 | define(["jquery", "utils"], function($, utils) {
3 | var setting;
4 | setting = {
5 | configCache: {
6 | windowWidth: 630,
7 | windowHeight: 700,
8 | enableSelectionOnMouseMove: false,
9 | enableSelectionSK1: true,
10 | selectionSK1: 'Meta',
11 | selectionTimeout: 500,
12 | enablePlainLookup: true,
13 | enableAmeAudio: false,
14 | enableBreAudio: false,
15 | enablePlainSK1: false,
16 | plainSK1: 'Meta',
17 | enableMinidict: false,
18 | enableMouseSK1: false,
19 | mouseSK1: 'Ctrl',
20 | openSK1: 'Ctrl',
21 | openSK2: 'Shift',
22 | openKey: 'X',
23 | browserActionType: 'openDictWindow',
24 | prevDictSK1: 'Ctrl',
25 | prevDictKey: 'ArrowLeft',
26 | nextDictSK1: 'Ctrl',
27 | nextDictKey: 'ArrowRight',
28 | prevHistorySK1: 'Alt',
29 | prevHistoryKey: 'ArrowLeft',
30 | nextHistorySK1: 'Alt',
31 | nextHistoryKey: 'ArrowRight',
32 | dictionary: '',
33 | upgradeNotice: false
34 | },
35 | init: function() {
36 | var dfd;
37 | dfd = $.Deferred();
38 | chrome.storage.sync.get(this.configCache, (obj) => {
39 | this.configCache = obj;
40 | chrome.storage.sync.set(obj);
41 | dfd.resolve(obj);
42 | if (!obj.upgradeNotice) {
43 | return chrome.runtime.openOptionsPage();
44 | }
45 | });
46 | return dfd;
47 | },
48 | setValue: function(key, value) {
49 | if (this.configCache[key] !== value) {
50 | this.configCache[key] = value;
51 | chrome.storage.sync.set(this.configCache);
52 | }
53 | return value;
54 | },
55 | getValue: function(key, defaultValue) {
56 | var v;
57 | v = this.configCache[key];
58 | if (v == null) {
59 | v = defaultValue;
60 | }
61 | return v;
62 | }
63 | };
64 | return setting;
65 | });
66 |
--------------------------------------------------------------------------------
/background/storage.coffee:
--------------------------------------------------------------------------------
1 | define ["jquery",
2 | "utils"], ($, utils)->
3 |
4 | storage = {
5 | maxLength: 200,
6 | history: [],
7 | init: ()->
8 | dfd = $.Deferred()
9 | chrome.storage.sync.get 'historyRating', (data)=>
10 | @history = data.historyRating or []
11 | dfd.resolve(data)
12 | return dfd
13 |
14 | isInHistory: (word)->
15 | return @history.find (item)->
16 | return item[word]?
17 |
18 | addRating: (word, rating)->
19 | item = @isInHistory(word)
20 | if item and rating?
21 | item[word] = rating
22 | chrome.storage.sync.set({historyRating: @history})
23 |
24 | addHistory: (word)->
25 | if not @isInHistory(word)
26 | if @history.length >= @maxLength
27 | @history.shift()
28 | item = {}
29 | item[word] = 0
30 | @history.push(item)
31 | chrome.storage.sync.set({historyRating: @history})
32 |
33 | deleteHistory: (word)->
34 | idx = @history.findIndex (item)->
35 | return item[word]?
36 | if idx >= 0
37 | @history.splice(idx, 1)
38 |
39 | }
40 |
41 | return storage
42 |
--------------------------------------------------------------------------------
/background/storage.js:
--------------------------------------------------------------------------------
1 | // Generated by CoffeeScript 1.10.0
2 | define(["jquery", "utils"], function($, utils) {
3 | var storage;
4 | storage = {
5 | maxLength: 200,
6 | history: [],
7 | init: function() {
8 | var dfd;
9 | dfd = $.Deferred();
10 | chrome.storage.sync.get('historyRating', (function(_this) {
11 | return function(data) {
12 | _this.history = data.historyRating || [];
13 | return dfd.resolve(data);
14 | };
15 | })(this));
16 | return dfd;
17 | },
18 | isInHistory: function(word) {
19 | return this.history.find(function(item) {
20 | return item[word] != null;
21 | });
22 | },
23 | addRating: function(word, rating) {
24 | var item;
25 | item = this.isInHistory(word);
26 | if (item && (rating != null)) {
27 | item[word] = rating;
28 | return chrome.storage.sync.set({
29 | historyRating: this.history
30 | });
31 | }
32 | },
33 | addHistory: function(word) {
34 | var item;
35 | if (!this.isInHistory(word)) {
36 | if (this.history.length >= this.maxLength) {
37 | this.history.shift();
38 | }
39 | item = {};
40 | item[word] = 0;
41 | this.history.push(item);
42 | return chrome.storage.sync.set({
43 | historyRating: this.history
44 | });
45 | }
46 | },
47 | deleteHistory: function(word) {
48 | var idx;
49 | idx = this.history.findIndex(function(item) {
50 | return item[word] != null;
51 | });
52 | if (idx >= 0) {
53 | return this.history.splice(idx, 1);
54 | }
55 | }
56 | };
57 | return storage;
58 | });
59 |
--------------------------------------------------------------------------------
/bower.json:
--------------------------------------------------------------------------------
1 | {
2 | "name": "FairyDict",
3 | "homepage": "https://github.com/revir/FairyDict",
4 | "authors": [
5 | "Revir "
6 | ],
7 | "description": "A fairy dictionary extension for chrome.",
8 | "main": "",
9 | "moduleType": [],
10 | "keywords": [
11 | "dictionary",
12 | "chrome",
13 | "extension"
14 | ],
15 | "license": "MIT",
16 | "ignore": [
17 | "**/.*",
18 | "node_modules",
19 | "bower_components",
20 | "test",
21 | "tests"
22 | ],
23 | "dependencies": {
24 | "bootstrap": "=3.0.3",
25 | "angular": "~1.4.8",
26 | "angular-ui": "~0.4.0",
27 | "angular-bootstrap": "~0.14.3",
28 | "angular-sanitize": "~1.5.7",
29 | "angular-route": "1.4.12",
30 | "jquery": "^3.1.1",
31 | "requirejs": "^2.3.2",
32 | "font-awesome": "^4.6.3",
33 | "underscore": "^1.8.3",
34 | "less": "^2.7.1"
35 | }
36 | }
37 |
--------------------------------------------------------------------------------
/build/fairy-dict.crx:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/revir/FairyDict/ac7722ceda402af1cf420cf7077a06c341e5d5d9/build/fairy-dict.crx
--------------------------------------------------------------------------------
/content/inject-fontello.css:
--------------------------------------------------------------------------------
1 | /* @font-face {
2 | font-family: "fairydict-font";
3 | src: url("data:application/octet-stream;base64,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")
4 | format("woff"),
5 | url("data:application/octet-stream;base64,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")
6 | format("truetype");
7 | } */
8 | @font-face {
9 | font-family: "fairydict-font";
10 | src: url("chrome-extension://__MSG_@@extension_id__/fonts/fairydict-font.woff?26686527")
11 | format("woff");
12 | font-weight: normal;
13 | font-style: normal;
14 | }
15 |
16 | /* Chrome hack: SVG is rendered more smooth in Windozze. 100% magic, uncomment if you need it. */
17 | /* Note, that will break hinting! In other OS-es font will be not as sharp as it could be */
18 | /*
19 | @media screen and (-webkit-min-device-pixel-ratio:0) {
20 | @font-face {
21 | font-family: 'fairydict-font';
22 | src: url('../font/fairydict-font.svg?83899544#fairydict-font') format('svg');
23 | }
24 | }
25 | */
26 |
27 | [class^="icon-fairydict"]:before,
28 | [class*=" icon-fairydict"]:before {
29 | font-family: "fairydict-font";
30 | font-style: normal;
31 | font-weight: normal;
32 | speak: none;
33 |
34 | display: inline-block;
35 | text-decoration: inherit;
36 | width: 1em;
37 | margin-right: 0.2em;
38 | text-align: center;
39 | /* opacity: .8; */
40 |
41 | /* For safety - reset parent styles, that can break glyph codes*/
42 | font-variant: normal;
43 | text-transform: none;
44 |
45 | /* fix buttons height, for twitter bootstrap */
46 | line-height: 1em;
47 |
48 | /* Animation center compensation - margins should be symmetric */
49 | /* remove if not needed */
50 | margin-left: 0.2em;
51 |
52 | /* you can be more comfortable with increased icons size */
53 | /* font-size: 120%; */
54 |
55 | /* Uncomment for 3D effect */
56 | /* text-shadow: 1px 1px 1px rgba(127, 127, 127, 0.3); */
57 | }
58 | .icon-fairydict-volume:before {
59 | content: "\e800";
60 | } /* '' */
61 |
--------------------------------------------------------------------------------
/content/inject.coffee:
--------------------------------------------------------------------------------
1 | chrome.runtime.sendMessage {
2 | type: 'setting',
3 | }, (setting)->
4 | mouseMoveTimer = null
5 | plainQuerying = null
6 |
7 | jQuery(document).ready ()->
8 | jQuery('''
9 |
18 | ''').appendTo('body')
19 |
20 | setupPlainContentPosition = (e) ->
21 | $el = jQuery('.fairydict-tooltip')
22 | if $el.length && e.pageX && e.pageY
23 | mousex = e.pageX + 20
24 | mousey = e.pageY + 10
25 | top = mousey
26 | left = mousex
27 |
28 | rect = window.document.body.getBoundingClientRect()
29 | domW = window.innerWidth - rect.left
30 | domH = window.innerHeight - rect.top
31 |
32 | if domW - left < 300
33 | left = domW - 300
34 | if domH - top < 200
35 | top = domH - 200
36 |
37 | $el.css({ top, left })
38 |
39 | jQuery(document).mousemove (e)->
40 | if setting.enableSelectionOnMouseMove
41 | if !setting.enableSelectionSK1 or (setting.enableSelectionSK1 and utils.checkEventKey(e, setting.selectionSK1))
42 | handleSelectionWord(e)
43 |
44 | jQuery(document).mouseup (e)->
45 | # 对 mouseup 事件做一个延时处理,
46 | # 以避免取消选中后getSelection依然能获得文字。
47 | setTimeout (()->handleMouseUp(e)), 1
48 |
49 | jQuery(document).bind 'keyup', (event)->
50 | if utils.checkEventKey event, setting.openSK1, setting.openSK2, setting.openKey
51 | chrome.runtime.sendMessage({
52 | type: 'look up',
53 | means: 'keyboard',
54 | text: window.getSelection().toString().trim()
55 | })
56 | if event.key == "Escape"
57 | jQuery('.fairydict-tooltip').fadeOut().hide()
58 | plainQuerying = null
59 |
60 | jQuery(document).on 'click', '.fairydict-pron-audio', (e) ->
61 | e.stopPropagation()
62 | playAudios [jQuery(this).data('mp3')]
63 | return false
64 |
65 | handleSelectionWord = (e)->
66 | clearTimeout(mouseMoveTimer) if mouseMoveTimer
67 | mouseMoveTimer = setTimeout (()->
68 | word = getWordAtPoint(e.target, e.clientX, e.clientY)
69 | if word
70 | console.log(word)
71 | handleLookupByMouse(e)
72 | ), (setting.selectionTimeout or 500)
73 |
74 | playAudios = (urls) ->
75 | return unless urls?.length
76 | audios = urls.map (url)->
77 | return new Audio(url)
78 |
79 | _play = (audio, timeout)->
80 | timeout ?= 0
81 | return jQuery.Deferred (dfd)->
82 | _func = ()->
83 | setTimeout (()->
84 | # console.log "play: ", audio.duration, timeout
85 | audio.play()
86 | dfd.resolve(audio.duration or 1)
87 | ), timeout
88 |
89 | if audio.duration
90 | _func()
91 | else
92 | audio.addEventListener 'loadedmetadata', _func
93 |
94 | __play = (idx, timeout)->
95 | idx ?= 0
96 | if audios[idx]
97 | _play(audios[idx], timeout).then (duration)->
98 | __play(idx+1, duration*1000)
99 |
100 | __play()
101 |
102 | getWordAtPoint = (elem, x, y)->
103 | if elem.nodeType == elem.TEXT_NODE
104 | range = elem.ownerDocument.createRange()
105 | range.selectNodeContents(elem)
106 | currentPos = 0
107 | endPos = range.endOffset
108 | while currentPos+1 < endPos
109 | range.setStart(elem, currentPos)
110 | range.setEnd(elem, currentPos+1)
111 | if range.getBoundingClientRect().left <= x && range.getBoundingClientRect().right >= x &&
112 | range.getBoundingClientRect().top <= y && range.getBoundingClientRect().bottom >= y
113 | range.detach()
114 | sel = window.getSelection()
115 | sel.removeAllRanges()
116 | sel.addRange(range)
117 | sel.modify("move", "backward", "word")
118 | sel.collapseToStart()
119 | sel.modify("extend", "forward", "word")
120 | return sel.toString().trim()
121 |
122 | currentPos += 1
123 | else
124 | for el in elem.childNodes
125 | range = el.ownerDocument.createRange()
126 | range.selectNodeContents(el)
127 | react = range.getBoundingClientRect()
128 | if react.left <= x && react.right >= x && react.top <= y && react.bottom >= y
129 | range.detach()
130 | return getWordAtPoint el, x, y
131 | else
132 | range.detach()
133 | return
134 |
135 | handleMouseUp = (event)->
136 | selObj = window.getSelection()
137 | text = selObj.toString().trim()
138 | unless text
139 | # click inside the dict
140 | if jQuery('.fairydict-tooltip').has(event.target).length
141 | return
142 |
143 | jQuery('.fairydict-tooltip').fadeOut().hide()
144 | plainQuerying = null
145 | return
146 |
147 | # issue #4
148 | including = jQuery(event.target).has(selObj.focusNode).length or jQuery(event.target).is(selObj.focusNode)
149 |
150 | if event.which == 1 and including
151 | handleLookupByMouse(event)
152 |
153 | renderQueryResult = (res) ->
154 | defTpl = (def) -> " #{def} "
155 | defsTpl = (defs) -> " #{defs} "
156 | posTpl = (pos) -> " #{pos} "
157 | contentTpl = (content) -> " #{content}
"
158 | pronTpl = (pron) -> " #{pron} "
159 | pronAudioTpl = (src) -> ""
160 | pronsTpl = (prons) -> " #{prons}
"
161 |
162 | html = ''
163 | if res?.prons
164 | pronHtml = ''
165 | pronHtml += pronTpl res.prons.ame if res.prons.ame
166 | pronHtml += pronAudioTpl res.prons.ameAudio if res.prons.ameAudio
167 | pronHtml += pronTpl res.prons.bre if res.prons.bre
168 | pronHtml += pronAudioTpl res.prons.breAudio if res.prons.breAudio
169 | html += pronsTpl pronHtml if pronHtml
170 |
171 | renderItem = (item) ->
172 | posHtml = posTpl item.pos
173 |
174 | defs = if Array.isArray(item.def) then item.def else [item.def]
175 | defsHtmls = defs.map (def) -> defTpl def
176 |
177 | defsHtml = defsTpl defsHtmls.join('
')
178 |
179 | html += contentTpl posHtml+defsHtml if defsHtml
180 |
181 | res.cn.forEach renderItem if res?.cn
182 | res.en.forEach renderItem if res?.en
183 |
184 | if html
185 | jQuery('.fairydict-tooltip .fairydict-spinner').hide()
186 | jQuery('.fairydict-tooltip .fairydict-tooltip-content').html(html)
187 | else
188 | jQuery('.fairydict-tooltip').fadeOut().hide()
189 |
190 | return html
191 |
192 | handleLookupByMouse = (event)->
193 | text = window.getSelection().toString().trim()
194 | return unless text
195 | return if text.split(/\s/).length > 4
196 |
197 | return if $('.dictionaries-tooltip').length # ignore when find Dictionaries
198 |
199 | if setting.enablePlainLookup && text != plainQuerying
200 | if !setting.enablePlainSK1 or (setting.plainSK1 and utils.checkEventKey(event, setting.plainSK1))
201 | jQuery('.fairydict-tooltip').fadeIn('slow')
202 | jQuery('.fairydict-tooltip .fairydict-spinner').show()
203 | jQuery('.fairydict-tooltip .fairydict-tooltip-content').empty()
204 |
205 | unless plainQuerying
206 | setupPlainContentPosition(event)
207 |
208 | plainQuerying = text
209 |
210 | chrome.runtime.sendMessage {
211 | type: 'look up pain',
212 | means: 'mouse',
213 | text: text
214 | }, (res)->
215 | html = renderQueryResult res
216 | if !html
217 | plainQuerying = null
218 |
219 | if res.prons
220 | audios = []
221 |
222 | if res.prons.ameAudio and setting.enableAmeAudio
223 | audios.push res.prons.ameAudio
224 |
225 | if res.prons.breAudio and setting.enableBreAudio
226 | audios.push res.prons.breAudio
227 |
228 | if audios.length
229 | playAudios audios
230 |
231 | if !setting.enableMouseSK1 or (setting.mouseSK1 and utils.checkEventKey(event, setting.mouseSK1))
232 | chrome.runtime.sendMessage({
233 | type: 'look up',
234 | means: 'mouse',
235 | text: text
236 | })
237 |
238 |
239 | chrome.runtime.sendMessage {
240 | type: 'injected',
241 | url: location.href
242 | }
243 |
--------------------------------------------------------------------------------
/content/inject.css:
--------------------------------------------------------------------------------
1 | .fairydict-tooltip {
2 | display: none;
3 | position: absolute;
4 | border: 1px solid #333;
5 | background-color: #161616;
6 | border-radius: 5px;
7 | padding: 10px;
8 |
9 | z-index: 99999;
10 | }
11 |
12 | .fairydict-tooltip p.fairydict-tooltip-content {
13 | color: #fff;
14 | font-size: 13px;
15 | line-height: normal;
16 | }
17 |
18 | .fairydict-tooltip .icon-fairydict-volume {
19 | color: goldenrod;
20 | }
21 |
22 | .fairydict-tooltip .fairydict-content {
23 | margin-top: 3px;
24 | }
25 |
26 | .fairydict-tooltip .fairydict-pos {
27 | display: table-cell;
28 | vertical-align: top;
29 | width: 32px;
30 | padding-top: 1px;
31 | }
32 |
33 | .fairydict-tooltip .fairydict-defs {
34 | display: table-cell;
35 | padding-top: 1px;
36 | }
37 |
38 | .fairydict-spinner {
39 | margin: 10px auto 0;
40 | width: 70px;
41 | text-align: center;
42 | }
43 |
44 | .fairydict-spinner > div {
45 | width: 18px;
46 | height: 18px;
47 | background-color: #333;
48 |
49 | border-radius: 100%;
50 | display: inline-block;
51 | -webkit-animation: sk-bouncedelay 1.4s infinite ease-in-out both;
52 | animation: sk-bouncedelay 1.4s infinite ease-in-out both;
53 | }
54 |
55 | .fairydict-spinner .fairydict-bounce1 {
56 | -webkit-animation-delay: -0.32s;
57 | animation-delay: -0.32s;
58 | }
59 |
60 | .fairydict-spinner .fairydict-bounce2 {
61 | -webkit-animation-delay: -0.16s;
62 | animation-delay: -0.16s;
63 | }
64 |
65 | @-webkit-keyframes sk-bouncedelay {
66 | 0%,
67 | 80%,
68 | 100% {
69 | -webkit-transform: scale(0);
70 | }
71 | 40% {
72 | -webkit-transform: scale(1);
73 | }
74 | }
75 |
76 | @keyframes sk-bouncedelay {
77 | 0%,
78 | 80%,
79 | 100% {
80 | -webkit-transform: scale(0);
81 | transform: scale(0);
82 | }
83 | 40% {
84 | -webkit-transform: scale(1);
85 | transform: scale(1);
86 | }
87 | }
88 |
--------------------------------------------------------------------------------
/content/inject.js:
--------------------------------------------------------------------------------
1 | // Generated by CoffeeScript 2.4.1
2 | chrome.runtime.sendMessage({
3 | type: 'setting'
4 | }, function(setting) {
5 | var getWordAtPoint, handleLookupByMouse, handleMouseUp, handleSelectionWord, mouseMoveTimer, plainQuerying, playAudios, renderQueryResult, setupPlainContentPosition;
6 | mouseMoveTimer = null;
7 | plainQuerying = null;
8 | jQuery(document).ready(function() {
9 | return jQuery('').appendTo('body');
10 | });
11 | setupPlainContentPosition = function(e) {
12 | var $el, domH, domW, left, mousex, mousey, rect, top;
13 | $el = jQuery('.fairydict-tooltip');
14 | if ($el.length && e.pageX && e.pageY) {
15 | mousex = e.pageX + 20;
16 | mousey = e.pageY + 10;
17 | top = mousey;
18 | left = mousex;
19 | rect = window.document.body.getBoundingClientRect();
20 | domW = window.innerWidth - rect.left;
21 | domH = window.innerHeight - rect.top;
22 | if (domW - left < 300) {
23 | left = domW - 300;
24 | }
25 | if (domH - top < 200) {
26 | top = domH - 200;
27 | }
28 | return $el.css({top, left});
29 | }
30 | };
31 | jQuery(document).mousemove(function(e) {
32 | if (setting.enableSelectionOnMouseMove) {
33 | if (!setting.enableSelectionSK1 || (setting.enableSelectionSK1 && utils.checkEventKey(e, setting.selectionSK1))) {
34 | return handleSelectionWord(e);
35 | }
36 | }
37 | });
38 | jQuery(document).mouseup(function(e) {
39 | // 对 mouseup 事件做一个延时处理,
40 | // 以避免取消选中后getSelection依然能获得文字。
41 | return setTimeout((function() {
42 | return handleMouseUp(e);
43 | }), 1);
44 | });
45 | jQuery(document).bind('keyup', function(event) {
46 | if (utils.checkEventKey(event, setting.openSK1, setting.openSK2, setting.openKey)) {
47 | chrome.runtime.sendMessage({
48 | type: 'look up',
49 | means: 'keyboard',
50 | text: window.getSelection().toString().trim()
51 | });
52 | }
53 | if (event.key === "Escape") {
54 | jQuery('.fairydict-tooltip').fadeOut().hide();
55 | return plainQuerying = null;
56 | }
57 | });
58 | jQuery(document).on('click', '.fairydict-pron-audio', function(e) {
59 | e.stopPropagation();
60 | playAudios([jQuery(this).data('mp3')]);
61 | return false;
62 | });
63 | handleSelectionWord = function(e) {
64 | if (mouseMoveTimer) {
65 | clearTimeout(mouseMoveTimer);
66 | }
67 | return mouseMoveTimer = setTimeout((function() {
68 | var word;
69 | word = getWordAtPoint(e.target, e.clientX, e.clientY);
70 | if (word) {
71 | console.log(word);
72 | return handleLookupByMouse(e);
73 | }
74 | }), setting.selectionTimeout || 500);
75 | };
76 | playAudios = function(urls) {
77 | var __play, _play, audios;
78 | if (!(urls != null ? urls.length : void 0)) {
79 | return;
80 | }
81 | audios = urls.map(function(url) {
82 | return new Audio(url);
83 | });
84 | _play = function(audio, timeout) {
85 | if (timeout == null) {
86 | timeout = 0;
87 | }
88 | return jQuery.Deferred(function(dfd) {
89 | var _func;
90 | _func = function() {
91 | return setTimeout((function() {
92 | // console.log "play: ", audio.duration, timeout
93 | audio.play();
94 | return dfd.resolve(audio.duration || 1);
95 | }), timeout);
96 | };
97 | if (audio.duration) {
98 | return _func();
99 | } else {
100 | return audio.addEventListener('loadedmetadata', _func);
101 | }
102 | });
103 | };
104 | __play = function(idx, timeout) {
105 | if (idx == null) {
106 | idx = 0;
107 | }
108 | if (audios[idx]) {
109 | return _play(audios[idx], timeout).then(function(duration) {
110 | return __play(idx + 1, duration * 1000);
111 | });
112 | }
113 | };
114 | return __play();
115 | };
116 | getWordAtPoint = function(elem, x, y) {
117 | var currentPos, el, endPos, i, len, range, react, ref, sel;
118 | if (elem.nodeType === elem.TEXT_NODE) {
119 | range = elem.ownerDocument.createRange();
120 | range.selectNodeContents(elem);
121 | currentPos = 0;
122 | endPos = range.endOffset;
123 | while (currentPos + 1 < endPos) {
124 | range.setStart(elem, currentPos);
125 | range.setEnd(elem, currentPos + 1);
126 | if (range.getBoundingClientRect().left <= x && range.getBoundingClientRect().right >= x && range.getBoundingClientRect().top <= y && range.getBoundingClientRect().bottom >= y) {
127 | range.detach();
128 | sel = window.getSelection();
129 | sel.removeAllRanges();
130 | sel.addRange(range);
131 | sel.modify("move", "backward", "word");
132 | sel.collapseToStart();
133 | sel.modify("extend", "forward", "word");
134 | return sel.toString().trim();
135 | }
136 | currentPos += 1;
137 | }
138 | } else {
139 | ref = elem.childNodes;
140 | for (i = 0, len = ref.length; i < len; i++) {
141 | el = ref[i];
142 | range = el.ownerDocument.createRange();
143 | range.selectNodeContents(el);
144 | react = range.getBoundingClientRect();
145 | if (react.left <= x && react.right >= x && react.top <= y && react.bottom >= y) {
146 | range.detach();
147 | return getWordAtPoint(el, x, y);
148 | } else {
149 | range.detach();
150 | }
151 | }
152 | }
153 | };
154 | handleMouseUp = function(event) {
155 | var including, selObj, text;
156 | selObj = window.getSelection();
157 | text = selObj.toString().trim();
158 | if (!text) {
159 | // click inside the dict
160 | if (jQuery('.fairydict-tooltip').has(event.target).length) {
161 | return;
162 | }
163 | jQuery('.fairydict-tooltip').fadeOut().hide();
164 | plainQuerying = null;
165 | return;
166 | }
167 | // issue #4
168 | including = jQuery(event.target).has(selObj.focusNode).length || jQuery(event.target).is(selObj.focusNode);
169 | if (event.which === 1 && including) {
170 | return handleLookupByMouse(event);
171 | }
172 | };
173 | renderQueryResult = function(res) {
174 | var contentTpl, defTpl, defsTpl, html, posTpl, pronAudioTpl, pronHtml, pronTpl, pronsTpl, renderItem;
175 | defTpl = function(def) {
176 | return ` ${def} `;
177 | };
178 | defsTpl = function(defs) {
179 | return ` ${defs} `;
180 | };
181 | posTpl = function(pos) {
182 | return ` ${pos} `;
183 | };
184 | contentTpl = function(content) {
185 | return ` ${content}
`;
186 | };
187 | pronTpl = function(pron) {
188 | return ` ${pron} `;
189 | };
190 | pronAudioTpl = function(src) {
191 | return ``;
192 | };
193 | pronsTpl = function(prons) {
194 | return ` ${prons}
`;
195 | };
196 | html = '';
197 | if (res != null ? res.prons : void 0) {
198 | pronHtml = '';
199 | if (res.prons.ame) {
200 | pronHtml += pronTpl(res.prons.ame);
201 | }
202 | if (res.prons.ameAudio) {
203 | pronHtml += pronAudioTpl(res.prons.ameAudio);
204 | }
205 | if (res.prons.bre) {
206 | pronHtml += pronTpl(res.prons.bre);
207 | }
208 | if (res.prons.breAudio) {
209 | pronHtml += pronAudioTpl(res.prons.breAudio);
210 | }
211 | if (pronHtml) {
212 | html += pronsTpl(pronHtml);
213 | }
214 | }
215 | renderItem = function(item) {
216 | var defs, defsHtml, defsHtmls, posHtml;
217 | posHtml = posTpl(item.pos);
218 | defs = Array.isArray(item.def) ? item.def : [item.def];
219 | defsHtmls = defs.map(function(def) {
220 | return defTpl(def);
221 | });
222 | defsHtml = defsTpl(defsHtmls.join('
'));
223 | if (defsHtml) {
224 | return html += contentTpl(posHtml + defsHtml);
225 | }
226 | };
227 | if (res != null ? res.cn : void 0) {
228 | res.cn.forEach(renderItem);
229 | }
230 | if (res != null ? res.en : void 0) {
231 | res.en.forEach(renderItem);
232 | }
233 | if (html) {
234 | jQuery('.fairydict-tooltip .fairydict-spinner').hide();
235 | jQuery('.fairydict-tooltip .fairydict-tooltip-content').html(html);
236 | } else {
237 | jQuery('.fairydict-tooltip').fadeOut().hide();
238 | }
239 | return html;
240 | };
241 | return handleLookupByMouse = function(event) {
242 | var text;
243 | text = window.getSelection().toString().trim();
244 | if (!text) {
245 | return;
246 | }
247 | if (text.split(/\s/).length > 4) {
248 | return;
249 | }
250 | if ($('.dictionaries-tooltip').length) { // ignore when find Dictionaries
251 | return;
252 | }
253 | if (setting.enablePlainLookup && text !== plainQuerying) {
254 | if (!setting.enablePlainSK1 || (setting.plainSK1 && utils.checkEventKey(event, setting.plainSK1))) {
255 | jQuery('.fairydict-tooltip').fadeIn('slow');
256 | jQuery('.fairydict-tooltip .fairydict-spinner').show();
257 | jQuery('.fairydict-tooltip .fairydict-tooltip-content').empty();
258 | if (!plainQuerying) {
259 | setupPlainContentPosition(event);
260 | }
261 | plainQuerying = text;
262 | chrome.runtime.sendMessage({
263 | type: 'look up pain',
264 | means: 'mouse',
265 | text: text
266 | }, function(res) {
267 | var audios, html;
268 | html = renderQueryResult(res);
269 | if (!html) {
270 | plainQuerying = null;
271 | }
272 | if (res.prons) {
273 | audios = [];
274 | if (res.prons.ameAudio && setting.enableAmeAudio) {
275 | audios.push(res.prons.ameAudio);
276 | }
277 | if (res.prons.breAudio && setting.enableBreAudio) {
278 | audios.push(res.prons.breAudio);
279 | }
280 | if (audios.length) {
281 | return playAudios(audios);
282 | }
283 | }
284 | });
285 | }
286 | }
287 | if (!setting.enableMouseSK1 || (setting.mouseSK1 && utils.checkEventKey(event, setting.mouseSK1))) {
288 | return chrome.runtime.sendMessage({
289 | type: 'look up',
290 | means: 'mouse',
291 | text: text
292 | });
293 | }
294 | };
295 | });
296 |
297 | chrome.runtime.sendMessage({
298 | type: 'injected',
299 | url: location.href
300 | });
301 |
--------------------------------------------------------------------------------
/css/91dict.css:
--------------------------------------------------------------------------------
1 | .widescreenNav {
2 | margin-top: 55px !important;
3 | }
4 | .header {
5 | display: none;
6 | }
7 |
--------------------------------------------------------------------------------
/css/apidict.css:
--------------------------------------------------------------------------------
1 | body {
2 | /*margin: 8px;*/
3 | padding-top: 70px;
4 | padding-left: 15px;
5 | }
6 |
--------------------------------------------------------------------------------
/css/baidu-dict.css:
--------------------------------------------------------------------------------
1 | #search-bar, #update_tips_div {
2 | display: none;
3 | }
4 |
5 | #header-detail label {
6 | // fix a bug of baidu;
7 | width: auto !important;
8 | }
9 |
--------------------------------------------------------------------------------
/css/bing.css:
--------------------------------------------------------------------------------
1 | body {
2 | /*margin: 8px;*/
3 | padding-left: 15px !important;
4 | padding-top: 70px !important;
5 | }
6 | body header {
7 | display: none !important;
8 | }
9 | body .contentPadding {
10 | padding-left: 0 !important;
11 | }
12 |
--------------------------------------------------------------------------------
/css/bing.less:
--------------------------------------------------------------------------------
1 | body {
2 | /*margin: 8px;*/
3 | padding-left: 15px !important;
4 | padding-top: 70px !important;
5 |
6 | header {
7 | display: none !important;
8 | }
9 |
10 | .contentPadding {
11 | padding-left: 0 !important;
12 | }
13 | }
14 |
--------------------------------------------------------------------------------
/css/bootstrap-theme.css:
--------------------------------------------------------------------------------
1 | /*!
2 | * Bootstrap v3.0.3 (http://getbootstrap.com)
3 | * Copyright 2013 Twitter, Inc.
4 | * Licensed under http://www.apache.org/licenses/LICENSE-2.0
5 | */
6 |
7 | .btn-default,
8 | .btn-primary,
9 | .btn-success,
10 | .btn-info,
11 | .btn-warning,
12 | .btn-danger {
13 | text-shadow: 0 -1px 0 rgba(0, 0, 0, 0.2);
14 | -webkit-box-shadow: inset 0 1px 0 rgba(255, 255, 255, 0.15), 0 1px 1px rgba(0, 0, 0, 0.075);
15 | box-shadow: inset 0 1px 0 rgba(255, 255, 255, 0.15), 0 1px 1px rgba(0, 0, 0, 0.075);
16 | }
17 |
18 | .btn-default:active,
19 | .btn-primary:active,
20 | .btn-success:active,
21 | .btn-info:active,
22 | .btn-warning:active,
23 | .btn-danger:active,
24 | .btn-default.active,
25 | .btn-primary.active,
26 | .btn-success.active,
27 | .btn-info.active,
28 | .btn-warning.active,
29 | .btn-danger.active {
30 | -webkit-box-shadow: inset 0 3px 5px rgba(0, 0, 0, 0.125);
31 | box-shadow: inset 0 3px 5px rgba(0, 0, 0, 0.125);
32 | }
33 |
34 | .btn:active,
35 | .btn.active {
36 | background-image: none;
37 | }
38 |
39 | .btn-default {
40 | text-shadow: 0 1px 0 #fff;
41 | background-image: -webkit-linear-gradient(top, #ffffff 0%, #e0e0e0 100%);
42 | background-image: linear-gradient(to bottom, #ffffff 0%, #e0e0e0 100%);
43 | background-repeat: repeat-x;
44 | border-color: #dbdbdb;
45 | border-color: #ccc;
46 | filter: progid:DXImageTransform.Microsoft.gradient(startColorstr='#ffffffff', endColorstr='#ffe0e0e0', GradientType=0);
47 | filter: progid:DXImageTransform.Microsoft.gradient(enabled=false);
48 | }
49 |
50 | .btn-default:hover,
51 | .btn-default:focus {
52 | background-color: #e0e0e0;
53 | background-position: 0 -15px;
54 | }
55 |
56 | .btn-default:active,
57 | .btn-default.active {
58 | background-color: #e0e0e0;
59 | border-color: #dbdbdb;
60 | }
61 |
62 | .btn-primary {
63 | background-image: -webkit-linear-gradient(top, #428bca 0%, #2d6ca2 100%);
64 | background-image: linear-gradient(to bottom, #428bca 0%, #2d6ca2 100%);
65 | background-repeat: repeat-x;
66 | border-color: #2b669a;
67 | filter: progid:DXImageTransform.Microsoft.gradient(startColorstr='#ff428bca', endColorstr='#ff2d6ca2', GradientType=0);
68 | filter: progid:DXImageTransform.Microsoft.gradient(enabled=false);
69 | }
70 |
71 | .btn-primary:hover,
72 | .btn-primary:focus {
73 | background-color: #2d6ca2;
74 | background-position: 0 -15px;
75 | }
76 |
77 | .btn-primary:active,
78 | .btn-primary.active {
79 | background-color: #2d6ca2;
80 | border-color: #2b669a;
81 | }
82 |
83 | .btn-success {
84 | background-image: -webkit-linear-gradient(top, #5cb85c 0%, #419641 100%);
85 | background-image: linear-gradient(to bottom, #5cb85c 0%, #419641 100%);
86 | background-repeat: repeat-x;
87 | border-color: #3e8f3e;
88 | filter: progid:DXImageTransform.Microsoft.gradient(startColorstr='#ff5cb85c', endColorstr='#ff419641', GradientType=0);
89 | filter: progid:DXImageTransform.Microsoft.gradient(enabled=false);
90 | }
91 |
92 | .btn-success:hover,
93 | .btn-success:focus {
94 | background-color: #419641;
95 | background-position: 0 -15px;
96 | }
97 |
98 | .btn-success:active,
99 | .btn-success.active {
100 | background-color: #419641;
101 | border-color: #3e8f3e;
102 | }
103 |
104 | .btn-warning {
105 | background-image: -webkit-linear-gradient(top, #f0ad4e 0%, #eb9316 100%);
106 | background-image: linear-gradient(to bottom, #f0ad4e 0%, #eb9316 100%);
107 | background-repeat: repeat-x;
108 | border-color: #e38d13;
109 | filter: progid:DXImageTransform.Microsoft.gradient(startColorstr='#fff0ad4e', endColorstr='#ffeb9316', GradientType=0);
110 | filter: progid:DXImageTransform.Microsoft.gradient(enabled=false);
111 | }
112 |
113 | .btn-warning:hover,
114 | .btn-warning:focus {
115 | background-color: #eb9316;
116 | background-position: 0 -15px;
117 | }
118 |
119 | .btn-warning:active,
120 | .btn-warning.active {
121 | background-color: #eb9316;
122 | border-color: #e38d13;
123 | }
124 |
125 | .btn-danger {
126 | background-image: -webkit-linear-gradient(top, #d9534f 0%, #c12e2a 100%);
127 | background-image: linear-gradient(to bottom, #d9534f 0%, #c12e2a 100%);
128 | background-repeat: repeat-x;
129 | border-color: #b92c28;
130 | filter: progid:DXImageTransform.Microsoft.gradient(startColorstr='#ffd9534f', endColorstr='#ffc12e2a', GradientType=0);
131 | filter: progid:DXImageTransform.Microsoft.gradient(enabled=false);
132 | }
133 |
134 | .btn-danger:hover,
135 | .btn-danger:focus {
136 | background-color: #c12e2a;
137 | background-position: 0 -15px;
138 | }
139 |
140 | .btn-danger:active,
141 | .btn-danger.active {
142 | background-color: #c12e2a;
143 | border-color: #b92c28;
144 | }
145 |
146 | .btn-info {
147 | background-image: -webkit-linear-gradient(top, #5bc0de 0%, #2aabd2 100%);
148 | background-image: linear-gradient(to bottom, #5bc0de 0%, #2aabd2 100%);
149 | background-repeat: repeat-x;
150 | border-color: #28a4c9;
151 | filter: progid:DXImageTransform.Microsoft.gradient(startColorstr='#ff5bc0de', endColorstr='#ff2aabd2', GradientType=0);
152 | filter: progid:DXImageTransform.Microsoft.gradient(enabled=false);
153 | }
154 |
155 | .btn-info:hover,
156 | .btn-info:focus {
157 | background-color: #2aabd2;
158 | background-position: 0 -15px;
159 | }
160 |
161 | .btn-info:active,
162 | .btn-info.active {
163 | background-color: #2aabd2;
164 | border-color: #28a4c9;
165 | }
166 |
167 | .thumbnail,
168 | .img-thumbnail {
169 | -webkit-box-shadow: 0 1px 2px rgba(0, 0, 0, 0.075);
170 | box-shadow: 0 1px 2px rgba(0, 0, 0, 0.075);
171 | }
172 |
173 | .dropdown-menu > li > a:hover,
174 | .dropdown-menu > li > a:focus {
175 | background-color: #e8e8e8;
176 | background-image: -webkit-linear-gradient(top, #f5f5f5 0%, #e8e8e8 100%);
177 | background-image: linear-gradient(to bottom, #f5f5f5 0%, #e8e8e8 100%);
178 | background-repeat: repeat-x;
179 | filter: progid:DXImageTransform.Microsoft.gradient(startColorstr='#fff5f5f5', endColorstr='#ffe8e8e8', GradientType=0);
180 | }
181 |
182 | .dropdown-menu > .active > a,
183 | .dropdown-menu > .active > a:hover,
184 | .dropdown-menu > .active > a:focus {
185 | background-color: #357ebd;
186 | background-image: -webkit-linear-gradient(top, #428bca 0%, #357ebd 100%);
187 | background-image: linear-gradient(to bottom, #428bca 0%, #357ebd 100%);
188 | background-repeat: repeat-x;
189 | filter: progid:DXImageTransform.Microsoft.gradient(startColorstr='#ff428bca', endColorstr='#ff357ebd', GradientType=0);
190 | }
191 |
192 | .navbar-default {
193 | background-image: -webkit-linear-gradient(top, #ffffff 0%, #f8f8f8 100%);
194 | background-image: linear-gradient(to bottom, #ffffff 0%, #f8f8f8 100%);
195 | background-repeat: repeat-x;
196 | border-radius: 4px;
197 | filter: progid:DXImageTransform.Microsoft.gradient(startColorstr='#ffffffff', endColorstr='#fff8f8f8', GradientType=0);
198 | filter: progid:DXImageTransform.Microsoft.gradient(enabled=false);
199 | -webkit-box-shadow: inset 0 1px 0 rgba(255, 255, 255, 0.15), 0 1px 5px rgba(0, 0, 0, 0.075);
200 | box-shadow: inset 0 1px 0 rgba(255, 255, 255, 0.15), 0 1px 5px rgba(0, 0, 0, 0.075);
201 | }
202 |
203 | .navbar-default .navbar-nav > .active > a {
204 | background-image: -webkit-linear-gradient(top, #ebebeb 0%, #f3f3f3 100%);
205 | background-image: linear-gradient(to bottom, #ebebeb 0%, #f3f3f3 100%);
206 | background-repeat: repeat-x;
207 | filter: progid:DXImageTransform.Microsoft.gradient(startColorstr='#ffebebeb', endColorstr='#fff3f3f3', GradientType=0);
208 | -webkit-box-shadow: inset 0 3px 9px rgba(0, 0, 0, 0.075);
209 | box-shadow: inset 0 3px 9px rgba(0, 0, 0, 0.075);
210 | }
211 |
212 | .navbar-brand,
213 | .navbar-nav > li > a {
214 | text-shadow: 0 1px 0 rgba(255, 255, 255, 0.25);
215 | }
216 |
217 | .navbar-inverse {
218 | background-image: -webkit-linear-gradient(top, #3c3c3c 0%, #222222 100%);
219 | background-image: linear-gradient(to bottom, #3c3c3c 0%, #222222 100%);
220 | background-repeat: repeat-x;
221 | filter: progid:DXImageTransform.Microsoft.gradient(startColorstr='#ff3c3c3c', endColorstr='#ff222222', GradientType=0);
222 | filter: progid:DXImageTransform.Microsoft.gradient(enabled=false);
223 | }
224 |
225 | .navbar-inverse .navbar-nav > .active > a {
226 | background-image: -webkit-linear-gradient(top, #222222 0%, #282828 100%);
227 | background-image: linear-gradient(to bottom, #222222 0%, #282828 100%);
228 | background-repeat: repeat-x;
229 | filter: progid:DXImageTransform.Microsoft.gradient(startColorstr='#ff222222', endColorstr='#ff282828', GradientType=0);
230 | -webkit-box-shadow: inset 0 3px 9px rgba(0, 0, 0, 0.25);
231 | box-shadow: inset 0 3px 9px rgba(0, 0, 0, 0.25);
232 | }
233 |
234 | .navbar-inverse .navbar-brand,
235 | .navbar-inverse .navbar-nav > li > a {
236 | text-shadow: 0 -1px 0 rgba(0, 0, 0, 0.25);
237 | }
238 |
239 | .navbar-static-top,
240 | .navbar-fixed-top,
241 | .navbar-fixed-bottom {
242 | border-radius: 0;
243 | }
244 |
245 | .alert {
246 | text-shadow: 0 1px 0 rgba(255, 255, 255, 0.2);
247 | -webkit-box-shadow: inset 0 1px 0 rgba(255, 255, 255, 0.25), 0 1px 2px rgba(0, 0, 0, 0.05);
248 | box-shadow: inset 0 1px 0 rgba(255, 255, 255, 0.25), 0 1px 2px rgba(0, 0, 0, 0.05);
249 | }
250 |
251 | .alert-success {
252 | background-image: -webkit-linear-gradient(top, #dff0d8 0%, #c8e5bc 100%);
253 | background-image: linear-gradient(to bottom, #dff0d8 0%, #c8e5bc 100%);
254 | background-repeat: repeat-x;
255 | border-color: #b2dba1;
256 | filter: progid:DXImageTransform.Microsoft.gradient(startColorstr='#ffdff0d8', endColorstr='#ffc8e5bc', GradientType=0);
257 | }
258 |
259 | .alert-info {
260 | background-image: -webkit-linear-gradient(top, #d9edf7 0%, #b9def0 100%);
261 | background-image: linear-gradient(to bottom, #d9edf7 0%, #b9def0 100%);
262 | background-repeat: repeat-x;
263 | border-color: #9acfea;
264 | filter: progid:DXImageTransform.Microsoft.gradient(startColorstr='#ffd9edf7', endColorstr='#ffb9def0', GradientType=0);
265 | }
266 |
267 | .alert-warning {
268 | background-image: -webkit-linear-gradient(top, #fcf8e3 0%, #f8efc0 100%);
269 | background-image: linear-gradient(to bottom, #fcf8e3 0%, #f8efc0 100%);
270 | background-repeat: repeat-x;
271 | border-color: #f5e79e;
272 | filter: progid:DXImageTransform.Microsoft.gradient(startColorstr='#fffcf8e3', endColorstr='#fff8efc0', GradientType=0);
273 | }
274 |
275 | .alert-danger {
276 | background-image: -webkit-linear-gradient(top, #f2dede 0%, #e7c3c3 100%);
277 | background-image: linear-gradient(to bottom, #f2dede 0%, #e7c3c3 100%);
278 | background-repeat: repeat-x;
279 | border-color: #dca7a7;
280 | filter: progid:DXImageTransform.Microsoft.gradient(startColorstr='#fff2dede', endColorstr='#ffe7c3c3', GradientType=0);
281 | }
282 |
283 | .progress {
284 | background-image: -webkit-linear-gradient(top, #ebebeb 0%, #f5f5f5 100%);
285 | background-image: linear-gradient(to bottom, #ebebeb 0%, #f5f5f5 100%);
286 | background-repeat: repeat-x;
287 | filter: progid:DXImageTransform.Microsoft.gradient(startColorstr='#ffebebeb', endColorstr='#fff5f5f5', GradientType=0);
288 | }
289 |
290 | .progress-bar {
291 | background-image: -webkit-linear-gradient(top, #428bca 0%, #3071a9 100%);
292 | background-image: linear-gradient(to bottom, #428bca 0%, #3071a9 100%);
293 | background-repeat: repeat-x;
294 | filter: progid:DXImageTransform.Microsoft.gradient(startColorstr='#ff428bca', endColorstr='#ff3071a9', GradientType=0);
295 | }
296 |
297 | .progress-bar-success {
298 | background-image: -webkit-linear-gradient(top, #5cb85c 0%, #449d44 100%);
299 | background-image: linear-gradient(to bottom, #5cb85c 0%, #449d44 100%);
300 | background-repeat: repeat-x;
301 | filter: progid:DXImageTransform.Microsoft.gradient(startColorstr='#ff5cb85c', endColorstr='#ff449d44', GradientType=0);
302 | }
303 |
304 | .progress-bar-info {
305 | background-image: -webkit-linear-gradient(top, #5bc0de 0%, #31b0d5 100%);
306 | background-image: linear-gradient(to bottom, #5bc0de 0%, #31b0d5 100%);
307 | background-repeat: repeat-x;
308 | filter: progid:DXImageTransform.Microsoft.gradient(startColorstr='#ff5bc0de', endColorstr='#ff31b0d5', GradientType=0);
309 | }
310 |
311 | .progress-bar-warning {
312 | background-image: -webkit-linear-gradient(top, #f0ad4e 0%, #ec971f 100%);
313 | background-image: linear-gradient(to bottom, #f0ad4e 0%, #ec971f 100%);
314 | background-repeat: repeat-x;
315 | filter: progid:DXImageTransform.Microsoft.gradient(startColorstr='#fff0ad4e', endColorstr='#ffec971f', GradientType=0);
316 | }
317 |
318 | .progress-bar-danger {
319 | background-image: -webkit-linear-gradient(top, #d9534f 0%, #c9302c 100%);
320 | background-image: linear-gradient(to bottom, #d9534f 0%, #c9302c 100%);
321 | background-repeat: repeat-x;
322 | filter: progid:DXImageTransform.Microsoft.gradient(startColorstr='#ffd9534f', endColorstr='#ffc9302c', GradientType=0);
323 | }
324 |
325 | .list-group {
326 | border-radius: 4px;
327 | -webkit-box-shadow: 0 1px 2px rgba(0, 0, 0, 0.075);
328 | box-shadow: 0 1px 2px rgba(0, 0, 0, 0.075);
329 | }
330 |
331 | .list-group-item.active,
332 | .list-group-item.active:hover,
333 | .list-group-item.active:focus {
334 | text-shadow: 0 -1px 0 #3071a9;
335 | background-image: -webkit-linear-gradient(top, #428bca 0%, #3278b3 100%);
336 | background-image: linear-gradient(to bottom, #428bca 0%, #3278b3 100%);
337 | background-repeat: repeat-x;
338 | border-color: #3278b3;
339 | filter: progid:DXImageTransform.Microsoft.gradient(startColorstr='#ff428bca', endColorstr='#ff3278b3', GradientType=0);
340 | }
341 |
342 | .panel {
343 | -webkit-box-shadow: 0 1px 2px rgba(0, 0, 0, 0.05);
344 | box-shadow: 0 1px 2px rgba(0, 0, 0, 0.05);
345 | }
346 |
347 | .panel-default > .panel-heading {
348 | background-image: -webkit-linear-gradient(top, #f5f5f5 0%, #e8e8e8 100%);
349 | background-image: linear-gradient(to bottom, #f5f5f5 0%, #e8e8e8 100%);
350 | background-repeat: repeat-x;
351 | filter: progid:DXImageTransform.Microsoft.gradient(startColorstr='#fff5f5f5', endColorstr='#ffe8e8e8', GradientType=0);
352 | }
353 |
354 | .panel-primary > .panel-heading {
355 | background-image: -webkit-linear-gradient(top, #428bca 0%, #357ebd 100%);
356 | background-image: linear-gradient(to bottom, #428bca 0%, #357ebd 100%);
357 | background-repeat: repeat-x;
358 | filter: progid:DXImageTransform.Microsoft.gradient(startColorstr='#ff428bca', endColorstr='#ff357ebd', GradientType=0);
359 | }
360 |
361 | .panel-success > .panel-heading {
362 | background-image: -webkit-linear-gradient(top, #dff0d8 0%, #d0e9c6 100%);
363 | background-image: linear-gradient(to bottom, #dff0d8 0%, #d0e9c6 100%);
364 | background-repeat: repeat-x;
365 | filter: progid:DXImageTransform.Microsoft.gradient(startColorstr='#ffdff0d8', endColorstr='#ffd0e9c6', GradientType=0);
366 | }
367 |
368 | .panel-info > .panel-heading {
369 | background-image: -webkit-linear-gradient(top, #d9edf7 0%, #c4e3f3 100%);
370 | background-image: linear-gradient(to bottom, #d9edf7 0%, #c4e3f3 100%);
371 | background-repeat: repeat-x;
372 | filter: progid:DXImageTransform.Microsoft.gradient(startColorstr='#ffd9edf7', endColorstr='#ffc4e3f3', GradientType=0);
373 | }
374 |
375 | .panel-warning > .panel-heading {
376 | background-image: -webkit-linear-gradient(top, #fcf8e3 0%, #faf2cc 100%);
377 | background-image: linear-gradient(to bottom, #fcf8e3 0%, #faf2cc 100%);
378 | background-repeat: repeat-x;
379 | filter: progid:DXImageTransform.Microsoft.gradient(startColorstr='#fffcf8e3', endColorstr='#fffaf2cc', GradientType=0);
380 | }
381 |
382 | .panel-danger > .panel-heading {
383 | background-image: -webkit-linear-gradient(top, #f2dede 0%, #ebcccc 100%);
384 | background-image: linear-gradient(to bottom, #f2dede 0%, #ebcccc 100%);
385 | background-repeat: repeat-x;
386 | filter: progid:DXImageTransform.Microsoft.gradient(startColorstr='#fff2dede', endColorstr='#ffebcccc', GradientType=0);
387 | }
388 |
389 | .well {
390 | background-image: -webkit-linear-gradient(top, #e8e8e8 0%, #f5f5f5 100%);
391 | background-image: linear-gradient(to bottom, #e8e8e8 0%, #f5f5f5 100%);
392 | background-repeat: repeat-x;
393 | border-color: #dcdcdc;
394 | filter: progid:DXImageTransform.Microsoft.gradient(startColorstr='#ffe8e8e8', endColorstr='#fff5f5f5', GradientType=0);
395 | -webkit-box-shadow: inset 0 1px 3px rgba(0, 0, 0, 0.05), 0 1px 0 rgba(255, 255, 255, 0.1);
396 | box-shadow: inset 0 1px 3px rgba(0, 0, 0, 0.05), 0 1px 0 rgba(255, 255, 255, 0.1);
397 | }
--------------------------------------------------------------------------------
/css/cambridgeenglish.css:
--------------------------------------------------------------------------------
1 | body #header,
2 | body #ad_topslot_a {
3 | display: none;
4 | }
5 |
--------------------------------------------------------------------------------
/css/cambridgeenglish.less:
--------------------------------------------------------------------------------
1 | body {
2 | #header, #ad_topslot_a {
3 | display: none
4 | }
5 |
6 | }
7 |
--------------------------------------------------------------------------------
/css/collins.css:
--------------------------------------------------------------------------------
1 | body header {
2 | display: none;
3 | }
4 |
--------------------------------------------------------------------------------
/css/collins.less:
--------------------------------------------------------------------------------
1 | body {
2 | header {
3 | display: none
4 | }
5 | }
6 |
--------------------------------------------------------------------------------
/css/dict-cn.css:
--------------------------------------------------------------------------------
1 | body #header {
2 | display: none;
3 | }
4 | body #content {
5 | padding-top: 60px;
6 | }
7 |
--------------------------------------------------------------------------------
/css/dict-cn.less:
--------------------------------------------------------------------------------
1 | body {
2 | #header {
3 | display: none;
4 | }
5 | #content {
6 | padding-top: 60px;
7 | }
8 | }
9 |
--------------------------------------------------------------------------------
/css/dictheader.css:
--------------------------------------------------------------------------------
1 | #fairy-dict {
2 | line-height: initial;
3 | box-sizing: border-box;
4 | /*Fix button and input styles on some websites*/
5 | }
6 | #fairy-dict .navbar {
7 | background-color: rgba(248, 250, 251, 0.75);
8 | padding-bottom: 0;
9 | margin-bottom: 0;
10 | z-index: 9000000304;
11 | }
12 | #fairy-dict .pron {
13 | color: #3a78d5;
14 | }
15 | #fairy-dict .example {
16 | color: #a26f14;
17 | }
18 | #fairy-dict .fa-coffee,
19 | #fairy-dict .fa-volume-up {
20 | color: black;
21 | }
22 | #fairy-dict .modal-body {
23 | padding-top: 8px;
24 | }
25 | #fairy-dict .navbar-form {
26 | padding: 5px 10px;
27 | margin: 0;
28 | }
29 | #fairy-dict .fa-2x {
30 | vertical-align: middle;
31 | }
32 | #fairy-dict .caret {
33 | margin-left: 5px;
34 | }
35 | #fairy-dict .navbar-form .dropdown-toggle {
36 | overflow: hidden;
37 | }
38 | #fairy-dict iframe {
39 | border: none;
40 | height: 620px;
41 | width: 100%;
42 | }
43 | #fairy-dict .default-page {
44 | margin-right: 10px;
45 | }
46 | #fairy-dict .search-group {
47 | display: block;
48 | position: relative;
49 | overflow: hidden;
50 | }
51 | #fairy-dict .search-group .starrr {
52 | position: relative;
53 | left: -15px;
54 | top: 5px;
55 | }
56 | #fairy-dict .search-group .fa-search {
57 | position: relative;
58 | right: 30px;
59 | top: 10px;
60 | cursor: pointer;
61 | }
62 | #fairy-dict .search-group .search-wrapper {
63 | display: block;
64 | overflow: hidden;
65 | padding-left: 10px;
66 | }
67 | #fairy-dict .search-group .search-wrapper .dict-input {
68 | width: 100%;
69 | margin: 0;
70 | }
71 | #fairy-dict .history-group .dropdown-menu {
72 | min-width: 220px;
73 | text-align: left;
74 | height: auto;
75 | max-height: 600px;
76 | overflow-y: auto;
77 | }
78 | #fairy-dict .history-group .dropdown-menu li > a {
79 | padding-right: 2px;
80 |
81 | overflow: hidden;
82 | text-overflow: ellipsis;
83 | width: 300px;
84 | white-space: nowrap;
85 | }
86 | #fairy-dict .history-group #history-btn {
87 | max-width: 100px;
88 | overflow: hidden;
89 | }
90 | #fairy-dict .history-group .vhide {
91 | visibility: hidden;
92 | }
93 | #fairy-dict .dict-group .dict-name {
94 | min-width: 180px;
95 | }
96 | #fairy-dict .dict-group .dict-list {
97 | text-align: left;
98 | min-width: 180px;
99 | overflow: hidden;
100 | }
101 | #fairy-dict .sound,
102 | #fairy-dict .default-page,
103 | #fairy-dict .dict_prev,
104 | #fairy-dict .dict_next {
105 | cursor: pointer;
106 | }
107 | #fairy-dict #fairy-stars {
108 | font-size: 20px;
109 | /*margin-left: 10px;*/
110 | margin-right: 5px;
111 | }
112 | #fairy-dict #fairy-stars i.fa {
113 | padding-left: 3px;
114 | color: orange;
115 | }
116 | #fairy-dict .fa.fa-star {
117 | color: orange;
118 | }
119 | #fairy-dict .btn {
120 | height: 34px;
121 | margin: 0 0 0 -1px;
122 | border: #cccccc solid 0.65px;
123 | padding: 6px 12px;
124 | box-shadow: none;
125 | }
126 | #fairy-dict input {
127 | width: 100%;
128 | height: 34px;
129 | padding: 6px 12px;
130 | box-sizing: border-box;
131 | }
132 |
--------------------------------------------------------------------------------
/css/dictheader.less:
--------------------------------------------------------------------------------
1 | #fairy-dict {
2 |
3 | line-height: initial;
4 | box-sizing: border-box;
5 |
6 | .navbar {
7 | background-color: rgba(248, 250, 251, 0.75);
8 | }
9 | .pron{
10 | color: rgb(58, 120, 213);
11 | }
12 | .example{
13 | color: rgb(162, 111, 20);
14 | }
15 | .fa-coffee, .fa-volume-up{
16 | color: black;
17 | }
18 |
19 | .modal-body{
20 | padding-top: 8px;
21 | }
22 |
23 | .navbar-form {
24 | padding: 5px 10px;
25 | }
26 | .form-group {
27 | // height: 34px;
28 | }
29 |
30 | .fa-2x{
31 | vertical-align: middle;
32 | }
33 |
34 | .caret{
35 | margin-left: 5px;
36 | }
37 |
38 | .navbar-form .dropdown-toggle {
39 | overflow: hidden;
40 | }
41 |
42 | iframe {
43 | border: none;
44 | height: 620px;
45 | width: 100%;
46 | }
47 |
48 | .default-page {
49 | margin-right: 10px;
50 | }
51 |
52 | .search-group {
53 | display: block;
54 | position: relative;
55 | overflow: hidden;
56 | .starrr {
57 | position: relative;
58 | left: -15px;
59 | top: 5px;
60 | }
61 |
62 | .fa-search {
63 | position: relative;
64 | right: 30px;
65 | top: 10px;
66 | cursor: pointer;
67 | }
68 | .search-wrapper {
69 | display: block;
70 | overflow: hidden;
71 | padding-left: 10px;
72 | .dict-input {
73 | width: 100%
74 | margin: 0; // override urban dictionary's style
75 | }
76 |
77 | }
78 | }
79 |
80 | .history-group {
81 | .dropdown-menu {
82 | min-width: 220px;
83 | text-align: left;
84 | height: auto;
85 | max-height: 600px;
86 | overflow-y: auto;
87 | }
88 |
89 | .dropdown-menu li>a {
90 | padding-right: 2px;
91 | }
92 | #history-btn {
93 | max-width: 100px;
94 | overflow: hidden;
95 | }
96 | .vhide {
97 | visibility: hidden;
98 | }
99 | }
100 |
101 | .dict-group {
102 | .dict-name {
103 | min-width: 180px;
104 | }
105 | .dict-list {
106 | text-align: left;
107 | min-width: 180px;
108 | overflow: hidden;
109 | }
110 | }
111 |
112 | .sound, .default-page, .dict_prev, .dict_next{
113 | cursor: pointer;
114 | }
115 |
116 | #fairy-stars {
117 | font-size: 20px;
118 | /*margin-left: 10px;*/
119 | margin-right: 5px;
120 | }
121 |
122 | #fairy-stars i.fa{
123 | padding-left: 3px;
124 | color: orange;
125 | }
126 |
127 | .fa.fa-star {
128 | color: orange;
129 | }
130 |
131 | /*Fix button and input styles on some websites*/
132 | .btn {
133 | height: 34px;
134 | margin: 0 0 0 -1px;
135 | border: rgb(204, 204, 204) solid 0.65px;
136 |
137 | padding: 6px 12px;
138 | box-shadow: none;
139 | }
140 |
141 | input {
142 | width: 100%;
143 | height: 34px;
144 | padding: 6px 12px;
145 | box-sizing: border-box; // fix on iciba.com
146 | }
147 |
148 | }
149 |
--------------------------------------------------------------------------------
/css/dictionary-com.css:
--------------------------------------------------------------------------------
1 | body .ham-nav,
2 | body .dicticon-hamburger-menu,
3 | body header.dictionary-header,
4 | body #fly-out,
5 | body iframe {
6 | display: none !important;
7 | }
8 | body #header-lb-container {
9 | padding-top: 100px;
10 | }
11 |
--------------------------------------------------------------------------------
/css/dictionary-com.less:
--------------------------------------------------------------------------------
1 | body {
2 | // padding-top: 90px !important;
3 |
4 | // iframe is ad.
5 | .ham-nav, .dicticon-hamburger-menu, header.dictionary-header, #fly-out, iframe {
6 | display: none !important;
7 | }
8 |
9 | #header-lb-container {
10 | padding-top: 100px;
11 | }
12 | }
13 |
--------------------------------------------------------------------------------
/css/eudic.css:
--------------------------------------------------------------------------------
1 | body {
2 | padding-top: 60px !important;
3 | }
4 | body header,
5 | body #head-bar,
6 | body #head-bk {
7 | display: none;
8 | }
9 |
--------------------------------------------------------------------------------
/css/eudic.less:
--------------------------------------------------------------------------------
1 | body {
2 | header, #head-bar, #head-bk {
3 | display: none;
4 | }
5 |
6 | padding-top: 60px !important;
7 | }
8 |
--------------------------------------------------------------------------------
/css/hjenglish.css:
--------------------------------------------------------------------------------
1 | .club_Header_pnl_newHead {
2 | display: none;
3 | }
4 |
5 | #xd_search {
6 | display: none;
7 | }
8 |
9 | #webbox-content {
10 | margin-top: 70px !important;
11 | }
12 |
--------------------------------------------------------------------------------
/css/iciba.css:
--------------------------------------------------------------------------------
1 | body .search,
2 | body .common-top {
3 | display: none;
4 | }
5 | body .screen {
6 | padding-top: 80px;
7 | }
8 |
--------------------------------------------------------------------------------
/css/iciba.less:
--------------------------------------------------------------------------------
1 | body {
2 | .search, .common-top {
3 | display: none;
4 | }
5 | .screen {
6 | padding-top: 80px;
7 | }
8 | }
9 |
--------------------------------------------------------------------------------
/css/longmanenglish.css:
--------------------------------------------------------------------------------
1 | body .header {
2 | display: none !important;
3 | }
4 | body .content {
5 | margin-top: 70px;
6 | }
7 |
--------------------------------------------------------------------------------
/css/longmanenglish.less:
--------------------------------------------------------------------------------
1 | body {
2 | .header {
3 | display: none !important;
4 | }
5 |
6 | .content {
7 | margin-top: 70px;
8 | }
9 | }
10 |
--------------------------------------------------------------------------------
/css/macmilland.css:
--------------------------------------------------------------------------------
1 | body #header,
2 | body #search_container {
3 | display: none !important;
4 | }
5 |
--------------------------------------------------------------------------------
/css/macmilland.less:
--------------------------------------------------------------------------------
1 | body {
2 | #header, #search_container {
3 | display: none !important;
4 | }
5 | }
6 |
--------------------------------------------------------------------------------
/css/merriamwebster.css:
--------------------------------------------------------------------------------
1 | body header,
2 | body .home-top-creative-cont {
3 | display: none;
4 | }
5 |
--------------------------------------------------------------------------------
/css/merriamwebster.less:
--------------------------------------------------------------------------------
1 | body {
2 | header, .home-top-creative-cont {
3 | display: none
4 | }
5 | }
6 |
--------------------------------------------------------------------------------
/css/options.css:
--------------------------------------------------------------------------------
1 | .indent {
2 | margin-left: 20px;
3 | }
4 |
--------------------------------------------------------------------------------
/css/options.less:
--------------------------------------------------------------------------------
1 | .indent {
2 | margin-left: 20px;
3 | }
4 |
--------------------------------------------------------------------------------
/css/oxfordlearner.css:
--------------------------------------------------------------------------------
1 | body .mainsearch {
2 | display: none;
3 | }
4 |
--------------------------------------------------------------------------------
/css/oxfordlearner.less:
--------------------------------------------------------------------------------
1 | body {
2 | .mainsearch {
3 | display: none
4 | }
5 | }
6 |
--------------------------------------------------------------------------------
/css/oxfordliving.css:
--------------------------------------------------------------------------------
1 | body #header {
2 | display: none;
3 | }
4 | body #main {
5 | padding-top: 0 !important;
6 | margin-top: 50px !important;
7 | }
8 |
--------------------------------------------------------------------------------
/css/oxfordliving.less:
--------------------------------------------------------------------------------
1 | body {
2 | #header {
3 | display: none;
4 | }
5 | #main {
6 | padding-top: 0 !important;
7 | margin-top: 50px !important;
8 | }
9 | }
10 |
--------------------------------------------------------------------------------
/css/urban.css:
--------------------------------------------------------------------------------
1 | body {
2 | padding-top: 15px !important;
3 | }
4 | body #urban-top-bar {
5 | display: none !important;
6 | }
7 |
--------------------------------------------------------------------------------
/css/urban.less:
--------------------------------------------------------------------------------
1 | body {
2 | padding-top: 15px !important;
3 |
4 | #urban-top-bar {
5 | display: none !important;
6 | }
7 | }
8 |
--------------------------------------------------------------------------------
/css/youdao.css:
--------------------------------------------------------------------------------
1 | body .c-topbar-wrapper {
2 | display: none;
3 | }
4 | body #scontainer {
5 | margin-top: 50px;
6 | padding-top: 0;
7 | }
8 |
--------------------------------------------------------------------------------
/css/youdao.less:
--------------------------------------------------------------------------------
1 | body {
2 | .c-topbar-wrapper {
3 | display: none
4 | }
5 | #scontainer {
6 | margin-top: 50px;
7 | padding-top: 0;
8 | }
9 |
10 | }
11 |
--------------------------------------------------------------------------------
/css/zdic.css:
--------------------------------------------------------------------------------
1 | body {
2 | padding-top: 70px;
3 | }
4 |
--------------------------------------------------------------------------------
/dict.coffee:
--------------------------------------------------------------------------------
1 | dictApp = angular.module('fairyDictApp', ['ui.bootstrap', 'ngSanitize'])
2 | dictApp.run ($rootScope)->
3 | $rootScope._ = _
4 |
5 | loader.loadTemplate().then ()->
6 | angular.bootstrap(document.getElementById('fairy-dict'), ['fairyDictApp'])
7 |
8 | dictApp.controller 'dictCtrl', ($scope, $sce) ->
9 | console.log "[dictCtrl] init"
10 |
11 | # change Bing dictionary's title
12 | document.title = 'Fairy Dict'
13 | baseNode = '#fairy-dict'
14 | $scope.initial = true
15 | $scope.querying = false
16 | $scope.queryResult = null
17 | $scope.historyIndex = -1
18 |
19 | chrome.runtime.sendMessage {
20 | type: 'dictionary'
21 | }, ({dictionary, allDicts, history})->
22 | console.log "[dict] all dicts: ", allDicts
23 | $scope.allDicts = allDicts
24 | $scope.currentDictionary = allDicts.find (d)->
25 | d.dictName == dictionary
26 | $scope.currentDictionary ?= allDicts[0]
27 | $scope.history = history.reverse()
28 | $scope.lastHistoryWord = $scope.history[0]
29 | $scope.$apply()
30 |
31 | chrome.runtime.sendMessage {
32 | type: 'setting'
33 | }, (setting)->
34 | $scope.setting = setting
35 |
36 | $scope.changeDict = (dict)->
37 | ci = $scope.allDicts.findIndex (d)->
38 | d.dictName == $scope.currentDictionary.dictName
39 |
40 | if dict == 'next'
41 | idx = (ci+1) % $scope.allDicts.length
42 | $scope.currentDictionary = $scope.allDicts[idx]
43 | else if dict == 'prev'
44 | idx = if ci > 0 then ci-1 else ($scope.allDicts.length-1)
45 | $scope.currentDictionary = $scope.allDicts[idx]
46 | else
47 | $scope.currentDictionary = dict
48 | $scope.query(true)
49 |
50 | applyHistory = (index)->
51 | $scope.historyIndex = index
52 | if index > -1
53 | $scope.word = _.keys($scope.history[index])[0]
54 | else
55 | $scope.word = $scope.lastQueryWord
56 |
57 | if index == $scope.history.length-1
58 | $scope.lastHistoryWord = $scope.history[0]
59 | else
60 | $scope.lastHistoryWord = $scope.history[index+1]
61 |
62 | $scope.selectHistory = (index)->
63 | if index == $scope.historyIndex
64 | return
65 | if index == 'prev'
66 | if $scope.historyIndex == $scope.history.length-1
67 | return
68 | index = $scope.historyIndex + 1
69 | else if index == 'next'
70 | if $scope.historyIndex < 0
71 | return
72 | index = $scope.historyIndex - 1
73 |
74 | if index >= $scope.history.length
75 | index = 0
76 |
77 | applyHistory(index)
78 |
79 | $scope.query(true)
80 |
81 | $scope.deleteHistory = (index)->
82 | item = $scope.history.splice(index, 1)
83 | chrome.runtime.sendMessage({
84 | type: 'deleteHistory',
85 | index: index,
86 | text: _.keys(item[0])[0]
87 | })
88 | return false
89 |
90 | $scope.query = (inHistory)->
91 | if not $scope.word or not $scope.currentDictionary
92 | $scope.initial = true
93 | return
94 |
95 | console.log "[dictCtrl] query `#{$scope.word}` from #{$scope.currentDictionary.dictName}"
96 | $scope.initial = false
97 | $scope.querying = true
98 |
99 | chrome.runtime.sendMessage({
100 | type: 'query',
101 | text: $scope.word,
102 | dictionary: $scope.currentDictionary.dictName,
103 | inHistory: inHistory
104 | })
105 |
106 | chrome.runtime.onMessage?.addListener (request, sender, sendResponse)->
107 | if request.type == 'querying'
108 | $scope.initial = false
109 | $scope.querying = true
110 | $scope.queryResult = null
111 | $scope.word = request.text
112 |
113 | else if request.type == 'queryResult'
114 | console.log "[dictCtrl] got query result for word: #{request.text}"
115 | if $scope.word == request.text or !$scope.word
116 | $scope.initial = false
117 | $scope.word = request.text
118 | $scope.querying = false
119 | if request.result?.html?
120 | $scope.queryResult = $sce.trustAsHtml(request.result.html)
121 | $scope.rating = request.rating
122 | updateRating(request.rating)
123 | if not request.inHistory
124 | $scope.lastQueryWord = $scope.word
125 | else
126 | $scope.history.forEach (item, idx)->
127 | itemText = _.keys(item)[0]
128 | if itemText == $scope.word
129 | applyHistory(idx)
130 |
131 | else if request.type == 'history'
132 | console.log "history", request.history
133 | $scope.history = request.history.reverse()
134 | $scope.lastHistoryWord = $scope.history[0]
135 | $scope.historyIndex = -1
136 |
137 | $scope.$apply()
138 |
139 | $('#fairy-stars', baseNode).on 'starrr:change', (e, value)->
140 | if $scope.word
141 | value ?= 0
142 | console.log "[dictCtrl] rating word: #{$scope.word} #{value}"
143 | chrome.runtime.sendMessage {
144 | type: 'rating',
145 | value: value,
146 | text: $scope.word
147 | }
148 | if $scope.historyIndex >= 0
149 | item = $scope.history[$scope.historyIndex]
150 | if item and item[$scope.word]?
151 | item[$scope.word] = value
152 |
153 | $('.starrr', baseNode).starrr({numStars: 3})
154 |
155 | updateRating = (value)->
156 | obj = $(".starrr", baseNode).data('star-rating')
157 | obj.options.rating = value
158 | obj.syncRating()
159 |
160 | _handler = (evt)->
161 | node = $(event.target)
162 | if node.is('.sound')
163 | a = node.next('audio')
164 | if a.length
165 | a[0].play()
166 |
167 | $(document).mouseover _handler
168 | $(document).click _handler
169 |
170 | $(document).keyup (evt)->
171 | code = evt.charCode or evt.keyCode
172 | if code == 27
173 | $('input.dict-input', baseNode)[0].select()
174 |
175 | $(document).keydown (evt)->
176 | code = evt.charCode or evt.keyCode
177 | prevSK = $scope.setting.prevDictSK1
178 | nextSK = $scope.setting.nextDictSK1
179 | prevKey = $scope.setting.prevDictKey
180 | nextKey = $scope.setting.nextDictKey
181 | stop = false
182 |
183 | if window.utils.checkEventKey evt, prevSK, null, prevKey
184 | $scope.changeDict('prev')
185 | stop = true
186 | if window.utils.checkEventKey evt, nextSK, null, nextKey
187 | $scope.changeDict('next')
188 | stop = true
189 | if window.utils.checkEventKey evt, $scope.setting.prevHistorySK1, null, $scope.setting.prevHistoryKey
190 | $scope.selectHistory('prev')
191 | stop = true
192 | if window.utils.checkEventKey evt, $scope.setting.nextHistorySK1, null, $scope.setting.nextHistoryKey
193 | $scope.selectHistory('next')
194 | stop = true
195 | if stop
196 | evt.preventDefault()
197 | evt.stopPropagation()
198 | return
199 |
200 |
--------------------------------------------------------------------------------
/dict.js:
--------------------------------------------------------------------------------
1 | // Generated by CoffeeScript 1.10.0
2 | var dictApp;
3 |
4 | dictApp = angular.module('fairyDictApp', ['ui.bootstrap', 'ngSanitize']);
5 |
6 | dictApp.run(function($rootScope) {
7 | return $rootScope._ = _;
8 | });
9 |
10 | loader.loadTemplate().then(function() {
11 | return angular.bootstrap(document.getElementById('fairy-dict'), ['fairyDictApp']);
12 | });
13 |
14 | dictApp.controller('dictCtrl', function($scope, $sce) {
15 | var _handler, applyHistory, baseNode, ref, updateRating;
16 | console.log("[dictCtrl] init");
17 | document.title = 'Fairy Dict';
18 | baseNode = '#fairy-dict';
19 | $scope.initial = true;
20 | $scope.querying = false;
21 | $scope.queryResult = null;
22 | $scope.historyIndex = -1;
23 | chrome.runtime.sendMessage({
24 | type: 'dictionary'
25 | }, function(arg) {
26 | var allDicts, dictionary, history;
27 | dictionary = arg.dictionary, allDicts = arg.allDicts, history = arg.history;
28 | console.log("[dict] all dicts: ", allDicts);
29 | $scope.allDicts = allDicts;
30 | $scope.currentDictionary = allDicts.find(function(d) {
31 | return d.dictName === dictionary;
32 | });
33 | if ($scope.currentDictionary == null) {
34 | $scope.currentDictionary = allDicts[0];
35 | }
36 | $scope.history = history.reverse();
37 | $scope.lastHistoryWord = $scope.history[0];
38 | return $scope.$apply();
39 | });
40 | chrome.runtime.sendMessage({
41 | type: 'setting'
42 | }, function(setting) {
43 | return $scope.setting = setting;
44 | });
45 | $scope.changeDict = function(dict) {
46 | var ci, idx;
47 | ci = $scope.allDicts.findIndex(function(d) {
48 | return d.dictName === $scope.currentDictionary.dictName;
49 | });
50 | if (dict === 'next') {
51 | idx = (ci + 1) % $scope.allDicts.length;
52 | $scope.currentDictionary = $scope.allDicts[idx];
53 | } else if (dict === 'prev') {
54 | idx = ci > 0 ? ci - 1 : $scope.allDicts.length - 1;
55 | $scope.currentDictionary = $scope.allDicts[idx];
56 | } else {
57 | $scope.currentDictionary = dict;
58 | }
59 | return $scope.query(true);
60 | };
61 | applyHistory = function(index) {
62 | $scope.historyIndex = index;
63 | if (index > -1) {
64 | $scope.word = _.keys($scope.history[index])[0];
65 | } else {
66 | $scope.word = $scope.lastQueryWord;
67 | }
68 | if (index === $scope.history.length - 1) {
69 | return $scope.lastHistoryWord = $scope.history[0];
70 | } else {
71 | return $scope.lastHistoryWord = $scope.history[index + 1];
72 | }
73 | };
74 | $scope.selectHistory = function(index) {
75 | if (index === $scope.historyIndex) {
76 | return;
77 | }
78 | if (index === 'prev') {
79 | if ($scope.historyIndex === $scope.history.length - 1) {
80 | return;
81 | }
82 | index = $scope.historyIndex + 1;
83 | } else if (index === 'next') {
84 | if ($scope.historyIndex < 0) {
85 | return;
86 | }
87 | index = $scope.historyIndex - 1;
88 | }
89 | if (index >= $scope.history.length) {
90 | index = 0;
91 | }
92 | applyHistory(index);
93 | return $scope.query(true);
94 | };
95 | $scope.deleteHistory = function(index) {
96 | var item;
97 | item = $scope.history.splice(index, 1);
98 | chrome.runtime.sendMessage({
99 | type: 'deleteHistory',
100 | index: index,
101 | text: _.keys(item[0])[0]
102 | });
103 | return false;
104 | };
105 | $scope.query = function(inHistory) {
106 | if (!$scope.word || !$scope.currentDictionary) {
107 | $scope.initial = true;
108 | return;
109 | }
110 | console.log("[dictCtrl] query `" + $scope.word + "` from " + $scope.currentDictionary.dictName);
111 | $scope.initial = false;
112 | $scope.querying = true;
113 | return chrome.runtime.sendMessage({
114 | type: 'query',
115 | text: $scope.word,
116 | dictionary: $scope.currentDictionary.dictName,
117 | inHistory: inHistory
118 | });
119 | };
120 | if ((ref = chrome.runtime.onMessage) != null) {
121 | ref.addListener(function(request, sender, sendResponse) {
122 | var ref1;
123 | if (request.type === 'querying') {
124 | $scope.initial = false;
125 | $scope.querying = true;
126 | $scope.queryResult = null;
127 | $scope.word = request.text;
128 | } else if (request.type === 'queryResult') {
129 | console.log("[dictCtrl] got query result for word: " + request.text);
130 | if ($scope.word === request.text || !$scope.word) {
131 | $scope.initial = false;
132 | $scope.word = request.text;
133 | $scope.querying = false;
134 | if (((ref1 = request.result) != null ? ref1.html : void 0) != null) {
135 | $scope.queryResult = $sce.trustAsHtml(request.result.html);
136 | }
137 | $scope.rating = request.rating;
138 | updateRating(request.rating);
139 | if (!request.inHistory) {
140 | $scope.lastQueryWord = $scope.word;
141 | } else {
142 | $scope.history.forEach(function(item, idx) {
143 | var itemText;
144 | itemText = _.keys(item)[0];
145 | if (itemText === $scope.word) {
146 | return applyHistory(idx);
147 | }
148 | });
149 | }
150 | }
151 | } else if (request.type === 'history') {
152 | console.log("history", request.history);
153 | $scope.history = request.history.reverse();
154 | $scope.lastHistoryWord = $scope.history[0];
155 | $scope.historyIndex = -1;
156 | }
157 | return $scope.$apply();
158 | });
159 | }
160 | $('#fairy-stars', baseNode).on('starrr:change', function(e, value) {
161 | var item;
162 | if ($scope.word) {
163 | if (value == null) {
164 | value = 0;
165 | }
166 | console.log("[dictCtrl] rating word: " + $scope.word + " " + value);
167 | chrome.runtime.sendMessage({
168 | type: 'rating',
169 | value: value,
170 | text: $scope.word
171 | });
172 | if ($scope.historyIndex >= 0) {
173 | item = $scope.history[$scope.historyIndex];
174 | if (item && (item[$scope.word] != null)) {
175 | return item[$scope.word] = value;
176 | }
177 | }
178 | }
179 | });
180 | $('.starrr', baseNode).starrr({
181 | numStars: 3
182 | });
183 | updateRating = function(value) {
184 | var obj;
185 | obj = $(".starrr", baseNode).data('star-rating');
186 | obj.options.rating = value;
187 | return obj.syncRating();
188 | };
189 | _handler = function(evt) {
190 | var a, node;
191 | node = $(event.target);
192 | if (node.is('.sound')) {
193 | a = node.next('audio');
194 | if (a.length) {
195 | return a[0].play();
196 | }
197 | }
198 | };
199 | $(document).mouseover(_handler);
200 | $(document).click(_handler);
201 | $(document).keyup(function(evt) {
202 | var code;
203 | code = evt.charCode || evt.keyCode;
204 | if (code === 27) {
205 | return $('input.dict-input', baseNode)[0].select();
206 | }
207 | });
208 | $(document).keydown(function(evt) {
209 | var code, nextKey, nextSK, prevKey, prevSK, stop;
210 | code = evt.charCode || evt.keyCode;
211 | prevSK = $scope.setting.prevDictSK1;
212 | nextSK = $scope.setting.nextDictSK1;
213 | prevKey = $scope.setting.prevDictKey;
214 | nextKey = $scope.setting.nextDictKey;
215 | stop = false;
216 | if (window.utils.checkEventKey(evt, prevSK, null, prevKey)) {
217 | $scope.changeDict('prev');
218 | stop = true;
219 | }
220 | if (window.utils.checkEventKey(evt, nextSK, null, nextKey)) {
221 | $scope.changeDict('next');
222 | stop = true;
223 | }
224 | if (window.utils.checkEventKey(evt, $scope.setting.prevHistorySK1, null, $scope.setting.prevHistoryKey)) {
225 | $scope.selectHistory('prev');
226 | stop = true;
227 | }
228 | if (window.utils.checkEventKey(evt, $scope.setting.nextHistorySK1, null, $scope.setting.nextHistoryKey)) {
229 | $scope.selectHistory('next');
230 | stop = true;
231 | }
232 | if (stop) {
233 | evt.preventDefault();
234 | return evt.stopPropagation();
235 | }
236 | });
237 | });
238 |
--------------------------------------------------------------------------------
/fonts/FontAwesome.otf:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/revir/FairyDict/ac7722ceda402af1cf420cf7077a06c341e5d5d9/fonts/FontAwesome.otf
--------------------------------------------------------------------------------
/fonts/fairydict-font.woff:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/revir/FairyDict/ac7722ceda402af1cf420cf7077a06c341e5d5d9/fonts/fairydict-font.woff
--------------------------------------------------------------------------------
/fonts/fontawesome-webfont.eot:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/revir/FairyDict/ac7722ceda402af1cf420cf7077a06c341e5d5d9/fonts/fontawesome-webfont.eot
--------------------------------------------------------------------------------
/fonts/fontawesome-webfont.ttf:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/revir/FairyDict/ac7722ceda402af1cf420cf7077a06c341e5d5d9/fonts/fontawesome-webfont.ttf
--------------------------------------------------------------------------------
/fonts/fontawesome-webfont.woff:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/revir/FairyDict/ac7722ceda402af1cf420cf7077a06c341e5d5d9/fonts/fontawesome-webfont.woff
--------------------------------------------------------------------------------
/fonts/fontawesome-webfont.woff2:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/revir/FairyDict/ac7722ceda402af1cf420cf7077a06c341e5d5d9/fonts/fontawesome-webfont.woff2
--------------------------------------------------------------------------------
/fonts/glyphicons-halflings-regular.eot:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/revir/FairyDict/ac7722ceda402af1cf420cf7077a06c341e5d5d9/fonts/glyphicons-halflings-regular.eot
--------------------------------------------------------------------------------
/fonts/glyphicons-halflings-regular.ttf:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/revir/FairyDict/ac7722ceda402af1cf420cf7077a06c341e5d5d9/fonts/glyphicons-halflings-regular.ttf
--------------------------------------------------------------------------------
/fonts/glyphicons-halflings-regular.woff:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/revir/FairyDict/ac7722ceda402af1cf420cf7077a06c341e5d5d9/fonts/glyphicons-halflings-regular.woff
--------------------------------------------------------------------------------
/helper.coffee:
--------------------------------------------------------------------------------
1 | helperFn = (window, $)->
2 | gConfig = window.gConfig
3 |
4 | window.helper = {
5 | getRandomInt: (min, max)->
6 | min ?= 1
7 | max ?= 10
8 | min = Math.ceil(min)
9 | max = Math.floor(max)
10 | return Math.floor(Math.random() * (max - min)) + min
11 |
12 | sendMessage: (config)->
13 | dfd = $.Deferred()
14 | chrome.runtime.sendMessage(config, (response)->
15 | dfd.resolve(response)
16 | )
17 | return dfd
18 |
19 | getJson: (url, data)->
20 | return this.sendMessage({url, data, type: 'getJson'})
21 |
22 | postJson: (url, data)->
23 | return this.sendMessage({url, data, type: 'postJson'})
24 |
25 | }
26 |
27 | helperFn(this, $)
28 |
--------------------------------------------------------------------------------
/helper.js:
--------------------------------------------------------------------------------
1 | // Generated by CoffeeScript 1.10.0
2 | var helperFn;
3 |
4 | helperFn = function(window, $) {
5 | var gConfig;
6 | gConfig = window.gConfig;
7 | return window.helper = {
8 | getRandomInt: function(min, max) {
9 | if (min == null) {
10 | min = 1;
11 | }
12 | if (max == null) {
13 | max = 10;
14 | }
15 | min = Math.ceil(min);
16 | max = Math.floor(max);
17 | return Math.floor(Math.random() * (max - min)) + min;
18 | },
19 | sendMessage: function(config) {
20 | var dfd;
21 | dfd = $.Deferred();
22 | chrome.runtime.sendMessage(config, function(response) {
23 | return dfd.resolve(response);
24 | });
25 | return dfd;
26 | },
27 | getJson: function(url, data) {
28 | return this.sendMessage({
29 | url: url,
30 | data: data,
31 | type: 'getJson'
32 | });
33 | },
34 | postJson: function(url, data) {
35 | return this.sendMessage({
36 | url: url,
37 | data: data,
38 | type: 'postJson'
39 | });
40 | }
41 | };
42 | };
43 |
44 | helperFn(this, $);
45 |
--------------------------------------------------------------------------------
/images/books-128.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/revir/FairyDict/ac7722ceda402af1cf420cf7077a06c341e5d5d9/images/books-128.png
--------------------------------------------------------------------------------
/images/books-48.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/revir/FairyDict/ac7722ceda402af1cf420cf7077a06c341e5d5d9/images/books-48.png
--------------------------------------------------------------------------------
/images/books-96.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/revir/FairyDict/ac7722ceda402af1cf420cf7077a06c341e5d5d9/images/books-96.png
--------------------------------------------------------------------------------
/images/books-b-48.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/revir/FairyDict/ac7722ceda402af1cf420cf7077a06c341e5d5d9/images/books-b-48.png
--------------------------------------------------------------------------------
/images/books-b-96.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/revir/FairyDict/ac7722ceda402af1cf420cf7077a06c341e5d5d9/images/books-b-96.png
--------------------------------------------------------------------------------
/images/gplus32.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/revir/FairyDict/ac7722ceda402af1cf420cf7077a06c341e5d5d9/images/gplus32.png
--------------------------------------------------------------------------------
/images/tom.jpg:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/revir/FairyDict/ac7722ceda402af1cf420cf7077a06c341e5d5d9/images/tom.jpg
--------------------------------------------------------------------------------
/images/twitter32.jpg:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/revir/FairyDict/ac7722ceda402af1cf420cf7077a06c341e5d5d9/images/twitter32.jpg
--------------------------------------------------------------------------------
/images/wordpress32.jpg:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/revir/FairyDict/ac7722ceda402af1cf420cf7077a06c341e5d5d9/images/wordpress32.jpg
--------------------------------------------------------------------------------
/js/ion.sound.js:
--------------------------------------------------------------------------------
1 | // Ion.Sound
2 | // version 1.3.0 Build: 20
3 | // © 2013 Denis Ineshin | IonDen.com
4 | //
5 | // Project page: http://ionden.com/a/plugins/ion.sound/en.html
6 | // GitHub page: https://github.com/IonDen/ion.sound
7 | //
8 | // Released under MIT licence:
9 | // http://ionden.com/a/plugins/licence-en.html
10 | // =====================================================================================================================
11 |
12 | (function ($) {
13 |
14 | if ($.ionSound) {
15 | return;
16 | }
17 |
18 |
19 | var settings = {},
20 | soundsNum,
21 | canMp3,
22 | url,
23 | i,
24 |
25 | sounds = {},
26 | playing = false,
27 |
28 | VERSION = "1.3.0";
29 |
30 |
31 | var createSound = function (soundInfo) {
32 | var name,
33 | volume;
34 |
35 | if (soundInfo.indexOf(":") !== -1) {
36 | name = soundInfo.split(":")[0];
37 | volume = soundInfo.split(":")[1];
38 | } else {
39 | name = soundInfo;
40 | }
41 |
42 | sounds[name] = new Audio();
43 | canMp3 = sounds[name].canPlayType("audio/mp3");
44 | if (canMp3 === "probably" || canMp3 === "maybe") {
45 | url = settings.path + name + ".mp3";
46 | } else {
47 | url = settings.path + name + ".ogg";
48 | }
49 |
50 | $(sounds[name]).prop("src", url);
51 | sounds[name].load();
52 | sounds[name].preload = "auto";
53 | sounds[name].volume = volume || settings.volume;
54 | };
55 |
56 |
57 | var playSound = function (info) {
58 | var $sound,
59 | name,
60 | volume,
61 | playing_int;
62 |
63 | if (info.indexOf(":") !== -1) {
64 | name = info.split(":")[0];
65 | volume = info.split(":")[1];
66 | } else {
67 | name = info;
68 | }
69 |
70 | $sound = sounds[name];
71 |
72 | if (typeof $sound !== "object" || $sound === null) {
73 | return;
74 | }
75 |
76 |
77 | if (volume) {
78 | $sound.volume = volume;
79 | }
80 |
81 | if (!settings.multiPlay && !playing) {
82 |
83 | $sound.play();
84 | playing = true;
85 |
86 | playing_int = setInterval(function () {
87 | if ($sound.ended) {
88 | clearInterval(playing_int);
89 | playing = false;
90 | }
91 | }, 250);
92 |
93 | } else if (settings.multiPlay) {
94 |
95 | if ($sound.ended) {
96 | $sound.play();
97 | } else {
98 | try {
99 | $sound.currentTime = 0;
100 | } catch (e) {}
101 | $sound.play();
102 | }
103 |
104 | }
105 | };
106 |
107 |
108 | var stopSound = function (name) {
109 | var $sound = sounds[name];
110 |
111 | if (typeof $sound !== "object" || $sound === null) {
112 | return;
113 | }
114 |
115 | $sound.pause();
116 | try {
117 | $sound.currentTime = 0;
118 | } catch (e) {}
119 | };
120 |
121 |
122 | var killSound = function (name) {
123 | var $sound = sounds[name];
124 |
125 | if (typeof $sound !== "object" || $sound === null) {
126 | return;
127 | }
128 |
129 | try {
130 | sounds[name].src = "";
131 | } catch (e) {}
132 | sounds[name] = null;
133 | };
134 |
135 |
136 | // Plugin methods
137 | $.ionSound = function (options) {
138 |
139 | settings = $.extend({
140 | sounds: [
141 | "water_droplet"
142 | ],
143 | path: "static/sounds/",
144 | multiPlay: true,
145 | volume: "0.5"
146 | }, options);
147 |
148 | soundsNum = settings.sounds.length;
149 |
150 | if (typeof Audio === "function" || typeof Audio === "object") {
151 | for (i = 0; i < soundsNum; i += 1) {
152 | createSound(settings.sounds[i]);
153 | }
154 | }
155 |
156 | $.ionSound.play = function (name) {
157 | playSound(name);
158 | };
159 | $.ionSound.stop = function (name) {
160 | stopSound(name);
161 | };
162 | $.ionSound.kill = function (name) {
163 | killSound(name);
164 | };
165 | };
166 |
167 |
168 | $.ionSound.destroy = function () {
169 | for (i = 0; i < soundsNum; i += 1) {
170 | sounds[settings.sounds[i]] = null;
171 | }
172 | soundsNum = 0;
173 | $.ionSound.play = function () {};
174 | $.ionSound.stop = function () {};
175 | $.ionSound.kill = function () {};
176 | };
177 |
178 | }(jQuery));
--------------------------------------------------------------------------------
/js/jquery.scoped.js:
--------------------------------------------------------------------------------
1 | /*
2 | * jQuery Scoped CSS plugin
3 | * This adds support for the CSS scoped attribute to limit a block of style declarations
4 | * to a specific area of the HTML. You can also use @import and media filters in scoped blocks
5 | * http://www.w3.org/TR/html5/semantics.html#the-style-element
6 | *
7 | * Simon Madine, 1 February 2011
8 | *
9 | * Use:
10 | * Include this plugin file (minified, ideally) and call $.scoped() on load
11 | *
12 | * Limitations:
13 | * - If you're using multiple nested declarations, Webkit might apply different inheritance
14 | * specificity rules from the other engines. I don't know who's right.
15 | * - Sometimes there are delays parsing externally loaded stylesheets (via @import) and they
16 | * might get skipped. Not often but it happens.
17 | *
18 | * Notes:
19 | * - If the browser natively supports
32 | FairyDict 选项
33 |
34 |
35 |
36 |
37 |
FairyDict
38 |
Notice: FairyDict 的升级版
39 | Dictionaries
40 | 已发布, 添加了管理单词表和词典列表的功能, 更多的设置和功能, 欢迎去下载使用
41 | Dictionaries.
42 |
43 |
44 | FairyDict 将不再更新!
45 |
46 |
47 | 此软件是开源软件,喜欢请帮忙评价或点赞,有任何问题或建议请在
48 | Github
49 | 或
50 | V2MM
51 | 上联系我 ;)
52 |
53 |
54 |
55 |
56 |
57 |
功能设置
58 |
59 |
60 |
64 |
65 |
66 |
67 | 同时必须按住
68 |
69 |
70 |
74 |
75 |
80 |
81 |
82 |
83 | 悬停延时检测时间
84 | 毫秒
88 |
89 |
90 |
91 |
92 |
93 |
96 |
97 |
98 |
102 |
103 |
107 |
108 |
109 |
113 |
114 |
115 |
119 |
120 |
125 |
126 |
127 |
128 |
129 |
130 |
131 |
134 |
135 |
136 |
140 |
141 |
142 |
146 |
147 |
152 |
153 |
154 |
155 |
156 |
168 |
169 |
170 |
171 |
172 |
173 |
快捷键设置
174 |
175 |
176 |
177 |
178 | 呼出词典:
179 |
180 |
181 |
185 |
186 |
191 |
192 |
193 |
194 |
198 |
199 |
204 |
205 |
206 |
207 |
211 |
212 |
217 |
218 |
219 |
220 |
221 | 查找上一个词典:
222 |
223 |
224 |
228 |
229 |
234 |
235 |
236 |
240 |
241 |
246 |
247 |
248 |
249 |
250 | 查找下一个词典:
251 |
252 |
253 |
257 |
258 |
263 |
264 |
265 |
269 |
270 |
275 |
276 |
277 |
278 |
279 |
280 | 查找上一个历史记录:
281 |
282 |
283 |
287 |
288 |
293 |
294 |
295 |
299 |
300 |
305 |
306 |
307 |
308 |
309 | 查找下一个历史记录:
310 |
311 |
312 |
316 |
317 |
322 |
323 |
324 |
328 |
329 |
334 |
335 |
336 |
337 |
338 |
339 |
340 |
341 |
好用就分享
342 |
362 |
363 |
364 |
365 |
366 |