├── .browserslistrc
├── .eslintrc.js
├── .github
├── FUNDING.yml
└── workflows
│ ├── build.yml
│ ├── chrome-token.yml
│ ├── codeql-analysis.yml
│ ├── comment-pr.yml
│ └── publish.yml
├── .gitignore
├── LICENSE
├── README.md
├── babel.config.js
├── package-lock.json
├── package.json
├── public
├── _locales
│ ├── be
│ │ └── messages.json
│ ├── ca
│ │ └── messages.json
│ ├── cs
│ │ └── messages.json
│ ├── da
│ │ └── messages.json
│ ├── de
│ │ └── messages.json
│ ├── el
│ │ └── messages.json
│ ├── en
│ │ └── messages.json
│ ├── es
│ │ └── messages.json
│ ├── es_419
│ │ └── messages.json
│ ├── et
│ │ └── messages.json
│ ├── fi
│ │ └── messages.json
│ ├── fr
│ │ └── messages.json
│ ├── gl
│ │ └── messages.json
│ ├── he
│ │ └── messages.json
│ ├── hu
│ │ └── messages.json
│ ├── id
│ │ └── messages.json
│ ├── it
│ │ └── messages.json
│ ├── ja
│ │ └── messages.json
│ ├── ko
│ │ └── messages.json
│ ├── lzh
│ │ └── messages.json
│ ├── mag
│ │ └── messages.json
│ ├── nb_NO
│ │ └── messages.json
│ ├── nl
│ │ └── messages.json
│ ├── pl
│ │ └── messages.json
│ ├── pt-PT
│ │ └── messages.json
│ ├── pt_BR
│ │ └── messages.json
│ ├── pt_PT
│ │ └── messages.json
│ ├── ru
│ │ └── messages.json
│ ├── sl
│ │ └── messages.json
│ ├── sv
│ │ └── messages.json
│ ├── th
│ │ └── messages.json
│ ├── tr
│ │ └── messages.json
│ ├── uk
│ │ └── messages.json
│ ├── zh_CN
│ │ └── messages.json
│ └── zh_Hant
│ │ └── messages.json
├── assets
│ ├── iconfont
│ │ ├── MaterialIcons-Regular.woff2
│ │ └── material-icons.css
│ ├── icons
│ │ ├── 24
│ │ │ └── userscript-no-icon.png
│ │ ├── 48
│ │ │ ├── icon-beta.png
│ │ │ └── icon.png
│ │ ├── 96
│ │ │ ├── icon-beta.png
│ │ │ └── icon.png
│ │ ├── 128
│ │ │ ├── icon-beta.png
│ │ │ └── icon.png
│ │ ├── extension.svg
│ │ ├── favicon.ico
│ │ └── icon.svg
│ ├── images
│ │ ├── IITC-black-horizontally.svg
│ │ └── IITC-black-horizontally.webp
│ ├── noto
│ │ ├── NotoSansMono-Regular.woff2
│ │ └── noto-font.css
│ └── roboto
│ │ ├── Roboto-Regular.woff2
│ │ └── roboto-font.css
├── browser-extension.html
└── index.html
├── safari
├── IITC Button.xcodeproj
│ ├── project.pbxproj
│ ├── project.xcworkspace
│ │ ├── contents.xcworkspacedata
│ │ └── xcshareddata
│ │ │ └── IDEWorkspaceChecks.plist
│ └── xcshareddata
│ │ └── xcschemes
│ │ ├── iOS.xcscheme
│ │ └── macOS.xcscheme
├── Safari Extension
│ ├── Shared
│ │ └── SafariWebExtensionHandler.swift
│ ├── iOS
│ │ └── Info.plist
│ └── macOS
│ │ ├── Info.plist
│ │ └── Safari Extension.entitlements
├── Scripts
│ └── pre-build.sh
├── Shared
│ ├── Assets.xcassets
│ │ ├── AccentColor.colorset
│ │ │ └── Contents.json
│ │ ├── AppIcon.appiconset
│ │ │ ├── Contents.json
│ │ │ ├── iOS_AppStore_1024.png
│ │ │ ├── iOS_iPadApp_76.png
│ │ │ ├── iOS_iPadApp_76@2x.png
│ │ │ ├── iOS_iPadNotifications_20.png
│ │ │ ├── iOS_iPadNotifications_20@2x.png
│ │ │ ├── iOS_iPadProApp_83.5@2x.png
│ │ │ ├── iOS_iPadSettings_29.png
│ │ │ ├── iOS_iPadSettings_29@2x.png
│ │ │ ├── iOS_iPadSpotlight_40.png
│ │ │ ├── iOS_iPadSpotlight_40@2x.png
│ │ │ ├── iOS_iPhoneApp_60@2x.png
│ │ │ ├── iOS_iPhoneApp_60@3x.png
│ │ │ ├── iOS_iPhoneNotifications_20@2x.png
│ │ │ ├── iOS_iPhoneNotifications_20@3x.png
│ │ │ ├── iOS_iPhoneSettings_29@2x.png
│ │ │ ├── iOS_iPhoneSettings_29@3x.png
│ │ │ ├── iOS_iPhoneSpotlight_40@2x.png
│ │ │ ├── iOS_iPhoneSpotlight_40@3x.png
│ │ │ ├── macOS_128.png
│ │ │ ├── macOS_128@2x.png
│ │ │ ├── macOS_16.png
│ │ │ ├── macOS_16@2x.png
│ │ │ ├── macOS_256.png
│ │ │ ├── macOS_256@2x.png
│ │ │ ├── macOS_32.png
│ │ │ ├── macOS_32@2x.png
│ │ │ ├── macOS_512.png
│ │ │ └── macOS_512@2x.png
│ │ └── Contents.json
│ └── IITCButtonApp.swift
├── iOS
│ ├── Info.plist
│ └── Views
│ │ ├── ContentView.swift
│ │ └── Helper.swift
└── macOS
│ ├── IITCButtonCommands.swift
│ ├── Info.plist
│ ├── Views
│ └── ContentView.swift
│ └── macOS.entitlements
├── src
├── background
│ ├── background.js
│ ├── injector.js
│ ├── intel.js
│ ├── requests.js
│ ├── utils.js
│ └── xhr-fallback.js
├── content-scripts
│ ├── bridge-manager.js
│ ├── loader.js
│ ├── storage-bridge.js
│ ├── utils.js
│ └── xhr-bridge.js
├── i18n.js
├── jsview
│ ├── App.vue
│ ├── Code.vue
│ ├── Header.vue
│ ├── highlightjs-lineToDiv.js
│ └── main.js
├── manifest.json
├── popup
│ ├── App.vue
│ ├── components
│ │ ├── Alert.vue
│ │ ├── Header.vue
│ │ ├── Hr.vue
│ │ ├── InputCustomServer.vue
│ │ ├── Message.vue
│ │ ├── SectionMainMenu
│ │ │ ├── PluginList
│ │ │ │ ├── NoData.vue
│ │ │ │ ├── Plugin.vue
│ │ │ │ ├── PluginList.vue
│ │ │ │ └── Title.vue
│ │ │ ├── ProgressBar.vue
│ │ │ ├── SearchBar.vue
│ │ │ ├── SectionMainMenu.vue
│ │ │ ├── Tags
│ │ │ │ ├── Tag.vue
│ │ │ │ └── Tags.vue
│ │ │ ├── Title.vue
│ │ │ └── ToggleIITC.vue
│ │ ├── SectionOptions.vue
│ │ ├── UpdateCheckIntervalSelector.vue
│ │ └── mixins.js
│ ├── data.js
│ ├── main.js
│ └── search.js
├── settings
│ ├── App.vue
│ ├── Header.vue
│ ├── add
│ │ ├── BlockDrop.vue
│ │ ├── BlockURL.vue
│ │ └── Main.vue
│ ├── backup
│ │ ├── Main.vue
│ │ └── utils.js
│ ├── debug
│ │ └── Main.vue
│ ├── main.js
│ └── utils.js
├── strToBase64.js
├── userscripts
│ ├── env.js
│ ├── gm-api.js
│ ├── utils.js
│ └── wrapper.js
├── uuid.js
└── xhr-sandbox.js
└── vue.config.js
/.browserslistrc:
--------------------------------------------------------------------------------
1 | > 1%
2 | last 2 versions
3 | not dead
4 |
--------------------------------------------------------------------------------
/.eslintrc.js:
--------------------------------------------------------------------------------
1 | module.exports = {
2 | root: true,
3 | env: {
4 | node: true,
5 | webextensions: true,
6 | },
7 | extends: [
8 | "plugin:vue/essential",
9 | "eslint:recommended",
10 | "plugin:prettier/recommended",
11 | ],
12 | parserOptions: {
13 | parser: "@babel/eslint-parser",
14 | },
15 | rules: {
16 | "no-console": process.env.NODE_ENV === "production" ? "warn" : "off",
17 | "no-debugger": process.env.NODE_ENV === "production" ? "warn" : "off",
18 | "vue/multi-word-component-names": "off",
19 | },
20 | };
21 |
--------------------------------------------------------------------------------
/.github/FUNDING.yml:
--------------------------------------------------------------------------------
1 | custom: ['https://t.me/iitc_news/58', 'https://iitc.app/donate.html']
2 |
--------------------------------------------------------------------------------
/.github/workflows/chrome-token.yml:
--------------------------------------------------------------------------------
1 | name: "fetch-chrome-webstore-access-token"
2 |
3 | on:
4 | schedule:
5 | - cron: '0 3 2 * *' # At 03:00 on day-of-month 2
6 |
7 | jobs:
8 | check-secret:
9 | runs-on: ubuntu-latest
10 | outputs:
11 | secrets: ${{ steps.key-check.outputs.defined }}
12 | steps:
13 | - name: Check for Secret availability
14 | id: key-check
15 | shell: bash
16 | run: |
17 | if [ "${{ secrets.CHROME_CLIENT_ID }}" != '' ]; then
18 | echo "defined=true" >> $GITHUB_OUTPUT;
19 | else
20 | echo "defined=false" >> $GITHUB_OUTPUT;
21 | fi
22 |
23 | fetchToken:
24 | runs-on: ubuntu-latest
25 | needs: [check-secret]
26 | if: needs.check-secret.outputs.secrets == 'true'
27 |
28 | steps:
29 | - uses: cardinalby/google-api-fetch-token-action@v1
30 | with:
31 | clientId: ${{ secrets.CHROME_CLIENT_ID }}
32 | clientSecret: ${{ secrets.CHROME_CLIENT_SECRET }}
33 | refreshToken: ${{ secrets.CHROME_REFRESH_TOKEN }}
34 |
--------------------------------------------------------------------------------
/.github/workflows/codeql-analysis.yml:
--------------------------------------------------------------------------------
1 | # For most projects, this workflow file will not need changing; you simply need
2 | # to commit it to your repository.
3 | #
4 | # You may wish to alter this file to override the set of languages analyzed,
5 | # or to provide custom queries or build logic.
6 | #
7 | # ******** NOTE ********
8 | # We have attempted to detect the languages in your repository. Please check
9 | # the `language` matrix defined below to confirm you have the correct set of
10 | # supported CodeQL languages.
11 | #
12 | name: "CodeQL"
13 |
14 | on:
15 | push:
16 | branches: [ master ]
17 | pull_request:
18 | # The branches below must be a subset of the branches above
19 | branches: [ master ]
20 | schedule:
21 | - cron: '37 12 * * 4'
22 |
23 | jobs:
24 | analyze:
25 | name: Analyze
26 | runs-on: ubuntu-latest
27 | permissions:
28 | actions: read
29 | contents: read
30 | security-events: write
31 |
32 | strategy:
33 | fail-fast: false
34 | matrix:
35 | language: [ 'javascript' ]
36 | # CodeQL supports [ 'cpp', 'csharp', 'go', 'java', 'javascript', 'python' ]
37 | # Learn more:
38 | # https://docs.github.com/en/free-pro-team@latest/github/finding-security-vulnerabilities-and-errors-in-your-code/configuring-code-scanning#changing-the-languages-that-are-analyzed
39 |
40 | steps:
41 | - name: Checkout repository
42 | uses: actions/checkout@v2
43 |
44 | # Initializes the CodeQL tools for scanning.
45 | - name: Initialize CodeQL
46 | uses: github/codeql-action/init@v1
47 | with:
48 | languages: ${{ matrix.language }}
49 | # If you wish to specify custom queries, you can do so here or in a config file.
50 | # By default, queries listed here will override any specified in a config file.
51 | # Prefix the list here with "+" to use these queries and those in the config file.
52 | # queries: ./path/to/local/query, your-org/your-repo/queries@main
53 |
54 | # Autobuild attempts to build any compiled languages (C/C++, C#, or Java).
55 | # If this step fails, then you should remove it and run the build manually (see below)
56 | - name: Autobuild
57 | uses: github/codeql-action/autobuild@v1
58 |
59 | # ℹ️ Command-line programs to run using the OS shell.
60 | # 📚 https://git.io/JvXDl
61 |
62 | # ✏️ If the Autobuild fails above, remove it and uncomment the following three lines
63 | # and modify them (or add more) to build your code if your project
64 | # uses a compiled language
65 |
66 | #- run: |
67 | # make bootstrap
68 | # make release
69 |
70 | - name: Perform CodeQL Analysis
71 | uses: github/codeql-action/analyze@v1
72 |
--------------------------------------------------------------------------------
/.github/workflows/comment-pr.yml:
--------------------------------------------------------------------------------
1 | name: Add artifact links to pull request
2 |
3 | on:
4 | workflow_run:
5 | workflows: ["Build IITC Button"]
6 | types: [completed]
7 | workflow_dispatch:
8 |
9 | jobs:
10 | comment-links:
11 | runs-on: ubuntu-latest
12 | steps:
13 | - name: Get artifact list from API
14 | id: get-artifacts
15 | uses: actions/github-script@v7
16 | with:
17 | github-token: ${{ secrets.GITHUB_TOKEN }}
18 | script: |
19 | const runId = ${{ github.event.workflow_run.id }};
20 | const artifacts = await github.rest.actions.listWorkflowRunArtifacts({
21 | owner: context.repo.owner,
22 | repo: context.repo.repo,
23 | run_id: runId
24 | });
25 | artifacts.data.artifacts.forEach((artifact, index) => {
26 | const nameVar = `artifact${index + 1}`;
27 | const displayNameVar = `displayArtifact${index + 1}`;
28 | const urlVar = `url${index + 1}`;
29 | let displayName = artifact.name.endsWith('-artifacts') ? `**${artifact.name}**` : artifact.name;
30 | core.exportVariable(nameVar, artifact.name);
31 | core.exportVariable(displayNameVar, displayName);
32 | core.exportVariable(urlVar, `https://github.com/${context.repo.owner}/${context.repo.repo}/actions/runs/${runId}/artifacts/${artifact.id}`);
33 | });
34 | core.exportVariable("firstArtifactId", artifacts.data.artifacts[0].id);
35 |
36 | - name: Download first artifact
37 | uses: actions/github-script@v7
38 | with:
39 | github-token: ${{ secrets.GITHUB_TOKEN }}
40 | script: |
41 | let download = await github.rest.actions.downloadArtifact({
42 | owner: context.repo.owner,
43 | repo: context.repo.repo,
44 | artifact_id: ${{ env.firstArtifactId }},
45 | archive_format: 'zip',
46 | });
47 | let fs = require('fs');
48 | fs.writeFileSync(`${process.env.GITHUB_WORKSPACE}/build.zip`, Buffer.from(download.data));
49 |
50 | - name: Extract PR number from artifact
51 | run: |
52 | unzip build.zip
53 | if [ -f ".metadata/pr_number" ]; then
54 | PR_NUMBER=$(cat .metadata/pr_number)
55 | echo "PR_NUMBER=$PR_NUMBER" >> $GITHUB_ENV
56 | fi
57 |
58 | - name: Comment with artifact links for PR
59 | uses: marocchino/sticky-pull-request-comment@v2
60 | if: ${{ env.PR_NUMBER != '' }}
61 | with:
62 | header: pr_artifacts
63 | number: ${{ env.PR_NUMBER }}
64 | message: |
65 | Build completed successfully. Below are the download links for the build artifacts:
66 |
67 | | Artifact Name | Download Link |
68 | | ------------- | ------------- |
69 | | ${{ env.displayArtifact1 }} | [Download](${{ env.url1 }}) |
70 | | ${{ env.displayArtifact2 }} | [Download](${{ env.url2 }}) |
71 | | ${{ env.displayArtifact3 }} | [Download](${{ env.url3 }}) |
72 | | ${{ env.displayArtifact4 }} | [Download](${{ env.url4 }}) |
73 | | ${{ env.displayArtifact5 }} | [Download](${{ env.url5 }}) |
74 |
75 | Artifacts will only be retained for 90 days.
76 |
--------------------------------------------------------------------------------
/.gitignore:
--------------------------------------------------------------------------------
1 | .DS_Store
2 | node_modules
3 | /dist
4 |
5 | # local env files
6 | .env.local
7 | .env.*.local
8 |
9 | # Log files
10 | npm-debug.log*
11 | yarn-debug.log*
12 | yarn-error.log*
13 | pnpm-debug.log*
14 |
15 | # Editor directories and files
16 | .idea
17 | .vscode
18 | *.suo
19 | *.ntvs*
20 | *.njsproj
21 | *.sln
22 | *.sw?
23 |
24 | # Vue Browser Extension Output
25 | *.pem
26 | *.pub
27 | *.zip
28 | /artifacts
29 |
30 | # Xcode
31 | ## User settings
32 | xcuserdata/
33 |
34 | ## Info.plist Preprocessor
35 | info-plist-preprocessor.h
--------------------------------------------------------------------------------
/babel.config.js:
--------------------------------------------------------------------------------
1 | module.exports = {
2 | presets: ["@vue/cli-plugin-babel/preset"],
3 | };
4 |
--------------------------------------------------------------------------------
/package.json:
--------------------------------------------------------------------------------
1 | {
2 | "name": "iitc-button",
3 | "version": "3.1.0",
4 | "repository": "https://github.com/IITC-CE/IITC-Button.git",
5 | "license": "GPLv3",
6 | "private": true,
7 | "scripts": {
8 | "build_mv2": "export MANIFEST_VERSION=2 && vue-cli-service build",
9 | "build_mv3_firefox": "export MANIFEST_VERSION=3 && export BROWSER=firefox && vue-cli-service build",
10 | "build_mv3_chrome": "export MANIFEST_VERSION=3 && export BROWSER=chrome && vue-cli-service build",
11 | "build_mv3_safari": "export MANIFEST_VERSION=3 && export BROWSER=safari && vue-cli-service build",
12 | "lint": "vue-cli-service lint"
13 | },
14 | "dependencies": {
15 | "@highlightjs/vue-plugin": "^1.0.2",
16 | "core-js": "^3.8.3",
17 | "highlight.js": "^10.7.3",
18 | "jszip": "^3.10.1",
19 | "lib-iitc-manager": "^1.10.1",
20 | "scored-fuzzysearch": "^1.0.5",
21 | "vue": "^2.6.14"
22 | },
23 | "devDependencies": {
24 | "@babel/core": "^7.12.16",
25 | "@babel/eslint-parser": "^7.12.16",
26 | "@vue/cli-plugin-babel": "~5.0.0",
27 | "@vue/cli-plugin-eslint": "~5.0.0",
28 | "@vue/cli-service": "~5.0.0",
29 | "@vue/eslint-config-prettier": "^6.0.0",
30 | "eslint": "^7.32.0",
31 | "eslint-config-prettier": "^8.3.0",
32 | "eslint-plugin-vue": "^8.0.3",
33 | "prettier": "^2.4.1",
34 | "publish-browser-extension": "^2.1.3",
35 | "vue-cli-plugin-browser-extension": "^0.26.1",
36 | "vue-template-compiler": "^2.6.14",
37 | "webextension-polyfill": "^0.10.0"
38 | },
39 | "readme": "README.md"
40 | }
41 |
--------------------------------------------------------------------------------
/public/_locales/be/messages.json:
--------------------------------------------------------------------------------
1 | {
2 | "iitcButtonOptions": {
3 | "message": "Налады IITC-CE кнопкі"
4 | },
5 | "updateNow": {
6 | "message": "Абнавіць зараз"
7 | },
8 | "release": {
9 | "message": "Выпуск"
10 | },
11 | "updateFrequency": {
12 | "message": "Праверка абнаўленняў IITC-CE"
13 | },
14 | "every6hours": {
15 | "message": "Кожныя шэсць гадзін"
16 | },
17 | "every12hours": {
18 | "message": "Кожныя дванаццаць гадзін"
19 | },
20 | "everyDay": {
21 | "message": "Кожны дзень"
22 | },
23 | "everyWeek": {
24 | "message": "Кожны тыдзень"
25 | },
26 | "lang": {
27 | "message": "by"
28 | },
29 | "titleDefault": {
30 | "message": "Адчыніць Intel",
31 | "description": "Title for the button at the application panel"
32 | },
33 | "needRebootIntel": {
34 | "message": "Змены будуць ужыты пасля перазагрузкі Intel"
35 | },
36 | "updateInProgress": {
37 | "message": "Абнаўляецца…"
38 | },
39 | "noData": {
40 | "message": "Няма дадзеных"
41 | },
42 | "addExternalPlugin": {
43 | "message": "Дабавіць знешнюю ўбудову"
44 | },
45 | "iitcHomePage": {
46 | "message": "Хатняя старонка"
47 | },
48 | "changesApplied": {
49 | "message": "Змены былі ўжытыя"
50 | },
51 | "extDescription": {
52 | "message": "Лёгкі запуск IITC.",
53 | "description": "Description of the extension"
54 | },
55 | "choosingUpdateChannel": {
56 | "message": "Выбар канала абнаўлення IITC-CE"
57 | },
58 | "updateExternalFrequency": {
59 | "message": "Праверка абнаўленняў знешніх убудоў"
60 | },
61 | "anyChannel": {
62 | "message": "Усе каналы"
63 | },
64 | "loading": {
65 | "message": "Чакайце…"
66 | },
67 | "install": {
68 | "message": "Усталяваць"
69 | },
70 | "clickInstallPlugin": {
71 | "message": "Гэта плагін IITC. Націсніце \"Усталяваць\", каб пачаць выкарыстоўваць яго."
72 | },
73 | "willBeOverwrittenByNewPlugin": {
74 | "message": "Плагін з тым самым ID будзе заменены новым плагінам."
75 | },
76 | "dropJSHereOrClick": {
77 | "message": "Перацягніце .js файлы сюды альбо націсніце, каб загрузіць."
78 | },
79 | "external": {
80 | "message": "Знешні"
81 | },
82 | "serverNotAvailableRetry": {
83 | "message": "Сервер недаступны. Паўтарыце спробу пасля $NUM$ сек",
84 | "placeholders": {
85 | "num": {
86 | "content": "$1",
87 | "example": "5"
88 | }
89 | }
90 | },
91 | "or": {
92 | "message": "ці"
93 | },
94 | "errorReadingFile": {
95 | "message": "Адбылася памылка падчас чытання файла $PLUGIN_NAME$.",
96 | "placeholders": {
97 | "plugin_name": {
98 | "content": "$1",
99 | "example": "Awesome plugin"
100 | }
101 | }
102 | },
103 | "addressNotAvailable": {
104 | "message": "Адрас недаступны"
105 | },
106 | "addedUserScriptTo": {
107 | "message": "$PLUGIN_NAME$ быў дададзены ў катэгорыю \"$PLUGIN_CATEGORY$\".",
108 | "placeholders": {
109 | "plugin_name": {
110 | "content": "$1",
111 | "example": "Awesome plugin"
112 | },
113 | "plugin_category": {
114 | "content": "$2",
115 | "example": "Draw"
116 | }
117 | }
118 | },
119 | "notValidUserScript": {
120 | "message": "$PLUGIN_NAME$ не з'яўляецца сапраўдным сцэнарыям карыстальніка.",
121 | "placeholders": {
122 | "plugin_name": {
123 | "content": "$1",
124 | "example": "Awesome plugin"
125 | }
126 | }
127 | },
128 | "pluginDelete": {
129 | "message": "Выдаліць"
130 | },
131 | "pluginSave": {
132 | "message": "Захаваць"
133 | },
134 | "openSupport": {
135 | "message": "Адкрыць старонку падтрымкі:"
136 | },
137 | "badgeOverride": {
138 | "message": "Перавызначыць"
139 | }
140 | }
141 |
--------------------------------------------------------------------------------
/public/_locales/ca/messages.json:
--------------------------------------------------------------------------------
1 | {
2 | "lang": {
3 | "message": "ca"
4 | },
5 | "titleDefault": {
6 | "message": "Obre l'Intel",
7 | "description": "Title for the button at the application panel"
8 | },
9 | "serverNotAvailableRetry": {
10 | "message": "El servidor no està disponible. Torna-ho a provar després de $NUM$ segons",
11 | "placeholders": {
12 | "num": {
13 | "content": "$1",
14 | "example": "5"
15 | }
16 | }
17 | },
18 | "updateInProgress": {
19 | "message": "S'està actualitzant…"
20 | },
21 | "needRebootIntel": {
22 | "message": "Els canvis s'aplicaran després de reiniciar l'Intel."
23 | },
24 | "extDescription": {
25 | "message": "Inicia IITC per Ingress Intel amb facilitat.",
26 | "description": "Description of the extension"
27 | },
28 | "external": {
29 | "message": "Extern"
30 | },
31 | "loading": {
32 | "message": "Carregant…"
33 | },
34 | "install": {
35 | "message": "Instal·la"
36 | },
37 | "clickInstallPlugin": {
38 | "message": "Això és un plugin d'IITC. Selecciona “Instal·la” per fer-lo servir."
39 | },
40 | "willBeOverwrittenByNewPlugin": {
41 | "message": "Els plugins amb el mateix ID es sobreescriuran pel nou plugin."
42 | },
43 | "dropJSHereOrClick": {
44 | "message": "Arrossega fitxers .js aquí o fes clic per carregar-los."
45 | },
46 | "or": {
47 | "message": "o"
48 | },
49 | "errorReadingFile": {
50 | "message": "S'ha trobat un error en llegir el fitxer $PLUGIN_NAME$.",
51 | "placeholders": {
52 | "plugin_name": {
53 | "content": "$1",
54 | "example": "Awesome plugin"
55 | }
56 | }
57 | },
58 | "addressNotAvailable": {
59 | "message": "L'adreça no està disponible"
60 | },
61 | "notValidUserScript": {
62 | "message": "$PLUGIN_NAME$ no és un UserScript vàlid.",
63 | "placeholders": {
64 | "plugin_name": {
65 | "content": "$1",
66 | "example": "Awesome plugin"
67 | }
68 | }
69 | },
70 | "pluginDelete": {
71 | "message": "Elimina"
72 | },
73 | "pluginSave": {
74 | "message": "Desa"
75 | },
76 | "openSupport": {
77 | "message": "Obre la pàgina de suport:"
78 | },
79 | "anyChannel": {
80 | "message": "Qualsevol canal"
81 | },
82 | "everyWeek": {
83 | "message": "Cada setmana"
84 | },
85 | "everyDay": {
86 | "message": "Cada dia"
87 | },
88 | "every12hours": {
89 | "message": "Cada 12 hores"
90 | },
91 | "every6hours": {
92 | "message": "Cada 6 hores"
93 | },
94 | "updateExternalFrequency": {
95 | "message": "Comprova actualitzacions de plugins externs"
96 | },
97 | "updateFrequency": {
98 | "message": "Comprova actualitzacions d'IITC-CE"
99 | },
100 | "release": {
101 | "message": "Estable"
102 | },
103 | "choosingUpdateChannel": {
104 | "message": "Tria un canal d'actualitzacions d'IITC-CE"
105 | },
106 | "updateNow": {
107 | "message": "actualitza ara"
108 | },
109 | "iitcButtonOptions": {
110 | "message": "Opcions del Botó IITC-CE"
111 | },
112 | "iitcHomePage": {
113 | "message": "Pàgina d'inici"
114 | },
115 | "addExternalPlugin": {
116 | "message": "Afegeix un plugin extern"
117 | },
118 | "noData": {
119 | "message": "Sense dades"
120 | },
121 | "changesApplied": {
122 | "message": "Els canvis s'han aplicat"
123 | },
124 | "addedUserScriptTo": {
125 | "message": "$PLUGIN_NAME$ ha estat afegit a la categoria \"$PLUGIN_CATEGORY$\".",
126 | "placeholders": {
127 | "plugin_name": {
128 | "content": "$1",
129 | "example": "Awesome plugin"
130 | },
131 | "plugin_category": {
132 | "content": "$2",
133 | "example": "Draw"
134 | }
135 | }
136 | },
137 | "badgeOverride": {
138 | "message": "substituir"
139 | },
140 | "beta": {
141 | "message": "Beta"
142 | }
143 | }
144 |
--------------------------------------------------------------------------------
/public/_locales/da/messages.json:
--------------------------------------------------------------------------------
1 | {
2 | "beta": {
3 | "message": "Beta"
4 | },
5 | "updateNow": {
6 | "message": "Updater nu"
7 | },
8 | "iitcButtonOptions": {
9 | "message": "IITC-CE Knap indstillinger"
10 | },
11 | "addExternalPlugin": {
12 | "message": "Tilføj eksternt plugin"
13 | },
14 | "noData": {
15 | "message": "Ingen data"
16 | },
17 | "updateInProgress": {
18 | "message": "Opdaterer…"
19 | },
20 | "titleDefault": {
21 | "message": "Åben Intel",
22 | "description": "Title for the button at the application panel"
23 | },
24 | "lang": {
25 | "message": "da"
26 | },
27 | "serverNotAvailableRetry": {
28 | "message": "Serveren er ikke tilgængelig. Prøv igen efter $NUM$ sekunder",
29 | "placeholders": {
30 | "num": {
31 | "content": "$1",
32 | "example": "5"
33 | }
34 | }
35 | },
36 | "dropJSHereOrClick": {
37 | "message": "Træk .js filerne her, eller klik for at uploade."
38 | },
39 | "errorReadingFile": {
40 | "message": "Der opstod en fejl under læsning af $PLUGIN_NAME$-fil.",
41 | "placeholders": {
42 | "plugin_name": {
43 | "content": "$1",
44 | "example": "Awesome plugin"
45 | }
46 | }
47 | },
48 | "addedUserScriptTo": {
49 | "message": "$PLUGIN_NAME$ er føjet til kategorien \"$PLUGIN_CATEGORY$\".",
50 | "placeholders": {
51 | "plugin_name": {
52 | "content": "$1",
53 | "example": "Awesome plugin"
54 | },
55 | "plugin_category": {
56 | "content": "$2",
57 | "example": "Draw"
58 | }
59 | }
60 | },
61 | "notValidUserScript": {
62 | "message": "$PLUGIN_NAME$ er ikke et gyldigt UserScript.",
63 | "placeholders": {
64 | "plugin_name": {
65 | "content": "$1",
66 | "example": "Awesome plugin"
67 | }
68 | }
69 | },
70 | "external": {
71 | "message": "Ekstern"
72 | },
73 | "loading": {
74 | "message": "Indlæser…"
75 | },
76 | "install": {
77 | "message": "Installere"
78 | },
79 | "clickInstallPlugin": {
80 | "message": "Dette er et IITC-plugin. Klik på installer for at begynde at bruge det."
81 | },
82 | "willBeOverwrittenByNewPlugin": {
83 | "message": "Plugin med samme ID overskrives af det nye plugin."
84 | },
85 | "or": {
86 | "message": "Eller"
87 | },
88 | "addressNotAvailable": {
89 | "message": "Adressen er ikke tilgængelig"
90 | },
91 | "pluginDelete": {
92 | "message": "Slet"
93 | },
94 | "pluginSave": {
95 | "message": "Gem"
96 | },
97 | "openSupport": {
98 | "message": "Åbn supportsiden:"
99 | },
100 | "badgeOverride": {
101 | "message": "tilsidesætte"
102 | },
103 | "anyChannel": {
104 | "message": "Enhver kanal"
105 | },
106 | "everyWeek": {
107 | "message": "Hver uge"
108 | },
109 | "everyDay": {
110 | "message": "Hver dag"
111 | },
112 | "every12hours": {
113 | "message": "Hver 12 time"
114 | },
115 | "every6hours": {
116 | "message": "Hver 6 time"
117 | },
118 | "updateExternalFrequency": {
119 | "message": "Eksterne plugins kontrollerer for opdateringer"
120 | },
121 | "updateFrequency": {
122 | "message": "IITC-CE kontrollerer for opdateringer"
123 | },
124 | "release": {
125 | "message": "Udgivelses dato"
126 | },
127 | "choosingUpdateChannel": {
128 | "message": "Valg af en IITC-CE opdateringskanal"
129 | },
130 | "iitcHomePage": {
131 | "message": "Hjemmeside"
132 | },
133 | "changesApplied": {
134 | "message": "Ændringer blev anvendt"
135 | },
136 | "needRebootIntel": {
137 | "message": "Ændringer vil blive aktiveret efter Intel er genstartet"
138 | },
139 | "extDescription": {
140 | "message": "Start IITC for Ingress med lethed.",
141 | "description": "Description of the extension"
142 | }
143 | }
144 |
--------------------------------------------------------------------------------
/public/_locales/el/messages.json:
--------------------------------------------------------------------------------
1 | {
2 | "release": {
3 | "message": "Σταθερή έκδοση"
4 | },
5 | "lang": {
6 | "message": "el"
7 | },
8 | "external": {
9 | "message": "\tΕξωτερικά"
10 | },
11 | "serverNotAvailableRetry": {
12 | "message": "Ο διακομιστής δεν είναι διαθέσιμος. Δοκιμάστε ξανά μετά από $NUM$ δευτερόλεπτα",
13 | "placeholders": {
14 | "num": {
15 | "content": "$1",
16 | "example": "5"
17 | }
18 | }
19 | },
20 | "loading": {
21 | "message": "Φόρτωση…"
22 | },
23 | "install": {
24 | "message": "Εγκατάσταση"
25 | },
26 | "clickInstallPlugin": {
27 | "message": "Αυτό είναι ένα πρόσθετο IITC. Κάντε κλικ στην εγκατάσταση για να αρχίσετε να το χρησιμοποιείτε."
28 | },
29 | "willBeOverwrittenByNewPlugin": {
30 | "message": "Πρόσθετα με την ίδια Ταυτότητα θα αντικατασταθούν από το νέο πρόσθετο."
31 | },
32 | "dropJSHereOrClick": {
33 | "message": "Τοποθετήστε αρχεία .js εδώ ή κάντε κλικ για μεταφόρτωση."
34 | },
35 | "or": {
36 | "message": "ή"
37 | },
38 | "errorReadingFile": {
39 | "message": "Παρουσιάστηκε σφάλμα κατά την ανάγνωση του αρχείου $PLUGIN_NAME$.",
40 | "placeholders": {
41 | "plugin_name": {
42 | "content": "$1",
43 | "example": "Awesome plugin"
44 | }
45 | }
46 | },
47 | "addressNotAvailable": {
48 | "message": "Η διεύθυνση δεν είναι διαθέσιμη"
49 | },
50 | "notValidUserScript": {
51 | "message": "Το $PLUGIN_NAME$ δεν είναι έγκυρο σενάριο χρήστη.",
52 | "placeholders": {
53 | "plugin_name": {
54 | "content": "$1",
55 | "example": "Awesome plugin"
56 | }
57 | }
58 | },
59 | "pluginDelete": {
60 | "message": "Διαγραφή"
61 | },
62 | "pluginSave": {
63 | "message": "Αποθήκευση"
64 | },
65 | "openSupport": {
66 | "message": "Άνοιγμα σελίδας υποστήριξης:"
67 | },
68 | "anyChannel": {
69 | "message": "Οποιοδήποτε κανάλι"
70 | },
71 | "everyWeek": {
72 | "message": "Κάθε Εβδομάδα"
73 | },
74 | "everyDay": {
75 | "message": "Κάθε Ημέρα"
76 | },
77 | "every12hours": {
78 | "message": "Κάθε 12 Ώρες"
79 | },
80 | "every6hours": {
81 | "message": "Κάθε 6 Ώρες"
82 | },
83 | "updateExternalFrequency": {
84 | "message": "Εξωτερικά πρόσθετα έλεγχος για ενημερώσεις"
85 | },
86 | "updateFrequency": {
87 | "message": "IITC-CE έλεγχος για ενημερώσεις"
88 | },
89 | "choosingUpdateChannel": {
90 | "message": "Επιλογή καναλιού ενημέρωσης IITC-CE"
91 | },
92 | "updateNow": {
93 | "message": "ενημέρωση τώρα"
94 | },
95 | "iitcButtonOptions": {
96 | "message": "IITC-CE επιλογές"
97 | },
98 | "iitcHomePage": {
99 | "message": "Αρχική σελίδα"
100 | },
101 | "addExternalPlugin": {
102 | "message": "Εισαγωγή εξωτερικού πρόσθετου"
103 | },
104 | "noData": {
105 | "message": "Χωρίς δεδομένα"
106 | },
107 | "changesApplied": {
108 | "message": "Οι αλλαγές εφαρμόστηκαν"
109 | },
110 | "updateInProgress": {
111 | "message": "Αναβάθμιση σε εξέλιξη…"
112 | },
113 | "needRebootIntel": {
114 | "message": "Οι αλλαγές θα εφαρμοστούν μετά την επανεκκίνηση του Intel"
115 | },
116 | "titleDefault": {
117 | "message": "Άνοιγμα Χάρτη",
118 | "description": "Title for the button at the application panel"
119 | },
120 | "extDescription": {
121 | "message": "Ξεκινήστε το IITC για τον χάρτη Ingress Intel με ευκολία.",
122 | "description": "Description of the extension"
123 | },
124 | "addedUserScriptTo": {
125 | "message": "Το $PLUGIN_NAME$ έχει προστεθεί στην κατηγορία \"$PLUGIN_CATEGORY$\".",
126 | "placeholders": {
127 | "plugin_name": {
128 | "content": "$1",
129 | "example": "Awesome plugin"
130 | },
131 | "plugin_category": {
132 | "content": "$2",
133 | "example": "Draw"
134 | }
135 | }
136 | },
137 | "badgeOverride": {
138 | "message": "παρακάμψετε"
139 | },
140 | "beta": {
141 | "message": "Beta"
142 | }
143 | }
144 |
--------------------------------------------------------------------------------
/public/_locales/es_419/messages.json:
--------------------------------------------------------------------------------
1 | {
2 | "serverNotAvailableRetry": {
3 | "message": "El servidor no está disponible. Reintentando en $NUM$ segundos",
4 | "placeholders": {
5 | "num": {
6 | "content": "$1",
7 | "example": "5"
8 | }
9 | }
10 | },
11 | "every12hours": {
12 | "message": "Cada 12 horas"
13 | },
14 | "everyDay": {
15 | "message": "Diariamente"
16 | },
17 | "everyWeek": {
18 | "message": "Semanalmente"
19 | },
20 | "anyChannel": {
21 | "message": "Cualquier medio"
22 | },
23 | "pluginSave": {
24 | "message": "Guardar"
25 | },
26 | "updateFrequency": {
27 | "message": "IITC-CE buscará actualizaciones"
28 | },
29 | "updateExternalFrequency": {
30 | "message": "Buscar actualizaciones de los plugin externos"
31 | },
32 | "every6hours": {
33 | "message": "Cada 6 horas"
34 | },
35 | "openSupport": {
36 | "message": "Abrir página de soporte:"
37 | },
38 | "titleDefault": {
39 | "message": "Abrir Intel",
40 | "description": "Title for the button at the application panel"
41 | },
42 | "extDescription": {
43 | "message": "Inicie IITC para Ingress Intel con facilidad.",
44 | "description": "Description of the extension"
45 | },
46 | "lang": {
47 | "message": "es_419"
48 | },
49 | "needRebootIntel": {
50 | "message": "Los cambios se aplicarán después de reiniciar Intel"
51 | },
52 | "updateInProgress": {
53 | "message": "Actualización en curso…"
54 | },
55 | "changesApplied": {
56 | "message": "Se aplicaron los cambios"
57 | },
58 | "noData": {
59 | "message": "Sin datos"
60 | },
61 | "addExternalPlugin": {
62 | "message": "Adicionar plugin externo"
63 | },
64 | "iitcHomePage": {
65 | "message": "Página de inicio"
66 | },
67 | "iitcButtonOptions": {
68 | "message": "Opciones del botón IITC-CE"
69 | },
70 | "updateNow": {
71 | "message": "actualizar ahora"
72 | },
73 | "choosingUpdateChannel": {
74 | "message": "Elija un canal de actualización de IITC-CE"
75 | },
76 | "release": {
77 | "message": "Versión definitiva"
78 | },
79 | "pluginDelete": {
80 | "message": "Borrar"
81 | },
82 | "notValidUserScript": {
83 | "message": "$PLUGIN_NAME$ no es un plugin válido.",
84 | "placeholders": {
85 | "plugin_name": {
86 | "content": "$1",
87 | "example": "Awesome plugin"
88 | }
89 | }
90 | },
91 | "addressNotAvailable": {
92 | "message": "Dirección no disponible"
93 | },
94 | "errorReadingFile": {
95 | "message": "Ocurrió un error leyendo el archivo $PLUGIN_NAME$ del plugin.",
96 | "placeholders": {
97 | "plugin_name": {
98 | "content": "$1",
99 | "example": "Awesome plugin"
100 | }
101 | }
102 | },
103 | "or": {
104 | "message": "o"
105 | },
106 | "clickInstallPlugin": {
107 | "message": "Este es un plugin para IITC. Haga clic en Instalar para comenzar a usarlo."
108 | },
109 | "install": {
110 | "message": "Instalar"
111 | },
112 | "loading": {
113 | "message": "Cargando…"
114 | },
115 | "external": {
116 | "message": "\tExterno"
117 | },
118 | "willBeOverwrittenByNewPlugin": {
119 | "message": "Otro plugin con el mismo ID será sobrescrito con el nuevo plugin."
120 | },
121 | "dropJSHereOrClick": {
122 | "message": "Arrastre aquí archivos .js o haga clic para cargarlos."
123 | },
124 | "addedUserScriptTo": {
125 | "message": "$PLUGIN_NAME$ se adicionó a la categoría de plugins \"$PLUGIN_CATEGORY$\".",
126 | "placeholders": {
127 | "plugin_name": {
128 | "content": "$1",
129 | "example": "Awesome plugin"
130 | },
131 | "plugin_category": {
132 | "content": "$2",
133 | "example": "Draw"
134 | }
135 | }
136 | },
137 | "badgeOverride": {
138 | "message": "anular"
139 | },
140 | "beta": {
141 | "message": "Beta"
142 | }
143 | }
144 |
--------------------------------------------------------------------------------
/public/_locales/et/messages.json:
--------------------------------------------------------------------------------
1 | {
2 | "noData": {
3 | "message": "Andmed puuduvad"
4 | },
5 | "changesApplied": {
6 | "message": "Muutused on jõustunud"
7 | },
8 | "updateInProgress": {
9 | "message": "Uuendus on tegemisel …"
10 | },
11 | "needRebootIntel": {
12 | "message": "Muutused jõustuvad peale Inteli restarti"
13 | },
14 | "titleDefault": {
15 | "message": "Ava Intel",
16 | "description": "Title for the button at the application panel"
17 | },
18 | "lang": {
19 | "message": "et"
20 | },
21 | "extDescription": {
22 | "message": "Käivita IITC Ingressi jaoks lihtsalt.",
23 | "description": "Description of the extension"
24 | }
25 | }
26 |
--------------------------------------------------------------------------------
/public/_locales/fi/messages.json:
--------------------------------------------------------------------------------
1 | {}
2 |
--------------------------------------------------------------------------------
/public/_locales/fr/messages.json:
--------------------------------------------------------------------------------
1 | {
2 | "noData": {
3 | "message": "Pas de données"
4 | },
5 | "addExternalPlugin": {
6 | "message": "Ajouter un plugin externe"
7 | },
8 | "iitcHomePage": {
9 | "message": "Accueil"
10 | },
11 | "pluginSave": {
12 | "message": "Enregistrer"
13 | },
14 | "pluginDelete": {
15 | "message": "Supprimer"
16 | },
17 | "or": {
18 | "message": "ou"
19 | },
20 | "willBeOverwrittenByNewPlugin": {
21 | "message": "Le plugin avec le même ID sera écrasé par le nouveau plugin."
22 | },
23 | "clickInstallPlugin": {
24 | "message": "Ceci est un plugin IITC. Cliquez sur installer pour commencer à l'utiliser."
25 | },
26 | "install": {
27 | "message": "Installer"
28 | },
29 | "loading": {
30 | "message": "Chargement…"
31 | },
32 | "external": {
33 | "message": "Externe"
34 | },
35 | "errorReadingFile": {
36 | "message": "Une erreur est survenue lors de la lecture du fichier $PLUGIN_NAME$.",
37 | "placeholders": {
38 | "plugin_name": {
39 | "content": "$1",
40 | "example": "Awesome plugin"
41 | }
42 | }
43 | },
44 | "serverNotAvailableRetry": {
45 | "message": "Le serveur n'est pas disponible. Réessayez dans $NUM$ secondes",
46 | "placeholders": {
47 | "num": {
48 | "content": "$1",
49 | "example": "5"
50 | }
51 | }
52 | },
53 | "updateInProgress": {
54 | "message": "Mise à jour en cours…"
55 | },
56 | "everyWeek": {
57 | "message": "Toutes les semaines"
58 | },
59 | "extDescription": {
60 | "message": "Lancer facilement IITC pour Ingress.",
61 | "description": "Description of the extension"
62 | },
63 | "titleDefault": {
64 | "message": "Ouvrir l'Intel",
65 | "description": "Title for the button at the application panel"
66 | },
67 | "lang": {
68 | "message": "fr"
69 | },
70 | "openSupport": {
71 | "message": "Ouvrir le support :"
72 | },
73 | "anyChannel": {
74 | "message": "Tout les canaux "
75 | },
76 | "release": {
77 | "message": "Release"
78 | },
79 | "choosingUpdateChannel": {
80 | "message": "Choisissez un canal de mise à jour"
81 | },
82 | "iitcButtonOptions": {
83 | "message": "Options du bouton IITC-CE"
84 | },
85 | "dropJSHereOrClick": {
86 | "message": "Déposez les fichiers .js ici ou cliquez pour télécharger."
87 | },
88 | "addressNotAvailable": {
89 | "message": "L'adresse n'est pas disponible"
90 | },
91 | "notValidUserScript": {
92 | "message": "$PLUGIN_NAME$ n'est pas un UserScript valide.",
93 | "placeholders": {
94 | "plugin_name": {
95 | "content": "$1",
96 | "example": "Awesome plugin"
97 | }
98 | }
99 | },
100 | "everyDay": {
101 | "message": "Tout les jours"
102 | },
103 | "every12hours": {
104 | "message": "Toutes les 12 heures"
105 | },
106 | "every6hours": {
107 | "message": "Toutes les 6 heures"
108 | },
109 | "updateExternalFrequency": {
110 | "message": "Vérifier les mises à jour des plugins externes"
111 | },
112 | "updateFrequency": {
113 | "message": "Mise à jour IITC-CE"
114 | },
115 | "updateNow": {
116 | "message": "Mettre à jour"
117 | },
118 | "changesApplied": {
119 | "message": "Les modifications ont été appliquées"
120 | },
121 | "needRebootIntel": {
122 | "message": "Les changements seront appliqués après le rechargement de l'Intel"
123 | },
124 | "addedUserScriptTo": {
125 | "message": "$PLUGIN_NAME$ a été ajouté à la catégorie \"$PLUGIN_CATEGORY$\".",
126 | "placeholders": {
127 | "plugin_name": {
128 | "content": "$1",
129 | "example": "Awesome plugin"
130 | },
131 | "plugin_category": {
132 | "content": "$2",
133 | "example": "Draw"
134 | }
135 | }
136 | },
137 | "badgeOverride": {
138 | "message": "passer outre"
139 | },
140 | "searchBoxPlaceholder": {
141 | "message": "Recherche…"
142 | },
143 | "customServerHint": {
144 | "message": "Par exemple :"
145 | },
146 | "customServerTooltipSuccess": {
147 | "message": "Connexion au serveur réussie"
148 | },
149 | "reinstall": {
150 | "message": "Réinstaller"
151 | }
152 | }
153 |
--------------------------------------------------------------------------------
/public/_locales/gl/messages.json:
--------------------------------------------------------------------------------
1 | {
2 | "release": {
3 | "message": "Lanzamento"
4 | },
5 | "choosingUpdateChannel": {
6 | "message": "Seleccionando dunha canle de actualización IITC-CE"
7 | },
8 | "updateNow": {
9 | "message": "actualizar agora"
10 | },
11 | "iitcButtonOptions": {
12 | "message": "Opcións do botón IITC-CE"
13 | },
14 | "iitcHomePage": {
15 | "message": "Páxina de inicio"
16 | },
17 | "addExternalPlugin": {
18 | "message": "Engade pluggin externo"
19 | },
20 | "noData": {
21 | "message": "Sen datos"
22 | },
23 | "changesApplied": {
24 | "message": "Aplicáronse cambios"
25 | },
26 | "needRebootIntel": {
27 | "message": "Os cambios aplicaranse despois de reiniciar Intel"
28 | },
29 | "titleDefault": {
30 | "message": "Abrir Intel",
31 | "description": "Title for the button at the application panel"
32 | },
33 | "extDescription": {
34 | "message": "Inicia IITC para Ingress Intel con facilidade.",
35 | "description": "Description of the extension"
36 | },
37 | "updateInProgress": {
38 | "message": "Actualización en curso…"
39 | },
40 | "lang": {
41 | "message": "gl"
42 | }
43 | }
44 |
--------------------------------------------------------------------------------
/public/_locales/he/messages.json:
--------------------------------------------------------------------------------
1 | {
2 | "updateFrequency": {
3 | "message": "בדיקת עדכונים של אייאייטיסי-סיאי"
4 | },
5 | "updateExternalFrequency": {
6 | "message": "בדיקת עדכונים של תוספים חיצוניים"
7 | },
8 | "beta": {
9 | "message": "בטא"
10 | },
11 | "release": {
12 | "message": "גרסא"
13 | },
14 | "choosingUpdateChannel": {
15 | "message": "בחירת ערוץ עדכונים של אייאייטיסי-סיאי"
16 | },
17 | "updateNow": {
18 | "message": "עדכן עכשיו"
19 | },
20 | "iitcButtonOptions": {
21 | "message": "אפשרויות כפתור אייאייטיסי-סיאי"
22 | },
23 | "iitcHomePage": {
24 | "message": "דף הבית"
25 | },
26 | "addExternalPlugin": {
27 | "message": "הוסף תוסף חיצוני"
28 | },
29 | "noData": {
30 | "message": "אין מידע"
31 | },
32 | "changesApplied": {
33 | "message": "השינויים הוחלו"
34 | },
35 | "updateInProgress": {
36 | "message": "עדכון בתהליך…"
37 | },
38 | "needRebootIntel": {
39 | "message": "השינויים יוחלו לאחר אתחול מחדש של אינטל"
40 | },
41 | "titleDefault": {
42 | "message": "פתח אינטל",
43 | "description": "Title for the button at the application panel"
44 | },
45 | "lang": {
46 | "message": "he"
47 | },
48 | "extDescription": {
49 | "message": "השק את אייאייטיסי לאינגרס אינטל בקלות.",
50 | "description": "Description of the extension"
51 | },
52 | "notValidUserScript": {
53 | "message": "$PLUGIN_NAME$ אינו יוזרסקריפט חוקי.",
54 | "placeholders": {
55 | "plugin_name": {
56 | "content": "$1",
57 | "example": "Awesome plugin"
58 | }
59 | }
60 | },
61 | "pluginDelete": {
62 | "message": "מחק"
63 | },
64 | "pluginSave": {
65 | "message": "שמור"
66 | },
67 | "openSupport": {
68 | "message": "פתח דף תמיכה:"
69 | },
70 | "badgeOverride": {
71 | "message": "לעקוף"
72 | },
73 | "anyChannel": {
74 | "message": "כול ערוץ"
75 | },
76 | "everyWeek": {
77 | "message": "כול שבוע"
78 | },
79 | "everyDay": {
80 | "message": "כול יום"
81 | },
82 | "every12hours": {
83 | "message": "כול 12 שעות"
84 | },
85 | "external": {
86 | "message": "חיצוני"
87 | },
88 | "serverNotAvailableRetry": {
89 | "message": "השרת אינו זמין. נסה שוב בעוד $NUM$ שניות",
90 | "placeholders": {
91 | "num": {
92 | "content": "$1",
93 | "example": "5"
94 | }
95 | }
96 | },
97 | "loading": {
98 | "message": "טוען…"
99 | },
100 | "install": {
101 | "message": "התקן"
102 | },
103 | "clickInstallPlugin": {
104 | "message": "זהו תוסף אייאייטיסי. לחץ על התקן כדי להתחיל להשתמש בו."
105 | },
106 | "willBeOverwrittenByNewPlugin": {
107 | "message": "תוסף עם אותו מזהה יוחלף על ידי התוסף החדש."
108 | },
109 | "dropJSHereOrClick": {
110 | "message": "זרוק לכאן קבצי .js או לחץ להעלאה."
111 | },
112 | "or": {
113 | "message": "או"
114 | },
115 | "errorReadingFile": {
116 | "message": "אירעה שגיאה בקריאת קובץ $PLUGIN_NAME$.",
117 | "placeholders": {
118 | "plugin_name": {
119 | "content": "$1",
120 | "example": "Awesome plugin"
121 | }
122 | }
123 | },
124 | "addressNotAvailable": {
125 | "message": "כתובת אינה זמינה"
126 | },
127 | "addedUserScriptTo": {
128 | "message": "$PLUGIN_NAME$ נוסף לקטגוריה \"$PLUGIN_CATEGORY$\".",
129 | "placeholders": {
130 | "plugin_name": {
131 | "content": "$1",
132 | "example": "Awesome plugin"
133 | },
134 | "plugin_category": {
135 | "content": "$2",
136 | "example": "Draw"
137 | }
138 | }
139 | }
140 | }
141 |
--------------------------------------------------------------------------------
/public/_locales/hu/messages.json:
--------------------------------------------------------------------------------
1 | {
2 | "notValidUserScript": {
3 | "message": "$PLUGIN_NAME$ nem érvényes UserScript.",
4 | "placeholders": {
5 | "plugin_name": {
6 | "content": "$1",
7 | "example": "Awesome plugin"
8 | }
9 | }
10 | },
11 | "external": {
12 | "message": "Külső"
13 | },
14 | "serverNotAvailableRetry": {
15 | "message": "A szerver nem elérhető. Újrapróbálkozás $NUM$ mp. múlva",
16 | "placeholders": {
17 | "num": {
18 | "content": "$1",
19 | "example": "5"
20 | }
21 | }
22 | },
23 | "loading": {
24 | "message": "Betöltés…"
25 | },
26 | "install": {
27 | "message": "Telepítés"
28 | },
29 | "or": {
30 | "message": "vagy"
31 | },
32 | "errorReadingFile": {
33 | "message": "Hiba történt a $PLUGIN_NAME$ fájl olvasása során.",
34 | "placeholders": {
35 | "plugin_name": {
36 | "content": "$1",
37 | "example": "Awesome plugin"
38 | }
39 | }
40 | },
41 | "addressNotAvailable": {
42 | "message": "Cím nem elérhető"
43 | },
44 | "pluginDelete": {
45 | "message": "Törlés"
46 | },
47 | "openSupport": {
48 | "message": "Támogatási oldal megnyitása:"
49 | },
50 | "pluginSave": {
51 | "message": "Mentés"
52 | },
53 | "everyWeek": {
54 | "message": "Hetente"
55 | },
56 | "everyDay": {
57 | "message": "Naponta"
58 | },
59 | "every12hours": {
60 | "message": "12 óránként"
61 | },
62 | "every6hours": {
63 | "message": "6 óránként"
64 | },
65 | "updateNow": {
66 | "message": "frissítés most"
67 | },
68 | "iitcHomePage": {
69 | "message": "Kezdőoldal"
70 | },
71 | "addExternalPlugin": {
72 | "message": "Bővítmény hozzáadása"
73 | },
74 | "updateInProgress": {
75 | "message": "Frissítés folyamatban…"
76 | },
77 | "addedUserScriptTo": {
78 | "message": "$PLUGIN_NAME$ hozzáadva a \"$PLUGIN_CATEGORY$\" kategóriába.",
79 | "placeholders": {
80 | "plugin_name": {
81 | "content": "$1",
82 | "example": "Awesome plugin"
83 | },
84 | "plugin_category": {
85 | "content": "$2",
86 | "example": "Draw"
87 | }
88 | }
89 | },
90 | "lang": {
91 | "message": "hu"
92 | }
93 | }
94 |
--------------------------------------------------------------------------------
/public/_locales/lzh/messages.json:
--------------------------------------------------------------------------------
1 | {}
2 |
--------------------------------------------------------------------------------
/public/_locales/mag/messages.json:
--------------------------------------------------------------------------------
1 | {}
2 |
--------------------------------------------------------------------------------
/public/_locales/nb_NO/messages.json:
--------------------------------------------------------------------------------
1 | {
2 | "lang": {
3 | "message": "nb_NO"
4 | }
5 | }
6 |
--------------------------------------------------------------------------------
/public/_locales/nl/messages.json:
--------------------------------------------------------------------------------
1 | {
2 | "extDescription": {
3 | "message": "Eenvoudig opstarten van IITC voor Ingress Intel.",
4 | "description": "Description of the extension"
5 | },
6 | "lang": {
7 | "message": "nl"
8 | },
9 | "external": {
10 | "message": "Extern"
11 | },
12 | "errorReadingFile": {
13 | "message": "Er is een fout opgetreden bij het lezen van het bestand $PLUGIN_NAME$.",
14 | "placeholders": {
15 | "plugin_name": {
16 | "content": "$1",
17 | "example": "Awesome plugin"
18 | }
19 | }
20 | },
21 | "addressNotAvailable": {
22 | "message": "Adres is niet beschikbaar"
23 | },
24 | "addedUserScriptTo": {
25 | "message": "$PLUGIN_NAME$ werd aan de $PLUGIN_CATEGORY$ categorie toegevoegd.",
26 | "placeholders": {
27 | "plugin_name": {
28 | "content": "$1",
29 | "example": "Awesome plugin"
30 | },
31 | "plugin_category": {
32 | "content": "$2",
33 | "example": "Draw"
34 | }
35 | }
36 | },
37 | "notValidUserScript": {
38 | "message": "$PLUGIN_NAME$ is geen geldig UserScript.",
39 | "placeholders": {
40 | "plugin_name": {
41 | "content": "$1",
42 | "example": "Awesome plugin"
43 | }
44 | }
45 | },
46 | "openSupport": {
47 | "message": "Hulppagina openen:"
48 | },
49 | "anyChannel": {
50 | "message": "Eender welk kanaal"
51 | },
52 | "updateExternalFrequency": {
53 | "message": "Externe plugins zoeken naar updates"
54 | },
55 | "updateFrequency": {
56 | "message": "IITC-CE zoekt naar updates"
57 | },
58 | "beta": {
59 | "message": "Beta"
60 | },
61 | "release": {
62 | "message": "Release"
63 | },
64 | "choosingUpdateChannel": {
65 | "message": "Selecteer een IITC-CE update kanaal"
66 | },
67 | "iitcHomePage": {
68 | "message": "Homepagina"
69 | },
70 | "addExternalPlugin": {
71 | "message": "Externe plugin toevoegen"
72 | },
73 | "noData": {
74 | "message": "Geen data"
75 | },
76 | "changesApplied": {
77 | "message": "Wijzigingen werden bewaard"
78 | },
79 | "updateInProgress": {
80 | "message": "Aan het updaten…"
81 | },
82 | "needRebootIntel": {
83 | "message": "Veranderingen worden bewaard na een herstart van Intel"
84 | },
85 | "titleDefault": {
86 | "message": "Intel openen",
87 | "description": "Title for the button at the application panel"
88 | },
89 | "iitcButtonOptions": {
90 | "message": "IITC-CE Knop opties"
91 | },
92 | "badgeOverride": {
93 | "message": "opheffen"
94 | },
95 | "dropJSHereOrClick": {
96 | "message": "Sleep hier .js bestanden of klik om te uploaden."
97 | },
98 | "loading": {
99 | "message": "Laden…"
100 | },
101 | "install": {
102 | "message": "Installeren"
103 | },
104 | "clickInstallPlugin": {
105 | "message": "Dit is een IITC plugin. Installeer om te gebruiken."
106 | },
107 | "willBeOverwrittenByNewPlugin": {
108 | "message": "Een plugin met hetzelfde ID zal overschreven worden door de nieuwe plugin."
109 | },
110 | "serverNotAvailableRetry": {
111 | "message": "De server is niet beschikbaar. Probeer opnieuw over $NUM$ seconden",
112 | "placeholders": {
113 | "num": {
114 | "content": "$1",
115 | "example": "5"
116 | }
117 | }
118 | },
119 | "or": {
120 | "message": "of"
121 | },
122 | "pluginDelete": {
123 | "message": "Verwijderen"
124 | },
125 | "pluginSave": {
126 | "message": "Bewaren"
127 | },
128 | "everyWeek": {
129 | "message": "Elke week"
130 | },
131 | "everyDay": {
132 | "message": "Elke dag"
133 | },
134 | "every12hours": {
135 | "message": "Iedere 12 uur"
136 | },
137 | "every6hours": {
138 | "message": "Iedere 6 uur"
139 | },
140 | "updateNow": {
141 | "message": "nu updaten"
142 | }
143 | }
144 |
--------------------------------------------------------------------------------
/public/_locales/pt-PT/messages.json:
--------------------------------------------------------------------------------
1 | {
2 | "external": {
3 | "message": "Externo"
4 | },
5 | "serverNotAvailableRetry": {
6 | "message": "O servidor não está disponível. Tente novamente depois de $NUM$ segundos",
7 | "placeholders": {
8 | "num": {
9 | "content": "$1",
10 | "example": "5"
11 | }
12 | }
13 | },
14 | "loading": {
15 | "message": "A carregar…"
16 | },
17 | "install": {
18 | "message": "Instalar"
19 | },
20 | "clickInstallPlugin": {
21 | "message": "Este é um plugin IITC. Clique em \"instalar\" para o começar a usar."
22 | },
23 | "willBeOverwrittenByNewPlugin": {
24 | "message": "O plugin com o mesmo ID será substituído pelo novo plugin."
25 | },
26 | "dropJSHereOrClick": {
27 | "message": "Solte os arquivos .js aqui ou clique em upload."
28 | },
29 | "or": {
30 | "message": "ou"
31 | },
32 | "errorReadingFile": {
33 | "message": "Ocorreu um erro ao ler o arquivo $PLUGIN_NAME$.",
34 | "placeholders": {
35 | "plugin_name": {
36 | "content": "$1",
37 | "example": "Awesome plugin"
38 | }
39 | }
40 | },
41 | "addressNotAvailable": {
42 | "message": "O endereço não está disponível"
43 | },
44 | "addedUserScriptTo": {
45 | "message": "$PLUGIN_NAME$ foi adicionado à categoria \"$PLUGIN_CATEGORY$\".",
46 | "placeholders": {
47 | "plugin_name": {
48 | "content": "$1",
49 | "example": "Awesome plugin"
50 | },
51 | "plugin_category": {
52 | "content": "$2",
53 | "example": "Draw"
54 | }
55 | }
56 | },
57 | "notValidUserScript": {
58 | "message": "$PLUGIN_NAME$ Não é um plugin válido.",
59 | "placeholders": {
60 | "plugin_name": {
61 | "content": "$1",
62 | "example": "Awesome plugin"
63 | }
64 | }
65 | },
66 | "pluginDelete": {
67 | "message": "Apagar"
68 | },
69 | "pluginSave": {
70 | "message": "Guardar"
71 | },
72 | "openSupport": {
73 | "message": "Abrir página de suporte:"
74 | },
75 | "badgeOverride": {
76 | "message": "substituir"
77 | },
78 | "anyChannel": {
79 | "message": "Qualquer canal"
80 | },
81 | "everyWeek": {
82 | "message": "Todas as Semanas"
83 | },
84 | "everyDay": {
85 | "message": "Todos os Dias"
86 | },
87 | "every12hours": {
88 | "message": "A cada 12 horas"
89 | },
90 | "every6hours": {
91 | "message": "A cada 6 horas"
92 | },
93 | "updateExternalFrequency": {
94 | "message": "Verificar atualizações dos plugins externos"
95 | },
96 | "updateFrequency": {
97 | "message": "Verificar atualizações do IITC-CE"
98 | },
99 | "beta": {
100 | "message": "Beta"
101 | },
102 | "release": {
103 | "message": "Lançamento"
104 | },
105 | "choosingUpdateChannel": {
106 | "message": "Escolher um canal de atualização para o IITC-CE"
107 | },
108 | "updateNow": {
109 | "message": "Atualizar agora"
110 | },
111 | "iitcButtonOptions": {
112 | "message": "Opções do Botão IITC-CE"
113 | },
114 | "iitcHomePage": {
115 | "message": "Página inicial"
116 | },
117 | "addExternalPlugin": {
118 | "message": "Adicionar plugin externo"
119 | },
120 | "noData": {
121 | "message": "Sem dados"
122 | },
123 | "changesApplied": {
124 | "message": "As alterações foram aplicadas"
125 | },
126 | "updateInProgress": {
127 | "message": "Atualização em progresso…"
128 | },
129 | "needRebootIntel": {
130 | "message": "As alterações serão aplicadas depois de reiniciar o Intel"
131 | },
132 | "titleDefault": {
133 | "message": "Abrir Intel",
134 | "description": "Title for the button at the application panel"
135 | },
136 | "lang": {
137 | "message": "pt_PT"
138 | },
139 | "extDescription": {
140 | "message": "Inicie o IITC para o mapa Ingress Intel com facilidade.",
141 | "description": "Description of the extension"
142 | }
143 | }
144 |
--------------------------------------------------------------------------------
/public/_locales/pt_PT/messages.json:
--------------------------------------------------------------------------------
1 | {
2 | "titleDefault": {
3 | "message": "Abrir Intel",
4 | "description": "Title for the button at the application panel"
5 | },
6 | "needRebootIntel": {
7 | "message": "As alterações serão aplicadas depois de reiniciar o Intel"
8 | },
9 | "updateInProgress": {
10 | "message": "Atualização em progresso…"
11 | },
12 | "changesApplied": {
13 | "message": "As alterações foram aplicadas"
14 | },
15 | "noData": {
16 | "message": "Sem dados"
17 | },
18 | "iitcHomePage": {
19 | "message": "Página inicial"
20 | },
21 | "iitcButtonOptions": {
22 | "message": "Opções do Botão IITC-CE"
23 | },
24 | "updateNow": {
25 | "message": "Atualizar agora"
26 | },
27 | "release": {
28 | "message": "Lançamento"
29 | },
30 | "updateFrequency": {
31 | "message": "Verificar atualizações do IITC-CE"
32 | },
33 | "updateExternalFrequency": {
34 | "message": "Verificar atualizações dos plugins externos"
35 | },
36 | "every6hours": {
37 | "message": "A cada 6 horas"
38 | },
39 | "every12hours": {
40 | "message": "A cada 12 horas"
41 | },
42 | "everyDay": {
43 | "message": "Diariamente"
44 | },
45 | "everyWeek": {
46 | "message": "Semanalmente"
47 | },
48 | "lang": {
49 | "message": "pt_PT"
50 | },
51 | "openSupport": {
52 | "message": "Abrir página de suporte:"
53 | },
54 | "pluginSave": {
55 | "message": "Guardar"
56 | },
57 | "pluginDelete": {
58 | "message": "Apagar"
59 | },
60 | "or": {
61 | "message": "ou"
62 | },
63 | "addressNotAvailable": {
64 | "message": "O endereço não está disponível"
65 | },
66 | "dropJSHereOrClick": {
67 | "message": "Solte os arquivos .js aqui ou clique em upload."
68 | },
69 | "clickInstallPlugin": {
70 | "message": "Este é um plugin IITC. Clique em \"instalar\" para o começar a usar."
71 | },
72 | "install": {
73 | "message": "Instalar"
74 | },
75 | "external": {
76 | "message": "Externo"
77 | },
78 | "errorReadingFile": {
79 | "message": "Ocorreu um erro ao ler o arquivo $PLUGIN_NAME$.",
80 | "placeholders": {
81 | "plugin_name": {
82 | "content": "$1",
83 | "example": "Awesome plugin"
84 | }
85 | }
86 | },
87 | "willBeOverwrittenByNewPlugin": {
88 | "message": "O plugin com o mesmo ID será substituído pelo novo plugin."
89 | },
90 | "loading": {
91 | "message": "A carregar…"
92 | },
93 | "serverNotAvailableRetry": {
94 | "message": "O servidor não está disponível. Tente novamente depois de $NUM$ segundos",
95 | "placeholders": {
96 | "num": {
97 | "content": "$1",
98 | "example": "5"
99 | }
100 | }
101 | },
102 | "notValidUserScript": {
103 | "message": "$PLUGIN_NAME$ não é um plugin válido.",
104 | "placeholders": {
105 | "plugin_name": {
106 | "content": "$1",
107 | "example": "Awesome plugin"
108 | }
109 | }
110 | },
111 | "extDescription": {
112 | "message": "Inicie o IITC para o mapa Ingress Intel com facilidade.",
113 | "description": "Description of the extension"
114 | },
115 | "addExternalPlugin": {
116 | "message": "Adicionar plugin externo"
117 | },
118 | "choosingUpdateChannel": {
119 | "message": "Escolher um canal de atualização para o IITC-CE"
120 | },
121 | "anyChannel": {
122 | "message": "Qualquer canal"
123 | },
124 | "addedUserScriptTo": {
125 | "message": "$PLUGIN_NAME$ foi adicionado à categoria \"$PLUGIN_CATEGORY$\".",
126 | "placeholders": {
127 | "plugin_name": {
128 | "content": "$1",
129 | "example": "Awesome plugin"
130 | },
131 | "plugin_category": {
132 | "content": "$2",
133 | "example": "Draw"
134 | }
135 | }
136 | },
137 | "badgeOverride": {
138 | "message": "substituir"
139 | },
140 | "beta": {
141 | "message": "Beta"
142 | }
143 | }
144 |
--------------------------------------------------------------------------------
/public/_locales/sl/messages.json:
--------------------------------------------------------------------------------
1 | {
2 | "updateInProgress": {
3 | "message": "Posodobitev v teku…"
4 | },
5 | "needRebootIntel": {
6 | "message": "Spremembe bodo uveljavljene po ponovnem zagonu Intela"
7 | },
8 | "titleDefault": {
9 | "message": "Odprite Intel",
10 | "description": "Title for the button at the application panel"
11 | },
12 | "lang": {
13 | "message": "sl"
14 | },
15 | "extDescription": {
16 | "message": "Zaženite IITC za Intel Ingress z lahkoto.",
17 | "description": "Description of the extension"
18 | },
19 | "beta": {
20 | "message": "Beta"
21 | },
22 | "release": {
23 | "message": "Izdati"
24 | },
25 | "choosingUpdateChannel": {
26 | "message": "Izbira kanala za posodobitev IITC-CE"
27 | },
28 | "updateNow": {
29 | "message": "posodobi zdaj"
30 | },
31 | "iitcButtonOptions": {
32 | "message": "Možnosti gumba IITC-CE"
33 | },
34 | "iitcHomePage": {
35 | "message": "Domača stran"
36 | },
37 | "addExternalPlugin": {
38 | "message": "Dodajte zunanji vtičnik"
39 | },
40 | "noData": {
41 | "message": "Ni podatkov"
42 | },
43 | "changesApplied": {
44 | "message": "Spremembe so bile uporabljene"
45 | },
46 | "addressNotAvailable": {
47 | "message": "Naslov ni na voljo"
48 | },
49 | "addedUserScriptTo": {
50 | "message": "$PLUGIN_NAME$ je bil dodan v kategorijo \"$PLUGIN_CATEGORY$\".",
51 | "placeholders": {
52 | "plugin_name": {
53 | "content": "$1",
54 | "example": "Awesome plugin"
55 | },
56 | "plugin_category": {
57 | "content": "$2",
58 | "example": "Draw"
59 | }
60 | }
61 | },
62 | "notValidUserScript": {
63 | "message": "$PLUGIN_NAME$ ni veljaven UserScript.",
64 | "placeholders": {
65 | "plugin_name": {
66 | "content": "$1",
67 | "example": "Awesome plugin"
68 | }
69 | }
70 | },
71 | "pluginDelete": {
72 | "message": "Izbriši"
73 | },
74 | "pluginSave": {
75 | "message": "Shrani"
76 | },
77 | "openSupport": {
78 | "message": "Odpri stran za podporo:"
79 | },
80 | "badgeOverride": {
81 | "message": "zavrnitev"
82 | },
83 | "anyChannel": {
84 | "message": "Kateri koli kanal"
85 | },
86 | "everyWeek": {
87 | "message": "Vsak teden"
88 | },
89 | "everyDay": {
90 | "message": "Vsak dan"
91 | },
92 | "every12hours": {
93 | "message": "Vsakih 12 ur"
94 | },
95 | "every6hours": {
96 | "message": "Vsakih 6 ur"
97 | },
98 | "updateExternalFrequency": {
99 | "message": "Zunanji vtičniki preverijo posodobitve"
100 | },
101 | "updateFrequency": {
102 | "message": "IITC-CE preverja posodobitve"
103 | },
104 | "external": {
105 | "message": "Zunanji"
106 | },
107 | "serverNotAvailableRetry": {
108 | "message": "Strežnik ni na voljo. Ponovno poskusi čez $NUM$ sekund",
109 | "placeholders": {
110 | "num": {
111 | "content": "$1",
112 | "example": "5"
113 | }
114 | }
115 | },
116 | "loading": {
117 | "message": "Nalaganje…"
118 | },
119 | "install": {
120 | "message": "Namestiti"
121 | },
122 | "clickInstallPlugin": {
123 | "message": "To je vtičnik IITC. Klikni \"namestiti\" gumb, da ga začneš uporabljati."
124 | },
125 | "willBeOverwrittenByNewPlugin": {
126 | "message": "Vtičnik z istim ID-jem bo novi vtičnik prepisal."
127 | },
128 | "dropJSHereOrClick": {
129 | "message": "Prenesi .js datoteko sem ali klikni za nalaganje."
130 | },
131 | "or": {
132 | "message": "ali"
133 | },
134 | "errorReadingFile": {
135 | "message": "Med branjem datoteke za $PLUGIN_NAME$ je prišlo do napake.",
136 | "placeholders": {
137 | "plugin_name": {
138 | "content": "$1",
139 | "example": "Awesome plugin"
140 | }
141 | }
142 | }
143 | }
144 |
--------------------------------------------------------------------------------
/public/_locales/sv/messages.json:
--------------------------------------------------------------------------------
1 | {
2 | "updateFrequency": {
3 | "message": "IITC-CE söker efter uppdateringar"
4 | },
5 | "updateNow": {
6 | "message": "uppdatera nu"
7 | },
8 | "iitcButtonOptions": {
9 | "message": "IITC-CE Knapp inställningar"
10 | },
11 | "noData": {
12 | "message": "Inga data"
13 | },
14 | "changesApplied": {
15 | "message": "Ändringar tillämpades"
16 | },
17 | "updateInProgress": {
18 | "message": "Uppdatering pågår…"
19 | },
20 | "needRebootIntel": {
21 | "message": "Ändringar kommer att tillämpas efter omstart av Intel"
22 | },
23 | "titleDefault": {
24 | "message": "Öppna Intel",
25 | "description": "Title for the button at the application panel"
26 | },
27 | "lang": {
28 | "message": "sv"
29 | },
30 | "beta": {
31 | "message": "Beta"
32 | },
33 | "extDescription": {
34 | "message": "Starta IITC för Ingress Intel enkelt.",
35 | "description": "Description of the extension"
36 | },
37 | "dropJSHereOrClick": {
38 | "message": "Släpp .js filer här eller klicka för att ladda upp."
39 | },
40 | "or": {
41 | "message": "eller"
42 | },
43 | "errorReadingFile": {
44 | "message": "Ett fel uppstod vid läsning av $PLUGIN_NAME$ filen.",
45 | "placeholders": {
46 | "plugin_name": {
47 | "content": "$1",
48 | "example": "Awesome plugin"
49 | }
50 | }
51 | },
52 | "addressNotAvailable": {
53 | "message": "Adressen är inte tillgänglig"
54 | },
55 | "pluginDelete": {
56 | "message": "Radera"
57 | },
58 | "pluginSave": {
59 | "message": "Spara"
60 | },
61 | "openSupport": {
62 | "message": "Öppna supportsida:"
63 | },
64 | "anyChannel": {
65 | "message": "Alla kanaler"
66 | },
67 | "everyWeek": {
68 | "message": "Varje vecka"
69 | },
70 | "everyDay": {
71 | "message": "Varje dag"
72 | },
73 | "updateExternalFrequency": {
74 | "message": "Externa plugins söker efter uppdateringar"
75 | },
76 | "external": {
77 | "message": "Extern"
78 | },
79 | "loading": {
80 | "message": "Laddar…"
81 | },
82 | "install": {
83 | "message": "Installera"
84 | },
85 | "notValidUserScript": {
86 | "message": "$PLUGIN_NAME$ är inte en giltig UserScript.",
87 | "placeholders": {
88 | "plugin_name": {
89 | "content": "$1",
90 | "example": "Awesome plugin"
91 | }
92 | }
93 | },
94 | "clickInstallPlugin": {
95 | "message": "Detta är en IITC plugin. Tryck installera för att börja använda den."
96 | },
97 | "every12hours": {
98 | "message": "Var 12:e timme"
99 | },
100 | "every6hours": {
101 | "message": "Var 6:e timme"
102 | },
103 | "addedUserScriptTo": {
104 | "message": "$PLUGIN_NAME$ har lagts till i kategorin \"$PLUGIN_CATEGORY$\".",
105 | "placeholders": {
106 | "plugin_name": {
107 | "content": "$1",
108 | "example": "Awesome plugin"
109 | },
110 | "plugin_category": {
111 | "content": "$2",
112 | "example": "Draw"
113 | }
114 | }
115 | },
116 | "serverNotAvailableRetry": {
117 | "message": "Servern är inte tillgänglig. Försök igen efter $NUM$ sekund(er)",
118 | "placeholders": {
119 | "num": {
120 | "content": "$1",
121 | "example": "5"
122 | }
123 | }
124 | },
125 | "willBeOverwrittenByNewPlugin": {
126 | "message": "Plugin med samma ID kommer skrivas över av det nya pluginet."
127 | },
128 | "iitcHomePage": {
129 | "message": "Startsida"
130 | },
131 | "choosingUpdateChannel": {
132 | "message": "Välj IITC-CE kanal för uppdateringar"
133 | },
134 | "badgeOverride": {
135 | "message": "Åsidosätt"
136 | },
137 | "release": {
138 | "message": "Stabil"
139 | },
140 | "addExternalPlugin": {
141 | "message": "Lägg till extern plugin"
142 | }
143 | }
144 |
--------------------------------------------------------------------------------
/public/_locales/uk/messages.json:
--------------------------------------------------------------------------------
1 | {
2 | "extDescription": {
3 | "message": "Запускай Ingress Intel с IITC в один клік."
4 | },
5 | "lang": {
6 | "message": "uk"
7 | },
8 | "titleDefault": {
9 | "message": "Відкрити Intel"
10 | },
11 | "install": {
12 | "message": "Встановити"
13 | },
14 | "or": {
15 | "message": "або"
16 | },
17 | "pluginDelete": {
18 | "message": "Видалити"
19 | },
20 | "pluginSave": {
21 | "message": "Зберегти"
22 | },
23 | "openSupport": {
24 | "message": "Відкрити сторінку підтримки:"
25 | },
26 | "everyWeek": {
27 | "message": "Кожен тиждень"
28 | },
29 | "everyDay": {
30 | "message": "Кожен день"
31 | },
32 | "every12hours": {
33 | "message": "Кожні 12 годин"
34 | },
35 | "every6hours": {
36 | "message": "Кожні 6 годин"
37 | },
38 | "updateNow": {
39 | "message": "Оновити зараз"
40 | },
41 | "iitcHomePage": {
42 | "message": "Домашня сторінка"
43 | },
44 | "noData": {
45 | "message": "Нема даних"
46 | },
47 | "changesApplied": {
48 | "message": "Зміни застосовані"
49 | },
50 | "updateInProgress": {
51 | "message": "Оновлення в процесі…"
52 | },
53 | "needRebootIntel": {
54 | "message": "Зміни буде застосовано після перезавантаження Intel"
55 | },
56 | "iitcButtonOptions": {
57 | "message": "Налаштування IITC-CE Button"
58 | },
59 | "notValidUserScript": {
60 | "message": "$PLUGIN_NAME$ не є дійсним UserScript.",
61 | "placeholders": {
62 | "plugin_name": {
63 | "content": "$1",
64 | "example": "Awesome plugin"
65 | }
66 | }
67 | },
68 | "errorReadingFile": {
69 | "message": "Під час читання $PLUGIN_NAME$ сталася помилка.",
70 | "placeholders": {
71 | "plugin_name": {
72 | "content": "$1",
73 | "example": "Awesome plugin"
74 | }
75 | }
76 | },
77 | "dropJSHereOrClick": {
78 | "message": "Перетягніть сюди .js файли або натисніть, щоб завантажити."
79 | },
80 | "willBeOverwrittenByNewPlugin": {
81 | "message": "При збігу ID плагін буде перезаписан новим."
82 | },
83 | "clickInstallPlugin": {
84 | "message": "Це плагін IITC. Натисни встановити щоб почати його використовувати."
85 | },
86 | "loading": {
87 | "message": "Завантаження…"
88 | },
89 | "addExternalPlugin": {
90 | "message": "Додати зовнішній плагін"
91 | },
92 | "choosingUpdateChannel": {
93 | "message": "Канал оновлень IITC-CE"
94 | },
95 | "release": {
96 | "message": "Реліз"
97 | },
98 | "updateFrequency": {
99 | "message": "IITC-CE перевіряє наявність оновлень"
100 | },
101 | "updateExternalFrequency": {
102 | "message": "Перевірка оновлень зовнішніх плагінів"
103 | },
104 | "anyChannel": {
105 | "message": "Будь-який канал"
106 | },
107 | "addressNotAvailable": {
108 | "message": "Недоступний"
109 | },
110 | "serverNotAvailableRetry": {
111 | "message": "Сервер не доступний. Повторна спроба через $NUM$ сек",
112 | "placeholders": {
113 | "num": {
114 | "content": "$1",
115 | "example": "5"
116 | }
117 | }
118 | },
119 | "external": {
120 | "message": "Зовнішні"
121 | },
122 | "addedUserScriptTo": {
123 | "message": "$PLUGIN_NAME$ додано до категорії \"$PLUGIN_CATEGORY$\".",
124 | "placeholders": {
125 | "plugin_name": {
126 | "content": "$1",
127 | "example": "Awesome plugin"
128 | },
129 | "plugin_category": {
130 | "content": "$2",
131 | "example": "Draw"
132 | }
133 | }
134 | },
135 | "badgeOverride": {
136 | "message": "замінити"
137 | },
138 | "beta": {
139 | "message": "Бета"
140 | }
141 | }
142 |
--------------------------------------------------------------------------------
/public/assets/iconfont/MaterialIcons-Regular.woff2:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/IITC-CE/IITC-Button/295a2bc1ffe80df6bafe68b161851906fa3e9308/public/assets/iconfont/MaterialIcons-Regular.woff2
--------------------------------------------------------------------------------
/public/assets/iconfont/material-icons.css:
--------------------------------------------------------------------------------
1 | /* MaterialIcons; Apache License 2.0 */
2 | /* https://github.com/google/material-design-icons/issues/786#issuecomment-487055009 */
3 |
4 | @font-face {
5 | font-family: 'Material Icons';
6 | font-style: normal;
7 | font-weight: 400;
8 | src: url(MaterialIcons-Regular.woff2) format('woff2');
9 | }
10 |
11 | .material-icons {
12 | font-family: 'Material Icons';
13 | font-weight: normal;
14 | font-style: normal;
15 | font-size: 24px; /* Preferred icon size */
16 | display: inline-block;
17 | line-height: 1;
18 | text-transform: none;
19 | letter-spacing: normal;
20 | word-wrap: normal;
21 | white-space: nowrap;
22 | direction: ltr;
23 |
24 | /* Support for all WebKit browsers. */
25 | -webkit-font-smoothing: antialiased;
26 | /* Support for Safari and Chrome. */
27 | text-rendering: optimizeLegibility;
28 |
29 | /* Support for Firefox. */
30 | -moz-osx-font-smoothing: grayscale;
31 |
32 | /* Support for IE. */
33 | font-feature-settings: 'liga';
34 | }
35 |
--------------------------------------------------------------------------------
/public/assets/icons/128/icon-beta.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/IITC-CE/IITC-Button/295a2bc1ffe80df6bafe68b161851906fa3e9308/public/assets/icons/128/icon-beta.png
--------------------------------------------------------------------------------
/public/assets/icons/128/icon.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/IITC-CE/IITC-Button/295a2bc1ffe80df6bafe68b161851906fa3e9308/public/assets/icons/128/icon.png
--------------------------------------------------------------------------------
/public/assets/icons/24/userscript-no-icon.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/IITC-CE/IITC-Button/295a2bc1ffe80df6bafe68b161851906fa3e9308/public/assets/icons/24/userscript-no-icon.png
--------------------------------------------------------------------------------
/public/assets/icons/48/icon-beta.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/IITC-CE/IITC-Button/295a2bc1ffe80df6bafe68b161851906fa3e9308/public/assets/icons/48/icon-beta.png
--------------------------------------------------------------------------------
/public/assets/icons/48/icon.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/IITC-CE/IITC-Button/295a2bc1ffe80df6bafe68b161851906fa3e9308/public/assets/icons/48/icon.png
--------------------------------------------------------------------------------
/public/assets/icons/96/icon-beta.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/IITC-CE/IITC-Button/295a2bc1ffe80df6bafe68b161851906fa3e9308/public/assets/icons/96/icon-beta.png
--------------------------------------------------------------------------------
/public/assets/icons/96/icon.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/IITC-CE/IITC-Button/295a2bc1ffe80df6bafe68b161851906fa3e9308/public/assets/icons/96/icon.png
--------------------------------------------------------------------------------
/public/assets/icons/extension.svg:
--------------------------------------------------------------------------------
1 |
--------------------------------------------------------------------------------
/public/assets/icons/favicon.ico:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/IITC-CE/IITC-Button/295a2bc1ffe80df6bafe68b161851906fa3e9308/public/assets/icons/favicon.ico
--------------------------------------------------------------------------------
/public/assets/images/IITC-black-horizontally.webp:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/IITC-CE/IITC-Button/295a2bc1ffe80df6bafe68b161851906fa3e9308/public/assets/images/IITC-black-horizontally.webp
--------------------------------------------------------------------------------
/public/assets/noto/NotoSansMono-Regular.woff2:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/IITC-CE/IITC-Button/295a2bc1ffe80df6bafe68b161851906fa3e9308/public/assets/noto/NotoSansMono-Regular.woff2
--------------------------------------------------------------------------------
/public/assets/noto/noto-font.css:
--------------------------------------------------------------------------------
1 | @font-face {
2 | font-family: 'Noto Sans Mono';
3 | font-style: normal;
4 | font-weight: 400;
5 | src: local('Noto Sans Mono'),
6 | local('NotoSansMono-Regular'),
7 | url(NotoSansMono-Regular.woff2) format('woff2');
8 | }
9 |
--------------------------------------------------------------------------------
/public/assets/roboto/Roboto-Regular.woff2:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/IITC-CE/IITC-Button/295a2bc1ffe80df6bafe68b161851906fa3e9308/public/assets/roboto/Roboto-Regular.woff2
--------------------------------------------------------------------------------
/public/assets/roboto/roboto-font.css:
--------------------------------------------------------------------------------
1 | @font-face {
2 | font-family: 'Roboto';
3 | font-style: normal;
4 | font-weight: 400;
5 | src: local('Roboto'),
6 | local('Roboto-Regular'),
7 | url(Roboto-Regular.woff2) format('woff2');
8 | }
9 |
10 | body, input, select {
11 | font-family: "Roboto", system-ui;
12 | }
13 |
--------------------------------------------------------------------------------
/public/browser-extension.html:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 |
7 |
8 | <%= htmlWebpackPlugin.options.title %>
9 |
10 |
11 |
12 |
13 |
14 |
--------------------------------------------------------------------------------
/public/index.html:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 |
7 |
8 | <%= htmlWebpackPlugin.options.title %>
9 |
10 |
11 |
14 |
15 |
16 |
17 |
18 |
--------------------------------------------------------------------------------
/safari/IITC Button.xcodeproj/project.xcworkspace/contents.xcworkspacedata:
--------------------------------------------------------------------------------
1 |
2 |
4 |
6 |
7 |
8 |
--------------------------------------------------------------------------------
/safari/IITC Button.xcodeproj/project.xcworkspace/xcshareddata/IDEWorkspaceChecks.plist:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 | IDEDidComputeMac32BitWarning
6 |
7 |
8 |
9 |
--------------------------------------------------------------------------------
/safari/IITC Button.xcodeproj/xcshareddata/xcschemes/iOS.xcscheme:
--------------------------------------------------------------------------------
1 |
2 |
5 |
8 |
9 |
15 |
21 |
22 |
23 |
24 |
25 |
30 |
31 |
32 |
33 |
43 |
45 |
51 |
52 |
53 |
54 |
60 |
62 |
68 |
69 |
70 |
71 |
73 |
74 |
77 |
78 |
79 |
--------------------------------------------------------------------------------
/safari/IITC Button.xcodeproj/xcshareddata/xcschemes/macOS.xcscheme:
--------------------------------------------------------------------------------
1 |
2 |
5 |
8 |
9 |
15 |
21 |
22 |
23 |
24 |
25 |
30 |
31 |
32 |
33 |
43 |
45 |
51 |
52 |
53 |
54 |
60 |
62 |
68 |
69 |
70 |
71 |
73 |
74 |
77 |
78 |
79 |
--------------------------------------------------------------------------------
/safari/Safari Extension/Shared/SafariWebExtensionHandler.swift:
--------------------------------------------------------------------------------
1 | //
2 | // SafariWebExtensionHandler.swift
3 | // Safari Extension macOS
4 | //
5 | // Created by Lucka on 3/10/2021.
6 | //
7 |
8 | import SafariServices
9 | import os.log
10 |
11 | #if os(macOS)
12 | let SFExtensionMessageKey = "message"
13 | #endif
14 |
15 | class SafariWebExtensionHandler: NSObject, NSExtensionRequestHandling {
16 |
17 | func beginRequest(with context: NSExtensionContext) {
18 | let item = context.inputItems[0] as! NSExtensionItem
19 | let message = item.userInfo?[SFExtensionMessageKey]
20 | os_log(.default, "Received message from browser.runtime.sendNativeMessage: %@", message as! CVarArg)
21 |
22 | let response = NSExtensionItem()
23 | response.userInfo = [ SFExtensionMessageKey: [ "Response to": message ] ]
24 |
25 | context.completeRequest(returningItems: [response], completionHandler: nil)
26 | }
27 |
28 | }
29 |
--------------------------------------------------------------------------------
/safari/Safari Extension/iOS/Info.plist:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 | NSExtension
6 |
7 | NSExtensionPointIdentifier
8 | com.apple.Safari.web-extension
9 | NSExtensionPrincipalClass
10 | $(PRODUCT_MODULE_NAME).SafariWebExtensionHandler
11 |
12 |
13 |
14 |
--------------------------------------------------------------------------------
/safari/Safari Extension/macOS/Info.plist:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 | NSExtension
6 |
7 | NSExtensionPointIdentifier
8 | com.apple.Safari.web-extension
9 | NSExtensionPrincipalClass
10 | $(PRODUCT_MODULE_NAME).SafariWebExtensionHandler
11 |
12 |
13 |
14 |
--------------------------------------------------------------------------------
/safari/Safari Extension/macOS/Safari Extension.entitlements:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 | com.apple.security.app-sandbox
6 |
7 | com.apple.security.files.user-selected.read-only
8 |
9 |
10 |
11 |
--------------------------------------------------------------------------------
/safari/Scripts/pre-build.sh:
--------------------------------------------------------------------------------
1 | #!/bin/sh
2 |
3 | # pre-build.sh
4 | # IITC-Button
5 | #
6 | # Created by Lucka on 6/10/2021.
7 | #
8 |
9 | cd "${PROJECT_DIR}"
10 |
11 | basePath=$(dirname "$0")
12 | PACKAGE_VERSION=$(sed -n 's/^.*version": "\(.*\)",$/\1/p' $basePath/../../package.json)
13 |
14 | GIT_COMMIT_COUNT=$(git rev-list --count HEAD || echo '1')
15 |
16 | INFO_PLIST_PREPROCESS_FILE="Shared/info-plist-preprocessor.h"
17 |
18 | echo "//---------------------------------------------------------------" > $INFO_PLIST_PREPROCESS_FILE
19 | echo "// Automatically generated by pre-build.sh. Do NOT edit manually." >> $INFO_PLIST_PREPROCESS_FILE
20 | echo "//---------------------------------------------------------------" >> $INFO_PLIST_PREPROCESS_FILE
21 | echo "" >> $INFO_PLIST_PREPROCESS_FILE
22 | echo "#define PACKAGE_VERSION ${PACKAGE_VERSION}" >> $INFO_PLIST_PREPROCESS_FILE
23 | echo "#define GIT_COMMIT_COUNT ${GIT_COMMIT_COUNT}" >> $INFO_PLIST_PREPROCESS_FILE
24 |
--------------------------------------------------------------------------------
/safari/Shared/Assets.xcassets/AccentColor.colorset/Contents.json:
--------------------------------------------------------------------------------
1 | {
2 | "colors" : [
3 | {
4 | "color" : {
5 | "color-space" : "srgb",
6 | "components" : {
7 | "alpha" : "1.000",
8 | "blue" : "1.000",
9 | "green" : "0.200",
10 | "red" : "0.547"
11 | }
12 | },
13 | "idiom" : "universal"
14 | },
15 | {
16 | "appearances" : [
17 | {
18 | "appearance" : "luminosity",
19 | "value" : "dark"
20 | }
21 | ],
22 | "color" : {
23 | "color-space" : "srgb",
24 | "components" : {
25 | "alpha" : "1.000",
26 | "blue" : "1.000",
27 | "green" : "0.000",
28 | "red" : "0.600"
29 | }
30 | },
31 | "idiom" : "universal"
32 | }
33 | ],
34 | "info" : {
35 | "author" : "xcode",
36 | "version" : 1
37 | }
38 | }
39 |
--------------------------------------------------------------------------------
/safari/Shared/Assets.xcassets/AppIcon.appiconset/Contents.json:
--------------------------------------------------------------------------------
1 | {
2 | "images" : [
3 | {
4 | "filename" : "iOS_iPhoneNotifications_20@2x.png",
5 | "idiom" : "iphone",
6 | "scale" : "2x",
7 | "size" : "20x20"
8 | },
9 | {
10 | "filename" : "iOS_iPhoneNotifications_20@3x.png",
11 | "idiom" : "iphone",
12 | "scale" : "3x",
13 | "size" : "20x20"
14 | },
15 | {
16 | "filename" : "iOS_iPhoneSettings_29@2x.png",
17 | "idiom" : "iphone",
18 | "scale" : "2x",
19 | "size" : "29x29"
20 | },
21 | {
22 | "filename" : "iOS_iPhoneSettings_29@3x.png",
23 | "idiom" : "iphone",
24 | "scale" : "3x",
25 | "size" : "29x29"
26 | },
27 | {
28 | "filename" : "iOS_iPhoneSpotlight_40@2x.png",
29 | "idiom" : "iphone",
30 | "scale" : "2x",
31 | "size" : "40x40"
32 | },
33 | {
34 | "filename" : "iOS_iPhoneSpotlight_40@3x.png",
35 | "idiom" : "iphone",
36 | "scale" : "3x",
37 | "size" : "40x40"
38 | },
39 | {
40 | "filename" : "iOS_iPhoneApp_60@2x.png",
41 | "idiom" : "iphone",
42 | "scale" : "2x",
43 | "size" : "60x60"
44 | },
45 | {
46 | "filename" : "iOS_iPhoneApp_60@3x.png",
47 | "idiom" : "iphone",
48 | "scale" : "3x",
49 | "size" : "60x60"
50 | },
51 | {
52 | "filename" : "iOS_iPadNotifications_20.png",
53 | "idiom" : "ipad",
54 | "scale" : "1x",
55 | "size" : "20x20"
56 | },
57 | {
58 | "filename" : "iOS_iPadNotifications_20@2x.png",
59 | "idiom" : "ipad",
60 | "scale" : "2x",
61 | "size" : "20x20"
62 | },
63 | {
64 | "filename" : "iOS_iPadSettings_29.png",
65 | "idiom" : "ipad",
66 | "scale" : "1x",
67 | "size" : "29x29"
68 | },
69 | {
70 | "filename" : "iOS_iPadSettings_29@2x.png",
71 | "idiom" : "ipad",
72 | "scale" : "2x",
73 | "size" : "29x29"
74 | },
75 | {
76 | "filename" : "iOS_iPadSpotlight_40.png",
77 | "idiom" : "ipad",
78 | "scale" : "1x",
79 | "size" : "40x40"
80 | },
81 | {
82 | "filename" : "iOS_iPadSpotlight_40@2x.png",
83 | "idiom" : "ipad",
84 | "scale" : "2x",
85 | "size" : "40x40"
86 | },
87 | {
88 | "filename" : "iOS_iPadApp_76.png",
89 | "idiom" : "ipad",
90 | "scale" : "1x",
91 | "size" : "76x76"
92 | },
93 | {
94 | "filename" : "iOS_iPadApp_76@2x.png",
95 | "idiom" : "ipad",
96 | "scale" : "2x",
97 | "size" : "76x76"
98 | },
99 | {
100 | "filename" : "iOS_iPadProApp_83.5@2x.png",
101 | "idiom" : "ipad",
102 | "scale" : "2x",
103 | "size" : "83.5x83.5"
104 | },
105 | {
106 | "filename" : "iOS_AppStore_1024.png",
107 | "idiom" : "ios-marketing",
108 | "scale" : "1x",
109 | "size" : "1024x1024"
110 | },
111 | {
112 | "filename" : "macOS_16.png",
113 | "idiom" : "mac",
114 | "scale" : "1x",
115 | "size" : "16x16"
116 | },
117 | {
118 | "filename" : "macOS_16@2x.png",
119 | "idiom" : "mac",
120 | "scale" : "2x",
121 | "size" : "16x16"
122 | },
123 | {
124 | "filename" : "macOS_32.png",
125 | "idiom" : "mac",
126 | "scale" : "1x",
127 | "size" : "32x32"
128 | },
129 | {
130 | "filename" : "macOS_32@2x.png",
131 | "idiom" : "mac",
132 | "scale" : "2x",
133 | "size" : "32x32"
134 | },
135 | {
136 | "filename" : "macOS_128.png",
137 | "idiom" : "mac",
138 | "scale" : "1x",
139 | "size" : "128x128"
140 | },
141 | {
142 | "filename" : "macOS_128@2x.png",
143 | "idiom" : "mac",
144 | "scale" : "2x",
145 | "size" : "128x128"
146 | },
147 | {
148 | "filename" : "macOS_256.png",
149 | "idiom" : "mac",
150 | "scale" : "1x",
151 | "size" : "256x256"
152 | },
153 | {
154 | "filename" : "macOS_256@2x.png",
155 | "idiom" : "mac",
156 | "scale" : "2x",
157 | "size" : "256x256"
158 | },
159 | {
160 | "filename" : "macOS_512.png",
161 | "idiom" : "mac",
162 | "scale" : "1x",
163 | "size" : "512x512"
164 | },
165 | {
166 | "filename" : "macOS_512@2x.png",
167 | "idiom" : "mac",
168 | "scale" : "2x",
169 | "size" : "512x512"
170 | }
171 | ],
172 | "info" : {
173 | "author" : "xcode",
174 | "version" : 1
175 | }
176 | }
177 |
--------------------------------------------------------------------------------
/safari/Shared/Assets.xcassets/AppIcon.appiconset/iOS_AppStore_1024.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/IITC-CE/IITC-Button/295a2bc1ffe80df6bafe68b161851906fa3e9308/safari/Shared/Assets.xcassets/AppIcon.appiconset/iOS_AppStore_1024.png
--------------------------------------------------------------------------------
/safari/Shared/Assets.xcassets/AppIcon.appiconset/iOS_iPadApp_76.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/IITC-CE/IITC-Button/295a2bc1ffe80df6bafe68b161851906fa3e9308/safari/Shared/Assets.xcassets/AppIcon.appiconset/iOS_iPadApp_76.png
--------------------------------------------------------------------------------
/safari/Shared/Assets.xcassets/AppIcon.appiconset/iOS_iPadApp_76@2x.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/IITC-CE/IITC-Button/295a2bc1ffe80df6bafe68b161851906fa3e9308/safari/Shared/Assets.xcassets/AppIcon.appiconset/iOS_iPadApp_76@2x.png
--------------------------------------------------------------------------------
/safari/Shared/Assets.xcassets/AppIcon.appiconset/iOS_iPadNotifications_20.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/IITC-CE/IITC-Button/295a2bc1ffe80df6bafe68b161851906fa3e9308/safari/Shared/Assets.xcassets/AppIcon.appiconset/iOS_iPadNotifications_20.png
--------------------------------------------------------------------------------
/safari/Shared/Assets.xcassets/AppIcon.appiconset/iOS_iPadNotifications_20@2x.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/IITC-CE/IITC-Button/295a2bc1ffe80df6bafe68b161851906fa3e9308/safari/Shared/Assets.xcassets/AppIcon.appiconset/iOS_iPadNotifications_20@2x.png
--------------------------------------------------------------------------------
/safari/Shared/Assets.xcassets/AppIcon.appiconset/iOS_iPadProApp_83.5@2x.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/IITC-CE/IITC-Button/295a2bc1ffe80df6bafe68b161851906fa3e9308/safari/Shared/Assets.xcassets/AppIcon.appiconset/iOS_iPadProApp_83.5@2x.png
--------------------------------------------------------------------------------
/safari/Shared/Assets.xcassets/AppIcon.appiconset/iOS_iPadSettings_29.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/IITC-CE/IITC-Button/295a2bc1ffe80df6bafe68b161851906fa3e9308/safari/Shared/Assets.xcassets/AppIcon.appiconset/iOS_iPadSettings_29.png
--------------------------------------------------------------------------------
/safari/Shared/Assets.xcassets/AppIcon.appiconset/iOS_iPadSettings_29@2x.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/IITC-CE/IITC-Button/295a2bc1ffe80df6bafe68b161851906fa3e9308/safari/Shared/Assets.xcassets/AppIcon.appiconset/iOS_iPadSettings_29@2x.png
--------------------------------------------------------------------------------
/safari/Shared/Assets.xcassets/AppIcon.appiconset/iOS_iPadSpotlight_40.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/IITC-CE/IITC-Button/295a2bc1ffe80df6bafe68b161851906fa3e9308/safari/Shared/Assets.xcassets/AppIcon.appiconset/iOS_iPadSpotlight_40.png
--------------------------------------------------------------------------------
/safari/Shared/Assets.xcassets/AppIcon.appiconset/iOS_iPadSpotlight_40@2x.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/IITC-CE/IITC-Button/295a2bc1ffe80df6bafe68b161851906fa3e9308/safari/Shared/Assets.xcassets/AppIcon.appiconset/iOS_iPadSpotlight_40@2x.png
--------------------------------------------------------------------------------
/safari/Shared/Assets.xcassets/AppIcon.appiconset/iOS_iPhoneApp_60@2x.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/IITC-CE/IITC-Button/295a2bc1ffe80df6bafe68b161851906fa3e9308/safari/Shared/Assets.xcassets/AppIcon.appiconset/iOS_iPhoneApp_60@2x.png
--------------------------------------------------------------------------------
/safari/Shared/Assets.xcassets/AppIcon.appiconset/iOS_iPhoneApp_60@3x.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/IITC-CE/IITC-Button/295a2bc1ffe80df6bafe68b161851906fa3e9308/safari/Shared/Assets.xcassets/AppIcon.appiconset/iOS_iPhoneApp_60@3x.png
--------------------------------------------------------------------------------
/safari/Shared/Assets.xcassets/AppIcon.appiconset/iOS_iPhoneNotifications_20@2x.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/IITC-CE/IITC-Button/295a2bc1ffe80df6bafe68b161851906fa3e9308/safari/Shared/Assets.xcassets/AppIcon.appiconset/iOS_iPhoneNotifications_20@2x.png
--------------------------------------------------------------------------------
/safari/Shared/Assets.xcassets/AppIcon.appiconset/iOS_iPhoneNotifications_20@3x.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/IITC-CE/IITC-Button/295a2bc1ffe80df6bafe68b161851906fa3e9308/safari/Shared/Assets.xcassets/AppIcon.appiconset/iOS_iPhoneNotifications_20@3x.png
--------------------------------------------------------------------------------
/safari/Shared/Assets.xcassets/AppIcon.appiconset/iOS_iPhoneSettings_29@2x.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/IITC-CE/IITC-Button/295a2bc1ffe80df6bafe68b161851906fa3e9308/safari/Shared/Assets.xcassets/AppIcon.appiconset/iOS_iPhoneSettings_29@2x.png
--------------------------------------------------------------------------------
/safari/Shared/Assets.xcassets/AppIcon.appiconset/iOS_iPhoneSettings_29@3x.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/IITC-CE/IITC-Button/295a2bc1ffe80df6bafe68b161851906fa3e9308/safari/Shared/Assets.xcassets/AppIcon.appiconset/iOS_iPhoneSettings_29@3x.png
--------------------------------------------------------------------------------
/safari/Shared/Assets.xcassets/AppIcon.appiconset/iOS_iPhoneSpotlight_40@2x.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/IITC-CE/IITC-Button/295a2bc1ffe80df6bafe68b161851906fa3e9308/safari/Shared/Assets.xcassets/AppIcon.appiconset/iOS_iPhoneSpotlight_40@2x.png
--------------------------------------------------------------------------------
/safari/Shared/Assets.xcassets/AppIcon.appiconset/iOS_iPhoneSpotlight_40@3x.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/IITC-CE/IITC-Button/295a2bc1ffe80df6bafe68b161851906fa3e9308/safari/Shared/Assets.xcassets/AppIcon.appiconset/iOS_iPhoneSpotlight_40@3x.png
--------------------------------------------------------------------------------
/safari/Shared/Assets.xcassets/AppIcon.appiconset/macOS_128.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/IITC-CE/IITC-Button/295a2bc1ffe80df6bafe68b161851906fa3e9308/safari/Shared/Assets.xcassets/AppIcon.appiconset/macOS_128.png
--------------------------------------------------------------------------------
/safari/Shared/Assets.xcassets/AppIcon.appiconset/macOS_128@2x.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/IITC-CE/IITC-Button/295a2bc1ffe80df6bafe68b161851906fa3e9308/safari/Shared/Assets.xcassets/AppIcon.appiconset/macOS_128@2x.png
--------------------------------------------------------------------------------
/safari/Shared/Assets.xcassets/AppIcon.appiconset/macOS_16.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/IITC-CE/IITC-Button/295a2bc1ffe80df6bafe68b161851906fa3e9308/safari/Shared/Assets.xcassets/AppIcon.appiconset/macOS_16.png
--------------------------------------------------------------------------------
/safari/Shared/Assets.xcassets/AppIcon.appiconset/macOS_16@2x.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/IITC-CE/IITC-Button/295a2bc1ffe80df6bafe68b161851906fa3e9308/safari/Shared/Assets.xcassets/AppIcon.appiconset/macOS_16@2x.png
--------------------------------------------------------------------------------
/safari/Shared/Assets.xcassets/AppIcon.appiconset/macOS_256.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/IITC-CE/IITC-Button/295a2bc1ffe80df6bafe68b161851906fa3e9308/safari/Shared/Assets.xcassets/AppIcon.appiconset/macOS_256.png
--------------------------------------------------------------------------------
/safari/Shared/Assets.xcassets/AppIcon.appiconset/macOS_256@2x.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/IITC-CE/IITC-Button/295a2bc1ffe80df6bafe68b161851906fa3e9308/safari/Shared/Assets.xcassets/AppIcon.appiconset/macOS_256@2x.png
--------------------------------------------------------------------------------
/safari/Shared/Assets.xcassets/AppIcon.appiconset/macOS_32.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/IITC-CE/IITC-Button/295a2bc1ffe80df6bafe68b161851906fa3e9308/safari/Shared/Assets.xcassets/AppIcon.appiconset/macOS_32.png
--------------------------------------------------------------------------------
/safari/Shared/Assets.xcassets/AppIcon.appiconset/macOS_32@2x.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/IITC-CE/IITC-Button/295a2bc1ffe80df6bafe68b161851906fa3e9308/safari/Shared/Assets.xcassets/AppIcon.appiconset/macOS_32@2x.png
--------------------------------------------------------------------------------
/safari/Shared/Assets.xcassets/AppIcon.appiconset/macOS_512.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/IITC-CE/IITC-Button/295a2bc1ffe80df6bafe68b161851906fa3e9308/safari/Shared/Assets.xcassets/AppIcon.appiconset/macOS_512.png
--------------------------------------------------------------------------------
/safari/Shared/Assets.xcassets/AppIcon.appiconset/macOS_512@2x.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/IITC-CE/IITC-Button/295a2bc1ffe80df6bafe68b161851906fa3e9308/safari/Shared/Assets.xcassets/AppIcon.appiconset/macOS_512@2x.png
--------------------------------------------------------------------------------
/safari/Shared/Assets.xcassets/Contents.json:
--------------------------------------------------------------------------------
1 | {
2 | "info" : {
3 | "author" : "xcode",
4 | "version" : 1
5 | }
6 | }
7 |
--------------------------------------------------------------------------------
/safari/Shared/IITCButtonApp.swift:
--------------------------------------------------------------------------------
1 | //
2 | // IITCButtonApp.swift
3 | // Shared
4 | //
5 | // Created by Lucka on 3/10/2021.
6 | //
7 |
8 | import SwiftUI
9 |
10 | @main
11 | struct IITCButtonApp: App {
12 | var body: some Scene {
13 | WindowGroup {
14 | ContentView()
15 | }
16 | .commands {
17 | #if os(macOS)
18 | IITCButtonCommands()
19 | #endif
20 | }
21 | }
22 | }
23 |
--------------------------------------------------------------------------------
/safari/iOS/Info.plist:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 | CFBundleExecutable
6 | $(EXECUTABLE_NAME)
7 | CFBundleShortVersionString
8 | PACKAGE_VERSION
9 | CFBundleDevelopmentRegion
10 | $(DEVELOPMENT_LANGUAGE)
11 | UILaunchScreen
12 |
13 | UILaunchScreen
14 |
15 |
16 | CFBundlePackageType
17 | $(PRODUCT_BUNDLE_PACKAGE_TYPE)
18 | UISupportedInterfaceOrientations
19 |
20 | UIInterfaceOrientationPortrait
21 | UIInterfaceOrientationLandscapeLeft
22 | UIInterfaceOrientationLandscapeRight
23 | UIInterfaceOrientationPortraitUpsideDown
24 |
25 | UIApplicationSceneManifest - 2
26 |
27 | UIApplicationSupportsMultipleScenes
28 |
29 |
30 | LSRequiresIPhoneOS
31 |
32 | CFBundleIdentifier
33 | $(PRODUCT_BUNDLE_IDENTIFIER)
34 | CFBundleVersion
35 | GIT_COMMIT_COUNT
36 | CFBundleInfoDictionaryVersion
37 | 6.0
38 | CFBundleName
39 | $(PRODUCT_NAME)
40 | UIApplicationSupportsIndirectInputEvents
41 |
42 | UIApplicationSceneManifest
43 |
44 | UIApplicationSupportsMultipleScenes
45 |
46 |
47 |
48 |
49 |
--------------------------------------------------------------------------------
/safari/iOS/Views/ContentView.swift:
--------------------------------------------------------------------------------
1 | //
2 | // ContentView.swift
3 | // iOS
4 | //
5 | // Created by Lucka on 6/10/2021.
6 | //
7 |
8 | import SwiftUI
9 |
10 | struct ContentView: View {
11 |
12 | @State private var presentingHelpSheet = false
13 |
14 | var body: some View {
15 | NavigationView {
16 | List {
17 | Button(action: { presentingHelpSheet.toggle() }) {
18 | Label("How to use", systemImage: "questionmark")
19 | }
20 | Link("Open Intel Maps", systemImage: "target", destination: .init(string: "https://intel.ingress.com")!)
21 |
22 | Section("About") {
23 | about
24 | }
25 | }
26 | .navigationTitle("IITC Button")
27 | }
28 | .navigationViewStyle(.stack)
29 | .sheet(isPresented: $presentingHelpSheet) {
30 | Helper()
31 | }
32 | }
33 |
34 | @ViewBuilder
35 | private var about: some View {
36 | Link("Homepage", systemImage: "house", destination: .init(string: "https://iitc.app")!)
37 | Link("Telegram Channel", systemImage: "paperplane.circle.fill", destination: .init(string: "https://t.me/iitc_news")!)
38 | Link("Source Code", systemImage: "swift", destination: .init(string: "https://github.com/IITC-CE/IITC-Button")!)
39 | Label("Version", systemImage: "info")
40 | .badge(version)
41 | }
42 |
43 | private var version: String {
44 | guard let infoDict = Bundle.main.infoDictionary else {
45 | return "Unknown"
46 | }
47 | let shortVersion = infoDict["CFBundleShortVersionString"] as? String ?? "Unknown"
48 | let build = infoDict["CFBundleVersion"] as? String ?? "Unknown"
49 | return "\(shortVersion) (\(build))"
50 | }
51 | }
52 |
53 | #if DEBUG
54 | struct ContentView_Previews: PreviewProvider {
55 | static var previews: some View {
56 | ContentView()
57 | }
58 | }
59 | #endif
60 |
61 | fileprivate extension Link where Label == SwiftUI.Label {
62 | init(_ titleKey: LocalizedStringKey, systemImage name: String, destination: URL) {
63 | self.init(destination: destination) {
64 | SwiftUI.Label(titleKey, systemImage: name)
65 | }
66 | }
67 | }
68 |
--------------------------------------------------------------------------------
/safari/iOS/Views/Helper.swift:
--------------------------------------------------------------------------------
1 | //
2 | // Helper.swift
3 | // iOS
4 | //
5 | // Created by Lucka on 6/10/2021.
6 | //
7 |
8 | import SwiftUI
9 |
10 | struct Helper: View {
11 |
12 | @Environment(\.dismiss) private var dismiss
13 |
14 | var body: some View {
15 | NavigationView {
16 | VStack(alignment: .leading) {
17 | step(1, content: Link("Open Settings \(Image(systemName: "chevron.forward"))", destination: .init(string: UIApplication.openSettingsURLString)!))
18 | step(2, content: Text("Open Safari → Extensions"))
19 | step(3, content: Text("Enable the IITC Button extension"))
20 | step(4, content: Text("Open Intel Map in Safari"))
21 | HStack {
22 | Spacer()
23 | }
24 | Spacer()
25 | }
26 | .listStyle(.plain)
27 | .navigationTitle("How to use")
28 | .navigationViewStyle(.stack)
29 | .toolbar {
30 | Button("Dismiss") { dismiss() }
31 | }
32 | }
33 | }
34 |
35 | @ViewBuilder
36 | private func step(_ index: Int, content: Content) -> some View {
37 | HStack {
38 | Label("Step \(index)", systemImage: "\(index)")
39 | .labelStyle(.iconOnly)
40 | .symbolVariant(.square.fill)
41 | .font(.largeTitle)
42 | .foregroundColor(.accentColor)
43 | content
44 | }
45 | .padding()
46 | }
47 | }
48 |
49 | #if DEBUG
50 | struct Helper_Previews: PreviewProvider {
51 | static var previews: some View {
52 | ContentView()
53 | }
54 | }
55 | #endif
56 |
--------------------------------------------------------------------------------
/safari/macOS/IITCButtonCommands.swift:
--------------------------------------------------------------------------------
1 | //
2 | // IITCButtonCommands.swift
3 | // macOS
4 | //
5 | // Created by Lucka on 6/10/2021.
6 | //
7 |
8 | import SwiftUI
9 |
10 | struct IITCButtonCommands: Commands {
11 |
12 | @Environment(\.openURL) private var openURL
13 |
14 | var body: some Commands {
15 | CommandGroup(after: .help) {
16 | Divider()
17 | Button("Homepage") { openURL(.init(string: "https://iitc.app")!) }
18 | Button("Telegram Channel") { openURL(.init(string: "https://t.me/iitc_news")!) }
19 | Button("Source Code") { openURL(.init(string: "https://github.com/IITC-CE/IITC-Button")!) }
20 | }
21 | }
22 | }
23 |
--------------------------------------------------------------------------------
/safari/macOS/Info.plist:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 | CFBundleName
6 | $(PRODUCT_NAME)
7 | CFBundleVersion
8 | GIT_COMMIT_COUNT
9 | NSHumanReadableCopyright
10 |
11 | CFBundlePackageType
12 | $(PRODUCT_BUNDLE_PACKAGE_TYPE)
13 | CFBundleDevelopmentRegion
14 | $(DEVELOPMENT_LANGUAGE)
15 | LSApplicationCategoryType
16 | public.app-category.utilities
17 | CFBundleInfoDictionaryVersion
18 | 6.0
19 | CFBundleShortVersionString
20 | PACKAGE_VERSION
21 | CFBundleExecutable
22 | $(EXECUTABLE_NAME)
23 | CFBundleIdentifier
24 | $(PRODUCT_BUNDLE_IDENTIFIER)
25 |
26 |
27 |
--------------------------------------------------------------------------------
/safari/macOS/Views/ContentView.swift:
--------------------------------------------------------------------------------
1 | //
2 | // ContentView.swift
3 | // Shared
4 | //
5 | // Created by Lucka on 3/10/2021.
6 | //
7 |
8 | import SwiftUI
9 | import SafariServices
10 |
11 | struct ContentView: View {
12 |
13 | private enum ExtensionStatus {
14 | case unknown
15 | case disabled
16 | case enabled
17 | }
18 |
19 | static private let extensionId = "org.exarhteam.iitc-button.Safari-Extension"
20 |
21 | @Environment(\.scenePhase) private var scenePhase : ScenePhase
22 | @State private var extensionStatus = ExtensionStatus.unknown
23 |
24 | var body: some View {
25 | VStack {
26 | Image(nsImage: NSApplication.shared.applicationIconImage)
27 | extensionStateIndicator
28 | Button("Open Safari Extension Preference", action: showPreferencesForExtension)
29 | }
30 | .frame(minWidth: 240)
31 | .padding()
32 | }
33 |
34 | @ViewBuilder
35 | private var extensionStateIndicator: some View {
36 | HStack {
37 | Text("Safari Extension")
38 | Spacer()
39 | Text(statusText)
40 | .foregroundColor(statusColor)
41 | }
42 | .onChange(of: scenePhase) { phase in
43 | if phase == .active {
44 | updateExtensionStatus()
45 | }
46 | }
47 | }
48 |
49 | private var statusText: LocalizedStringKey {
50 | switch extensionStatus {
51 | case .unknown: return "Unknown"
52 | case .disabled: return "Disabled"
53 | case .enabled: return "Enabled"
54 | }
55 | }
56 |
57 | private var statusColor: Color {
58 | switch extensionStatus {
59 | case .unknown: return .orange
60 | case .disabled: return .red
61 | case .enabled: return .green
62 | }
63 | }
64 |
65 | private func updateExtensionStatus() {
66 | SFSafariExtensionManager.getStateOfSafariExtension(withIdentifier: Self.extensionId) { state, error in
67 | guard let solidState = state, error == nil else {
68 | extensionStatus = .unknown
69 | return
70 | }
71 | DispatchQueue.main.async {
72 | extensionStatus = solidState.isEnabled ? .enabled : .disabled
73 | }
74 | }
75 | }
76 |
77 | private func showPreferencesForExtension() {
78 | SFSafariApplication.showPreferencesForExtension(withIdentifier: Self.extensionId)
79 | }
80 | }
81 |
82 | struct ContentView_Previews: PreviewProvider {
83 | static var previews: some View {
84 | ContentView()
85 | }
86 | }
87 |
--------------------------------------------------------------------------------
/safari/macOS/macOS.entitlements:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 | com.apple.security.app-sandbox
6 |
7 | com.apple.security.files.user-selected.read-only
8 |
9 |
10 |
11 |
--------------------------------------------------------------------------------
/src/background/injector.js:
--------------------------------------------------------------------------------
1 | //@license magnet:?xt=urn:btih:1f739d935676111cfff4b4693e3816e664797050&dn=gpl-3.0.txt GPL-v3
2 |
3 | import browser from "webextension-polyfill";
4 | import { gm_api_for_plugin } from "@/userscripts/wrapper";
5 | import { getNiaTabsToInject, getPluginMatches } from "@/background/utils";
6 | import { is_userscripts_api_available } from "@/userscripts/utils";
7 | import { IS_LEGACY_API } from "@/userscripts/env";
8 |
9 | export async function inject_plugin_via_content_scripts(plugin, use_gm_api) {
10 | const tabs = await getNiaTabsToInject(plugin);
11 | for (let tab of Object.values(tabs)) {
12 | const pluginTab = { ...plugin };
13 | if (use_gm_api) {
14 | pluginTab.code = await gm_api_for_plugin(pluginTab, tab.id);
15 | }
16 |
17 | try {
18 | if (IS_LEGACY_API) {
19 | const inject = `
20 | document.dispatchEvent(new CustomEvent('IITCButtonInitJS', {
21 | detail: ${JSON.stringify({ plugin: pluginTab })}
22 | }));
23 | `;
24 | await browser.tabs.executeScript(tab.id, {
25 | code: inject,
26 | runAt: "document_end",
27 | });
28 | } else {
29 | await browser.scripting.executeScript({
30 | target: { tabId: tab.id },
31 | func: (pluginDetail) => {
32 | document.dispatchEvent(
33 | new CustomEvent("IITCButtonInitJS", {
34 | detail: pluginDetail,
35 | })
36 | );
37 | },
38 | args: [{ plugin: pluginTab }],
39 | injectImmediately: true,
40 | });
41 | }
42 | } catch (error) {
43 | console.error(
44 | `An error occurred while injecting script: ${error.message}`
45 | );
46 | }
47 | }
48 | }
49 |
50 | export async function manage_userscripts_api(plugins_event) {
51 | if (!is_userscripts_api_available()) return;
52 |
53 | const event = plugins_event.event;
54 | const plugins = plugins_event.plugins;
55 | const use_gm_api = plugins_event.use_gm_api !== false;
56 |
57 | if (event === "remove") {
58 | const remove_ids = Object.keys(plugins);
59 | try {
60 | await browser.userScripts.unregister({ ids: remove_ids });
61 | return;
62 | } catch (e) {
63 | console.log("an error occurred while unregistering the plugin", e);
64 | }
65 | }
66 |
67 | let plugins_obj = [];
68 | for (let plugin of Object.values(plugins)) {
69 | if (use_gm_api) {
70 | plugin.code = await gm_api_for_plugin(plugin, 0);
71 | }
72 | plugins_obj.push({
73 | id: plugin.uid,
74 | matches:
75 | plugin.uid === "gm_api" ? ["https://*/*"] : getPluginMatches(plugin),
76 | js: [{ code: plugin.code }],
77 | runAt: plugin.uid === "gm_api" ? "document_start" : "document_end",
78 | world: "MAIN",
79 | });
80 | }
81 |
82 | try {
83 | const registeredScripts = await browser.userScripts.getScripts();
84 | const registeredIds = registeredScripts.map((script) => script.id);
85 |
86 | const pluginsToAdd = plugins_obj.filter(
87 | (plugin) => !registeredIds.includes(plugin.id)
88 | );
89 | const pluginsToUpdate = plugins_obj.filter((plugin) =>
90 | registeredIds.includes(plugin.id)
91 | );
92 |
93 | try {
94 | await browser.userScripts.register(pluginsToAdd);
95 | } catch (e) {
96 | console.log("an error occurred while registering the plugin", e);
97 | }
98 |
99 | try {
100 | await browser.userScripts.update(pluginsToUpdate);
101 | } catch (e) {
102 | console.log("an error occurred while updating the plugin", e);
103 | }
104 | } catch (e) {
105 | console.log("an error occurred while handling the plugin event", e);
106 | }
107 | }
108 |
--------------------------------------------------------------------------------
/src/background/intel.js:
--------------------------------------------------------------------------------
1 | //@license magnet:?xt=urn:btih:1f739d935676111cfff4b4693e3816e664797050&dn=gpl-3.0.txt GPL-v3
2 | import browser from "webextension-polyfill";
3 | import { getTabsToInject } from "@/background/utils";
4 | import { is_iitc_enabled } from "@/userscripts/utils";
5 | import { IS_USERSCRIPTS_API } from "@/userscripts/env";
6 |
7 | const activeTabs = [];
8 | let lastIITCTab = null;
9 |
10 | export async function onRequestOpenIntel() {
11 | if (lastIITCTab) {
12 | const tabInfo = await getTabInfo(lastIITCTab);
13 | if (tabInfo && isIngressIntelUrl(tabInfo.url)) {
14 | return await setTabActive(lastIITCTab);
15 | }
16 | }
17 |
18 | try {
19 | const tab = await browser.tabs.create({
20 | url: "https://intel.ingress.com/",
21 | pinned: true,
22 | });
23 | lastIITCTab = tab.id;
24 | } catch (error) {
25 | console.error(`An error occurred while open tab: ${error.message}`);
26 | }
27 | }
28 |
29 | export async function onToggleIITC(status) {
30 | await browser.storage.local.set({ IITC_is_enabled: status });
31 |
32 | if (IS_USERSCRIPTS_API) {
33 | if (status === false) {
34 | try {
35 | await browser.userScripts.unregister();
36 | // eslint-disable-next-line no-empty
37 | } catch {}
38 | }
39 | } else {
40 | // Fetch all completly loaded Ingress Intel tabs
41 | const tabs = await getTabsToInject();
42 |
43 | for (let tab of Object.values(tabs)) {
44 | if (isIngressIntelUrl(tab.url)) {
45 | await browser.tabs.reload(tab.id);
46 | }
47 | }
48 | }
49 | }
50 |
51 | function removeTabFromActiveTabs(tabId) {
52 | const index = activeTabs.indexOf(tabId);
53 | if (index !== -1) {
54 | activeTabs.splice(index, 1);
55 | }
56 | }
57 |
58 | // tab listeners
59 | export async function onUpdatedListener(tabId, status, tab, manager) {
60 | if (status.status !== "complete" && activeTabs.includes(tabId)) {
61 | removeTabFromActiveTabs(tabId);
62 | }
63 | // Prevent reinitialization on the same page
64 | if (status.status === "complete" && !activeTabs.includes(tabId)) {
65 | activeTabs.push(tabId);
66 | await initialize(manager);
67 | if (isIngressIntelUrl(tab.url)) {
68 | lastIITCTab = tabId;
69 | }
70 | }
71 | }
72 |
73 | export function onRemovedListener(tabId) {
74 | removeTabFromActiveTabs(tabId);
75 | if (lastIITCTab === tabId) {
76 | lastIITCTab = null;
77 | }
78 | }
79 |
80 | async function initialize(manager) {
81 | const status = await is_iitc_enabled();
82 | if (status) {
83 | await manager.inject();
84 | }
85 | }
86 |
87 | async function setTabActive(tabId) {
88 | const tab = await browser.tabs.update(tabId, {
89 | active: true,
90 | });
91 |
92 | try {
93 | await browser.windows.update(tab.windowId, { focused: true });
94 | } catch (error) {
95 | lastIITCTab = null;
96 | await onRequestOpenIntel();
97 | }
98 | }
99 |
100 | async function getTabInfo(tabId) {
101 | try {
102 | return await browser.tabs.get(tabId);
103 | } catch {
104 | return null;
105 | }
106 | }
107 |
108 | function isIngressIntelUrl(url) {
109 | if (url) {
110 | return /^https:\/\/intel\.ingress\.com/.test(url);
111 | }
112 | return false;
113 | }
114 |
--------------------------------------------------------------------------------
/src/background/utils.js:
--------------------------------------------------------------------------------
1 | //@license magnet:?xt=urn:btih:1f739d935676111cfff4b4693e3816e664797050&dn=gpl-3.0.txt GPL-v3
2 |
3 | import browser from "webextension-polyfill";
4 | import { check_matching } from "lib-iitc-manager";
5 |
6 | const is_ingress_tab = (url) => {
7 | return /https:\/\/(intel|missions).ingress.com\/*/.test(url);
8 | };
9 |
10 | // Fetch all completly loaded tabs
11 | export async function getTabsToInject() {
12 | let allTabs = await browser.tabs.query({ status: "complete" });
13 | return allTabs.filter(function (tab) {
14 | return tab.status === "complete" && tab.url;
15 | });
16 | }
17 |
18 | // Filter all completly loaded Ingress Intel tabs
19 | export async function getNiaTabsToInject(plugin) {
20 | const tabs = await getTabsToInject();
21 | return Object.values(tabs).filter(
22 | (tab) =>
23 | (is_ingress_tab(tab.url) && check_matching(plugin, "")) ||
24 | check_matching(plugin, tab.url)
25 | );
26 | }
27 |
28 | export function getPluginMatches(plugin) {
29 | let matches = [];
30 | if (check_matching(plugin, "")) {
31 | matches.push("https://intel.ingress.com/*");
32 | matches.push("https://missions.ingress.com/*");
33 | }
34 | if (plugin.match) {
35 | matches = matches.concat(plugin.match);
36 | } else if (plugin.include) {
37 | matches = matches.concat(plugin.include);
38 | }
39 | return matches;
40 | }
41 |
--------------------------------------------------------------------------------
/src/background/xhr-fallback.js:
--------------------------------------------------------------------------------
1 | //@license magnet:?xt=urn:btih:1f739d935676111cfff4b4693e3816e664797050&dn=gpl-3.0.txt GPL-v3
2 |
3 | import { strToBase64 } from "@/strToBase64";
4 | import { IS_USERSCRIPTS_API } from "@/userscripts/env";
5 |
6 | // Execution in the context of an extension, to bypass CORS policy.
7 | export async function xmlHttpRequestFallbackHandler(data) {
8 | async function xmlResponse(tab_id, callback, response) {
9 | const detail_stringify = JSON.stringify({
10 | task_uuid: data.task_uuid,
11 | task_type: data.task_type,
12 | response: JSON.stringify(response),
13 | });
14 |
15 | const bridge_data = strToBase64(String(detail_stringify));
16 |
17 | let allTabs = [
18 | {
19 | id: data.tab_id,
20 | },
21 | ];
22 | if (IS_USERSCRIPTS_API) {
23 | allTabs = await browser.tabs.query({ active: true });
24 | }
25 |
26 | for (const tab of allTabs) {
27 | await browser.tabs.sendMessage(tab.id, {
28 | type: "XHRFallbackResponse",
29 | value: bridge_data,
30 | });
31 | }
32 | }
33 |
34 | try {
35 | const response = await fetch(data.url, {
36 | mode: "no-cors",
37 | method: data.method,
38 | headers: data.headers,
39 | body: data.method !== "GET" ? data.data : undefined,
40 | credentials: data.user && data.password ? "include" : "same-origin",
41 | });
42 |
43 | const text = await response.text();
44 |
45 | // Create a response object similar to the one in XMLHttpRequest
46 | const responseObject = {
47 | readyState: 4,
48 | responseHeaders: "Not directly accessible with fetch",
49 | responseText: text,
50 | status: response.status,
51 | statusText: response.statusText,
52 | };
53 |
54 | await xmlResponse(data.tab_id, data.onload, responseObject);
55 | } catch (error) {
56 | console.error("Fetch error:", error);
57 | }
58 | }
59 |
--------------------------------------------------------------------------------
/src/content-scripts/bridge-manager.js:
--------------------------------------------------------------------------------
1 | //@license magnet:?xt=urn:btih:1f739d935676111cfff4b4693e3816e664797050&dn=gpl-3.0.txt GPL-v3
2 |
3 | import { sendXhrRequest } from "./xhr-bridge";
4 | import { handleStorageRequest } from "./storage-bridge";
5 | import { isRunContentScript } from "@/content-scripts/utils";
6 |
7 | // Flag to prevent multiple initializations
8 | let isInitialized = false;
9 |
10 | /**
11 | * Initialize all communication bridges
12 | */
13 | export function setupBridges() {
14 | if (isInitialized) return;
15 | isInitialized = true;
16 |
17 | // Set up main event listener for bridge requests
18 | document.addEventListener("bridgeRequest", bridgeAction);
19 | }
20 |
21 | /**
22 | * Process incoming bridge requests from page context
23 | */
24 | export function bridgeAction(e) {
25 | const task = e.detail;
26 |
27 | switch (task.task_type) {
28 | case "xmlHttpRequest":
29 | sendXhrRequest(task);
30 | break;
31 | case "getStorage":
32 | case "setValue":
33 | case "delValue":
34 | handleStorageRequest(task).then();
35 | break;
36 | default:
37 | console.warn("IITC Button: Unknown bridge request type", task.task_type);
38 | break;
39 | }
40 | }
41 |
42 | // Fallback XHR
43 | if (isRunContentScript) {
44 | browser.runtime.onMessage.addListener(async (request) => {
45 | switch (request.type) {
46 | case "XHRFallbackResponse":
47 | bridgeResponse(request.value);
48 | break;
49 | }
50 | });
51 | }
52 |
53 | /**
54 | * Send response back to page context
55 | */
56 | export function bridgeResponse(data) {
57 | dispatchEvent(
58 | new CustomEvent("bridgeResponse", {
59 | detail: data,
60 | })
61 | );
62 | }
63 |
--------------------------------------------------------------------------------
/src/content-scripts/loader.js:
--------------------------------------------------------------------------------
1 | //@license magnet:?xt=urn:btih:1f739d935676111cfff4b4693e3816e664797050&dn=gpl-3.0.txt GPL-v3
2 |
3 | import { IITCButtonInitJS, isRunContentScript } from "./utils";
4 | import { setupBridges } from "@/content-scripts/bridge-manager";
5 | import { inject_gm_api } from "@/userscripts/wrapper";
6 | import { IS_USERSCRIPTS_API } from "@/userscripts/env";
7 | import { is_iitc_enabled } from "@/userscripts/utils";
8 |
9 | function preparePage() {
10 | // Initialize all communication bridges
11 | setupBridges();
12 |
13 | if (IS_USERSCRIPTS_API) return;
14 |
15 | inject_gm_api();
16 | document.addEventListener("IITCButtonInitJS", IITCButtonInitJS);
17 | }
18 |
19 | if (isRunContentScript) {
20 | window.iitcbutton = true;
21 | is_iitc_enabled().then((status) => {
22 | if (status) {
23 | preparePage();
24 | }
25 | });
26 | }
27 |
--------------------------------------------------------------------------------
/src/content-scripts/storage-bridge.js:
--------------------------------------------------------------------------------
1 | //@license magnet:?xt=urn:btih:1f739d935676111cfff4b4693e3816e664797050&dn=gpl-3.0.txt GPL-v3
2 |
3 | import browser from "webextension-polyfill";
4 | import { strToBase64 } from "@/strToBase64";
5 | import { bridgeResponse } from "./bridge-manager";
6 |
7 | /**
8 | * Handle storage-related requests
9 | */
10 | export async function handleStorageRequest(task) {
11 | switch (task.task_type) {
12 | case "getStorage":
13 | await getStorageBridge(task);
14 | break;
15 | case "setValue":
16 | await setValueBridge(task);
17 | break;
18 | case "delValue":
19 | await deleteValueBridge(task);
20 | break;
21 | }
22 | }
23 |
24 | /**
25 | * Get all plugin storage data and send it to page context
26 | */
27 | async function getStorageBridge(req) {
28 | try {
29 | const all_storage = await browser.storage.local.get(null);
30 | const plugins_storage = {};
31 |
32 | // Filter for plugin-related storage keys
33 | for (const key in all_storage) {
34 | if (key.startsWith("VMin")) {
35 | plugins_storage[key] = all_storage[key];
36 | }
37 | }
38 |
39 | const detail_stringify = JSON.stringify({
40 | task_type: req.task_type,
41 | response: JSON.stringify(plugins_storage),
42 | });
43 |
44 | const bridge_base64_data = strToBase64(String(detail_stringify));
45 | bridgeResponse(bridge_base64_data);
46 | } catch (error) {
47 | console.error("IITC Button Storage Bridge: Error getting storage", error);
48 | }
49 | }
50 |
51 | /**
52 | * Save value to extension storage
53 | */
54 | export async function setValueBridge(req) {
55 | try {
56 | const set_data = {};
57 | set_data[req.key] = req.value;
58 | await browser.storage.local.set(set_data);
59 | } catch (error) {
60 | console.error("IITC Button Storage Bridge: Error setting value", error);
61 | }
62 | }
63 |
64 | /**
65 | * Delete value from extension storage
66 | */
67 | export async function deleteValueBridge(req) {
68 | try {
69 | await browser.storage.local.remove(req.key);
70 | } catch (error) {
71 | console.error("IITC Button Storage Bridge: Error removing value", error);
72 | }
73 | }
74 |
--------------------------------------------------------------------------------
/src/content-scripts/utils.js:
--------------------------------------------------------------------------------
1 | //@license magnet:?xt=urn:btih:1f739d935676111cfff4b4693e3816e664797050&dn=gpl-3.0.txt GPL-v3
2 |
3 | import { getUID } from "lib-iitc-manager";
4 |
5 | const LOADED_PLUGINS = [];
6 |
7 | export const isRunContentScript = !window.iitcbutton;
8 |
9 | export function inject(code) {
10 | const script = document.createElement("script");
11 | script.appendChild(document.createTextNode(code));
12 | (document.body || document.head || document.documentElement).appendChild(
13 | script
14 | );
15 | script.parentElement.removeChild(script);
16 | }
17 |
18 | export async function IITCButtonInitJS(e) {
19 | const plugin = e.detail.plugin;
20 |
21 | const uid = plugin.uid ? plugin.uid : getUID(plugin);
22 | if (LOADED_PLUGINS.includes(uid)) {
23 | console.debug(`Plugin ${uid} is already loaded. Skip`);
24 | } else {
25 | LOADED_PLUGINS.push(uid);
26 | console.debug(`Plugin ${uid} loaded`);
27 | inject(plugin.code);
28 | }
29 | }
30 |
--------------------------------------------------------------------------------
/src/content-scripts/xhr-bridge.js:
--------------------------------------------------------------------------------
1 | //@license magnet:?xt=urn:btih:1f739d935676111cfff4b4693e3816e664797050&dn=gpl-3.0.txt GPL-v3
2 |
3 | import browser from "webextension-polyfill";
4 | import { strToBase64 } from "@/strToBase64";
5 | import { IS_SAFARI } from "@/userscripts/env";
6 |
7 | let xhrIframe = null;
8 | let pendingRequests = [];
9 | let messageListener = null;
10 |
11 | // Retry tracking
12 | let retryCount = 0;
13 | const MAX_RETRIES = 3;
14 |
15 | // Create sandbox iframe
16 | function createIframe() {
17 | try {
18 | // Don't create if already exists
19 | if (xhrIframe) return;
20 |
21 | // Add message listener before creating iframe
22 | if (messageListener) {
23 | window.removeEventListener("message", messageListener);
24 | }
25 |
26 | messageListener = function (event) {
27 | // Process response messages from iframe
28 | if (event.data && event.data.type === "xhr_response") {
29 | handleXhrResponseData(event.data);
30 | }
31 | };
32 |
33 | window.addEventListener("message", messageListener);
34 |
35 | // Create hidden iframe with sandbox for XHR
36 | xhrIframe = document.createElement("iframe");
37 | xhrIframe.sandbox = "allow-scripts allow-same-origin";
38 | xhrIframe.style.cssText =
39 | "display:none; position:absolute; width:0; height:0; border:0;";
40 | xhrIframe.src = browser.runtime.getURL("xhr-sandbox.html");
41 |
42 | // Add to DOM
43 | document.body.appendChild(xhrIframe);
44 |
45 | // Process pending requests when iframe loads
46 | xhrIframe.onload = function () {
47 | if (pendingRequests.length > 0) {
48 | pendingRequests.forEach((data) => sendXhrRequest(data));
49 | pendingRequests = [];
50 | }
51 | };
52 | } catch (error) {
53 | console.error("IITC Button XHR Bridge: failed to create iframe", error);
54 | }
55 | }
56 |
57 | // Process response data from iframe
58 | function handleXhrResponseData(data) {
59 | try {
60 | const detail_stringify = JSON.stringify({
61 | task_uuid: data.uuid,
62 | task_type: "xmlHttpRequest",
63 | response: JSON.stringify(data.response),
64 | });
65 |
66 | const bridge_data = strToBase64(String(detail_stringify));
67 |
68 | // Send result in the same format as background would do
69 | window.dispatchEvent(
70 | new CustomEvent("bridgeResponse", {
71 | detail: bridge_data,
72 | })
73 | );
74 | } catch (error) {
75 | console.error("IITC Button XHR Bridge: error handling response", error);
76 | }
77 | }
78 |
79 | // Send XHR request
80 | export function sendXhrRequest(data) {
81 | // For Safari, use fetch fallback
82 | if (IS_SAFARI) {
83 | browser.runtime
84 | .sendMessage({
85 | type: "XHRFallbackRequest",
86 | value: data,
87 | })
88 | .then();
89 | return;
90 | }
91 |
92 | // For other browsers, use iframe
93 | // Queue request if iframe not ready
94 | if (!xhrIframe || !xhrIframe.contentWindow) {
95 | pendingRequests.push(data);
96 |
97 | // Create iframe if it doesn't exist
98 | if (!xhrIframe) {
99 | createIframe();
100 |
101 | // Add retry logic for iframe problems
102 | if (retryCount < MAX_RETRIES) {
103 | retryCount++;
104 | setTimeout(() => {
105 | if (pendingRequests.includes(data)) {
106 | sendXhrRequest(data);
107 | }
108 | }, 500 * retryCount);
109 | }
110 | }
111 | return;
112 | }
113 |
114 | retryCount = 0;
115 |
116 | try {
117 | // Send request to iframe
118 | xhrIframe.contentWindow.postMessage(
119 | {
120 | type: "xhr_request",
121 | uuid: data.task_uuid,
122 | method: data.method,
123 | url: data.url,
124 | headers: data.headers,
125 | data: data.data,
126 | user: data.user,
127 | password: data.password,
128 | overrideMimeType: data.overrideMimeType,
129 | timeout: data.timeout,
130 | withCredentials: data.withCredentials,
131 | },
132 | "*"
133 | );
134 | } catch (error) {
135 | console.error("IITC Button XHR Bridge: error sending request", error);
136 | }
137 | }
138 |
--------------------------------------------------------------------------------
/src/i18n.js:
--------------------------------------------------------------------------------
1 | //@license magnet:?xt=urn:btih:1f739d935676111cfff4b4693e3816e664797050&dn=gpl-3.0.txt GPL-v3
2 | import browser from "webextension-polyfill";
3 |
4 | export function _(msg, arg) {
5 | return browser.i18n.getMessage(msg, arg);
6 | }
7 |
--------------------------------------------------------------------------------
/src/jsview/App.vue:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 |
7 |
8 |
9 |
79 |
80 |
86 |
87 |
99 |
--------------------------------------------------------------------------------
/src/jsview/Code.vue:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 | {{ status }}
5 |
6 |
7 |
30 |
31 |
32 |
33 |
72 |
--------------------------------------------------------------------------------
/src/jsview/highlightjs-lineToDiv.js:
--------------------------------------------------------------------------------
1 | /*
2 | * highlightjs-lineToDiv
3 | * Plugin for highlightJS that transforms a line into a div element.
4 | *
5 | * https://github.com/deleterium/highlightjs-lineToDiv
6 | */
7 | export const plugin = (result) => {
8 | let className, idName;
9 | /* Configuration */
10 | className = "line";
11 | idName = "code%line%";
12 | /* end of configuration */
13 | const htmlLines = result.value.split("\n");
14 | let spanStack = [];
15 | result.value = htmlLines
16 | .map((content, index) => {
17 | let startSpanIndex, endSpanIndex;
18 | let needle = 0;
19 | content = spanStack.join("") + content;
20 | spanStack = [];
21 | do {
22 | const remainingContent = content.slice(needle);
23 | startSpanIndex = remainingContent.indexOf("/.exec(remainingContent);
33 | if (nextSpan === null) {
34 | // never: but ensure no exception is raised if it happens some day.
35 | break;
36 | }
37 | spanStack.push(nextSpan[0]);
38 | needle += startSpanIndex + nextSpan[0].length;
39 | } else {
40 | spanStack.pop();
41 | needle += endSpanIndex + 1;
42 | }
43 | // eslint-disable-next-line no-constant-condition
44 | } while (true);
45 | if (spanStack.length > 0) {
46 | content += Array(spanStack.length).fill("").join("");
47 | }
48 | let retString = "`;
57 | return retString;
58 | })
59 | .join("");
60 | };
61 |
--------------------------------------------------------------------------------
/src/jsview/main.js:
--------------------------------------------------------------------------------
1 | //@license magnet:?xt=urn:btih:1f739d935676111cfff4b4693e3816e664797050&dn=gpl-3.0.txt GPL-v3
2 | import Vue from "vue";
3 | import App from "./App.vue";
4 |
5 | /* eslint-disable no-new */
6 | new Vue({
7 | el: "#app",
8 | render: (h) => h(App),
9 | });
10 |
--------------------------------------------------------------------------------
/src/manifest.json:
--------------------------------------------------------------------------------
1 | {
2 | "name": "IITC Button",
3 | "description": "__MSG_extDescription__",
4 | "minimum_chrome_version": "61",
5 | "browser_specific_settings": {
6 | "gecko": {
7 | "id": "iitc@modos189.ru",
8 | "strict_min_version": "57.0"
9 | },
10 | "gecko_android": {
11 | "strict_min_version": "113.0"
12 | }
13 | },
14 | "permissions": [
15 | "tabs",
16 | "storage",
17 | "unlimitedStorage"
18 | ],
19 | "default_locale": "en",
20 | "background": {},
21 | "browser_action": {
22 | "default_popup": "popup.html",
23 | "default_title": "__MSG_titleDefault__",
24 | "default_icon": {
25 | "48": "assets/icons/48/icon.png",
26 | "96": "assets/icons/96/icon.png"
27 | }
28 | },
29 | "icons": {
30 | "48": "assets/icons/48/icon.png",
31 | "128": "assets/icons/128/icon.png"
32 | },
33 | "web_accessible_resources": [
34 | {
35 | "resources": [
36 | "xhr-sandbox.html"
37 | ],
38 | "matches": [
39 | ""
40 | ]
41 | }
42 | ]
43 | }
44 |
--------------------------------------------------------------------------------
/src/popup/App.vue:
--------------------------------------------------------------------------------
1 |
2 |
3 |
18 |
19 |
20 |
68 |
69 |
70 |
71 |
72 |
174 |
--------------------------------------------------------------------------------
/src/popup/components/Header.vue:
--------------------------------------------------------------------------------
1 |
2 |
3 |
12 |
13 |
14 |
31 |
32 |
55 |
--------------------------------------------------------------------------------
/src/popup/components/Hr.vue:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 |
9 |
10 |
16 |
--------------------------------------------------------------------------------
/src/popup/components/InputCustomServer.vue:
--------------------------------------------------------------------------------
1 |
2 |
3 |
37 |
38 |
39 |
123 |
124 |
165 |
--------------------------------------------------------------------------------
/src/popup/components/Message.vue:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 | {{ message.text }}
5 |
6 |
7 |
8 |
32 |
33 |
71 |
--------------------------------------------------------------------------------
/src/popup/components/SectionMainMenu/PluginList/NoData.vue:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 | {{ _("noData") }}
5 |
6 |
7 |
8 |
16 |
17 |
34 |
--------------------------------------------------------------------------------
/src/popup/components/SectionMainMenu/PluginList/PluginList.vue:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 |
7 |
14 |
15 |
16 |
17 |
18 |
25 |
26 |
27 |
28 |
29 |
30 |
76 |
77 |
82 |
--------------------------------------------------------------------------------
/src/popup/components/SectionMainMenu/PluginList/Title.vue:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 | {{ text }}
6 |
7 |
8 |
9 |
10 |
11 |
25 |
26 |
48 |
--------------------------------------------------------------------------------
/src/popup/components/SectionMainMenu/ProgressBar.vue:
--------------------------------------------------------------------------------
1 |
2 |
3 |
8 |
9 |
10 |
25 |
26 |
95 |
--------------------------------------------------------------------------------
/src/popup/components/SectionMainMenu/SearchBar.vue:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 | search
5 | cancel
11 |
19 |
20 |
21 |
22 |
41 |
42 |
79 |
--------------------------------------------------------------------------------
/src/popup/components/SectionMainMenu/SectionMainMenu.vue:
--------------------------------------------------------------------------------
1 |
2 |
3 |
15 |
16 |
17 |
105 |
106 |
113 |
--------------------------------------------------------------------------------
/src/popup/components/SectionMainMenu/Tags/Tag.vue:
--------------------------------------------------------------------------------
1 |
2 |
3 |
9 | {{ tag.name }}
10 |
11 |
12 |
13 |
46 |
47 |
84 |
--------------------------------------------------------------------------------
/src/popup/components/SectionMainMenu/Tags/Tags.vue:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
11 |
12 |
13 |
14 |
103 |
104 |
111 |
--------------------------------------------------------------------------------
/src/popup/components/SectionMainMenu/Title.vue:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
14 |
19 | add
20 |
21 |
22 | settings
23 |
24 |
25 |
26 |
27 |
28 |
49 |
50 |
82 |
--------------------------------------------------------------------------------
/src/popup/components/SectionMainMenu/ToggleIITC.vue:
--------------------------------------------------------------------------------
1 |
2 |
3 |
16 |
17 |
18 |
49 |
50 |
90 |
--------------------------------------------------------------------------------
/src/popup/components/UpdateCheckIntervalSelector.vue:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 | {{ updateChannelsIntervals[channel]["name"] }}:
8 |
9 |
25 |
26 |
27 |
28 |
64 |
65 |
89 |
--------------------------------------------------------------------------------
/src/popup/components/mixins.js:
--------------------------------------------------------------------------------
1 | //@license magnet:?xt=urn:btih:1f739d935676111cfff4b4693e3816e664797050&dn=gpl-3.0.txt GPL-v3
2 | import browser from "webextension-polyfill";
3 | import { _ } from "@/i18n";
4 |
5 | export const mixin = {
6 | data() {
7 | return {
8 | updateChannels: {
9 | release: { name: _("release") },
10 | beta: { name: _("beta") },
11 | custom: { name: _("custom") },
12 | },
13 | updateChannelsIntervals: {
14 | release: { name: _("release") },
15 | beta: { name: _("beta") },
16 | custom: { name: _("custom") },
17 | external: { name: _("anyChannel") },
18 | },
19 | updateIntervals: [
20 | { name: _("every5seconds"), value: "5" },
21 | { name: _("every6hours"), value: "21600" },
22 | { name: _("every12hours"), value: "43200" },
23 | { name: _("everyDay"), value: "86400" },
24 | { name: _("everyWeek"), value: "604800" },
25 | ],
26 | };
27 | },
28 | methods: {
29 | _: _,
30 | __: function (key, item) {
31 | if (item === undefined || !(key in item)) return "";
32 | const lang = browser.i18n.getUILanguage();
33 | return `${key}:${lang}` in item ? item[`${key}:${lang}`] : item[key];
34 | },
35 | objIsEmpty: function (obj) {
36 | return typeof obj !== "object" || Object.keys(obj).length === 0;
37 | },
38 | openLink: async function (url) {
39 | await browser.tabs.create({ url: url });
40 | window.close();
41 | },
42 | back: function () {
43 | document.body.id = "main-menu";
44 | },
45 | sortIITCObj: function (obj) {
46 | if (obj === undefined) {
47 | return {};
48 | }
49 |
50 | const arr = Object.entries(obj);
51 | arr.sort((a, b) => {
52 | const nameA = this.__("name", a[1]).toLowerCase();
53 | const nameB = this.__("name", b[1]).toLowerCase();
54 | return nameA > nameB ? 1 : -1;
55 | });
56 |
57 | return Object.fromEntries(arr);
58 | },
59 | showMessage: function (msg) {
60 | this.$root.$emit("message", msg);
61 | },
62 | },
63 | };
64 |
--------------------------------------------------------------------------------
/src/popup/data.js:
--------------------------------------------------------------------------------
1 | //@license magnet:?xt=urn:btih:1f739d935676111cfff4b4693e3816e664797050&dn=gpl-3.0.txt GPL-v3
2 |
3 | import browser from "webextension-polyfill";
4 |
5 | export async function init(self) {
6 | const appData = self.$data;
7 | const data = await browser.storage.local.get([
8 | "channel",
9 | "release_categories",
10 | "beta_categories",
11 | "custom_categories",
12 | "release_plugins_flat",
13 | "beta_plugins_flat",
14 | "custom_plugins_flat",
15 | "release_iitc_core",
16 | "beta_iitc_core",
17 | "custom_iitc_core",
18 | "release_iitc_core_user",
19 | "beta_iitc_core_user",
20 | "custom_iitc_core_user",
21 | ]);
22 | const channel = data.channel ? data.channel : "release";
23 | // initialize categories
24 | appData.categories = data[channel + "_categories"];
25 | // initialize all plugins
26 | appData.plugins_flat = data[channel + "_plugins_flat"];
27 | // initialize iitc core
28 | setIitcCore(
29 | appData,
30 | data[channel + "_iitc_core"],
31 | data[channel + "_iitc_core_user"]
32 | );
33 | }
34 |
35 | function setCategories(appData, categories) {
36 | appData.categories = {};
37 | appData.categories = categories;
38 | }
39 |
40 | function setPlugins(appData, plugins_flat) {
41 | appData.plugins_flat = plugins_flat;
42 | const category_name = appData.category_name;
43 | if (category_name !== "") {
44 | if (appData.categories[category_name]) {
45 | appData.plugins = Object.entries(plugins_flat).reduce(
46 | (category_plugins, plugin_pair) => {
47 | const [plugin_uid, plugin_obj] = plugin_pair;
48 | if (plugin_obj.category === category_name) {
49 | category_plugins[plugin_uid] = plugin_obj;
50 | }
51 | return category_plugins;
52 | },
53 | {}
54 | );
55 | } else {
56 | appData.plugins = {};
57 | }
58 | }
59 | }
60 |
61 | function setIitcCore(appData, iitc_core, iitc_core_user) {
62 | let core = iitc_core;
63 | if (iitc_core_user && iitc_core_user.code) {
64 | core = iitc_core_user;
65 | core.override = true;
66 | core.user = true;
67 | }
68 | appData.iitc_core = core;
69 | }
70 |
71 | export async function onChangedListener(self) {
72 | const appData = self.$data;
73 | browser.storage.onChanged.addListener(async function (changes) {
74 | const data = await browser.storage.local.get("channel");
75 | const channel = data.channel ? data.channel : "release";
76 |
77 | for (let key in changes) {
78 | const new_value = changes[key].newValue;
79 |
80 | if (key === "channel") {
81 | const storage = await browser.storage.local.get([
82 | channel + "_categories",
83 | channel + "_plugins_flat",
84 | channel + "_iitc_core",
85 | channel + "_iitc_core_user",
86 | ]);
87 | setCategories(appData, storage[channel + "_categories"]);
88 | setPlugins(appData, storage[channel + "_plugins_flat"]);
89 | setIitcCore(
90 | appData,
91 | storage[channel + "_iitc_core"],
92 | storage[channel + "_iitc_core_user"]
93 | );
94 | }
95 |
96 | if (key === channel + "_categories") {
97 | setCategories(appData, new_value);
98 | }
99 |
100 | if (key === channel + "_plugins_flat") {
101 | setPlugins(appData, new_value);
102 | }
103 |
104 | if (key === channel + "_iitc_core_user") {
105 | const storage = await browser.storage.local.get([
106 | channel + "_iitc_core",
107 | ]);
108 | setIitcCore(appData, storage[channel + "_iitc_core"], new_value);
109 | }
110 | }
111 | });
112 | }
113 |
114 | export async function onMessageListener(self) {
115 | browser.runtime.onMessage.addListener(function (request) {
116 | switch (request.type) {
117 | case "showProgressbar":
118 | self.$root.$emit("showProgressbar", request.value);
119 | break;
120 | case "showMessage":
121 | self.showMessage(request.message);
122 | break;
123 | }
124 | return new Promise((resolve) => {
125 | setTimeout(() => {
126 | resolve();
127 | }, 1);
128 | });
129 | });
130 | }
131 |
--------------------------------------------------------------------------------
/src/popup/main.js:
--------------------------------------------------------------------------------
1 | //@license magnet:?xt=urn:btih:1f739d935676111cfff4b4693e3816e664797050&dn=gpl-3.0.txt GPL-v3
2 | import Vue from "vue";
3 | import App from "./App.vue";
4 |
5 | new Vue({
6 | el: "#app",
7 | render: (h) => h(App),
8 | });
9 |
--------------------------------------------------------------------------------
/src/popup/search.js:
--------------------------------------------------------------------------------
1 | import browser from "webextension-polyfill";
2 |
3 | import { fuzzysearch } from "scored-fuzzysearch";
4 |
5 | const score = (query, text) => {
6 | if (text === undefined) return 0;
7 | return fuzzysearch(query, text);
8 | };
9 |
10 | const setPluginScore = (p, q) => {
11 | const lang = browser.i18n.getUILanguage();
12 | p._search_score = Math.max(
13 | score(q, p.name),
14 | score(q, p["name:" + lang]),
15 | score(q, p.description),
16 | score(q, p["description:" + lang]),
17 | score(q, p.category)
18 | );
19 | return p;
20 | };
21 |
22 | const sortScoredPlugins = (arr) => {
23 | for (let i = 0; i < arr.length; i++) {
24 | for (let j = i + 1; j < arr.length; j++) {
25 | if (arr[i]._search_score < arr[j]._search_score) {
26 | let swap = arr[i];
27 | arr[i] = arr[j];
28 | arr[j] = swap;
29 | }
30 | }
31 | }
32 | return arr;
33 | };
34 |
35 | export function searchPlugins(query, plugins_obj) {
36 | const plugins = Object.keys(plugins_obj).map((key) => plugins_obj[key]);
37 | const scored_plugins = plugins.map((plugin) => setPluginScore(plugin, query));
38 | const sorted_plugins = sortScoredPlugins(scored_plugins);
39 | const result_plugins = sorted_plugins.filter((p) => p._search_score);
40 | return result_plugins;
41 | }
42 |
--------------------------------------------------------------------------------
/src/settings/App.vue:
--------------------------------------------------------------------------------
1 |
2 |
3 |
9 |
10 |
11 |
50 |
51 |
57 |
58 |
89 |
--------------------------------------------------------------------------------
/src/settings/Header.vue:
--------------------------------------------------------------------------------
1 |
2 |
3 |
33 |
34 |
35 |
48 |
49 |
50 |
51 |
118 |
--------------------------------------------------------------------------------
/src/settings/add/BlockDrop.vue:
--------------------------------------------------------------------------------
1 |
2 |
3 |
32 |
33 |
34 |
125 |
126 |
161 |
--------------------------------------------------------------------------------
/src/settings/add/BlockURL.vue:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
11 | »
12 |
13 |
20 |
21 |
22 |
23 |
24 |
83 |
84 |
133 |
--------------------------------------------------------------------------------
/src/settings/add/Main.vue:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 |
7 | — {{ _("or") }} —
8 |
9 |
10 |
11 |
12 |
13 |
14 |
27 |
28 |
29 |
30 |
36 |
--------------------------------------------------------------------------------
/src/settings/backup/utils.js:
--------------------------------------------------------------------------------
1 | //@license magnet:?xt=urn:btih:1f739d935676111cfff4b4693e3816e664797050&dn=gpl-3.0.txt GPL-v3
2 | import JSZip from "jszip";
3 |
4 | export const backup_json_name = "iitc.json";
5 |
6 | export function formatDate(date) {
7 | const year = date.getFullYear();
8 | const month = padZero(date.getMonth() + 1);
9 | const day = padZero(date.getDate());
10 | const hours = padZero(date.getHours());
11 | const minutes = padZero(date.getMinutes());
12 | const seconds = padZero(date.getSeconds());
13 |
14 | return (
15 | year + "-" + month + "-" + day + "_" + hours + "." + minutes + "." + seconds
16 | );
17 | }
18 |
19 | function padZero(number) {
20 | if (number < 10) {
21 | return "0" + number;
22 | }
23 | return number;
24 | }
25 |
26 | export const saveAs = (blob, fileName) => {
27 | const link = document.createElement("a");
28 | // create a blobURI pointing to our Blob
29 | link.href = URL.createObjectURL(blob);
30 | link.download = fileName;
31 | // some browser needs the anchor to be in the doc
32 | document.body.append(link);
33 | link.click();
34 | link.remove();
35 | // in case the Blob uses a lot of memory
36 | setTimeout(() => URL.revokeObjectURL(link.href), 7000);
37 | };
38 |
39 | export const getBackupDataFromZip = async (file) => {
40 | const backup = {
41 | external_plugins: {},
42 | data: {},
43 | };
44 | const zip = await JSZip.loadAsync(file);
45 |
46 | for (const zipName in zip.files) {
47 | const zipEntry = zip.files[zipName];
48 | if (!zipEntry.dir) {
49 | const filename = zipEntry.name;
50 | const filename_split = filename.split("/");
51 |
52 | if (filename === backup_json_name) {
53 | // import iitc.json
54 | backup.data = JSON.parse(await zip.file(filename).async("string"));
55 | } else if (
56 | filename_split.length > 1 &&
57 | ["release", "beta", "custom"].includes(filename_split[0])
58 | ) {
59 | // import external plugins
60 | const channel = filename_split[0];
61 | const plugin_filename = filename_split[1];
62 | if (!Object.hasOwn(backup.external_plugins, channel)) {
63 | backup.external_plugins[channel] = {};
64 | }
65 | backup.external_plugins[channel][plugin_filename] = await zip
66 | .file(filename)
67 | .async("string");
68 | }
69 | }
70 | }
71 | return backup;
72 | };
73 |
74 | export const createBackupZip = async (backup) => {
75 | const zip = new JSZip();
76 |
77 | zip.file(backup_json_name, JSON.stringify(backup.data));
78 |
79 | for (const channel in backup.external_plugins) {
80 | for (const external_plugin_name in backup.external_plugins[channel]) {
81 | zip.file(
82 | `${channel}/${external_plugin_name}`,
83 | backup.external_plugins[channel][external_plugin_name]
84 | );
85 | }
86 | }
87 |
88 | const filename = "iitc-backup_" + formatDate(new Date()) + ".zip";
89 | zip.generateAsync({ type: "blob" }).then(function (content) {
90 | saveAs(content, filename);
91 | });
92 | };
93 |
--------------------------------------------------------------------------------
/src/settings/debug/Main.vue:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
{{ _("debug") }}
6 |
7 |
{{ _("warningAboutLocalStoragePart1") }}
8 |
9 | {{ _("warningAboutLocalStoragePart2") }}
10 |
11 |
16 |
{{ _("saveToJson") }}
17 |
18 |
19 |
{{ _("importLocalStorage") }}
20 |
21 |
22 | {{ _("warningAboutImportLocalStorage") }}
23 |
24 |
34 |
35 |
36 |
37 |
38 |
39 |
87 |
88 |
89 |
90 |
132 |
--------------------------------------------------------------------------------
/src/settings/main.js:
--------------------------------------------------------------------------------
1 | //@license magnet:?xt=urn:btih:1f739d935676111cfff4b4693e3816e664797050&dn=gpl-3.0.txt GPL-v3
2 | import Vue from "vue";
3 | import App from "./App.vue";
4 |
5 | /* eslint-disable no-new */
6 | new Vue({
7 | el: "#app",
8 | render: (h) => h(App),
9 | });
10 |
--------------------------------------------------------------------------------
/src/settings/utils.js:
--------------------------------------------------------------------------------
1 | //@license magnet:?xt=urn:btih:1f739d935676111cfff4b4693e3816e664797050&dn=gpl-3.0.txt GPL-v3
2 |
3 | export const readUploadedFileAsText = (inputFile) => {
4 | const temporaryFileReader = new FileReader();
5 |
6 | return new Promise((resolve, reject) => {
7 | temporaryFileReader.onerror = () => {
8 | temporaryFileReader.abort();
9 | reject(new DOMException("Problem parsing input file."));
10 | };
11 |
12 | temporaryFileReader.onload = () => {
13 | resolve(temporaryFileReader.result);
14 | };
15 | temporaryFileReader.readAsText(inputFile);
16 | });
17 | };
18 |
--------------------------------------------------------------------------------
/src/strToBase64.js:
--------------------------------------------------------------------------------
1 | //@license magnet:?xt=urn:btih:1f739d935676111cfff4b4693e3816e664797050&dn=gpl-3.0.txt GPL-v3
2 |
3 | export function strToBase64(str) {
4 | const bytes = new TextEncoder().encode(str);
5 | const binString = String.fromCodePoint(...bytes);
6 | return btoa(binString);
7 | }
8 |
--------------------------------------------------------------------------------
/src/userscripts/env.js:
--------------------------------------------------------------------------------
1 | //@license magnet:?xt=urn:btih:1f739d935676111cfff4b4693e3816e664797050&dn=gpl-3.0.txt GPL-v3
2 |
3 | import browser from "webextension-polyfill";
4 |
5 | export const IS_CHROME = !!browser.runtime.OnInstalledReason?.CHROME_UPDATE;
6 | export const IS_SAFARI =
7 | /^((?!chrome|android).)*safari/i.test(navigator.userAgent) ||
8 | (navigator.vendor && navigator.vendor.indexOf("Apple") > -1);
9 | export const MANIFEST = browser.runtime.getManifest();
10 |
11 | export const IS_USERSCRIPTS_API = IS_CHROME && MANIFEST.manifest_version === 3;
12 | export const IS_SCRIPTING_API = !!browser.scripting;
13 | export const IS_LEGACY_API = !IS_USERSCRIPTS_API && !IS_SCRIPTING_API;
14 |
--------------------------------------------------------------------------------
/src/userscripts/utils.js:
--------------------------------------------------------------------------------
1 | //@license magnet:?xt=urn:btih:1f739d935676111cfff4b4693e3816e664797050&dn=gpl-3.0.txt GPL-v3
2 |
3 | import browser from "webextension-polyfill";
4 | import { inject_gm_api } from "@/userscripts/wrapper";
5 |
6 | export async function is_iitc_enabled() {
7 | const status = await browser.storage.local
8 | .get(["IITC_is_enabled"])
9 | .then((data) => data["IITC_is_enabled"]);
10 | return status !== false;
11 | }
12 |
13 | export function is_userscripts_api_available() {
14 | try {
15 | // Property access which throws if developer mode is not enabled.
16 | return browser.userScripts !== undefined;
17 | } catch {
18 | // Not available.
19 | return false;
20 | }
21 | }
22 |
23 | export const init_userscripts_api = () => {
24 | if (!is_userscripts_api_available()) return;
25 | try {
26 | browser.userScripts.configureWorld({
27 | csp: "script-src 'self' 'unsafe-inline'",
28 | messaging: true,
29 | });
30 | inject_gm_api();
31 | // eslint-disable-next-line no-empty
32 | } catch {}
33 | };
34 |
--------------------------------------------------------------------------------
/src/userscripts/wrapper.js:
--------------------------------------------------------------------------------
1 | //@license magnet:?xt=urn:btih:1f739d935676111cfff4b4693e3816e664797050&dn=gpl-3.0.txt GPL-v3
2 |
3 | import browser from "webextension-polyfill";
4 | import { IS_USERSCRIPTS_API } from "@/userscripts/env";
5 | import { manage_userscripts_api } from "@/background/injector";
6 | import { strToBase64 } from "@/strToBase64";
7 | import { getUID } from "lib-iitc-manager";
8 | import { GM } from "@/userscripts/gm-api";
9 |
10 | function getPluginHash(uid) {
11 | return "VMin" + strToBase64(uid);
12 | }
13 |
14 | function inject(code) {
15 | const script = document.createElement("script");
16 | script.appendChild(document.createTextNode(code));
17 | (document.body || document.head || document.documentElement).appendChild(
18 | script
19 | );
20 | script.parentElement.removeChild(script);
21 | }
22 |
23 | export function inject_gm_api() {
24 | const plugin = {
25 | uid: "gm_api",
26 | code: `((${GM.toString()}))()\n//# sourceURL=${browser.runtime.getURL(
27 | "js/GM_api.js"
28 | )}`,
29 | };
30 |
31 | if (IS_USERSCRIPTS_API) {
32 | const plugins_event = {
33 | event: "add",
34 | use_gm_api: false,
35 | plugins: [plugin],
36 | };
37 | manage_userscripts_api(plugins_event).then();
38 | } else {
39 | inject(plugin.code);
40 | }
41 | }
42 |
43 | export async function gm_api_for_plugin(plugin, tab_id) {
44 | const uid = plugin.uid ? plugin.uid : getUID(plugin);
45 | let data_key = getPluginHash(uid);
46 | const name = encodeURIComponent(plugin.name);
47 |
48 | const meta = { ...plugin };
49 | delete meta.code;
50 |
51 | return [
52 | "((GM)=>{",
53 | // an implementation of GM API v3 based on GM API v4
54 | "const GM_info = GM.info; const unsafeWindow = window;",
55 | "const exportFunction = GM.exportFunction; const createObjectIn = GM.createObjectIn; const cloneInto = GM.cloneInto;",
56 | "const GM_getValue = (key, value) => GM._getValueSync(key, value);",
57 | "const GM_setValue = (key, value) => GM._setValueSync(key, value);",
58 | "const GM_xmlhttpRequest = (details) => GM.xmlHttpRequest(details);",
59 |
60 | plugin.code,
61 | // adding a new line in case the code ends with a line comment
62 | plugin.code.endsWith("\n") ? "" : "\n",
63 | `})(GM("${data_key}", ${tab_id}, ${JSON.stringify(meta)}))`,
64 |
65 | // Firefox lists .user.js among our own content scripts so a space at start will group them
66 | `\n//# sourceURL=${browser.runtime.getURL(
67 | "plugins/%20" + name + ".user.js"
68 | )}`,
69 | ].join("");
70 | }
71 |
--------------------------------------------------------------------------------
/src/uuid.js:
--------------------------------------------------------------------------------
1 | //@license magnet:?xt=urn:btih:1f739d935676111cfff4b4693e3816e664797050&dn=gpl-3.0.txt GPL-v3
2 |
3 | export function uuidv4() {
4 | return ([1e7] + -1e3 + -4e3 + -8e3 + -1e11).replace(/[018]/g, (c) =>
5 | (
6 | c ^
7 | (crypto.getRandomValues(new Uint8Array(1))[0] & (15 >> (c / 4)))
8 | ).toString(16)
9 | );
10 | }
11 |
--------------------------------------------------------------------------------
/src/xhr-sandbox.js:
--------------------------------------------------------------------------------
1 | //@license magnet:?xt=urn:btih:1f739d935676111cfff4b4693e3816e664797050&dn=gpl-3.0.txt GPL-v3
2 |
3 | // XHR Handler for sandbox iframe
4 | window.addEventListener("message", (event) => {
5 | if (event.data && event.data.type === "xhr_request") {
6 | const data = event.data;
7 | const req = new XMLHttpRequest();
8 |
9 | // Function to send response
10 | const sendResponse = (response) => {
11 | try {
12 | window.parent.postMessage(
13 | {
14 | type: "xhr_response",
15 | uuid: data.uuid,
16 | response: response,
17 | },
18 | "*"
19 | );
20 | } catch (error) {
21 | console.error("IITC Button XHR Sandbox: error sending response", error);
22 | }
23 | };
24 |
25 | // Event handlers
26 | req.onload = function () {
27 | sendResponse({
28 | readyState: this.readyState,
29 | responseHeaders: this.getAllResponseHeaders(),
30 | responseText: this.responseText,
31 | status: this.status,
32 | statusText: this.statusText,
33 | });
34 | };
35 |
36 | req.onerror = function () {
37 | sendResponse({
38 | readyState: this.readyState,
39 | status: 0,
40 | statusText: "Error",
41 | responseText: "",
42 | responseHeaders: "",
43 | });
44 | };
45 |
46 | req.ontimeout = function () {
47 | sendResponse({
48 | readyState: this.readyState,
49 | status: 0,
50 | statusText: "Timeout",
51 | responseText: "",
52 | responseHeaders: "",
53 | });
54 | };
55 |
56 | try {
57 | // Open connection
58 | req.open(data.method, data.url, true, data.user, data.password);
59 |
60 | // Set headers
61 | if (data.headers) {
62 | for (const [name, value] of Object.entries(data.headers)) {
63 | req.setRequestHeader(name, value);
64 | }
65 | }
66 |
67 | // Additional settings
68 | if (data.overrideMimeType) req.overrideMimeType(data.overrideMimeType);
69 | if (data.timeout) req.timeout = data.timeout;
70 | if (data.withCredentials) req.withCredentials = true;
71 |
72 | // Send request
73 | req.send(data.data);
74 | } catch (error) {
75 | sendResponse({
76 | readyState: 0,
77 | status: 0,
78 | statusText: "Error: " + error.message,
79 | responseText: "",
80 | responseHeaders: "",
81 | });
82 | }
83 | }
84 | });
85 |
--------------------------------------------------------------------------------