├── 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 | 
13 |
14 | ## Боломжууд:
15 |
16 | - Та энэхүү extension-ийг суулгасанаар орчуулахыг хүссэн текстээ идэвхижүүлэн хулганы баруун гар талын товч буюу "mouse 2" товчоо даран "Bolor tolidogch" гэсэн товч дээр даран орчуулна.
17 |
18 | 
19 |
20 | - Хөтөчийн баруун дээд талд байрлах Bolor tolidogch-ийн icon буюу жижиг зурган дээр дарж гарч ирэх текст бичих хэсэгт өөрийн орчуулахыг хүссэн үгээ бичин хайх товч дарна.
21 |
22 | 
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 |
--------------------------------------------------------------------------------