Compare commits

..

89 Commits

Author SHA1 Message Date
RiotRobot
ad337b1f7c v1.7.32 2021-07-05 16:55:20 +01:00
RiotRobot
8d380fe533 Prepare changelog for v1.7.32 2021-07-05 16:55:19 +01:00
David Baker
6e7913c7d1 Merge pull request #224 from vector-im/dbkr/fix_rootdir
Fix the build: make the rootDir correct
2021-07-01 17:33:36 +01:00
David Baker
9cb171f953 Fix the build: make the rootDir correct 2021-07-01 17:18:26 +01:00
David Baker
44310712f3 Merge pull request #223 from vector-im/t3chguy/ts/10
Fix i18n in Element Desktop
2021-07-01 15:51:31 +01:00
Michael Telatynski
9b65962d26 Update scripts/copy-res.js
Co-authored-by: J. Ryan Stinnett <jryans@gmail.com>
2021-07-01 15:48:07 +01:00
Michael Telatynski
8302e284a3 delint 2021-07-01 12:03:38 +01:00
Michael Telatynski
390e2306d0 Fix i18n in Element Desktop 2021-07-01 11:32:09 +01:00
Michael Telatynski
60e61415ea Merge pull request #222 from vector-im/t3chguy/ts/10 2021-07-01 09:26:42 +01:00
Michael Telatynski
f4be51959b disable require lint rule in couple more places 2021-07-01 09:24:02 +01:00
Michael Telatynski
397bc66522 fix ts linting and delint the world 2021-07-01 09:22:57 +01:00
Michael Telatynski
4db0a0ac0c Make eslint happy 2021-07-01 09:16:49 +01:00
Michael Telatynski
d353c68a75 Convert preload.js to Typescript so that it gets copied to lib where we expect it 2021-07-01 09:11:42 +01:00
David Baker
0143b4b114 Merge pull request #221 from vector-im/dbkr/lib_not_src
Bundle the `lib` dir now, not `src`
2021-06-30 19:14:40 +01:00
David Baker
93dd8aa2ba Bbundle the lib dir now, not src 2021-06-30 18:56:48 +01:00
Michael Telatynski
140b0b8c29 Merge pull request #219 from vector-im/t3chguy/ts/d 2021-06-30 17:55:25 +01:00
David Baker
744050d8f4 Electron 12.0.12 2021-06-29 14:16:52 +01:00
David Baker
39f3e3b9c2 Merge pull request #220 from RiotTranslateBot/weblate-element-desktop-element-desktop
Translations update from Weblate
2021-06-29 14:14:43 +01:00
Weblate
43c8b13d75 Merge branch 'origin/develop' into Weblate. 2021-06-29 13:08:43 +00:00
Michael Telatynski
2d568f9688 iterate ts support 2021-06-29 11:41:08 +01:00
J. Ryan Stinnett
3f49046980 Merge pull request #218 from vector-im/jryans/aarch64-apple-darwin
Fix Windows target arch in native build
2021-06-25 14:36:05 +01:00
Michael Telatynski
53e7100033 Initial Typescripting for Element Desktop 2021-06-25 14:35:58 +01:00
J. Ryan Stinnett
b8cb53e11b Fix Windows target arch in native build 2021-06-25 13:10:08 +01:00
J. Ryan Stinnett
c751470abf Merge pull request #217 from vector-im/jryans/libera-chat
Add libera.chat to default room directory
2021-06-25 11:24:16 +01:00
J. Ryan Stinnett
9860ac6b75 Add libera.chat to default room directory 2021-06-25 10:59:16 +01:00
J. Ryan Stinnett
6e76d658b1 Merge pull request #216 from vector-im/jryans/aarch64-apple-darwin
Add update and native build support for Apple silicon
2021-06-24 15:37:02 +01:00
J. Ryan Stinnett
3aff9cb9eb Add generated file warning 2021-06-24 15:20:24 +01:00
J. Ryan Stinnett
6579ba80b4 More copyright headers 2021-06-24 15:11:57 +01:00
J. Ryan Stinnett
37410e6bc4 Log update URL 2021-06-24 14:45:35 +01:00
J. Ryan Stinnett
b036113786 Revert "Prefer machine's native arch on macOS"
This reverts commit ebcd68428e.
2021-06-24 14:44:59 +01:00
Ridhubharan
c579031afc Translated using Weblate (Tamil)
Currently translated at 100.0% (44 of 44 strings)

Translation: Element Desktop/element-desktop
Translate-URL: https://translate.element.io/projects/element-desktop/element-desktop/ta/
2021-06-23 19:34:45 +00:00
J. Ryan Stinnett
ebcd68428e Prefer machine's native arch on macOS
This uses `uname` to check the machine's native architecture, and tries to
prefer builds for that, rather than continuing to use emulation.
2021-06-23 16:42:00 +01:00
J. Ryan Stinnett
f63436a2cb Send the current arch when updating
This depends on further builder changes to actually place updates at this new
location for both architectures.
2021-06-23 16:18:10 +01:00
J. Ryan Stinnett
c5dd6195f2 Fix copy command log 2021-06-23 16:18:10 +01:00
J. Ryan Stinnett
c3a36bb17d Cross-compile matrix-seshat for aarch64-apple-darwin 2021-06-23 16:18:09 +01:00
J. Ryan Stinnett
f3c1db3313 Cross-compile SQLCipher for aarch64-apple-darwin 2021-06-23 16:18:09 +01:00
J. Ryan Stinnett
c57a173649 Check for Rust host and target support 2021-06-23 16:18:09 +01:00
J. Ryan Stinnett
48dc1ab396 Print rejections that reach the root handler 2021-06-23 16:18:09 +01:00
J. Ryan Stinnett
997f2c21bf Use targets in hak environment for cross-compiling
This arranges the hak environment target info around target IDs that come from
the builder, which simplifies cross-compiling. The `target.js` module is a
generated copy of the builder's `target.ts`.
2021-06-23 16:18:09 +01:00
J. Ryan Stinnett
a171fa417b Borrow target definition from electron-builder
A bit hacky, but for now we paste in the JS generated version of the builder's
`target.ts` module. It's quite unlikely to change often, so this is perhaps
enough for now.
2021-06-23 16:18:09 +01:00
J. Ryan Stinnett
115f25165a Rename hak target to runtime version
The hak environment's `target` is more like a runtime version, so this renames
to call it that, especially since we're about to add more traditional target
strings. `npm_config_target` remains, since that's what `npm` expects.
2021-06-23 16:18:09 +01:00
J. Ryan Stinnett
c1ca909c7c Limit macOS updates to x86_64 temporarily
As a temporary measure, this limits the updater on macOS to only supporting the
`x86_64` / `x64` architecture. This ensures `aarch64` users are not
inadvertently kicked back to `x86_64`.
2021-06-23 16:18:09 +01:00
Travis Ralston
f61370505b Merge pull request #203 from dogancelik/numpad-zoom
Add numpad accelerators for zooming
2021-06-22 19:42:49 -06:00
Travis Ralston
02d0999b18 Merge pull request #201 from aaronraimist/invalid-config
Add warning dialog when custom config.json is invalid
2021-06-22 14:16:24 -06:00
Ridhubharan
5b15bc9b5d Added translation using Weblate (Tamil) 2021-06-22 17:30:41 +00:00
Michael Telatynski
6b4e6f6be6 Merge pull request #215 from alarsyo/develop 2021-06-22 15:43:27 +01:00
Antoine Martin
10a11242ff Don't show Quit warning on keyUp residual event
The warning triggered whenever the app got focus after another window
was closed with a Ctrl+Q shortcut and the keys were then released.

Hitting the 'Close Element' button didn't even close the app in this
case, as only the warning handler was triggered, not the actual quit
shortcut (which does discriminate between key press and key release).

Actually checking for 'keyDown' should prevent this from occurring
again.

Fixes vector-im/element-web#17714

Signed-off-by: Antoine Martin <antoine@alarsyo.net>
2021-06-22 16:35:36 +02:00
Michael Telatynski
e59a2588ec Merge pull request #213 from vector-im/t3chguy/fix/17631
Fix accelerator for save-image-as clashing with copy-link-address
2021-06-22 09:27:18 +01:00
RiotRobot
a7938ae514 v1.7.31 2021-06-21 17:10:17 +01:00
RiotRobot
cf3112a9a9 Prepare changelog for v1.7.31 2021-06-21 17:10:17 +01:00
RiotRobot
b23048c5ce v1.7.31-rc.1 2021-06-15 17:35:25 +01:00
RiotRobot
c689529641 Prepare changelog for v1.7.31-rc.1 2021-06-15 17:35:24 +01:00
J. Ryan Stinnett
7b6ead738e Merge pull request #211 from xvenge00/electron-12.0.11
Upgrade to Electron 12.0.11
2021-06-15 15:44:37 +01:00
J. Ryan Stinnett
b6b5547ad0 Merge pull request #214 from RiotTranslateBot/weblate-element-desktop-element-desktop
Translations update from Weblate
2021-06-15 15:42:56 +01:00
Weblate
e28390fddb Merge branch 'origin/develop' into Weblate. 2021-06-15 14:42:37 +00:00
Michael Telatynski
b18bcd9bed Fix accelerator for save-image-as clashing with copy-link-address 2021-06-14 22:38:37 +01:00
J. Ryan Stinnett
b470657cdb Merge pull request #212 from vector-im/jryans/node-14
Upgrade to Node 14
2021-06-14 13:46:25 +01:00
J. Ryan Stinnett
fc51063f7a Upgrade to Node 14 2021-06-14 12:17:15 +01:00
lvre
099ecc468a Translated using Weblate (Portuguese (Brazil))
Currently translated at 100.0% (44 of 44 strings)

Translation: Element Desktop/element-desktop
Translate-URL: https://translate.element.io/projects/element-desktop/element-desktop/pt_BR/
2021-06-13 00:33:52 +00:00
Adam Venger
99b5947d7d Upgrade to Electron 12.0.11
Signed-off-by: Adam Venger <jawe1222@gmail.com>
2021-06-12 21:55:23 +02:00
lvre
7418161475 Translated using Weblate (Portuguese (Brazil))
Currently translated at 100.0% (44 of 44 strings)

