Browse Source

开始添加系统菜单。

oldj 8 years ago
parent
commit
60c4f84744
14 changed files with 457 additions and 72 deletions
  1. 57 31
      app/bundle.js
  2. 1 0
      app/main.js
  3. 322 0
      app/menu/main_menu.js
  4. 1 1
      app/package.json
  5. 2 19
      app/server/Server.js
  6. 32 0
      app/server/svr.js
  7. 1 1
      app/version.js
  8. 14 2
      ui/app.js
  9. 3 5
      ui/events/list_updated.js
  10. 6 2
      ui/frame/edit.js
  11. 1 1
      ui/package.json
  12. 13 2
      ui/panel/list-item.js
  13. 2 2
      ui/panel/list-item.less
  14. 2 6
      ui/panel/list.js

File diff suppressed because it is too large
+ 57 - 31
app/bundle.js


+ 1 - 0
app/main.js

@@ -104,6 +104,7 @@ if (should_quit) {
 app.on('ready', () => {
   createWindow()
   //require('./ui/modules/mainMenu').init(app, user_language)
+  require('./menu/main_menu').init(app, user_language)
 
   setTimeout(() => {
     if (renderer) {

+ 322 - 0
app/menu/main_menu.js

@@ -0,0 +1,322 @@
+/**
+ * @author oldj
+ * @blog https://oldj.net
+ */
+
+'use strict'
+
+const path = require('path')
+const paths = require('../server/paths')
+const {Menu, shell, dialog} = require('electron')
+const m_lang = require('../server/lang')
+const getPref = require('../server/actions/getPref')
+const svr = require('../server/svr')
+const version = require('../version').version
+
+function doInit (app, lang) {
+  let last_path = null
+
+  const template = [
+    {
+      label: lang.file,
+      submenu: [
+        {
+          label: lang.new,
+          accelerator: 'CommandOrControl+N',
+          click: () => {
+            svr.broadcast('add_hosts')
+          }
+        }, {
+          type: 'separator'
+        }, {
+          label: lang.import,
+          accelerator: 'Alt+CommandOrControl+I',
+          click: () => {
+            dialog.showOpenDialog({
+              title: lang.import,
+              defaultPath: path.join(last_path || paths.home_path, 'sh.json'),
+              filters: [
+                {name: 'JSON', extensions: ['json']},
+                {name: 'All Files', extensions: ['*']}
+              ]
+            }, (fns) => {
+              if (fns && fns.length > 0) {
+                svr.emit('to_import', fns[0])
+                last_path = path.dirname(fns[0])
+              }
+            })
+          }
+        }, {
+          label: lang.export,
+          accelerator: 'Alt+CommandOrControl+E',
+          click: () => {
+            dialog.showSaveDialog({
+              title: lang.export,
+              defaultPath: path.join(last_path || paths.home_path, 'sh.json'),
+              filters: [
+                {name: 'JSON', extensions: ['json']},
+                {name: 'All Files', extensions: ['*']}
+              ]
+            }, (fn) => {
+              if (fn) {
+                svr.emit('to_export', fn)
+                last_path = path.dirname(fn)
+              }
+            })
+          }
+        }, {
+          type: 'separator'
+        }, {
+          label: lang.preferences,
+          accelerator: 'CommandOrControl+,',
+          click: () => {
+            //app.mainWindow.webContents.send('show_preferences')
+            svr.broadcast('show_preferences')
+          }
+        }
+      ]
+    },
+    {
+      label: lang.edit,
+      submenu: [
+        {
+          role: 'undo'
+        }, {
+          role: 'redo'
+        }, {
+          type: 'separator'
+        }, {
+          role: 'cut'
+        }, {
+          role: 'copy'
+        }, {
+          role: 'paste'
+        }, {
+          role: 'pasteandmatchstyle'
+        }, {
+          role: 'delete'
+        }, {
+          role: 'selectall'
+        }, {
+          type: 'separator'
+        }, {
+          label: lang.search,
+          accelerator: 'CommandOrControl+F',
+          click () {
+            // ipcMain.emit('to_search');
+            //app.mainWindow.webContents.send('to_search')
+            svr.broadcast('to_search')
+          }
+        }, {
+          label: lang.comment,
+          accelerator: 'CommandOrControl+/',
+          click () {
+            // ipcMain.emit('to_search');
+            //app.mainWindow.webContents.send('to_comment')
+            svr.broadcast('to_comment')
+          }
+        }]
+    }, {
+      label: lang.view,
+      submenu: [
+        // {
+        //     label: 'Reload',
+        //     accelerator: 'CmdOrCtrl+R',
+        //     click (item, focusedWindow) {
+        //         if (focusedWindow) focusedWindow.reload()
+        //     }
+        // },
+        // {
+        //     label: 'Toggle Developer Tools',
+        //     accelerator: process.platform === 'darwin' ? 'Alt+Command+I' : 'Ctrl+Shift+I',
+        //     click (item, focusedWindow) {
+        //         if (focusedWindow) focusedWindow.webContents.toggleDevTools()
+        //     }
+        // },
+        // {
+        //     type: 'separator'
+        // },
+        {
+          role: 'resetzoom'
+        },
+        {
+          role: 'zoomin'
+        },
+        {
+          role: 'zoomout'
+        },
+        {
+          type: 'separator'
+        },
+        {
+          role: 'togglefullscreen'
+        }
+      ]
+    }, {
+      label: lang.window,
+      role: 'window',
+      submenu: [
+        {
+          role: 'minimize'
+        }, {
+          role: 'close'
+        }]
+    }, {
+      label: lang.help,
+      role: 'help',
+      submenu: [
+        {
+          label: lang.check_update,
+          click () {
+            //m_chk_update.check()
+            // todo
+          }
+        }, {
+          type: 'separator'
+        }, {
+          label: lang.feedback,
+          click () {
+            shell.openExternal('https://github.com/oldj/SwitchHosts/issues')
+          }
+        }, {
+          label: lang.homepage,
+          click () {
+            shell.openExternal('http://oldj.github.io/SwitchHosts/')
+          }
+        }]
+    }
+  ]
+
+  const name = require('electron').app.getName()
+  const os = process.platform
+  if (os === 'darwin') {
+    template.unshift({
+      label: name,
+      submenu: [
+        {
+          role: 'about'
+        }, {
+          type: 'separator'
+        },
+        // {
+        //     role: 'services',
+        //     submenu: []
+        // },
+        // {
+        //     type: 'separator'
+        // },
+        {
+          role: 'hide'
+        }, {
+          role: 'hideothers'
+        }, {
+          role: 'unhide'
+        }, {
+          type: 'separator'
+        }, {
+          role: 'quit'
+        }]
+    })
+    // Edit menu.
+    /*template[2].submenu.push(
+     {
+     type: 'separator'
+     },
+     {
+     label: 'Speech',
+     submenu: [
+     {
+     role: 'startspeaking'
+     },
+     {
+     role: 'stopspeaking'
+     }
+     ]
+     }
+     );*/
+    // Window menu.
+    template[4].submenu = [
+      {
+        label: 'Close',
+        accelerator: 'CmdOrCtrl+W',
+        role: 'close'
+      },
+      {
+        label: 'Minimize',
+        accelerator: 'CmdOrCtrl+M',
+        role: 'minimize'
+      },
+      {
+        label: 'Zoom',
+        role: 'zoom'
+      },
+      {
+        type: 'separator'
+      },
+      {
+        label: 'Bring All to Front',
+        role: 'front'
+      }
+    ]
+  } else if (os === 'win32') {
+    template[0].submenu.unshift({
+      type: 'separator'
+    })
+    template[0].submenu.unshift({
+      role: 'about',
+      click: () => {
+        dialog.showMessageBox({
+          type: 'info',
+          buttons: [],
+          title: 'About',
+          message: `${name} v${version.slice(0, 3).join('.')} (${version[3]})`
+        })
+      }
+    })
+
+    template[0].submenu.push({
+      type: 'separator'
+    })
+    template[0].submenu.push({
+      label: 'Quit',
+      role: 'quit',
+      accelerator: 'CmdOrCtrl+Q'
+    })
+
+    // VIEW
+    template[2].submenu.splice(0, 4)
+  }
+
+  if (process.env.ENV === 'dev') {
+    // VIEW
+    template[3].submenu = [
+      {
+        label: 'Reload',
+        accelerator: 'CmdOrCtrl+R',
+        click (item, focusedWindow) {
+          if (focusedWindow) focusedWindow.reload()
+        }
+      },
+      {
+        label: 'Toggle Developer Tools',
+        accelerator: process.platform === 'darwin'
+          ? 'Alt+Command+I'
+          : 'Ctrl+Shift+I',
+        click (item, focusedWindow) {
+          if (focusedWindow) focusedWindow.webContents.toggleDevTools()
+        }
+      },
+      {
+        type: 'separator'
+      }
+    ].concat(template[3].submenu)
+  }
+
+  const menu = Menu.buildFromTemplate(template)
+  Menu.setApplicationMenu(menu)
+}
+
+exports.init = function (app, language = 'en') {
+  let lang = m_lang.getLang(language)
+  doInit(app, lang)
+}

+ 1 - 1
app/package.json

@@ -14,4 +14,4 @@
     "md5-file": "^3.1.1",
     "superagent": "^3.5.2"
   }
-}
+}

+ 2 - 19
app/server/Server.js

@@ -5,35 +5,18 @@
 
 'use strict'
 
-const EventEmitter = require('events')
 const {ipcMain} = require('electron')
 const actions = require('./actions/index')
 const app = require('./http/app')
+const svr = require('./svr')
 
 let renderer
-let svr = new EventEmitter()
-svr.broadcast = broadcast
-
-function broadcast (event, ...args) {
-  if (!renderer) {
-    console.log('no renderer!')
-    return
-  }
-
-  try {
-    renderer.send('y', {
-      event,
-      data: args
-    })
-  } catch (e) {
-    console.log(e)
-  }
-}
 
 ipcMain.on('x', (e, d) => {
   let sender = e.sender
   if (!renderer) {
     renderer = sender
+    svr.registerRenderer(renderer)
   }
 
   let action = d.action

+ 32 - 0
app/server/svr.js

@@ -0,0 +1,32 @@
+/**
+ * @author oldj
+ * @blog https://oldj.net
+ */
+
+'use strict'
+
+const EventEmitter = require('events')
+let svr = new EventEmitter()
+svr.broadcast = broadcast
+
+function broadcast (event, ...args) {
+  if (!svr.renderer) {
+    console.log('no renderer!')
+    return
+  }
+
+  try {
+    svr.renderer.send('y', {
+      event,
+      data: args
+    })
+  } catch (e) {
+    console.log(e)
+  }
+}
+
+svr.registerRenderer = (r) => {
+  svr.renderer = r
+}
+
+module.exports = svr

+ 1 - 1
app/version.js

@@ -1 +1 @@
-exports.version = [3,3,0,4412];
+exports.version = [3,3,0,4497];

+ 14 - 2
ui/app.js

@@ -23,7 +23,8 @@ export default class App extends React.Component {
       list: [], // 用户的 hosts 列表
       sys_hosts: {}, // 系统 hosts
       current: {}, // 当前 hosts
-      lang: {} // 语言
+      lang: {}, // 语言
+      just_added_id: null
     }
 
     this.loadHosts()
@@ -98,6 +99,12 @@ export default class App extends React.Component {
     this.toSave()
   }
 
+  justAdd(id) {
+    this.setState({
+      just_added_id: id
+    })
+  }
+
   componentDidMount () {
     window.addEventListener('keydown', (e) => {
       if (e.keyCode === 27) {
@@ -116,6 +123,8 @@ export default class App extends React.Component {
           current={current}
           setCurrent={this.setCurrent.bind(this)}
           lang={this.state.lang}
+          just_added_id={this.state.just_added_id}
+          justAdd={this.justAdd.bind(this)}
         />
         <Content
           current={current}
@@ -125,7 +134,10 @@ export default class App extends React.Component {
         />
         <div className="frames">
           <SudoPrompt lang={this.state.lang}/>
-          <EditPrompt lang={this.state.lang} list={this.state.list}/>
+          <EditPrompt lang={this.state.lang}
+                      list={this.state.list}
+                      justAdd={this.justAdd.bind(this)}
+          />
           {/*<PreferencesPrompt/>*/}
         </div>
       </div>

+ 3 - 5
ui/events/list_updated.js

@@ -13,14 +13,12 @@ module.exports = (app, new_list, hosts = null) => {
     .then(sys_hosts => {
       state.sys_hosts = sys_hosts
 
+      if (hosts) {
+        state.current = hosts
+      }
       let current = app.state.current
       if (current.is_sys) {
         state.current = sys_hosts
-      } else {
-        let item = new_list.find(i => i.id === current.id)
-        if (item) {
-          state.current = item
-        }
       }
 
       app.setState(state, () => {

+ 6 - 2
ui/frame/edit.js

@@ -115,14 +115,18 @@ export default class EditPrompt extends React.Component {
       return false
     }
 
+    let new_id = makeId()
     let data = Object.assign({}, this.current_hosts, this.state,
       this.state.is_add ? {
-        id: makeId(),
+        id: new_id,
         content: `# ${this.state.title}`,
         on: false
       } : {})
 
-    if (!data.id) data.id = makeId()
+    if (!data.id) data.id = new_id
+    if (this.state.is_add) {
+      this.props.justAdd(new_id)
+    }
 
     delete data['is_add']
     Agent.emit('update_hosts', data)

+ 1 - 1
ui/package.json

@@ -14,6 +14,6 @@
     "react": "^15.4.2",
     "react-dom": "^15.4.2",
     "sortablejs": "^1.5.1",
-    "wheel-js": "0.0.4"
+    "wheel-js": "0.0.5"
   }
 }

+ 13 - 2
ui/panel/list-item.js

@@ -8,6 +8,7 @@
 import React from 'react'
 import classnames from 'classnames'
 import Agent from '../Agent'
+import isInViewport from 'wheel-js/src/browser/isInViewport'
 import './list-item.less'
 
 export default class ListItem extends React.Component {
@@ -16,7 +17,6 @@ export default class ListItem extends React.Component {
 
     this.is_sys = !!this.props.sys
     this.state = {}
-
   }
 
   getTitle () {
@@ -38,19 +38,30 @@ export default class ListItem extends React.Component {
   }
 
   componentDidMount () {
+    let {just_added_id, data} = this.props
     //Agent.on('select_hosts', id => {
     //  if (id && id === this.props.data.id) {
     //    this.beSelected()
     //    this.el && this.el.scrollIntoView()
     //  }
     //})
+
+    if (!this.el) {
+      return
+    }
+
+    let el = this.el
+    if (just_added_id === data.id && !isInViewport(el)) {
+      el.scrollIntoView()
+      this.props.justAdd(null)
+    }
   }
 
   render () {
     let {data, sys, current, show} = this.props
     if (!data) return null
 
-    let is_selected = data.id === current.id
+    let is_selected = data.id === current.id || (data.is_sys && current.is_sys)
     let attrs = {
       'data-id': data.id || ''
     }

+ 2 - 2
ui/panel/list-item.less

@@ -10,10 +10,10 @@
 
     &.sys-hosts {
       font-size: 14px;
-      padding: 8px 10px 8px 12px;
+      padding: 8px 10px 8px 13px;
 
       i {
-        width: 23px;
+        width: 22px;
       }
     }
 

+ 2 - 6
ui/panel/list.js

@@ -44,11 +44,9 @@ export default class List extends React.Component {
         <ListItem
           data={item}
           idx={idx}
-          current={this.props.current}
-          setCurrent={this.props.setCurrent}
-          lang={this.props.lang}
           key={'hosts-' + idx + Math.random()}
           show={show}
+          {...this.props}
         />
       )
     })
@@ -84,9 +82,7 @@ export default class List extends React.Component {
       <div id="sh-list">
         <ListItem
           data={this.props.sys_hosts}
-          lang={this.props.lang}
-          current={this.props.current}
-          setCurrent={this.props.setCurrent}
+          {...this.props}
           sys="1"/>
         <div ref="items" className="custom-items">
           {this.customItems()}

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