├── src
├── ts
│ ├── background.ts
│ ├── types.ts
│ ├── tooltip.ts
│ ├── popup.ts
│ ├── rosy.ts
│ ├── data.ts
│ └── content.ts
├── icons
│ ├── icon16.png
│ ├── icon24.png
│ ├── icon32.png
│ ├── icon48.png
│ └── icon128.png
├── css
│ ├── content.css
│ └── popup.css
├── manifest.json
├── html
│ └── popup.html
└── js
│ └── buttons.js
├── .gitignore
├── logo
├── logo.png
└── square.png
├── tslint.json
├── tsconfig.json
├── README.md
├── LICENSE
├── package.json
└── webpack.config.js
/src/ts/background.ts:
--------------------------------------------------------------------------------
1 |
--------------------------------------------------------------------------------
/.gitignore:
--------------------------------------------------------------------------------
1 | package-lock.json
2 | node_modules/
3 | dist/
4 | rosy.zip
--------------------------------------------------------------------------------
/logo/logo.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/whizsid/Rosy/HEAD/logo/logo.png
--------------------------------------------------------------------------------
/logo/square.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/whizsid/Rosy/HEAD/logo/square.png
--------------------------------------------------------------------------------
/src/icons/icon16.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/whizsid/Rosy/HEAD/src/icons/icon16.png
--------------------------------------------------------------------------------
/src/icons/icon24.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/whizsid/Rosy/HEAD/src/icons/icon24.png
--------------------------------------------------------------------------------
/src/icons/icon32.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/whizsid/Rosy/HEAD/src/icons/icon32.png
--------------------------------------------------------------------------------
/src/icons/icon48.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/whizsid/Rosy/HEAD/src/icons/icon48.png
--------------------------------------------------------------------------------
/src/icons/icon128.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/whizsid/Rosy/HEAD/src/icons/icon128.png
--------------------------------------------------------------------------------
/tslint.json:
--------------------------------------------------------------------------------
1 | {
2 | "defaultSeverity": "error",
3 | "extends": [
4 | "tslint:recommended",
5 | "tslint-config-prettier"
6 | ],
7 | "jsRules": {},
8 | "rules": {
9 | "no-console": false
10 | },
11 | "rulesDirectory": []
12 | }
--------------------------------------------------------------------------------
/tsconfig.json:
--------------------------------------------------------------------------------
1 | {
2 | "compilerOptions": {
3 | "target": "esnext",
4 | "module": "commonjs",
5 | "noImplicitAny": true,
6 | "removeComments": true,
7 | "preserveConstEnums": true,
8 | "sourceMap": true
9 | },
10 | "files": [
11 | "src/ts/background.ts"
12 | ]
13 | }
--------------------------------------------------------------------------------
/src/ts/types.ts:
--------------------------------------------------------------------------------
1 | export type RosyPosition = {
2 | powerOfTen:number;
3 | noun: string;
4 | prefix: string;
5 | }
6 |
7 |
8 | export type RosyNumber = {
9 | number: number;
10 | noun: string;
11 | prefix: string;
12 | plusTenNoun: string;
13 | plusTenPrefix: string;
14 | productTenPrefix:string;
15 | productTenNoun:string;
16 | }
--------------------------------------------------------------------------------
/src/css/content.css:
--------------------------------------------------------------------------------
1 | .rosy-tooltip {
2 | position: absolute;
3 | background: #4285f4;
4 | color:#fff;
5 | font-size:1.2em;
6 | font-weight: 600;
7 | box-shadow: 1px 1px 2px rgba(0,0,0,0.5);
8 | margin-top: -60px;
9 | padding:8px;
10 | border-radius: 2px;
11 | transition-delay: .5s;
12 | transition-duration: .6s
13 | }
14 |
--------------------------------------------------------------------------------
/README.md:
--------------------------------------------------------------------------------
1 |