Translation: Element Desktop/element-desktop
Translate-URL: https://translate.element.io/projects/element-desktop/element-desktop/pt_BR/
2021-06-11 22:08:08 +00:00
J. Ryan Stinnett
40be024c9f Merge pull request #210 from vector-im/dependabot/npm_and_yarn/npm-registry-fetch-4.0.7
Bump npm-registry-fetch from 4.0.2 to 4.0.7
2021-06-11 13:41:42 +01:00
J. Ryan Stinnett
b2f09570f7 Merge pull request #204 from pavlukivan/update-electron-builder
Update electron-builder for Node 16 compatibility
2021-06-11 13:40:54 +01:00
dependabot[bot]
c3f150f9f0 Bump npm-registry-fetch from 4.0.2 to 4.0.7
Bumps [npm-registry-fetch](https://github.com/npm/npm-registry-fetch) from 4.0.2 to 4.0.7.
- [Release notes](https://github.com/npm/npm-registry-fetch/releases)
- [Changelog](https://github.com/npm/npm-registry-fetch/blob/v4.0.7/CHANGELOG.md)
- [Commits](https://github.com/npm/npm-registry-fetch/compare/v4.0.2...v4.0.7)

---
updated-dependencies:
- dependency-name: npm-registry-fetch
  dependency-type: indirect
...

Signed-off-by: dependabot[bot] <support@github.com>
2021-06-11 12:40:41 +00:00
J. Ryan Stinnett
8a90a12683 Merge pull request #209 from vector-im/dependabot/npm_and_yarn/hosted-git-info-2.8.9
Bump hosted-git-info from 2.8.5 to 2.8.9
2021-06-11 13:40:04 +01:00
J. Ryan Stinnett
e7bc785ae4 Merge pull request #206 from vector-im/dependabot/npm_and_yarn/glob-parent-5.1.2
Bump glob-parent from 5.1.1 to 5.1.2
2021-06-11 13:39:54 +01:00
J. Ryan Stinnett
d1cb3092e8 Merge pull request #208 from vector-im/dependabot/npm_and_yarn/dot-prop-4.2.1
Bump dot-prop from 4.2.0 to 4.2.1
2021-06-11 13:39:48 +01:00
J. Ryan Stinnett
a136ccbf4c Merge pull request #207 from vector-im/dependabot/npm_and_yarn/y18n-3.2.2
Bump y18n from 3.2.1 to 3.2.2
2021-06-11 13:39:38 +01:00
dependabot[bot]
231db351ec Bump hosted-git-info from 2.8.5 to 2.8.9
Bumps [hosted-git-info](https://github.com/npm/hosted-git-info) from 2.8.5 to 2.8.9.
- [Release notes](https://github.com/npm/hosted-git-info/releases)
- [Changelog](https://github.com/npm/hosted-git-info/blob/v2.8.9/CHANGELOG.md)
- [Commits](https://github.com/npm/hosted-git-info/compare/v2.8.5...v2.8.9)

---
updated-dependencies:
- dependency-name: hosted-git-info
  dependency-type: indirect
...

Signed-off-by: dependabot[bot] <support@github.com>
2021-06-11 12:27:54 +00:00
dependabot[bot]
06b0f0fe01 Bump dot-prop from 4.2.0 to 4.2.1
Bumps [dot-prop](https://github.com/sindresorhus/dot-prop) from 4.2.0 to 4.2.1.
- [Release notes](https://github.com/sindresorhus/dot-prop/releases)
- [Commits](https://github.com/sindresorhus/dot-prop/compare/v4.2.0...v4.2.1)

---
updated-dependencies:
- dependency-name: dot-prop
  dependency-type: indirect
...

Signed-off-by: dependabot[bot] <support@github.com>
2021-06-11 12:27:52 +00:00
dependabot[bot]
4b71142a87 Bump glob-parent from 5.1.1 to 5.1.2
Bumps [glob-parent](https://github.com/gulpjs/glob-parent) from 5.1.1 to 5.1.2.
- [Release notes](https://github.com/gulpjs/glob-parent/releases)
- [Changelog](https://github.com/gulpjs/glob-parent/blob/main/CHANGELOG.md)
- [Commits](https://github.com/gulpjs/glob-parent/compare/v5.1.1...v5.1.2)

---
updated-dependencies:
- dependency-name: glob-parent
  dependency-type: indirect
...

Signed-off-by: dependabot[bot] <support@github.com>
2021-06-11 12:27:51 +00:00
dependabot[bot]
9726be5754 Bump y18n from 3.2.1 to 3.2.2
Bumps [y18n](https://github.com/yargs/y18n) from 3.2.1 to 3.2.2.
- [Release notes](https://github.com/yargs/y18n/releases)
- [Changelog](https://github.com/yargs/y18n/blob/master/CHANGELOG.md)
- [Commits](https://github.com/yargs/y18n/commits)

---
updated-dependencies:
- dependency-name: y18n
  dependency-type: indirect
...

Signed-off-by: dependabot[bot] <support@github.com>
2021-06-11 12:27:51 +00:00
J. Ryan Stinnett
2293b6794c Merge pull request #205 from vector-im/dependabot/npm_and_yarn/normalize-url-4.5.1
Bump normalize-url from 4.5.0 to 4.5.1
2021-06-11 13:27:23 +01:00
Ivan Pavluk
492bbcbe06 update electron-builder-squirrel-windows 2021-06-11 00:30:11 +07:00
dependabot[bot]
9cc1d91011 Bump normalize-url from 4.5.0 to 4.5.1
Bumps [normalize-url](https://github.com/sindresorhus/normalize-url) from 4.5.0 to 4.5.1.
- [Release notes](https://github.com/sindresorhus/normalize-url/releases)
- [Commits](https://github.com/sindresorhus/normalize-url/commits)

---
updated-dependencies:
- dependency-name: normalize-url
  dependency-type: indirect
...

Signed-off-by: dependabot[bot] <support@github.com>
2021-06-10 17:18:11 +00:00
Zachinquarantine
c08b62015e Translated using Weblate (Croatian)
Currently translated at 25.0% (11 of 44 strings)

Translation: Element Desktop/element-desktop
Translate-URL: https://translate.element.io/projects/element-desktop/element-desktop/hr/
2021-06-08 18:34:39 +00:00
Zachinquarantine
03abf9f9d0 Added translation using Weblate (Croatian) 2021-06-07 18:26:19 +00:00
RiotRobot
69e4ec7287 Merge branch 'master' into develop 2021-06-07 17:54:39 +01:00
Ivan Pavlyuk
57ba22f874 Update electron-builder (Node 16 compat) 2021-06-07 23:25:13 +07:00
Doğan Çelik
225456b8e0 Add numpad accelerators for zooming
Signed-off-by: Doğan Çelik <dogancelik93@gmail.com>
2021-06-05 16:29:26 +03:00
Aaron Raimist
03e59aa60c Remove translation
Signed-off-by: Aaron Raimist <aaron@raim.ist>
2021-06-04 17:18:02 -05:00
Michael Telatynski
330e230f2c Merge pull request #200 from aaronraimist/macos-preferences 2021-06-04 09:53:30 +01:00
Michael Telatynski
dee2ecdf6c Merge pull request #202 from aaronraimist/zoomin 2021-06-04 09:50:18 +01:00
Aaron Raimist
f109065606 lint
Signed-off-by: Aaron Raimist <aaron@raim.ist>
2021-06-04 00:23:02 -05:00
Aaron Raimist
344800d835 Remove accelerator
Signed-off-by: Aaron Raimist <aaron@raim.ist>
2021-06-04 00:16:51 -05:00
Aaron Raimist
8c99f0ad12 Switch zoomIn accelerator to CommandOrControl+Plus
Signed-off-by: Aaron Raimist <aaron@raim.ist>
2021-06-04 00:07:05 -05:00
Aaron Raimist
bc0e3bb317 Add warning dialog when custom config.json is invalid
Signed-off-by: Aaron Raimist <aaron@raim.ist>
2021-06-03 23:39:33 -05:00
Aaron Raimist
b7e4e9e075 Follow HIG: use ellipsis for Preferences menu item, add app name to About menu item
Signed-off-by: Aaron Raimist <aaron@raim.ist>
2021-06-03 23:07:28 -05:00
Aaron Raimist
5055ad0aec Put Preferences menu item in correct location on macOS
Signed-off-by: Aaron Raimist <aaron@raim.ist>
2021-06-03 22:56:06 -05:00
30 changed files with 1702 additions and 624 deletions

View File

@@ -1,7 +1,5 @@
module.exports = {
plugins: [
"matrix-org",
],
plugins: ["matrix-org"],
extends: [
"plugin:matrix-org/javascript",
],
@@ -19,5 +17,19 @@ module.exports = {
"indent": "off",
"prefer-promise-reject-errors": "off",
"no-async-promise-executor": "off",
}
}
},
overrides: [{
files: ["src/**/*.{ts,tsx}"],
extends: [
"plugin:matrix-org/typescript",
],
rules: {
// Things we do that break the ideal style
"prefer-promise-reject-errors": "off",
"quotes": "off",
// We disable this while we're transitioning
"@typescript-eslint/no-explicit-any": "off",
},
}],
};

1
.gitignore vendored
View File

@@ -1,4 +1,5 @@
/dist
/lib
/webapp
/webapp.asar
/packages

View File

@@ -1,3 +1,69 @@
Changes in [1.7.32](https://github.com/vector-im/element-desktop/releases/tag/v1.7.32) (2021-07-05)
===================================================================================================
[Full Changelog](https://github.com/vector-im/element-desktop/compare/v1.7.31...v1.7.32)
* Fix the build: make the rootDir correct
[\#224](https://github.com/vector-im/element-desktop/pull/224)
* Fix i18n in Element Desktop
[\#223](https://github.com/vector-im/element-desktop/pull/223)
* Convert preload.js to Typescript so that it gets copied to `lib`
[\#222](https://github.com/vector-im/element-desktop/pull/222)
* Bundle the `lib` dir now, not `src`
[\#221](https://github.com/vector-im/element-desktop/pull/221)
* Initial Typescripting for Element Desktop
[\#219](https://github.com/vector-im/element-desktop/pull/219)
* Translations update from Weblate
[\#220](https://github.com/vector-im/element-desktop/pull/220)
* Fix Windows target arch in native build
[\#218](https://github.com/vector-im/element-desktop/pull/218)
* Add libera.chat to default room directory
[\#217](https://github.com/vector-im/element-desktop/pull/217)
* Add update and native build support for Apple silicon
[\#216](https://github.com/vector-im/element-desktop/pull/216)
* Add numpad accelerators for zooming
[\#203](https://github.com/vector-im/element-desktop/pull/203)
* Add warning dialog when custom config.json is invalid
[\#201](https://github.com/vector-im/element-desktop/pull/201)
* Don't show Quit warning on keyUp residual event
[\#215](https://github.com/vector-im/element-desktop/pull/215)
* Fix accelerator for save-image-as clashing with copy-link-address
[\#213](https://github.com/vector-im/element-desktop/pull/213)
Changes in [1.7.31](https://github.com/vector-im/element-desktop/releases/tag/v1.7.31) (2021-06-21)
===================================================================================================
[Full Changelog](https://github.com/vector-im/element-desktop/compare/v1.7.31-rc.1...v1.7.31)
* No changes since rc.1
Changes in [1.7.31-rc.1](https://github.com/vector-im/element-desktop/releases/tag/v1.7.31-rc.1) (2021-06-15)
=============================================================================================================
[Full Changelog](https://github.com/vector-im/element-desktop/compare/v1.7.30...v1.7.31-rc.1)
* Upgrade to Electron 12.0.11
[\#211](https://github.com/vector-im/element-desktop/pull/211)
* Translations update from Weblate
[\#214](https://github.com/vector-im/element-desktop/pull/214)
* Upgrade to Node 14
[\#212](https://github.com/vector-im/element-desktop/pull/212)
* Bump npm-registry-fetch from 4.0.2 to 4.0.7
[\#210](https://github.com/vector-im/element-desktop/pull/210)
* Update electron-builder for Node 16 compatibility
[\#204](https://github.com/vector-im/element-desktop/pull/204)
* Bump hosted-git-info from 2.8.5 to 2.8.9
[\#209](https://github.com/vector-im/element-desktop/pull/209)
* Bump glob-parent from 5.1.1 to 5.1.2
[\#206](https://github.com/vector-im/element-desktop/pull/206)
* Bump dot-prop from 4.2.0 to 4.2.1
[\#208](https://github.com/vector-im/element-desktop/pull/208)
* Bump y18n from 3.2.1 to 3.2.2
[\#207](https://github.com/vector-im/element-desktop/pull/207)
* Bump normalize-url from 4.5.0 to 4.5.1
[\#205](https://github.com/vector-im/element-desktop/pull/205)
* Put Preferences menu item in correct location on macOS
[\#200](https://github.com/vector-im/element-desktop/pull/200)
* Switch zoomIn accelerator to default
[\#202](https://github.com/vector-im/element-desktop/pull/202)
Changes in [1.7.30](https://github.com/vector-im/element-desktop/releases/tag/v1.7.30) (2021-06-07)
===================================================================================================
[Full Changelog](https://github.com/vector-im/element-desktop/compare/v1.7.30-rc.1...v1.7.30)

View File

@@ -30,7 +30,7 @@ ENV LC_ALL C.UTF-8
ENV DEBUG_COLORS true
ENV FORCE_COLOR true
ENV NODE_VERSION 12.16.1
ENV NODE_VERSION 14.17.0
# this package is used for snapcraft and we should not clear apt list - to avoid apt-get update during snap build
RUN curl -L https://nodejs.org/dist/v$NODE_VERSION/node-v$NODE_VERSION-linux-x64.tar.gz | tar xz -C /usr/local --strip-components=1 && \

View File

@@ -22,7 +22,8 @@
"roomDirectory": {
"servers": [
"matrix.org",
"gitter.im"
"gitter.im",
"libera.chat"
]
},
"enable_presence_by_hs_url": {

View File

@@ -16,7 +16,8 @@
"roomDirectory": {
"servers": [
"matrix.org",
"gitter.im"
"gitter.im",
"libera.chat"
]
},
"showLabsSettings": false,

View File

@@ -1,5 +1,5 @@
/*
Copyright 2020 The Matrix.org Foundation C.I.C.
Copyright 2020-2021 The Matrix.org Foundation C.I.C.
Licensed under the Apache License, Version 2.0 (the "License");
you may not use this file except in compliance with the License.
@@ -34,7 +34,7 @@ async function buildOpenSslWin(hakEnv, moduleInfo) {
const version = moduleInfo.cfg.dependencies.openssl;
const openSslDir = path.join(moduleInfo.moduleDotHakDir, `openssl-${version}`);
const openSslArch = hakEnv.arch === 'x64' ? 'VC-WIN64A' : 'VC-WIN32';
const openSslArch = hakEnv.getTargetArch() === 'x64' ? 'VC-WIN64A' : 'VC-WIN32';
console.log("Building openssl in " + openSslDir);
await new Promise((resolve, reject) => {
@@ -182,9 +182,36 @@ async function buildSqlCipherUnix(hakEnv, moduleInfo) {
if (hakEnv.isMac()) {
args.push('--with-crypto-lib=commoncrypto');
}
args.push('CFLAGS=-DSQLITE_HAS_CODEC');
if (!hakEnv.isHost()) {
// In the nonsense world of `configure`, it is assumed you are building
// a compiler like `gcc`, so the `host` option actually means the target
// the build output runs on.
args.push(`--host=${hakEnv.getTargetId()}`);
}
const cflags = [
'-DSQLITE_HAS_CODEC',
];
if (!hakEnv.isHost()) {
// `clang` uses more logical option naming.
cflags.push(`--target=${hakEnv.getTargetId()}`);
}
if (cflags.length) {
args.push(`CFLAGS=${cflags.join(' ')}`);
}
const ldflags = [];
if (hakEnv.isMac()) {
args.push('LDFLAGS=-framework Security -framework Foundation');
ldflags.push('-framework Security');
ldflags.push('-framework Foundation');
}
if (ldflags.length) {
args.push(`LDFLAGS=${ldflags.join(' ')}`);
}
await new Promise((resolve, reject) => {
@@ -248,7 +275,11 @@ async function buildMatrixSeshat(hakEnv, moduleInfo) {
// the build scripts since they run on the host, but vcvarsall.bat sets the c
// compiler in the path to be the one for the target, so we just use the matching
// toolchain for the target architecture which makes everything happy.
env.RUSTUP_TOOLCHAIN = hakEnv.arch == 'x64' ? 'stable-x86_64-pc-windows-msvc' : 'stable-i686-pc-windows-msvc';
env.RUSTUP_TOOLCHAIN = `stable-${hakEnv.getTargetId()}`;
}
if (!hakEnv.isHost()) {
env.CARGO_BUILD_TARGET = hakEnv.getTargetId();
}
console.log("Running neon with env", env);

View File

@@ -1,5 +1,5 @@
/*
Copyright 2020 The Matrix.org Foundation C.I.C.
Copyright 2020-2021 The Matrix.org Foundation C.I.C.
Licensed under the Apache License, Version 2.0 (the "License");
you may not use this file except in compliance with the License.
@@ -34,7 +34,10 @@ module.exports = async function(hakEnv, moduleInfo) {
});
}
const tools = [['python', '--version']]; // node-gyp uses python for reasons beyond comprehension
const tools = [
['rustc', '--version'],
['python', '--version'], // node-gyp uses python for reasons beyond comprehension
];
if (hakEnv.isWin()) {
tools.push(['perl', '--version']); // for openssl configure
tools.push(['patch', '--version']); // to patch sqlcipher Makefile.msc
@@ -57,4 +60,18 @@ module.exports = async function(hakEnv, moduleInfo) {
});
});
}
// Ensure Rust target exists
await new Promise((resolve, reject) => {
childProcess.execFile('rustup', ['target', 'list', '--installed'], (err, out) => {
if (err) {
reject("Can't find rustup");
}
const target = hakEnv.getTargetId();
if (!out.includes(target)) {
reject(`Rust target ${target} not installed`);
}
resolve();
});
});
};

View File

@@ -1,8 +1,8 @@
{
"name": "element-desktop",
"productName": "Element",
"main": "src/electron-main.js",
"version": "1.7.30",
"main": "lib/electron-main.js",
"version": "1.7.32",
"description": "A feature-rich client for Matrix.org",
"author": "Element",
"repository": {
@@ -18,18 +18,22 @@
"mkdirs": "mkdirp packages deploys",
"fetch": "yarn run mkdirs && node scripts/fetch-package.js",
"asar-webapp": "asar p webapp webapp.asar",
"start": "electron .",
"lint": "eslint src/ scripts/ hak/",
"start": "yarn run build:ts && yarn run build:res && electron .",
"lint": "yarn lint:types && yarn lint:js",
"lint:js": "eslint src/ scripts/ hak/",
"lint:types": "tsc --noEmit",
"build:native": "yarn run hak",
"build32": "electron-builder --ia32",
"build64": "electron-builder --x64",
"build": "electron-builder",
"build32": "yarn run build:ts && yarn run build:res && electron-builder --ia32",
"build64": "yarn run build:ts && yarn run build:res && electron-builder --x64",
"build": "yarn run build:ts && yarn run build:res && electron-builder",
"build:ts": "tsc",
"build:res": "node scripts/copy-res.js",
"docker:setup": "docker build -t element-desktop-dockerbuild dockerbuild",
"docker:build:native": "scripts/in-docker.sh yarn run hak",
"docker:build": "scripts/in-docker.sh yarn run build",
"docker:install": "scripts/in-docker.sh yarn install",
"debrepo": "scripts/mkrepo.sh",
"clean": "rimraf webapp.asar dist packages deploys",
"clean": "rimraf webapp.asar dist packages deploys lib",
"hak": "node scripts/hak/index.js"
},
"dependencies": {
@@ -42,9 +46,16 @@
"request": "^2.88.2"
},
"devDependencies": {
"@types/auto-launch": "^5.0.1",
"@types/counterpart": "^0.18.1",
"@types/minimist": "^1.2.1",
"@typescript-eslint/eslint-plugin": "^4.17.0",
"@typescript-eslint/parser": "^4.17.0",
"asar": "^2.0.1",
"electron-builder": "22.10.5",
"electron-builder-squirrel-windows": "22.10.5",
"chokidar": "^3.5.2",
"electron": "12.0.11",
"electron-builder": "22.11.4",
"electron-builder-squirrel-windows": "22.11.4",
"electron-devtools-installer": "^3.1.1",
"electron-notarize": "^1.0.0",
"eslint": "7.18.0",
@@ -60,7 +71,8 @@
"npm": "^6.14.11",
"rimraf": "^3.0.2",
"semver": "^7.3.4",
"tar": "^6.1.0"
"tar": "^6.1.0",
"typescript": "^4.1.3"
},
"hakDependencies": {
"matrix-seshat": "^2.2.3",
@@ -68,14 +80,14 @@
},
"build": {
"appId": "im.riot.app",
"electronVersion": "12.0.9",
"electronVersion": "12.0.12",
"files": [
"package.json",
{
"from": ".hak/hakModules",
"to": "node_modules"
},
"src/**"
"lib/**"
],
"extraResources": [
{

121
scripts/copy-res.js Executable file
View File

@@ -0,0 +1,121 @@
#!/usr/bin/env node
// copies resources into the lib directory.
const parseArgs = require('minimist');
const chokidar = require('chokidar');
const path = require('path');
const fs = require('fs');
const argv = parseArgs(process.argv.slice(2), {});
const watch = argv.w;
const verbose = argv.v;
function errCheck(err) {
if (err) {
console.error(err.message);
process.exit(1);
}
}
const I18N_BASE_PATH = "src/i18n/strings/";
const INCLUDE_LANGS = fs.readdirSync(I18N_BASE_PATH).filter(fn => fn.endsWith(".json"));
// Ensure lib, lib/i18n and lib/i18n/strings all exist
fs.mkdirSync('lib/i18n/strings', { recursive: true });
function genLangFile(file, dest) {
let translations = {};
[file].forEach(function(f) {
if (fs.existsSync(f)) {
try {
Object.assign(
translations,
JSON.parse(fs.readFileSync(f).toString()),
);
} catch (e) {
console.error("Failed: " + f, e);
throw e;
}
}
});
translations = weblateToCounterpart(translations);
const json = JSON.stringify(translations, null, 4);
const filename = path.basename(file);
fs.writeFileSync(dest + filename, json);
if (verbose) {
console.log("Generated language file: " + filename);
}
}
/*
* Convert translation key from weblate format
* (which only supports a single level) to counterpart
* which requires object values for 'count' translations.
*
* eg.
* "there are %(count)s badgers|one": "a badger",
* "there are %(count)s badgers|other": "%(count)s badgers"
* becomes
* "there are %(count)s badgers": {
* "one": "a badger",
* "other": "%(count)s badgers"
* }
*/
function weblateToCounterpart(inTrs) {
const outTrs = {};
for (const key of Object.keys(inTrs)) {
const keyParts = key.split('|', 2);
if (keyParts.length === 2) {
let obj = outTrs[keyParts[0]];
if (obj === undefined) {
obj = {};
outTrs[keyParts[0]] = obj;
}
obj[keyParts[1]] = inTrs[key];
} else {
outTrs[key] = inTrs[key];
}
}
return outTrs;
}
/*
watch the input files for a given language,
regenerate the file, and regenerating languages.json with the new filename
*/
function watchLanguage(file, dest) {
// XXX: Use a debounce because for some reason if we read the language
// file immediately after the FS event is received, the file contents
// appears empty. Possibly https://github.com/nodejs/node/issues/6112
let makeLangDebouncer;
const makeLang = () => {
if (makeLangDebouncer) {
clearTimeout(makeLangDebouncer);
}
makeLangDebouncer = setTimeout(() => {
genLangFile(file, dest);
}, 500);
};
chokidar.watch(file)
.on('add', makeLang)
.on('change', makeLang)
.on('error', errCheck);
}
// language resources
const I18N_DEST = "lib/i18n/strings/";
INCLUDE_LANGS.forEach((file) => {
genLangFile(I18N_BASE_PATH + file, I18N_DEST);
}, {});
if (watch) {
INCLUDE_LANGS.forEach(file => watchLanguage(I18N_BASE_PATH + file, I18N_DEST));
}

View File

@@ -1,5 +1,5 @@
/*
Copyright 2020 The Matrix.org Foundation C.I.C.
Copyright 2020-2021 The Matrix.org Foundation C.I.C.
Licensed under the Apache License, Version 2.0 (the "License");
you may not use this file except in compliance with the License.
@@ -41,8 +41,8 @@ async function copy(hakEnv, moduleInfo) {
if (moduleInfo.cfg.copy) {
console.log(
"Copying " + moduleInfo.cfg.prune + " from " +
moduleInfo.moduleOutDir + " to " + moduleInfo.moduleOutDir,
"Copying files from " +
moduleInfo.moduleBuildDir + " to " + moduleInfo.moduleOutDir,
);
const files = await new Promise(async (resolve, reject) => {
glob(moduleInfo.cfg.copy, {

View File

@@ -1,5 +1,5 @@
/*
Copyright 2020 The Matrix.org Foundation C.I.C.
Copyright 2020-2021 The Matrix.org Foundation C.I.C.
Licensed under the Apache License, Version 2.0 (the "License");
you may not use this file except in compliance with the License.
@@ -18,6 +18,7 @@ const path = require('path');
const os = require('os');
const nodePreGypVersioning = require('node-pre-gyp/lib/util/versioning');
const { TARGETS, getHost, isHostId } = require('./target');
function getElectronVersion(packageJson) {
// should we pick the version of an installed electron
@@ -33,7 +34,7 @@ function getRuntime(packageJson) {
return electronVersion ? 'electron' : 'node-webkit';
}
function getTarget(packageJson) {
function getRuntimeVersion(packageJson) {
const electronVersion = getElectronVersion(packageJson);
if (electronVersion) {
return electronVersion;
@@ -42,30 +43,24 @@ function getTarget(packageJson) {
}
}
function detectArch() {
if (process.platform === 'win32') {
// vcvarsall.bat (the script that sets up the environment for
// visual studio build tools) sets an env var to tell us what
// architecture the active build tools target, so we auto-detect
// this.
const targetArch = process.env.VSCMD_ARG_TGT_ARCH;
if (targetArch === 'x86') {
return 'ia32';
} else if (targetArch === 'x64') {
return 'x64';
}
}
return process.arch;
}
module.exports = class HakEnv {
constructor(prefix, packageJson) {
constructor(prefix, packageJson, targetId) {
let target;
if (targetId) {
target = TARGETS[targetId];
} else {
target = getHost();
}
if (!target) {
throw new Error(`Unknown target ${targetId}!`);
}
Object.assign(this, {
// what we're targeting
runtime: getRuntime(packageJson),
target: getTarget(packageJson),
platform: process.platform,
arch: detectArch(),
runtimeVersion: getRuntimeVersion(packageJson),
target,
// paths
projectRoot: prefix,
@@ -76,34 +71,46 @@ module.exports = class HakEnv {
getRuntimeAbi() {
return nodePreGypVersioning.get_runtime_abi(
this.runtime,
this.target,
this.runtimeVersion,
);
}
// {node_abi}-{platform}-{arch}
getNodeTriple() {
return this.getRuntimeAbi() + '-' + this.platform + '-' + this.arch;
return this.getRuntimeAbi() + '-' + this.target.platform + '-' + this.target.arch;
}
getTargetId() {
return this.target.id;
}
isWin() {
return this.platform === 'win32';
return this.target.platform === 'win32';
}
isMac() {
return this.platform === 'darwin';
return this.target.platform === 'darwin';
}
isLinux() {
return this.platform === 'linux';
return this.target.platform === 'linux';
}
getTargetArch() {
return this.target.arch;
}
isHost() {
return isHostId(this.target.id);
}
makeGypEnv() {
return Object.assign({}, process.env, {
npm_config_target: this.target,
npm_config_arch: this.arch,
npm_config_target_arch: this.arch,
npm_config_arch: this.target.arch,
npm_config_target_arch: this.target.arch,
npm_config_disturl: 'https://atom.io/download/electron',
npm_config_runtime: this.runtime,
npm_config_target: this.runtimeVersion,
npm_config_build_from_source: true,
npm_config_devdir: path.join(os.homedir(), ".electron-gyp"),
});

View File

@@ -1,5 +1,5 @@
/*
Copyright 2020 The Matrix.org Foundation C.I.C.
Copyright 2020-2021 The Matrix.org Foundation C.I.C.
Licensed under the Apache License, Version 2.0 (the "License");
you may not use this file except in compliance with the License.
@@ -53,7 +53,19 @@ async function main() {
process.exit(1);
}
const hakEnv = new HakEnv(prefix, packageJson);
// Apply `--target <target>` option if specified
const targetIndex = process.argv.indexOf('--target');
let targetId;
if (targetIndex >= 0) {
if ((targetIndex + 1) >= process.argv.length) {
console.error("--target option specified without a target");
process.exit(1);
}
// Extract target ID and remove from args
targetId = process.argv.splice(targetIndex, 2)[1];
}
const hakEnv = new HakEnv(prefix, packageJson, targetId);
const deps = {};
@@ -133,4 +145,7 @@ async function main() {
}
}
main().catch(() => process.exit(1));
main().catch(err => {
console.error(err);
process.exit(1);
});

82
scripts/hak/target.js Normal file
View File

@@ -0,0 +1,82 @@
"use strict";
/*
Copyright 2021 The Matrix.org Foundation C.I.C.
Licensed under the Apache License, Version 2.0 (the "License");
you may not use this file except in compliance with the License.
You may obtain a copy of the License at
http://www.apache.org/licenses/LICENSE-2.0
Unless required by applicable law or agreed to in writing, software
distributed under the License is distributed on an "AS IS" BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
See the License for the specific language governing permissions and
limitations under the License.
*/
/*
* THIS FILE IS GENERATED, NOT MEANT FOR EDITING DIRECTLY
* The original source is `target.ts` in the `element-builder` repo. You can
* edit it over there, run `yarn build`, and paste the changes here. It is
* currently assumed this file will rarely change, so a spearate package is not
* yet warranted.
*/
Object.defineProperty(exports, "__esModule", { value: true });
exports.isHost = exports.isHostId = exports.getHost = exports.ENABLED_TARGETS = exports.TARGETS = void 0;
const aarch64AppleDarwin = {
id: 'aarch64-apple-darwin',
platform: 'darwin',
arch: 'arm64',
};
const i686PcWindowsMsvc = {
id: 'i686-pc-windows-msvc',
platform: 'win32',
arch: 'ia32',
vcVarsArch: 'x86',
};
const x8664PcWindowsMsvc = {
id: 'x86_64-pc-windows-msvc',
platform: 'win32',
arch: 'x64',
vcVarsArch: 'amd64',
};
const x8664AppleDarwin = {
id: 'x86_64-apple-darwin',
platform: 'darwin',
arch: 'x64',
};
const x8664UnknownLinuxGnu = {
id: 'x86_64-unknown-linux-gnu',
platform: 'linux',
arch: 'x64',
};
exports.TARGETS = {
'aarch64-apple-darwin': aarch64AppleDarwin,
'i686-pc-windows-msvc': i686PcWindowsMsvc,
'x86_64-pc-windows-msvc': x8664PcWindowsMsvc,
'x86_64-apple-darwin': x8664AppleDarwin,
'x86_64-unknown-linux-gnu': x8664UnknownLinuxGnu,
};
// The set of targets we build by default, sorted by increasing complexity so
// that we fail fast when the native host target fails.
exports.ENABLED_TARGETS = [
exports.TARGETS['x86_64-apple-darwin'],
exports.TARGETS['aarch64-apple-darwin'],
exports.TARGETS['x86_64-unknown-linux-gnu'],
exports.TARGETS['i686-pc-windows-msvc'],
];
function getHost() {
return Object.values(exports.TARGETS).find(target => (target.platform === process.platform &&
target.arch === process.arch));
}
exports.getHost = getHost;
function isHostId(id) {
return getHost()?.id === id;
}
exports.isHostId = isHostId;
function isHost(target) {
return getHost()?.id === target.id;
}
exports.isHost = isHost;

26
src/@types/global.d.ts vendored Normal file
View File

@@ -0,0 +1,26 @@
/*
Copyright 2021 New Vector Ltd
Licensed under the Apache License, Version 2.0 (the "License");
you may not use this file except in compliance with the License.
You may obtain a copy of the License at
http://www.apache.org/licenses/LICENSE-2.0
Unless required by applicable law or agreed to in writing, software
distributed under the License is distributed on an "AS IS" BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
See the License for the specific language governing permissions and
limitations under the License.
*/
import { BrowserWindow } from "electron";
declare global {
namespace NodeJS {
interface Global {
mainWindow: BrowserWindow;
appQuitting: boolean;
}
}
}

View File

@@ -20,34 +20,33 @@ limitations under the License.
// Squirrel on windows starts the app with various flags
// as hooks to tell us when we've been installed/uninstalled
// etc.
const checkSquirrelHooks = require('./squirrelhooks');
if (checkSquirrelHooks()) return;
import { checkSquirrelHooks } from "./squirrelhooks";
if (checkSquirrelHooks()) process.exit(1);
const argv = require('minimist')(process.argv, {
import { app, ipcMain, powerSaveBlocker, BrowserWindow, Menu, autoUpdater, protocol, dialog } from "electron";
import AutoLaunch from "auto-launch";
import path from "path";
import windowStateKeeper from 'electron-window-state';
import Store from 'electron-store';
import fs, { promises as afs } from "fs";
import crypto from "crypto";
import { URL } from "url";
import minimist from "minimist";
import * as tray from "./tray";
import { buildMenuTemplate } from './vectormenu';
import webContentsHandler from './webcontents-handler';
import * as updater from './updater';
import { getProfileFromDeeplink, protocolInit, recordSSOSession } from './protocol';
import { _t, AppLocalization } from './language-helper';
const argv = minimist(process.argv, {
alias: { help: "h" },
});
const {
app, ipcMain, powerSaveBlocker, BrowserWindow, Menu, autoUpdater, protocol, dialog,
} = require('electron');
const AutoLaunch = require('auto-launch');
const path = require('path');
const tray = require('./tray');
const buildMenuTemplate = require('./vectormenu');
const webContentsHandler = require('./webcontents-handler');
const updater = require('./updater');
const { getProfileFromDeeplink, protocolInit, recordSSOSession } = require('./protocol');
const windowStateKeeper = require('electron-window-state');
const Store = require('electron-store');
const fs = require('fs');
const afs = fs.promises;
const crypto = require('crypto');
let keytar;
try {
// eslint-disable-next-line @typescript-eslint/no-var-requires
keytar = require('keytar');
} catch (e) {
if (e.code === "MODULE_NOT_FOUND") {
@@ -57,14 +56,13 @@ try {
}
}
const { _t, AppLocalization } = require('./language-helper');
let seshatSupported = false;
let Seshat;
let SeshatRecovery;
let ReindexError;
try {
// eslint-disable-next-line @typescript-eslint/no-var-requires
const seshatModule = require('matrix-seshat');
Seshat = seshatModule.Seshat;
SeshatRecovery = seshatModule.SeshatRecovery;
@@ -181,6 +179,7 @@ async function setupGlobals() {
]);
try {
// eslint-disable-next-line @typescript-eslint/no-var-requires
vectorConfig = require(asarPath + 'config.json');
} catch (e) {
// it would be nice to check the error code here and bail if the config
@@ -192,6 +191,7 @@ async function setupGlobals() {
try {
// Load local config and use it to override values from the one baked with the build
// eslint-disable-next-line @typescript-eslint/no-var-requires
const localConfig = require(path.join(app.getPath('userData'), 'config.json'));
// If the local config has a homeserver defined, don't use the homeserver from the build
@@ -207,6 +207,16 @@ async function setupGlobals() {
vectorConfig = Object.assign(vectorConfig, localConfig);
} catch (e) {
if (e instanceof SyntaxError) {
dialog.showMessageBox({
type: "error",
title: `Your ${vectorConfig.brand || 'Element'} is misconfigured`,
message: `Your custom ${vectorConfig.brand || 'Element'} configuration contains invalid JSON. ` +
`Please correct the problem and reopen ${vectorConfig.brand || 'Element'}.`,
detail: e.message || "",
});
}
// Could not load local config, this is expected in most cases.
}
@@ -249,7 +259,13 @@ async function moveAutoLauncher() {
}
const eventStorePath = path.join(app.getPath('userData'), 'EventStore');
const store = new Store({ name: "electron-config" });
const store = new Store<{
warnBeforeExit?: boolean;
minimizeToTray?: boolean;
spellCheckerEnabled?: boolean;
autoHideMenuBar?: boolean;
locale?: string | string[];
}>({ name: "electron-config" });
let eventIndex = null;
@@ -264,7 +280,8 @@ const exitShortcuts = [
const warnBeforeExit = (event, input) => {
const shouldWarnBeforeExit = store.get('warnBeforeExit', true);
const exitShortcutPressed = exitShortcuts.some(shortcutFn => shortcutFn(input, process.platform));
const exitShortcutPressed =
input.type === 'keyDown' && exitShortcuts.some(shortcutFn => shortcutFn(input, process.platform));
if (shouldWarnBeforeExit && exitShortcutPressed) {
const shouldCancelCloseRequest = dialog.showMessageBoxSync(mainWindow, {
@@ -821,6 +838,7 @@ app.on('ready', async () => {
if (argv['devtools']) {
try {
// eslint-disable-next-line @typescript-eslint/no-var-requires
const { default: installExt, REACT_DEVELOPER_TOOLS, REACT_PERF } = require('electron-devtools-installer');
installExt(REACT_DEVELOPER_TOOLS)
.then((name) => console.log(`Added Extension: ${name}`))
@@ -1005,7 +1023,7 @@ function beforeQuit() {
}
app.on('before-quit', beforeQuit);
app.on('before-quit-for-update', beforeQuit);
autoUpdater.on('before-quit-for-update', beforeQuit);
app.on('second-instance', (ev, commandLine, workingDirectory) => {
// If other instance launched with --hidden then skip showing window

13
src/i18n/strings/hr.json Normal file
View File

@@ -0,0 +1,13 @@
{
"Paste": "Zalijepiti",
"Copy": "Kopirati",
"Cut": "Izrezati",
"Redo": "Preurediti",
"Undo": "Poništi",
"Edit": "Uredi",
"Quit": "Prestati",
"Show/Hide": "Pokaži/sakrij",
"Are you sure you want to quit?": "Jesi li siguran da želiš odustati?",
"Close Element": "Zatvori Element",
"Cancel": "Otkazati"
}

View File

@@ -26,8 +26,8 @@
"Zoom Out": "Dar Zoom Out",
"Zoom In": "Dar Zoom In",
"Actual Size": "Tamanho de Verdade",
"View": "Ver",
"Select All": "Selecionar Tudo",
"View": "Visualizar",
"Select All": "Selecionar Todas",
"Delete": "Deletar",
"Paste and Match Style": "Colar e Adequar Estilo",
"Paste": "Colar",
@@ -38,7 +38,9 @@
"Edit": "Editar",
"Quit": "Sair",
"Show/Hide": "Mostrar/Esconder",
"Are you sure you want to quit?": "Você tem certeza que quer sair?",
"Are you sure you want to quit?": "Você tem certeza que você quer sair?",
"Close Element": "Fechar Element",
"Cancel": "Cancelar"
"Cancel": "Cancelar",
"Bring All to Front": "Trazer Todas Para Frente",
"Hide Others": "Esconder Outras(os)"
}

46
src/i18n/strings/ta.json Normal file
View File

@@ -0,0 +1,46 @@
{
"Zoom": "பெரிதாக்குதல்",
"Minimize": "சிறிதாக்கு",
"Toggle Developer Tools": "படைப்பாளர் கருவிகளை நிலைமாற்று",
"Toggle Full Screen": "முழு திரையை நிலைமாற்று",
"Paste and Match Style": "ஒட்டு மற்றும் நடையை பொறுத்து",
"Add to dictionary": "அகராதியில் சேர்",
"The image failed to save": "படம் சேமிக்கத் தவறிவிட்டது",
"Failed to save image": "படத்தைச் சேமிப்பதில் தோல்வி",
"Save image as...": "படத்தை இவ்வாறு சேமி...",
"Copy link address": "இணைப்பு முகவரியை நகலெடு",
"Copy email address": "மின்னஞ்சல் முகவரியை நகலெடு",
"Copy image": "படத்தை நகலெடு",
"File": "கோப்பு",
"Bring All to Front": "அனைத்தையும் முன்னால் கொண்டுவா",
"Stop Speaking": "பேசுவதை நிறுத்து",
"Start Speaking": "பேசத் துவங்கு",
"Speech": "பேச்சு",
"Unhide": "காட்டு",
"Hide Others": "மற்றதை மறை",
"Hide": "மறை",
"Services": "சேவைகள்",
"About": "இதனைப் பற்றி",
"Element Help": "எலிமெண்ட் உதவி",
"Help": "உதவி",
"Close": "மூடு",
"Window": "சாளரம்",
"Preferences": "விருப்பத்தேர்வுகள்",
"Zoom Out": "சிறிதாக்கு",
"Zoom In": "பெரிதாக்கு",
"Actual Size": "உண்மையான அளவு",
"View": "காட்சி",
"Select All": "அனைத்தையும் தெரிவுசெய்",
"Delete": "அழி",
"Paste": "ஒட்டு",
"Copy": "நகலெடு",
"Cut": "வெட்டு",
"Redo": "மீண்டும் செய்",
"Undo": "செயல்தவிர்",
"Edit": "திருத்து",
"Quit": "வெளியேறு",
"Show/Hide": "காட்டு/மறை",
"Are you sure you want to quit?": "நீங்கள் நிச்சயம் வெளியேற விரும்புகிறீர்களா?",
"Close Element": "எலிமெண்ட் ஐ மூடு",
"Cancel": "ரத்துசெய்"
}

View File

@@ -14,15 +14,23 @@ See the License for the specific language governing permissions and
limitations under the License.
*/
const counterpart = require('counterpart');
import counterpart from "counterpart";
import type Store from 'electron-store';
const DEFAULT_LOCALE = "en";
function _td(text) {
export function _td(text: string): string {
return text;
}
function _t(text, variables = {}) {
type SubstitutionValue = number | string;
interface IVariables {
[key: string]: SubstitutionValue;
count?: number;
}
export function _t(text: string, variables: IVariables = {}): string {
const args = Object.assign({ interpolate: false }, variables);
const { count } = args;
@@ -55,11 +63,17 @@ function _t(text, variables = {}) {
return translated;
}
class AppLocalization {
constructor({ store, components = [] }) {
// TODO: Should be static field, but that doesn't parse without Babel
this.STORE_KEY = "locale";
type Component = () => void;
type TypedStore = Store<{ locale?: string | string[] }>;
export class AppLocalization {
private static readonly STORE_KEY = "locale";
private readonly store: TypedStore;
private readonly localizedComponents: Set<Component>;
constructor({ store, components = [] }: { store: TypedStore, components: Component[] }) {
counterpart.registerTranslations("en", this.fetchTranslationJson("en_EN"));
counterpart.setFallbackLocale('en');
counterpart.setSeparator('|');
@@ -69,15 +83,15 @@ class AppLocalization {
}
this.store = store;
if (this.store.has(this.STORE_KEY)) {
const locales = this.store.get(this.STORE_KEY);
if (this.store.has(AppLocalization.STORE_KEY)) {
const locales = this.store.get(AppLocalization.STORE_KEY);
this.setAppLocale(locales);
}
this.resetLocalizedUI();
}
fetchTranslationJson(locale) {
public fetchTranslationJson(locale: string): Record<string, string> {
try {
console.log("Fetching translation json for locale: " + locale);
return require(`./i18n/strings/${locale}.json`);
@@ -87,11 +101,7 @@ class AppLocalization {
}
}
get languageTranslationJson() {
return this.translationJsonMap.get(this.language);
}
setAppLocale(locales) {
public setAppLocale(locales: string | string[]): void {
console.log(`Changing application language to ${locales}`);
if (!Array.isArray(locales)) {
@@ -105,13 +115,15 @@ class AppLocalization {
}
});
// eslint-disable-next-line @typescript-eslint/ban-ts-comment
// @ts-ignore - this looks like a bug but is out of scope for this conversion
counterpart.setLocale(locales);
this.store.set(this.STORE_KEY, locales);
this.store.set(AppLocalization.STORE_KEY, locales);
this.resetLocalizedUI();
}
resetLocalizedUI() {
public resetLocalizedUI(): void {
console.log("Resetting the UI components after locale change");
this.localizedComponents.forEach(componentSetup => {
if (typeof componentSetup === "function") {
@@ -120,9 +132,3 @@ class AppLocalization {
});
}
}
module.exports = {
AppLocalization,
_t,
_td,
};

View File

@@ -14,7 +14,7 @@ See the License for the specific language governing permissions and
limitations under the License.
*/
const { ipcRenderer, desktopCapturer, contextBridge } = require('electron');
import { ipcRenderer, desktopCapturer, contextBridge, IpcRendererEvent, SourcesOptions } from 'electron';
// Expose only expected IPC wrapper APIs to the renderer process to avoid
// handing out generalised messaging access.
@@ -36,26 +36,32 @@ const CHANNELS = [
"userDownloadOpen",
];
interface ISource {
id: string;
name: string;
thumbnailURL: string;
}
contextBridge.exposeInMainWorld(
"electron",
{
on(channel, listener) {
on(channel: string, listener: (event: IpcRendererEvent, ...args: any[]) => void): void {
if (!CHANNELS.includes(channel)) {
console.error(`Unknown IPC channel ${channel} ignored`);
return;
}
ipcRenderer.on(channel, listener);
},
send(channel, ...args) {
send(channel: string, ...args: any[]): void {
if (!CHANNELS.includes(channel)) {
console.error(`Unknown IPC channel ${channel} ignored`);
return;
}
ipcRenderer.send(channel, ...args);
},
async getDesktopCapturerSources(options) {
async getDesktopCapturerSources(options: SourcesOptions): Promise<ISource[]> {
const sources = await desktopCapturer.getSources(options);
const desktopCapturerSources = [];
const desktopCapturerSources: ISource[] = [];
for (const source of sources) {
desktopCapturerSources.push({

View File

@@ -1,102 +0,0 @@
/*
Copyright 2020 The Matrix.org Foundation C.I.C.
Licensed under the Apache License, Version 2.0 (the "License");
you may not use this file except in compliance with the License.
You may obtain a copy of the License at
http://www.apache.org/licenses/LICENSE-2.0
Unless required by applicable law or agreed to in writing, software
distributed under the License is distributed on an "AS IS" BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
See the License for the specific language governing permissions and
limitations under the License.
*/
const { app } = require("electron");
const path = require("path");
const fs = require("fs");
const PROTOCOL = "element://";
const SEARCH_PARAM = "element-desktop-ssoid";
const STORE_FILE_NAME = "sso-sessions.json";
// we getPath userData before electron-main changes it, so this is the default value
const storePath = path.join(app.getPath("userData"), STORE_FILE_NAME);
const processUrl = (url) => {
if (!global.mainWindow) return;
console.log("Handling link: ", url);
global.mainWindow.loadURL(url.replace(PROTOCOL, "vector://"));
};
const readStore = () => {
try {
const s = fs.readFileSync(storePath, { encoding: "utf8" });
const o = JSON.parse(s);
return typeof o === "object" ? o : {};
} catch (e) {
return {};
}
};
const writeStore = (data) => {
fs.writeFileSync(storePath, JSON.stringify(data));
};
module.exports = {
recordSSOSession: (sessionID) => {
const userDataPath = app.getPath('userData');
const store = readStore();
for (const key in store) {
// ensure each instance only has one (the latest) session ID to prevent the file growing unbounded
if (store[key] === userDataPath) {
delete store[key];
break;
}
}
store[sessionID] = userDataPath;
writeStore(store);
},
getProfileFromDeeplink: (args) => {
// check if we are passed a profile in the SSO callback url
const deeplinkUrl = args.find(arg => arg.startsWith('element://'));
if (deeplinkUrl && deeplinkUrl.includes(SEARCH_PARAM)) {
const parsedUrl = new URL(deeplinkUrl);
if (parsedUrl.protocol === 'element:') {
const ssoID = parsedUrl.searchParams.get(SEARCH_PARAM);
const store = readStore();
console.log("Forwarding to profile: ", store[ssoID]);
return store[ssoID];
}
}
},
protocolInit: () => {
// get all args except `hidden` as it'd mean the app would not get focused
// XXX: passing args to protocol handlers only works on Windows, so unpackaged deep-linking
// --profile/--profile-dir are passed via the SEARCH_PARAM var in the callback url
const args = process.argv.slice(1).filter(arg => arg !== "--hidden" && arg !== "-hidden");
if (app.isPackaged) {
app.setAsDefaultProtocolClient('element', process.execPath, args);
} else if (process.platform === 'win32') { // on Mac/Linux this would just cause the electron binary to open
// special handler for running without being packaged, e.g `electron .` by passing our app path to electron
app.setAsDefaultProtocolClient('element', process.execPath, [app.getAppPath(), ...args]);
}
if (process.platform === 'darwin') {
// Protocol handler for macos
app.on('open-url', function(ev, url) {
ev.preventDefault();
processUrl(url);
});
} else {
// Protocol handler for win32/Linux
app.on('second-instance', (ev, commandLine) => {
const url = commandLine[commandLine.length - 1];
if (!url.startsWith(PROTOCOL)) return;
processUrl(url);
});
}
},
};

103
src/protocol.ts Normal file
View File

@@ -0,0 +1,103 @@
/*
Copyright 2020 The Matrix.org Foundation C.I.C.
Licensed under the Apache License, Version 2.0 (the "License");
you may not use this file except in compliance with the License.
You may obtain a copy of the License at
http://www.apache.org/licenses/LICENSE-2.0
Unless required by applicable law or agreed to in writing, software
distributed under the License is distributed on an "AS IS" BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
See the License for the specific language governing permissions and
limitations under the License.
*/
import { app } from "electron";
import { URL } from "url";
import path from "path";
import fs from "fs";
const PROTOCOL = "element://";
const SEARCH_PARAM = "element-desktop-ssoid";
const STORE_FILE_NAME = "sso-sessions.json";
// we getPath userData before electron-main changes it, so this is the default value
const storePath = path.join(app.getPath("userData"), STORE_FILE_NAME);
function processUrl(url: string): void {
if (!global.mainWindow) return;
console.log("Handling link: ", url);
global.mainWindow.loadURL(url.replace(PROTOCOL, "vector://"));
}
function readStore(): object {
try {
const s = fs.readFileSync(storePath, { encoding: "utf8" });
const o = JSON.parse(s);
return typeof o === "object" ? o : {};
} catch (e) {
return {};
}
}
function writeStore(data: object): void {
fs.writeFileSync(storePath, JSON.stringify(data));
}
export function recordSSOSession(sessionID: string): void {
const userDataPath = app.getPath('userData');
const store = readStore();
for (const key in store) {
// ensure each instance only has one (the latest) session ID to prevent the file growing unbounded
if (store[key] === userDataPath) {
delete store[key];
break;
}
}
store[sessionID] = userDataPath;
writeStore(store);
}
export function getProfileFromDeeplink(args): string | undefined {
// check if we are passed a profile in the SSO callback url
const deeplinkUrl = args.find(arg => arg.startsWith('element://'));
if (deeplinkUrl && deeplinkUrl.includes(SEARCH_PARAM)) {
const parsedUrl = new URL(deeplinkUrl);
if (parsedUrl.protocol === 'element:') {
const ssoID = parsedUrl.searchParams.get(SEARCH_PARAM);
const store = readStore();
console.log("Forwarding to profile: ", store[ssoID]);
return store[ssoID];
}
}
}
export function protocolInit(): void {
// get all args except `hidden` as it'd mean the app would not get focused
// XXX: passing args to protocol handlers only works on Windows, so unpackaged deep-linking
// --profile/--profile-dir are passed via the SEARCH_PARAM var in the callback url
const args = process.argv.slice(1).filter(arg => arg !== "--hidden" && arg !== "-hidden");
if (app.isPackaged) {
app.setAsDefaultProtocolClient('element', process.execPath, args);
} else if (process.platform === 'win32') { // on Mac/Linux this would just cause the electron binary to open
// special handler for running without being packaged, e.g `electron .` by passing our app path to electron
app.setAsDefaultProtocolClient('element', process.execPath, [app.getAppPath(), ...args]);
}
if (process.platform === 'darwin') {
// Protocol handler for macos
app.on('open-url', function(ev, url) {
ev.preventDefault();
processUrl(url);
});
} else {
// Protocol handler for win32/Linux
app.on('second-instance', (ev, commandLine) => {
const url = commandLine[commandLine.length - 1];
if (!url.startsWith(PROTOCOL)) return;
processUrl(url);
});
}
}

View File

@@ -14,12 +14,12 @@ See the License for the specific language governing permissions and
limitations under the License.
*/
const path = require('path');
const spawn = require('child_process').spawn;
const { app } = require('electron');
const fsProm = require('fs').promises;
import path from "path";
import { spawn } from "child_process";
import { app } from "electron";
import { promises as fsProm } from "fs";
function runUpdateExe(args) {
function runUpdateExe(args: string[]): Promise<void> {
// Invokes Squirrel's Update.exe which will do things for us like create shortcuts
// Note that there's an Update.exe in the app-x.x.x directory and one in the parent
// directory: we need to run the one in the parent directory, because it discovers
@@ -33,7 +33,7 @@ function runUpdateExe(args) {
});
}
function checkSquirrelHooks() {
export function checkSquirrelHooks(): boolean {
if (process.platform !== 'win32') return false;
const cmd = process.argv[1];
@@ -82,5 +82,3 @@ function checkSquirrelHooks() {
}
return false;
}
module.exports = checkSquirrelHooks;

View File

@@ -15,26 +15,26 @@ See the License for the specific language governing permissions and
limitations under the License.
*/
const { app, Tray, Menu, nativeImage } = require('electron');
const pngToIco = require('png-to-ico');
const path = require('path');
const fs = require('fs');
const { _t } = require('./language-helper');
import { app, Tray, Menu, nativeImage } from "electron";
import pngToIco from "png-to-ico";
import path from "path";
import fs from "fs";
import { _t } from "./language-helper";
let trayIcon = null;
let trayIcon: Tray = null;
exports.hasTray = function hasTray() {
export function hasTray(): boolean {
return (trayIcon !== null);
};
}
exports.destroy = function() {
export function destroy(): void {
if (trayIcon) {
trayIcon.destroy();
trayIcon = null;
}
};
}
const toggleWin = function() {
function toggleWin(): void {
if (global.mainWindow.isVisible() && !global.mainWindow.isMinimized()) {
global.mainWindow.hide();
} else {
@@ -42,9 +42,14 @@ const toggleWin = function() {
if (!global.mainWindow.isVisible()) global.mainWindow.show();
global.mainWindow.focus();
}
};
}
exports.create = function(config) {
interface IConfig {
icon_path: string; // eslint-disable-line camelcase
brand: string;
}
export function create(config: IConfig): void {
// no trays on darwin
if (process.platform === 'darwin' || trayIcon) return;
const defaultIcon = nativeImage.createFromPath(config.icon_path);
@@ -89,9 +94,9 @@ exports.create = function(config) {
global.mainWindow.webContents.on('page-title-updated', function(ev, title) {
trayIcon.setToolTip(title);
});
};
}
function initApplicationMenu() {
export function initApplicationMenu(): void {
if (!trayIcon) {
return;
}
@@ -112,5 +117,3 @@ function initApplicationMenu() {
trayIcon.setContextMenu(contextMenu);
}
exports.initApplicationMenu = initApplicationMenu;

View File

@@ -1,16 +1,32 @@
const { app, autoUpdater, ipcMain } = require('electron');
/*
Copyright 2016-2021 New Vector Ltd
Licensed under the Apache License, Version 2.0 (the "License");
you may not use this file except in compliance with the License.
You may obtain a copy of the License at
http://www.apache.org/licenses/LICENSE-2.0
Unless required by applicable law or agreed to in writing, software
distributed under the License is distributed on an "AS IS" BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
See the License for the specific language governing permissions and
limitations under the License.
*/
import { app, autoUpdater, ipcMain } from "electron";
const UPDATE_POLL_INTERVAL_MS = 60 * 60 * 1000;
const INITIAL_UPDATE_DELAY_MS = 30 * 1000;
function installUpdate() {
function installUpdate(): void {
// for some reason, quitAndInstall does not fire the
// before-quit event, so we need to set the flag here.
global.appQuitting = true;
autoUpdater.quitAndInstall();
}
function pollForUpdates() {
function pollForUpdates(): void {
try {
autoUpdater.checkForUpdates();
} catch (e) {
@@ -18,8 +34,7 @@ function pollForUpdates() {
}
}
module.exports = {};
module.exports.start = function startAutoUpdate(updateBaseUrl) {
export function start(updateBaseUrl: string): void {
if (updateBaseUrl.slice(-1) !== '/') {
updateBaseUrl = updateBaseUrl + '/';
}
@@ -37,7 +52,7 @@ module.exports.start = function startAutoUpdate(updateBaseUrl) {
// rely on NSURLConnection setting the User-Agent to what we expect,
// and also acts as a convenient cache-buster to ensure that when the
// app updates it always gets a fresh value to avoid update-looping.
url = `${updateBaseUrl}macos/?localVersion=${encodeURIComponent(app.getVersion())}`;
url = `${updateBaseUrl}macos/${process.arch}/?localVersion=${encodeURIComponent(app.getVersion())}`;
} else if (process.platform === 'win32') {
url = `${updateBaseUrl}win32/${process.arch}/`;
} else {
@@ -48,6 +63,7 @@ module.exports.start = function startAutoUpdate(updateBaseUrl) {
}
if (url) {
console.log(`Update URL: ${url}`);
autoUpdater.setFeedURL(url);
// We check for updates ourselves rather than using 'updater' because we need to
// do it in the main process (and we don't really need to check every 10 minutes:
@@ -63,18 +79,25 @@ module.exports.start = function startAutoUpdate(updateBaseUrl) {
// will fail if running in debug mode
console.log('Couldn\'t enable update checking', err);
}
};
}
ipcMain.on('install_update', installUpdate);
ipcMain.on('check_updates', pollForUpdates);
function ipcChannelSendUpdateStatus(status) {
function ipcChannelSendUpdateStatus(status: boolean | string): void {
if (!global.mainWindow) return;
global.mainWindow.webContents.send('check_updates', status);
}
interface ICachedUpdate {
releaseNotes: string;
releaseName: string;
releaseDate: Date;
updateURL: string;
}
// cache the latest update which has been downloaded as electron offers no api to read it
let latestUpdateDownloaded;
let latestUpdateDownloaded: ICachedUpdate;
autoUpdater.on('update-available', function() {
ipcChannelSendUpdateStatus(true);
}).on('update-not-available', function() {

View File

@@ -14,12 +14,14 @@ See the License for the specific language governing permissions and
limitations under the License.
*/
const { app, shell, Menu } = require('electron');
const { _t } = require('./language-helper');
import { app, shell, Menu, MenuItem, MenuItemConstructorOptions } from 'electron';
import { _t } from './language-helper';
function buildMenuTemplate() {
const isMac = process.platform === 'darwin';
export function buildMenuTemplate(): Menu {
// Menu template from http://electron.atom.io/docs/api/menu/, edited
const template = [
const template: Array<(MenuItemConstructorOptions) | (MenuItem)> = [
{
label: _t('Edit'),
accelerator: 'e',
@@ -46,7 +48,7 @@ function buildMenuTemplate() {
label: _t('Paste'),
},
{
role: 'pasteandmatchstyle',
role: 'pasteAndMatchStyle',
label: _t('Paste and Match Style'),
},
{
@@ -54,7 +56,7 @@ function buildMenuTemplate() {
label: _t('Delete'),
},
{
role: 'selectall',
role: 'selectAll',
label: _t('Select All'),
},
],
@@ -65,30 +67,44 @@ function buildMenuTemplate() {
submenu: [
{ type: 'separator' },
{
role: 'resetzoom',
role: 'resetZoom',
accelerator: 'CmdOrCtrl+Num0',
visible: false,
},
{
role: 'zoomIn',
accelerator: 'CmdOrCtrl+NumAdd',
visible: false,
},
{
role: 'zoomOut',
accelerator: 'CmdOrCtrl+NumSub',
visible: false,
},
{
role: 'resetZoom',
label: _t('Actual Size'),
},
{
role: 'zoomin',
accelerator: 'CommandOrControl+=',
role: 'zoomIn',
label: _t('Zoom In'),
},
{
role: 'zoomout',
role: 'zoomOut',
label: _t('Zoom Out'),
},
{ type: 'separator' },
{
// in macOS the Preferences menu item goes in the first menu
...(!isMac ? [{
label: _t('Preferences'),
accelerator: 'Command+,', // Mac-only accelerator
click() { global.mainWindow.webContents.send('preferences'); },
},
}] : []),
{
role: 'togglefullscreen',
label: _t('Toggle Full Screen'),
},
{
role: 'toggledevtools',
role: 'toggleDevTools',
label: _t('Toggle Developer Tools'),
},
],
@@ -122,7 +138,7 @@ function buildMenuTemplate() {
];
// macOS has specific menu conventions...
if (process.platform === 'darwin') {
if (isMac) {
template.unshift({
// first macOS menu is the name of the app
role: 'appMenu',
@@ -130,7 +146,13 @@ function buildMenuTemplate() {
submenu: [
{
role: 'about',
label: _t('About'),
label: _t('About') + ' ' + app.name,
},
{ type: 'separator' },
{
label: _t('Preferences') + '…',
accelerator: 'Command+,', // Mac-only accelerator
click() { global.mainWindow.webContents.send('preferences'); },
},
{ type: 'separator' },
{
@@ -144,7 +166,7 @@ function buildMenuTemplate() {
label: _t('Hide'),
},
{
role: 'hideothers',
role: 'hideOthers',
label: _t('Hide Others'),
},
{
@@ -160,17 +182,17 @@ function buildMenuTemplate() {
});
// Edit menu.
// This has a 'speech' section on macOS
template[1].submenu.push(
(template[1].submenu as MenuItemConstructorOptions[]).push(
{ type: 'separator' },
{
label: _t('Speech'),
submenu: [
{
role: 'startspeaking',
role: 'startSpeaking',
label: _t('Start Speaking'),
},
{
role: 'stopspeaking',
role: 'stopSpeaking',
label: _t('Stop Speaking'),
},
],
@@ -221,6 +243,3 @@ function buildMenuTemplate() {
return Menu.buildFromTemplate(template);
}
module.exports = buildMenuTemplate;

View File

@@ -1,19 +1,49 @@
const { clipboard, nativeImage, Menu, MenuItem, shell, dialog, ipcMain } = require('electron');
const url = require('url');
const fs = require('fs');
const request = require('request');
const path = require('path');
const { _t } = require('./language-helper');
/*
Copyright 2021 New Vector Ltd
Licensed under the Apache License, Version 2.0 (the "License");
you may not use this file except in compliance with the License.
You may obtain a copy of the License at
http://www.apache.org/licenses/LICENSE-2.0
Unless required by applicable law or agreed to in writing, software
distributed under the License is distributed on an "AS IS" BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
See the License for the specific language governing permissions and
limitations under the License.
*/
import {
clipboard,
nativeImage,
Menu,
MenuItem,
shell,
dialog,
ipcMain,
NativeImage,
WebContents,
ContextMenuParams,
DownloadItem,
MenuItemConstructorOptions,
IpcMainEvent,
} from 'electron';
import url from 'url';
import fs from 'fs';
import request from 'request';
import path from 'path';
import { _t } from './language-helper';
const MAILTO_PREFIX = "mailto:";
const PERMITTED_URL_SCHEMES = [
const PERMITTED_URL_SCHEMES: string[] = [
'http:',
'https:',
MAILTO_PREFIX,
];
function safeOpenURL(target) {
function safeOpenURL(target: string): void {
// openExternal passes the target to open/start/xdg-open,
// so put fairly stringent limits on what can be opened
// (for instance, open /bin/sh does indeed open a terminal
@@ -28,7 +58,7 @@ function safeOpenURL(target) {
}
}
function onWindowOrNavigate(ev, target) {
function onWindowOrNavigate(ev: Event, target: string): void {
// always prevent the default: if something goes wrong,
// we don't want to end up opening it in the electron
// app, as we could end up opening any sort of random
@@ -37,7 +67,7 @@ function onWindowOrNavigate(ev, target) {
safeOpenURL(target);
}
function writeNativeImage(filePath, img) {
function writeNativeImage(filePath: string, img: NativeImage): Promise<void> {
switch (filePath.split('.').pop().toLowerCase()) {
case "jpg":
case "jpeg":
@@ -50,7 +80,7 @@ function writeNativeImage(filePath, img) {
}
}
function onLinkContextMenu(ev, params) {
function onLinkContextMenu(ev: Event, params: ContextMenuParams, webContents: WebContents): void {
let url = params.linkURL || params.srcURL;
if (url.startsWith('vector://vector/webapp')) {
@@ -76,7 +106,7 @@ function onLinkContextMenu(ev, params) {
label: _t('Copy image'),
accelerator: 'c',
click() {
ev.sender.copyImageAt(params.x, params.y);
webContents.copyImageAt(params.x, params.y);
},
}));
}
@@ -108,7 +138,7 @@ function onLinkContextMenu(ev, params) {
if (params.hasImageContents && !url.startsWith('blob:')) {
popupMenu.append(new MenuItem({
label: _t('Save image as...'),
accelerator: 'a',
accelerator: 's',
async click() {
const targetFileName = params.titleText || "image.png";
const { filePath } = await dialog.showSaveDialog({
@@ -140,8 +170,8 @@ function onLinkContextMenu(ev, params) {
ev.preventDefault();
}
function _CutCopyPasteSelectContextMenus(params) {
const options = [];
function cutCopyPasteSelectContextMenus(params: ContextMenuParams): MenuItemConstructorOptions[] {
const options: MenuItemConstructorOptions[] = [];
if (params.misspelledWord) {
params.dictionarySuggestions.forEach(word => {
@@ -180,10 +210,10 @@ function _CutCopyPasteSelectContextMenus(params) {
accelerator: 'p',
enabled: params.editFlags.canPaste,
}, {
role: 'pasteandmatchstyle',
role: 'pasteAndMatchStyle',
enabled: params.editFlags.canPaste,
}, {
role: 'selectall',
role: 'selectAll',
label: _t("Select All"),
accelerator: 'a',
enabled: params.editFlags.canSelectAll,
@@ -192,7 +222,7 @@ function _CutCopyPasteSelectContextMenus(params) {
}
function onSelectedContextMenu(ev, params) {
const items = _CutCopyPasteSelectContextMenus(params);
const items = cutCopyPasteSelectContextMenus(params);
const popupMenu = Menu.buildFromTemplate(items);
// popup() requires an options object even for no options
@@ -200,12 +230,13 @@ function onSelectedContextMenu(ev, params) {
ev.preventDefault();
}
function onEditableContextMenu(ev, params) {
const items = [
function onEditableContextMenu(ev: Event, params: ContextMenuParams) {
const items: MenuItemConstructorOptions[] = [
{ role: 'undo' },
{ role: 'redo', enabled: params.editFlags.canRedo },
{ type: 'separator' },
].concat(_CutCopyPasteSelectContextMenus(params));
...cutCopyPasteSelectContextMenus(params),
];
const popupMenu = Menu.buildFromTemplate(items);
@@ -214,20 +245,20 @@ function onEditableContextMenu(ev, params) {
ev.preventDefault();
}
ipcMain.on('userDownloadOpen', function(ev, { path }) {
ipcMain.on('userDownloadOpen', function(ev: IpcMainEvent, { path }) {
shell.openPath(path);
});
module.exports = (webContents) => {
export default (webContents: WebContents): void => {
webContents.on('new-window', onWindowOrNavigate);
webContents.on('will-navigate', (ev, target) => {
webContents.on('will-navigate', (ev: Event, target: string): void => {
if (target.startsWith("vector://")) return;
return onWindowOrNavigate(ev, target);
});
webContents.on('context-menu', function(ev, params) {
webContents.on('context-menu', function(ev: Event, params: ContextMenuParams): void {
if (params.linkURL || params.srcURL) {
onLinkContextMenu(ev, params);
onLinkContextMenu(ev, params, webContents);
} else if (params.selectionText) {
onSelectedContextMenu(ev, params);
} else if (params.isEditable) {
@@ -235,7 +266,7 @@ module.exports = (webContents) => {
}
});
webContents.session.on('will-download', (event, item) => {
webContents.session.on('will-download', (event: Event, item: DownloadItem): void => {
item.once('done', (event, state) => {
if (state === 'completed') {
const savePath = item.getSavePath();

24
tsconfig.json Normal file
View File

@@ -0,0 +1,24 @@
{
"compilerOptions": {
"resolveJsonModule": true,
"esModuleInterop": true,
"module": "commonjs",
"moduleResolution": "node",
"target": "es2016",
"noImplicitAny": false,
"sourceMap": false,
"outDir": "./lib",
"rootDir": "./src",
"declaration": true,
"types": [
"node"
],
"lib": [
"es2019",
"dom"
]
},
"include": [
"./src/**/*.ts"
]
}

1126
yarn.lock
View File

File diff suppressed because it is too large Load Diff