Compare commits

...

120 Commits

Author SHA1 Message Date
RiotRobot
494200d576 v1.7.33 2021-07-19 16:40:58 +01:00
RiotRobot
28cbc01d61 Prepare changelog for v1.7.33 2021-07-19 16:40:58 +01:00
David Baker
45eb1252b6 Bump electron to 12.0.14 2021-07-14 12:10:10 +01:00
David Baker
b9e2fbbd23 Merge pull request #232 from RiotTranslateBot/weblate-element-desktop-element-desktop
Translations update from Weblate
2021-07-14 11:43:30 +01:00
Weblate
5febbeb681 Merge branch 'origin/develop' into Weblate. 2021-07-14 10:30:56 +00:00
Michael Telatynski
768066e764 Merge pull request #231 from SimonBrandner/ignore-vscode 2021-07-13 19:19:08 +01:00
Šimon Brandner
e436b87e80 Ignore vscode
Signed-off-by: Šimon Brandner <simon.bra.ag@gmail.com>
2021-07-13 20:11:54 +02:00
Alex Henrie
d5c395f509 Translated using Weblate (Catalan)
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/ca/
2021-07-10 08:25:03 +00:00
David Baker
7107f45cee Merge pull request #230 from vector-im/dbkr/windows_use_target_build_dir
Use the target-specific build dir for sqlcipher / openssl
2021-07-09 10:10:44 +01:00
David Baker
bd85f19c15 Use the target-specific build dir for sqlcipher / openssl 2021-07-09 10:07:07 +01:00
HelaBasa
e2697cd8b4 Translated using Weblate (Sinhala)
Currently translated at 65.9% (29 of 44 strings)

Translation: Element Desktop/element-desktop
Translate-URL: https://translate.element.io/projects/element-desktop/element-desktop/si/
2021-07-09 03:34:50 +00:00
JosephZERO
15ca3a3145 Translated using Weblate (Belarusian)
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/be/
2021-07-09 03:34:50 +00:00
Alex Henrie
e2829822a3 Added translation using Weblate (Catalan) 2021-07-08 17:36:32 +00:00
David Baker
fac9f53bb6 Merge pull request #229 from vector-im/dbkr/fix_default_target
Fix not specifying a target
2021-07-08 09:18:06 +01:00
HelaBasa
3c324ad5f7 Added translation using Weblate (Sinhala) 2021-07-08 02:32:52 +00:00
David Baker
d82377e2de Fix not specifying a target
ie. it should use whatever's detected
2021-07-07 21:38:09 +01:00
Germain
79a426b1c0 Merge pull request #227 from vector-im/gsouquet/ci-pure-lockfile
Do not generate a lockfile when running in CI
2021-07-07 17:53:38 +01:00
David Baker
00a91489a8 Merge pull request #228 from vector-im/dbkr/windows_compatible_quotes
Use double quotes in readme
2021-07-07 15:52:33 +01:00
David Baker
b315b71e43 Use double quotes in readme
which work in the windows shell
2021-07-07 15:48:58 +01:00
Germain Souquet
e132e1c610 Do not generate a lockfile when running in CI 2021-07-07 16:10:01 +02:00
JosephZERO
8592840143 Added translation using Weblate (Belarusian) 2021-07-07 11:24:46 +00:00
David Baker
a8f44fd6e9 Merge pull request #226 from vector-im/dbkr/universally_speaking
Support universal builds
2021-07-07 11:19:26 +01:00
David Baker
a22ba39e63 Use colons consistently in build scripts 2021-07-07 11:17:31 +01:00
David Baker
3dd611b5d5 Address macos properly
Co-authored-by: J. Ryan Stinnett <jryans@gmail.com>
2021-07-07 11:01:45 +01:00
David Baker
eed1252f33 Merge pull request #225 from vector-im/dbkr/no_rustup
Check target with rustc directly
2021-07-07 11:00:43 +01:00
David Baker
9913b0ff78 Fix confused toolchain / target naming
Co-authored-by: J. Ryan Stinnett <jryans@gmail.com>
2021-07-07 10:58:54 +01:00
David Baker
e07bfc1d6a Support universal builds
Hopefully adequately documented in the README
2021-07-06 23:52:19 +01:00
David Baker
b5725da9ea lint 2021-07-06 19:06:58 +01:00
David Baker
5bbce91e51 Check target with rustc directly
To avoid depending on rustup (at least when not cross-compiling)
2021-07-06 19:01:34 +01:00
a5r0n
0aed8eac36 Translated using Weblate (Hebrew)
Currently translated at 97.7% (43 of 44 strings)

