├── images ├── icon.png ├── icon128.png ├── icon16.png ├── icon48.png └── search.png ├── scripts ├── locales.js ├── background.js └── window.js ├── manifest.json ├── popup ├── popup.html ├── popup.js └── popup.css ├── LICENSE └── README.md /images/icon.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ganzorig-ganbat/bolor-tolidogch/HEAD/images/icon.png -------------------------------------------------------------------------------- /images/icon128.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ganzorig-ganbat/bolor-tolidogch/HEAD/images/icon128.png -------------------------------------------------------------------------------- /images/icon16.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ganzorig-ganbat/bolor-tolidogch/HEAD/images/icon16.png -------------------------------------------------------------------------------- /images/icon48.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ganzorig-ganbat/bolor-tolidogch/HEAD/images/icon48.png -------------------------------------------------------------------------------- /images/search.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ganzorig-ganbat/bolor-tolidogch/HEAD/images/search.png -------------------------------------------------------------------------------- /scripts/locales.js: -------------------------------------------------------------------------------- 1 | /* Copyright (c) 2017 Kenzo. All rights reserved. */ 2 | 3 | export const bolorLocales = [ 4 | { 5 | direction: "1", 6 | title: "Монгол <> Англи", 7 | }, 8 | { 9 | direction: "3", 10 | title: "Монгол <> Герман", 11 | }, 12 | { 13 | direction: "4", 14 | title: "Монгол <> Солонгос", 15 | }, 16 | { 17 | direction: "5", 18 | title: "Монгол <> Япон", 19 | }, 20 | { 21 | direction: "7", 22 | title: "Монгол <> Хятад", 23 | }, 24 | { 25 | direction: "8", 26 | title: "Монгол <> Орос", 27 | }, 28 | ]; 29 | -------------------------------------------------------------------------------- /manifest.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "Bolor Tolidogch", 3 | "version": "2.0", 4 | "description": "Bolor tolidogch by Kenzo. Unofficial Bolor toli chrome extension.", 5 | "manifest_version": 3, 6 | "action": { 7 | "default_title": "Bolor Tolidogch", 8 | "default_icon": "images/icon.png", 9 | "default_popup": "popup/popup.html" 10 | }, 11 | "icons": { 12 | "16": "images/icon16.png", 13 | "48": "images/icon48.png", 14 | "128": "images/icon128.png" 15 | }, 16 | "permissions": ["contextMenus", "storage"], 17 | "background": { 18 | "service_worker": "scripts/background.js", 19 | "type": "module" 20 | } 21 | } 22 | -------------------------------------------------------------------------------- /popup/popup.html: -------------------------------------------------------------------------------- 1 | 2 | 7 | 8 | 9 | 10 | Bolor Toli-догч 11 | 12 | 13 | 14 |
15 |
16 |
17 |

Хайх үгээ оруулна уу!