2 |
3 | ---
4 |
5 |
6 |
7 |
8 |
9 |
10 | ---
11 |
12 | > Don't tell lies. Rosy can translate any long number to sinhala.
13 |
14 | Rosy is a firefox addon to helping persons to translate their numerical values to sinhala words. It will automatically translating numeric values in webpages and display the result in a cool tooltip box. You can also translate your own numbers with the help of simple popup.
15 |
16 | 
17 |
18 | ## License
19 |
20 | You can copy any codes/algorythm from this repository and give credits when copying.
21 |
22 | ## Contribution
23 |
24 | All PRs and issues are welcome.
25 |
--------------------------------------------------------------------------------
/src/manifest.json:
--------------------------------------------------------------------------------
1 | {
2 | "name": "Rosy Number Translator",
3 | "version": "1.1",
4 | "description": "Numbers to sinhala words converter",
5 | "permissions": ["storage"],
6 | "short_name":"Rosy",
7 | "content_scripts": [{
8 | "run_at": "document_end",
9 | "all_frames": true,
10 | "matches": [
11 | "http://*/*",
12 | "https://*/*",
13 | "file://*/*"
14 | ],
15 | "js": [
16 | "content.js"
17 | ],
18 | "css": [
19 | "content.css"
20 | ]
21 | }],
22 | "icons": {
23 | "16": "icon16.png",
24 | "48": "icon48.png",
25 | "128": "icon128.png"
26 | },
27 | "manifest_version": 2,
28 | "browser_action": {
29 | "default_icon": {
30 | "16": "icon16.png",
31 | "24": "icon24.png",
32 | "32": "icon32.png"
33 | },
34 | "default_title": "Translate your numbers to sinhala with Rosy.",
35 | "default_popup": "popup.html"
36 | }
37 | }
--------------------------------------------------------------------------------
/LICENSE:
--------------------------------------------------------------------------------
1 | MIT License
2 |
3 | Copyright (c) 2019 WhizSid
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 |
--------------------------------------------------------------------------------
/package.json:
--------------------------------------------------------------------------------
1 | {
2 | "name": "rosy",
3 | "version": "1.0.0",
4 | "description": "A firefox extension to translate numerical values to sinhala words.",
5 | "main": "index.js",
6 | "repository": {
7 | "type": "git",
8 | "url": "git+https://github.com/whizsid/Rosy.git"
9 | },
10 | "keywords": [
11 | "firefox",
12 | "numbers",
13 | "sinhala",
14 | "words",
15 | "translate",
16 | "unicode",
17 | "mouseover",
18 | "tooltip",
19 | "convert",
20 | "numeric"
21 | ],
22 | "author": "whizsid",
23 | "license": "MIT",
24 | "bugs": {
25 | "url": "https://github.com/whizsid/Rosy/issues"
26 | },
27 | "homepage": "https://github.com/whizsid/Rosy#readme",
28 | "scripts": {
29 | "build": "NODE_ENV=production node ./node_modules/webpack-cli/bin/cli.js && zip -FS -r -j rosy dist",
30 | "dev": "node ./node_modules/webpack-cli/bin/cli.js --watch",
31 | "lint": "eslint --ignore-pattern dist ."
32 | },
33 | "devDependencies": {
34 | "@babel/core": "^7.4.4",
35 | "@babel/plugin-transform-classes": "^7.4.4",
36 | "babel-loader": "^8.0.5",
37 | "clean-webpack-plugin": "^1.0.0",
38 | "copy-webpack-plugin": "^4.6.0",
39 | "eslint": "^5.11.0",
40 | "ts-loader": "^6.0.4",
41 | "typescript": "^3.5.3",
42 | "webextension-polyfill-ts": "^0.9.1",
43 | "webpack": "^4.28.2",
44 | "webpack-cli": "^3.1.2"
45 | },
46 | "dependencies": {
47 | "tslint-config-prettier": "^1.18.0"
48 | }
49 | }
50 |
--------------------------------------------------------------------------------
/src/ts/tooltip.ts:
--------------------------------------------------------------------------------
1 | class Tooltip {
2 |
3 | protected htmlElement:HTMLElement;
4 |
5 | protected top:number;
6 |
7 | protected left:number;
8 |
9 | protected display:boolean;
10 |
11 | protected content:string;
12 |
13 | constructor(){
14 | const htmlElement = document.createElement('DIV');
15 | htmlElement.setAttribute('class','rosy-tooltip');
16 |
17 | this.htmlElement = htmlElement;
18 | this.top = 0;
19 | this.left = 0;
20 | this.display = false;
21 | this.content = "";
22 |
23 | document.body.appendChild(htmlElement);
24 | }
25 |
26 | public move(x:number,y:number):void{
27 | this.left = x;
28 | this.top = y;
29 | this.render();
30 | }
31 |
32 | public changeContent(content:string):void{
33 | this.content = content;
34 | }
35 |
36 | public show():void{
37 | this.display = true;
38 | this.render();
39 | }
40 |
41 | public hide():void{
42 | this.display = false;
43 | this.render();
44 | }
45 |
46 | protected render(){
47 | let style:string = "";
48 |
49 | if(this.display){
50 | style = "opacity:1;top:"+this.top+'px;left:'+this.left+'px';
51 | } else {
52 | style = 'opacity:0';
53 | }
54 |
55 | this.htmlElement.innerHTML = this.content;
56 | this.htmlElement.setAttribute('style',style);
57 | }
58 | }
59 |
60 | export default Tooltip;
--------------------------------------------------------------------------------
/webpack.config.js:
--------------------------------------------------------------------------------
1 | const path = require("path");
2 | const CopyWebpackPlugin = require("copy-webpack-plugin");
3 | const CleanWebpackPlugin = require("clean-webpack-plugin");
4 |
5 | const mode =
6 | process.env.NODE_ENV === "production" ? "production" : "development";
7 |
8 | const config = {
9 | devtool: "inline-source-map",
10 | mode,
11 | entry: {
12 | background: "./src/ts/background.ts",
13 | content: "./src/ts/content.ts",
14 | popup: "./src/ts/popup.ts",
15 | },
16 | output: {
17 | filename: "[name].js",
18 | path: path.resolve(__dirname, "dist")
19 | },
20 | module: {
21 | rules: [
22 | {
23 | test: /\.js$/,
24 | exclude: /node_modules/,
25 | use: {
26 | loader: "babel-loader",
27 | options: {
28 | plugins: ["@babel/plugin-transform-classes"]
29 | }
30 | }
31 | },
32 | {
33 | test: /\.ts$/,
34 | exclude: /node_modules/,
35 | loader: "ts-loader"
36 | }
37 | ]
38 | },
39 | resolve: {
40 | extensions: [".js", ".ts"]
41 | },
42 | plugins: [
43 | new CleanWebpackPlugin(["dist"]),
44 | new CopyWebpackPlugin([
45 | "src/manifest.json",
46 | "src/icons/*.png",
47 | "src/html/popup.html",
48 | "src/css/popup.css",
49 | "src/css/content.css",
50 | "src/js/buttons.js",
51 | "logo/square.png"
52 | ], {
53 | to: "dist"
54 | })
55 | ]
56 | };
57 |
58 | module.exports = config;
59 |
--------------------------------------------------------------------------------
/src/ts/popup.ts:
--------------------------------------------------------------------------------
1 | import { browser } from "webextension-polyfill-ts";
2 | import Rosy from "./rosy";
3 |
4 | const inputElement = document.getElementById("quickInput") as HTMLInputElement;
5 | const rowElement = document.getElementById("quickRow") as HTMLElement;
6 | const displayElement = document.getElementById("quickResult") as HTMLElement;
7 |
8 | if (inputElement) {
9 | const callback = function(this: HTMLInputElement) {
10 | const value: string = this.value;
11 |
12 | if (value.length > 0) {
13 | rowElement.setAttribute("style", "display:unset");
14 |
15 | // tslint:disable-next-line: radix
16 | displayElement.innerHTML = Rosy(parseInt(value));
17 | } else {
18 | rowElement.setAttribute("style", "display:none");
19 | }
20 | };
21 |
22 | inputElement.addEventListener("change", callback);
23 | inputElement.addEventListener("keyup", callback);
24 | }
25 |
26 | const switchButton = document.getElementById("switch-blue") as HTMLInputElement;
27 | browser.storage.local
28 | .get(["rosyEnabled"])
29 | .then(({ rosyEnabled }: { rosyEnabled?: string }) => {
30 | // tslint:disable-next-line: radix
31 | let enabled = parseInt(rosyEnabled);
32 |
33 | if (enabled) {
34 | switchButton.checked = true;
35 | } else {
36 | switchButton.checked = false;
37 | }
38 |
39 | switchButton.addEventListener("change", function(this) {
40 | enabled = enabled ? 0 : 1;
41 |
42 | if (enabled) {
43 | browser.storage.local.set({ rosyEnabled: "1" }).then(() => {
44 | switchButton.checked = true;
45 | });
46 | } else {
47 | browser.storage.local.set({ rosyEnabled: "0" }).then(() => {
48 | switchButton.checked = false;
49 | });
50 | }
51 | });
52 | });
53 |
--------------------------------------------------------------------------------
/src/html/popup.html:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 | Rosy Popup
5 |
6 |
7 |
8 |
9 |
10 |
58 |
59 |
60 |
61 |
62 |
63 |
--------------------------------------------------------------------------------
/src/ts/rosy.ts:
--------------------------------------------------------------------------------
1 | import {numbers,positions} from "./data";
2 |
3 | const Rosy = (translateMe:number,lastPrefix:boolean=false):string=>{
4 |
5 | let translated:string ="";
6 |
7 | const powers:number[]= Object.keys(positions)
8 | // tslint:disable-next-line: radix
9 | .map((a:string):number=>parseInt(a))
10 | .sort((a:number,b:number)=>b-a);
11 |
12 | let lastModedIndex:number=0;
13 |
14 | while(translateMe>0){
15 | const position = positions[powers[lastModedIndex]];
16 |
17 | const divided=Math.floor(translateMe/Math.pow(10,position.powerOfTen));
18 | const moded:number = translateMe % Math.pow(10,position.powerOfTen);
19 |
20 | const prefix = lastPrefix? true : moded!==0||position.powerOfTen!==0;
21 | translateMe = moded;
22 |
23 |
24 | if(divided>99){
25 | translated += Rosy(divided,true);
26 | } else if(divided>19){
27 |
28 | const dividedByTen = Math.floor(divided/10);
29 | const modedByTen = divided%10;
30 |
31 | if(modedByTen>=1){
32 | translated += numbers[dividedByTen].productTenPrefix+' ';
33 | } else {
34 | if(prefix){
35 | translated += numbers[dividedByTen].productTenPrefix+' ';
36 | } else {
37 | translated += numbers[dividedByTen].productTenNoun;
38 | }
39 | }
40 |
41 | if(modedByTen>=1){
42 | if(prefix){
43 | translated += numbers[modedByTen].prefix+' ';
44 | } else {
45 | translated += numbers[modedByTen].noun;
46 | }
47 | }
48 | } else if (divided>9) {
49 | const modedByTen = divided%10;
50 |
51 | if(prefix) {
52 | translated += numbers[modedByTen].plusTenPrefix+' ';
53 | } else {
54 | translated += numbers[modedByTen].plusTenNoun;
55 | }
56 |
57 | } else if(divided>0&&!(divided===1&&position.powerOfTen!=0 &&moded===0&&translated==='')) {
58 |
59 | if(prefix){
60 | translated += numbers[divided].prefix+' ';
61 | } else {
62 | translated += numbers[divided].noun;
63 | }
64 |
65 | }
66 |
67 | if(divided>0){
68 | if(moded>0){
69 | translated += position.prefix+' ';
70 | } else {
71 | translated += position.noun;
72 | }
73 | }
74 | lastModedIndex++;
75 | }
76 |
77 | return translated;
78 | }
79 |
80 | export default Rosy;
81 |
--------------------------------------------------------------------------------
/src/css/popup.css:
--------------------------------------------------------------------------------
1 | body{
2 | max-width: 460px;
3 | }
4 |
5 | h4 {
6 | margin: 0;
7 | }
8 |
9 | td {
10 | padding-left: 1em;
11 | padding-top: 0.2em;
12 | }
13 |
14 | tr {
15 | margin-top: 1em;
16 | }
17 |
18 | label {
19 | font-size: 0.7em;
20 | color: #404040;
21 | }
22 | .wrapper {
23 | position: relative;
24 | }
25 |
26 | .gh-button {
27 | position: absolute;
28 | top: 0;
29 | left: 0;
30 | }
31 |
32 | .button-switch {
33 | font-size: 1.5em;
34 | height: 1em;
35 | margin-bottom: 0.625em;
36 | position: relative;
37 | width: 2.4em;
38 | }
39 |
40 | .button-switch .lbl-off,
41 | .button-switch .lbl-on {
42 | cursor: pointer;
43 | display: block;
44 | font-size: 0.9em;
45 | font-weight: bold;
46 | line-height: 1em;
47 | position: absolute;
48 | top: 0.5em;
49 | transition: opacity 0.25s ease-out 0.1s;
50 | text-transform: uppercase;
51 | }
52 |
53 | .button-switch .lbl-off {
54 | right: 0.4375em;
55 | }
56 |
57 | .button-switch .lbl-on {
58 | color: #fefefe;
59 | opacity: 0;
60 | left: 0.4375em;
61 | }
62 |
63 | .button-switch .switch {
64 | -webkit-appearance: none;
65 | -moz-appearance: none;
66 | appearance: none;
67 | height: 0;
68 | font-size: 1em;
69 | left: 0;
70 | line-height: 0;
71 | outline: none;
72 | position: absolute;
73 | top: 0;
74 | width: 0;
75 | }
76 |
77 | .button-switch .switch:before,
78 | .button-switch .switch:after {
79 | content: "";
80 | font-size: 1em;
81 | position: absolute;
82 | }
83 |
84 | .button-switch .switch:before {
85 | border-radius: 1.25em;
86 | background: #bdc3c7;
87 | height: 1em;
88 | left: -0.25em;
89 | transition: background-color 0.25s ease-out 0.1s;
90 | width: 2.4em;
91 | }
92 |
93 | .button-switch .switch:after {
94 | box-shadow: 0 0.0625em 0.375em 0 #666;
95 | border-radius: 50%;
96 | background: #fefefe;
97 | height: 1em;
98 | transform: translate(0, 0);
99 | transition: transform 0.25s ease-out 0.1s;
100 | width: 1em;
101 | }
102 |
103 | .button-switch .switch:checked:after {
104 | transform: translate(1em, 0);
105 | }
106 |
107 | .button-switch .switch:checked ~ .lbl-off {
108 | opacity: 0;
109 | }
110 |
111 | .button-switch .switch:checked ~ .lbl-on {
112 | opacity: 1;
113 | }
114 |
115 | .button-switch .switch#switch-orange:checked:before {
116 | background: #e67e22;
117 | }
118 |
119 | .button-switch .switch#switch-blue:checked:before {
120 | background: #3498db;
121 | }
122 |
--------------------------------------------------------------------------------
/src/ts/data.ts:
--------------------------------------------------------------------------------
1 | import { RosyNumber, RosyPosition } from "./types";
2 |
3 | export const positions: { [x: number]: RosyPosition } = {
4 | 0: {
5 | noun: "",
6 | powerOfTen: 0,
7 | prefix: ""
8 | },
9 | 2: {
10 | noun: "සියය",
11 | powerOfTen: 2,
12 | prefix: "සිය"
13 | },
14 | 3: {
15 | noun: "දහස",
16 | powerOfTen: 3,
17 | prefix: "දහස්"
18 | },
19 | 5: {
20 | noun: "ලක්ෂය",
21 | powerOfTen: 5,
22 | prefix: "ලක්ෂ"
23 | },
24 | 6: {
25 | noun: "මිලියනය",
26 | powerOfTen: 6,
27 | prefix: "මිලියන"
28 | },
29 | 7: {
30 | noun: "කෝටිය",
31 | powerOfTen: 7,
32 | prefix: "කෝටි"
33 | },
34 | 9: {
35 | noun: "බිලියනය",
36 | powerOfTen: 9,
37 | prefix: "බිලියන"
38 | },
39 | 12: {
40 | noun: "ත්රිලියනය",
41 | powerOfTen: 12,
42 | prefix: "ත්රිලියන"
43 | },
44 | 15: {
45 | noun: "ක්වාඩ්රිලියනය",
46 | powerOfTen: 15,
47 | prefix: "ක්වාඩ්රිලියන"
48 | },
49 | 18: {
50 | noun: "ක්වින්ටිලියනය",
51 | powerOfTen: 18,
52 | prefix: "ක්වින්ටිලියන"
53 | },
54 | 21: {
55 | noun: "සෙක්ස්ටිලියනය",
56 | powerOfTen: 21,
57 | prefix: "සෙක්සිටිලියන"
58 | },
59 | 24: {
60 | noun: "සෙප්ටිලියනය",
61 | powerOfTen: 24,
62 | prefix: "සෙප්ටිලියන"
63 | },
64 | 27: {
65 | noun: "ඔක්ටිලියනය",
66 | powerOfTen: 27,
67 | prefix: "ඔක්ටිලියන"
68 | },
69 | 30: {
70 | noun: "නොලියනය",
71 | powerOfTen: 30,
72 | prefix: "නොලියන"
73 | },
74 | 33: {
75 | noun: "ඩෙසිලියනය",
76 | powerOfTen: 33,
77 | prefix: "ඩෙසිලියන"
78 | }
79 | };
80 |
81 | export const numbers: { [x: number]: RosyNumber } = {
82 | 0: {
83 | noun: "බිංදුව",
84 | number: 0,
85 | plusTenNoun: "දහය",
86 | plusTenPrefix: "දස",
87 | prefix: "",
88 | productTenNoun: "බිංදුව",
89 | productTenPrefix: ""
90 | },
91 | 1: {
92 | noun: "එක",
93 | number: 1,
94 | plusTenNoun: "එකොළහ",
95 | plusTenPrefix: "එකොළොස්",
96 | prefix: "එක්",
97 | productTenNoun: "දහය",
98 | productTenPrefix: "දස"
99 | },
100 | 2: {
101 | noun: "දෙක",
102 | number: 2,
103 | plusTenNoun: "දොළහ",
104 | plusTenPrefix: "දොළොස්",
105 | prefix: "දෙ",
106 | productTenNoun: "විස්ස",
107 | productTenPrefix: "විසි"
108 | },
109 | 3: {
110 | noun: "තුන",
111 | number: 3,
112 | plusTenNoun: "දහතුන",
113 | plusTenPrefix: "දහතුන්",
114 | prefix: "තුන්",
115 | productTenNoun: "තිහ",
116 | productTenPrefix: "තිස්"
117 | },
118 | 4: {
119 | noun: "හතර",
120 | number: 4,
121 | plusTenNoun: "දහ හතර",
122 | plusTenPrefix: "දහ හතර",
123 | prefix: "හාර",
124 | productTenNoun: "හතළිහ",
125 | productTenPrefix: "හතළිස්"
126 | },
127 | 5: {
128 | noun: "පහ",
129 | number: 5,
130 | plusTenNoun: "පහළොව",
131 | plusTenPrefix: "පහළොස්",
132 | prefix: "පන්",
133 | productTenNoun: "පනහ",
134 | productTenPrefix: "පනස්"
135 | },
136 | 6: {
137 | noun: "හය",
138 | number: 6,
139 | plusTenNoun: "දහසය",
140 | plusTenPrefix: "දහසය",
141 | prefix: "හය",
142 | productTenNoun: "හැට",
143 | productTenPrefix: "හැට"
144 | },
145 | 7: {
146 | noun: "හත",
147 | number: 7,
148 | plusTenNoun: "දහ හත",
149 | plusTenPrefix: "දහ හත්",
150 | prefix: "හත්",
151 | productTenNoun: "හැත්තෑව",
152 | productTenPrefix: "හැත්තෑ"
153 | },
154 | 8: {
155 | noun: "අට",
156 | number: 8,
157 | plusTenNoun: "දහ අට",
158 | plusTenPrefix: "දහ අට",
159 | prefix: "අට",
160 | productTenNoun: "අසූව",
161 | productTenPrefix: "අසූ"
162 | },
163 | 9: {
164 | noun: "නවය",
165 | number: 9,
166 | plusTenNoun: "දහ නවය",
167 | plusTenPrefix: "දහ නව",
168 | prefix: "නව",
169 | productTenNoun: "අනූව",
170 | productTenPrefix: "අනූ"
171 | }
172 | };
173 |
--------------------------------------------------------------------------------
/src/ts/content.ts:
--------------------------------------------------------------------------------
1 | import { browser } from "webextension-polyfill-ts";
2 | import Rosy from "./rosy";
3 | import Tooltip from "./tooltip";
4 |
5 | interface IFoundWord {
6 | word: string;
7 | start: number;
8 | rect: ClientRect | DOMRect;
9 | }
10 |
11 | /**
12 | * Returning the word by x,y coordinates
13 | *
14 | * @link https://jsfiddle.net/abrady0/ggr5mu7o/
15 | */
16 | const getWordByCoordinates = (
17 | parentElt: ChildNode,
18 | x: number,
19 | y: number
20 | ): IFoundWord | null => {
21 | if (parentElt.nodeName !== "#text") {
22 | return null;
23 | }
24 |
25 | const range: Range = document.createRange();
26 | const words: string[] = parentElt.textContent.split(" ");
27 | let start: number = 0;
28 | let end: number = 0;
29 |
30 | const isInRect = (
31 | rects: ClientRectList | DOMRectList
32 | ): ClientRect | DOMRect | null => {
33 | for (const r of rects) {
34 | if (r.left < x && r.right > x && r.top < y && r.bottom > y) {
35 | return r;
36 | }
37 | }
38 | return null;
39 | };
40 |
41 | for (const word of words) {
42 | end = start + word.length;
43 |
44 | range.setStart(parentElt, start);
45 |
46 | range.setEnd(parentElt, end);
47 |
48 | // not getBoundingClientRect as word could wrap
49 | const rects = range.getClientRects();
50 |
51 | const clickedRect = isInRect(rects);
52 | if (clickedRect) {
53 | return {
54 | rect: clickedRect,
55 | start,
56 | word
57 | };
58 | }
59 | start = end + 1;
60 | }
61 |
62 | return null;
63 | };
64 |
65 | // const pattern = /(\d+)/g;
66 |
67 | const tags: string[] = [
68 | "p",
69 | "a",
70 | "b",
71 | "i",
72 | "h1",
73 | "h2",
74 | "h3",
75 | "h4",
76 | "h5",
77 | "h6",
78 | "span",
79 | "em",
80 | "div",
81 | "strong",
82 | "td",
83 | "th",
84 | "li",
85 | "code",
86 | "q",
87 | "s",
88 | "pre",
89 | "small",
90 | "textarea",
91 | "title"
92 | ];
93 |
94 | const pattern = /^([0-9\,\)\(]+[0-9]+[0-9\,\)\(]+)$/;
95 |
96 | const tooltip = new Tooltip();
97 |
98 | for (const tag of tags) {
99 | const elmnts = document.getElementsByTagName(tag) as HTMLCollectionOf<
100 | HTMLElement
101 | >;
102 |
103 | for (const elmnt of elmnts) {
104 | let child: ChildNode | undefined;
105 |
106 | const textNodes: ChildNode[] = [];
107 |
108 | for (child = elmnt.firstChild; child !== null; child = child.nextSibling) {
109 | if (child.nodeName === "#text") {
110 | textNodes.push(child);
111 | }
112 | }
113 |
114 | if (textNodes.length) {
115 | elmnt.addEventListener("mousemove", function(
116 | this: Element,
117 | e: MouseEvent
118 | ) {
119 |
120 | browser.storage.local
121 | .get(["rosyEnabled"])
122 | .then(({ rosyEnabled }: { rosyEnabled?: string }) => {
123 | // tslint:disable-next-line: radix
124 | if (parseInt(rosyEnabled)) {
125 | let hoveredWord: IFoundWord | null = null;
126 |
127 | const x: number = e.pageX;
128 | const y: number = e.pageY;
129 |
130 | tooltip.move(x, y);
131 |
132 | for (const textNode of textNodes) {
133 | if (!hoveredWord) {
134 | hoveredWord = getWordByCoordinates(
135 | textNode,
136 | e.clientX,
137 | e.clientY
138 | );
139 | }
140 | }
141 |
142 | if (hoveredWord) {
143 | if (pattern.test(hoveredWord.word)) {
144 | tooltip.changeContent(
145 | // tslint:disable-next-line: radix
146 | Rosy(parseInt(hoveredWord.word.replace(/([^0-9]+)/g, "")))
147 | );
148 | tooltip.show();
149 | }
150 | }
151 | }
152 | });
153 | });
154 |
155 | elmnt.addEventListener("mouseleave", () => {
156 | tooltip.hide();
157 | });
158 | }
159 | }
160 | }
161 |
--------------------------------------------------------------------------------
/src/js/buttons.js:
--------------------------------------------------------------------------------
1 | /*!
2 | * github-buttons v2.2.10
3 | * (c) 2019 なつき
4 | * @license BSD-2-Clause
5 | */
6 | !function(){"use strict";var e=window.document,t=e.location,o=window.encodeURIComponent,r=window.decodeURIComponent,n=window.Math,a=window.HTMLElement,i=window.XMLHttpRequest,l="https://buttons.github.io/buttons.html",c=i&&i.prototype&&"withCredentials"in i.prototype,d=c&&a&&a.prototype.attachShadow&&!a.prototype.attachShadow.prototype,s=function(e,t,o){e.addEventListener?e.addEventListener(t,o):e.attachEvent("on"+t,o)},u=function(e,t,o){e.removeEventListener?e.removeEventListener(t,o):e.detachEvent("on"+t,o)},h=function(e,t,o){var r=function(n){return u(e,t,r),o(n)};s(e,t,r)},f=function(e,t,o){var r=function(n){if(t.test(e.readyState))return u(e,"readystatechange",r),o(n)};s(e,"readystatechange",r)},p=function(e){return function(t,o,r){var n=e.createElement(t);if(o)for(var a in o){var i=o[a];null!=i&&(null!=n[a]?n[a]=i:n.setAttribute(a,i))}if(r)for(var l=0,c=r.length;l'},eye:{width:16,height:16,path:''},star:{width:14,height:16,path:''},"repo-forked":{width:10,height:16,path:''},"issue-opened":{width:14,height:16,path:''},"cloud-download":{width:16,height:16,path:''}},w={},x=function(e,t,o){var r=p(e.ownerDocument),n=e.appendChild(r("style",{type:"text/css"}));n.styleSheet?n.styleSheet.cssText=m:n.appendChild(e.ownerDocument.createTextNode(m));var a,l,d=r("a",{className:"btn",href:t.href,target:"_blank",innerHTML:(a=t["data-icon"],l=/^large$/i.test(t["data-size"])?16:14,a=(""+a).toLowerCase().replace(/^octicon-/,""),{}.hasOwnProperty.call(v,a)||(a="mark-github"),'"),"aria-label":t["aria-label"]||void 0},[" ",r("span",{},[t["data-text"]||""])]);/\.github\.com$/.test("."+d.hostname)?/^https?:\/\/((gist\.)?github\.com\/[^\/?#]+\/[^\/?#]+\/archive\/|github\.com\/[^\/?#]+\/[^\/?#]+\/releases\/download\/|codeload\.github\.com\/)/.test(d.href)&&(d.target="_top"):(d.href="#",d.target="_self");var u,h,g,x,y=e.appendChild(r("div",{className:"widget"+(/^large$/i.test(t["data-size"])?" lg":"")},[d]));/^(true|1)$/i.test(t["data-show-count"])&&"github.com"===d.hostname&&(u=d.pathname.replace(/^(?!\/)/,"/").match(/^\/([^\/?#]+)(?:\/([^\/?#]+)(?:\/(?:(subscription)|(fork)|(issues)|([^\/?#]+)))?)?(?:[\/?#]|$)/))&&!u[6]?(u[2]?(h="/repos/"+u[1]+"/"+u[2],u[3]?(x="subscribers_count",g="watchers"):u[4]?(x="forks_count",g="network"):u[5]?(x="open_issues_count",g="issues"):(x="stargazers_count",g="stargazers")):(h="/users/"+u[1],g=x="followers"),function(e,t){var o=w[e]||(w[e]=[]);if(!(o.push(t)>1)){var r=b(function(){for(delete w[e];t=o.shift();)t.apply(null,arguments)});if(c){var n=new i;s(n,"abort",r),s(n,"error",r),s(n,"load",function(){var e;try{e=JSON.parse(n.responseText)}catch(e){return void r(e)}r(200!==n.status,e)}),n.open("GET",e),n.send()}else{var a=this||window;a._=function(e){a._=null,r(200!==e.meta.status,e.data)};var l=p(a.document)("script",{async:!0,src:e+(/\?/.test(e)?"&":"?")+"callback=_"}),d=function(){a._&&a._({meta:{}})};s(l,"load",d),s(l,"error",d),l.readyState&&f(l,/de|m/,d),a.document.getElementsByTagName("head")[0].appendChild(l)}}}.call(this,"https://api.github.com"+h,function(e,t){if(!e){var n=t[x];y.appendChild(r("a",{className:"social-count",href:t.html_url+"/"+g,target:"_blank","aria-label":n+" "+x.replace(/_count$/,"").replace("_"," ").slice(0,n<2?-1:void 0)+" on GitHub"},[r("b"),r("i"),r("span",{},[(""+n).replace(/\B(?=(\d{3})+(?!\d))/g,",")])]))}o&&o(y)})):o&&o(y)},y=window.devicePixelRatio||1,C=function(e){return(y>1?n.ceil(n.round(e*y)/y*2)/2:n.ceil(e))||0},F=function(e,t){e.style.width=t[0]+"px",e.style.height=t[1]+"px"},k=function(t,r){if(null!=t&&null!=r)if(t.getAttribute&&(t=function(e){for(var t={href:e.href,title:e.title,"aria-label":e.getAttribute("aria-label")},o=["icon","text","size","show-count"],r=0,n=o.length;r