diff options
-rw-r--r-- | all.json | 4 | ||||
-rw-r--r-- | docs/frontend_api.md | 16 | ||||
-rw-r--r-- | docs/integration.md | 48 | ||||
-rw-r--r-- | recipes/element/webview.js | 8 | ||||
-rw-r--r-- | recipes/telegram/package.json | 2 | ||||
-rw-r--r-- | recipes/telegram/webview.js | 23 | ||||
-rw-r--r-- | recipes/whatsapp/package.json | 2 | ||||
-rw-r--r-- | recipes/whatsapp/webview.js | 39 |
8 files changed, 108 insertions, 34 deletions
@@ -1593,7 +1593,7 @@ | |||
1593 | "featured": true, | 1593 | "featured": true, |
1594 | "id": "telegram", | 1594 | "id": "telegram", |
1595 | "name": "Telegram", | 1595 | "name": "Telegram", |
1596 | "version": "3.2.2", | 1596 | "version": "3.2.3", |
1597 | "icons": { | 1597 | "icons": { |
1598 | "svg": "https://cdn.jsdelivr.net/gh/getferdi/recipes/recipes/telegram/icon.svg" | 1598 | "svg": "https://cdn.jsdelivr.net/gh/getferdi/recipes/recipes/telegram/icon.svg" |
1599 | } | 1599 | } |
@@ -1809,7 +1809,7 @@ | |||
1809 | "featured": true, | 1809 | "featured": true, |
1810 | "id": "whatsapp", | 1810 | "id": "whatsapp", |
1811 | "name": "WhatsApp", | 1811 | "name": "WhatsApp", |
1812 | "version": "3.3.5", | 1812 | "version": "3.3.6", |
1813 | "icons": { | 1813 | "icons": { |
1814 | "svg": "https://cdn.jsdelivr.net/gh/getferdi/recipes/recipes/whatsapp/icon.svg" | 1814 | "svg": "https://cdn.jsdelivr.net/gh/getferdi/recipes/recipes/whatsapp/icon.svg" |
1815 | } | 1815 | } |
diff --git a/docs/frontend_api.md b/docs/frontend_api.md index aa1070b..bd0bfef 100644 --- a/docs/frontend_api.md +++ b/docs/frontend_api.md | |||
@@ -34,6 +34,22 @@ Ferdi.setBadge(4, 2); | |||
34 | Ferdi.setBadge(3); | 34 | Ferdi.setBadge(3); |
35 | ``` | 35 | ``` |
36 | 36 | ||
37 | ### setDialogTitle(title) | ||
38 | |||
39 | Sets the active dialog title to the app title | ||
40 | |||
41 | #### Arguments | ||
42 | |||
43 | 1. `string` title | ||
44 | |||
45 | - sets the active dialog title eg. WhatsApp contact name | ||
46 | |||
47 | #### Usage | ||
48 | |||
49 | ```js | ||
50 | Ferdi.setDialogTitle('Dialog title'); | ||
51 | ``` | ||
52 | |||
37 | ### injectCSS(pathToCssFile) | 53 | ### injectCSS(pathToCssFile) |
38 | 54 | ||
39 | Injects the contents of one or more CSS files into the current webview | 55 | Injects the contents of one or more CSS files into the current webview |
diff --git a/docs/integration.md b/docs/integration.md index 08164fc..acbc6b5 100644 --- a/docs/integration.md +++ b/docs/integration.md | |||
@@ -87,26 +87,26 @@ Please note that the fields `id`, `name`, `version` and `config` are mandatory. | |||
87 | This is your "backend" code. Right now the options are very limited and most of the services don't need a custom handling here. If your service is relatively straight forward and has a static URL eg. _messenger.com_, _`[TEAMID]`.slack.com_ or _web.skype.com_ all you need to do to return the Ferdi Class: | 87 | This is your "backend" code. Right now the options are very limited and most of the services don't need a custom handling here. If your service is relatively straight forward and has a static URL eg. _messenger.com_, _`[TEAMID]`.slack.com_ or _web.skype.com_ all you need to do to return the Ferdi Class: |
88 | 88 | ||
89 | ```js | 89 | ```js |
90 | module.exports = (Ferdi) => Ferdi; | 90 | module.exports = Ferdi => Ferdi; |
91 | ``` | 91 | ``` |
92 | 92 | ||
93 | If your service can be hosted on custom servers, you can validate the given URL to detect if it's your server and not e.g. google.com. To enable validation you can override the function `validateServer` | 93 | If your service can be hosted on custom servers, you can validate the given URL to detect if it's your server and not e.g. google.com. To enable validation you can override the function `validateServer` |
94 | 94 | ||
95 | ```js | 95 | ```js |
96 | // RocketChat integration | 96 | // RocketChat integration |
97 | module.exports = (Ferdi) => | 97 | module.exports = Ferdi => |
98 | class RocketChat extends Ferdi { | 98 | class RocketChat extends Ferdi { |
99 | async validateUrl(url) { | 99 | async validateUrl(url) { |
100 | try { | 100 | try { |
101 | const resp = await window.fetch(`${url}/api/info`, { | 101 | const resp = await window.fetch(`${url}/api/info`, { |
102 | method: "GET", | 102 | method: 'GET', |
103 | headers: { | 103 | headers: { |
104 | "Content-Type": "application/json", | 104 | 'Content-Type': 'application/json', |
105 | }, | 105 | }, |
106 | }); | 106 | }); |
107 | const data = await resp.json(); | 107 | const data = await resp.json(); |
108 | 108 | ||
109 | return Object.hasOwnProperty.call(data, "version"); | 109 | return Object.hasOwnProperty.call(data, 'version'); |
110 | } catch (err) { | 110 | } catch (err) { |
111 | console.error(err); | 111 | console.error(err); |
112 | } | 112 | } |
@@ -147,24 +147,44 @@ overrideUserAgent() { | |||
147 | 147 | ||
148 | ### webview.js | 148 | ### webview.js |
149 | 149 | ||
150 | The `webview.js` is the actual script that will be loaded into the webview. Here you can do whatever you want to do in order perfectly integrate the service into Ferdi. For convenience, we have provided a very simple set of functions to set unread message badges (`Ferdi.setBadge()`) and inject CSS files (`Ferdi.injectCSS()`). | 150 | The `webview.js` is the actual script that will be loaded into the webview. Here you can do whatever you want to do in order perfectly integrate the service into Ferdi. For convenience, we have provided a very simple set of functions to set unread message badges (`Ferdi.setBadge()`), set active dialog title (`Ferdi.setDialogTitle()`) and inject CSS files (`Ferdi.injectCSS()`). |
151 | 151 | ||
152 | ```js | 152 | ```js |
153 | // orat.io integration | 153 | // telegram integration |
154 | module.exports = (Ferdi) => { | 154 | module.exports = Ferdi => { |
155 | const getMessages = () => { | 155 | const getMessages = () => { |
156 | let direct = 0; | 156 | let direct = 0; |
157 | let indirect = 0; | 157 | let indirect = 0; |
158 | const FerdiData = document.querySelector("#FerdiMessages").dataset; | 158 | const elements = document.querySelectorAll('.rp'); |
159 | if (FerdiData) { | 159 | for (const element of elements) { |
160 | direct = FerdiData.direct; | 160 | const subtitleBadge = element.querySelector('.dialog-subtitle-badge'); |
161 | indirect = FerdiData.indirect; | 161 | if (subtitleBadge) { |
162 | const parsedValue = Ferdi.safeParseInt(subtitleBadge.textContent); | ||
163 | if (element.dataset.peerId > 0) { | ||
164 | direct += parsedValue; | ||
165 | } else { | ||
166 | indirect += parsedValue; | ||
167 | } | ||
168 | } | ||
162 | } | 169 | } |
163 | 170 | ||
164 | Ferdi.setBadge(direct, indirect); | 171 | Ferdi.setBadge(direct, indirect); |
165 | } | 172 | }; |
173 | |||
174 | const getActiveDialogTitle = () => { | ||
175 | const element = document.querySelector('.top .peer-title'); | ||
176 | |||
177 | Ferdi.setDialogTitle(element ? element.textContent : ''); | ||
178 | }; | ||
179 | |||
180 | const loopFunc = () => { | ||
181 | getMessages(); | ||
182 | getActiveDialogTitle(); | ||
183 | }; | ||
184 | |||
185 | Ferdi.loop(loopFunc); | ||
166 | 186 | ||
167 | Ferdi.loop(getMessages); | 187 | Ferdi.injectCSS(_path.default.join(__dirname, 'service.css')); |
168 | }; | 188 | }; |
169 | ``` | 189 | ``` |
170 | 190 | ||
diff --git a/recipes/element/webview.js b/recipes/element/webview.js index 771c758..75df4d9 100644 --- a/recipes/element/webview.js +++ b/recipes/element/webview.js | |||
@@ -9,7 +9,7 @@ module.exports = Ferdi => { | |||
9 | let indirectCount = 0; | 9 | let indirectCount = 0; |
10 | // Count Badges depending on Element Settings | 10 | // Count Badges depending on Element Settings |
11 | if (avatarBadges.length > 0) { | 11 | if (avatarBadges.length > 0) { |
12 | avatarBadges.forEach(function(badge) { | 12 | for (const badge of avatarBadges) { |
13 | if (badge.parentElement.getAttribute('class').includes('mx_NotificationBadge_highlighted')) { | 13 | if (badge.parentElement.getAttribute('class').includes('mx_NotificationBadge_highlighted')) { |
14 | directCount = directCount + Ferdi.safeParseInt(badge.textContent); | 14 | directCount = directCount + Ferdi.safeParseInt(badge.textContent); |
15 | } else if (badge.parentElement.previousSibling != null && badge.parentElement.previousSibling.getAttribute('class').includes('mx_DecoratedRoomAvatar_icon_online')) { | 15 | } else if (badge.parentElement.previousSibling != null && badge.parentElement.previousSibling.getAttribute('class').includes('mx_DecoratedRoomAvatar_icon_online')) { |
@@ -19,9 +19,9 @@ module.exports = Ferdi => { | |||
19 | } else { | 19 | } else { |
20 | indirectCount = indirectCount + Ferdi.safeParseInt(badge.textContent); | 20 | indirectCount = indirectCount + Ferdi.safeParseInt(badge.textContent); |
21 | } | 21 | } |
22 | }); | 22 | } |
23 | } else { | 23 | } else { |
24 | spaceBadges.forEach(function(badge) { | 24 | for (const badge of spaceBadges) { |
25 | if (badge.parentElement.getAttribute('class').includes('mx_NotificationBadge_highlighted')) { | 25 | if (badge.parentElement.getAttribute('class').includes('mx_NotificationBadge_highlighted')) { |
26 | directCount = directCount + Ferdi.safeParseInt(badge.textContent); | 26 | directCount = directCount + Ferdi.safeParseInt(badge.textContent); |
27 | } else if (badge.parentElement.getAttribute('class').includes('mx_NotificationBadge_dot')) { | 27 | } else if (badge.parentElement.getAttribute('class').includes('mx_NotificationBadge_dot')) { |
@@ -29,7 +29,7 @@ module.exports = Ferdi => { | |||
29 | } else { | 29 | } else { |
30 | indirectCount = indirectCount + Ferdi.safeParseInt(badge.textContent); | 30 | indirectCount = indirectCount + Ferdi.safeParseInt(badge.textContent); |
31 | } | 31 | } |
32 | }); | 32 | } |
33 | } | 33 | } |
34 | // set Ferdi badge | 34 | // set Ferdi badge |
35 | Ferdi.setBadge(directCount, indirectCount); | 35 | Ferdi.setBadge(directCount, indirectCount); |
diff --git a/recipes/telegram/package.json b/recipes/telegram/package.json index adb6de6..beda3c3 100644 --- a/recipes/telegram/package.json +++ b/recipes/telegram/package.json | |||
@@ -1,7 +1,7 @@ | |||
1 | { | 1 | { |
2 | "id": "telegram", | 2 | "id": "telegram", |
3 | "name": "Telegram", | 3 | "name": "Telegram", |
4 | "version": "3.2.2", | 4 | "version": "3.2.3", |
5 | "license": "MIT", | 5 | "license": "MIT", |
6 | "config": { | 6 | "config": { |
7 | "serviceURL": "https://web.telegram.org", | 7 | "serviceURL": "https://web.telegram.org", |
diff --git a/recipes/telegram/webview.js b/recipes/telegram/webview.js index 358bdaa..7d2c8e3 100644 --- a/recipes/telegram/webview.js +++ b/recipes/telegram/webview.js | |||
@@ -8,25 +8,36 @@ function _interopRequireDefault(obj) { | |||
8 | 8 | ||
9 | module.exports = Ferdi => { | 9 | module.exports = Ferdi => { |
10 | const getMessages = () => { | 10 | const getMessages = () => { |
11 | let count = 0; | 11 | let direct = 0; |
12 | let count_sec = 0; | 12 | let indirect = 0; |
13 | const elements = document.querySelectorAll('.rp'); | 13 | const elements = document.querySelectorAll('.rp'); |
14 | for (const element of elements) { | 14 | for (const element of elements) { |
15 | const subtitleBadge = element.querySelector('.dialog-subtitle-badge'); | 15 | const subtitleBadge = element.querySelector('.dialog-subtitle-badge'); |
16 | if (subtitleBadge) { | 16 | if (subtitleBadge) { |
17 | const parsedValue = Ferdi.safeParseInt(subtitleBadge.textContent); | 17 | const parsedValue = Ferdi.safeParseInt(subtitleBadge.textContent); |
18 | if (element.dataset.peerId > 0) { | 18 | if (element.dataset.peerId > 0) { |
19 | count += parsedValue; | 19 | direct += parsedValue; |
20 | } else { | 20 | } else { |
21 | count_sec += parsedValue; | 21 | indirect += parsedValue; |
22 | } | 22 | } |
23 | } | 23 | } |
24 | } | 24 | } |
25 | 25 | ||
26 | Ferdi.setBadge(count, count_sec); | 26 | Ferdi.setBadge(direct, indirect); |
27 | }; | 27 | }; |
28 | 28 | ||
29 | Ferdi.loop(getMessages); | 29 | const getActiveDialogTitle = () => { |
30 | const element = document.querySelector('.top .peer-title'); | ||
31 | |||
32 | Ferdi.setDialogTitle(element ? element.textContent : ''); | ||
33 | }; | ||
34 | |||
35 | const loopFunc = () => { | ||
36 | getMessages(); | ||
37 | getActiveDialogTitle(); | ||
38 | }; | ||
39 | |||
40 | Ferdi.loop(loopFunc); | ||
30 | 41 | ||
31 | Ferdi.injectCSS(_path.default.join(__dirname, 'service.css')); | 42 | Ferdi.injectCSS(_path.default.join(__dirname, 'service.css')); |
32 | }; | 43 | }; |
diff --git a/recipes/whatsapp/package.json b/recipes/whatsapp/package.json index 8f4aab7..208a3a8 100644 --- a/recipes/whatsapp/package.json +++ b/recipes/whatsapp/package.json | |||
@@ -1,7 +1,7 @@ | |||
1 | { | 1 | { |
2 | "id": "whatsapp", | 2 | "id": "whatsapp", |
3 | "name": "WhatsApp", | 3 | "name": "WhatsApp", |
4 | "version": "3.3.5", | 4 | "version": "3.3.6", |
5 | "license": "MIT", | 5 | "license": "MIT", |
6 | "config": { | 6 | "config": { |
7 | "serviceURL": "https://web.whatsapp.com", | 7 | "serviceURL": "https://web.whatsapp.com", |
diff --git a/recipes/whatsapp/webview.js b/recipes/whatsapp/webview.js index a908637..1c11edc 100644 --- a/recipes/whatsapp/webview.js +++ b/recipes/whatsapp/webview.js | |||
@@ -1,14 +1,17 @@ | |||
1 | const _path = _interopRequireDefault(require('path')); | 1 | const _path = _interopRequireDefault(require('path')); |
2 | 2 | ||
3 | function _interopRequireDefault(obj) { return obj && obj.__esModule ? obj : { default: obj }; } | 3 | function _interopRequireDefault(obj) { |
4 | return obj && obj.__esModule ? obj : { default: obj }; | ||
5 | } | ||
4 | 6 | ||
5 | module.exports = (Ferdi, settings) => { | 7 | module.exports = (Ferdi, settings) => { |
6 | const getMessages = () => { | 8 | const getMessages = () => { |
7 | let count = 0; | 9 | let count = 0; |
8 | let indirectCount = 0; | 10 | let indirectCount = 0; |
9 | 11 | ||
10 | const parentChatElem = [...document.querySelectorAll('div[aria-label]')] | 12 | const parentChatElem = [ |
11 | .sort((a, b) => (a.offsetHeight < b.offsetHeight) ? 1 : -1)[0]; | 13 | ...document.querySelectorAll('div[aria-label]'), |
14 | ].sort((a, b) => (a.offsetHeight < b.offsetHeight ? 1 : -1))[0]; | ||
12 | if (!parentChatElem) { | 15 | if (!parentChatElem) { |
13 | return; | 16 | return; |
14 | } | 17 | } |
@@ -17,7 +20,12 @@ module.exports = (Ferdi, settings) => { | |||
17 | for (const unreadElem of unreadSpans) { | 20 | for (const unreadElem of unreadSpans) { |
18 | const countValue = Ferdi.safeParseInt(unreadElem.textContent); | 21 | const countValue = Ferdi.safeParseInt(unreadElem.textContent); |
19 | if (countValue > 0) { | 22 | if (countValue > 0) { |
20 | if (!unreadElem.parentNode.previousSibling || unreadElem.parentNode.previousSibling.querySelectorAll('[data-icon=muted]').length === 0) { | 23 | if ( |
24 | !unreadElem.parentNode.previousSibling || | ||
25 | unreadElem.parentNode.previousSibling.querySelectorAll( | ||
26 | '[data-icon=muted]', | ||
27 | ).length === 0 | ||
28 | ) { | ||
21 | count += countValue; | 29 | count += countValue; |
22 | } else { | 30 | } else { |
23 | indirectCount += countValue; | 31 | indirectCount += countValue; |
@@ -28,12 +36,31 @@ module.exports = (Ferdi, settings) => { | |||
28 | Ferdi.setBadge(count, indirectCount); | 36 | Ferdi.setBadge(count, indirectCount); |
29 | }; | 37 | }; |
30 | 38 | ||
39 | const getActiveDialogTitle = () => { | ||
40 | const element = document.querySelector('header .emoji-texttt'); | ||
41 | |||
42 | Ferdi.setDialogTitle(element ? element.textContent : ''); | ||
43 | }; | ||
44 | |||
45 | const loopFunc = () => { | ||
46 | getMessages(); | ||
47 | getActiveDialogTitle(); | ||
48 | }; | ||
49 | |||
31 | window.addEventListener('beforeunload', async () => { | 50 | window.addEventListener('beforeunload', async () => { |
32 | Ferdi.clearStorageData(settings.id, { storages: ['appcache', 'serviceworkers', 'cachestorage', 'websql', 'indexdb'] }); | 51 | Ferdi.clearStorageData(settings.id, { |
52 | storages: [ | ||
53 | 'appcache', | ||
54 | 'serviceworkers', | ||
55 | 'cachestorage', | ||
56 | 'websql', | ||
57 | 'indexdb', | ||
58 | ], | ||
59 | }); | ||
33 | Ferdi.releaseServiceWorkers(); | 60 | Ferdi.releaseServiceWorkers(); |
34 | }); | 61 | }); |
35 | 62 | ||
36 | Ferdi.loop(getMessages); | 63 | Ferdi.loop(loopFunc); |
37 | 64 | ||
38 | Ferdi.injectCSS(_path.default.join(__dirname, 'service.css')); | 65 | Ferdi.injectCSS(_path.default.join(__dirname, 'service.css')); |
39 | }; | 66 | }; |