aboutsummaryrefslogtreecommitdiffstats
path: root/src
diff options
context:
space:
mode:
authorLibravatar Bennett <hello@vantezzen.io>2020-04-12 13:33:11 +0200
committerLibravatar GitHub <noreply@github.com>2020-04-12 12:33:11 +0100
commit9ab996a5f01ef88d72d8d5bb28fea518db8c88e6 (patch)
tree58cdb855c1074ce54d0d669910328d4ebb805d2a /src
parentFix cache clearing not working in Windows 10 (#541) (#544) (diff)
downloadferdium-app-9ab996a5f01ef88d72d8d5bb28fea518db8c88e6.tar.gz
ferdium-app-9ab996a5f01ef88d72d8d5bb28fea518db8c88e6.tar.zst
ferdium-app-9ab996a5f01ef88d72d8d5bb28fea518db8c88e6.zip
Improve user scripts (#559)
* Add template to user.js creation * Add Userscript library * Add internalOpen function * Fix lint * Remove excess line break
Diffstat (limited to 'src')
-rw-r--r--src/stores/ServicesStore.js12
-rw-r--r--src/webview/lib/Userscript.js132
-rw-r--r--src/webview/recipe.js11
3 files changed, 152 insertions, 3 deletions
diff --git a/src/stores/ServicesStore.js b/src/stores/ServicesStore.js
index 54befee77..19e6f8299 100644
--- a/src/stores/ServicesStore.js
+++ b/src/stores/ServicesStore.js
@@ -351,7 +351,17 @@ export default class ServicesStore extends Store {
351 351
352 // Create and open file 352 // Create and open file
353 const filePath = path.join(directory, file); 353 const filePath = path.join(directory, file);
354 await fs.ensureFile(filePath); 354 if (file === 'user.js') {
355 if (!await fs.exists(filePath)) {
356 await fs.writeFile(filePath, `module.exports = (config, Ferdi) => {
357 // Write your scripts here
358 console.log("Hello, World!", config);
359}
360`);
361 }
362 } else {
363 await fs.ensureFile(filePath);
364 }
355 shell.showItemInFolder(filePath); 365 shell.showItemInFolder(filePath);
356 } 366 }
357 367
diff --git a/src/webview/lib/Userscript.js b/src/webview/lib/Userscript.js
new file mode 100644
index 000000000..2043d9fff
--- /dev/null
+++ b/src/webview/lib/Userscript.js
@@ -0,0 +1,132 @@
1import { ipcRenderer } from 'electron';
2
3export default class Userscript {
4 // Current ./lib/RecipeWebview instance
5 recipe = null;
6
7 // Current ./recipe.js instance
8 controller = null;
9
10 // Service configuration
11 config = {};
12
13 // Ferdi and service settings
14 settings = {};
15
16 settingsUpdateHandler = null;
17
18 constructor(recipe, controller, config) {
19 this.recipe = recipe;
20 this.controller = controller;
21 this.internal_setSettings(controller.settings);
22 this.config = config;
23 }
24
25 /**
26 * Set internal copy of Ferdi's settings.
27 * This is only used internally and can not be used to change any settings
28 *
29 * @param {*} settings
30 */
31 // eslint-disable-next-line
32 internal_setSettings(settings) {
33 // This is needed to get a clean JS object from the settings itself to provide better accessibility
34 // Otherwise this will be a mobX instance
35 this.settings = JSON.parse(JSON.stringify(settings));
36
37 if (typeof this.settingsUpdateHandler === 'function') {
38 this.settingsUpdateHandler();
39 }
40 }
41
42 /**
43 * Register a settings handler to be executed when the settings change
44 *
45 * @param {function} handler
46 */
47 onSettingsUpdate(handler) {
48 this.settingsUpdateHandler = handler;
49 }
50
51 /**
52 * Set badge count for the current service
53 * @param {*} direct Direct messages
54 * @param {*} indirect Indirect messages
55 */
56 setBadge(direct = 0, indirect = 0) {
57 if (this.recipe && this.recipe.setBadge) {
58 this.recipe.setBadge(direct, indirect);
59 }
60 }
61
62 /**
63 * Inject CSS files into the current page
64 *
65 * @param {...string} files
66 */
67 injectCSSFiles(...files) {
68 if (this.recipe && this.recipe.injectCSS) {
69 this.recipe.injectCSS(...files);
70 }
71 }
72
73 /**
74 * Inject a CSS string into the page
75 *
76 * @param {string} css
77 */
78 injectCSS(css) {
79 const style = document.createElement('style');
80 style.textContent = css;
81 document.head.append(style);
82 }
83
84 /**
85 * Open "Find in Page" popup
86 */
87 openFindInPage() {
88 this.controller.openFindInPage();
89 }
90
91 /**
92 * Set or update value in storage
93 *
94 * @param {*} key
95 * @param {*} value
96 */
97 set(key, value) {
98 window.localStorage.setItem(
99 `ferdi-user-${key}`, JSON.stringify(value),
100 );
101 }
102
103 /**
104 * Get value from storage
105 *
106 * @param {*} key
107 * @return Value of the key
108 */
109 get(key) {
110 return JSON.parse(window.localStorage.getItem(
111 `ferdi-user-${key}`,
112 ));
113 }
114
115 /**
116 * Open a URL in an external browser
117 *
118 * @param {*} url
119 */
120 externalOpen(url) {
121 ipcRenderer.sendToHost('new-window', url);
122 }
123
124 /**
125 * Open a URL in the current service
126 *
127 * @param {*} url
128 */
129 internalOpen(url) {
130 window.location.href = url;
131 }
132}
diff --git a/src/webview/recipe.js b/src/webview/recipe.js
index bad5a93b2..7b762af17 100644
--- a/src/webview/recipe.js
+++ b/src/webview/recipe.js
@@ -21,6 +21,7 @@ import ignoreList from './darkmode/ignore';
21import customDarkModeCss from './darkmode/custom'; 21import customDarkModeCss from './darkmode/custom';
22 22
23import RecipeWebview from './lib/RecipeWebview'; 23import RecipeWebview from './lib/RecipeWebview';
24import Userscript from './lib/Userscript';
24 25
25import spellchecker, { switchDict, disable as disableSpellchecker, getSpellcheckerLocaleByFuzzyIdentifier } from './spellchecker'; 26import spellchecker, { switchDict, disable as disableSpellchecker, getSpellcheckerLocaleByFuzzyIdentifier } from './spellchecker';
26import { injectDarkModeStyle, isDarkModeStyleInjected, removeDarkModeStyle } from './darkmode'; 27import { injectDarkModeStyle, isDarkModeStyleInjected, removeDarkModeStyle } from './darkmode';
@@ -55,6 +56,8 @@ class RecipeController {
55 56
56 recipe = null; 57 recipe = null;
57 58
59 userscript = null;
60
58 hasUpdatedBeforeRecipeLoaded = false; 61 hasUpdatedBeforeRecipeLoaded = false;
59 62
60 constructor() { 63 constructor() {
@@ -130,7 +133,8 @@ class RecipeController {
130 const userJsModule = require(userJs); 133 const userJsModule = require(userJs);
131 134
132 if (typeof userJsModule === 'function') { 135 if (typeof userJsModule === 'function') {
133 userJsModule(config); 136 this.userscript = new Userscript(this.recipe, this, config);
137 userJsModule(config, this.userscript);
134 } 138 }
135 }; 139 };
136 140
@@ -154,6 +158,10 @@ class RecipeController {
154 debug('System spellcheckerLanguage', this.settings.app.spellcheckerLanguage); 158 debug('System spellcheckerLanguage', this.settings.app.spellcheckerLanguage);
155 debug('Service spellcheckerLanguage', this.settings.service.spellcheckerLanguage); 159 debug('Service spellcheckerLanguage', this.settings.service.spellcheckerLanguage);
156 160
161 if (this.userscript && this.userscript.internal_setSettings) {
162 this.userscript.internal_setSettings(this.settings);
163 }
164
157 if (this.settings.app.enableSpellchecking) { 165 if (this.settings.app.enableSpellchecking) {
158 debug('Setting spellchecker language to', this.spellcheckerLanguage); 166 debug('Setting spellchecker language to', this.spellcheckerLanguage);
159 let { spellcheckerLanguage } = this; 167 let { spellcheckerLanguage } = this;
@@ -322,7 +330,6 @@ new RecipeController();
322// Patching window.open 330// Patching window.open
323const originalWindowOpen = window.open; 331const originalWindowOpen = window.open;
324 332
325
326window.open = (url, frameName, features) => { 333window.open = (url, frameName, features) => {
327 if (!url && !frameName && !features) { 334 if (!url && !frameName && !features) {
328 // The service hasn't yet supplied a URL (as used in Skype). 335 // The service hasn't yet supplied a URL (as used in Skype).