diff options
Diffstat (limited to 'src/lib/Menu.js')
-rw-r--r-- | src/lib/Menu.js | 324 |
1 files changed, 258 insertions, 66 deletions
diff --git a/src/lib/Menu.js b/src/lib/Menu.js index ed21315d8..475352bba 100644 --- a/src/lib/Menu.js +++ b/src/lib/Menu.js | |||
@@ -1,10 +1,14 @@ | |||
1 | import { remote, shell } from 'electron'; | 1 | import { remote, shell } from 'electron'; |
2 | import { autorun, computed, observable, toJS } from 'mobx'; | 2 | import { autorun, computed, observable, toJS } from 'mobx'; |
3 | 3 | ||
4 | import { isMac } from '../environment'; | 4 | import { isMac, ctrlKey, cmdKey } from '../environment'; |
5 | 5 | ||
6 | const { app, Menu, dialog } = remote; | 6 | const { app, Menu, dialog } = remote; |
7 | 7 | ||
8 | function getActiveWebview() { | ||
9 | return window.franz.stores.services.active.webview; | ||
10 | } | ||
11 | |||
8 | const template = [ | 12 | const template = [ |
9 | { | 13 | { |
10 | label: 'Edit', | 14 | label: 'Edit', |
@@ -23,12 +27,12 @@ const template = [ | |||
23 | }, | 27 | }, |
24 | { | 28 | { |
25 | label: 'Copy', | 29 | label: 'Copy', |
26 | accelerator: 'Cmd+C', | 30 | accelerator: 'CmdOrCtrl+C', |
27 | selector: 'copy:', | 31 | selector: 'copy:', |
28 | }, | 32 | }, |
29 | { | 33 | { |
30 | label: 'Paste', | 34 | label: 'Paste', |
31 | accelerator: 'Cmd+V', | 35 | accelerator: 'CmdOrCtrl+V', |
32 | selector: 'paste:', | 36 | selector: 'paste:', |
33 | }, | 37 | }, |
34 | { | 38 | { |
@@ -114,8 +118,161 @@ const template = [ | |||
114 | }, | 118 | }, |
115 | ]; | 119 | ]; |
116 | 120 | ||
121 | const titleBarTemplate = [ | ||
122 | { | ||
123 | label: 'Edit', | ||
124 | submenu: [ | ||
125 | { | ||
126 | label: 'Undo', | ||
127 | accelerator: `${ctrlKey}+Z`, | ||
128 | click() { | ||
129 | getActiveWebview().undo(); | ||
130 | }, | ||
131 | }, | ||
132 | { | ||
133 | label: 'Redo', | ||
134 | accelerator: `${ctrlKey}+Y`, | ||
135 | click() { | ||
136 | getActiveWebview().redo(); | ||
137 | }, | ||
138 | }, | ||
139 | { | ||
140 | type: 'separator', | ||
141 | }, | ||
142 | { | ||
143 | label: 'Cut', | ||
144 | accelerator: `${ctrlKey}+X`, | ||
145 | click() { | ||
146 | getActiveWebview().cut(); | ||
147 | }, | ||
148 | }, | ||
149 | { | ||
150 | label: 'Copy', | ||
151 | accelerator: `${ctrlKey}+C`, | ||
152 | click() { | ||
153 | getActiveWebview().copy(); | ||
154 | }, | ||
155 | }, | ||
156 | { | ||
157 | label: 'Paste', | ||
158 | accelerator: `${ctrlKey}+V`, | ||
159 | click() { | ||
160 | getActiveWebview().paste(); | ||
161 | }, | ||
162 | }, | ||
163 | { | ||
164 | label: 'Paste and Match Style', | ||
165 | accelerator: `${ctrlKey}+Shift+V`, | ||
166 | click() { | ||
167 | getActiveWebview().pasteAndMatchStyle(); | ||
168 | }, | ||
169 | }, | ||
170 | { | ||
171 | label: 'Delete', | ||
172 | click() { | ||
173 | getActiveWebview().delete(); | ||
174 | }, | ||
175 | }, | ||
176 | { | ||
177 | label: 'Select All', | ||
178 | accelerator: `${ctrlKey}+A`, | ||
179 | click() { | ||
180 | getActiveWebview().selectAll(); | ||
181 | }, | ||
182 | }, | ||
183 | ], | ||
184 | }, | ||
185 | { | ||
186 | label: 'View', | ||
187 | submenu: [ | ||
188 | { | ||
189 | type: 'separator', | ||
190 | }, | ||
191 | { | ||
192 | label: 'Reset Zoom', | ||
193 | accelerator: `${ctrlKey}+0`, | ||
194 | click() { | ||
195 | getActiveWebview().setZoomLevel(0); | ||
196 | }, | ||
197 | }, | ||
198 | { | ||
199 | label: 'Zoom in', | ||
200 | accelerator: `${ctrlKey}+=`, | ||
201 | click() { | ||
202 | getActiveWebview().getZoomLevel((zoomLevel) => { | ||
203 | getActiveWebview().setZoomLevel(zoomLevel === 5 ? zoomLevel : zoomLevel + 1); | ||
204 | }); | ||
205 | }, | ||
206 | }, | ||
207 | { | ||
208 | label: 'Zoom out', | ||
209 | accelerator: `${ctrlKey}+-`, | ||
210 | click() { | ||
211 | getActiveWebview().getZoomLevel((zoomLevel) => { | ||
212 | getActiveWebview().setZoomLevel(zoomLevel === -5 ? zoomLevel : zoomLevel - 1); | ||
213 | }); | ||
214 | }, | ||
215 | }, | ||
216 | ], | ||
217 | }, | ||
218 | { | ||
219 | label: 'Services', | ||
220 | submenu: [], | ||
221 | }, | ||
222 | { | ||
223 | label: 'Window', | ||
224 | submenu: [ | ||
225 | { | ||
226 | label: 'Minimize', | ||
227 | accelerator: 'Alt+M', | ||
228 | click(menuItem, browserWindow) { | ||
229 | browserWindow.minimize(); | ||
230 | }, | ||
231 | }, | ||
232 | { | ||
233 | label: 'Close', | ||
234 | accelerator: 'Alt+W', | ||
235 | click(menuItem, browserWindow) { | ||
236 | browserWindow.close(); | ||
237 | }, | ||
238 | }, | ||
239 | ], | ||
240 | }, | ||
241 | { | ||
242 | label: '?', | ||
243 | submenu: [ | ||
244 | { | ||
245 | label: 'Learn More', | ||
246 | click() { shell.openExternal('http://meetfranz.com'); }, | ||
247 | }, | ||
248 | { | ||
249 | label: 'Changelog', | ||
250 | click() { shell.openExternal('https://github.com/meetfranz/franz/blob/master/CHANGELOG.md'); }, | ||
251 | }, | ||
252 | { | ||
253 | type: 'separator', | ||
254 | }, | ||
255 | { | ||
256 | label: 'Support', | ||
257 | click() { shell.openExternal('http://meetfranz.com/support'); }, | ||
258 | }, | ||
259 | { | ||
260 | type: 'separator', | ||
261 | }, | ||
262 | { | ||
263 | label: 'Terms of Service', | ||
264 | click() { shell.openExternal('https://meetfranz.com/terms'); }, | ||
265 | }, | ||
266 | { | ||
267 | label: 'Privacy Statement', | ||
268 | click() { shell.openExternal('https://meetfranz.com/privacy'); }, | ||
269 | }, | ||
270 | ], | ||
271 | }, | ||
272 | ]; | ||
273 | |||
117 | export default class FranzMenu { | 274 | export default class FranzMenu { |
118 | @observable tpl = template; | 275 | @observable tpl = isMac ? template : titleBarTemplate; |
119 | @observable currentTemplate = null; | 276 | @observable currentTemplate = null; |
120 | 277 | ||
121 | constructor(stores, actions) { | 278 | constructor(stores, actions) { |
@@ -126,17 +283,23 @@ export default class FranzMenu { | |||
126 | } | 283 | } |
127 | 284 | ||
128 | get template() { | 285 | get template() { |
129 | return this.currentTemplate; | 286 | return this.currentTemplate.toJS(); |
130 | } | 287 | } |
131 | 288 | ||
132 | _build() { | 289 | _build() { |
133 | const tpl = toJS(this.tpl); | 290 | const tpl = toJS(this.tpl); |
134 | 291 | ||
135 | tpl[1].submenu.push({ | 292 | tpl[1].submenu.push({ |
136 | role: 'toggledevtools', | 293 | type: 'separator', |
294 | }, { | ||
295 | label: 'Toggle Developer Tools', | ||
296 | accelerator: `${cmdKey}+Alt+I`, | ||
297 | click: (menuItem, browserWindow) => { | ||
298 | browserWindow.webContents.toggleDevTools(); | ||
299 | }, | ||
137 | }, { | 300 | }, { |
138 | label: 'Toggle Service Developer Tools', | 301 | label: 'Open Service Developer Tools', |
139 | accelerator: 'CmdOrCtrl+Shift+Alt+i', | 302 | accelerator: `${cmdKey}+Shift+Alt+I`, |
140 | click: () => { | 303 | click: () => { |
141 | this.actions.service.openDevToolsForActiveService(); | 304 | this.actions.service.openDevToolsForActiveService(); |
142 | }, | 305 | }, |
@@ -145,7 +308,7 @@ export default class FranzMenu { | |||
145 | tpl[1].submenu.unshift({ | 308 | tpl[1].submenu.unshift({ |
146 | label: 'Reload Service', | 309 | label: 'Reload Service', |
147 | id: 'reloadService', | 310 | id: 'reloadService', |
148 | accelerator: 'CmdOrCtrl+R', | 311 | accelerator: `${cmdKey}+R`, |
149 | click: () => { | 312 | click: () => { |
150 | if (this.stores.user.isLoggedIn | 313 | if (this.stores.user.isLoggedIn |
151 | && this.stores.services.enabled.length > 0) { | 314 | && this.stores.services.enabled.length > 0) { |
@@ -156,56 +319,69 @@ export default class FranzMenu { | |||
156 | }, | 319 | }, |
157 | }, { | 320 | }, { |
158 | label: 'Reload Franz', | 321 | label: 'Reload Franz', |
159 | accelerator: 'CmdOrCtrl+Shift+R', | 322 | accelerator: `${cmdKey}+Shift+R`, |
160 | click: () => { | 323 | click: () => { |
161 | window.location.reload(); | 324 | window.location.reload(); |
162 | }, | 325 | }, |
163 | }); | 326 | }); |
164 | 327 | ||
165 | if (isMac) { | 328 | tpl.unshift({ |
166 | tpl.unshift({ | 329 | label: isMac ? app.getName() : 'File', |
167 | label: app.getName(), | 330 | submenu: [ |
168 | submenu: [ | 331 | { |
169 | { | 332 | role: 'about', |
170 | role: 'about', | 333 | }, |
171 | }, | 334 | { |
172 | { | 335 | type: 'separator', |
173 | type: 'separator', | 336 | }, |
174 | }, | 337 | { |
175 | { | 338 | label: 'Settings', |
176 | label: 'Settings', | 339 | accelerator: 'CmdOrCtrl+,', |
177 | accelerator: 'CmdOrCtrl+,', | 340 | click: () => { |
178 | click: () => { | 341 | this.actions.ui.openSettings({ path: 'app' }); |
179 | this.actions.ui.openSettings({ path: 'app' }); | ||
180 | }, | ||
181 | }, | ||
182 | { | ||
183 | type: 'separator', | ||
184 | }, | ||
185 | { | ||
186 | role: 'services', | ||
187 | submenu: [], | ||
188 | }, | ||
189 | { | ||
190 | type: 'separator', | ||
191 | }, | ||
192 | { | ||
193 | role: 'hide', | ||
194 | }, | ||
195 | { | ||
196 | role: 'hideothers', | ||
197 | }, | ||
198 | { | ||
199 | role: 'unhide', | ||
200 | }, | ||
201 | { | ||
202 | type: 'separator', | ||
203 | }, | ||
204 | { | ||
205 | role: 'quit', | ||
206 | }, | 342 | }, |
207 | ], | 343 | }, |
208 | }); | 344 | { |
345 | type: 'separator', | ||
346 | }, | ||
347 | { | ||
348 | role: 'services', | ||
349 | submenu: [], | ||
350 | }, | ||
351 | { | ||
352 | type: 'separator', | ||
353 | }, | ||
354 | { | ||
355 | role: 'hide', | ||
356 | }, | ||
357 | { | ||
358 | role: 'hideothers', | ||
359 | }, | ||
360 | { | ||
361 | role: 'unhide', | ||
362 | }, | ||
363 | { | ||
364 | type: 'separator', | ||
365 | }, | ||
366 | { | ||
367 | role: 'quit', | ||
368 | }, | ||
369 | ], | ||
370 | }); | ||
371 | |||
372 | const about = { | ||
373 | label: 'About Franz', | ||
374 | click: () => { | ||
375 | dialog.showMessageBox({ | ||
376 | type: 'info', | ||
377 | title: 'Franz', | ||
378 | message: 'Franz', | ||
379 | detail: `Version: ${remote.app.getVersion()}\nRelease: ${process.versions.electron} / ${process.platform} / ${process.arch}`, | ||
380 | }); | ||
381 | }, | ||
382 | }; | ||
383 | |||
384 | if (isMac) { | ||
209 | // Edit menu. | 385 | // Edit menu. |
210 | tpl[1].submenu.push( | 386 | tpl[1].submenu.push( |
211 | { | 387 | { |
@@ -223,25 +399,41 @@ export default class FranzMenu { | |||
223 | ], | 399 | ], |
224 | }, | 400 | }, |
225 | ); | 401 | ); |
402 | |||
403 | tpl[4].submenu.unshift(about, { | ||
404 | type: 'separator', | ||
405 | }); | ||
226 | } else { | 406 | } else { |
227 | tpl[4].submenu.unshift({ | 407 | tpl[0].submenu = [ |
228 | role: 'about', | 408 | { |
229 | click: () => { | 409 | label: 'Preferences...', |
230 | dialog.showMessageBox({ | 410 | accelerator: 'Ctrl+P', |
231 | type: 'info', | 411 | click: () => { |
232 | title: 'Franz', | 412 | this.actions.ui.openSettings({ path: 'app' }); |
233 | message: 'Franz', | 413 | }, |
234 | detail: `Version: ${remote.app.getVersion()}\nRelease: ${process.versions.electron} / ${process.platform} / ${process.arch}`, | ||
235 | }); | ||
236 | }, | 414 | }, |
237 | }); | 415 | { |
416 | type: 'separator', | ||
417 | }, | ||
418 | { | ||
419 | label: 'Quit', | ||
420 | accelerator: 'Alt+F4', | ||
421 | click: () => { | ||
422 | app.quit(); | ||
423 | }, | ||
424 | }, | ||
425 | ]; | ||
426 | |||
427 | tpl[5].submenu.push({ | ||
428 | type: 'separator', | ||
429 | }, about); | ||
238 | } | 430 | } |
239 | 431 | ||
240 | const serviceTpl = this.serviceTpl; | 432 | const serviceTpl = this.serviceTpl; |
241 | 433 | ||
242 | serviceTpl.unshift({ | 434 | serviceTpl.unshift({ |
243 | label: 'Add new Service', | 435 | label: 'Add new Service', |
244 | accelerator: 'CmdOrCtrl+N', | 436 | accelerator: `${cmdKey}+N`, |
245 | click: () => { | 437 | click: () => { |
246 | this.actions.ui.openSettings({ path: 'recipes' }); | 438 | this.actions.ui.openSettings({ path: 'recipes' }); |
247 | }, | 439 | }, |
@@ -250,7 +442,7 @@ export default class FranzMenu { | |||
250 | }); | 442 | }); |
251 | 443 | ||
252 | if (serviceTpl.length > 0) { | 444 | if (serviceTpl.length > 0) { |
253 | tpl[isMac ? 3 : 2].submenu = toJS(this.serviceTpl); | 445 | tpl[3].submenu = toJS(this.serviceTpl); |
254 | } | 446 | } |
255 | 447 | ||
256 | this.currentTemplate = tpl; | 448 | this.currentTemplate = tpl; |
@@ -264,7 +456,7 @@ export default class FranzMenu { | |||
264 | if (this.stores.user.isLoggedIn) { | 456 | if (this.stores.user.isLoggedIn) { |
265 | return services.map((service, i) => ({ | 457 | return services.map((service, i) => ({ |
266 | label: this._getServiceName(service), | 458 | label: this._getServiceName(service), |
267 | accelerator: i <= 9 ? `CmdOrCtrl+${i + 1}` : null, | 459 | accelerator: i <= 9 ? `${cmdKey}+${i + 1}` : null, |
268 | type: 'radio', | 460 | type: 'radio', |
269 | checked: service.isActive, | 461 | checked: service.isActive, |
270 | click: () => { | 462 | click: () => { |