Adrià Vilanova Martínez | 5bdc473 | 2022-05-31 20:12:21 +0200 | [diff] [blame^] | 1 | import {convertLanguages, isoLangs} from './consts'; |
Adrià Vilanova Martínez | 53f7a7f | 2022-05-30 13:59:59 +0200 | [diff] [blame] | 2 | |
Adrià Vilanova Martínez | 5bdc473 | 2022-05-31 20:12:21 +0200 | [diff] [blame^] | 3 | type TabOptionValue = ''|'yep'|'popup'; |
| 4 | type DeprecatedTabOptionValue = 'panel'; |
| 5 | type TabOptionValueIncludingDeprecated = |
| 6 | TabOptionValue|DeprecatedTabOptionValue; |
| 7 | |
| 8 | interface TabOption { |
| 9 | value: TabOptionValue; |
| 10 | labelMsg: string; |
| 11 | deprecatedValues: TabOptionValueIncludingDeprecated[]; |
| 12 | } |
| 13 | |
| 14 | interface TargetLangs { |
| 15 | [key: string]: string; // Here the key is a string with a number. |
| 16 | } |
| 17 | interface OptionsV0 { |
| 18 | translateinto: TargetLangs; |
| 19 | uniquetab: TabOptionValue; |
| 20 | } |
| 21 | |
| 22 | interface LegacyLanguages { |
| 23 | [key: string]: string; // Here the key is a string with the language code. |
| 24 | } |
| 25 | /** |
| 26 | * Backwards-compatible interface for the information available in the sync |
| 27 | * storage area. |
| 28 | */ |
| 29 | interface LegacyOptions { |
| 30 | translateinto: TargetLangs; |
| 31 | languages: LegacyLanguages; |
| 32 | uniquetab: TabOptionValueIncludingDeprecated; |
| 33 | } |
| 34 | |
| 35 | interface OptionsWrapper { |
| 36 | options: OptionsV0; |
| 37 | isFirstRun: boolean; |
| 38 | } |
| 39 | |
| 40 | export const TAB_OPTIONS: TabOption[] = [ |
Adrià Vilanova Martínez | 53f7a7f | 2022-05-30 13:59:59 +0200 | [diff] [blame] | 41 | // Open in new tab for each translation |
| 42 | { |
| 43 | value: '', |
| 44 | labelMsg: 'options_tabsoption_1', |
| 45 | deprecatedValues: [], |
| 46 | }, |
| 47 | // Open in a unique tab |
| 48 | { |
| 49 | value: 'yep', |
| 50 | labelMsg: 'options_tabsoption_2', |
| 51 | deprecatedValues: [], |
| 52 | }, |
| 53 | // Open in a popup |
| 54 | { |
| 55 | value: 'popup', |
| 56 | labelMsg: 'options_tabsoption_3', |
| 57 | deprecatedValues: ['panel'], |
| 58 | }, |
| 59 | ]; |
| 60 | |
| 61 | // Class which can be used to retrieve the user options in order to act |
| 62 | // accordingly. |
| 63 | export default class Options { |
Adrià Vilanova Martínez | 5bdc473 | 2022-05-31 20:12:21 +0200 | [diff] [blame^] | 64 | _options: OptionsV0; |
| 65 | isFirstRun: boolean; |
| 66 | |
| 67 | constructor(options: OptionsV0, isFirstRun: boolean) { |
Adrià Vilanova Martínez | 53f7a7f | 2022-05-30 13:59:59 +0200 | [diff] [blame] | 68 | this._options = options; |
| 69 | this.isFirstRun = isFirstRun; |
| 70 | } |
| 71 | |
Adrià Vilanova Martínez | 5bdc473 | 2022-05-31 20:12:21 +0200 | [diff] [blame^] | 72 | get uniqueTab(): TabOptionValue { |
Adrià Vilanova Martínez | 53f7a7f | 2022-05-30 13:59:59 +0200 | [diff] [blame] | 73 | return this._options.uniquetab; |
| 74 | } |
| 75 | |
Adrià Vilanova Martínez | 5bdc473 | 2022-05-31 20:12:21 +0200 | [diff] [blame^] | 76 | get targetLangs(): TargetLangs { |
Adrià Vilanova Martínez | 53f7a7f | 2022-05-30 13:59:59 +0200 | [diff] [blame] | 77 | return this._options.translateinto; |
| 78 | } |
| 79 | |
| 80 | // Returns a promise that resolves in an instance of the Object class with the |
| 81 | // current options. |
Adrià Vilanova Martínez | 5bdc473 | 2022-05-31 20:12:21 +0200 | [diff] [blame^] | 82 | static getOptions(readOnly: boolean = true): Promise<Options> { |
Adrià Vilanova Martínez | 53f7a7f | 2022-05-30 13:59:59 +0200 | [diff] [blame] | 83 | return Options.getOptionsRaw(readOnly).then(res => { |
| 84 | return new Options(res.options, res.isFirstRun); |
| 85 | }); |
| 86 | } |
| 87 | |
| 88 | // Returns a promise that resolves to an object containing: |
| 89 | // - |options|: normalized options object which can be used to initialize the |
| 90 | // Options class, and which contains the current options set up by the user. |
| 91 | // - |isFirstRun|: whether the extension is running for the first time and |
| 92 | // needs to be set up. |
| 93 | // |
| 94 | // If the options needed to be normalized/created, they are also saved in the |
| 95 | // sync storage area. |
Adrià Vilanova Martínez | 5bdc473 | 2022-05-31 20:12:21 +0200 | [diff] [blame^] | 96 | static getOptionsRaw(readOnly: boolean): Promise<OptionsWrapper> { |
Adrià Vilanova Martínez | 53f7a7f | 2022-05-30 13:59:59 +0200 | [diff] [blame] | 97 | return new Promise((res, rej) => { |
Adrià Vilanova Martínez | 5bdc473 | 2022-05-31 20:12:21 +0200 | [diff] [blame^] | 98 | chrome.storage.sync.get(null, itemsAny => { |
Adrià Vilanova Martínez | 53f7a7f | 2022-05-30 13:59:59 +0200 | [diff] [blame] | 99 | if (chrome.runtime.lastError) { |
| 100 | return rej(chrome.runtime.lastError); |
| 101 | } |
| 102 | |
Adrià Vilanova Martínez | 5bdc473 | 2022-05-31 20:12:21 +0200 | [diff] [blame^] | 103 | let items = <LegacyOptions>itemsAny; |
Adrià Vilanova Martínez | 53f7a7f | 2022-05-30 13:59:59 +0200 | [diff] [blame] | 104 | let didTranslateintoChange = false; |
| 105 | let didUniquetabChange = false; |
Adrià Vilanova Martínez | 53f7a7f | 2022-05-30 13:59:59 +0200 | [diff] [blame] | 106 | |
| 107 | // If the extension sync storage area is blank, set this as being the |
| 108 | // first run. |
Adrià Vilanova Martínez | 5bdc473 | 2022-05-31 20:12:21 +0200 | [diff] [blame^] | 109 | let isFirstRun = Object.keys(items).length === 0; |
Adrià Vilanova Martínez | 53f7a7f | 2022-05-30 13:59:59 +0200 | [diff] [blame] | 110 | |
| 111 | // Create |translateinto| property if it doesn't exist. |
| 112 | if (items.translateinto === undefined) { |
| 113 | didTranslateintoChange = true; |
| 114 | |
| 115 | // Upgrade from a version previous to v0.7 if applicable, otherwise |
| 116 | // create the property with the default values. |
| 117 | if (items.languages !== undefined) { |
Adrià Vilanova Martínez | 5bdc473 | 2022-05-31 20:12:21 +0200 | [diff] [blame^] | 118 | let newTranslateinto: TargetLangs; |
Adrià Vilanova Martínez | 53f7a7f | 2022-05-30 13:59:59 +0200 | [diff] [blame] | 119 | items.translateinto = |
Adrià Vilanova Martínez | 5bdc473 | 2022-05-31 20:12:21 +0200 | [diff] [blame^] | 120 | Object.assign(newTranslateinto, Object.values(items.languages)); |
Adrià Vilanova Martínez | 53f7a7f | 2022-05-30 13:59:59 +0200 | [diff] [blame] | 121 | } else { |
| 122 | let uiLocale = chrome.i18n.getMessage('@@ui_locale'); |
| 123 | let defaultLang1 = uiLocale.replace('_', '-'); |
| 124 | let defaultLang2 = uiLocale.split('_')[0]; |
| 125 | |
| 126 | items.translateinto = {}; |
Adrià Vilanova Martínez | 28f2aa0 | 2022-05-31 11:25:06 +0200 | [diff] [blame] | 127 | if (isoLangs[defaultLang1] != undefined) |
Adrià Vilanova Martínez | 53f7a7f | 2022-05-30 13:59:59 +0200 | [diff] [blame] | 128 | items.translateinto['0'] = defaultLang1; |
Adrià Vilanova Martínez | 28f2aa0 | 2022-05-31 11:25:06 +0200 | [diff] [blame] | 129 | else if (isoLangs[defaultLang2] != undefined) |
Adrià Vilanova Martínez | 53f7a7f | 2022-05-30 13:59:59 +0200 | [diff] [blame] | 130 | items.translateinto['0'] = defaultLang2; |
| 131 | } |
| 132 | } |
| 133 | |
| 134 | // Normalize |translateinto| property: remove non-existent languages or |
| 135 | // change them with the correct language code. |
| 136 | for (let [index, language] of Object.entries(items.translateinto)) { |
| 137 | if (isoLangs[language] === undefined) { |
| 138 | didTranslateintoChange = true; |
| 139 | if (convertLanguages[language] === undefined) { |
| 140 | // The language doesn't exist |
| 141 | console.log( |
| 142 | 'Deleting ' + language + |
| 143 | ' from items.translateinto because it doesn\'t exist.'); |
| 144 | delete items.translateinto[index]; |
| 145 | } else { |
| 146 | // The language doesn't exist but a known replacement is known |
| 147 | let newLanguage = convertLanguages[language]; |
| 148 | console.log('Replacing ' + language + ' with ' + newLanguage); |
| 149 | |
| 150 | // If the converted language is already on the list, just remove |
| 151 | // the wrong language, otherwise convert the language |
| 152 | if (Object.values(items.translateinto).includes(newLanguage)) |
| 153 | delete items.translateinto[index]; |
| 154 | else |
| 155 | items.translateinto[index] = newLanguage; |
| 156 | } |
| 157 | } |
| 158 | } |
| 159 | |
| 160 | // Normalize |uniquetab| property: |
| 161 | // - If it is set to a valid value, leave it alone. |
| 162 | // - If it is set to a deprecated value, change it to the corresponding |
| 163 | // value we use now. |
| 164 | // - If it is set to an incorrect value or it isn't set, change it to |
| 165 | // the default value. |
Adrià Vilanova Martínez | 5bdc473 | 2022-05-31 20:12:21 +0200 | [diff] [blame^] | 166 | let uniquetabNewValue: TabOptionValue; |
Adrià Vilanova Martínez | 53f7a7f | 2022-05-30 13:59:59 +0200 | [diff] [blame] | 167 | let foundValue = false; |
| 168 | for (let opt of TAB_OPTIONS) { |
| 169 | if (opt.value == items?.uniquetab) { |
Adrià Vilanova Martínez | 5bdc473 | 2022-05-31 20:12:21 +0200 | [diff] [blame^] | 170 | uniquetabNewValue = opt.value; |
Adrià Vilanova Martínez | 53f7a7f | 2022-05-30 13:59:59 +0200 | [diff] [blame] | 171 | foundValue = true; |
| 172 | break; |
| 173 | } |
| 174 | if (opt.deprecatedValues.includes(items?.uniquetab)) { |
| 175 | foundValue = true; |
Adrià Vilanova Martínez | 5bdc473 | 2022-05-31 20:12:21 +0200 | [diff] [blame^] | 176 | uniquetabNewValue = opt.value; |
Adrià Vilanova Martínez | 53f7a7f | 2022-05-30 13:59:59 +0200 | [diff] [blame] | 177 | break; |
| 178 | } |
| 179 | } |
| 180 | if (!foundValue) { |
Adrià Vilanova Martínez | 5bdc473 | 2022-05-31 20:12:21 +0200 | [diff] [blame^] | 181 | uniquetabNewValue = 'popup'; |
Adrià Vilanova Martínez | 53f7a7f | 2022-05-30 13:59:59 +0200 | [diff] [blame] | 182 | didUniquetabChange = true; |
| 183 | } |
| 184 | |
| 185 | // Clean up deprecated properties |
| 186 | if (items.languages !== undefined) { |
| 187 | delete items.languages; |
| 188 | chrome.storage.sync.remove('languages'); |
| 189 | } |
| 190 | |
Adrià Vilanova Martínez | 5bdc473 | 2022-05-31 20:12:21 +0200 | [diff] [blame^] | 191 | let returnObject: OptionsWrapper = { |
| 192 | isFirstRun, |
| 193 | options: { |
| 194 | translateinto: items.translateinto, |
| 195 | uniquetab: uniquetabNewValue, |
| 196 | } |
| 197 | }; |
| 198 | |
Adrià Vilanova Martínez | 53f7a7f | 2022-05-30 13:59:59 +0200 | [diff] [blame] | 199 | // Save properties that have changed if we're not in read-only mode |
| 200 | if (!readOnly) { |
| 201 | if (didTranslateintoChange || didUniquetabChange) { |
Adrià Vilanova Martínez | 5bdc473 | 2022-05-31 20:12:21 +0200 | [diff] [blame^] | 202 | chrome.storage.sync.set(returnObject.options); |
Adrià Vilanova Martínez | 53f7a7f | 2022-05-30 13:59:59 +0200 | [diff] [blame] | 203 | } |
| 204 | } |
| 205 | |
Adrià Vilanova Martínez | 53f7a7f | 2022-05-30 13:59:59 +0200 | [diff] [blame] | 206 | res(returnObject); |
| 207 | }); |
| 208 | }); |
| 209 | } |
| 210 | } |