Compare commits

...

231 Commits

Author SHA1 Message Date
Ramiro Saenz eaa33fc8f3
EOL: Thank you, thank you, thank you, thank you 3 years ago
Ramiro Saenz 0669dafde5 EOL: Thank you, thank you, thank you, thank you 3 years ago
Ramiro Saenz 78acfeed42 Update .travis.yml 3 years ago
Ramiro Saenz f9e9a547bd Update appveyor.yml 3 years ago
Ramiro Saenz 02aa8ce840 Update appveyor.yml 3 years ago
Ramiro Saenz 6c31dcce1d Update appveyor.yml 3 years ago
Ramiro Saenz 7f3ecf5e1e Update appveyor.yml 3 years ago
Ramiro Saenz 287ee85067 CI fixes 3 years ago
Ramiro Saenz b7a5b39b1f
Merge pull request #3109 from KevinRoebert/master 3 years ago
Ramiro Saenz 6fcd982b46
Merge pull request #3102 from rodriguescelio/fix/screen-share 3 years ago
Kevin 5c4ee8d06a
Update package.json 3 years ago
Kevin R cb654525e0
Added Apple Silicon Support 3 years ago
Ramiro Saenz 1eebe2445f
Removed invitation to Slack 4 years ago
Celio Rodrigues 4a79697487 Fixed the screenshare capability 4 years ago
Ramiro Saenz 84a8f20bbc Versioning 4 years ago
Ramiro Saenz 04413c81eb Fixed exit on Master Password screen 4 years ago
Ramiro Saenz 1605ec5ebd Temporary fix to load Twitter and other websites inside webviews 4 years ago
Ramiro Saenz 6f4f33d53d Minor fixes 4 years ago
Ramiro Saenz f3fc3c7cf0 Removed diskusage because of build problems 4 years ago
Ramiro Saenz 89d0560ed3 Update appveyor.yml 4 years ago
Ramiro Saenz cc39ed6980 Update appveyor.yml 4 years ago
Ramiro Saenz 58f53323f3 Update appveyor.yml 4 years ago
Ramiro Saenz 82a44e93fc Updated Node 4 years ago
Ramiro Saenz c91ef575e3 Updated Electron and fixed some major bugs 4 years ago
Ramiro Saenz 5e94ebf0e9
Merge pull request #2897 from mhatvan/chore/update-electron 4 years ago
Ramiro Saenz c26845662c
Merge branch 'master' into chore/update-electron 4 years ago
Ramiro Saenz 008efd5f08 Reviewed code and tested 4 years ago
Ramiro Saenz 4f0c6e9bc1
Merge pull request #2807 from Vioner/fix/#2077-stop-rambox-when-running-out-of-space 4 years ago
mhatvan e18ff5e003
chore: Update Electron (#2871) 4 years ago
Ramiro Saenz 611235aee6 Added required scope to snap 5 years ago
Ramiro Saenz a8e5a42e51 Added new permissions to Snap package 5 years ago
Ramiro Saenz 2037dbafe5 Versioning 5 years ago
Ramiro Saenz 5eed7f02fd Changed URLs for updates and services 5 years ago
Ramiro Saenz 58b5975912 Added new Google URLs to avoid security rule 5 years ago
Karol Putra f8610047eb Merge branch 'fix/#2077-stop-rambox-when-running-out-of-space' of https://github.com/Vioner/community-edition into fix/#2077-stop-rambox-when-running-out-of-space 5 years ago
Karol Putra 072997e59c Added availableSpaceWatchDog. 5 years ago
Karol Putra 4127e0a707 Added availableSpaceWatchDog 5 years ago
Ramiro Saenz e14cfdff86 Update package.json 5 years ago
Ramiro Saenz 82f70c0c89 Changed URLs 5 years ago
Ramiro Saenz 120512e386 Update electron to 7.23.4 5 years ago
Ramiro Saenz dcaa45e86f Changed publisher name 5 years ago
Ramiro Saenz 95d04aa76e Versioning 5 years ago
Ramiro Saenz 025a8fab68 Fixes #2780 5 years ago
Ramiro Saenz 18ae907bd0 Update README.md 5 years ago
Ramiro Saenz 155a7fd2a2 Fixes #2706 5 years ago
Ramiro Saenz 6e1220fbae Added Volta 5 years ago
Ramiro Saenz c0293be615 Merge branch 'master' of https://github.com/saenzramiro/rambox 5 years ago
Ramiro Saenz 03e0c3be2d
Merge pull request #2639 from Zarel/patch-3 5 years ago
Ramiro Saenz 429721393e
Merge pull request #2751 from ramboxapp/dependabot/npm_and_yarn/electron-7.2.4 5 years ago
Ramiro Saenz 813c0d4628
Merge pull request #2671 from ramboxapp/dependabot/npm_and_yarn/auth0-js-9.13.2 5 years ago
Ramiro Saenz 3048d9d28c Install exact versions of libs 5 years ago
dependabot[bot] eb88f5d8fc
Bump electron from 7.1.12 to 7.2.4 5 years ago
Vulich Fernando d4b89a48ac Fix Do Not Disturb Tooltip 5 years ago
dependabot[bot] 02c0c549ce
Bump auth0-js from 9.7.3 to 9.13.2 5 years ago
Vulich Fernando ef2a2a9f15
Add files via upload 5 years ago
Vulich Fernando 9a5e686bb0
Add files via upload 5 years ago
Vulich Fernando 01265fdbae
Add files via upload 5 years ago
Vulich Fernando 02c8bacb2a
Add files via upload 5 years ago
Guangcong Luo c00109417f
Update repo URL in CONTRIBUTING.md 5 years ago
Vulich Fernando e01453b6a0
Merge pull request #2635 from Zarel/patch-1 5 years ago
Guangcong Luo d748323142
Update CONTRIBUTING.md with new services location 5 years ago
Vulich Fernando 7261dd10c6 Versioning 5 years ago
Vulich Fernando 10f577549a Provide option to disable auto-reload on fail 5 years ago
Vulich Fernando bec9bae9b9 Fix: Blue screen after getting the backup from Auth0 5 years ago
Vulich Fernando 151caa037d
Merge pull request #2621 from andia89/minimized 5 years ago
andreas 2185f32dd8 Adds requested changes for start minimized 5 years ago
Ramiro Saenz 168eacb2fe Added script for notarization 5 years ago
Ramiro Saenz 9166c49aae Fixed camera and mic permissions prompt 5 years ago
Ramiro Saenz 3326447d0f
Merge pull request #2628 from ramboxapp/0.7.4 5 years ago
Ramiro Saenz 313b29cd00 Versioning 5 years ago
Ramiro Saenz 7a3e4b1e6a Notarization of MacOS app 5 years ago
Ramiro Saenz 2ae71facd5 Grant camera/microphone permission to macOS Catalina 5 years ago
Vulich Fernando 4dd81ccf74 URL Regex update 5 years ago
Vulich Fernando 3937f43ffe Electron 7.1.12 5 years ago
Vulich Fernando fb1ab0dae5
Merge pull request #2623 from BKPepe/fix_readme 5 years ago
Josef Schlehofer 66f16e465d
Drop Table of Contents from menu 5 years ago
Josef Schlehofer 7d63ba374e
Fix Services available in Table of Contents 5 years ago
andreas e4f6746b28 Fixes start miniized 5 years ago
Vulich Fernando 634989427d Get the services list from Github 5 years ago
Vulich Fernando 14ab68acd7 Reload service when fail at loading 5 years ago
Vulich Fernando 7947cc20dd Grant camera/microphone permission to macOS Catalina 5 years ago
Vulich Fernando 78e86721f4 Bump to electron 7.1.12 5 years ago
Vulich Fernando 1a5ff9c8d1 Improvement of the fix for Google login issues 5 years ago
Vulich Fernando 55351f6f72 Versioning to 0.7.3 5 years ago
Vulich Fernando 83e7fd38d6 Fix: Google login issue "You are trying to sign in from a browser or app that doesn't allow us to keep your account secure" 5 years ago
Vulich Fernando ad0f70ab34 Fix Keyboard shortcuts for switching apps do not focus the app 5 years ago
Vulich Fernando 54747e8719 Fix: Services aren't editable due broken URL validation 5 years ago
Vulich Fernando c309c0f385 Change Mac DND shortcut to Cmd+Alt+D 5 years ago
Vulich Fernando 906c997ccb Fix Copy/Paste READY READY READY READY 5 years ago
Vulich Fernando 18e5794724 Versioning to 0.7.2 6 years ago
Vulich Fernando 30d93831df Fix: Skype not loading and issues with badges and notifications 6 years ago
Ramiro Saenz 48e4e9f627
Update FUNDING.yml 6 years ago
Vulich Fernando 748b1857d8 Minor fixes 6 years ago
Vulich Fernando 51e5ad8858 Versioning to 0.7.1 6 years ago
Vulich Fernando 4b8962c753
Update README.md 6 years ago
Vulich Fernando 4ad7edc4ea Fix: shortcuts interferes with Chrome/Safari/Firefox 6 years ago
Vulich Fernando 44cb534e18
Merge pull request #2453 from StormPooper/patch-1 6 years ago
Daniel Smith f3a064a237
Update DND and Lock shortcut prompts 6 years ago
Vulich Fernando 18e1ed0809 Minor focus fix 6 years ago
Vulich Fernando 7cf83a695f Fix: Rambox stays on the master password window 6 years ago
Vulich Fernando 8992c2cdda Fix Cmd+number tab changing in MacOs 6 years ago
Vulich Fernando 1f5f966e06 minor CSS fix 6 years ago
Ramiro Saenz 1874c3b900
Update .travis.yml 6 years ago
Vulich Fernando b73c7f0444 Remove unused Icons 6 years ago
Vulich Fernando 0aebff3cbb Code Cleaning 6 years ago
Vulich Fernando a5f158ecad Fix: Linux build failure 6 years ago
Vulich Fernando e1344ea05b Get Services remotely and Bump Electron to 7.1.1 6 years ago
Vulich Fernando 0ae49f55fa
Merge pull request #2409 from jcherniak/gv-update-sept-2019 6 years ago
Vulich Fernando fccf9646ac Change Regex to validate services URLs 6 years ago
Vulich Fernando ecbea2e944 Fix:Window doesn't restore from Tray in Linux 6 years ago
Vulich Fernando 8456831acc Zoom: fixes and improvements 6 years ago
Vulich Fernando 28080c10bc Change Shortcuts for DND and LockRambox 6 years ago
Vulich Fernando 55d957d5af Add Unread code to Teams 6 years ago
Vulich Fernando df66ae160a Fix: Webview is no longer focused when switching tabs 6 years ago
Vulich Fernando 7384c17c9f Fix: Fast switching with Command+1/2/3/etc. does not work 6 years ago
Vulich Fernando 1723b2472f Fix: Cursor missing 6 years ago
Vulich Fernando 5454c07f46 Logo: update Teams, Outlook and Outlook365 6 years ago
Vulich Fernando 8226efaf30
Merge pull request #2415 from ash14/fix/slack-icon 6 years ago
Vulich Fernando 7654d4ac47
Merge pull request #2379 from StormPooper/feature/update-mastodon-logo 6 years ago
Vulich Fernando 2de8e8e41b
Merge pull request #2370 from Lomanic/fix/ms-teams-blank-page 6 years ago
Vulich Fernando 41977ea554 Update: Unread Code Outlook 6 years ago
Ashvin 983b489d52
Update Slack icon fetching script 6 years ago
Justin Cherniak fbbb1b73eb Fix Google Voice unread count for September 2019 updates 6 years ago
Ramiro Saenz 76939cbc3e
Create FUNDING.yml 6 years ago
Daniel Smith f3b2c943ac Update to use official logo instead of unused favicon from PDF 6 years ago
Daniel Smith ef7afecb80 Update Mastodon logo 6 years ago
Lomanic 42be7f3a1f Fix MS Teams blank page 6 years ago
Juan Manuel Gonzalez Alama 516fa1c1b7 Update ServicesList.js 6 years ago
Juan Manuel Gonzalez Alama 5658ee5c33 Update ServicesList.js 6 years ago
Ramiro Saenz e82a945a72
Update README.md 6 years ago
Ramiro Saenz 8d509c4bca Merge branch 'master' of https://github.com/saenzramiro/rambox 6 years ago
Ramiro Saenz a5716b76c3
Merge pull request #2310 from mwohlert/feature/add-aws-workmail 6 years ago
Ramiro Saenz 0b8306d6a5 Versioning 6 years ago
Michel Wohlert 40fca201e8 Add AWS WorkMail Service 6 years ago
Juan Manuel Gonzalez Alama 51b4be02d6 Update updater.js 6 years ago
Ramiro Saenz 90f93202c4 Versioning 6 years ago
Ramiro Saenz 4e7ebdf175 Added new languages 6 years ago
Juan Manuel Gonzalez Alama 2af377c60c Merge branch 'master' of https://github.com/saenzramiro/rambox 6 years ago
Juan Manuel Gonzalez Alama 8687b2486d Update ServicesList.js 6 years ago
Ramiro Saenz 2bdd4ed07e
Update README.md 6 years ago
Juan Manuel Gonzalez Alama ef015d60c6 Update ServicesList.js 6 years ago
Juan Manuel Gonzalez Alama d619a66a99 Update ServicesList.js 6 years ago
Juan Manuel Gonzalez Alama e8c664be1c Update ServicesList.js 6 years ago
Juan Manuel Gonzalez Alama 9b344beb46 Fix Whatsapp counter 6 years ago
Juan Manuel Gonzalez Alama aa1d051b8f Update MainController.js 6 years ago
Juan Manuel Gonzalez Alama 6fd77c45e8 Disable "Remove All" if there are no services 6 years ago
Juan Manuel Gonzalez Alama b191445926 Update MainController.js 6 years ago
Juan Manuel Gonzalez Alama 6b1fb166a3 Fixed minimize behavior 6 years ago
Ramiro Saenz 810f9b9688
Update stale.yml 6 years ago
Ramiro Saenz ca7693bf84 Enable opening links in Skype 6 years ago
Ramiro Saenz c725d1984b Fixed bug on macOS when restart app on new version 6 years ago
Ramiro Saenz c61e3b7475 Versioning 6 years ago
Ramiro Saenz 8a53e4fac5 Prevent to block main process 6 years ago
Ramiro Saenz 6f382d9663
Merge pull request #2232 from maxerbox/allow-to-disable-no-connection-message 6 years ago
Ramiro Saenz 2c8d7452c5 🎪 6 years ago
mxb e27fc8d83f Dialog is always on top, and changed the way we check internet connection 6 years ago
mxb 3f3b9e66ee Added is-online package 6 years ago
Ramiro Saenz 90ccdc27cc
Merge pull request #2227 from maxerbox/fixed-snap-configuration 6 years ago
Ramiro Saenz 67164bab1e
Merge pull request #2229 from maxerbox/fixed-input-proxy-password 6 years ago
Ramiro Saenz 956ff0377e Identation 6 years ago
Ramiro Saenz 7752c37a01
Merge pull request #2230 from maxerbox/fix-input-bypass-lock 6 years ago
Ramiro Saenz 819c625f93
Merge pull request #2231 from maxerbox/fix-copy-past-not-working-master-password-field 6 years ago
Ramiro Saenz 086ceba908 Minor bug 6 years ago
Ramiro Saenz fe9056105a Improved search text feature 6 years ago
Ramiro Saenz dbeab3f95c Merge branch 'master' of https://github.com/saenzramiro/rambox 6 years ago
Ramiro Saenz 0446c9cae3 Display tabbar gray on Do Not Disturb enabled 6 years ago
Ramiro Saenz 4b0c54f7fc Fixed unread bug on window closed and keep in tray 6 years ago
Ramiro Saenz e00c86ef57 Fixed minor bug 6 years ago
Ramiro Saenz 3b8dbfef8b Added Google Duo 6 years ago
mxb 587947f867 Rewrittend the function 6 years ago
mxb 6dd7984e6d Added new message: sConfig 6 years ago
mxb 4877920787 Added handlePaste function 6 years ago
mxb 8f30ec7b8d Added script fix 6 years ago
mxb e3542d411d Set inputType as password 6 years ago
mxb 9ba564c713 Improved list 6 years ago
mxb 67b50b54ca Added camera plug 6 years ago
Juan Manuel Gonzalez Alama d4d7c4b49e
Merge pull request #2219 from maxerbox/fix-locale-language 6 years ago
Juan Manuel Gonzalez Alama 874d79e76c Update main.js 6 years ago
Juan Manuel Gonzalez Alama e664792072
Merge pull request #2223 from maxerbox/Added-search-feature 6 years ago
Juan Manuel Gonzalez Alama c961e594a5 Code review 6 years ago
mxb 93580405fc Added search feature 6 years ago
mxb 8e19c59170 Updated regular expressions for user agent 6 years ago
mxb 7bdd0a0a97 Allow to send accept language header to websites, according to settings 6 years ago
Ramiro Saenz c74bb72c7d Fixed error on save preferences 6 years ago
Ramiro Saenz e0917cb1d0 Versioning 6 years ago
Ramiro Saenz b1adbc4d25 Removed Rambox in User Agent in production 6 years ago
Ramiro Saenz 3a4e318a4f Updated electron-builder and electron-updater 6 years ago
Ramiro Saenz ecaf73835b Fixed security vulnerabilities 6 years ago
Ramiro Saenz 83d4c5cbb4
Merge pull request #2195 from nopticon/fix/allow-more-than-25-services 6 years ago
Ramiro Saenz 981dbdc445 Added more visual style when the app is in DO NOT DISTURB 6 years ago
Ramiro Saenz 9142b11928
Merge pull request #2205 from maxerbox/fix-invalid-version-whatsapp 6 years ago
Ramiro Saenz 15b2533c65
Merge pull request #2206 from maxerbox/fix-electron-issue-key-propragation 6 years ago
Ramiro Saenz f59b518e58 Minor adjustment 6 years ago
Ramiro Saenz bc844f47a0 Merge branch 'master' of https://github.com/saenzramiro/rambox 6 years ago
Ramiro Saenz 57b2c4e7b9 Use vanilla JS to detect unread code in Slack 6 years ago
mxb f9b24f1761 Closes #2191 6 years ago
mxb 106621efcc Fix issue with electron before-input-event 6 years ago
mxb aefcfa80fc Removed user agent 6 years ago
mxb 4b35ecbd25 Removed electron from user agent, because whatsapp user agent parsing server side is poorly functional 6 years ago
Guillermo Azurdia 26f65b3c05
Fix issue when adding more than 25 services. 6 years ago
Ramiro Saenz 61af48511d Updated to Electron 4.1.4 6 years ago
Ramiro Saenz 86cfd302d1 Temp fix missing cursor after upgrade to electron 3.x + 6 years ago
Ramiro Saenz d2a0170fda Removed Dasher 6 years ago
Ramiro Saenz f0159e3c02 Prevent execute AutoLaunch on dev 6 years ago
Ramiro Saenz f07625a04e typo 6 years ago
Ramiro Saenz 3886b03acf Removed Google Allo 6 years ago
Ramiro Saenz 3bfb040969 Fixed right click / context menu 6 years ago
Ramiro Saenz eaf9dff537 Changed Gmail unread code to read also from tabs like Promotions,etc 6 years ago
Ramiro Saenz 37768b9c36 Options menu does not adapt to screen 6 years ago
Ramiro Saenz 51bdce2715
Merge pull request #2034 from maxerbox/patch-4 6 years ago
Ramiro Saenz c407ecc685
Merge pull request #2050 from arthur-fr/googlecalendar 6 years ago
Ramiro Saenz 394a1debd2
Merge pull request #2055 from maxerbox/patch-5 6 years ago
Ramiro Saenz 44836bd5b8 Update languages 6 years ago
Ramiro Saenz 3168c35b46 Merge branch 'master' of https://github.com/saenzramiro/rambox 6 years ago
Ramiro Saenz 3318e39cb5
Merge pull request #2144 from bertyhell/pr/2101-hide-service-labels 6 years ago
Ramiro Saenz 0c4875ab1a Updated Electron to 4.1.1 6 years ago
Ramiro Saenz 9a4ec26997
Merge pull request #2160 from bartekczyz/master 6 years ago
Ramiro Saenz c406af2f82 Add UserAgent to WhatsApp 6 years ago
Ramiro Saenz e615605342 Versioning 6 years ago
Ramiro Saenz b89c8a0f98
Fix AZERTY Ctrl Z and Ctrl W 6 years ago
Ramiro Saenz e32bcce9d1
Update WebView.js 6 years ago
mxb fdd1ae30f6 Put keycode at the top 6 years ago
Bartek Czyż 1376383050 Allow mainWindow to be undefined 6 years ago
Bert Verhelst 8114c44276 Set hide_tabbar_labels default to false 6 years ago
Bert Verhelst d726ed0b23 feat: #2101 Add option to hide tabbar labels 6 years ago
Simon Sassi 87b60ad296
Merge branch 'master' into patch-5 6 years ago
Simon Sassi 768eaede43
Fixed external link opening 6 years ago
@rthur 6dac82ea62 Added Google Calendar 6 years ago
Simon Sassi 921fc80447
Unscaped espaced json character xD 6 years ago
Simon Sassi 8a240df1da
Escaped json special characters 6 years ago
Simon Sassi 65f5699bb8
Edited gmail notification check 6 years ago
  1. 3
      .github/FUNDING.yml
  2. 7
      .github/stale.yml
  3. 2
      .gitignore
  4. 2
      .npmrc
  5. 5
      .travis.yml
  6. 6
      Backers.md
  7. 43
      CONTRIBUTING.md
  8. 135
      README.md
  9. 41
      app.js
  10. 8
      app.json
  11. 432
      app/Application.js
  12. 9
      app/store/Services.js
  13. 938
      app/store/ServicesList.js
  14. 17
      app/util/IconLoader.js
  15. 289
      app/ux/Auth0.js
  16. 480
      app/ux/WebView.js
  17. 27
      app/view/add/Add.js
  18. 1
      app/view/add/AddController.js
  19. 154
      app/view/main/Main.js
  20. 121
      app/view/main/MainController.js
  21. 1
      app/view/main/MainModel.js
  22. 99
      app/view/preferences/Preferences.js
  23. 2
      app/view/preferences/PreferencesController.js
  24. 7
      appveyor.yml
  25. 277
      electron/main.js
  26. 74
      electron/menu.js
  27. 4
      electron/tray.js
  28. 18
      electron/updater.js
  29. 5
      env-sample.js
  30. 67
      index.html
  31. 20
      masterpassword.html
  32. 5465
      package-lock.json
  33. 114
      package.json
  34. 12
      packages/local/rambox-default-theme/sass/etc/all.scss
  35. BIN
      resources/auth0.png
  36. BIN
      resources/icons/airdroid.png
  37. BIN
      resources/icons/allo.png
  38. BIN
      resources/icons/amium.png
  39. BIN
      resources/icons/androidmessages.png
  40. BIN
      resources/icons/aol.png
  41. BIN
      resources/icons/awsworkmail.png
  42. BIN
      resources/icons/bearychat.png
  43. BIN
      resources/icons/bip.png
  44. BIN
      resources/icons/calendar.png
  45. BIN
      resources/icons/cliq.png
  46. BIN
      resources/icons/clocktweets.png
  47. BIN
      resources/icons/converse.png
  48. BIN
      resources/icons/crisp.png
  49. BIN
      resources/icons/dasher.png
  50. BIN
      resources/icons/dingtalk.png
  51. BIN
      resources/icons/discord.png
  52. BIN
      resources/icons/drift.png
  53. BIN
      resources/icons/duo.png
  54. BIN
      resources/icons/element.png
  55. BIN
      resources/icons/facebook.png
  56. BIN
      resources/icons/fastmail.png
  57. BIN
      resources/icons/fleep.png
  58. BIN
      resources/icons/flock.png
  59. BIN
      resources/icons/freenode.png
  60. BIN
      resources/icons/glip.png
  61. BIN
      resources/icons/glowingbear.png
  62. BIN
      resources/icons/gmail.png
  63. BIN
      resources/icons/googledrive.png
  64. BIN
      resources/icons/googlevoice.png
  65. BIN
      resources/icons/grape.png
  66. BIN
      resources/icons/guilded.png
  67. BIN
      resources/icons/hangoutschat.png
  68. BIN
      resources/icons/hibox.png
  69. BIN
      resources/icons/hipchat.png
  70. BIN
      resources/icons/honeypot.png
  71. BIN
      resources/icons/hootsuite.png
  72. BIN
      resources/icons/horde.png
  73. BIN
      resources/icons/hushmail.png
  74. BIN
      resources/icons/icloud.png
  75. BIN
      resources/icons/icloudmail.png
  76. BIN
      resources/icons/icq.png
  77. BIN
      resources/icons/instagramdirect.png
  78. BIN
      resources/icons/intercom.png
  79. BIN
      resources/icons/irccloud.png
  80. BIN
      resources/icons/jandi.png
  81. BIN
      resources/icons/kaiwa.png
  82. BIN
      resources/icons/kiwi.png
  83. BIN
      resources/icons/kune.png
  84. BIN
      resources/icons/linkedin.png
  85. BIN
      resources/icons/lounge.png
  86. BIN
      resources/icons/mailru.png
  87. BIN
      resources/icons/mastodon.png
  88. BIN
      resources/icons/mattermost.png
  89. BIN
      resources/icons/messenger.png
  90. BIN
      resources/icons/mightytext.png
  91. BIN
      resources/icons/missive.png
  92. BIN
      resources/icons/mmmelon.png
  93. BIN
      resources/icons/movim.png
  94. BIN
      resources/icons/noysi.png
  95. BIN
      resources/icons/office365.png
  96. BIN
      resources/icons/okru.png
  97. BIN
      resources/icons/openmailbox.png
  98. BIN
      resources/icons/outlook.png
  99. BIN
      resources/icons/outlook365.png
  100. BIN
      resources/icons/protonmail.png
  101. Some files were not shown because too many files have changed in this diff Show More

3
.github/FUNDING.yml

@ -0,0 +1,3 @@
# These are supported funding model platforms
custom: ['https://rambox.app/donate.html']

7
.github/stale.yml

@ -2,14 +2,19 @@
daysUntilStale: 60
# Number of days of inactivity before a stale issue is closed
daysUntilClose: 7
# Only issues or pull requests with all of these labels are check if stale. Defaults to `[]` (disabled)
onlyLabels:
- more-information-needed
# Issues with these labels will never be considered stale
exemptLabels:
- bug
- to do
- enhancement
- feature request
- in progress
- investigate
# Label to use when marking an issue as stale
staleLabel: wontfix
staleLabel: stale
# Comment to post when marking an issue as stale. Set to `false` to disable
markComment: >
This issue has been automatically marked as stale because it has not had

2
.gitignore vendored

@ -34,7 +34,5 @@ npm-debug.log
# Vagrant
.vagrant/
env.js
rambox_cfg.json
languages.js
electron/dev-app-update.yml

2
.npmrc

@ -0,0 +1,2 @@
package-lock = false
save-exact = true

5
.travis.yml

@ -1,9 +1,9 @@
matrix:
include:
- os: osx
osx_image: xcode9.4
osx_image: xcode12.4
language: node_js
node_js: "10"
node_js: "14.16.1"
env:
- ELECTRON_CACHE=$HOME/.cache/electron
- ELECTRON_BUILDER_CACHE=$HOME/.cache/electron-builder
@ -44,5 +44,6 @@ script:
else
cd $TRAVIS_BUILD_DIR/build/production/Rambox/
npm i
npm i cli-truncate
npm run build:osx
fi

6
Backers.md

@ -1,6 +0,0 @@
# Monthly Donators
[Martin Grünbaum](https://github.com/alathon)
Ivan Toshkov
[Simon Joda Stößer](https://github.com/SimJoSt)

43
CONTRIBUTING.md

@ -2,7 +2,7 @@
We welcome pull requests! Follow these steps to contribute:
1. Find an [issue](https://github.com/saenzramiro/rambox/issues) that needs assistance.
1. Find an [issue](https://github.com/ramboxapp/community-edition/issues) that needs assistance.
1. Let us know you are working on it by posting a comment on the issue.
1. Follow the [Contribution Guidelines](#contribution-guidelines) to start working on the issue.
@ -65,15 +65,15 @@ If your versions are lower than the prerequisite versions, you should update.
#### Forking rambox
1. Go to the top level rambox repository: <https://github.com/saenzramiro/rambox>
1. Go to the top level rambox repository: <https://github.com/ramboxapp/community-edition>
1. Click the "Fork" Button in the upper right hand corner of the interface ([More Details Here](https://help.github.com/articles/fork-a-repo/))
1. After the repository (repo) has been forked, you will be taken to your copy of the rambox repo at <https://github.com/yourUsername/rambox>
1. After the repository (repo) has been forked, you will be taken to your copy of the rambox repo at <https://github.com/yourUsername/community-edition>
#### Cloning Your Fork
1. Open a Terminal / Command Line / Bash Shell in your projects directory (_i.e.: `/yourprojectdirectory/`_)
1. Clone your fork of rambox
- `git clone https://github.com/yourUsername/rambox.git`
- `git clone https://github.com/yourUsername/community-edition.git`
**(make sure to replace `yourUsername` with your GitHub username)**
@ -81,9 +81,9 @@ This will download the entire rambox repo to your projects directory.
#### Setup Your Upstream
1. Change directory to the new rambox directory (`cd rambox`)
1. Change directory to the new rambox directory (`cd community-edition`)
1. Add a remote to the official rambox repo:
- `git remote add upstream https://github.com/saenzramiro/rambox.git`
- `git remote add upstream https://github.com/ramboxapp/community-edition.git`
Congratulations, you now have a local copy of the rambox repo! :tada:
@ -122,22 +122,6 @@ Once you have rambox cloned, before you start the application, you first need to
npm install
```
Then you need to add the private environment variables (API Keys):
```bash
# Copy `env-sample.js` with a name of env.js
# Populate it with Auth0 clientid and domain e.g. test.auth0.com
# You can get these details from one of your "apps" here https://manage.auth0.com/#/clients/
# macOS / Linux
cp env-sample.js env.js
# Windows
copy env-sample.js env.js
```
Then edit the `env.js` file and modify the API keys only for services that you will use.
```bash
# Compile the files...
sencha app watch
@ -157,8 +141,11 @@ Always feel free to reach out to the chat room when you are not certain of any t
#### Adding or Editing Services
The services are stored inside the file `./app/store/ServicesList.js`. Add your service to the *BOTTOM* of the array.
The logo it's referencing is located in `./resources/icons/`.
The services are stored inside the file `./api/services.json` in the `gh-pages` branch:
https://github.com/ramboxapp/community-edition/blob/gh-pages/api/services.json
Add your service to the *BOTTOM* of the array.
To see these changes you'll need to stop your `npm start` and `sencha app watch`, and then rerun those.
### Creating a Pull Request
@ -170,15 +157,15 @@ You will make changes to copies of thefiles which make up rambox in a personal f
#### Important: ALWAYS EDIT ON A BRANCH
Take away only one thing from this document: Never, **EVER** make edits to the `staging` branch.
Take away only one thing from this document: Never, **EVER** make edits to the `master` branch.
ALWAYS make a new branch BEFORE you edit files.
This is critical, because if your PR is not accepted, your copy of staging will be forever sullied and the only way to fix it is to delete your fork and re-fork.
This is critical, because your copy of `master` will be forever sullied and the only way to fix it is a difficult hard-reset and force-push process, or deleting your fork and re-forking.
### Common Steps
1. Once the edits have been committed, you will be prompted to create a pull request on your fork's GitHub Page.
1. By default, all pull requests should be against the rambox main repo, `staging` branch.
- **Make sure that your Base Fork is set to saenzramiro/rambox when raising a Pull Request.**
1. By default, all pull requests should be against the rambox main repo, `master` branch.
- **Make sure that your Base Fork is set to ramboxapp/community-edition when raising a Pull Request.**
1. Submit a pull request.
1. The title (also called the subject) of your PR should be descriptive of your changes and succinctly indicates what is being fixed.
- **Do not add the issue number in the PR title or commit message.**

135
README.md

@ -1,3 +1,14 @@
# EOL
The Community Edition of Rambox is no longer maintained. We highly recommend that you update to the new version of Rambox, which has a FREE plan with all the features you already use and much more!
Visit: https://rambox.app/download
Thank you so much for all the users who contribute to this project all these years.
[Read our blog post to know more about our new Rambox.](https://rambox.medium.com/hello-2022-hello-new-rambox-4bdef5d6c3b8)
---
<div align="center">
<h1>
<br />
@ -26,7 +37,7 @@
<h5>Available for Windows, Mac and Linux.</h5>
<h5><a href="https://rambox.pro/#download" target="_blank"><img src="https://cdn.rawgit.com/saenzramiro/rambox/gh-pages/images/img-download.svg" width="250" alt="DOWNLOAD HERE" /></a></h5>
<h5><a href="https://rambox.pro/#ce" target="_blank"><img src="https://cdn.rawgit.com/saenzramiro/rambox/gh-pages/images/img-download.svg" width="250" alt="DOWNLOAD HERE" /></a></h5>
<h6>Logo designed by <a href="https://www.linkedin.com/in/andriyyurchenko/" target="_blank">Andriy Yurchenko</a></h6>
</div>
@ -35,9 +46,8 @@
## Table of Contents
- [Table of Contents](#table-of-contents)
- [Screenshot](#screenshot)
- [Services available - 100](#services-available---100)
- [Apps available](#apps-available)
- [Features](#features)
- [Privacy](#privacy)
- [Donations](#donations)
@ -54,118 +64,9 @@
![Rambox](./resources/screenshots/mac.png)
## Services available - 103
<img width="80" align="left" src="./resources/icons/whatsapp.png" alt="WhatsApp" title="WhatsApp" />
<img width="80" align="left" src="./resources/icons/messenger.png" alt="Messenger" title="Messenger" />
<img width="80" align="left" src="./resources/icons/skype.png" alt="Skype" title="Skype" />
<img width="80" align="left" src="./resources/icons/slack.png" alt="Slack" title="Slack" />
<img width="80" align="left" src="./resources/icons/hangouts.png" alt="Hangouts" title="Hangouts" />
<img width="80" align="left" src="./resources/icons/telegram.png" alt="Telegram" title="Telegram" />
<img width="80" align="left" src="./resources/icons/wechat.png" alt="WeChat" title="WeChat" />
<img width="80" align="left" src="./resources/icons/gmail.png" alt="Gmail" title="Gmail" />
<img width="80" align="left" src="./resources/icons/inbox.png" alt="Inbox" title="Inbox" />
<img width="80" align="left" src="./resources/icons/hipchat.png" alt="HipChat" title="HipChat" />
<img width="80" align="left" src="./resources/icons/allo.png" alt="Allo" title="Allo" />
<img width="80" align="left" src="./resources/icons/chatwork.png" alt="ChatWork" title="ChatWork"/>
<img width="80" align="left" src="./resources/icons/groupme.png" alt="GroupMe" title="GroupMe"/>
<img width="80" align="left" src="./resources/icons/grape.png" alt="Grape" title="Grape"/>
<img width="80" align="left" src="./resources/icons/gitter.png" alt="Gitter" title="Gitter"/>
<img width="80" align="left" src="./resources/icons/steam.png" alt="Steam" title="Steam"/>
<img width="80" align="left" src="./resources/icons/discord.png" alt="Discord" title="Discord"/>
<img width="80" align="left" src="./resources/icons/noysi.png" alt="Noysi" title="Noysi"/>
<img width="80" align="left" src="./resources/icons/outlook.png" alt="Outlook" title="Outlook"/>
<img width="80" align="left" src="./resources/icons/outlook365.png" alt="Outlook 365" title="Outlook 365"/>
<img width="80" align="left" src="./resources/icons/tutanota.png" alt="TutaNota" title="TutaNota"/>
<img width="80" align="left" src="./resources/icons/hushmail.png" alt="Hushmail" title="Hushmail" />
<img width="80" align="left" src="./resources/icons/bearychat.png" alt="BearyChat" title="BearyChat" />
<img width="80" align="left" src="./resources/icons/aol.png" alt="Aol" title="Aol" />
<img width="80" align="left" src="./resources/icons/sync.png" alt="Sync" title="Sync" />
<img width="80" align="left" src="./resources/icons/wire.png" alt="Wire" title="Wire" />
<img width="80" align="left" src="./resources/icons/rocketchat.png" alt="Rocket Chat" title="Rocket Chat" />
<img width="80" align="left" src="./resources/icons/missive.png" alt="Missive" title="Missive" />
<img width="80" align="left" src="./resources/icons/yahoo.png" alt="Yahoo! Mail" title="Yahoo! Mail" />
<img width="80" align="left" src="./resources/icons/ryver.png" alt="Ryver" title="Ryver" />
<img width="80" align="left" src="./resources/icons/yandex.png" alt="Yandex Mail" title="Yandex Mail" />
<img width="80" align="left" src="./resources/icons/dasher.png" alt="Dasher" title="Dasher" />
<img width="80" align="left" src="./resources/icons/dingtalk.png" alt="DingTalk" title="DingTalk" />
<img width="80" align="left" src="./resources/icons/flowdock.png" alt="FlowDock" title="FlowDock" />
<img width="80" align="left" src="./resources/icons/mattermost.png" alt="Mattermost" title="Mattermost" />
<img width="80" align="left" src="./resources/icons/voxer.png" alt="Voxer" title="Voxer" />
<img width="80" align="left" src="./resources/icons/glip.png" alt="Glip" title="Glip" />
<img width="80" align="left" src="./resources/icons/yahoomessenger.png" alt="Yahoo! Messenger" title="Yahoo! Messenger" />
<img width="80" align="left" src="./resources/icons/mysms.png" alt="mysms" title="mysms" />
<img width="80" align="left" src="./resources/icons/icq.png" alt="ICQ" title="ICQ" />
<img width="80" align="left" src="./resources/icons/tweetdeck.png" alt="TweetDeck" title="TweetDeck" />
<img width="80" align="left" src="./resources/icons/zinc.png" alt="Zinc" title="Zinc" />
<img width="80" align="left" src="./resources/icons/freenode.png" alt="FreeNode" title="FreeNode" />
<img width="80" align="left" src="./resources/icons/mightytext.png" alt="MightyText" title="MightyText" />
<img width="80" align="left" src="./resources/icons/zohoemail.png" alt="Zoho Email" title="Zoho Email" />
<img width="80" align="left" src="./resources/icons/zohocliq.png" alt="Zoho Cliq" title="Zoho Cliq" />
<img width="80" align="left" src="./resources/icons/roundcube.png" alt="Roundcube" title="Roundcube" />
<img width="80" align="left" src="./resources/icons/horde.png" alt="Horde" title="Horde" />
<img width="80" align="left" src="./resources/icons/squirrelmail.png" alt="SquirrelMail" title="SquirrelMail" />
<img width="80" align="left" src="./resources/icons/zimbra.png" alt="Zimbra" title="Zimbra" />
<img width="80" align="left" src="./resources/icons/hootsuite.png" alt="Hootsuite" title="Hootsuite" />
<img width="80" align="left" src="./resources/icons/amium.png" alt="Amium" title="Amium" />
<img width="80" align="left" src="./resources/icons/rainloop.png" alt="RainLoop" title="RainLoop" />
<img width="80" align="left" src="./resources/icons/icloud.png" alt="iCloud Mail" title="iCloud Mail" />
<img width="80" align="left" src="./resources/icons/irccloud.png" alt="IRC Cloud" title="IRC Cloud" />
<img width="80" align="left" src="./resources/icons/kiwi.png" alt="Kiwi IRC" title="Kiwi IRC" />
<img width="80" align="left" src="./resources/icons/smooch.png" alt="Smooch" title="Smooch" />
<img width="80" align="left" src="./resources/icons/crisp.png" alt="Crisp" title="Crisp" />
<img width="80" align="left" src="./resources/icons/flock.png" alt="Flock" title="Flock" />
<img width="80" align="left" src="./resources/icons/openmailbox.png" alt="Openmailbox" title="Openmailbox" />
<img width="80" align="left" src="./resources/icons/typetalk.png" alt="Typetalk" title="Typetalk" />
<img width="80" align="left" src="./resources/icons/drift.png" alt="Drift" title="Drift" />
<img width="80" align="left" src="./resources/icons/webexteams.png" alt="Cisco Webex Teams" title="Cisco Webex Teams" />
<img width="80" align="left" src="./resources/icons/fleep.png" alt="Fleep" title="Fleep" />
<img width="80" align="left" src="./resources/icons/socialcast.png" alt="Socialcast" title="Socialcast" />
<img width="80" align="left" src="./resources/icons/riot.png" alt="Riot" title="Riot" />
<img width="80" align="left" src="./resources/icons/pushbullet.png" alt="Pushbullet" title="Pushbullet" />
<img width="80" align="left" src="./resources/icons/movim.png" alt="Movim" title="Movim" />
<img width="80" align="left" src="./resources/icons/kaiwa.png" alt="Kaiwa" title="Kaiwa" />
<img width="80" align="left" src="./resources/icons/zyptonite.png" alt="Zyptonite" title="Zyptonite" />
<img width="80" align="left" src="./resources/icons/linkedin.png" alt="LinkedIn" title="LinkedIn" />
<img width="80" align="left" src="./resources/icons/lounge.png" alt="The Lounge" title="The Lounge" />
<img width="80" align="left" src="./resources/icons/kezmo.png" alt="Kezmo" title="Kezmo" />
<img width="80" align="left" src="./resources/icons/teams.png" alt="Teams" title="Teams" />
<img width="80" align="left" src="./resources/icons/xing.png" alt="Xing" title="Xing" />
<img width="80" align="left" src="./resources/icons/workplace.png" alt="Workplace" title="Workplace" />
<img width="80" align="left" src="./resources/icons/fastmail.png" alt="FastMail" title="FastMail" />
<img width="80" align="left" src="./resources/icons/hibox.png" alt="Hibox" title="Hibox" />
<img width="80" align="left" src="./resources/icons/jandi.png" alt="Jandi" title="Jandi" />
<img width="80" align="left" src="./resources/icons/threema.png" alt="Threema" title="Threema" />
<img width="80" align="left" src="./resources/icons/messengerpages.png" alt="Messenger for Pages" title="Messenger for Pages" />
<img width="80" align="left" src="./resources/icons/vk.png" alt="VK Messenger" title="VK Messenger" />
<img width="80" align="left" src="./resources/icons/mastodon.png" alt="Mastodon" title="Mastodon" />
<img width="80" align="left" src="./resources/icons/teamworkchat.png" alt="Teamwork Chat" title="Teamwork Chat" />
<img width="80" align="left" src="./resources/icons/clocktweets.png" alt="ClockTweets" title="ClockTweets" />
<img width="80" align="left" src="./resources/icons/intercom.png" alt="Intercom" title="Intercom" />
<img width="80" align="left" src="./resources/icons/googlevoice.png" alt="Voice" title="Voice" />
<img width="80" align="left" src="./resources/icons/sandstorm.png" alt="Sandstorm" title="Sandstorm" />
<img width="80" align="left" src="./resources/icons/gadugadu.png" alt="Gadu-Gadu" title="Gadu-Gadu" />
<img width="80" align="left" src="./resources/icons/mailru.png" alt="Mail.Ru" title="Mail.Ru" />
<img width="80" align="left" src="./resources/icons/kune.png" alt="Kune" title="Kune" />
<img width="80" align="left" src="./resources/icons/zulip.png" alt="Zulip" title="Zulip" />
<img width="80" align="left" src="./resources/icons/stride.png" alt="Stride" title="Stride" />
<img width="80" align="left" src="./resources/icons/hangoutschat.png" alt="Hangouts Chat" title="Hangouts Chat" />
<img width="80" align="left" src="./resources/icons/messengerpages.png" alt="Messenger for Business" title="Messenger for Business" />
<img width="80" align="left" src="./resources/icons/androidmessages.png" alt="Android Messages" title="Android Messages">
<img width="80" align="left" src="./resources/icons/sococo.png" alt="Sococo" title="Sococo">
<img width="80" align="left" src="./resources/icons/tawkto.png" alt="Tawk.to" title="Tawk.to">
<img width="80" align="left" src="./resources/icons/protonmail.png" alt="ProtonMail & ProtonMail Onion" title="ProtonMail & ProtonMail Onion">
<img width="80" align="left" src="./resources/icons/devrant.png" alt="devRant" title="devRant">
<img width="80" align="left" src="./resources/icons/reddit.png" alt="Reddit" title="Reddit">
<br><br><br><br><br><br><br><br><br><br><br><br><br><br><br><br><br><br><br><br><br><br><br><br><br><br><br><br><br><br><br><br><br><br><br><br><br><br><br><br><br><br><br><br>
## Apps available
Visit our website https://rambox.app/#apps and select the "Community-Edition" filter to see all the apps available.
## Features
@ -200,7 +101,7 @@ You are always welcome to check the code! ;)
| Type | URL/Wallet |
| ---------------- | :----------------------------------------------------------------------------------------: |
| Credit Cards | [HERE](https://rambox.pro/#donate) |
| Credit Cards | [HERE](https://rambox.app/donate.html) |
| Cryptocurrencies | [HERE](https://www.vaulty.io/v/b6480279-af28-4855-868c-17e5cb0ae7fa) |
## Translations
@ -220,8 +121,6 @@ Fork and work!
```shell
git clone https://github.com/saenzramiro/rambox.git
cd rambox
cp env-sample.js env.js
# update env.js with your auth0 details.
npm install
sencha app watch
npm start

41
app.js

@ -16,7 +16,11 @@ Ext.application({
// auto update logic
const ipc = require('electron').ipcRenderer;
require('electron-context-menu')();
const { ContextMenuBuilder, ContextMenuListener } = require('electron-contextmenu-wrapper');
const contextMenuBuilder = new ContextMenuBuilder();
const contextMenuListener = new ContextMenuListener(function(event, info) {
contextMenuBuilder.showPopupMenu(info);
});
ipc.on('showAbout', function(event, message) {
!Ext.cq1('about') ? Ext.create('Rambox.view.main.About') : '';
@ -24,6 +28,10 @@ ipc.on('showAbout', function(event, message) {
ipc.on('showPreferences', function(event, message) {
!Ext.cq1('preferences') ? Ext.create('Rambox.view.preferences.Preferences').show() : '';
});
ipc.on('grantPermissions', async function() {
await require('electron').remote.systemPreferences.askForMediaAccess('microphone');
await require('electron').remote.systemPreferences.askForMediaAccess('camera');
});
ipc.on('autoUpdater:check-update', function() {
Rambox.app.checkUpdate();
});
@ -53,18 +61,18 @@ ipc.on('autoUpdater:update-downloaded', function(e, info) {
'->'
,{
xtype: 'label'
,html: '<b>New version ready to install ('+info.version+')!</b> It will be installed the next time Rambox is relaunched.'
,html: '<b>New version is ready to be installed ('+info.version+')!</b> Click the following button to install it now.'
}
,{
xtype: 'button'
,text: 'Relaunch Now'
,text: 'Install now'
,handler: function(btn) { ipc.send('autoUpdater:quit-and-install'); }
}
,{
xtype: 'button'
,text: 'Changelog'
,ui: 'decline'
,href: 'https://github.com/ramboxapp/community-edition/releases/tag/'+info.version
,href: 'https://github.com/ramboxapp/download/releases/latest'
}
,'->'
,{
@ -143,3 +151,28 @@ ipc.on('toggleStatusBar', function() {
window.addEventListener('focus', function() {
if(Ext.cq1("app-main")) Ext.cq1("app-main").getActiveTab().down('component').el.dom.focus();
});
// Handles zoom from menu
ipc.on('resetzoom-webview', function() {
var tabPanel = Ext.cq1('app-main');
if ( tabPanel.items.indexOf(tabPanel.getActiveTab()) === 0 ) return false;
tabPanel.getActiveTab().resetZoom();
});
ipc.on('zoomin-webview', function() {
var tabPanel = Ext.cq1('app-main');
if ( tabPanel.items.indexOf(tabPanel.getActiveTab()) === 0 ) return false;
tabPanel.getActiveTab().zoomIn();
});
ipc.on('zoomout-webview', function() {
var tabPanel = Ext.cq1('app-main');
if ( tabPanel.items.indexOf(tabPanel.getActiveTab()) === 0 ) return false;
tabPanel.getActiveTab().zoomOut();
});
ipc.on('shortcut:tab', function(e, arg) {
var tabPanel = Ext.cq1('app-main');
if ( arg >= tabPanel.items.indexOf(Ext.getCmp('tbfill')) ) arg++;
tabPanel.setActiveTab(arg);
});

8
app.json

@ -109,10 +109,6 @@
{
"path": "resources/js/loadscreen.js"
},
{
"path": "env.js",
"remote": true
},
{
"path": "app.js",
"bundle": true
@ -291,10 +287,10 @@
*/
"resources": [
"electron",
"env.js",
"package.json",
"package-lock.json",
"masterpassword.html"
"masterpassword.html",
"screenselector.html"
],
/**

432
app/Application.js

@ -4,8 +4,7 @@ Ext.define('Rambox.Application', {
,name: 'Rambox'
,requires: [
'Rambox.ux.Auth0'
,'Rambox.util.MD5'
'Rambox.util.MD5'
,'Ext.window.Toast'
,'Ext.util.Cookies'
]
@ -23,204 +22,211 @@ Ext.define('Rambox.Application', {
,config: {
totalServicesLoaded: 0
,totalNotifications: 0
,googleURLs: []
}
,launch: function () {
// Prevent track if the user have disabled this option (default: false)
if ( !ipc.sendSync('sendStatistics') ) {
ga_storage = {
_enableSSL: Ext.emptyFn
,_disableSSL: Ext.emptyFn
,_setAccount: Ext.emptyFn
,_setDomain: Ext.emptyFn
,_setLocale: Ext.emptyFn
,_setCustomVar: Ext.emptyFn
,_deleteCustomVar: Ext.emptyFn
,_trackPageview: Ext.emptyFn
,_trackEvent: Ext.emptyFn
}
}
// Set Google Analytics events
ga_storage._setAccount('UA-80680424-1');
ga_storage._trackPageview('/index.html', 'main');
ga_storage._trackEvent('Versions', require('electron').remote.app.getVersion());
// Load language for Ext JS library
Ext.Loader.loadScript({url: Ext.util.Format.format("ext/packages/ext-locale/build/ext-locale-{0}.js", localStorage.getItem('locale-auth0') || 'en')});
// Initialize Auth0
if ( auth0Cfg.clientID !== '' && auth0Cfg.domain !== '' ) Rambox.ux.Auth0.init();
// Set cookies to help Tooltip.io messages segmentation
Ext.util.Cookies.set('version', require('electron').remote.app.getVersion());
if ( Ext.util.Cookies.get('auth0') === null ) Ext.util.Cookies.set('auth0', false);
// Check for updates
if ( require('electron').remote.process.argv.indexOf('--without-update') === -1 ) Rambox.app.checkUpdate(true);
// Add shortcuts to switch services using CTRL + Number
document.keyMapping = new Ext.util.KeyMap({
target: document
,binding: [
{
key: "\t"
,ctrl: true
,alt: false
,shift: false
,handler: function(key) {
var tabPanel = Ext.cq1('app-main');
var activeIndex = tabPanel.items.indexOf(tabPanel.getActiveTab());
var i = activeIndex + 1;
// "cycle" (go to the start) when the end is reached or the end is the spacer "tbfill"
if (i === tabPanel.items.items.length || i === tabPanel.items.items.length - 1 && tabPanel.items.items[i].id === 'tbfill') i = 0;
// skip spacer
while (tabPanel.items.items[i].id === 'tbfill') i++;
,launch: function () {
tabPanel.setActiveTab(i);
}
const isOnline = require('is-online');
const Mousetrap = require('mousetrap');
(async () => {
await isOnline().then(res => {
var hideNoConnection = ipc.sendSync('getConfig').hideNoConnectionDialog
if ( !res && !hideNoConnection ) {
Ext.get('spinner') ? Ext.get('spinner').destroy() : null;
Ext.get('background') ? Ext.get('background').destroy() : null;
Ext.Msg.show({
title: 'No Internet Connection'
,msg: 'Please, check your internet connection. If you use a Proxy, please go to Preferences to configure it. Rambox will try to re-connect in 10 seconds'
,width: 300
,closable: false
,buttons: Ext.Msg.YESNO
,buttonText: {
yes: 'Ok'
,no: 'Never show this again'
}
,multiline: false
,fn: function(buttonValue, inputText, showConfig) {
if ( buttonValue === 'no' ) {
ipc.send('sConfig', { hideNoConnectionDialog: true });
hideNoConnection = true;
}
}
,icon: Ext.Msg.QUESTION
});
setTimeout(function() {
if ( !hideNoConnection ) ipc.send('reloadApp')
}, 10000)
}
,{
key: "\t"
,ctrl: true
,alt: false
,shift: true
,handler: function(key) {
var tabPanel = Ext.cq1('app-main');
var activeIndex = tabPanel.items.indexOf(tabPanel.getActiveTab());
var i = activeIndex - 1;
if ( i < 0 ) i = tabPanel.items.items.length - 1;
while ( tabPanel.items.items[i].id === 'tbfill' || i < 0 ) i--;
tabPanel.setActiveTab( i );
})
})();
if ( !localStorage.getItem('hideMacPermissions') && process.platform === 'darwin' && (require('electron').remote.systemPreferences.getMediaAccessStatus('microphone') !== 'granted' || require('electron').remote.systemPreferences.getMediaAccessStatus('camera') !== 'granted') ) {
console.info('Checking mac permissions...');
Ext.cq1('app-main').addDocked({
xtype: 'toolbar'
,dock: 'top'
,style: {background: '#30BBF3'}
,items: [
'->'
,{
xtype: 'label'
,html: '<b>Rambox CE needs permissions to use Microphone and Camera for the apps.</b>'
}
}
,{
key: Ext.event.Event.PAGE_DOWN
,ctrl: true
,alt: false
,shift: false
,handler: function(key) {
var tabPanel = Ext.cq1('app-main');
var activeIndex = tabPanel.items.indexOf(tabPanel.getActiveTab());
var i = activeIndex + 1;
// "cycle" (go to the start) when the end is reached or the end is the spacer "tbfill"
if (i === tabPanel.items.items.length || i === tabPanel.items.items.length - 1 && tabPanel.items.items[i].id === 'tbfill') i = 0;
// skip spacer
while (tabPanel.items.items[i].id === 'tbfill') i++;
tabPanel.setActiveTab(i);
,{
xtype: 'button'
,text: 'Grant permissions'
,ui: 'decline'
,handler: async function(btn) {
await require('electron').remote.systemPreferences.askForMediaAccess('microphone');
await require('electron').remote.systemPreferences.askForMediaAccess('camera');
Ext.cq1('app-main').removeDocked(btn.up('toolbar'), true);
}
}
}
,{
key: Ext.event.Event.PAGE_UP
,ctrl: true
,alt: false
,shift: false
,handler: function(key) {
var tabPanel = Ext.cq1('app-main');
var activeIndex = tabPanel.items.indexOf(tabPanel.getActiveTab());
var i = activeIndex - 1;
if ( i < 0 ) i = tabPanel.items.items.length - 1;
while ( tabPanel.items.items[i].id === 'tbfill' || i < 0 ) i--;
tabPanel.setActiveTab( i );
,{
xtype: 'button'
,text: 'Never ask again'
,ui: 'decline'
,handler: function(btn) {
Ext.cq1('app-main').removeDocked(btn.up('toolbar'), true);
localStorage.setItem('hideMacPermissions', true);
}
}
}
,{
key: [Ext.event.Event.NUM_PLUS, Ext.event.Event.NUM_MINUS, 187, 189]
,ctrl: true
,alt: false
,shift: false
,handler: function(key) {
var tabPanel = Ext.cq1('app-main');
if ( tabPanel.items.indexOf(tabPanel.getActiveTab()) === 0 ) return false;
key === Ext.event.Event.NUM_PLUS || key === 187 ? tabPanel.getActiveTab().zoomIn() : tabPanel.getActiveTab().zoomOut();
,'->'
,{
glyph: 'xf00d@FontAwesome'
,baseCls: ''
,style: 'cursor:pointer;'
,handler: function(btn) { Ext.cq1('app-main').removeDocked(btn.up('toolbar'), true); }
}
}
,{
key: [Ext.event.Event.NUM_ZERO, '0']
,ctrl: true
,alt: false
,shift: false
,handler: function(key) {
var tabPanel = Ext.cq1('app-main');
if ( tabPanel.items.indexOf(tabPanel.getActiveTab()) === 0 ) return false;
]
});
}
tabPanel.getActiveTab().resetZoom();
}
}
,{
key: "123456789"
,ctrl: true
,alt: false
,handler: function(key) {
key = key - 48;
if ( key >= Ext.cq1('app-main').items.indexOf(Ext.getCmp('tbfill')) ) key++;
Ext.cq1('app-main').setActiveTab(key);
}
}
,{
key: 188 // comma
,ctrl: true
,alt: false
,handler: function(key) {
Ext.cq1('app-main').setActiveTab(0);
}
}
,{
key: Ext.event.Event.F1
,ctrl: false
,alt: false
,shift: false
,handler: function(key) {
var btn = Ext.getCmp('disturbBtn');
btn.toggle();
Ext.cq1('app-main').getController().dontDisturb(btn, true);
}
}
,{
key: Ext.event.Event.F2
,ctrl: false
,alt: false
,shift: false
,handler: function(key) {
var btn = Ext.getCmp('lockRamboxBtn');
Ext.cq1('app-main').getController().lockRambox(btn);
}
}
]
});
// Mouse Wheel zooming
document.addEventListener('mousewheel', function(e) {
if( e.ctrlKey ) {
var delta = Math.max(-1, Math.min(1, (e.wheelDelta || -e.detail)));
Ext.getStore('ServicesList').load(function (records, operations, success) {
if (!success) {
Ext.cq1('app-main').addDocked({
xtype: 'toolbar'
,dock: 'top'
,ui: 'servicesnotloaded'
,style: { background: '#efef6d' }
,items: [
'->'
,{
xtype: 'label'
,html: '<b>Services couldn\'t be loaded, some Rambox features will not be available.</b>'
}
,{
xtype: 'button'
,text: 'Reload'
,handler: function() { ipc.send('reloadApp'); }
}
,'->'
,{
glyph: 'xf00d@FontAwesome'
,baseCls: ''
,style: 'cursor:pointer;'
,handler: function(btn) { Ext.cq1('app-main').removeDocked(btn.up('toolbar'), true); }
}
]
});
}
// Load language for Ext JS library
Ext.Loader.loadScript({url: Ext.util.Format.format("ext/packages/ext-locale/build/ext-locale-{0}.js", localStorage.getItem('locale-extjs') || 'en')});
// Set Google URLs
Rambox.app.config.googleURLs = [
"accounts.google.com/ServiceLogin",
"accounts.google.com/signin",
"accounts.google.com/_/lookup/accountlookup",
"accounts.google.com/o/oauth2",
"accounts.google.com/_/signin",
"accounts.google.com/AddSession?",
"accounts.google.com/_/"
];
// Shortcuts
const platform = require('electron').remote.process.platform;
// Prevents default behaviour of Mousetrap, that prevents shortcuts in textareas
Mousetrap.prototype.stopCallback = function(e, element, combo) {
return false;
};
// Add shortcuts to switch services using CTRL + Number
Mousetrap.bind(platform === 'darwin' ? ["command+1","command+2","command+3","command+4","command+5","command+6","command+7","command+8","command+9"] : ["ctrl+1","ctrl+2","ctrl+3","ctrl+4","ctrl+5","ctrl+6","ctrl+7","ctrl+8","ctrl+9"], function(e, combo) { // GROUPS
var tabPanel = Ext.cq1('app-main');
if ( tabPanel.items.indexOf(tabPanel.getActiveTab()) === 0 ) return false;
if ( delta === 1 ) { // Zoom In
tabPanel.getActiveTab().zoomIn();
} else { // Zoom Out
tabPanel.getActiveTab().zoomOut();
var arg = parseInt(e.key);
if ( arg >= tabPanel.items.indexOf(Ext.getCmp('tbfill')) ) arg++;
tabPanel.setActiveTab(arg);
});
// Add shortcut to main tab (ctrl+,)
Mousetrap.bind(platform === 'darwin' ? 'command+,' : 'ctrl+,', (e, combo) => {
Ext.cq1('app-main').setActiveTab(0);
});
// Add shortcuts to navigate through services
Mousetrap.bind(['ctrl+tab', 'ctrl+pagedown'], (e, combo) => {
var tabPanel = Ext.cq1('app-main');
var activeIndex = tabPanel.items.indexOf(tabPanel.getActiveTab());
var i = activeIndex + 1;
// "cycle" (go to the start) when the end is reached or the end is the spacer "tbfill"
if (i === tabPanel.items.items.length || i === tabPanel.items.items.length - 1 && tabPanel.items.items[i].id === 'tbfill') i = 0;
// skip spacer
while (tabPanel.items.items[i].id === 'tbfill') i++;
tabPanel.setActiveTab(i);
});
Mousetrap.bind(['ctrl+shift+tab', 'ctrl+pageup'], (e, combo) => {
var tabPanel = Ext.cq1('app-main');
var activeIndex = tabPanel.items.indexOf(tabPanel.getActiveTab());
var i = activeIndex - 1;
if ( i < 0 ) i = tabPanel.items.items.length - 1;
while ( tabPanel.items.items[i].id === 'tbfill' || i < 0 ) i--;
tabPanel.setActiveTab(i);
});
// Add shortcut to search inside a service
Mousetrap.bind(process.platform === 'darwin' ? ['command+alt+f'] : ['shift+alt+f'], (e, combo) => {
var currentTab = Ext.cq1('app-main').getActiveTab();
if ( currentTab.getWebView ) currentTab.showSearchBox(true);
});
// Add shortcut to Do Not Disturb
Mousetrap.bind(platform === 'darwin' ? ["command+alt+d"] : ["shift+alt+d"], function(e, combo) {
var btn = Ext.getCmp('disturbBtn');
btn.toggle();
Ext.cq1('app-main').getController().dontDisturb(btn, true);
});
// Add shortcut to Lock Rambox
Mousetrap.bind(platform === 'darwin' ? ['command+alt+l'] : ['shift+alt+l'], (e, combo) => {
var btn = Ext.getCmp('lockRamboxBtn');
Ext.cq1('app-main').getController().lockRambox(btn);
});
// Mouse Wheel zooming
document.addEventListener('mousewheel', function(e) {
if( e.ctrlKey ) {
var delta = Math.max(-1, Math.min(1, (e.wheelDelta || -e.detail)));
var tabPanel = Ext.cq1('app-main');
if ( tabPanel.items.indexOf(tabPanel.getActiveTab()) === 0 ) return false;
if ( delta === 1 ) { // Zoom In
tabPanel.getActiveTab().zoomIn();
} else { // Zoom Out
tabPanel.getActiveTab().zoomOut();
}
}
}
});
// Define default value
if ( localStorage.getItem('dontDisturb') === null ) localStorage.setItem('dontDisturb', false);
ipc.send('setDontDisturb', localStorage.getItem('dontDisturb')); // We store it in config
});
if ( localStorage.getItem('locked') ) {
console.info('Lock Rambox:', 'Enabled');
Ext.cq1('app-main').getController().showLockWindow();
}
// Define default value
if ( localStorage.getItem('dontDisturb') === null ) localStorage.setItem('dontDisturb', false);
ipc.send('setDontDisturb', localStorage.getItem('dontDisturb')); // We store it in config
// Remove spinner
Ext.get('spinner').destroy();
if ( localStorage.getItem('locked') ) {
console.info('Lock Rambox:', 'Enabled');
Ext.cq1('app-main').getController().showLockWindow();
}
Ext.getStore('Services').load();
});
}
,updateTotalNotifications: function( newValue, oldValue ) {
@ -241,60 +247,6 @@ Ext.define('Rambox.Application', {
}
,checkUpdate: function(silence) {
console.info('Checking for updates...');
Ext.Ajax.request({
url: 'https://rambox.pro/api/latestversion.json'
,method: 'GET'
,success: function(response) {
var json = Ext.decode(response.responseText);
var appVersion = new Ext.Version(require('electron').remote.app.getVersion());
if ( appVersion.isLessThan(json.version) ) {
console.info('New version is available', json.version);
Ext.cq1('app-main').addDocked({
xtype: 'toolbar'
,dock: 'top'
,ui: 'newversion'
,items: [
'->'
,{
xtype: 'label'
,html: '<b>'+locale['app.update[0]']+'</b> ('+json.version+')' + ( process.platform === 'win32' ? ' is downloading in the background and you will be notified when it is ready to be installed.' : '' )
}
,{
xtype: 'button'
,text: locale['app.update[1]']
,href: process.platform === 'darwin' ? 'https://getrambox.herokuapp.com/download/'+process.platform+'_'+process.arch : 'https://github.com/ramboxapp/community-edition/releases/latest'
,hidden: process.platform === 'win32'
}
,{
xtype: 'button'
,text: locale['app.update[2]']
,ui: 'decline'
,tooltip: 'Click here to see more information about the new version.'
,href: 'https://github.com/ramboxapp/community-edition/releases/tag/'+json.version
}
,'->'
,{
glyph: 'xf00d@FontAwesome'
,baseCls: ''
,style: 'cursor:pointer;'
,handler: function(btn) { Ext.cq1('app-main').removeDocked(btn.up('toolbar'), true); }
}
]
});
ipc.send('autoUpdater:check-for-updates');
return;
} else if ( !silence ) {
Ext.Msg.show({
title: locale['app.update[3]']
,message: locale['app.update[4]']
,icon: Ext.Msg.INFO
,buttons: Ext.Msg.OK
});
}
console.info('Your version is the latest. No need to update.');
}
});
ipc.send('autoUpdater:check-for-updates');
}
});

9
app/store/Services.js

@ -8,8 +8,9 @@ Ext.define('Rambox.store.Services', {
,model: 'Rambox.model.Service'
,autoLoad: true
,autoLoad: false
,autoSync: true
,pageSize: 0
,groupField: 'align'
,sorters: [
@ -20,7 +21,7 @@ Ext.define('Rambox.store.Services', {
]
,listeners: {
load: function( store, records, successful ) {
load: function( store, records, successful ) {
Ext.cq1('app-main').suspendEvent('add');
var servicesLeft = [];
@ -75,5 +76,9 @@ Ext.define('Rambox.store.Services', {
store.suspendEvent('load');
Ext.cq1('app-main').resumeEvent('add');
}
,datachanged: function(store, eOpts) {
var isEmpty = store.getCount() > 0 ? false : true;
Ext.cq1('app-main').getViewModel().set('emptyServices', isEmpty);
}
}
});

938
app/store/ServicesList.js

@ -9,9 +9,28 @@ Ext.define('Rambox.store.ServicesList', {
,model: 'Rambox.model.ServiceList'
,proxy: {
type: 'memory'
type: 'ajax',
url: 'resources/services.json',
reader: {
type: 'json',
rootProperty: 'responseText'
}
}
,listeners: {
load: function () {
Ext.get('spinner') ? Ext.get('spinner').destroy() : null;
Ext.get('background') ? Ext.get('background').destroy() : null;
this.add({
id: 'custom'
,logo: 'custom.png'
,name: '_Custom Service'
,description: locale['services[38]']
,url: '___'
,type: 'custom'
,allow_popups: true
})
}
}
,sorters: [{
property: 'name'
,direction: 'ASC'
@ -20,919 +39,4 @@ Ext.define('Rambox.store.ServicesList', {
,autoLoad: true
,autoSync: true
,pageSize: 100000
,data: [
{
id: 'whatsapp'
,logo: 'whatsapp.png'
,name: 'WhatsApp'
,description: locale['services[0]']
,url: 'https://web.whatsapp.com/'
,type: 'messaging'
,js_unread: 'function checkUnread(){const elements = document.querySelectorAll(\'.CxUIE, .unread\');let count = 0;for (let i = 0; i < elements.length; i++) {if (elements[i].querySelectorAll(\'*[data-icon="muted"]\').length === 0) {count++;}}updateBadge(count);}function updateBadge(count){if(count && count>=1){rambox.setUnreadCount(count);}else{rambox.clearUnreadCount();}}setInterval(checkUnread, 1e3);(async()=>{try{const a=await window.navigator.serviceWorker.getRegistrations();for(const b of a)b.unregister()}catch(a){}})();'
},
{
id: 'slack'
,logo: 'slack.png'
,name: 'Slack'
,description: locale['services[1]']
,url: 'https://___.slack.com/'
,type: 'messaging'
,js_unread: 'function checkUnread(){var e=$(".p-channel_sidebar__channel--unread:not(.p-channel_sidebar__channel--muted)").length,n=0;$(".p-channel_sidebar__badge").each(function(){n+=isNaN(parseInt($(this).html()))?0:parseInt($(this).html())}),count=0<n?n:0<e?"•":0,updateBadge(count)}function updateBadge(e){1<=e||"•"===e?rambox.setUnreadCount(e):rambox.clearUnreadCount();}setInterval(checkUnread,3e3);'
},
{
id: 'noysi'
,logo: 'noysi.png'
,name: 'Noysi'
,description: locale['services[2]']
,url: 'https://noysi.com/#/identity/sign-in'
,type: 'messaging'
},
{
id: 'messenger'
,logo: 'messenger.png'
,name: 'Messenger'
,description: locale['services[3]']
,url: 'https://www.messenger.com/login/'
,type: 'messaging'
,titleBlink: true
,note: 'To enable desktop notifications, you have to go to Options inside Messenger.'
},
{
id: 'skype'
,logo: 'skype.png'
,name: 'Skype'
,description: locale['services[4]']
,url: 'https://web.skype.com/'
,type: 'messaging'
,note: 'Text and Audio calls are supported only. <a href="https://github.com/saenzramiro/rambox/wiki/Skype" target="_blank">Read more...</a>'
},
{
id: 'hangouts'
,logo: 'hangouts.png'
,name: 'Hangouts'
,description: locale['services[5]']
,url: 'https://hangouts.google.com/'
,type: 'messaging'
,titleBlink: true
,manual_notifications: true
,js_unread: 'function checkUnread(){updateBadge(document.getElementById("hangout-landing-chat").lastChild.contentWindow.document.body.getElementsByClassName("ee").length)}function updateBadge(e){e>=1?rambox.setUnreadCount(e):rambox.clearUnreadCount()}setInterval(checkUnread,3000);'
},
{
id: 'hipchat'
,logo: 'hipchat.png'
,name: 'HipChat'
,description: locale['services[6]']
,url: 'https://___.hipchat.com/chat'
,type: 'messaging'
,js_unread: 'function checkUnread(){var e=document.getElementsByClassName("hc-badge"),t=0;for(i=0;i<e.length;i++)t+=parseInt(e[i].innerHTML.trim());updateBadge(t)}function updateBadge(a){a>=1?rambox.setUnreadCount(a):rambox.clearUnreadCount()}setInterval(checkUnread,3e3);'
,custom_domain: true
},
{
id: 'telegram'
,logo: 'telegram.png'
,name: 'Telegram'
,description: locale['services[7]']
,url: 'https://web.telegram.org/'
,type: 'messaging'
,js_unread: 'function checkUnread(){var e=document.getElementsByClassName("im_dialog_badge badge"),t=0;for(i=0;i<e.length;i++)if(!e[i].classList.contains("im_dialog_badge_muted")){t+=parseInt(e[i].innerHTML.trim())}updateBadge(t)}function updateBadge(e){e>=1?rambox.setUnreadCount(e):rambox.clearUnreadCount()}setInterval(checkUnread,3000);'
},
{
id: 'wechat'
,logo: 'wechat.png'
,name: 'WeChat'
,description: locale['services[8]']
,url: 'https://web.wechat.com/'
,type: 'messaging'
},
{
id: 'gmail'
,logo: 'gmail.png'
,name: 'Gmail'
,description: locale['services[9]']
,url: 'https://mail.google.com/mail/'
,type: 'email'
,allow_popups: true
,js_unread: 'function checkUnread(){var e=document.getElementsByClassName("aim")[0];updateBadge(-1!=e.innerHTML.indexOf("(")&&(t=parseInt(e.textContent.replace(\/[^0-9]\/g,""))))}function updateBadge(e){1<=e?rambox.setUnreadCount(e):rambox.clearUnreadCount()}setInterval(checkUnread,3e3);'
,note: 'To enable desktop notifications, you have to go to Settings inside Gmail. <a href="https://support.google.com/mail/answer/1075549?ref_topic=3394466" target="_blank">Read more...</a>'
},
{
id: 'inbox'
,logo: 'inbox.png'
,name: 'Inbox'
,description: locale['services[10]']
,url: 'https://inbox.google.com/?cid=imp'
,type: 'email'
,manual_notifications: true
,js_unread: 'function checkUnread() {if(getComputedStyle(document.getElementsByClassName("sM")[0])["font-weight"] == "bold"){updateBadge(document.getElementsByClassName("ss").length)}} function updateBadge(a){a>=1?rambox.setUnreadCount(a):rambox.clearUnreadCount()};setInterval(checkUnread,3e3);'
,note: 'Please be sure to sign out of Hangouts inside Inbox, as it causes problems. <a href="https://github.com/saenzramiro/rambox/wiki/Inbox" target="_blank">Read more...</a>'
},
{
id: 'chatwork'
,logo: 'chatwork.png'
,name: 'ChatWork'
,description: locale['services[11]']
,url: 'https://www.chatwork.com/login.php'
,type: 'messaging'
,note: 'To enable desktop notifications, you have to go to Options inside ChatWork.'
},
{
id: 'groupme'
,logo: 'groupme.png'
,name: 'GroupMe'
,description: locale['services[12]']
,url: 'https://web.groupme.com/signin'
,type: 'messaging'
,note: 'To enable desktop notifications, you have to go to Options inside GroupMe. To count unread messages, be sure to be in Chats.'
,js_unread: 'function checkUnread(){var a=document.querySelectorAll(".badge-count:not(.ng-hide)"),b=0;for(i=0;i<a.length;i++)b+=parseInt(a[i].innerHTML.trim());updateBadge(b)}function updateBadge(a){a>=1?rambox.setUnreadCount(a):rambox.clearUnreadCount()}setInterval(checkUnread,3e3);'
},
{
id: 'grape'
,logo: 'grape.png'
,name: 'Grape'
,description: locale['services[13]']
,url: 'https://chatgrape.com/accounts/login/'
,type: 'messaging'
},
{
id: 'gitter'
,logo: 'gitter.png'
,name: 'Gitter'
,description: locale['services[14]']
,url: 'https://gitter.im/'
,type: 'messaging'
,js_unread: 'function checkUnread(){var e=document.getElementsByClassName("room-item__unread-indicator"),t=0;for(i=0;i<e.length;i++)t+=isNaN(parseInt(e[i].innerHTML.trim())) ? 0 : parseInt(e[i].innerHTML.trim());updateBadge(t)}function updateBadge(a){a>=1?rambox.setUnreadCount(a):rambox.clearUnreadCount()}setInterval(checkUnread,3e3);'
},
{
id: 'steam'
,logo: 'steam.png'
,name: 'Steam Chat'
,description: locale['services[15]']
,url: 'https://steamcommunity.com/chat'
,type: 'messaging'
,note: 'To enable desktop notifications, you have to go to Options inside Steam Chat.'
,js_unread: 'CTitleManager.UpdateTitle = function(){};function checkUnread(){var e=document.getElementsByClassName("unread_message_count_value"),t=0;for(i=0;i<e.length;i++)t+=isNaN(parseInt(e[i].innerHTML.trim())) || e[i].parentNode.style.display === "none" ? 0 : parseInt(e[i].innerHTML.trim());updateBadge(t/2)}function updateBadge(a){a>=1?rambox.setUnreadCount(a):rambox.clearUnreadCount()}setInterval(checkUnread,3e3);'
},
{
id: 'discord'
,logo: 'discord.png'
,name: 'Discord'
,description: locale['services[16]']
,url: 'https://discordapp.com/login'
,type: 'messaging'
,titleBlink: true
,js_unread: 'function checkUnread(){var e=document.querySelectorAll("[class*=scroller] [class*=container]"),r=Array.from(e.values()).reduce((e,r)=>e+(r&&r.querySelector("[class*=avatar]")&&r.querySelector("[class*=wrapper][class*=badge]")?parseInt(r.querySelector("[class*=wrapper][class*=badge]").innerHTML):0),0);rambox.setUnreadCount(r)}setInterval(checkUnread,3e3);'
,note: 'To enable desktop notifications, you have to go to Options inside Discord. Will count only unread DMs.'
},
{
id: 'outlook'
,logo: 'outlook.png'
,name: 'Outlook'
,description: locale['services[17]']
,url: 'https://mail.live.com/'
,type: 'email'
,manual_notifications: true
,js_unread: 'function checkUnread(){var a=$(".subfolders [role=treeitem]:first .treeNodeRowElement").siblings().last().text();updateBadge(""===a?0:parseInt(a))}function updateBadge(a){a>=1?rambox.setUnreadCount(a):rambox.clearUnreadCount()}setInterval(checkUnread,3e3);'
},
{
id: 'outlook365'
,logo: 'outlook365.png'
,name: 'Outlook 365'
,description: locale['services[18]']
,url: 'https://outlook.office.___/owa/'
,type: 'email'
,manual_notifications: true
,js_unread: 'function checkUnread(){var a=$(".subfolders [role=treeitem]:first .treeNodeRowElement").siblings().last().text();updateBadge(""===a?0:parseInt(a))}function updateBadge(a){a>=1?rambox.setUnreadCount(a):rambox.clearUnreadCount()}setInterval(checkUnread,3e3);'
,note: 'Please insert the cloud region you want to use. Can be "com", "de", etc.'
},
{
id: 'yahoo'
,logo: 'yahoo.png'
,name: 'Yahoo! Mail'
,description: locale['services[19]']
,url: 'https://mail.yahoo.com/'
,type: 'email'
,note: 'To enable desktop notifications, you have to go to Options inside Yahoo! Mail.'
},
{
id: 'protonmail'
,logo: 'protonmail.png'
,name: 'ProtonMail'
,description: locale['services[20]']
,url: 'https://mail.protonmail.com/inbox'
,type: 'email'
},
{
id: 'protonmailch'
,logo: 'protonmail.png'
,name: 'ProtonMail CH'
,description: locale['services[20]']
,url: 'https://app.protonmail.ch/inbox'
,type: 'email'
,note: 'Read <a href="https://protonmail.com/support/knowledge-base/what-is-the-difference-between-protonmail-com-and-protonmail-ch/" target="_blank">HERE</a> to see the differences between protonmail.com and protonmail.ch.'
},
{
id: 'protonmailonion'
,logo: 'protonmail.png'
,name: 'ProtonMail Onion'
,description: locale['services[20]']
,url: 'https://protonirockerxow.onion/inbox'
,type: 'email'
,note: 'Read <a href="https://protonmail.com/tor" target="_blank">HERE</a> to see the differences between protonmail.com and protonmail hidden service (over TOR).'
},
{
id: 'tutanota'
,logo: 'tutanota.png'
,name: 'Tutanota'
,description: locale['services[21]']
,url: 'https://mail.tutanota.com/'
,type: 'email'
},
{
id: 'hushmail'
,logo: 'hushmail.png'
,name: 'Hushmail'
,description: locale['services[22]']
,url: 'https://www.hushmail.com/hushmail/index.php'
,type: 'email'
},
{
id: 'missive'
,logo: 'missive.png'
,name: 'Missive'
,description: locale['services[23]']
,url: 'https://mail.missiveapp.com/login'
,type: 'messaging'
,js_unread: 'function checkUnread(){var e=document.getElementsByClassName("unseen-count"),t=0;for(i=0;i<e.length;i++)t+=parseInt(e[i].innerHTML.trim());updateBadge(t)}function updateBadge(a){a>=1?rambox.setUnreadCount(a):rambox.clearUnreadCount()}setInterval(checkUnread,3e3);'
},
{
id: 'rocketchat'
,logo: 'rocketchat.png'
,name: 'Rocket Chat'
,description: locale['services[24]']
,url: '___'
,type: 'messaging'
,note: 'You have to use this service by signing in with your email or username (No SSO allowed yet).'
},
{
id: 'wire'
,logo: 'wire.png'
,name: 'Wire'
,description: locale['services[25]']
,url: 'https://app.wire.com/'
,type: 'messaging'
},
{
id: 'sync'
,logo: 'sync.png'
,name: 'Sync'
,description: locale['services[26]']
,url: 'https://m.wantedly.com/login'
,type: 'messaging'
},
{
id: 'bearychat'
,logo: 'bearychat.png'
,name: 'BearyChat'
,url: 'https://___.bearychat.com/'
,type: 'messaging'
},
{
id: 'voxer'
,logo: 'voxer.png'
,name: 'Voxer'
,description: locale['services[29]']
,url: 'https://web.voxer.com/'
,type: 'messaging'
},
{
id: 'dasher'
,logo: 'dasher.png'
,name: 'Dasher'
,description: locale['services[30]']
,url: 'https://dasher.im/'
,type: 'messaging'
},
{
id: 'flowdock'
,logo: 'flowdock.png'
,name: 'Flowdock'
,description: locale['services[31]']
,url: 'https://www.flowdock.com/login'
,type: 'messaging'
},
{
id: 'mattermost'
,logo: 'mattermost.png'
,name: 'Mattermost'
,description: locale['services[32]']
,url: '___'
,type: 'messaging'
,js_unread: 'function checkUnread() {const selectBadges = "#sidebarChannelContainer .unread-title.has-badge > span.badge"; const pmUnread = Array.from(document.querySelectorAll(selectBadges)) .reduce((total, el) => total += parseInt(el.innerText), 0); if (pmUnread) return updateBadge(pmUnread); const channelsUnread = document.querySelectorAll("#sidebarChannelContainer .unread-title:not(.has-badge)").length; const teamsUnread = document.querySelectorAll(".team-sidebar .team-container.unread").length; updateBadge((channelsUnread + teamsUnread) > 0); } function updateBadge(count) {if (count === true) rambox.setUnreadCount("•"); else if (count >= 1) rambox.setUnreadCount(count); else rambox.clearUnreadCount(); } setInterval(checkUnread, 3e3);'
},
{
id: 'dingtalk'
,logo: 'dingtalk.png'
,name: 'DingTalk'
,description: locale['services[33]']
,url: 'https://im.dingtalk.com/'
,type: 'messaging'
},
{
id: 'mysms'
,logo: 'mysms.png'
,name: 'mysms'
,description: locale['services[34]']
,url: 'https://app.mysms.com/'
,type: 'messaging'
,js_unread: 'function checkUnread(){var e=document.getElementsByClassName("unread"),t=0;for(i=0;i<e.length;i++)t+=parseInt(e[i].firstChild.innerHTML.trim());updateBadge(t)}function updateBadge(a){a>=1?rambox.setUnreadCount(a):rambox.clearUnreadCount()}"https://app.mysms.com/#login"===document.baseURI&&(document.getElementsByClassName("innerPanel")[0].rows[0].style.display="none",document.getElementsByClassName("innerPanel")[0].rows[1].cells[0].firstElementChild.style.display="none",document.getElementsByClassName("msisdnLoginPanel")[0].style.display="inline");var originalTitle=document.title;setInterval(checkUnread,3e3);'
,note: 'You have to use this service by signing in with your mobile number.'
},
{
id: 'icq'
,logo: 'icq.png'
,name: 'ICQ'
,description: locale['services[35]']
,url: 'https://web.icq.com/'
,type: 'messaging'
,js_unread: 'function checkUnread(){let total=0;for(let counter of document.getElementsByClassName("icq-msg-counter"))total+=parseInt("block"===counter.style.display?counter.innerHTML.trim():0);updateBadge(total)}function updateBadge(e){e>=1?rambox.setUnreadCount(e):rambox.clearUnreadCount()}setInterval(checkUnread,3e3);'
,titleBlink: true
},
{
id: 'tweetdeck'
,logo: 'tweetdeck.png'
,name: 'TweetDeck'
,description: locale['services[36]']
,url: 'https://tweetdeck.twitter.com/'
,type: 'messaging'
},
{
id: 'custom'
,logo: 'custom.png'
,name: '_Custom Service'
,description: locale['services[38]']
,url: '___'
,type: 'custom'
,allow_popups: true
},
{
id: 'zinc'
,logo: 'zinc.png'
,name: 'Zinc'
,description: locale['services[39]']
,url: 'https://zinc-app.com/'
,type: 'messaging'
},
{
id: 'freenode'
,logo: 'freenode.png'
,name: 'FreeNode'
,description: locale['services[40]']
,url: 'https://webchat.freenode.net/'
,type: 'messaging'
},
{
id: 'mightytext'
,logo: 'mightytext.png'
,name: 'Mighty Text'
,description: locale['services[41]']
,url: 'https://mightytext.net/web/'
,type: 'messaging'
},
{
id: 'roundcube'
,logo: 'roundcube.png'
,name: 'Roundcube'
,description: locale['services[42]']
,url: '___'
,type: 'email'
},
{
id: 'horde'
,logo: 'horde.png'
,name: 'Horde'
,description: locale['services[43]']
,url: '___'
,type: 'email'
,js_unread: 'function checkUnread(){var e=document.getElementsByClassName("count"),t=0;for(i=0;i<e.length;i++)t+=parseInt(e[i].innerHTML.match(/\d+/g));updateBadge(t)}function updateBadge(a){a>=1?rambox.setUnreadCount(a):rambox.clearUnreadCount()}setInterval(checkUnread,3e3);'
,note: 'To enable desktop notifications and automatic mail check, you have to go to Options inside Horde.'
},
{
id: 'squirrelmail'
,logo: 'squirrelmail.png'
,name: 'SquirrelMail'
,description: locale['services[44]']
,url: '___'
,type: 'email'
,js_unread: 'function checkUnread(){var e=document.getElementsByClassName("leftunseen"),t=0;for(i=0;i<e.length;i++)t+=parseInt(e[i].innerHTML);updateBadge(t)}function updateBadge(a){a>=1?rambox.setUnreadCount(a):rambox.clearUnreadCount()}setInterval(checkUnread,3e3);'
},
{
id: 'zohoemail'
,logo: 'zohoemail.png'
,name: 'Zoho Email'
,description: locale['services[45]']
,url: 'https://mail.zoho.com/'
,type: 'email'
,js_unread: 'zmail.aInfo[zmail.accId].mailId = "a";'
,note: 'To enable desktop notifications, you have to go to Settings inside Zoho Email.'
},
{
id: 'zohochat'
,logo: 'zohocliq.png'
,name: 'Zoho Cliq'
,description: locale['services[46]']
,url: 'https://accounts.zoho.com/signin?servicename=ZohoChat&signupurl=https://www.zoho.com/cliq/signup.html'
,type: 'messaging'
,js_unread: 'NotifyByTitle.show = function(){};NotifyByTitle.start = function(){};NotifyByTitle.stop = function(){};function checkUnread(){var t=0;$(".msgnotify").each(function() { t += isNaN(parseInt($(this).html())) ? 0 : parseInt(parseInt($(this).html())) });updateBadge(t)}function updateBadge(a){a>=1?rambox.setUnreadCount(a):rambox.clearUnreadCount()}setInterval(checkUnread,3e3);'
},
{
id: 'aol'
,logo: 'aol.png'
,name: 'Aol'
,description: 'Free and simple (old) webmail service.'
,url: 'https://mail.aol.com/'
,type: 'email'
},
{
id: 'glip'
,logo: 'glip.png'
,name: 'Glip'
,description: 'Glip is fully searchable, real-time group chat & video chat, task management, file sharing, calendars and more.'
,url: 'https://glip.com/'
,type: 'messaging'
,note: 'To enable desktop notifications, you have to go to Options inside Glip.'
},
{
id: 'yandex'
,logo: 'yandex.png'
,name: 'Yandex Mail'
,description: 'Yandex is a free webmail service with unlimited mail storage, protection from viruses and spam, access from web interface, etc.'
,url: 'https://mail.yandex.com/'
,type: 'email'
,js_unread: 'function checkUnread(){var t=parseInt($(".mail-MessagesFilters-Item_unread .mail-LabelList-Item_count").html());updateBadge(isNaN(t)?0:t)}function updateBadge(a){a>=1?rambox.setUnreadCount(a):rambox.clearUnreadCount()}setInterval(checkUnread,3e3);'
},
{
id: 'irccloud'
,logo: 'irccloud.png'
,name: 'IRCCloud'
,description: 'IRCCloud is a modern IRC client that keeps you connected, with none of the baggage.'
,url: 'https://www.irccloud.com/'
,type: 'messaging'
,js_unread: 'function checkUnread(){var t=0;[].map.call(document.querySelectorAll(".bufferBadges > .badge"),n=>n.textContent?parseInt(n.textContent,10):0).reduce((x,y)=>x+y,0);updateBadge(t)}function updateBadge(a){a>=1?rambox.setUnreadCount(a):rambox.clearUnreadCount()}setInterval(checkUnread,3e3);'
,custom_domain: true
},
{
id: 'ryver'
,logo: 'ryver.png'
,name: 'Ryver'
,description: 'Ryver is a team communication tool that organizes team collaboration, chats, files, and even emails into a single location, for any size team, for FREE.'
,url: 'https://___.ryver.com/'
,type: 'messaging'
,js_unread: 'function checkUnread(){updateBadge(parseInt(document.getElementsByClassName("scene-space-tab-button__badge-icon").length))}function updateBadge(a){a>=1?rambox.setUnreadCount(a):rambox.clearUnreadCount()}setInterval(checkUnread,3e3);'
},
{
id: 'kiwi'
,logo: 'kiwi.png'
,name: 'Kiwi IRC'
,description: 'KiwiIRC makes Web IRC easy. A hand-crafted IRC client that you can enjoy. Designed to be used easily and freely.'
,url: 'https://kiwiirc.com/client'
,type: 'messaging'
,js_unread: 'function getUnreadCount(){var a=0;$(".activity").each(function(){a+=parseInt($(this).html())});var b=!1;return $(".panel[style*=\'display:block\'] .msg").each(function(){b?a++:$(this).hasClass("last_seen")&&(b=!0)}),a}function updateTitle(a){count=getUnreadCount(),cleanTitle=a.match(re),null!==cleanTitle&&cleanTitle.length>1?cleanTitle=cleanTitle[1]:cleanTitle=a,a=count>0?"("+getUnreadCount()+") "+cleanTitle:cleanTitle,$("title").text(a)}var re=/\(\d+\)[ ](.*)/;Object.defineProperty(document,"title",{configurable:!0,set:function(a){updateTitle(a)},get:function(){return $("title").text()}}),setInterval(function(){updateTitle(document.title)},3e3);'
,custom_domain: true
},
{
id: 'icloud'
,logo: 'icloud.png'
,name: 'iCloud Mail'
,description: 'iCloud makes sure you always have the latest versions of your most important things — documents, photos, notes, contacts, and more — on all your devices. It can even help you locate a missing iPhone, iPad, iPod touch or Mac.'
,url: 'https://www.icloud.com/#mail'
,type: 'email'
,js_unread: 'function checkUnread(){updateBadge(document.querySelector(".current-app").querySelector(".sb-badge").style.display==="none"?0:parseInt(document.querySelector(".current-app").querySelector(".text").innerHTML.trim()))}function updateBadge(a){a>=1?rambox.setUnreadCount(a):rambox.clearUnreadCount()}setInterval(checkUnread,3e3);'
},
{
id: 'rainloop'
,logo: 'rainloop.png'
,name: 'RainLoop'
,description: 'RainLoop Webmail - Simple, modern & fast web-based email client.'
,url: '___'
,type: 'email'
,js_unread: 'function checkUnread(){var t=document.querySelectorAll(".e-item .e-link:not(.hidden) .badge.pull-right.count"),e=0;for(i=0;i<t.length;i++)parseInt(t[i].textContent.trim())%1==0&&"block"==window.getComputedStyle(t[i]).display&&(count=parseInt(t[i].textContent.trim()),e+=parseInt(t[i].textContent.trim()));updateBadge(e)}function updateBadge(a){a>=1?rambox.setUnreadCount(a):rambox.clearUnreadCount()}setInterval(checkUnread,3e3);'
},
{
id: 'amium'
,logo: 'amium.png'
,name: 'Amium'
,description: 'Amium turns any file into a real-time activity feed and conversation. So you can work better, together.'
,url: 'https://___.amium.com/'
,type: 'messaging'
},
{
id: 'hootsuite'
,logo: 'hootsuite.png'
,name: 'Hootsuite'
,description: 'Enhance your social media management with Hootsuite, the leading social media dashboard. Manage multiple networks and profiles and measure your campaign results.'
,url: 'https://hootsuite.com/dashboard'
,type: 'messaging'
},
{
id: 'zimbra'
,logo: 'zimbra.png'
,name: 'Zimbra'
,description: 'Over 500 million people rely on Zimbra and enjoy enterprise-class open source email collaboration at the lowest TCO in the industry. Discover the benefits!'
,url: '___'
,type: 'email'
,js_unread: 'function check_unread(){update_badge(appCtxt.getById(ZmFolder.ID_INBOX).numUnread)}function update_badge(a){document.title=a>0?"("+a+") "+original_title:original_title}const original_title=document.title;setInterval(check_unread,3e3);'
},
{
id: 'kaiwa'
,logo: 'kaiwa.png'
,name: 'Kaiwa'
,description: 'A modern and Open Source Web client for XMPP.'
,url: '___'
,type: 'messaging'
,js_unread: 'function check_unread() { let count=0; for (let node of document.getElementsByClassName("unread")){ if (node.innerHTML){ count += parseInt(node.innerHTML); } } update_badge(count);}function update_badge(a) { document.title = a > 0 ? "(" + a + ") " + original_title : original_title}const original_title = document.title;setInterval(check_unread, 3e3);'
},
{
id: 'movim'
,logo: 'movim.png'
,name: 'Movim'
,description: 'Movim is a decentralized social network, written in PHP and HTML5 and based on the XMPP standard protocol.'
,url: 'https://___.movim.eu/'
,type: 'messaging'
,js_unread: 'function checkUnread(){var a=document.getElementsByClassName("color dark"),b=0;for(i=0;i<a.length;i++){var c=a[i].getElementsByClassName("counter");for(ii=0;ii<c.length;ii++)parseInt(c[ii].textContent.trim())%1===0&&(b+=parseInt(c[ii].textContent.trim()))}updateBadge(b)}function updateBadge(a){a>=1?rambox.setUnreadCount(a):rambox.clearUnreadCount()}setInterval(checkUnread,3e3);'
,custom_domain: true
},
{
id: 'pushbullet'
,logo: 'pushbullet.png'
,name: 'Pushbullet'
,description: 'Pushbullet connects your devices, making them feel like one.'
,url: 'https://www.pushbullet.com/'
,type: 'messaging'
},
{
id: 'riot'
,logo: 'riot.png'
,name: 'Riot'
,description: 'Riot is a simple and elegant collaboration environment that gathers all of your different conversations and app integrations into one single app.'
,url: 'https://riot.im/app/'
,type: 'messaging'
,js_unread: 'function checkUnread(){var a=document.getElementsByClassName("mx_RoomTile_nameContainer"),b=0;for(i=0;i<a.length;i++){var c=a[i].getElementsByClassName("mx_RoomTile_badge");for(ii=0;ii<c.length;ii++)parseInt(c[ii].textContent.trim())%1===0&&(b+=parseInt(c[ii].textContent.trim()))}updateBadge(b)}function updateBadge(a){a>=1?rambox.setUnreadCount(a):rambox.clearUnreadCount()}setInterval(checkUnread,3e3);'
,custom_domain: true
},
{
id: 'socialcast'
,logo: 'socialcast.png'
,name: 'Socialcast'
,description: 'Socialcast is the premier enterprise social networking platform that connects people to the knowledge, ideas and resources they need to work more effectively.'
,url: 'https://___.socialcast.com/'
,type: 'messaging'
},
{
id: 'fleep'
,logo: 'fleep.png'
,name: 'Fleep'
,description: 'Fleep enables communication within and across organizations - be it your team chats, project communication or 1:1 conversations.'
,url: 'https://fleep.io/chat'
,type: 'messaging'
,js_unread: 'document.getElementsByClassName("google-login-area")[0].remove();document.getElementsByClassName("microsoft-login-area")[0].remove();'
},
{
id: 'webexteams'
,logo: 'webexteams.png'
,name: 'Cisco Webex Teams'
,description: 'Cisco Webex Teams is for group chat, video calling, and sharing documents with your team. It’s all backed by Cisco security and reliability.'
,url: 'https://teams.webex.com/'
,type: 'messaging'
},
{
id: 'drift'
,logo: 'drift.png'
,name: 'Drift'
,description: 'Drift is a messaging app that makes it easy for businesses to talk to their website visitors and customers in real-time, from anywhere.'
,url: 'https://app.drift.com/'
,type: 'messaging'
},
{
id: 'typetalk'
,logo: 'typetalk.png'
,name: 'Typetalk'
,description: 'Typetalk brings fun and ease to team discussions through instant messaging on desktop and mobile devices.'
,url: 'https://typetalk.in/signin'
,type: 'messaging'
},
{
id: 'openmailbox'
,logo: 'openmailbox.png'
,name: 'Openmailbox'
,description: 'Free mail hosting. Respect your rights and your privacy.'
,url: 'https://app.openmailbox.org/webmail/'
,type: 'email'
},
{
id: 'flock'
,logo: 'flock.png'
,name: 'Flock'
,description: 'Flock is a free enterprise tool for business communication. Packed with tons of productivity features, Flock drives efficiency and boosts speed of execution.'
,url: 'https://web.flock.co/'
,type: 'messaging'
,js_unread: 'function checkUnread(){var a=document.getElementsByClassName("unreadMessages no-unread-mentions has-unread"),b=0;for(i=0;i<a.length;i++)b+=parseInt(a[i].innerHTML.trim());updateBadge(b)}function updateBadge(a){a>=1?rambox.setUnreadCount(a):rambox.clearUnreadCount()}setInterval(checkUnread,3e3);'
},
{
id: 'crisp'
,logo: 'crisp.png'
,name: 'Crisp'
,description: 'Connect your customers to your team.'
,url: 'https://app.crisp.chat/'
,type: 'messaging'
},
{
id: 'smooch'
,logo: 'smooch.png'
,name: 'Smooch'
,description: 'Unified multi-channel messaging for businesses, bots and software makers.'
,url: 'https://app.smooch.io/'
,type: 'messaging'
},
{
id: 'xing',
logo: 'xing.png',
name: 'XING',
description: 'Career-oriented social networking',
url: 'https://www.xing.com/messages/conversations',
type: 'messaging',
js_unread: '(function() { let originalTitle = document.title; function checkUnread() { let count = null; let notificationElement = document.querySelector(\'[data-update="unread_conversations"]\'); if (notificationElement && notificationElement.style.display !== \'none\') { count = parseInt(notificationElement.textContent.trim(), 10); } updateBadge(count); } function updateBadge(count) { if (count && count >= 1) { rambox.setUnreadCount(count); } else { rambox.clearUnreadCount(); } } setInterval(checkUnread, 3000); checkUnread(); })();',
},
{
id: 'threema',
logo: 'threema.png',
name: 'Threema',
description: 'Seriously secure messaging',
url: 'https://web.threema.ch/',
type: 'messaging',
js_unread: '(function () { let unreadCount = 0; function checkUnread() { let newUnread = 0; try { let webClientService = angular.element(document.documentElement).injector().get(\'WebClientService\'); let conversations = webClientService.conversations.conversations; conversations.forEach(function(conversation) { newUnread += conversation.unreadCount; }); } catch (e) { } if (newUnread !== unreadCount) { unreadCount = newUnread; updateBadge(unreadCount); } } function updateBadge(count) { if (count && count >= 1) { rambox.setUnreadCount(count); } else { rambox.clearUnreadCount(); } } setInterval(checkUnread, 3000); checkUnread(); })();',
},
{
id: 'workplace'
,logo: 'workplace.png'
,name: 'Workplace'
,description: 'Connect everyone in your company and turn ideas into action. Through group discussion, a personalised News Feed, and voice and video calling, work together and get more done. Workplace is an ad-free space, separate from your personal Facebook account.'
,url: 'https://___.facebook.com/'
,type: 'messaging'
},
{
id: 'teams'
,logo: 'teams.png'
,name: 'Teams'
,description: 'Microsoft Teams is the chat-based workspace in Office 365 that integrates all the people, content, and tools your team needs to be more engaged and effective.'
,url: 'https://teams.microsoft.com'
,type: 'messaging'
},
{
id: 'kezmo'
,logo: 'kezmo.png'
,name: 'Kezmo'
,description: 'Kezmo is an enterprise chat and collaboration tool to help teams get things done. It’s an email alternative for secure team communication.'
,url: 'https://app.kezmo.com/web/'
,type: 'messaging'
},
{
id: 'lounge'
,logo: 'lounge.png'
,name: 'The Lounge'
,description: 'Self-hosted web IRC client.'
,url: '___'
,type: 'messaging'
,js_unread: 'function checkUnread(){var a=document.getElementsByClassName("badge highlight"),b=0;for(i=0;i<a.length;i++)parseInt(a[i].textContent.trim())%1===0&&(b+=parseInt(a[i].textContent.trim()));updateBadge(b)}function updateBadge(a){a>=1?rambox.setUnreadCount(a):rambox.clearUnreadCount()}setInterval(checkUnread,3e3);'
},
{
id: 'linkedin'
,logo: 'linkedin.png'
,name: 'LinkedIn Messaging'
,description: 'Manage your professional identity. Build and engage with your professional network. Access knowledge, insights and opportunities.'
,url: 'https://www.linkedin.com/messaging'
,type: 'messaging'
},
{
id: 'zyptonite'
,logo: 'zyptonite.png'
,name: 'Zyptonite'
,description: 'Zyptonite is the ultimate cyber secure communication tool for enterprise customers designed to address the need to securely communicate via voice, video, and chat, and transfer files and information across a global mobile workforce.'
,url: 'https://app.zyptonite.com/'
,type: 'messaging'
,js_unread: 'function checkUnread(){var a=document.getElementsByClassName("z-messages"),b=0;for(i=0;i<a.length;i++)b+=parseInt(a[i].innerHTML.trim());updateBadge(b)}function updateBadge(a){a>=1?rambox.setUnreadCount(a):rambox.clearUnreadCount()}setInterval(checkUnread,3e3);'
},
{
id: 'fastmail'
,logo: 'fastmail.png'
,name: 'FastMail'
,description: 'Secure, reliable email hosting for businesses, families and professionals. Premium email with no ads, excellent spam protection and rapid personal support.'
,url: 'https://www.fastmail.com/mail/'
,type: 'email'
,js_unread: 'function checkUnread(){var e=document.getElementsByClassName("v-FolderSource-badge"),t=0;for(i=0;i<e.length;i++)t+=isNaN(parseInt(e[i].innerHTML.trim())) ? 0 : parseInt(e[i].innerHTML.trim());updateBadge(t)}function updateBadge(a){a>=1?rambox.setUnreadCount(a):rambox.clearUnreadCount()}setInterval(checkUnread,3e3);setTimeout(function(){O.WindowController.openExternal=function(a){var b=document.createElement("a");b.href=a,b.setAttribute("target","_blank"),b.click()};},3000);'
,note: 'To enable desktop notifications, you have to go to Settings inside FastMail.'
},
{
id: 'hibox'
,logo: 'hibox.png'
,name: 'Hibox'
,description: 'Hibox is a secure and private messaging platform for your business.'
,url: 'https://app.hibox.co/'
,type: 'messaging'
},
{
id: 'jandi'
,logo: 'jandi.png'
,name: 'Jandi'
,description: 'Jandi is a group-oriented enterprise messaging platform with an integrated suite of collaboration tools for workplace.'
,url: 'https://___.jandi.com/'
,type: 'messaging'
},
{
id: 'messengerpages'
,logo: 'messengerpages.png'
,name: 'Messenger for Pages'
,description: 'Chat with the people of your Facebook Page.'
,url: 'https://facebook.com/___/inbox/'
,type: 'messaging'
,js_unread: 'function remove(e){var r=document.getElementById(e);return r.parentNode.removeChild(r)}remove("pagelet_bluebar"),remove("pages_manager_top_bar_container");'
},
{
id: 'messengerbusiness'
,logo: 'messengerpages.png'
,name: 'Messenger for Business'
,description: 'Messenger can help facilitate communication with your customers.'
,url: 'https://business.facebook.com/___/inbox/'
,type: 'messaging'
,js_unread: 'function remove(e){var r=document.getElementById(e);return r.parentNode.removeChild(r)}remove("pagelet_bluebar"),remove("pages_manager_top_bar_container");'
},
{
id: 'vk'
,logo: 'vk.png'
,name: 'VK Messenger'
,description: 'Simple and Easy App for Messaging on VK.'
,url: 'https://m.vk.com/im'
,type: 'messaging'
,js_unread: 'function checkUnread(){updateBadge(parseInt(document.getElementById("l_msg").innerText.replace(/\D+/g,"")))}function updateBadge(a){a>=1?rambox.setUnreadCount(a):rambox.clearUnreadCount()}setInterval(checkUnread,3e3);'
},
{
id: 'mastodon'
,logo: 'mastodon.png'
,name: 'Mastodon'
,description: 'Mastodon is a free, open-source social network server. A decentralized solution to commercial platforms, it avoids the risks of a single company monopolizing your communication. Anyone can run Mastodon and participate in the social network seamlessly.'
,url: 'https://mastodon.social/auth/sign_in'
,type: 'messaging'
,custom_domain: true
,note: '<a href="https://instances.mastodon.xyz/" target="_blank">List of instances</a>'
},
{
id: 'teamworkchat'
,logo: 'teamworkchat.png'
,name: 'Teamwork Chat'
,description: 'Say goodbye to email. Take your online collaboration to the next level with Teamwork Chat and keep all team discussions in one place. Chat to your team in a fun and informal way with Teamwork Chat.'
,url: 'https://___/chat'
,type: 'messaging'
,js_unread: 'function checkUnread(){updateBadge(parseInt(document.getElementsByClassName("sidebar-notification-indicator").length > 0 ? document.getElementsByClassName("sidebar-notification-indicator")[0].innerHTML : 0))}function updateBadge(a){a>=1?rambox.setUnreadCount(a):rambox.clearUnreadCount()}setInterval(checkUnread,3e3);'
},
{
id: 'clocktweets'
,logo: 'clocktweets.png'
,name: 'ClockTweets'
,description: 'Schedule your Tweets with love. Save time and manage your social media strategy easily.'
,url: 'https://clocktweets.com/dashboard/'
,type: 'messaging'
},
{
id: 'intercom'
,logo: 'intercom.png'
,name: 'Intercom'
,description: 'Intercom makes it easy to communicate with your customers personally, at scale. Designed to feel like the messaging apps you use every day, Intercom lets you talk to consumers almost anywhere: inside your app, on your website, across social media and via email.'
,url: 'https://app.intercom.io'
,type: 'messaging'
,js_unread: 'function checkUnread(){var a=document.getElementsByClassName("unread")[0];updateBadge(t=a===undefined?0:parseInt(a.textContent.replace(/[^0-9]/g,"")))}function updateBadge(a){a>=1?rambox.setUnreadCount(a):rambox.clearUnreadCount()}setInterval(checkUnread,3000);'
},
{
id: 'allo'
,logo: 'allo.png'
,name: 'Allo'
,description: 'Google Allo is a smart messaging app that helps you say more and do more. Express yourself better with stickers, doodles, and HUGE emojis & text. Allo also brings you the Google Assistant.'
,url: 'https://allo.google.com/web'
,type: 'messaging'
,js_unread: 'function checkUnread(){var e=document.querySelectorAll(".hasUnread.conversation_item"),n=0;for(i=0;i<e.length;i++){var m=e[i].querySelector("#muted"),u=e[i].querySelector(".unreadCount"),c=parseInt(u.innerHTML.trim()),r=(m===null||m.style.display==="none")?c:0;n+=isNaN(r)?0:r}updateBadge(n)}function updateBadge(e){e&&e>=1?rambox.setUnreadCount(e):rambox.clearUnreadCount()}setInterval(checkUnread,3e3);'
},
{
id: 'Kune'
,logo: 'kune.png'
,name: 'Kune'
,description: 'Kune is a web tool, based on Apache Wave, for creating environments of constant inter-communication, collective intelligence, knowledge and shared work.'
,url: 'https://kune.cc'
,type: 'messaging'
},
{
id: 'googlevoice'
,logo: 'googlevoice.png'
,name: 'Google Voice'
,description: 'A free phone number for life. Stay in touch from any screen. Use your free number to text, call, and check voicemail all from one app. Plus, Google Voice works on all of your devices so you can connect and communicate how you want.'
,url: 'https://voice.google.com'
,type: 'messaging'
,js_unread: 'function parseIntOrZero(e){return isNaN(parseInt(e))?0:parseInt(e)}function checkUnread(){var e=document.querySelector(".msgCount"),n=0;e?n=parseIntOrZero(e.innerHTML.replace(/[\(\) ]/gi,"")):["Messages","Calls","Voicemail"].forEach(function(e){var r=document.querySelector(\'gv-nav-tab[tooltip="\'+e+\'"] div[aria-label="Unread count"]\');r&&(n+=parseIntOrZero(r.innerHTML))}),updateBadge(n)}function updateBadge(a){a>=1?rambox.setUnreadCount(a):rambox.clearUnreadCount()}setInterval(checkUnread,3e3);'
},
{
id: 'sandstorm'
,logo: 'sandstorm.png'
,name: 'Sandstorm'
,description: 'Sandstorm is a self-hostable web productivity suite.'
,url: 'https://oasis.sandstorm.io/'
,type: 'messaging'
,custom_domain: true
,allow_popups: true
},
{
id: 'gadugadu'
,logo: 'gadugadu.png'
,name: 'Gadu-Gadu'
,description: 'The most popular Polish messenger.'
,url: 'https://www.gg.pl/'
,type: 'messaging'
},
{
id: 'mailru'
,logo: 'mailru.png'
,name: 'Mail.Ru'
,description: 'Free voice and video calls, ICQ support, Odnoklassniki, VKontakte, Facebook, online games, free SMS.'
,url: 'https://webagent.mail.ru/webim/agent/popup.html'
,type: 'email'
},
{
id: 'zulip'
,logo: 'zulip.png'
,name: 'Zulip'
,description: "The world's most productive group chat"
,url: 'https://___.zulipchat.com/'
,type: 'messaging'
,custom_domain: true
},
{
id: 'stride'
,logo: 'stride.png'
,name: 'Stride'
,description: 'Stride is the complete team communication solution with group messaging, video meetings, and built-in collaboration tools.'
,url: 'https://app.stride.com/___'
,type: 'messaging'
,js_unread: 'function checkUnread(){var t=0,e=!1;document.querySelectorAll(".conversations-nav .nav-item .activity-indicator").forEach(function(n){n.classList.contains("has-count")?t+=parseInt(n.innerHTML):e=!0}),updateBadge(t,e)}function updateBadge(t,e){var n=t>0?"("+t+") ":e?"(•) ":"";n!==""?rambox.setUnreadCount(n):rambox.clearUnreadCount()}setInterval(checkUnread,3e3);'
},
{
id: 'hangoutschat'
,logo: 'hangoutschat.png'
,name: 'Hangouts Chat'
,description: 'A messaging platform built for teams.'
,url: 'https://chat.google.com/'
,type: 'messaging'
,titleBlink: true
,manual_notifications: true
,js_unread: 'function checkUnread(){updateBadge(document.querySelectorAll(".SSPGKf.EyyDtb.Q6oXP:not(.oCHqfe) .eM5l9e.FVKzAb").length)}function updateBadge(e){e>=1?rambox.setUnreadCount(e):rambox.clearUnreadCount()}setInterval(checkUnread,3000);'
},
{
id: 'devrant'
,logo: 'devrant.png'
,name: 'devRant'
,description: 'Share and bond over successes and frustrations with code, tech and life as a programmer'
,url: 'https://devrant.com/'
,type: 'messaging'
,js_unread: 'function checkUnread(){var a=document.querySelectorAll(".menu-notif.notif-badge")[0];updateBadge(t=a===undefined?0:(a.textContent.length?parseInt(a.textContent.replace(/[^0-9]/g,"")):0))}function updateBadge(a){a>=1?rambox.setUnreadCount(a):rambox.clearUnreadCount()}setInterval(checkUnread,3000);'
},
{
id: 'reddit'
,logo: 'reddit.png'
,name: 'Reddit'
,description: 'Reddit\'s in-build chat service.'
,url: 'https://www.reddit.com/chat'
,type: 'messaging'
},
{
id: 'androidmessages'
,logo: 'androidmessages.png'
,name: 'Android Messages'
,description: 'Text on your computer with Messages for web.'
,url: 'https://messages.android.com/'
,type: 'messaging'
,js_unread: 'function checkUnread(){var t = document.querySelectorAll(".tpEAA.yrs5ff").length;if(t>=1){rambox.setUnreadCount(t)}else{rambox.clearUnreadCount()}}setInterval(checkUnread,3000);'
},
{
id: 'tawktochat'
,logo: 'tawkto.png'
,name: 'Tawk.to Chat'
,description: 'A chat platform built for monitor and chat with visitors on your website.'
,url: 'https://dashboard.tawk.to/'
,type: 'messaging'
},
{
id: 'sococo'
,logo: 'sococo.png'
,name: 'Sococo'
,description: 'Sococo is an online workplace that adds the magic of co-location back into the day to day life of distributed Agile teams.'
,url: 'https://app.sococo.com/a/login'
,type: 'messaging'
}
]
});

17
app/util/IconLoader.js

@ -18,16 +18,15 @@ Ext.define('Rambox.util.IconLoader', {
this.loadServiceIconUrl = function (service, webview) {
switch (service.type) {
case 'slack':
webview.executeJavaScript(
"(()=>{let a=document.querySelector('.team_icon');if(!a){const d=document.querySelector('#team_menu');d&&(d.click(),a=document.querySelector('.team_icon'))}if(!a)return!1;const{style:{backgroundImage:b}}=a,c=document.createEvent('MouseEvents');return c.initEvent('mousedown',!0,!0),document.querySelector('.client_channels_list_container').dispatchEvent(c),b.slice(5,-2)})();",
false,
function (backgroundImage) {
if (backgroundImage) {
service.setTitle('<img src="'+service.icon+'" width="" style="background-color: white;border-radius: 50%;position: absolute;left: 18px;top: 17px;width: 12px;">'+service.title);
service.fireEvent('iconchange', service, backgroundImage, service.icon);
}
webview.executeJavaScript("(a=>window.slackDebug.activeTeam.redux.getState().teams[a].icon.image_44)(window.slackDebug.activeTeamId);")
.then(backgroundImage => {
if (backgroundImage) {
service.setTitle('<img src="'+service.icon+'" width="" style="background-color: white;border-radius: 50%;position: absolute;left: 18px;top: 17px;width: 12px;">'+service.title);
service.fireEvent('iconchange', service, backgroundImage, service.icon);
}
);
}).catch(err => {
console.log(err);
})
break;
default:
break;

289
app/ux/Auth0.js

@ -1,289 +0,0 @@
Ext.define('Rambox.ux.Auth0', {
singleton: true
// private
,lock: null
,auth0: null
,authService: null
,backupCurrent: false
,init: function() {
var me = this;
var Auth0 = require('auth0-js');
var _AuthService = require('./resources/js/AuthService');
me.authService = new _AuthService.default({
clientId: auth0Cfg.clientID,
authorizeEndpoint: 'https://'+auth0Cfg.domain+'/authorize',
audience: 'https://'+auth0Cfg.domain+'/userinfo',
scope: 'openid profile offline_access',
redirectUri: 'https://'+auth0Cfg.domain+'/mobile',
tokenEndpoint: 'https://'+auth0Cfg.domain+'/oauth/token'
});
me.auth0 = new Auth0.WebAuth({ clientID: auth0Cfg.clientID, domain : auth0Cfg.domain });
//me.defineEvents();
}
,onLogin: function(token, authWindow) {
var me = this;
authWindow.close();
me.auth0.client.userInfo(token.access_token, function(err, profile) {
if ( err ) {
if ( err.error === 401 || err.error === 'Unauthorized' ) return me.renewToken(me.checkConfiguration);
Ext.Msg.hide();
return Ext.Msg.show({
title: 'Error'
,message: 'There was an error getting the profile: ' + err.error_description
,icon: Ext.Msg.ERROR
,buttons: Ext.Msg.OK
});
}
profile.user_metadata = profile['https://rambox.pro/user_metadata'];
delete profile['https://rambox.pro/user_metadata'];
// Display a spinner while waiting
Ext.Msg.wait(locale['app.window[29]'], locale['app.window[28]']);
// Google Analytics Event
ga_storage._trackEvent('Users', 'loggedIn');
// Set cookies to help Tooltip.io messages segmentation
Ext.util.Cookies.set('auth0', true);
// User is logged in
// Save the profile and JWT.
localStorage.setItem('profile', JSON.stringify(profile));
localStorage.setItem('access_token', token.access_token);
localStorage.setItem('id_token', token.id_token);
localStorage.setItem('refresh_token', token.refresh_token);
if ( !Ext.isEmpty(profile.user_metadata) && !Ext.isEmpty(profile.user_metadata.services) && !me.backupCurrent ) {
Ext.each(profile.user_metadata.services, function(s) {
var service = Ext.create('Rambox.model.Service', s);
service.save();
Ext.getStore('Services').add(service);
});
require('electron').remote.getCurrentWindow().reload();
}
Ext.Msg.hide();
Ext.cq1('app-main').getViewModel().set('username', profile.name);
Ext.cq1('app-main').getViewModel().set('avatar', profile.picture);
});
}
,backupConfiguration: function(callback) {
var me = this;
Ext.Msg.wait('Saving backup...', 'Please wait...');
// Getting all services
var lastupdate = (new Date()).toJSON();
var services = [];
Ext.getStore('Services').each(function(service) {
var s = Ext.clone(service);
delete s.data.id;
delete s.data.zoomLevel;
services.push(s.data);
});
Ext.Ajax.request({
url: 'https://rambox.auth0.com/api/v2/users/'+Ext.decode(localStorage.getItem('profile')).sub
,method: 'PATCH'
,headers: { authorization: "Bearer " + localStorage.getItem('id_token') }
,jsonData: { user_metadata: { services: services, services_lastupdate: lastupdate } }
,success: function(response) {
Ext.Msg.hide();
// Save the last update in localStorage
var profile = Ext.decode(localStorage.getItem('profile'));
if ( !profile.user_metadata ) profile.user_metadata = {};
profile.user_metadata.services_lastupdate = lastupdate;
localStorage.setItem('profile', Ext.encode(profile));
Ext.cq1('app-main').getViewModel().set('last_sync', new Date(lastupdate).toUTCString());
Ext.toast({
html: '<i class="fa fa-check fa-3x fa-pull-left" aria-hidden="true"></i> Your configuration were successfully backed up.'
,title: 'Synchronize Configuration'
,width: 300
,align: 't'
,closable: false
});
if ( Ext.isFunction(callback) ) callback.bind(me)();
}
,failure: function(response) {
if ( response.status === 401 ) return me.renewToken(me.backupConfiguration);
Ext.Msg.hide();
Ext.toast({
html: '<i class="fa fa-times fa-3x fa-pull-left" aria-hidden="true"></i> Error occurred when trying to backup your configuration.'
,title: 'Synchronize Configuration'
,width: 300
,align: 't'
,closable: false
});
if ( Ext.isFunction(callback) ) callback.bind(me)();
console.error(response);
}
});
}
,restoreConfiguration: function() {
var me = this;
me.auth0.client.userInfo(localStorage.getItem('access_token'), function(err, profile) {
if ( err ) {
if ( err.code === 401 ) return me.renewToken(me.restoreConfiguration);
return Ext.Msg.show({
title: 'Error'
,message: 'There was an error getting the profile: ' + err.description
,icon: Ext.Msg.ERROR
,buttons: Ext.Msg.OK
});
}
profile.user_metadata = profile['https://rambox.pro/user_metadata'];
delete profile['https://rambox.pro/user_metadata'];
// First we remove all current services
Ext.cq1('app-main').getController().removeAllServices(false, function() {
if ( !profile.user_metadata || !profile.user_metadata.services ) return;
Ext.each(profile.user_metadata.services, function(s) {
var service = Ext.create('Rambox.model.Service', s);
service.save();
Ext.getStore('Services').add(service);
});
require('electron').remote.getCurrentWindow().reload();
});
});
}
,checkConfiguration: function() {
var me = this;
me.auth0.client.userInfo(localStorage.getItem('access_token'), function(err, profile) {
if ( err ) {
if ( err.code === 401 ) return me.renewToken(me.checkConfiguration);
return Ext.Msg.show({
title: 'Error'
,message: 'There was an error getting the profile: ' + err.description
,icon: Ext.Msg.ERROR
,buttons: Ext.Msg.OK
});
}
profile.user_metadata = profile['https://rambox.pro/user_metadata'];
delete profile['https://rambox.pro/user_metadata'];
if ( !profile.user_metadata ) {
Ext.toast({
html: 'You don\'t have any backup yet.'
,title: 'Synchronize Configuration'
,width: 300
,align: 't'
,closable: false
});
return;
}
if ( Math.floor(new Date(profile.user_metadata.services_lastupdate) / 1000) > Math.floor(new Date(Ext.decode(localStorage.getItem('profile')).user_metadata.services_lastupdate) / 1000) ) {
Ext.toast({
html: 'Your settings are out of date.'
,title: 'Synchronize Configuration'
,width: 300
,align: 't'
,closable: false
});
} else {
Ext.toast({
html: '<i class="fa fa-check fa-3x fa-pull-left" aria-hidden="true"></i> Latest backup is already applied.'
,title: 'Synchronize Configuration'
,width: 300
,align: 't'
,closable: false
});
}
});
}
,renewToken: function(callback) {
var me = this;
Ext.Ajax.request({
url: 'https://rambox.auth0.com/oauth/token'
,method: 'POST'
,jsonData: {
grant_type: 'refresh_token'
,client_id: auth0Cfg.clientID
,client_secret: auth0Cfg.clientSecret
,refresh_token: localStorage.getItem('refresh_token')
,api_type: 'app'
}
,success: function(response) {
var json = Ext.decode(response.responseText);
localStorage.setItem('access_token', json.access_token);
localStorage.setItem('id_token', json.id_token);
if ( Ext.isFunction(callback) ) callback.bind(me)();
}
,failure: function(response) {
console.error(response);
}
});
}
,login: function() {
var me = this;
var electron = require('electron').remote;
var authWindow = new electron.BrowserWindow({
title: 'Rambox - Login'
,width: 400
,height: 600
,maximizable: false
,minimizable: false
,resizable: false
,center: true
,autoHideMenuBar: true
,skipTaskbar: true
,fullscreenable: false
,modal: true
,parent: require('electron').remote.getCurrentWindow()
,webPreferences: {
partition: 'persist:rambox'
}
});
authWindow.on('closed', function() {
authWindow = null;
});
authWindow.loadURL(me.authService.requestAuthCode());
authWindow.webContents.on('did-navigate', function(e, url) {
me.authService.requestAccessCode(url, me.onLogin.bind(me), authWindow);
});
}
,logout: function() {
var me = this;
localStorage.removeItem('profile');
localStorage.removeItem('id_token');
localStorage.removeItem('refresh_token');
localStorage.removeItem('access_token');
// Set cookies to help Tooltip.io messages segmentation
Ext.util.Cookies.set('auth0', false);
}
});

480
app/ux/WebView.js

@ -1,6 +1,7 @@
/**
* Default config for all webviews created
*/
Ext.define('Rambox.ux.WebView',{
extend: 'Ext.panel.Panel'
,xtype: 'webview'
@ -34,12 +35,10 @@ Ext.define('Rambox.ux.WebView',{
}
}
// Allow Custom sites with self certificates
//if ( me.record.get('trust') ) ipc.send('allowCertificate', me.src);
const prefConfig = ipc.sendSync('getConfig');
Ext.apply(me, {
items: me.webViewConstructor()
,title: me.record.get('tabname') ? me.record.get('name') : ''
,title: prefConfig.hide_tabbar_labels ? '' : (me.record.get('tabname') ? me.record.get('name') : '')
,icon: me.record.get('type') === 'custom' ? (me.record.get('logo') === '' ? 'resources/icons/custom.png' : me.record.get('logo')) : 'resources/icons/'+me.record.get('logo')
,src: me.record.get('url')
,type: me.record.get('type')
@ -124,6 +123,45 @@ Ext.define('Rambox.ux.WebView',{
]
}
}
,tbar: {
itemId: 'searchBar'
,hidden: true
,items: ['->', {
xtype: 'textfield'
,emptyText: 'Search...'
,listeners: {
scope: me
,change: me.doSearchText
,specialkey: function(field, e) {
if ( e.getKey() === e.ENTER ) return me.doSearchText(field, field.getValue(), null, null, true)
if ( e.getKey() === e.ESC ) return me.showSearchBox(false)
}
}
}, {
xtype: 'displayfield'
}, {
xtype: 'segmentedbutton'
,allowMultiple: false
,allowToggle: false
,items: [{
glyph: 'xf053@FontAwesome'
,handler: function() {
var field = this.up('toolbar').down('textfield');
me.doSearchText(field, field.getValue(), null, null, false)
}
}, {
glyph: 'xf054@FontAwesome'
,handler: function() {
var field = this.up('toolbar').down('textfield');
me.doSearchText(field, field.getValue(), null, null, true)
}
}]
}, {
xtype: 'button'
,glyph: 'xf00d@FontAwesome'
,handler: function() { me.showSearchBox(false) }
}]
}
,listeners: {
afterrender: me.onAfterRender
,beforedestroy: me.onBeforeDestroy
@ -163,6 +201,7 @@ Ext.define('Rambox.ux.WebView',{
} else {
cfg = [{
xtype: 'component'
,cls: 'webview'
,hideMode: 'offsets'
,autoRender: true
,autoShow: true
@ -174,24 +213,28 @@ Ext.define('Rambox.ux.WebView',{
,plugins: 'true'
,allowtransparency: 'on'
,autosize: 'on'
,webpreferences: '' //,nativeWindowOpen=yes
//,disablewebsecurity: 'on' // Disabled because some services (Like Google Drive) dont work with this enabled
,useragent: ipc.sendSync('getConfig').user_agent ? ipc.sendSync('getConfig').user_agent : Ext.getStore('ServicesList').getById(me.record.get('type')).get('userAgent')
,webpreferences: 'nativeWindowOpen=yes, spellcheck=no, contextIsolation=no'
,allowpopups: 'on'
// ,disablewebsecurity: 'on' // Disabled because some services (Like Google Drive) dont work with this enabled
,useragent: me.getUserAgent()
,preload: './resources/js/rambox-service-api.js'
}
}];
if ( Ext.getStore('ServicesList').getById(me.record.get('type')).get('allow_popups') ) cfg[0].autoEl.allowpopups = 'on';
}
return cfg;
}
,getUserAgent: function() {
var ua = ipc.sendSync('getConfig').user_agent ? ipc.sendSync('getConfig').user_agent : Ext.getStore('ServicesList').getById(this.record.get('type')) ? Ext.getStore('ServicesList').getById(this.record.get('type')).get('userAgent') : ''
return ua.length === 0 ? window.clientInformation.userAgent.replace(/Rambox\/([0-9]\.?)+\s/ig,'').replace(/Electron\/([0-9]\.?)+\s/ig,'') : ua;
}
,statusBarConstructor: function(floating) {
var me = this;
return {
xtype: 'statusbar'
,id: me.id+'statusbar'
,hidden: !me.record.get('statusbar')
,keep: me.record.get('statusbar')
,y: floating ? '-18px' : 'auto'
@ -228,24 +271,26 @@ Ext.define('Rambox.ux.WebView',{
if ( !me.record.get('enabled') ) return;
var webview = me.down('component').el.dom;
setTimeout(function() {
require('electron-context-menu')({window: webview});
}, 100);
// Google Analytics Event
ga_storage._trackEvent('Services', 'load', me.type, 1, true);
var webview = me.getWebView();
me.errorCodeLog = []
// Notifications in Webview
me.setNotifications(localStorage.getItem('locked') || JSON.parse(localStorage.getItem('dontDisturb')) ? false : me.record.get('notifications'));
require('electron').remote.session.fromPartition('persist:' + me.record.get('type') + '_' + me.id.replace('tab_', '') + (localStorage.getItem('id_token') ? '_' + Ext.decode(localStorage.getItem('profile')).sub : '')).webRequest.onBeforeSendHeaders((details, callback) => {
const change = details.url.match(/^https:\/\/accounts\.google\.com(\/|$)/);
if ( change ) details.requestHeaders['User-Agent'] = 'Mozilla/5.0 (Windows NT 10.0; Win64; x64; rv:97.0) Gecko/20100101 Firefox/97.0';
callback({ cancel: false, requestHeaders: details.requestHeaders });
});
// Show and hide spinner when is loading
webview.addEventListener("did-start-loading", function() {
console.info('Start loading...', me.src);
if ( !me.down('statusbar').closed || !me.down('statusbar').keep ) me.down('statusbar').show();
me.down('statusbar').showBusy();
});
webview.addEventListener("did-stop-loading", function() {
me.down('statusbar').clearStatus({useDefaults: true});
if ( !me.down('statusbar').keep ) me.down('statusbar').hide();
@ -257,155 +302,94 @@ Ext.define('Rambox.ux.WebView',{
// Apply saved zoom level
webview.setZoomLevel(me.record.get('zoomLevel'));
// Fix cursor sometimes dissapear
let currentTab = Ext.cq1('app-main').getActiveTab();
if ( currentTab.id === me.id ) {
webview.blur();
webview.focus();
}
// Set special icon for some service (like Slack)
setTimeout(function() {
Rambox.util.IconLoader.loadServiceIconUrl(me, webview);
}, 1000);
Rambox.util.IconLoader.loadServiceIconUrl(me, webview);
});
// Open links in default browser
webview.addEventListener('new-window', function(e) {
switch ( me.type ) {
case 'skype':
// hack to fix multiple browser tabs on Skype link click, re #11
if ( e.url.match('https:\/\/web.skype.com\/..\/undefined') ) {
e.preventDefault();
return;
} else if ( e.url.indexOf('imgpsh_fullsize') >= 0 ) {
ipc.send('image:download', e.url, e.target.partition);
e.preventDefault();
return;
}
// On search text
webview.addEventListener('found-in-page', function(e) {
me.onSearchText(e.result)
});
// On search text
webview.addEventListener('did-fail-load', function(e) {
console.info('The service fail at loading', me.src, e);
if ( me.record.get('disableAutoReloadOnFail') || !e.isMainFrame ) return
me.errorCodeLog.push(e.errorCode)
var attempt = me.errorCodeLog.filter(function(code) { return code === e.errorCode });
// Error codes: https://cs.chromium.org/chromium/src/net/base/net_error_list.h
var msg = []
msg[-2] = 'NET error: failed.'
msg[-3] = 'An operation was aborted (due to user action)'
msg[-7] = 'Connection timeout.'
msg[-21] = 'Network change.'
msg[-100] = 'The connection was reset. Check your internet connection.'
msg[-101] = 'The connection was reset. Check your internet connection.'
msg[-105] = 'Name not resolved. Check your internet connection.'
msg[-106] = 'There is no active internet connection.'
msg[-118] = 'Connection timed out. Check your internet connection.'
msg[-130] = 'Proxy connection failed. Please, check the proxy configuration.'
msg[-300] = 'The URL is invalid.'
msg[-324] = 'Empty response. Check your internet connection.'
switch ( e.errorCode ) {
case 0:
break
case -3: // An operation was aborted (due to user action) I think that gmail an other pages that use iframes stop some of them making this error fired
if ( attempt.length <= 4 ) return
setTimeout(() => me.reloadService(me), 200);
me.errorCodeLog = []
break;
case 'hangouts':
e.preventDefault();
if ( e.url.indexOf('plus.google.com/u/0/photos/albums') >= 0 ) {
ipc.send('image:popup', e.url, e.target.partition);
return;
} else if ( e.url.indexOf('/el/CONVERSATION/') >= 0 ) {
me.add({
xtype: 'window'
,title: 'Video Call'
,width: '80%'
,height: '80%'
,maximizable: true
,resizable: true
,draggable: true
,collapsible: true
,items: {
xtype: 'component'
,hideMode: 'offsets'
,autoRender: true
,autoShow: true
,autoEl: {
tag: 'webview'
,src: e.url
,style: 'width:100%;height:100%;'
,partition: me.getWebView().partition
,useragent: ipc.sendSync('getConfig').user_agent ? ipc.sendSync('getConfig').user_agent : Ext.getStore('ServicesList').getById(me.record.get('type')).get('userAgent')
}
}
}).show();
return;
}
case -2:
case -7:
case -21:
case -118:
case -324:
case -100:
case -101:
case -105:
attempt.length > 4 ? me.onFailLoad(msg[e.errorCode]) : setTimeout(() => me.reloadService(me), 2000);
break;
case 'slack':
if ( e.url.indexOf('slack.com/call/') >= 0 ) {
me.add({
xtype: 'window'
,title: e.options.title
,width: e.options.width
,height: e.options.height
,maximizable: true
,resizable: true
,draggable: true
,collapsible: true
,items: {
xtype: 'component'
,hideMode: 'offsets'
,autoRender: true
,autoShow: true
,autoEl: {
tag: 'webview'
,src: e.url
,style: 'width:100%;height:100%;'
,partition: me.getWebView().partition
,useragent: ipc.sendSync('getConfig').user_agent ? ipc.sendSync('getConfig').user_agent : Ext.getStore('ServicesList').getById(me.record.get('type')).get('userAgent')
}
}
}).show();
e.preventDefault();
return;
}
case -106:
me.onFailLoad(msg[e.errorCode])
break;
case 'icloud':
if ( e.url.indexOf('index.html#compose') >= 0 ) {
me.add({
xtype: 'window'
,title: 'iCloud - Compose'
,width: 700
,height: 500
,maximizable: true
,resizable: true
,draggable: true
,collapsible: true
,items: {
xtype: 'component'
,itemId: 'webview'
,hideMode: 'offsets'
,autoRender: true
,autoShow: true
,autoEl: {
tag: 'webview'
,src: e.url
,style: 'width:100%;height:100%;'
,partition: me.getWebView().partition
,useragent: ipc.sendSync('getConfig').user_agent ? ipc.sendSync('getConfig').user_agent : Ext.getStore('ServicesList').getById(me.record.get('type')).get('userAgent')
,preload: './resources/js/rambox-modal-api.js'
}
}
,listeners: {
show: function(win) {
const webview = win.down('#webview').el.dom;
webview.addEventListener('ipc-message', function(event) {
var channel = event.channel;
switch (channel) {
case 'close':
win.close();
break;
default:
break;
}
});
}
}
}).show();
e.preventDefault();
return;
}
break;
case 'flowdock':
if ( e.disposition === 'new-window' ) {
e.preventDefault();
require('electron').shell.openExternal(e.url);
}
return;
break;
default:
case -130:
// Could not create a connection to the proxy server. An error occurred
// either in resolving its name, or in connecting a socket to it.
// Note that this does NOT include failures during the actual "CONNECT" method
// of an HTTP proxy.
case -300:
attempt.length > 4 ? me.onFailLoad(msg[e.errorCode]) : me.reloadService(me);
break;
}
});
const protocol = require('url').parse(e.url).protocol;
if (protocol === 'http:' || protocol === 'https:' || protocol === 'mailto:') {
e.preventDefault();
require('electron').shell.openExternal(e.url);
}
// Open links in default browser
webview.addEventListener('new-window', function(e) {
e.preventDefault();
const { URL } = require('url');
const url = new URL(e.url);
const protocol = url.protocol;
// Block some Deep links to prevent that open its app (Ex: Slack)
if ( ['slack:'].includes(protocol) ) return;
// Allow Deep links
if ( !['http:', 'https:', 'about:'].includes(protocol) ) return require('electron').shell.openExternal(url.href);
});
webview.addEventListener('will-navigate', function(e, url) {
e.preventDefault();
});
let eventsOnDom = false;
webview.addEventListener("dom-ready", function(e) {
// Mute Webview
if ( me.record.get('muted') || localStorage.getItem('locked') || JSON.parse(localStorage.getItem('dontDisturb')) ) me.setAudioMuted(true, true);
@ -413,7 +397,7 @@ Ext.define('Rambox.ux.WebView',{
var js_inject = '';
// Injected code to detect new messages
if ( me.record ) {
var js_unread = Ext.getStore('ServicesList').getById(me.record.get('type')).get('js_unread');
var js_unread = Ext.getStore('ServicesList').getById(me.record.get('type')) ? Ext.getStore('ServicesList').getById(me.record.get('type')).get('js_unread') : '' ;
js_unread = js_unread + me.record.get('js_unread');
if ( js_unread !== '' ) {
console.groupCollapsed(me.record.get('type').toUpperCase() + ' - JS Injected to Detect New Messages');
@ -424,7 +408,7 @@ Ext.define('Rambox.ux.WebView',{
}
// Prevent Title blinking (some services have) and only allow when the title have an unread regex match: "(3) Title"
if ( Ext.getStore('ServicesList').getById(me.record.get('type')).get('titleBlink') ) {
if ( Ext.getStore('ServicesList').getById(me.record.get('type')) ? Ext.getStore('ServicesList').getById(me.record.get('type')).get('titleBlink') : false ) {
var js_preventBlink = 'var originalTitle=document.title;Object.defineProperty(document,"title",{configurable:!0,set:function(a){null===a.match(new RegExp("[(]([0-9•]+)[)][ ](.*)","g"))&&a!==originalTitle||(document.getElementsByTagName("title")[0].innerHTML=a)},get:function(){return document.getElementsByTagName("title")[0].innerHTML}});';
console.log(js_preventBlink);
js_inject += js_preventBlink;
@ -436,8 +420,8 @@ Ext.define('Rambox.ux.WebView',{
js_inject += 'document.body.scrollTop=0;';
// Handles Certificate Errors
webview.getWebContents().on('certificate-error', function(event, url, error, certificate, callback) {
if ( me.record.get('trust') ) {
require('electron').remote.webContents.fromId(webview.getWebContentsId()).on('certificate-error', function(event, url, error, certificate, callback) {
if (me.record.get('trust')) {
event.preventDefault();
callback(true);
} else {
@ -447,35 +431,54 @@ Ext.define('Rambox.ux.WebView',{
me.down('statusbar').keep = true;
me.down('statusbar').show();
me.down('statusbar').setStatus({
text: '<i class="fa fa-exclamation-triangle" aria-hidden="true"></i> Certification Warning'
text: '<i class="fa fa-exclamation-triangle" aria-hidden="true"></i> Certification Warning',
});
me.down('statusbar').down('button').show();
});
if (!eventsOnDom) {
require('electron').remote.webContents.fromId(webview.getWebContentsId()).on('before-input-event', (event, input) => {
if (input.type !== 'keyDown') return;
var modifiers = [];
if (input.shift) modifiers.push('shift');
if (input.control) modifiers.push('control');
if (input.alt) modifiers.push('alt');
if (input.meta) modifiers.push('meta');
if (input.isAutoRepeat) modifiers.push('isAutoRepeat');
if (input.key === 'Tab' && !(modifiers && modifiers.length)) return;
// Maps special keys to fire the correct event in Mac OS
if (require('electron').remote.process.platform === 'darwin') {
var keys = [];
keys['ƒ'] = 'f'; // Search
keys[' '] = 'l'; // Lock
keys['∂'] = 'd'; // DND
input.key = keys[input.key] ? keys[input.key] : input.key;
}
webview.executeJavaScript(js_inject);
});
webview.getWebContents().on('before-input-event', (event, input) => {
if (input.type !== 'keyDown') { // event used by default
return;
}
// because keyCode property is not passed
const keycode = require('keycodes')
// Create a fake KeyboardEvent from the data provided
var emulatedKeyboardEvent = new KeyboardEvent('keydown', {
code: input.code,
key: input.key,
shiftKey: input.shift,
altKey: input.alt,
ctrlKey: input.control,
metaKey: input.meta,
repeat: input.isAutoRepeat,
keyCode: keycode(input.key) //get real key code
});
emulatedKeyboardEvent.getKey = function() {
return this.keyCode || this.charCode // fake function, normally used by Ext.js, simply returning keyCode
}
document.keyMapping.handleTargetEvent(emulatedKeyboardEvent) // we directly trigger handleTargetEvent. That's a private method normally. We can't fire the event directly with document.dispatch, unfortunately
if (
input.key === 'F11' ||
input.key === 'a' ||
input.key === 'A' ||
input.key === 'F12' ||
input.key === 'q' ||
(input.key === 'F1' && modifiers.includes('control'))
)
return;
require('electron').remote.getCurrentWebContents().sendInputEvent({
type: input.type,
keyCode: input.key,
modifiers: modifiers,
});
});
eventsOnDom = true;
Rambox.app.config.googleURLs.forEach((loginURL) => { if ( webview.getURL().indexOf(loginURL) > -1 ) webview.reload() })
}
webview.executeJavaScript(js_inject).then(result => {} ).catch(err => { console.log(err) })
});
webview.addEventListener('ipc-message', function(event) {
@ -491,7 +494,6 @@ Ext.define('Rambox.ux.WebView',{
showWindowAndActivateTab(event);
break;
}
/**
* Handles 'rambox.clearUnreadCount' messages.
* Clears the unread count.
@ -512,6 +514,7 @@ Ext.define('Rambox.ux.WebView',{
if (Array.isArray(event.args) === true && event.args.length > 0) {
var count = event.args[0];
if (count === parseInt(count, 10) || "•" === count) {
if ( count === 999999 ) count = "•";
me.setUnreadCount(count);
}
}
@ -519,14 +522,18 @@ Ext.define('Rambox.ux.WebView',{
function showWindowAndActivateTab(event) {
require('electron').remote.getCurrentWindow().show();
Ext.cq1('app-main').setActiveTab(me);
var tabPanel = Ext.cq1('app-main');
// Temp fix missing cursor after upgrade to electron 3.x +
tabPanel.setActiveTab(me);
tabPanel.getActiveTab().getWebView().blur();
tabPanel.getActiveTab().getWebView().focus();
}
});
/**
* Register page title update event listener only for services that don't specify a js_unread
*/
if (Ext.getStore('ServicesList').getById(me.record.get('type')).get('js_unread') === '' && me.record.get('js_unread') === '') {
if ( Ext.getStore('ServicesList').getById(me.record.get('type')) ? Ext.getStore('ServicesList').getById(me.record.get('type')).get('js_unread') === '' : false && me.record.get('js_unread') === '' ) {
webview.addEventListener("page-title-updated", function(e) {
var count = e.title.match(/\(([^)]+)\)/); // Get text between (...)
count = count ? count[1] : '0';
@ -575,12 +582,9 @@ Ext.define('Rambox.ux.WebView',{
*/
,doManualNotification: function(count) {
var me = this;
if (Ext.getStore('ServicesList').getById(me.type).get('manual_notifications') &&
me.currentUnreadCount < count &&
me.record.get('notifications') &&
!JSON.parse(localStorage.getItem('dontDisturb'))) {
Rambox.util.Notifier.dispatchNotification(me, count);
var manualNotifications = Ext.getStore('ServicesList').getById(me.type) ? Ext.getStore('ServicesList').getById(me.type).get('manual_notifications') : false;
if ( manualNotifications && me.currentUnreadCount < count && me.record.get('notifications') && !JSON.parse(localStorage.getItem('dontDisturb'))) {
Rambox.util.Notifier.dispatchNotification(me, count);
}
me.currentUnreadCount = count;
@ -613,7 +617,7 @@ Ext.define('Rambox.ux.WebView',{
,reloadService: function(btn) {
var me = this;
var webview = me.down('component').el.dom;
var webview = me.getWebView();
if ( me.record.get('enabled') ) {
me.clearUnreadCounter();
@ -621,16 +625,62 @@ Ext.define('Rambox.ux.WebView',{
}
}
,onFailLoad: function(v) {
let me = this
me.errorCodeLog = []
setTimeout(() => Ext.getCmp(me.id+'statusbar').setStatus({ text: '<i class="fa fa-warning fa-fw" aria-hidden="true"></i> The service failed at loading, Error: '+ v }), 1000);
}
,showSearchBox: function(v) {
var me = this;
if ( !me.record.get('enabled') ) return;
var webview = me.getWebView();
webview.stopFindInPage('keepSelection');
if ( v ) {
me.down('#searchBar').show();
setTimeout(() => { me.down('#searchBar textfield').focus() }, 100)
} else {
me.down('#searchBar').hide();
me.down('#searchBar textfield').setValue('');
}
me.down('#searchBar displayfield').setValue('');
}
,doSearchText: function(field, newValue, oldValue, eOpts, forward = true) {
var me = this;
var webview = me.getWebView();
if ( newValue === '' ) {
webview.stopFindInPage('clearSelection');
me.down('#searchBar displayfield').setValue('');
return;
}
webview.findInPage(newValue, {
forward: forward,
findNext: false,
matchCase: false
})
}
,onSearchText: function( result ) {
var me = this;
me.down('#searchBar displayfield').setValue(result.activeMatchOrdinal+ '/' + result.matches);
}
,toggleDevTools: function(btn) {
var me = this;
var webview = me.down('component').el.dom;
var webview = me.getWebView();
if ( me.record.get('enabled') ) webview.isDevToolsOpened() ? webview.closeDevTools() : webview.openDevTools();
}
,setURL: function(url) {
var me = this;
var webview = me.down('component').el.dom;
var webview = me.getWebView();
me.src = url;
@ -639,7 +689,7 @@ Ext.define('Rambox.ux.WebView',{
,setAudioMuted: function(muted, calledFromDisturb) {
var me = this;
var webview = me.down('component').el.dom;
var webview = me.getWebView();
me.muted = muted;
@ -671,7 +721,7 @@ Ext.define('Rambox.ux.WebView',{
,setNotifications: function(notification, calledFromDisturb) {
var me = this;
var webview = me.down('component').el.dom;
var webview = me.getWebView();
me.notifications = notification;
@ -700,43 +750,47 @@ Ext.define('Rambox.ux.WebView',{
,goBack: function() {
var me = this;
var webview = me.down('component').el.dom;
var webview = me.getWebView();
if ( me.record.get('enabled') ) webview.goBack();
}
,goForward: function() {
var me = this;
var webview = me.down('component').el.dom;
var webview = me.getWebView();
if ( me.record.get('enabled') ) webview.goForward();
}
,zoomIn: function() {
var me = this;
var webview = me.down('component').el.dom;
me.zoomLevel = me.zoomLevel + 0.25;
if ( me.record.get('enabled') ) {
webview.setZoomLevel(me.zoomLevel);
me.record.set('zoomLevel', me.zoomLevel);
}
if ( this.timeout ) clearTimeout( this.timeout );
this.timeout = setTimeout(() => {
var me = this;
var webview = me.getWebView();
me.zoomLevel = me.zoomLevel + 0.25;
if ( me.record.get('enabled') ) {
webview.setZoomLevel(me.zoomLevel);
me.record.set('zoomLevel', me.zoomLevel);
}
}, 100);
}
,zoomOut: function() {
var me = this;
var webview = me.down('component').el.dom;
me.zoomLevel = me.zoomLevel - 0.25;
if ( me.record.get('enabled') ) {
webview.setZoomLevel(me.zoomLevel);
me.record.set('zoomLevel', me.zoomLevel);
}
if ( this.timeout ) clearTimeout( this.timeout );
this.timeout = setTimeout(() => {
var me = this;
var webview = me.getWebView();
me.zoomLevel = me.zoomLevel - 0.25;
if ( me.record.get('enabled') ) {
webview.setZoomLevel(me.zoomLevel);
me.record.set('zoomLevel', me.zoomLevel);
}
}, 100);
}
,resetZoom: function() {
var me = this;
var webview = me.down('component').el.dom;
var webview = me.getWebView();
me.zoomLevel = 0;
if ( me.record.get('enabled') ) {
@ -747,7 +801,7 @@ Ext.define('Rambox.ux.WebView',{
,getWebView: function() {
if ( this.record.get('enabled') ) {
return this.down('component').el.dom;
return this.down('component[cls=webview]').el.dom;
} else {
return false;
}

27
app/view/add/Add.js

@ -61,13 +61,19 @@ Ext.define('Rambox.view.add.Add',{
,{
xtype: 'textfield'
,name: 'url'
,value: me.edit && me.service.get('url').indexOf('___') >= 0 ? me.record.get('url').replace(me.service.get('url').split('___')[0], '').replace(me.service.get('url').split('___')[1], '') : (me.record.get('url').indexOf('___') === -1 ? me.record.get('url') : '')
,value: me.edit && me.service.get('url').indexOf('___') >= 0 ? me.record.get('url').replace(me.service.get('url').split('___')[0], '').replace(me.service.get('url').split('___')[1], '').endsWith('/') ? me.record.get('url').replace(me.service.get('url').split('___')[0], '').replace(me.service.get('url').split('___')[1], '').slice(0, -1) : me.record.get('url').replace(me.service.get('url').split('___')[0], '').replace(me.service.get('url').split('___')[1], '') : (me.record.get('url').indexOf('___') === -1 ? me.record.get('url') : '')
,readOnly: me.edit ? (me.service.get('custom_domain') && me.service.get('url') === me.record.get('url') ? true : me.service.get('url').indexOf('___') === -1 && !me.service.get('custom_domain')) : me.record.get('url').indexOf('___') === -1 && me.record.get('custom_domain')
,allowBlank: false
,submitEmptyText: false
,emptyText: me.record.get('url') === '___' ? 'https://' : ''
,vtype: me.record.get('url') === '___' ? 'url' : ''
,listeners: { specialkey: 'onEnter' }
,validator: function(v) {
if ( !me.edit ? me.record.get('url') !== '___' : me.service.get('url').indexOf('https://___') === 0 ) return true
if ( v.match(/^(?:(?:https?|ftp):\/\/)(?:\S+(?::\S*)?@)?(?:(?!(?:10|127)(?:\.\d{1,3}){3})(?!(?:169\.254|192\.168)(?:\.\d{1,3}){2})(?!172\.(?:1[6-9]|2\d|3[0-1])(?:\.\d{1,3}){2})(?:[1-9]\d?|1\d\d|2[01]\d|22[0-3])(?:\.(?:1?\d{1,2}|2[0-4]\d|25[0-5])){2}(?:\.(?:[1-9]\d?|1\d\d|2[0-4]\d|25[0-4]))|(?:(?:[a-z\u00a1-\uffff0-9]-*)*[a-z\u00a1-\uffff0-9]+)(?:\.(?:[a-z\u00a1-\uffff0-9]-*)*[a-z\u00a1-\uffff0-9]+)*(?:\.(?:[a-z\u00a1-\uffff]{2,}))\.?)(?::\d{2,5})?(?:[/?#]\S*)?$/i) === null && v.match(/^https:\/\/\w+(\.\w+)*(:[0-9]+)?\/?(\/[.\w]*)*$/) === null && v.match(/^http:\/\/\w+(\.\w+)*(:[0-9]+)?\/?(\/[.\w]*)*$/) === null ) return false;
return true;
}
,listeners: {
specialkey: 'onEnter'
}
,flex: 1
}
,{
@ -80,12 +86,12 @@ Ext.define('Rambox.view.add.Add',{
items: [
{
text: me.edit ? (me.service.get('url').indexOf('___') === -1 ? 'Official Server' : Ext.String.endsWith(me.service.get('url'), '/') ? me.service.get('url').split('___')[1].slice(0, -1) : me.service.get('url').split('___')[1]) : (me.record.get('url').indexOf('___') === -1 ? 'Official Server' : Ext.String.endsWith(me.record.get('url'), '/') ? me.record.get('url').split('___')[1].slice(0, -1) : me.record.get('url').split('___')[1])
,checked: me.edit ? (me.service.get('custom_domain') && me.service.get('url') === me.record.get('url') ? true : Ext.String.endsWith(me.record.get('url'), me.service.get('url').split('___')[1])) : true
,checked: me.edit ? (me.service.get('custom_domain') && me.service.get('url') === me.record.get('url') ? true : Ext.String.endsWith(me.record.get('url').endsWith('/') ? me.record.get('url').slice(0, -1) : me.record.get('url'), me.service.get('url').split('___')[1])) : true
,disabled: me.edit ? me.service.get('url') === '___' : me.record.get('url') === '___'
}
,{
text: 'Custom Server'
,checked: me.edit ? (me.service.get('custom_domain') && me.service.get('url') === me.record.get('url') ? false : !Ext.String.endsWith(me.record.get('url'), me.service.get('url').split('___')[1])) : false
,checked: me.edit ? (me.service.get('custom_domain') && me.service.get('url') === me.record.get('url') ? false : !Ext.String.endsWith(me.record.get('url').endsWith('/') ? me.record.get('url').slice(0, -1) : me.record.get('url'), me.service.get('url').split('___')[1])) : false
,custom: true
,disabled: me.edit ? !me.service.get('custom_domain') : !me.record.get('custom_domain')
}
@ -120,7 +126,7 @@ Ext.define('Rambox.view.add.Add',{
,{
xtype: 'hiddenfield'
,name: 'cycleValue'
,value: me.edit ? (me.service.get('custom_domain') && me.service.get('url') === me.record.get('url') ? 1 : (!Ext.String.endsWith(me.record.get('url'), me.service.get('url').split('___')[1]) ? 2 : 1)) : 1
,value: me.edit ? (me.service.get('custom_domain') && me.service.get('url') === me.record.get('url') ? 1 : (!Ext.String.endsWith(me.record.get('url').endsWith('/') ? me.record.get('url').slice(0, -1) : me.record.get('url'), me.service.get('url').split('___')[1]) ? 2 : 1)) : 1
}
]
}
@ -186,6 +192,15 @@ Ext.define('Rambox.view.add.Add',{
,uncheckedValue: false
,inputValue: true
}
,{
xtype: 'checkbox'
,boxLabel: 'Disable auto-reload on fail'
,name: 'disableAutoReloadOnFail'
,hidden: false
,checked: me.edit ? me.record.get('disableAutoReloadOnFail') : false
,uncheckedValue: false
,inputValue: true
}
,{
xtype: 'checkbox'
,boxLabel: locale['app.window[19]']

1
app/view/add/AddController.js

@ -40,6 +40,7 @@ Ext.define('Rambox.view.add.AddController', {
,includeInGlobalUnreadCounter: formValues.includeInGlobalUnreadCounter
,trust: formValues.trust
,js_unread: formValues.js_unread
,disableAutoReloadOnFail: formValues.disableAutoReloadOnFail
});
var view = Ext.getCmp('tab_'+win.record.get('id'));

154
app/view/main/Main.js

@ -26,13 +26,8 @@ Ext.define('Rambox.view.main.Main', {
,autoShow: true
,deferredRender: false
,tabBar: {
items: [{
xtype: 'button'
,html: '<span class="fa fa-heart" style="color:red;font-size:16px;cursor:pointer;padding:0 5px;"></span>'
,baseCls: ''
,tooltip: locale['app.main[25]']
,href: 'https://rambox.pro/#donate'
}]
id: 'mainTabBar'
,cls: JSON.parse(localStorage.getItem('dontDisturb')) ? 'dontdisturb' : ''
}
,items: [
{
@ -146,12 +141,15 @@ Ext.define('Rambox.view.main.Main', {
,baseCls: ''
,tooltip: locale['app.main[10]']
,handler: 'removeAllServices'
,bind: {
disabled: '{emptyServices}'
}
}
]
,columns: [
{
xtype: 'templatecolumn'
,width: 50
,width: 52
,variableRowHeight: true
,tpl: '<img src="{[ values.type !== \"custom\" ? \"resources/icons/\"+values.logo : (values.logo == \"\" ? \"resources/icons/custom.png\" : values.logo) ]}" data-qtip="{type:capitalize}" width="32" style="{[ values.enabled ? \"-webkit-filter: grayscale(0)\" : \"-webkit-filter: grayscale(1)\" ]}" />'
}
@ -238,7 +236,7 @@ Ext.define('Rambox.view.main.Main', {
{
glyph: JSON.parse(localStorage.getItem('dontDisturb')) ? 'xf1f7@FontAwesome' : 'xf0f3@FontAwesome'
,text: locale['app.main[16]']+': '+(JSON.parse(localStorage.getItem('dontDisturb')) ? locale['app.window[20]'] : locale['app.window[21]'])
,tooltip: locale['app.main[17]']+'<br/><b>'+locale['app.main[18]']+': F1</b>'
,tooltip: locale['app.main[17]']+'<br/><b>'+locale['app.main[18]']+(require('electron').remote.process.platform === 'darwin' ? ': Cmd + Alt + D</b>' : ': Alt + Shift + D</b>')
,enableToggle: true
,handler: 'dontDisturb'
,reference: 'disturbBtn'
@ -248,82 +246,11 @@ Ext.define('Rambox.view.main.Main', {
,{
glyph: 'xf023@FontAwesome'
,text: locale['app.main[19]']
,tooltip: locale['app.main[20]']+'<br/><b>'+locale['app.main[18]']+': F2</b>'
,tooltip: locale['app.main[20]']+'<br/><b>'+locale['app.main[18]']+(require('electron').remote.process.platform === 'darwin' ? ': Cmd + Alt + L</b>' : ': Alt + Shift + L</b>')
,handler: 'lockRambox'
,id: 'lockRamboxBtn'
},'-'
,{
html: '<span style="color:#FFF;cursor:pointer;"><span class="fa fa-star" style="color:#F8D64E;font-size:16px;padding:0 5px;"></span> Try Rambox Pro</span>'
,href: 'https://rambox.pro/api/download'
,baseCls: ''
}
,'->'
,{
xtype: 'image'
,id: 'avatar'
,bind: {
src: '{avatar}'
,hidden: '{!avatar}'
}
,width: 30
,height: 30
,style: 'border-radius: 50%;border:2px solid #d8d8d8;'
}
,{
id: 'usernameBtn'
,bind: {
text: '{username}'
,hidden: '{!username}'
}
,menu: [
{
text: 'Synchronize Configuration'
,glyph: 'xf0c2@FontAwesome'
,menu: [
{
xtype: 'label'
,bind: {
html: '<b class="menu-title">Last Sync: {last_sync}</b>'
}
}
,{
text: 'Backup'
,glyph: 'xf0ee@FontAwesome'
,scope: Rambox.ux.Auth0
,handler: Rambox.ux.Auth0.backupConfiguration
}
,{
text: 'Restore'
,glyph: 'xf0ed@FontAwesome'
,scope: Rambox.ux.Auth0
,handler: Rambox.ux.Auth0.restoreConfiguration
}
,{
text: 'Check for updated backup'
,glyph: 'xf021@FontAwesome'
,scope: Rambox.ux.Auth0
,handler: Rambox.ux.Auth0.checkConfiguration
}
]
}
,'-'
,{
text: locale['app.main[21]']
,glyph: 'xf08b@FontAwesome'
,handler: 'logout'
}
]
}
,{
text: locale['app.main[22]']
,icon: 'resources/auth0.png'
,id: 'loginBtn'
,tooltip: locale['app.main[23]']+'<br /><br /><i>'+locale['app.main[24]']+' Auth0 (https://auth0.com)</i>'
,bind: {
hidden: '{username}'
}
,handler: 'login'
}
,{
tooltip: locale['preferences[0]']
,glyph: 'xf013@FontAwesome'
@ -331,56 +258,23 @@ Ext.define('Rambox.view.main.Main', {
}
]
}
,bbar: [
{
xtype: 'segmentedbutton'
,allowToggle: false
,items: [
{
text: '<b>Help us</b> with'
,pressed: true
}
,{
text: locale['app.main[25]']
,glyph: 'xf21e@FontAwesome'
,href: 'https://rambox.pro/#donate'
}
,{
text: 'Translation'
,glyph: 'xf0ac@FontAwesome'
,href: 'https://crowdin.com/project/rambox/invite'
}
]
}
,'->'
,{
xtype: 'label'
,html: '<span class="fa fa-code" style="color:black;"></span> '+locale['app.main[26]']+' <span class="fa fa-heart" style="color:red;"></span> '+locale['app.main[27]'].replace('Argentina', '<img src="resources/flag.png" alt="Argentina" data-qtip="Argentina" />')
}
,'->'
,{
xtype: 'segmentedbutton'
,allowToggle: false
,items: [
{
text: '<b>Follow us</b>'
,pressed: true
}
,{
glyph: 'xf082@FontAwesome'
,href: 'https://www.facebook.com/ramboxapp'
}
,{
glyph: 'xf099@FontAwesome'
,href: 'https://www.twitter.com/ramboxapp'
}
,{
glyph: 'xf09b@FontAwesome'
,href: 'https://github.com/ramboxapp/community-edition'
,bbar: {
xtype: 'toolbar'
,cls: 'deprecation'
,items: [
'<i class="fa fa-exclamation-triangle" aria-hidden="true"></i> <b>This version of Rambox is no longer supported.</b> We highly recommend that you update to the new version of Rambox which has a free plan with all the features you already use and much more!'
,'->'
,{
xtype: 'button'
,text: 'Migrate now'
,handler: function(btn) {
btn.setText('Downloading...');
btn.setDisabled(true);
Rambox.app.checkUpdate();
}
]
}
]
}
]
}
}
,{ id: 'tbfill', tabConfig : { xtype : 'tbfill' } }
]

121
app/view/main/MainController.js

@ -23,9 +23,6 @@ Ext.define('Rambox.view.main.MainController', {
,onTabChange: function( tabPanel, newTab, oldTab ) {
var me = this;
// Set Google Analytics event
ga_storage._trackPageview('/index.html', 'main');
localStorage.setItem('last_active_service', newTab.id);
if ( newTab.id === 'ramboxTab' ) {
@ -42,7 +39,13 @@ Ext.define('Rambox.view.main.MainController', {
}
var webview = newTab.down('component').el.dom;
if ( webview ) webview.focus();
setTimeout(function () {
if ( webview ) {
tabPanel.getActiveTab().getWebView().blur();
tabPanel.getActiveTab().getWebView().focus();
}
}, 300);
// Update the main window so it includes the active tab title.
if ( Rambox.app.getTotalNotifications() > 0 ) {
@ -136,16 +139,14 @@ Ext.define('Rambox.view.main.MainController', {
if ( !rec.get('enabled') ) {
rec.set('enabled', true);
me.onEnableDisableService(null, Ext.getStore('Services').indexOf(rec), true, null, true);
Ext.defer(function() {
// Get Tab
var tab = Ext.getCmp('tab_'+serviceId);
// Clear all trash data
const webview = tab.getWebView();
webview.addEventListener("did-start-loading", function() {
clearData(webview, tab);
});
}, 1000);
// Get Tab
var tab = Ext.getCmp('tab_'+serviceId);
// Clear all trash data
const webview = tab.getWebView();
webview.addEventListener("did-start-loading", function() {
clearData(webview, tab);
});
} else {
// Get Tab
var tab = Ext.getCmp('tab_'+serviceId);
@ -158,11 +159,15 @@ Ext.define('Rambox.view.main.MainController', {
if ( config.default_service === rec.get('id') ) ipc.send('setConfig', Ext.apply(config, { default_service: 'ramboxTab' }));
function clearData(webview, tab) {
webview.getWebContents().clearHistory();
webview.getWebContents().session.flushStorageData();
webview.getWebContents().session.clearCache(function() {
webview.getWebContents().session.clearStorageData(function() {
webview.getWebContents().session.cookies.flushStore(function() {
const currentWebView = require("electron").remote.webContents.fromId(
webview.getWebContentsId()
);
currentWebView.clearHistory();
currentWebView.session.flushStorageData();
currentWebView.session.clearCache().then(() => {
currentWebView.session.clearStorageData().then(() => {
currentWebView.session.cookies.flushStore().then(() => {
// Remove record from localStorage
Ext.getStore('Services').remove(rec);
// Close tab
@ -172,9 +177,9 @@ Ext.define('Rambox.view.main.MainController', {
Ext.Msg.hide();
if ( Ext.isFunction(callback) ) callback();
}
});
});
});
}).catch(err => { console.log(err) })
}).catch(err => { console.log(err) })
}).catch(err => { console.log(err) })
}
}
@ -192,12 +197,12 @@ Ext.define('Rambox.view.main.MainController', {
,removeAllServices: function(btn, callback) {
var me = this;
// Clear counter for unread messaging
document.title = 'Rambox';
if ( btn ) {
Ext.Msg.confirm(locale['app.window[12]'], locale['app.window[14]'], function(btnId) {
if ( btnId === 'yes' ) {
// Clear counter for unread messaging
document.title = 'Rambox';
Ext.cq1('app-main').suspendEvent('remove');
Ext.getStore('Services').load();
Ext.Msg.wait('Please wait until we clear all.', 'Removing...');
@ -292,9 +297,6 @@ Ext.define('Rambox.view.main.MainController', {
,dontDisturb: function(btn, e, called) {
console.info('Dont Disturb:', btn.pressed ? 'Enabled' : 'Disabled');
// Google Analytics Event
if ( !called ) ga_storage._trackEvent('Usability', 'dontDisturb', ( btn.pressed ? 'on' : 'off' ));
Ext.Array.each(Ext.getStore('Services').collect('id'), function(serviceId) {
// Get Tab
var tab = Ext.getCmp('tab_'+serviceId);
@ -319,6 +321,8 @@ Ext.define('Rambox.view.main.MainController', {
btn.pressed ? btn.setGlyph('xf1f7@FontAwesome') : btn.setGlyph('xf0f3@FontAwesome');
Ext.getCmp('mainTabBar').getEl().toggleCls('dontdisturb');
// If this method is called from Lock method, prevent showing toast
if ( !e ) return;
Ext.toast({
@ -371,14 +375,22 @@ Ext.define('Rambox.view.main.MainController', {
}
function setLock(text) {
var ramboxTab = Ext.cq1('#ramboxTab');
// Related to issue #2065. Focusing in an sub frame is a workaround
if (ramboxTab.getWebView) {
ramboxTab.down('component').el.dom.executeJavaScript(`
var iframeFix = document.createElement('iframe');
document.body.appendChild(iframeFix);
iframeFix.focus();
document.body.removeChild(iframeFix);
`);
}
console.info('Lock Rambox:', 'Enabled');
// Save encrypted password in localStorage to show locked when app is reopen
localStorage.setItem('locked', text);
// Google Analytics Event
ga_storage._trackEvent('Usability', 'locked');
me.lookupReference('disturbBtn').setPressed(true);
me.dontDisturb(me.lookupReference('disturbBtn'), false, true);
@ -466,53 +478,6 @@ Ext.define('Rambox.view.main.MainController', {
}
,openPreferences: function( btn ) {
var me = this;
Ext.create('Rambox.view.preferences.Preferences').show();
}
,login: function(btn) {
var me = this;
Rambox.ux.Auth0.login();
}
,logout: function(btn) {
var me = this;
var logoutFn = function(callback) {
Ext.Msg.wait(locale['app.window[37]'], locale['app.main[21]']);
// Google Analytics Event
ga_storage._trackEvent('Users', 'loggedOut');
// Logout from Auth0
Rambox.ux.Auth0.logout();
Ext.cq1('app-main').getViewModel().set('username', '');
Ext.cq1('app-main').getViewModel().set('avatar', '');
if ( Ext.isFunction(callback) ) {
callback(false, function() {
Ext.Msg.hide();
});
} else {
Ext.Msg.hide();
}
}
if ( btn ) {
Ext.Msg.confirm(locale['app.main[21]'], locale['app.window[38]'], function(btnId) {
if ( btnId === 'yes' ) {
logoutFn(me.removeAllServices.bind(me));
}
});
} else {
logoutFn();
}
}
,showDonate: function( btn ) {
Signalayer.API.show('tChaoq3PwSG9wswhn');
}
});

1
app/view/main/MainModel.js

@ -9,5 +9,6 @@ Ext.define('Rambox.view.main.MainModel', {
,username: localStorage.getItem('profile') ? JSON.parse(localStorage.getItem('profile')).name : ''
,avatar: localStorage.getItem('profile') ? JSON.parse(localStorage.getItem('profile')).picture : ''
,last_sync: localStorage.getItem('profile') && JSON.parse(localStorage.getItem('profile')).user_metadata && JSON.parse(localStorage.getItem('profile')).user_metadata.services_lastupdate ? new Date(JSON.parse(localStorage.getItem('profile')).user_metadata.services_lastupdate).toUTCString() : ''
,emptyServices: true
}
});

99
app/view/preferences/Preferences.js

@ -16,12 +16,15 @@ Ext.define('Rambox.view.preferences.Preferences',{
,title: locale['preferences[0]']
,width: 420
,height: 500
,modal: true
,closable: true
,minimizable: false
,maximizable: false
,draggable: true
,resizable: false
,scrollable: 'vertical'
,bodyStyle: 'margin-right:15px;'
,buttons: [
{
text: locale['button[1]']
@ -71,45 +74,50 @@ Ext.define('Rambox.view.preferences.Preferences',{
,store: Ext.create('Ext.data.Store', {
fields: ['value', 'label']
,data: [
{ 'value': 'af', 'auth0': 'af', 'label': 'Afrikaans' }
,{ 'value': 'ar', 'auth0': 'en', 'label': 'Arabic' }
,{ 'value': 'bs2', 'auth0': 'en', 'label': 'Barndutsch, Switzerland' }
,{ 'value': 'bn', 'auth0': 'en', 'label': 'Bengali' }
,{ 'value': 'bg', 'auth0': 'en', 'label': 'Bulgarian' }
,{ 'value': 'ca', 'auth0': 'ca', 'label': 'Catalan' }
,{ 'value': 'zh-CN', 'auth0': 'zh', 'label': 'Chinese Simplified' }
,{ 'value': 'zh-TW', 'auth0': 'zh-tw', 'label': 'Chinese Traditional' }
,{ 'value': 'hr', 'auth0': 'en', 'label': 'Croatian' }
,{ 'value': 'cs', 'auth0': 'cs', 'label': 'Czech' }
,{ 'value': 'da', 'auth0': 'da', 'label': 'Danish' }
,{ 'value': 'nl', 'auth0': 'nl', 'label': 'Dutch' }
,{ 'value': 'en', 'auth0': 'en', 'label': 'English' }
,{ 'value': 'fi', 'auth0': 'fi', 'label': 'Finnish' }
,{ 'value': 'fr', 'auth0': 'fr', 'label': 'French' }
,{ 'value': 'de', 'auth0': 'de', 'label': 'German' }
,{ 'value': 'de-CH', 'auth0': 'de', 'label': 'German, Switzerland' }
,{ 'value': 'el', 'auth0': 'en', 'label': 'Greek' }
,{ 'value': 'he', 'auth0': 'en', 'label': 'Hebrew' }
,{ 'value': 'hi', 'auth0': 'en', 'label': 'Hindi' }
,{ 'value': 'hu', 'auth0': 'hu', 'label': 'Hungarian' }
,{ 'value': 'id', 'auth0': 'en', 'label': 'Indonesian' }
,{ 'value': 'it', 'auth0': 'it', 'label': 'Italian' }
,{ 'value': 'ja', 'auth0': 'ja', 'label': 'Japanese' }
,{ 'value': 'ko', 'auth0': 'ko', 'label': 'Korean' }
,{ 'value': 'no', 'auth0': 'no', 'label': 'Norwegian' }
,{ 'value': 'fa', 'auth0': 'fa', 'label': 'Persian' }
,{ 'value': 'pl', 'auth0': 'pl', 'label': 'Polish' }
,{ 'value': 'pt-PT', 'auth0': 'pt-br', 'label': 'Portuguese' }
,{ 'value': 'pt-BR', 'auth0': 'pt-br', 'label': 'Portuguese (Brazilian)' }
,{ 'value': 'ro', 'auth0': 'ro', 'label': 'Romanian' }
,{ 'value': 'ru', 'auth0': 'ru', 'label': 'Russian' }
,{ 'value': 'sr', 'auth0': 'en', 'label': 'Serbian (Cyrillic)' }
,{ 'value': 'sk', 'auth0': 'sk', 'label': 'Slovak' }
,{ 'value': 'es-ES', 'auth0': 'es', 'label': 'Spanish' }
,{ 'value': 'sv-SE', 'auth0': 'sv', 'label': 'Swedish' }
,{ 'value': 'tr', 'auth0': 'tr', 'label': 'Turkish' }
,{ 'value': 'uk', 'auth0': 'en', 'label': 'Ukrainian' }
,{ 'value': 'vi', 'auth0': 'en', 'label': 'Vietnamese' }
{ 'value': 'af', 'extjs': 'af', 'label': 'Afrikaans' }
,{ 'value': 'ar', 'extjs': 'en', 'label': 'Arabic' }
,{ 'value': 'bs2', 'extjs': 'en', 'label': 'Barndutsch, Switzerland' }
,{ 'value': 'bn', 'extjs': 'en', 'label': 'Bengali' }
,{ 'value': 'bg', 'extjs': 'en', 'label': 'Bulgarian' }
,{ 'value': 'ca', 'extjs': 'ca', 'label': 'Catalan' }
,{ 'value': 'ceb', 'extjs': 'en', 'label': 'Cebuano' }
,{ 'value': 'zh-CN', 'extjs': 'zh', 'label': 'Chinese Simplified' }
,{ 'value': 'zh-TW', 'extjs': 'zh-tw', 'label': 'Chinese Traditional' }
,{ 'value': 'hr', 'extjs': 'en', 'label': 'Croatian' }
,{ 'value': 'cs', 'extjs': 'cs', 'label': 'Czech' }
,{ 'value': 'da', 'extjs': 'da', 'label': 'Danish' }
,{ 'value': 'nl', 'extjs': 'nl', 'label': 'Dutch' }
,{ 'value': 'en', 'extjs': 'en', 'label': 'English' }
,{ 'value': 'fi', 'extjs': 'fi', 'label': 'Finnish' }
,{ 'value': 'fil', 'extjs': 'en', 'label': 'Filipino' }
,{ 'value': 'fr', 'extjs': 'fr', 'label': 'French' }
,{ 'value': 'de', 'extjs': 'de', 'label': 'German' }
,{ 'value': 'de-CH', 'extjs': 'de', 'label': 'German, Switzerland' }
,{ 'value': 'el', 'extjs': 'el', 'label': 'Greek' }
,{ 'value': 'he', 'extjs': 'en', 'label': 'Hebrew' }
,{ 'value': 'hi', 'extjs': 'en', 'label': 'Hindi' }
,{ 'value': 'hu', 'extjs': 'hu', 'label': 'Hungarian' }
,{ 'value': 'id', 'extjs': 'en', 'label': 'Indonesian' }
,{ 'value': 'it', 'extjs': 'it', 'label': 'Italian' }
,{ 'value': 'ja', 'extjs': 'ja', 'label': 'Japanese' }
,{ 'value': 'ko', 'extjs': 'ko', 'label': 'Korean' }
,{ 'value': 'no', 'extjs': 'no', 'label': 'Norwegian' }
,{ 'value': 'fa', 'extjs': 'fa', 'label': 'Persian' }
,{ 'value': 'pl', 'extjs': 'pl', 'label': 'Polish' }
,{ 'value': 'pt-PT', 'extjs': 'pt-br', 'label': 'Portuguese' }
,{ 'value': 'pt-BR', 'extjs': 'pt-br', 'label': 'Portuguese (Brazilian)' }
,{ 'value': 'ro', 'extjs': 'ro', 'label': 'Romanian' }
,{ 'value': 'ru', 'extjs': 'ru', 'label': 'Russian' }
,{ 'value': 'sr', 'extjs': 'en', 'label': 'Serbian (Cyrillic)' }
,{ 'value': 'sk', 'extjs': 'sk', 'label': 'Slovak' }
,{ 'value': 'es-ES', 'extjs': 'es', 'label': 'Spanish' }
,{ 'value': 'sv-SE', 'extjs': 'sv', 'label': 'Swedish' }
,{ 'value': 'tl', 'extjs': 'en', 'label': 'Tagalog' }
,{ 'value': 'th', 'extjs': 'en', 'label': 'Thai' }
,{ 'value': 'tr', 'extjs': 'tr', 'label': 'Turkish' }
,{ 'value': 'uk', 'extjs': 'en', 'label': 'Ukrainian' }
,{ 'value': 'ur-PK', 'extjs': 'en', 'label': 'Urdu (Pakistan)' }
,{ 'value': 'vi', 'extjs': 'en', 'label': 'Vietnamese' }
]
})
}
@ -167,6 +175,12 @@ Ext.define('Rambox.view.preferences.Preferences',{
]
})
}
,{
xtype: 'checkbox'
,name: 'hide_tabbar_labels'
,boxLabel: locale['preferences[28]']
,value: config.hide_tabbar_labels
}
,{
xtype: 'combo'
,name: 'default_service'
@ -343,15 +357,10 @@ Ext.define('Rambox.view.preferences.Preferences',{
,name: 'proxyPassword'
,value: config.proxyPassword
,emptyText: 'Optional'
,inputType: 'password'
}
]
}
,{
xtype: 'checkbox'
,name: 'sendStatistics'
,boxLabel: locale['preferences[27]']
,value: config.sendStatistics
}
]
}
];

2
app/view/preferences/PreferencesController.js

@ -55,7 +55,7 @@ Ext.define('Rambox.view.preferences.PreferencesController', {
// Locale
if ( values.locale !== ipc.sendSync('getConfig').locale ) {
localStorage.setItem('locale', values.locale);
localStorage.setItem('locale-auth0', me.getView().down('form').down('combo[name="locale"]').getSelection().get('auth0'));
localStorage.setItem('locale-extjs', me.getView().down('form').down('combo[name="locale"]').getSelection().get('extjs'));
Ext.Msg.confirm('Action required', 'To change the language of Rambox, you need to reload the app. Do you want to do it now?', function(btnId) {
if ( btnId === 'yes' ) ipc.send('relaunchApp');
});

7
appveyor.yml

@ -1,6 +1,6 @@
environment:
matrix:
- nodejs_version: '8'
- nodejs_version: '14.16.1'
pull_requests:
do_not_increment_build_number: true
branches:
@ -12,16 +12,13 @@ init:
- cmd: node --version
- cmd: npm --version
install:
- ps: Install-Product node $env:nodejs_version
- ps: Update-NodeJsInstallation $env:nodejs_version x64
- cmd: >-
git clone https://github.com/saenzramiro/rambox-build.git %APPVEYOR_BUILD_FOLDER%\build\production\Rambox\
cd %APPVEYOR_BUILD_FOLDER%\build\production\Rambox\
npm install
cache:
- '%APPDATA%\npm-cache'
- '%USERPROFILE%\.electron'
build_script:
- cmd: cd %APPVEYOR_BUILD_FOLDER%\build\production\Rambox\
- cmd: npm run build:win

277
electron/main.js

@ -1,6 +1,6 @@
'use strict';
const {app, protocol, BrowserWindow, dialog, shell, Menu, ipcMain, nativeImage, session} = require('electron');
const {app, BrowserWindow, shell, Menu, ipcMain, nativeImage, session} = require('electron');
// Tray
const tray = require('./tray');
// AutoLaunch
@ -15,6 +15,9 @@ const updater = require('./updater');
var fs = require("fs");
const path = require('path');
// Disk usage:
// const disk = require('diskusage');
if ( isDev ) app.getVersion = function() { return require('../package.json').version; }; // FOR DEV ONLY, BECAUSE IN DEV RETURNS ELECTRON'S VERSION
// Initial Config
@ -23,6 +26,7 @@ const config = new Config({
always_on_top: false
,hide_menu_bar: false
,tabbar_location: 'top'
,hide_tabbar_labels: false
,window_display_behavior: 'taskbar_tray'
,auto_launch: !isDev
,flash_frame: true
@ -57,6 +61,12 @@ if (config.get('enable_hidpi_support') && (process.platform === 'win32')) {
app.commandLine.appendSwitch('force-device-scale-factor', '1')
}
app.commandLine.appendSwitch('lang', config.get('locale') === 'en' ? 'en-US' : config.get('locale'));
// Temporary fix to load Twitter and other websites inside webviews
// Bug related with Electron: https://github.com/electron/electron/issues/25469
app.commandLine.appendSwitch('disable-features', 'CrossOriginOpenerPolicy');
// Because we build it using Squirrel, it will assign UserModelId automatically, so we match it here to display notifications correctly.
// https://github.com/electron-userland/electron-builder/issues/362
app.setAppUserModelId('com.grupovrs.ramboxce');
@ -65,11 +75,14 @@ app.setAppUserModelId('com.grupovrs.ramboxce');
const appMenu = require('./menu')(config);
// Configure AutoLaunch
const appLauncher = new AutoLaunch({
name: 'Rambox'
,isHidden: config.get('start_minimized')
});
config.get('auto_launch') && !isDev ? appLauncher.enable() : appLauncher.disable();
let appLauncher;
if ( !isDev ) {
appLauncher = new AutoLaunch({
name: 'Rambox'
,isHidden: config.get('start_minimized')
});
config.get('auto_launch') ? appLauncher.enable() : appLauncher.disable();
}
// Keep a global reference of the window object, if you don't, the window will
// be closed automatically when the JavaScript object is garbage collected.
@ -92,22 +105,22 @@ function createWindow () {
,show: !config.get('start_minimized')
,acceptFirstMouse: true
,webPreferences: {
plugins: true
enableRemoteModule: true
,plugins: true
,partition: 'persist:rambox'
,nodeIntegration: true
,webviewTag: true
,contextIsolation: false
,spellcheck: false
}
});
// Check if user has defined a custom User-Agent
if ( config.get('user_agent').length > 0 ) mainWindow.webContents.setUserAgent( config.get('user_agent') );
if ( !config.get('start_minimized') && config.get('maximized') ) mainWindow.maximize();
if ( config.get('window_display_behavior') !== 'show_trayIcon' && config.get('start_minimized') ) {
// Wait for the mainWindow.loadURL(..) and the optional mainWindow.webContents.openDevTools()
// to be finished before minimizing
mainWindow.webContents.once('did-finish-load', function(e) {
mainWindow.minimize();
});
}
// Wait for the mainWindow.loadURL(..) and the optional mainWindow.webContents.openDevTools()
// to be finished before minimizing
config.get('start_minimized') && mainWindow.webContents.once('did-finish-load', () => config.get('window_display_behavior') === 'show_trayIcon' ? mainWindow.hide() : mainWindow.minimize());
// Check if the window its outside of the view (ex: multi monitor setup)
const { positionOnScreen } = require('./utils/positionOnScreen');
@ -130,7 +143,7 @@ function createWindow () {
tray.create(mainWindow, config);
if ( process.argv.indexOf('--without-update') === -1 ) updater.initialize(mainWindow);
updater.initialize(mainWindow);
// Open links in default browser
mainWindow.webContents.on('new-window', function(e, url, frameName, disposition, options) {
@ -199,6 +212,15 @@ function createWindow () {
}
}
});
mainWindow.on('minimize', function(e) {
if ( config.get('window_display_behavior') === 'show_trayIcon' ) mainWindow.setSkipTaskbar(true);
});
mainWindow.on('restore', function(e) {
if ( config.get('window_display_behavior') === 'show_taskbar' ) mainWindow.setSkipTaskbar(false);
});
mainWindow.on('show', function(e) {
if ( config.get('window_display_behavior') !== 'show_trayIcon' ) mainWindow.setSkipTaskbar(false);
});
mainWindow.on('closed', function(e) {
mainWindow = null;
});
@ -210,6 +232,10 @@ function createMasterPasswordWindow() {
mainMasterPasswordWindow = new BrowserWindow({
backgroundColor: '#0675A0'
,frame: false
,webPreferences: {
nodeIntegration: true
,enableRemoteModule: true
}
});
// Open the DevTools.
if ( isDev ) mainMasterPasswordWindow.webContents.openDevTools();
@ -235,6 +261,40 @@ function updateBadge(title) {
if ( messageCount > 0 && !mainWindow.isFocused() && !config.get('dont_disturb') && config.get('flash_frame') ) mainWindow.flashFrame(true);
}
function formatBytes(bytes, decimals = 2) {
if (bytes === 0) return '0 Bytes';
const k = 1024;
const dm = decimals < 0 ? 0 : decimals;
const sizes = ['Bytes', 'KB', 'MB', 'GB', 'TB', 'PB', 'EB', 'ZB', 'YB'];
const i = Math.floor(Math.log(bytes) / Math.log(k));
return parseFloat((bytes / Math.pow(k, i)).toFixed(dm)) + ' ' + sizes[i];
}
/* async function availableSpaceWatchDog() {
// optionally render this information also in rambox window
try {
const { available } = await disk.check(appPath);
if (available < 1073741824) { // 1 GB
const options = {
type: 'warning',
buttons: ['OK, quit'],
defaultId: 0,
title: `Running out of disk space! - Rambox shutting down`,
detail: `You've got just ${formatBytes(available)} space left.\n\nRambox has been frozen to prevent settings corruption.\n\nOnce you quit this dialog, Rambox will shutdown.\n\n1 GB of avalable disk space is required.\nFree up space on partition where Rambox is installed then start the app again.\n\nRambox path: \n${appPath}`,
message: `Running out of disk space! - Rambox shutting down`,
};
dialog.showMessageBoxSync(null, options);
app.quit();
}
} catch (err) {
console.error(err)
}
} */
ipcMain.on('setBadge', function(event, messageCount, value) {
mainWindow.setOverlayIcon(nativeImage.createFromDataURL(value), messageCount.toString());
});
@ -242,7 +302,10 @@ ipcMain.on('setBadge', function(event, messageCount, value) {
ipcMain.on('getConfig', function(event, arg) {
event.returnValue = config.store;
});
ipcMain.on('sConfig', function(event, values) {
config.set(values);
event.returnValue = config;
});
ipcMain.on('setConfig', function(event, values) {
config.set(values);
@ -252,7 +315,7 @@ ipcMain.on('setConfig', function(event, values) {
// always_on_top
mainWindow.setAlwaysOnTop(values.always_on_top);
// auto_launch
values.auto_launch ? appLauncher.enable() : appLauncher.disable();
if ( !isDev ) values.auto_launch ? appLauncher.enable() : appLauncher.disable();
// systemtray_indicator
updateBadge(mainWindow.getTitle());
@ -291,6 +354,7 @@ ipcMain.on('validateMasterPassword', function(event, pass) {
// Handle Service Notifications
ipcMain.on('setServiceNotifications', function(event, partition, op) {
if ( partition === null ) return;
session.fromPartition(partition).setPermissionRequestHandler(function(webContents, permission, callback) {
if (permission === 'notifications') return callback(op);
callback(true)
@ -299,7 +363,7 @@ ipcMain.on('setServiceNotifications', function(event, partition, op) {
ipcMain.on('setDontDisturb', function(event, arg) {
config.set('dont_disturb', arg);
})
});
// Reload app
ipcMain.on('reloadApp', function(event) {
@ -312,22 +376,101 @@ ipcMain.on('relaunchApp', function(event) {
app.exit(0);
});
const shouldQuit = app.requestSingleInstanceLock()
const shouldQuit = app.requestSingleInstanceLock();
if (!shouldQuit) {
app.quit();
return;
}
app.on('second-instance', (event, commandLine, workingDirectory) => {
// Someone tried to run a second instance, we should focus our window.
if (mainWindow) {
if (mainWindow.isMinimized()) mainWindow.restore();
mainWindow.focus();
mainWindow.show();
mainWindow.setSkipTaskbar(false);
if (app.dock && app.dock.show) app.dock.show();
}
if (mainWindow) {
if (mainWindow.isMinimized()) mainWindow.restore();
mainWindow.focus();
mainWindow.show();
mainWindow.setSkipTaskbar(false);
if (app.dock && app.dock.show) app.dock.show();
}
});
// ALLOWED URLS POPUPS
let allowPopUp = [
'feedly.com/v3/auth/',
'identity.linuxfoundation.org/cas/login',
'auth.missiveapp.com',
'accounts.google.com/AccountChooser',
'facebook.com/v3.1/dialog/oauth?',
'accounts.google.com/o/oauth2',
'app.slack.com/files/import/gdrive',
'spikenow.com/s/account',
'app.mixmax.com/_oauth/google',
'officeapps.live.com',
'dropbox.com/profile_services/start_auth_flow',
'facebook.com/v3.2/dialog/oauth?',
'notion.so/googlepopupredirect',
'zoom.us/office365',
'figma.com/start_google_sso',
'mail.google.com/mail',
'app.slack.com/free-willy/',
'messenger.com/videocall',
'api.moo.do',
'manychat.com/fb?popup',
'=?print=true' // esta ultima checkea como anda imprimir un pedf desde gmail, si no va bie sacala
];
app.on('web-contents-created', (webContentsCreatedEvent, contents) => {
if (contents.getType() !== 'webview') return;
// Block some Deep links to prevent that open its app (Ex: Slack)
contents.on('will-navigate', (event, url) => url.substring(0, 8) === 'slack://' && event.preventDefault());
// New Window handler
contents.on('new-window', (event, url, frameName, disposition, options, additionalFeatures, referrer, postBody) => {
// If the url is about:blank we allow the window and handle it in 'did-create-window'
if (['about:blank', 'about:blank#blocked'].includes(url)) {
event.preventDefault();
Object.assign(options, { show: false });
const win = new BrowserWindow(options);
win.center();
let once = false;
win.webContents.on('will-navigate', (e, nextURL) => {
if (once) return;
if (['about:blank', 'about:blank#blocked'].includes(nextURL)) return;
once = true;
let allow = false;
allowPopUp.forEach(url => nextURL.indexOf(url) > -1 && (allow = true));
// If the url is in aboutBlankOnlyWindow we handle this as a popup window
if (allow) return win.show();
shell.openExternal(nextURL);
win.close()
})
event.newGuest = win;
return;
}
// We check if url is in the allowPopUpLoginURLs or allowForegroundTabURLs in Firebase to open a as a popup,
// if it is not we send this to the app
let allow = false;
allowPopUp.forEach(allowed => url.indexOf(allowed) > -1 && (allow = true));
if (allow) return;
shell.openExternal(url);
event.preventDefault();
});
contents.on('did-create-window', (win, details) => {
// Here we center the new window.
win.center();
// The following code is for handling the about:blank cases only.
if (!['about:blank', 'about:blank#blocked'].includes(details.url)) return;
let once = false;
win.webContents.on('will-navigate', (e, nextURL) => {
if (once) return;
if (['about:blank', 'about:blank#blocked'].includes(nextURL)) return;
once = true;
let allow = false;
allowPopUp.forEach(url => nextURL.indexOf(url) > -1 && (allow = true));
// If the url is in aboutBlankOnlyWindow we handle this as a popup window
if (allow) return win.show();
shell.openExternal(url);
win.close();
});
});
});
// Code for downloading images as temporal files
// Credit: Ghetto Skype (https://github.com/stanfieldr/ghetto-skype)
@ -395,25 +538,91 @@ ipcMain.on('image:popup', function(event, url, partition) {
});
ipcMain.on('toggleWin', function(event, allwaysShow) {
if ( config.get('window_display_behavior') !== 'show_trayIcon' ) mainWindow.setSkipTaskbar(false);
if ( !mainWindow.isMinimized() && mainWindow.isMaximized() && mainWindow.isVisible() ) { // Maximized
!allwaysShow ? mainWindow.close() : mainWindow.show();
} else if ( mainWindow.isMinimized() && !mainWindow.isMaximized() && !mainWindow.isVisible() ) { // Minimized
if ( process.platform === 'linux' ) {
mainWindow.minimize();
mainWindow.restore();
mainWindow.focus();
return
}
mainWindow.restore();
} else if ( !mainWindow.isMinimized() && !mainWindow.isMaximized() && mainWindow.isVisible() ) { // Windowed mode
!allwaysShow ? mainWindow.close() : mainWindow.show();
} else if ( mainWindow.isMinimized() && !mainWindow.isMaximized() && mainWindow.isVisible() ) { // Closed to taskbar
if ( process.platform === 'linux' ) {
mainWindow.minimize();
mainWindow.restore();
mainWindow.focus();
return
}
mainWindow.restore();
} else if ( !mainWindow.isMinimized() && mainWindow.isMaximized() && !mainWindow.isVisible() ) { // Closed maximized to tray
mainWindow.show();
} else if ( !mainWindow.isMinimized() && !mainWindow.isMaximized() && !mainWindow.isVisible() ) { // Closed windowed to tray
mainWindow.show();
} else if ( mainWindow.isMinimized() && !mainWindow.isMaximized() && !mainWindow.isVisible() ) { // Closed minimized to tray
mainWindow.restore();
} else {
mainWindow.show();
} else {
if ( process.platform === 'linux' ) {
mainWindow.minimize();
mainWindow.maximize();
mainWindow.focus();
return
}
mainWindow.restore();
}
});
// ScreenShare
ipcMain.on('screenShare:show', (event, screenList) => {
let tmpWindow = new BrowserWindow({
title: 'Rambox - Select screen',
width: 600,
height: 500,
icon: __dirname + '/../resources/Icon.ico',
autoHideMenuBar: true,
transparent: true,
show: true,
frame: false,
hasShadow: true,
webPreferences: {
nodeIntegration: true,
contextIsolation: false,
},
});
const close = () => {
tmpWindow.close();
tmpWindow = null;
};
const onCancel = () => {
event.sender.send('screenShare:cancel');
close();
};
const onShare = (_, shareId) => {
event.sender.send('screenShare:share', shareId);
close();
};
ipcMain.handle('screenShare:getSources', () => screenList);
ipcMain.on('screenShare:cancelSelection', onCancel);
ipcMain.on('screenShare:selectScreen', onShare);
tmpWindow.on('closed', () => {
ipcMain.removeHandler('screenShare:getSources');
ipcMain.removeAllListeners('screenShare:cancelSelection');
ipcMain.removeAllListeners('screenShare:selectScreen');
});
tmpWindow.loadFile(__dirname + '/../screenselector.html');
});
// Proxy
if ( config.get('proxy') ) {
app.commandLine.appendSwitch('proxy-server', config.get('proxyHost')+':'+config.get('proxyPort'));
@ -421,7 +630,7 @@ if ( config.get('proxy') ) {
if(!authInfo.isProxy)
return;
event.preventDefault()
event.preventDefault();
callback(config.get('proxyLogin'), config.get('proxyPassword'))
})
}
@ -436,8 +645,8 @@ if ( config.get('disable_gpu') ) app.disableHardwareAcceleration();
// initialization and is ready to create browser windows.
app.on('ready', function() {
config.get('master_password') ? createMasterPasswordWindow() : createWindow();
// setInterval(availableSpaceWatchDog, 1000 * 60);
});
// Quit when all windows are closed.
app.on('window-all-closed', function () {
// On OS X it is common for applications and their menu bar
@ -454,7 +663,9 @@ app.on('activate', function () {
config.get('master_password') ? createMasterPasswordWindow() : createWindow();
}
if ( mainWindow !== null ) mainWindow.show();
if (mainWindow) {
mainWindow.show();
}
});
app.on('before-quit', function () {

74
electron/menu.js

@ -1,6 +1,7 @@
'use strict';
const os = require('os');
const electron = require('electron');
const { systemPreferences } = require('electron')
const app = electron.app;
const BrowserWindow = electron.BrowserWindow;
const shell = electron.shell;
@ -22,7 +23,7 @@ module.exports = function(config) {
{
label: `&`+locale['menu.help[0]'],
click() {
shell.openExternal('https://rambox.pro');
shell.openExternal('https://rambox.app');
}
},
{
@ -46,38 +47,18 @@ module.exports = function(config) {
{
type: 'separator'
},
{
label: '&'+locale['menu.help[1]'],
click() {
const body = `
<!-- Please describe here your issue and steps to reproduce it. -->
<!-- DON'T REMOVE THE FOLLOWING LINES -->
-
> ${app.getName()} ${app.getVersion()}
> Electron ${process.versions.electron}
> ${process.platform} ${process.arch} ${os.release()}`;
shell.openExternal(`https://github.com/ramboxapp/community-edition/issues/new?body=${encodeURIComponent(body)}`);
}
},
{
label: `&`+locale['menu.help[2]'],
click() {
shell.openExternal('https://rambox.typeform.com/to/t7jc4C');
}
},
{
label: `&Tools`,
submenu: [
{
label: `&Clear Cache`,
click(item, win) {
win.webContents.session.clearCache(function() {
win.webContents.session.clearCache()
.then(() => {
win.reload();
});
}).catch(err => {
console.log(err)
})
}
},
{
@ -85,22 +66,15 @@ module.exports = function(config) {
click(item, win) {
win.webContents.session.clearStorageData({
storages: ['localstorage']
}, function() {
}).then(() => {
win.reload();
});
}).catch(err => {
console.log(err)
})
}
}
]
},
{
type: 'separator'
},
{
label: `&`+locale['menu.help[3]'],
click() {
shell.openExternal('https://rambox.pro/#donate');
}
}
];
let tpl = [
@ -172,13 +146,19 @@ module.exports = function(config) {
type: 'separator'
},
{
role: 'zoomin'
label: 'Zoom In',
accelerator: 'Ctrl+Plus',
click(item, win) { win.webContents.send('zoomin-webview')}
},
{
role: 'zoomout'
label: 'Zoom Out',
accelerator: 'Ctrl+-',
click(item, win) { win.webContents.send('zoomout-webview')}
},
{
role: 'resetzoom'
label: 'Reset Zoom',
accelerator: 'Ctrl+0',
click(item, win) { win.webContents.send('resetzoom-webview')}
}
]
},
@ -218,7 +198,7 @@ module.exports = function(config) {
}
];
if (process.platform === 'darwin') {
if ( process.platform === 'darwin' ) {
tpl.unshift({
label: appName,
submenu: [
@ -277,6 +257,18 @@ module.exports = function(config) {
}
]
});
helpSubmenu.push({
type: 'separator'
});
helpSubmenu.push({
label: 'Grant Microphone and Camera permissions',
visible: systemPreferences.getMediaAccessStatus('microphone') !== 'granted' || systemPreferences.getMediaAccessStatus('camera') !== 'granted',
click(item, win) {
const webContents = win.webContents;
const send = webContents.send.bind(win.webContents);
send('grantPermissions');
}
});
} else {
tpl.unshift({
label: '&'+locale['menu.file[0]'],

4
electron/tray.js

@ -44,12 +44,12 @@ exports.create = function(win, config) {
// Double click is not supported and Click its only supported when app indicator is not used.
// Read more here (Platform limitations): https://github.com/electron/electron/blob/master/docs/api/tray.md
appIcon.on('click', function() {
win.webContents.executeJavaScript('ipc.send("toggleWin", true);');
win.webContents.executeJavaScript('ipc.send("toggleWin", false);');
});
break;
case 'win32':
appIcon.on('double-click', function() {
win.webContents.executeJavaScript('ipc.send("toggleWin", true);');
win.webContents.executeJavaScript('ipc.send("toggleWin", false);');
});
break;
default:

18
electron/updater.js

@ -1,18 +1,28 @@
const {app, ipcMain} = require('electron');
const { app, ipcMain, BrowserWindow } = require('electron');
const { autoUpdater } = require("electron-updater");
const path = require('path');
// autoUpdater.logger = require("electron-log");
// autoUpdater.logger.transports.file.level = "debug";
// autoUpdater.currentVersion = '0.6.0';
// autoUpdater.currentVersion = '0.8.0';
// autoUpdater.updateConfigPath = path.join(__dirname, 'dev-app-update.yml');
autoUpdater.setFeedURL({
"provider": "github",
"owner": "ramboxapp",
"repo": "download",
"vPrefixedTagName": true
});
const initialize = (window) => {
const webContents = window.webContents;
const send = webContents.send.bind(window.webContents);
autoUpdater.on('checking-for-update', (event) => send('autoUpdater:checking-for-update'));
autoUpdater.on('update-downloaded', (...args) => send('autoUpdater:update-downloaded', ...args));
ipcMain.on('autoUpdater:quit-and-install', (event) => autoUpdater.quitAndInstall());
ipcMain.on('autoUpdater:quit-and-install', (event) => {
app.removeAllListeners('window-all-closed');
BrowserWindow.getAllWindows().forEach((browserWindow) => browserWindow.removeAllListeners('close'));
autoUpdater.quitAndInstall(true, true);
});
ipcMain.on('autoUpdater:check-for-updates', (event) => autoUpdater.checkForUpdates());
};

5
env-sample.js

@ -1,5 +0,0 @@
var auth0Cfg = {
clientID: ''
,clientSecret: ''
,domain: ''
};

67
index.html

@ -1,5 +1,6 @@
<!DOCTYPE HTML>
<html>
<head>
<meta http-equiv="X-UA-Compatible" content="IE=edge">
<meta charset="UTF-8">
@ -7,36 +8,12 @@
<title>Rambox</title>
<script type='text/javascript'>
var xhr = new XMLHttpRequest();
var file = "http://rambox.pro/api/latestversion.json";
var randomNum = Math.round(Math.random() * 10000);
xhr.open('HEAD', file + "?rand=" + randomNum, true);
xhr.send();
xhr.addEventListener("readystatechange", function() {
setTimeout(processRequest, 5000);
}, false);
function processRequest(e) {
if (xhr.readyState == 4) {
if (xhr.status >= 200 && xhr.status < 304) {
console.info('Internet Connection', true);
} else {
console.info('Internet Connection', false);
alert('Please, check your internet connection and restart Rambox. If you use a Proxy, please go to Preferences to configure it.', 'No Internet Connection');
}
}
}
</script>
<!-- The line below must be kept intact for Sencha Cmd to build your application -->
<script id="microloader" type="text/javascript" src="bootstrap.js"></script>
<!--- Localization -->
<script type='text/javascript'>
(function(d, s){
(function(d, s){
var t = d.createElement(s), e = d.getElementsByTagName(s)[0];
t.type = "text/javascript"; e.parentNode.insertBefore(t, e);
t.src = "resources/languages/"+require('electron').ipcRenderer.sendSync('getConfig').locale+".js";
@ -46,23 +23,24 @@
<!--- Signalayer player -->
<script type='text/javascript'>
window.Signalayer||function(t,e){var o={
url:"https://cdn.signalayer.com/static/player.js",
key:"sEF8shc4KSuqtHMx0ztmTFdcrQO0cAVpszZ9Y8hLfQ2",
async:true
};window.Signalayer={cs:[],_apiKey:o.key};for(
var r=["identify","goal","updateUserData","start","stop","refresh","show","hide","on"],
i={},n=0;n>r.length;n++){var a=r[n];i[a]=function(t){return function(){var
e=Array.prototype.slice.call(arguments);
window.Signalayer.cs.push({method:t,args:e})}}(a)}window.Signalayer.API=i;var
n=t.createElement(e),s=t.getElementsByTagName(e)[0];
n.type="text/javascript",
n.async=o.async,s.parentNode.insertBefore(n,s),n.src=o.url}(document,"script");
window.Signalayer||function(t,e){var o={
url:"https://cdn.signalayer.com/static/player.js",
key:"sEF8shc4KSuqtHMx0ztmTFdcrQO0cAVpszZ9Y8hLfQ2",
async:true
};window.Signalayer={cs:[],_apiKey:o.key};for(
var r=["identify","goal","updateUserData","start","stop","refresh","show","hide","on"],
i={},n=0;n>r.length;n++){var a=r[n];i[a]=function(t){return function(){var
e=Array.prototype.slice.call(arguments);
window.Signalayer.cs.push({method:t,args:e})}}(a)}window.Signalayer.API=i;var
n=t.createElement(e),s=t.getElementsByTagName(e)[0];
n.type="text/javascript",
n.async=o.async,s.parentNode.insertBefore(n,s),n.src=o.url}(document,"script");
</script>
<!--- Signalayer player -->
</head>
<body>
<div id="spinner" class="component" data-path-start="M280,466c0,0.13-0.001,0.26-0.003,0.39c-0.002,0.134-0.004,0.266-0.007,0.396
<div id="spinner" class="component" style="z-index:999999;" data-path-start="M280,466c0,0.13-0.001,0.26-0.003,0.39c-0.002,0.134-0.004,0.266-0.007,0.396
C279.572,482.992,266.307,496,250,496h-2.125H51.625H50c-16.316,0-29.592-13.029-29.99-29.249c-0.003-0.13-0.006-0.261-0.007-0.393
C20.001,466.239,20,466.119,20,466l0,0c0-0.141,0.001-0.281,0.003-0.422C20.228,449.206,33.573,436,50,436h1.625h196.25H250
c16.438,0,29.787,13.222,29.997,29.608C279.999,465.738,280,465.869,280,466L280,466z" data-path-listen="M181,466c0,0.13-0.001,0.26-0.003,0.39c-0.002,0.134-0.004,0.266-0.007,0.396
@ -71,5 +49,18 @@ C120.001,466.239,120,466.119,120,466l0,0c0-0.141,0.001-0.281,0.003-0.422C120.228
c16.438,0,29.787,13.222,29.997,29.608C180.999,465.738,181,465.869,181,466L181,466z" data-path-player="M290,40c0,0.13-0.001,380.26-0.003,380.39c-0.002,0.134,0.006,24.479,0.003,24.609 c0,3.095-2.562,5.001-5,5.001h-27.125H41.625H15c-1.875,0-5-1.25-5-5.001c-0.003-0.13,0.004-24.509,0.003-24.641 C10.001,420.239,10,40.119,10,40l0,0c0-0.141-0.002-24.859,0-25c0,0,0-5,5-5h26.625h216.25H285c2.438,0,5,1.906,5,5 C290.002,15.13,290,39.869,290,40L290,40z">
<div class="button button--start uil-ring-css" style="transform:scale(1);"><div></div></div>
</div>
<div id="background" style="height: 100%; width: 100%; background-color: #0675A0; position: absolute; z-index:99999; top: 0;">
</div>
</body>
<!-- Fixes visibility issues with some apps that only update the badges while visible -->
<style>
.x-hidden-offsets {
visibility: visible!important;
position: absolute!important;
z-index: -10!important;
top: 0!important;
}
</style>
</html>

20
masterpassword.html

@ -9,15 +9,31 @@
<body>
<div style="background-image: url(resources/Icon.png);background-size:200px;width:200px;height:200px;position:relative;left:50%;margin-left:-100px;margin-top:100px;"></div>
<div style="color:#FFF;text-align:center;font-size:20px;font-family:Verdana;margin:30px 0;">Master Password</div>
<div style="text-align:center;margin:30px 0;"><input type="password" autofocus placeholder="Enter your password..." onkeyup="doValidate(event, this.value)" style="text-align:center;font-size:20px;font-family:Verdana;padding:10px;border: 0;" /><button onclick="onButtonClick()" style="height:44px;border:0;width:44px;position:relative;top:2px;font-size:30px;background-color:#053767;color:white;">&raquo;</button></div>
<div style="text-align:center;margin:30px 0;"><input type="password" autofocus placeholder="Enter your password..." onpaste="handlePaste(event)" onkeyup="doValidate(event, this.value)" style="text-align:center;font-size:20px;font-family:Verdana;padding:10px;border: 0;" /><button onclick="onButtonClick()" style="height:44px;border:0;width:44px;position:relative;top:2px;font-size:30px;background-color:#053767;color:white;">&raquo;</button></div>
<div id='wrong-pass' style="color:crimson;text-align:center;font-size:20px;font-family:Verdana;margin:30px 0;visibility:hidden;">The password is incorrect. Try again...</div>
<div style="text-align:center;margin-top:60px;"><a href="#" onclick="exit()" style="text-decoration:none;color:#4e9dbb;font-family:Arial;">Exit Rambox</a></div>
<script>
function handlePaste(e) {
var clipboardData, pastedData;
// Stop data actually being pasted into div
e.stopPropagation();
e.preventDefault();
// Get pasted data via clipboard API
clipboardData = e.clipboardData || window.clipboardData;
pastedData = clipboardData.getData('Text');
document.getElementsByTagName('input')[0].value += pastedData
// Do whatever with pasteddata
}
function doValidate(e, value) {
document.getElementById('wrong-pass').style.visibility = 'hidden'
if (e.keyCode == 13) {
const { ipcRenderer } = require('electron');
if ( !ipcRenderer.sendSync('validateMasterPassword', value) ) {
alert('The password is incorrect. Try again...');
document.getElementsByTagName("input")[0].value = "";
document.getElementById('wrong-pass').style.visibility = 'visible'
}
}
}

5465
package-lock.json generated

File diff suppressed because it is too large Load Diff

114
package.json

@ -1,7 +1,7 @@
{
"name": "Rambox",
"productName": "Rambox",
"version": "0.6.4",
"version": "0.8.0",
"description": "Free and Open Source messaging and emailing app that combines common web applications into one.",
"main": "electron/main.js",
"repository": {
@ -11,7 +11,7 @@
"bugs": {
"url": "https://github.com/ramboxapp/community-edition/issues"
},
"homepage": "https://rambox.pro",
"homepage": "https://rambox.app",
"keywords": [
"Rambox",
"messaging",
@ -25,7 +25,7 @@
"hangouts",
"skype"
],
"author": "Rambox <support@rambox.pro>",
"author": "Rambox LLC <support@rambox.app>",
"license": "GPL-3.0",
"scripts": {
"start": "electron electron/main.js",
@ -39,7 +39,9 @@
"clean:osx": "rm -rf ./dist/Rambox-darwin-*",
"clean:win": "rm -rf ./dist/Rambox-win32-*",
"pack": "npm run pack:osx && npm run pack:win",
"pack:osx": "electron-packager \"./build/production/Rambox/\" \"Rambox\" --out=dist --platform=darwin --arch=x64 --icon=resources/installer/Icon.icns --app-version=0.2.0 --build-version=64-bit --version-string.CompanyName=\"Rambox\" --version-string.ProductName=\"Rambox\" --asar --prune --overwrite",
"pack:osx": "npm run pack:osx64 && npm run pack:osxarm64",
"pack:osx64": "electron-packager \"./build/production/Rambox/\" \"Rambox\" --out=dist --platform=darwin --arch=x64 --icon=resources/installer/Icon.icns --app-version=0.2.0 --build-version=64-bit --version-string.CompanyName=\"Rambox\" --version-string.ProductName=\"Rambox\" --asar --prune --overwrite",
"pack:osxarm64": "electron-packager \"./build/production/Rambox/\" \"Rambox\" --out=dist --platform=darwin --arch=arm64 --icon=resources/installer/Icon.icns --app-version=0.2.0 --build-version=64-bit --version-string.CompanyName=\"Rambox\" --version-string.ProductName=\"Rambox\" --asar --prune --overwrite",
"pack:win": "npm run pack:win32 && npm run pack:win64",
"pack:win32": "electron-packager \"./build/production/Rambox/\" \"Rambox\" --out=dist --platform=win32 --arch=ia32 --icon=resources/installer/Icon.ico --app-version=0.2.0 --build-version=32-bit --version-string.CompanyName=\"Rambox\" --version-string.ProductName=\"Rambox\" --asar --prune --overwrite",
"pack:win64": "electron-packager \"./build/production/Rambox/\" \"Rambox\" --out=dist --platform=win32 --arch=x64 --icon=resources/installer/Icon.ico --app-version=0.2.0 --build-version=64-bit --version-string.CompanyName=\"Rambox\" --version-string.ProductName=\"Rambox\" --asar --prune --overwrite",
@ -47,14 +49,16 @@
"pack:linux32": "electron-packager \"./build/production/Rambox/\" \"Rambox\" --out=dist --platform=linux --arch=ia32 --icon=resources/installer/Icon.ico --app-version=0.2.0 --build-version=64-bit --version-string.CompanyName=\"Rambox\" --version-string.ProductName=\"Rambox\" --asar --prune --overwrite",
"pack:linux64": "electron-packager \"./build/production/Rambox/\" \"Rambox\" --out=dist --platform=linux --arch=x64 --icon=resources/installer/Icon.ico --app-version=0.2.0 --build-version=64-bit --version-string.CompanyName=\"Rambox\" --version-string.ProductName=\"Rambox\" --asar --prune --overwrite",
"build": "npm run build:linux && npm run build:osx && npm run build:win",
"build:osx": "build --macos",
"build:linux": "build --linux --publish=onTagOrDraft",
"build:linux32": "build --linux --ia32 --publish=onTagOrDraft",
"build:linux64": "build --linux --x64 --publish=onTagOrDraft",
"build:win": "build --win --ia32 --x64",
"build:win32": "build --win --ia32",
"build:win64": "build --win --x64",
"setup:osx": "npm run sencha:clean && npm run sencha:compile && npm run clean:osx && npm run pack:osx && npm run build:osx",
"build:osx": "electron-builder --macos --universal",
"build:osx64": "electron-builder --macos --x64",
"build:osxarm64": "electron-builder --macos --arm64",
"build:linux": "electron-builder --linux --publish=onTagOrDraft",
"build:linux32": "electron-builder --linux --ia32 --publish=onTagOrDraft",
"build:linux64": "electron-builder --linux --x64 --publish=onTagOrDraft",
"build:win": "electron-builder --win --ia32 --x64",
"build:win32": "electron-builder --win --ia32",
"build:win64": "electron-builder --win --x64",
"setup:osx": "npm run sencha:clean && npm run sencha:compile && npm run clean:osx && npm run pack:osx && npm run build:osx && npm run build:osx64 && npm run build:osxarm64",
"setup:win": "npm run sencha:clean && npm run sencha:compile && npm run clean:win && npm run pack:win && npm run build:win",
"all:win": "npm run sencha:clean && npm run sencha:compile && npm run clean:win && npm run pack:win && npm run zip:win32 && npm run zip:win64 && npm run build:win",
"all:linux": "npm run sencha:clean && npm run sencha:compile && npm run build:linux",
@ -64,17 +68,36 @@
"build": {
"productName": "Rambox",
"appId": "com.grupovrs.ramboxce",
"afterSign": "resources/installer/notarize.js",
"asar": true,
"electronVersion": "13.6.3",
"electronDownload": {
"version": "13.6.3"
},
"mac": {
"category": "public.app-category.productivity",
"artifactName": "Rambox-${version}-mac.${ext}",
"artifactName": "Rambox-${version}-mac-${arch}.${ext}",
"target": [
"default"
]
{
"target": "default",
"arch": [
"universal"
]
}
],
"hardenedRuntime": true,
"gatekeeperAssess": false,
"entitlements": "resources/installer/entitlements.mac.plist",
"entitlementsInherit": "resources/installer/entitlements.mac.plist",
"extendInfo": {
"NSMicrophoneUsageDescription": "Apps inside Rambox CE may need access to your microphone. Please, grant access to have a better experience.",
"NSCameraUsageDescription": "Apps inside Rambox CE may need access to your camera. Please, grant access to have a better experience."
}
},
"dmg": {
"title": "Rambox",
"iconSize": 128,
"sign": false,
"contents": [
{
"x": 355,
@ -90,7 +113,7 @@
]
},
"win": {
"publisherName": "Ramiro Pablo Saenz",
"publisherName": "Rambox LLC",
"artifactName": "Rambox-${version}-win-${arch}.${ext}",
"target": [
"nsis",
@ -103,7 +126,25 @@
"perMachine": false,
"runAfterFinish": true
},
"snap": {
"publish": [
{
"provider": "github"
}
],
"plugs": [
"default",
"camera",
"audio-record",
"audio-playback",
"removable-media",
"raw-usb",
"u2f-devices",
"cups-control"
]
},
"linux": {
"icon": "resources/installer/icons",
"category": "Network",
"desktop": {
"Terminal": "false",
@ -111,6 +152,9 @@
"Categories": "GTK;GNOME;Network;Email;Chat;InstantMessaging;"
},
"artifactName": "Rambox-${version}-linux-${arch}.${ext}",
"executableArgs": [
"--no-sandbox"
],
"target": [
{
"target": "snap",
@ -169,31 +213,35 @@
]
},
"devDependencies": {
"asar": "^0.12.4",
"asar": "0.12.4",
"chai": "3.5.0",
"crowdin": "1.0.0",
"csvjson": "4.3.3",
"electron": "^3.1.4",
"electron-builder": "^20.28.3",
"electron-packager": "^12.1.0",
"mocha": "^5.2.0",
"spectron": "^3.8.0"
"electron": "13.6.3",
"electron-builder": "22.14.13",
"electron-notarize": "1.0.0",
"electron-packager": "15.1.0",
"mocha": "5.2.0",
"spectron": "^15.0.0"
},
"dependencies": {
"@exponent/electron-cookies": "2.0.0",
"auth0-js": "^9.7.3",
"auto-launch-patched": "5.0.2",
"crypto": "^1.0.1",
"electron-context-menu": "0.9.1",
"electron-is-dev": "^0.3.0",
"electron-log": "^2.2.17",
"electron-store": "^2.0.0",
"electron-updater": "^3.1.2",
"keycodes": "^1.0.0",
"mime": "^2.3.1",
"request": "^2.88.0",
"request-promise": "^4.2.2",
"crypto": "1.0.1",
"electron-contextmenu-wrapper": "git+https://github.com/ramboxapp/electron-contextmenu-wrapper.git",
"electron-is-dev": "1.2.0",
"electron-log": "4.3.0",
"electron-store": "6.0.1",
"electron-updater": "4.5.2",
"is-online": "8.2.0",
"mime": "2.3.1",
"mousetrap": "1.6.3",
"request": "2.88.0",
"request-promise": "4.2.2",
"rimraf": "2.6.1",
"tmp": "0.0.28"
},
"volta": {
"node": "14.16.1"
}
}

12
packages/local/rambox-default-theme/sass/etc/all.scss

@ -272,3 +272,15 @@ body {
color: #FFF !important;
}
}
.x-tab-bar-default.dontdisturb {
background-color: #c3c3c3 !important;
.x-tab {
background-color: #c3c3c3;
}
}
.deprecation {
background-color: #E6A23C !important;
color: #FFF;
}

BIN
resources/auth0.png

Binary file not shown.

Before

Width:  |  Height:  |  Size: 45 KiB

BIN
resources/icons/airdroid.png

Binary file not shown.

After

Width:  |  Height:  |  Size: 2.7 KiB

BIN
resources/icons/allo.png

Binary file not shown.

Before

Width:  |  Height:  |  Size: 8.6 KiB

BIN
resources/icons/amium.png

Binary file not shown.

Before

Width:  |  Height:  |  Size: 49 KiB

BIN
resources/icons/androidmessages.png

Binary file not shown.

Before

Width:  |  Height:  |  Size: 27 KiB

After

Width:  |  Height:  |  Size: 62 KiB

BIN
resources/icons/aol.png

Binary file not shown.

Before

Width:  |  Height:  |  Size: 20 KiB

After

Width:  |  Height:  |  Size: 2.2 KiB

BIN
resources/icons/awsworkmail.png

Binary file not shown.

After

Width:  |  Height:  |  Size: 6.9 KiB

BIN
resources/icons/bearychat.png

Binary file not shown.

Before

Width:  |  Height:  |  Size: 70 KiB

After

Width:  |  Height:  |  Size: 4.6 KiB

BIN
resources/icons/bip.png

Binary file not shown.

After

Width:  |  Height:  |  Size: 9.7 KiB

BIN
resources/icons/calendar.png

Binary file not shown.

After

Width:  |  Height:  |  Size: 4.0 KiB

BIN
resources/icons/cliq.png

Binary file not shown.

After

Width:  |  Height:  |  Size: 3.9 KiB

BIN
resources/icons/clocktweets.png

Binary file not shown.

Before

Width:  |  Height:  |  Size: 18 KiB

BIN
resources/icons/converse.png

Binary file not shown.

After

Width:  |  Height:  |  Size: 2.9 KiB

BIN
resources/icons/crisp.png

Binary file not shown.

Before

Width:  |  Height:  |  Size: 68 KiB

After

Width:  |  Height:  |  Size: 2.3 KiB

BIN
resources/icons/dasher.png

Binary file not shown.

Before

Width:  |  Height:  |  Size: 52 KiB

BIN
resources/icons/dingtalk.png

Binary file not shown.

Before

Width:  |  Height:  |  Size: 56 KiB

After

Width:  |  Height:  |  Size: 3.4 KiB

BIN
resources/icons/discord.png

Binary file not shown.

Before

Width:  |  Height:  |  Size: 4.9 KiB

After

Width:  |  Height:  |  Size: 2.2 KiB

BIN
resources/icons/drift.png

Binary file not shown.

Before

Width:  |  Height:  |  Size: 52 KiB

After

Width:  |  Height:  |  Size: 2.2 KiB

BIN
resources/icons/duo.png

Binary file not shown.

After

Width:  |  Height:  |  Size: 2.4 KiB

BIN
resources/icons/element.png

Binary file not shown.

After

Width:  |  Height:  |  Size: 2.3 KiB

BIN
resources/icons/facebook.png

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.6 KiB

BIN
resources/icons/fastmail.png

Binary file not shown.

Before

Width:  |  Height:  |  Size: 53 KiB

After

Width:  |  Height:  |  Size: 2.1 KiB

BIN
resources/icons/fleep.png

Binary file not shown.

Before

Width:  |  Height:  |  Size: 48 KiB

After

Width:  |  Height:  |  Size: 1.1 KiB

BIN
resources/icons/flock.png

Binary file not shown.

Before

Width:  |  Height:  |  Size: 47 KiB

After

Width:  |  Height:  |  Size: 1.2 KiB

BIN
resources/icons/freenode.png

Binary file not shown.

Before

Width:  |  Height:  |  Size: 56 KiB

After

Width:  |  Height:  |  Size: 2.8 KiB

BIN
resources/icons/glip.png

Binary file not shown.

Before

Width:  |  Height:  |  Size: 48 KiB

After

Width:  |  Height:  |  Size: 1.1 KiB

BIN
resources/icons/glowingbear.png

Binary file not shown.

After

Width:  |  Height:  |  Size: 6.3 KiB

BIN
resources/icons/gmail.png

Binary file not shown.

Before

Width:  |  Height:  |  Size: 9.3 KiB

After

Width:  |  Height:  |  Size: 3.1 KiB

BIN
resources/icons/googledrive.png

Binary file not shown.

After

Width:  |  Height:  |  Size: 4.6 KiB

BIN
resources/icons/googlevoice.png

Binary file not shown.

Before

Width:  |  Height:  |  Size: 57 KiB

After

Width:  |  Height:  |  Size: 4.7 KiB

BIN
resources/icons/grape.png

Binary file not shown.

Before

Width:  |  Height:  |  Size: 61 KiB

After

Width:  |  Height:  |  Size: 4.1 KiB

BIN
resources/icons/guilded.png

Binary file not shown.

After

Width:  |  Height:  |  Size: 3.7 KiB

BIN
resources/icons/hangoutschat.png

Binary file not shown.

Before

Width:  |  Height:  |  Size: 15 KiB

After

Width:  |  Height:  |  Size: 700 B

BIN
resources/icons/hibox.png

Binary file not shown.

Before

Width:  |  Height:  |  Size: 64 KiB

After

Width:  |  Height:  |  Size: 4.3 KiB

BIN
resources/icons/hipchat.png

Binary file not shown.

Before

Width:  |  Height:  |  Size: 8.3 KiB

BIN
resources/icons/honeypot.png

Binary file not shown.

After

Width:  |  Height:  |  Size: 6.6 KiB

BIN
resources/icons/hootsuite.png

Binary file not shown.

Before

Width:  |  Height:  |  Size: 51 KiB

After

Width:  |  Height:  |  Size: 2.0 KiB

BIN
resources/icons/horde.png

Binary file not shown.

Before

Width:  |  Height:  |  Size: 57 KiB

After

Width:  |  Height:  |  Size: 3.3 KiB

BIN
resources/icons/hushmail.png

Binary file not shown.

Before

Width:  |  Height:  |  Size: 13 KiB

After

Width:  |  Height:  |  Size: 5.1 KiB

BIN
resources/icons/icloud.png

Binary file not shown.

Before

Width:  |  Height:  |  Size: 64 KiB

BIN
resources/icons/icloudmail.png

Binary file not shown.

After

Width:  |  Height:  |  Size: 4.2 KiB

BIN
resources/icons/icq.png

Binary file not shown.

Before

Width:  |  Height:  |  Size: 18 KiB

After

Width:  |  Height:  |  Size: 4.4 KiB

BIN
resources/icons/instagramdirect.png

Binary file not shown.

After

Width:  |  Height:  |  Size: 5.5 KiB

BIN
resources/icons/intercom.png

Binary file not shown.

Before

Width:  |  Height:  |  Size: 49 KiB

After

Width:  |  Height:  |  Size: 1.1 KiB

BIN
resources/icons/irccloud.png

Binary file not shown.

Before

Width:  |  Height:  |  Size: 48 KiB

After

Width:  |  Height:  |  Size: 1.2 KiB

BIN
resources/icons/jandi.png

Binary file not shown.

Before

Width:  |  Height:  |  Size: 52 KiB

After

Width:  |  Height:  |  Size: 2.5 KiB

BIN
resources/icons/kaiwa.png

Binary file not shown.

Before

Width:  |  Height:  |  Size: 51 KiB

After

Width:  |  Height:  |  Size: 2.2 KiB

BIN
resources/icons/kiwi.png

Binary file not shown.

Before

Width:  |  Height:  |  Size: 74 KiB

After

Width:  |  Height:  |  Size: 5.6 KiB

BIN
resources/icons/kune.png

Binary file not shown.

Before

Width:  |  Height:  |  Size: 30 KiB

After

Width:  |  Height:  |  Size: 9.1 KiB

BIN
resources/icons/linkedin.png

Binary file not shown.

Before

Width:  |  Height:  |  Size: 3.0 KiB

After

Width:  |  Height:  |  Size: 4.7 KiB

BIN
resources/icons/lounge.png

Binary file not shown.

Before

Width:  |  Height:  |  Size: 3.2 KiB

After

Width:  |  Height:  |  Size: 1.6 KiB

BIN
resources/icons/mailru.png

Binary file not shown.

Before

Width:  |  Height:  |  Size: 70 KiB

After

Width:  |  Height:  |  Size: 5.0 KiB

BIN
resources/icons/mastodon.png

Binary file not shown.

Before

Width:  |  Height:  |  Size: 25 KiB

After

Width:  |  Height:  |  Size: 16 KiB

BIN
resources/icons/mattermost.png

Binary file not shown.

Before

Width:  |  Height:  |  Size: 18 KiB

After

Width:  |  Height:  |  Size: 1.7 KiB

BIN
resources/icons/messenger.png

Binary file not shown.

Before

Width:  |  Height:  |  Size: 4.7 KiB

After

Width:  |  Height:  |  Size: 4.3 KiB

BIN
resources/icons/mightytext.png

Binary file not shown.

Before

Width:  |  Height:  |  Size: 56 KiB

After

Width:  |  Height:  |  Size: 3.3 KiB

BIN
resources/icons/missive.png

Binary file not shown.

Before

Width:  |  Height:  |  Size: 72 KiB

After

Width:  |  Height:  |  Size: 5.3 KiB

BIN
resources/icons/mmmelon.png

Binary file not shown.

Before

Width:  |  Height:  |  Size: 49 KiB

BIN
resources/icons/movim.png

Binary file not shown.

Before

Width:  |  Height:  |  Size: 62 KiB

After

Width:  |  Height:  |  Size: 4.2 KiB

BIN
resources/icons/noysi.png

Binary file not shown.

Before

Width:  |  Height:  |  Size: 58 KiB

After

Width:  |  Height:  |  Size: 1.8 KiB

BIN
resources/icons/office365.png

Binary file not shown.

Before

Width:  |  Height:  |  Size: 45 KiB

BIN
resources/icons/okru.png

Binary file not shown.

After

Width:  |  Height:  |  Size: 12 KiB

BIN
resources/icons/openmailbox.png

Binary file not shown.

Before

Width:  |  Height:  |  Size: 55 KiB

After

Width:  |  Height:  |  Size: 2.8 KiB

BIN
resources/icons/outlook.png

Binary file not shown.

Before

Width:  |  Height:  |  Size: 5.1 KiB

After

Width:  |  Height:  |  Size: 8.5 KiB

BIN
resources/icons/outlook365.png

Binary file not shown.

Before

Width:  |  Height:  |  Size: 7.2 KiB

After

Width:  |  Height:  |  Size: 8.5 KiB

BIN
resources/icons/protonmail.png

Binary file not shown.

Before

Width:  |  Height:  |  Size: 9.4 KiB

After

Width:  |  Height:  |  Size: 3.9 KiB

Some files were not shown because too many files have changed in this diff Show More

Loading…
Cancel
Save