Translation: Element Desktop/element-desktop
Translate-URL: https://translate.element.io/projects/element-desktop/element-desktop/he/
2021-07-06 05:34:49 +00:00
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
a5r0n
b6cd3c4cee Added translation using Weblate (Hebrew) 2021-07-05 04:51:02 +00: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
37 changed files with 2053 additions and 661 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",
},
}],
};

3
.gitignore vendored
View File

@@ -1,4 +1,5 @@
/dist
/lib
/webapp
/webapp.asar
/packages
@@ -10,3 +11,5 @@
/.yarnrc
/docker
/.npmrc
.vscode
.vscode/

View File

@@ -1,3 +1,90 @@
Changes in [1.7.33](https://github.com/vector-im/element-desktop/releases/tag/v1.7.33) (2021-07-19)
===================================================================================================
[Full Changelog](https://github.com/vector-im/element-desktop/compare/v1.7.32...v1.7.33)
* Translations update from Weblate
[\#232](https://github.com/vector-im/element-desktop/pull/232)
* Add VS Code to gitignore
[\#231](https://github.com/vector-im/element-desktop/pull/231)
* Use the target-specific build dir for sqlcipher / openssl
[\#230](https://github.com/vector-im/element-desktop/pull/230)
* Fix not specifying a target
[\#229](https://github.com/vector-im/element-desktop/pull/229)
* Do not generate a lockfile when running in CI
[\#227](https://github.com/vector-im/element-desktop/pull/227)
* Use double quotes in readme
[\#228](https://github.com/vector-im/element-desktop/pull/228)
* Support universal builds
[\#226](https://github.com/vector-im/element-desktop/pull/226)
* Check target with rustc directly
[\#225](https://github.com/vector-im/element-desktop/pull/225)
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

@@ -20,7 +20,7 @@ so the first step is to get a working copy of Element Web. There are a few ways
# Fetch the prebuilt release Element package from the element-web GitHub releases page. The version
# fetched will be the same as the local element-desktop package.
# We're explicitly asking for no config, so the packaged Element will have no config.json.
yarn run fetch --noverify --cfgdir ''
yarn run fetch --noverify --cfgdir ""
```
...or if you'd like to use GPG to verify the downloaded package:
@@ -30,14 +30,14 @@ yarn run fetch --noverify --cfgdir ''
# once.
yarn run fetch --importkey
# Fetch the package and verify the signature
yarn run fetch --cfgdir ''
yarn run fetch --cfgdir ""
```
...or either of the above, but fetching a specific version of Element:
```
# Fetch the prebuilt release Element package from the element-web GitHub releases page. The version
# fetched will be the same as the local element-desktop package.
yarn run fetch --noverify --cfgdir '' v1.5.6
yarn run fetch --noverify --cfgdir "" v1.5.6
```
If you only want to run the app locally and don't need to build packages, you can
@@ -58,15 +58,19 @@ run Element locally, skip to the next section.
If you'd like to build the native modules (for searching in encrypted rooms and
secure storage), do this first. This will take 10 minutes or so, and will
require a number of native tools to be installed, depending on your OS (eg.
rust, tcl, make/nmake). If you don't need these features, you can skip this
step.
rust, tcl, make/nmake).
You'll also to need to make sure you've built the native modules for the same
architecture as your package, so for anything more advanced than just building
the modules and app for the host architecture see 'Other Architectures'.
If you don't need these features, you can skip this step.
To just build these for your native architecture:
```
yarn run build:native
```
On Windows, this will automatically determine the architecture to build for based
on the environment. Make sure that you have all the [tools required to perform the native modules build](docs/windows-requirements.md)
Now you can build the package:
```
@@ -78,15 +82,6 @@ This will do a couple of things:
* Run electron-builder to build a package. The package built will match the operating system
you're running the build process on.
If you're on Windows, you can choose to build specifically for 32 or 64 bit:
```
yarn run build32
```
or
```
yarn run build64
```
This build step will not build any native modules.
You can also build using docker, which will always produce the linux package:
@@ -112,6 +107,70 @@ yarn add electron
yarn start
```
Other Architectures
===================
Building the native modules will build for the host architecture (and only the
host architecture) by default. On Windows, this will automatically determine
the architecture to build for based on the environment. Make sure that you have
all the [tools required to perform the native modules build](docs/windows-requirements.md)
On macOS, you can build universal native modules too:
```
yarn run build:native:universal
```
...or you can build for a specific architecture:
```
yarn run build:native --target x86_64-apple-darwin
```
or
```
yarn run build:native --target aarch64-apple-darwin
```
You'll then need to create a built bundle with the same architecture.
To bundle a universal build for macOS, run:
```
yarn run build:universal
```
If you're on Windows, you can choose to build specifically for 32 or 64 bit:
```
yarn run build:32
```
or
```
yarn run build:64
```
Note that the native module build system keeps the different architectures
separate, so you can keep native modules for several architectures at the same
time and switch which are active using a `yarn run hak copy` command, passing
the appropriate architectures. This will error if you haven't yet built those
architectures. eg:
```
yarn run build:native --target x86_64-apple-darwin
# We've now built & linked into place native modules for Intel
yarn run build:native --target aarch64-apple-darwin
# We've now built Apple Silicon modules too, and linked them into place as the active ones
yarn run hak copy --target x86_64-apple-darwin
# We've now switched back to our Intel modules
yarn run hak copy --target x86_64-apple-darwin --target aarch64-apple-darwin
# Now our native modules are universal x86_64+aarch64 binaries
```
The current set of native modules are stored in `.hak/hakModules`,
so you can use this to check what architecture is currently in place, eg:
```
$ lipo -info .hak/hakModules/keytar/build/Release/keytar.node
Architectures in the fat file: .hak/hakModules/keytar/build/Release/keytar.node are: x86_64 arm64
```
Config
======
If you'd like the packaged Element to have a configuration file, you can create a

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.
@@ -32,9 +32,9 @@ module.exports = async function(hakEnv, moduleInfo) {
async function buildOpenSslWin(hakEnv, moduleInfo) {
const version = moduleInfo.cfg.dependencies.openssl;
const openSslDir = path.join(moduleInfo.moduleDotHakDir, `openssl-${version}`);
const openSslDir = path.join(moduleInfo.moduleTargetDotHakDir, `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) => {
@@ -134,7 +134,7 @@ async function buildOpenSslWin(hakEnv, moduleInfo) {
async function buildSqlCipherWin(hakEnv, moduleInfo) {
const version = moduleInfo.cfg.dependencies.sqlcipher;
const sqlCipherDir = path.join(moduleInfo.moduleDotHakDir, `sqlcipher-${version}`);
const sqlCipherDir = path.join(moduleInfo.moduleTargetDotHakDir, `sqlcipher-${version}`);
const buildDir = path.join(sqlCipherDir, 'bld');
await mkdirp(buildDir);
@@ -171,7 +171,7 @@ async function buildSqlCipherWin(hakEnv, moduleInfo) {
async function buildSqlCipherUnix(hakEnv, moduleInfo) {
const version = moduleInfo.cfg.dependencies.sqlcipher;
const sqlCipherDir = path.join(moduleInfo.moduleDotHakDir, `sqlcipher-${version}`);
const sqlCipherDir = path.join(moduleInfo.moduleTargetDotHakDir, `sqlcipher-${version}`);
const args = [
'--prefix=' + moduleInfo.depPrefix + '',
@@ -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.
@@ -15,6 +15,7 @@ limitations under the License.
*/
const childProcess = require('child_process');
const fsProm = require('fs').promises;
module.exports = async function(hakEnv, moduleInfo) {
// of course tcl doesn't have a --version
@@ -34,7 +35,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 +61,22 @@ module.exports = async function(hakEnv, moduleInfo) {
});
});
}
// Ensure Rust target exists (nb. we avoid depending on rustup)
await new Promise((resolve, reject) => {
const rustc = childProcess.execFile('rustc', [
'--target', hakEnv.getTargetId(), '-o', 'tmp', '-',
], (err, out) => {
if (err) {
reject(
"rustc can't build for target " + hakEnv.getTargetId() +
": ensure target is installed via `rustup target add " + hakEnv.getTargetId() + "` " +
"or your package manager if not using `rustup`",
);
}
fsProm.unlink('tmp').then(resolve);
});
rustc.stdin.write('fn main() {}');
rustc.stdin.end();
});
};

View File

@@ -34,7 +34,7 @@ module.exports = async function(hakEnv, moduleInfo) {
async function getSqlCipher(hakEnv, moduleInfo) {
const version = moduleInfo.cfg.dependencies.sqlcipher;
const sqlCipherDir = path.join(moduleInfo.moduleDotHakDir, `sqlcipher-${version}`);
const sqlCipherDir = path.join(moduleInfo.moduleTargetDotHakDir, `sqlcipher-${version}`);
let haveSqlcipher;
try {
@@ -62,9 +62,10 @@ async function getSqlCipher(hakEnv, moduleInfo) {
await bob;
}
// Extract the tarball to per-target directories, then we avoid cross-contaiminating archs
await tar.x({
file: sqlCipherTarball,
cwd: moduleInfo.moduleDotHakDir,
cwd: moduleInfo.moduleTargetDotHakDir,
});
if (hakEnv.isWin()) {
@@ -94,7 +95,7 @@ async function getSqlCipher(hakEnv, moduleInfo) {
async function getOpenSsl(hakEnv, moduleInfo) {
const version = moduleInfo.cfg.dependencies.openssl;
const openSslDir = path.join(moduleInfo.moduleDotHakDir, `openssl-${version}`);
const openSslDir = path.join(moduleInfo.moduleTargetDotHakDir, `openssl-${version}`);
let haveOpenSsl;
try {
@@ -121,9 +122,9 @@ async function getOpenSsl(hakEnv, moduleInfo) {
});
}
console.log("extracting " + openSslTarball + " in " + moduleInfo.moduleDotHakDir);
console.log("extracting " + openSslTarball + " in " + moduleInfo.moduleTargetDotHakDir);
await tar.x({
file: openSslTarball,
cwd: moduleInfo.moduleDotHakDir,
cwd: moduleInfo.moduleTargetDotHakDir,
});
}

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.33",
"description": "A feature-rich client for Matrix.org",
"author": "Element",
"repository": {
@@ -18,18 +18,24 @@
"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",
"build:native:universal": "yarn run hak --target x86_64-apple-darwin fetchandbuild && yarn run hak --target aarch64-apple-darwin fetchandbuild && yarn run hak --target x86_64-apple-darwin --target aarch64-apple-darwin copyandlink",
"build:32": "yarn run build:ts && yarn run build:res && electron-builder --ia32",
"build:64": "yarn run build:ts && yarn run build:res && electron-builder --x64",
"build:universal": "yarn run build:ts && yarn run build:res && electron-builder --universal",
"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 +48,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 +73,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 +82,14 @@
},
"build": {
"appId": "im.riot.app",
"electronVersion": "12.0.9",
"electronVersion": "12.0.14",
"files": [
"package.json",
{
"from": ".hak/hakModules",
"to": "node_modules"
},
"src/**"
"lib/**"
],
"extraResources": [
{

View File

@@ -2,4 +2,4 @@
set -ex
yarn install $@
yarn install --pure-lockfile $@

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.
@@ -16,6 +16,7 @@ limitations under the License.
const path = require('path');
const fsProm = require('fs').promises;
const childProcess = require('child_process');
const rimraf = require('rimraf');
const glob = require('glob');
@@ -40,10 +41,9 @@ async function copy(hakEnv, moduleInfo) {
}
if (moduleInfo.cfg.copy) {
console.log(
"Copying " + moduleInfo.cfg.prune + " from " +
moduleInfo.moduleOutDir + " to " + moduleInfo.moduleOutDir,
);
// If there are multiple moduleBuildDirs, singular moduleBuildDir
// is the same as moduleBuildDirs[0], so we're just listing the contents
// of the first one.
const files = await new Promise(async (resolve, reject) => {
glob(moduleInfo.cfg.copy, {
nosort: true,
@@ -53,13 +53,46 @@ async function copy(hakEnv, moduleInfo) {
err ? reject(err) : resolve(files);
});
});
for (const f of files) {
console.log("\t" + f);
const src = path.join(moduleInfo.moduleBuildDir, f);
const dst = path.join(moduleInfo.moduleOutDir, f);
await mkdirp(path.dirname(dst));
await fsProm.copyFile(src, dst);
if (moduleInfo.moduleBuildDirs.length > 1) {
if (!hakEnv.isMac()) {
console.error(
"You asked me to copy multiple targets but I've only been taught " +
"how to do that on macOS.",
);
throw new Error("Can't copy multiple targets on this platform");
}
for (const f of files) {
const components = moduleInfo.moduleBuildDirs.map(dir => path.join(dir, f));
const dst = path.join(moduleInfo.moduleOutDir, f);
await mkdirp(path.dirname(dst));
await new Promise((resolve, reject) => {
childProcess.execFile('lipo',
['-create', '-output', dst, ...components], (err) => {
if (err) {
reject(err);
} else {
resolve();
}
},
);
});
}
} else {
console.log(
"Copying files from " +
moduleInfo.moduleBuildDir + " to " + moduleInfo.moduleOutDir,
);
for (const f of files) {
console.log("\t" + f);
const src = path.join(moduleInfo.moduleBuildDir, f);
const dst = path.join(moduleInfo.moduleOutDir, f);
await mkdirp(path.dirname(dst));
await fsProm.copyFile(src, dst);
}
}
}
}

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.
@@ -35,6 +35,13 @@ const MODULECOMMANDS = [
'clean',
];
// Shortcuts for multiple commands at once (useful for building universal binaries
// because you can run the fetch/fetchDeps/build for each arch and then copy/link once)
const METACOMMANDS = {
'fetchandbuild': ['check', 'fetch', 'fetchDeps', 'build'],
'copyandlink': ['copy', 'link'],
};
// Scripts valid in a hak.json 'scripts' section
const HAKSCRIPTS = [
'check',
@@ -53,7 +60,25 @@ async function main() {
process.exit(1);
}
const hakEnv = new HakEnv(prefix, packageJson);
const targetIds = [];
// Apply `--target <target>` option if specified
// Can be specified multiple times for the copy command to bundle
// multiple archs into a single universal output module)
while (true) { // eslint-disable-line no-constant-condition
const targetIndex = process.argv.indexOf('--target');
if (targetIndex === -1) break;
if ((targetIndex + 1) >= process.argv.length) {
console.error("--target option specified without a target");
process.exit(1);
}
// Extract target ID and remove from args
targetIds.push(process.argv.splice(targetIndex, 2)[1]);
}
const hakEnvs = targetIds.map(tid => new HakEnv(prefix, packageJson, tid));
if (hakEnvs.length == 0) hakEnvs.push(new HakEnv(prefix, packageJson, null));
const hakEnv = hakEnvs[0];
const deps = {};
@@ -75,10 +100,12 @@ async function main() {
cfg: hakJson,
moduleHakDir: path.join(prefix, 'hak', dep),
moduleDotHakDir: path.join(hakEnv.dotHakDir, dep),
moduleBuildDir: path.join(hakEnv.dotHakDir, dep, 'build'),
moduleTargetDotHakDir: path.join(hakEnv.dotHakDir, dep, hakEnv.getTargetId()),
moduleBuildDir: path.join(hakEnv.dotHakDir, dep, hakEnv.getTargetId(), 'build'),
moduleBuildDirs: hakEnvs.map(h => path.join(h.dotHakDir, dep, h.getTargetId(), 'build')),
moduleOutDir: path.join(hakEnv.dotHakDir, 'hakModules', dep),
nodeModuleBinDir: path.join(hakEnv.dotHakDir, dep, 'build', 'node_modules', '.bin'),
depPrefix: path.join(hakEnv.dotHakDir, dep, 'opt'),
nodeModuleBinDir: path.join(hakEnv.dotHakDir, dep, hakEnv.getTargetId(), 'build', 'node_modules', '.bin'),
depPrefix: path.join(hakEnv.dotHakDir, dep, hakEnv.getTargetId(), 'opt'),
scripts: {},
};
@@ -92,10 +119,18 @@ async function main() {
let cmds;
if (process.argv.length < 3) {
cmds = ['check', 'fetch', 'fetchDeps', 'build', 'copy', 'link'];
} else if (METACOMMANDS[process.argv[2]]) {
cmds = METACOMMANDS[process.argv[2]];
} else {
cmds = [process.argv[2]];
}
if (hakEnvs.length > 1 && cmds.some(c => !['copy', 'link'].includes(c))) {
// We allow link here too for convenience because it's completely arch independent
console.error("Multiple targets only supported with the copy command");
return;
}
let modules = process.argv.slice(3);
if (modules.length === 0) modules = Object.keys(deps);
@@ -133,4 +168,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

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

@@ -0,0 +1,46 @@
{
"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": "Вынесці ўсё наперад",
"Zoom": "Маштаб",
"Stop Speaking": "Перастаць гаварыць",
"Start Speaking": "Гаварыць",
"Speech": "Голас",
"Unhide": "Паказаць",
"Hide Others": "Схаваць іншыя",
"Hide": "Схаваць",
"Services": "Сервісы",
"About": "Аб праграме",
"Element Help": "Даведка Element",
"Help": "Даведка",
"Close": "Зачыніць",
"Minimize": "Згарнуць",
"Window": "Акно",
"Toggle Developer Tools": "Пераключэнне інструментаў распрацоўніка",
"Toggle Full Screen": "Пераключэнне на ўвесь экран",
"Preferences": "Параметры",
"Zoom Out": "Паменшыць",
"Zoom In": "Павялічыць",
"Actual Size": "Фактычны Памер",
"View": "Прагляд",
"Select All": "Выбраць усё",
"Delete": "Выдаліць",
"Paste and Match Style": "Уставіць і супаставіць стыль",
"Paste": "Уставіць",
"Copy": "Капіяваць",
"Cut": "Выразаць",
"Redo": "Паўтарыць",
"Undo": "Адмяніць",
"Edit": "Змяніць",
"Quit": "Выйсці",
"Show/Hide": "Паказаць / схаваць",
"Are you sure you want to quit?": "Вы ўпэўненыя, што хочаце выйсці?",
"Close Element": "Зачыніць Element",
"Cancel": "Адмена"
}

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

@@ -0,0 +1,46 @@
{
"Add to dictionary": "Afegeix al diccionari",
"The image failed to save": "S'ha fallat en desar la imatge",
"Failed to save image": "S'ha fallat en desar la imatge",
"Save image as...": "Anomena i desa la imatge...",
"Copy link address": "Copia l'adreça de l'enllaç",
"Copy email address": "Copia l'adreça de correu electrònic",
"Copy image": "Copia la imatge",
"File": "Fitxer",
"Bring All to Front": "Porta-ho tot al davant",
"Zoom": "Escala",
"Stop Speaking": "Para la veu",
"Start Speaking": "Comença la veu",
"Speech": "Veu",
"Unhide": "Deixa d'amagar",
"Hide Others": "Amaga les altres",
"Hide": "Amaga",
"Services": "Serveis",
"About": "Quant a",
"Element Help": "Ajuda sobre l'Element",
"Help": "Ajuda",
"Close": "Tanca",
"Minimize": "Minimitza",
"Window": "Finestra",
"Toggle Developer Tools": "Commuta les eines per a desenvolupadors",
"Toggle Full Screen": "Commuta la pantalla completa",
"Preferences": "Preferències",
"Zoom Out": "Allunya",
"Zoom In": "Apropia",
"Actual Size": "Mida real",
"View": "Visualitza",
"Select All": "Selecciona-ho tot",
"Delete": "Suprimeix",
"Paste and Match Style": "Enganxa i fes coincidir l'estil",
"Paste": "Enganxa",
"Copy": "Copia",
"Cut": "Retalla",
"Redo": "Refés",
"Undo": "Desfés",
"Edit": "Edita",
"Quit": "Surt",
"Show/Hide": "Mostra/Amaga",
"Are you sure you want to quit?": "Esteu segur que voleu sortir?",
"Close Element": "Tanca l'Element",
"Cancel": "Cancel·la"
}

45
src/i18n/strings/he.json Normal file
View File

@@ -0,0 +1,45 @@
{
"Actual Size": "גודל ממשי",
"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": "הבא הכל לחזית",
"Zoom": "גודל תצוגה",
"Stop Speaking": "הפסק לדבר",
"Start Speaking": "התחל לדבר",
"Speech": "דיבור",
"Unhide": "בטל הסתרה",
"Hide Others": "הסתר אחרים",
"Hide": "הסתר",
"Services": "שרותים",
"About": "אודות",
"Element Help": "עזרה של אלמנט",
"Help": "עזרה",
"Close": "סגור",
"Minimize": "מזער",
"Window": "חלון",
"Toggle Developer Tools": "הפעל כלי מפתחים",
"Toggle Full Screen": "הפעל מצב מסך מלא",
"Preferences": "העדפות",
"Zoom Out": "התרחק",
"Zoom In": "התקרב",
"View": "צפה",
"Select All": "בחר הכל",
"Delete": "מחק",
"Paste": "הדבק",
"Copy": "העתק",
"Cut": "גזור",
"Undo": "בטל ביצוע",
"Redo": "בצע שוב",
"Edit": "עריכה",
"Quit": "יציאה",
"Show/Hide": "הצג\\הסתר",
"Are you sure you want to quit?": "האם אתה בטוח שברצונך לצאת?",
"Close Element": "סגור את אלמנט",
"Cancel": "ביטול"
}

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)"
}

31
src/i18n/strings/si.json Normal file
View File

@@ -0,0 +1,31 @@
{
"Show/Hide": "පෙන්වන්න/සඟවන්න",
"Are you sure you want to quit?": "ඔබට ඉවත් වීමට අවශ්‍ය බව විශ්වාස ද?",
"Close Element": "ඉලමෙන්ට් වසන්න",
"Cancel": "අවලංගු කරන්න",
"Add to dictionary": "ශබ්ද කෝෂයට එකතු කරන්න",
"Copy link address": "සබැඳියේ ලිපිනය පිටපත් කරන්න",
"Copy email address": "වි-තැපෑල පිටපත් කරන්න",
"File": "ගොනුව",
"Zoom": "විශාල කරන්න",
"Hide Others": "වෙනත් දෑ සඟවන්න",
"Hide": "සඟවන්න",
"Services": "සේවා",
"About": "පිළිබඳව",
"Element Help": "ඉලමෙන්ට් උපකාර",
"Help": "උපකාර",
"Close": "වසන්න",
"Minimize": "හකුලන්න",
"Window": "කවුළුව",
"Zoom Out": "කුඩාලනය කරන්න",
"Zoom In": "විශාලනය කරන්න",
"Actual Size": "සැබෑ ප්‍රමාණය",
"Select All": "සියල්ල තෝරන්න",
"Paste": "අලවන්න",
"Copy": "පිටපත්",
"Cut": "කපන්න",
"Redo": "පසුසේ",
"Undo": "පෙරසේ",
"Edit": "සංස්කරණය",
"Quit": "ඉවත් වන්න"
}

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