18 |
19 |
20 | 21 | 22 | -------------------------------------------------------------------------------- /scripts/background.js: -------------------------------------------------------------------------------- 1 | /* Copyright (c) 2017 Kenzo. All rights reserved. */ 2 | 3 | import { bolorLocales } from "./locales.js"; 4 | import { updateWindow } from "./window.js"; 5 | 6 | chrome.runtime.onInstalled.addListener(async () => { 7 | for (const { direction, title } of bolorLocales) { 8 | chrome.contextMenus.create({ 9 | id: direction, 10 | title: title, 11 | type: "normal", 12 | contexts: ["selection"], 13 | }); 14 | } 15 | }); 16 | 17 | chrome.contextMenus.onClicked.addListener((item) => { 18 | const direction = item.menuItemId; 19 | const search_text = item.selectionText; 20 | console.log(direction, search_text); 21 | updateWindow(search_text, direction); 22 | }); 23 | -------------------------------------------------------------------------------- /LICENSE: -------------------------------------------------------------------------------- 1 | MIT License 2 | 3 | Copyright (c) 2017 Ganzorig 4 | 5 | Permission is hereby granted, free of charge, to any person obtaining a copy 6 | of this software and associated documentation files (the "Software"), to deal 7 | in the Software without restriction, including without limitation the rights 8 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 9 | copies of the Software, and to permit persons to whom the Software is 10 | furnished to do so, subject to the following conditions: 11 | 12 | The above copyright notice and this permission notice shall be included in all 13 | copies or substantial portions of the Software. 14 | 15 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 16 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 17 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 18 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 19 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 20 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 21 | SOFTWARE. 22 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # Тухай 2 | 3 | Bolor tolidogch нь Bolor-toli.com сайтын хэрэглээг хялбаршуулахыг зорьсон chrome extension юм. Bolor-toli.com сайтыг байнга ашигладаг хүмүүс тохиромжтой. ( Bolor-toli.com сайтын албан ёсны бус chrome extension. ) 4 | 5 | Bolor-toli.com сайт нь Монголчуудын хамгийн ихээр ордог толь бичгийн сайт юм. 6 | 7 | ## Суулгах 8 | 9 | a. Дараах холбоосоор орж татаж авч суулгаж болно. https://chrome.google.com/webstore/detail/bolor-toli-%D0%B4%D0%BE%D0%B3%D1%87-extension/pnijfkjcnhmfndeiaeadoamipoipcoeh 10 | 11 | b. Эсвэл кодыг нь github.com сайтаас татаж аваад суулгахдаа **chrome://extensions** гэсэн хаягаар ороод **"Load unpacked"** гэсэн товч дээр дарж кодын байрлах фолдэрийг зааж өгнө. 12 | ![Bolor tolidogch-ийг суулгах заавар](https://i.imgur.com/lnjMALv.png) 13 | 14 | ## Боломжууд: 15 | 16 | - Та энэхүү extension-ийг суулгасанаар орчуулахыг хүссэн текстээ идэвхижүүлэн хулганы баруун гар талын товч буюу "mouse 2" товчоо даран "Bolor tolidogch" гэсэн товч дээр даран орчуулна. 17 | 18 | ![Bolor tolidogch-ийг хэрэглэх заавар 1](https://i.imgur.com/byyVhPA.jpg) 19 | 20 | - Хөтөчийн баруун дээд талд байрлах Bolor tolidogch-ийн icon буюу жижиг зурган дээр дарж гарч ирэх текст бичих хэсэгт өөрийн орчуулахыг хүссэн үгээ бичин хайх товч дарна. 21 | 22 | ![Bolor tolidogch-ийг хэрэглэх заавар 2](https://i.imgur.com/8KiZxbX.png) 23 | 24 | ## Цаашид сайжруулах: 25 | 26 | - Хайсан үгнүүдээр түүх (history) үүсгэх. 27 | - Заавал mouse 2 дарахгүйгээр үгээ зөвхөн select хийж идэвхижүүлэхэд bolor tolidoh товч гарч ирэх. 28 | - Хэрэв bolor-toli-оос api гаргаж өгвөл түүнтэй холбох. гэх мэт... 29 | Та энэхүү extension-ий хөгжүүлэлтэд саналаа нэмэрлэж, кодын хөгжүүлэлтэд хамтран орж болно. Саналаа swganzo@gmail.com руу явуулаарай. 30 | 31 | ## Холбогдох: 32 | 33 | Хамтарч хөгжүүлэх, алдаа илрүүлсэн бол, нэмэлт хөгжүүлэлтийн санал байгаа бол, эсвэл зүгээр мэйл бичмээр санагдвал дараах мэйл рүү бичээрэй. 34 | swganzo@gmail.com 35 | -------------------------------------------------------------------------------- /popup/popup.js: -------------------------------------------------------------------------------- 1 | /* Copyright (c) 2017 Kenzo. All rights reserved. */ 2 | 3 | import { bolorLocales } from "../scripts/locales.js"; 4 | import { updateWindow } from "../scripts/window.js"; 5 | 6 | const direction_key = "direction"; 7 | 8 | const selectChange = async (event) => { 9 | chrome.storage.local.set({ [direction_key]: event.target.value }); 10 | }; 11 | 12 | const getSelectBox = async () => { 13 | const select_box = document.createElement("select"); 14 | select_box.id = "selected_lang"; 15 | select_box.classList.add("select-lang"); 16 | const default_direction_obj = await chrome.storage.local.get([direction_key]); 17 | 18 | for (const { direction, title } of bolorLocales) { 19 | const option = document.createElement("option"); 20 | option.value = direction; 21 | option.textContent = title; 22 | if (direction === default_direction_obj.direction) { 23 | option.selected = true; 24 | } 25 | select_box.appendChild(option); 26 | } 27 | 28 | select_box.addEventListener("change", selectChange); 29 | 30 | return select_box; 31 | }; 32 | 33 | const showError = () => { 34 | const messageElement = document.getElementById("message"); 35 | messageElement.classList.add("error-message"); 36 | 37 | setTimeout(() => { 38 | messageElement.classList.remove("error-message"); 39 | }, 1000); 40 | }; 41 | 42 | const buttonClick = (e) => { 43 | e.preventDefault(); 44 | const input = document.getElementById("search_field"); 45 | const select = document.getElementById("selected_lang"); 46 | 47 | if (input.value.trim() == "") { 48 | showError(); 49 | return; 50 | } 51 | 52 | updateWindow(input.value.trim(), select.value); 53 | input.value = ""; 54 | }; 55 | 56 | const getButton = () => { 57 | const button = document.createElement("button"); 58 | button.classList.add("inline-block"); 59 | button.classList.add("sw-button"); 60 | button.classList.add("sw-button-action"); 61 | 62 | button.addEventListener("click", buttonClick); 63 | return button; 64 | }; 65 | 66 | const getTextBox = () => { 67 | const text_box = document.createElement("input"); 68 | text_box.type = "text"; 69 | text_box.name = "q"; 70 | text_box.id = "search_field"; 71 | text_box.classList.add("text-input"); 72 | text_box.placeholder = "Хайх..."; 73 | text_box.autofocus = true; 74 | return text_box; 75 | }; 76 | 77 | const createForm = async () => { 78 | const form = document.getElementById("search-form"); 79 | form.appendChild(await getSelectBox()); 80 | form.appendChild(getTextBox()); 81 | form.appendChild(getButton()); 82 | }; 83 | 84 | createForm().catch(console.error); 85 | -------------------------------------------------------------------------------- /popup/popup.css: -------------------------------------------------------------------------------- 1 | html { 2 | -webkit-box-sizing: border-box; 3 | -moz-box-sizing: border-box; 4 | box-sizing: border-box; 5 | } 6 | *, 7 | *:before, 8 | *:after { 9 | -webkit-box-sizing: inherit; 10 | -moz-box-sizing: inherit; 11 | box-sizing: inherit; 12 | } 13 | .clearfix:after { 14 | content: ""; 15 | display: table; 16 | clear: both; 17 | } 18 | input[type="text"], 19 | textarea { 20 | -webkit-transition: all 0.3s ease-in-out; 21 | -moz-transition: all 0.3s ease-in-out; 22 | -ms-transition: all 0.3s ease-in-out; 23 | -o-transition: all 0.3s ease-in-out; 24 | border: 1px solid #dddddd; 25 | outline: none; 26 | } 27 | 28 | input[type="text"]:focus, 29 | textarea:focus { 30 | border: 1px solid #724f33; 31 | } 32 | body { 33 | font-family: Arial, Tahoma, sans-serif; 34 | font-size: 100%; 35 | 36 | width: 350px; 37 | position: relative; 38 | } 39 | .content { 40 | padding: 15px; 41 | overflow: hidden; 42 | } 43 | #search-form { 44 | width: 100%; 45 | } 46 | #search-form .text-input { 47 | float: left; 48 | width: 85%; 49 | padding: 7px 10px; 50 | height: 33px; 51 | } 52 | #search-form .sw-button { 53 | width: 15%; 54 | float: left; 55 | cursor: pointer; 56 | height: 33px; 57 | color: #fff; 58 | text-indent: -9999px; 59 | overflow: hidden; 60 | background: #724f33 url(../images/search.png) no-repeat center center; 61 | border: none; 62 | display: inline-block; 63 | } 64 | .select-lang { 65 | margin-bottom: 20px; 66 | display: block; 67 | width: 100%; 68 | height: 34px; 69 | padding: 6px 12px; 70 | font-size: 14px; 71 | line-height: 1.42857143; 72 | outline: none; 73 | color: #724f33; 74 | background-color: #fff; 75 | background-image: none; 76 | border: 1px solid #dddddd; 77 | -webkit-box-shadow: inset 0 1px 1px rgba(0, 0, 0, 0.075); 78 | box-shadow: inset 0 1px 1px rgba(0, 0, 0, 0.075); 79 | -webkit-transition: border-color ease-in-out 0.15s, 80 | -webkit-box-shadow ease-in-out 0.15s; 81 | -o-transition: border-color ease-in-out 0.15s, box-shadow ease-in-out 0.15s; 82 | transition: border-color ease-in-out 0.15s, box-shadow ease-in-out 0.15s; 83 | } 84 | .select-lang:focus, 85 | .select-lang:focus option { 86 | border-color: #724f33; 87 | } 88 | .hidden-message { 89 | visibility: hidden; 90 | } 91 | .hidden-message p { 92 | font-size: 10px; 93 | color: red; 94 | margin-bottom: 0; 95 | } 96 | .error-message { 97 | visibility: visible; 98 | } 99 | 100 | @keyframes ellipsis { 101 | to { 102 | width: 1.25em; 103 | } 104 | } 105 | 106 | @-webkit-keyframes ellipsis { 107 | to { 108 | width: 1.25em; 109 | } 110 | } 111 | -------------------------------------------------------------------------------- /scripts/window.js: -------------------------------------------------------------------------------- 1 | /* Copyright (c) 2017 Kenzo. All rights reserved. */ 2 | 3 | const window_key = "windowId", 4 | tab_key = "tabId", 5 | bolor_url = "https://bolor-toli.com/result?", 6 | top = 100, 7 | top_key = "top", 8 | left = 100, 9 | left_key = "left", 10 | height = 500, 11 | height_key = "height", 12 | width = 710, 13 | width_key = "width"; 14 | 15 | const getWidth = async () => { 16 | const width_obj = await chrome.storage.local.get([width_key]); 17 | return width_obj[width_key] ?? width; 18 | }; 19 | 20 | const getHeight = async () => { 21 | const height_obj = await chrome.storage.local.get([height_key]); 22 | return height_obj[height_key] ?? height; 23 | }; 24 | 25 | const getLeft = async () => { 26 | const left_obj = await chrome.storage.local.get([left_key]); 27 | return left_obj[left_key] ?? left; 28 | }; 29 | 30 | const getTop = async () => { 31 | const top_obj = await chrome.storage.local.get([top_key]); 32 | return top_obj[top_key] ?? top; 33 | }; 34 | 35 | const removeWindowId = () => { 36 | chrome.storage.local.remove([window_key, tab_key]); 37 | }; 38 | 39 | const getArgs = async (url) => { 40 | return { 41 | focused: true, 42 | width: await getWidth(), 43 | height: await getHeight(), 44 | left: await getLeft(), 45 | top: await getTop(), 46 | type: "popup", 47 | url: url, 48 | }; 49 | }; 50 | 51 | const getDefaultArgs = (url) => { 52 | return { 53 | focused: true, 54 | width: width, 55 | height: height, 56 | left: left, 57 | top: top, 58 | type: "popup", 59 | url: url, 60 | }; 61 | }; 62 | 63 | const updateArgs = (window) => { 64 | chrome.storage.local.set({ [top_key]: window.top }); 65 | chrome.storage.local.set({ [left_key]: window.left }); 66 | chrome.storage.local.set({ [height_key]: window.height }); 67 | chrome.storage.local.set({ [width_key]: window.width }); 68 | }; 69 | 70 | const getUrl = (search_text, direction) => { 71 | const encodeQueryData = (data) => { 72 | const ret = []; 73 | for (let d in data) 74 | ret.push(encodeURIComponent(d) + "=" + encodeURIComponent(data[d])); 75 | return ret.join("&"); 76 | }; 77 | const params = { 78 | word: search_text, 79 | direction: direction, 80 | }; 81 | const url = `${bolor_url}${encodeQueryData(params)}`; 82 | return url; 83 | }; 84 | 85 | const getWindowId = async () => { 86 | let window_id_obj = await chrome.storage.local.get([window_key]); 87 | if (!window_id_obj[window_key]) { 88 | return 0; 89 | } 90 | return parseInt(window_id_obj[window_key]); 91 | }; 92 | 93 | const getCurrentTab = async () => { 94 | const queryOptions = { active: true, lastFocusedWindow: true }; 95 | const [tab] = await chrome.tabs.query(queryOptions); 96 | return tab; 97 | }; 98 | 99 | const setWindow = async (window) => { 100 | await chrome.storage.local.set({ [window_key]: window.id }); 101 | const tab = await getCurrentTab(); 102 | await chrome.storage.local.set({ [tab_key]: tab.id }); 103 | 104 | chrome.windows.onBoundsChanged.addListener((window) => { 105 | updateArgs(window); 106 | }); 107 | 108 | chrome.windows.onRemoved.addListener(async (window_id) => { 109 | if (window_id == (await getWindowId())) { 110 | removeWindowId(); 111 | } 112 | }); 113 | }; 114 | 115 | const createWindow = async (url) => { 116 | chrome.windows.create(await getArgs(url), async (window) => { 117 | if (chrome.runtime.lastError) { 118 | chrome.windows.create(getDefaultArgs(url), async (window) => { 119 | setWindow(window); 120 | }); 121 | } else { 122 | setWindow(window); 123 | } 124 | }); 125 | }; 126 | 127 | const updateWindow = async (search_text, direction) => { 128 | const window_id = await getWindowId(); 129 | const url = getUrl(search_text, direction); 130 | if (!window_id) { 131 | createWindow(url); 132 | return; 133 | } 134 | const tab_id = await chrome.storage.local.get([tab_key]); 135 | chrome.windows.update(window_id, { focused: true }, function () { 136 | if (chrome.runtime.lastError) { 137 | createWindow(url); 138 | } else { 139 | chrome.tabs.update(parseInt(tab_id[tab_key]), { 140 | url: url, 141 | active: true, 142 | }); 143 | } 144 | }); 145 | }; 146 | 147 | export { updateWindow }; 148 | --------------------------------------------------------------------------------