2015-08-15 06:40:11 +08:00
|
|
|
React = require 'react'
|
|
|
|
_ = require 'underscore'
|
|
|
|
path = require 'path'
|
|
|
|
fs = require 'fs'
|
|
|
|
{RetinaImg, Flexbox} = require 'nylas-component-kit'
|
|
|
|
|
|
|
|
DisplayedKeybindings = [
|
2015-12-02 10:31:12 +08:00
|
|
|
{
|
|
|
|
title: 'Application',
|
|
|
|
items: [
|
|
|
|
['application:new-message', 'New Message'],
|
|
|
|
['application:focus-search', 'Search'],
|
|
|
|
]
|
|
|
|
},
|
|
|
|
{
|
|
|
|
title: 'Actions',
|
|
|
|
items: [
|
|
|
|
['application:reply', 'Reply'],
|
|
|
|
['application:reply-all', 'Reply All'],
|
|
|
|
['application:forward', 'Forward'],
|
|
|
|
['application:archive-item', 'Archive'],
|
|
|
|
['application:delete-item', 'Trash'],
|
|
|
|
['core:remove-from-view', 'Remove from view'],
|
|
|
|
['application:star-item', 'Star'],
|
|
|
|
['application:change-category', 'Change Folder / Labels'],
|
|
|
|
['application:mark-as-read', 'Mark as read'],
|
|
|
|
['application:mark-as-unread', 'Mark as unread'],
|
|
|
|
['application:mark-important', 'Mark as important (Gmail)'],
|
|
|
|
['application:mark-unimportant', 'Mark as unimportant (Gmail)'],
|
|
|
|
['application:remove-and-previous', 'Remove from view and previous'],
|
|
|
|
['application:remove-and-next', 'Remove from view and next'],
|
|
|
|
]
|
|
|
|
},
|
|
|
|
{
|
|
|
|
title: 'Navigation',
|
|
|
|
items: [
|
|
|
|
['application:pop-sheet', 'Return to conversation list'],
|
|
|
|
['core:focus-item', 'Open selected conversation'],
|
|
|
|
['core:previous-item', 'Move to newer conversation'],
|
|
|
|
['core:next-item', 'Move to older conversation'],
|
|
|
|
]
|
|
|
|
},
|
|
|
|
{
|
|
|
|
title: 'Selection',
|
|
|
|
items: [
|
|
|
|
['core:select-item', 'Select conversation'],
|
|
|
|
['multiselect-list:select-all', 'Select all conversations'],
|
|
|
|
['multiselect-list:deselect-all', 'Deselect all conversations'],
|
|
|
|
['thread-list:select-read', 'Select all read conversations'],
|
|
|
|
['thread-list:select-unread', 'Select all unread conversations'],
|
|
|
|
['thread-list:select-starred', 'Select all starred conversations'],
|
|
|
|
['thread-list:select-unstarred', 'Select all unstarred conversations'],
|
|
|
|
]
|
|
|
|
},
|
|
|
|
{
|
|
|
|
title: 'Jumping',
|
|
|
|
items: [
|
|
|
|
['navigation:go-to-inbox', 'Go to "Inbox"'],
|
|
|
|
['navigation:go-to-starred', 'Go to "Starred"'],
|
|
|
|
['navigation:go-to-sent', 'Go to "Sent Mail"'],
|
|
|
|
['navigation:go-to-drafts', 'Go to "Drafts"'],
|
|
|
|
['navigation:go-to-all', 'Go to "All Mail"'],
|
|
|
|
]
|
|
|
|
}
|
2015-08-15 06:40:11 +08:00
|
|
|
]
|
|
|
|
|
|
|
|
class PreferencesKeymaps extends React.Component
|
|
|
|
@displayName: 'PreferencesKeymaps'
|
|
|
|
|
|
|
|
constructor: (@props) ->
|
|
|
|
@state =
|
|
|
|
templates: []
|
|
|
|
bindings: @_getStateFromKeymaps()
|
|
|
|
@_loadTemplates()
|
|
|
|
|
|
|
|
componentDidMount: =>
|
2015-11-12 02:25:11 +08:00
|
|
|
@_disposable = NylasEnv.keymaps.onDidReloadKeymap =>
|
2015-08-15 06:40:11 +08:00
|
|
|
@setState(bindings: @_getStateFromKeymaps())
|
|
|
|
|
|
|
|
componentWillUnmount: =>
|
2015-11-12 02:20:48 +08:00
|
|
|
@_disposable.dispose()
|
2015-08-15 06:40:11 +08:00
|
|
|
|
|
|
|
_loadTemplates: =>
|
2015-11-12 02:25:11 +08:00
|
|
|
templatesDir = path.join(NylasEnv.getLoadSettings().resourcePath, 'keymaps', 'templates')
|
2015-08-15 06:40:11 +08:00
|
|
|
fs.readdir templatesDir, (err, files) =>
|
|
|
|
return unless files and files instanceof Array
|
|
|
|
templates = files.filter (filename) =>
|
2015-08-19 05:50:53 +08:00
|
|
|
path.extname(filename) is '.cson' or path.extname(filename) is '.json'
|
|
|
|
templates = templates.map (filename) =>
|
|
|
|
path.parse(filename).name
|
2015-08-15 06:40:11 +08:00
|
|
|
@setState(templates: templates)
|
|
|
|
|
|
|
|
_getStateFromKeymaps: =>
|
|
|
|
bindings = {}
|
2015-12-02 10:31:12 +08:00
|
|
|
for section in DisplayedKeybindings
|
|
|
|
for [command, label] in section.items
|
|
|
|
bindings[command] = NylasEnv.keymaps.findKeyBindings(command: command, target: document.body) || []
|
2015-08-15 06:40:11 +08:00
|
|
|
bindings
|
|
|
|
|
|
|
|
render: =>
|
|
|
|
<div className="container-keymaps">
|
2015-11-24 04:20:51 +08:00
|
|
|
<section>
|
|
|
|
<h2>Shortcuts</h2>
|
2015-12-02 10:31:12 +08:00
|
|
|
<Flexbox className="shortcut-presets">
|
|
|
|
<div className="col-left">Keyboard shortcut set:</div>
|
|
|
|
<div className="col-right">
|
2015-11-24 04:20:51 +08:00
|
|
|
<select
|
|
|
|
style={margin:0}
|
|
|
|
value={@props.config.get('core.keymapTemplate')}
|
|
|
|
onChange={ (event) => @props.config.set('core.keymapTemplate', event.target.value) }>
|
|
|
|
{ @state.templates.map (template) =>
|
|
|
|
<option key={template} value={template}>{template}</option>
|
|
|
|
}
|
|
|
|
</select>
|
|
|
|
</div>
|
|
|
|
</Flexbox>
|
2015-12-02 10:31:12 +08:00
|
|
|
{
|
|
|
|
DisplayedKeybindings.map(@_renderBindingsSection)
|
|
|
|
}
|
2015-11-24 04:20:51 +08:00
|
|
|
</section>
|
|
|
|
<section>
|
|
|
|
<h2>Customization</h2>
|
|
|
|
<p>Define additional shortcuts by adding them to your shortcuts file.</p>
|
2015-08-15 06:40:11 +08:00
|
|
|
<button className="btn" onClick={@_onShowUserKeymaps}>Edit custom shortcuts</button>
|
2015-11-24 04:20:51 +08:00
|
|
|
</section>
|
2015-08-15 06:40:11 +08:00
|
|
|
</div>
|
|
|
|
|
2015-12-02 10:31:12 +08:00
|
|
|
_renderBindingsSection: (section) =>
|
|
|
|
<section>
|
|
|
|
<div className="shortcut-section-title">{section.title}</div>
|
|
|
|
{
|
|
|
|
section.items.map(@_renderBindingFor)
|
|
|
|
}
|
|
|
|
</section>
|
|
|
|
|
2015-08-15 06:40:11 +08:00
|
|
|
_renderBindingFor: ([command, label]) =>
|
2015-08-15 07:41:52 +08:00
|
|
|
descriptions = []
|
2015-08-15 06:40:11 +08:00
|
|
|
if @state.bindings[command]
|
2015-08-15 07:41:52 +08:00
|
|
|
for binding in @state.bindings[command]
|
2015-12-02 10:31:12 +08:00
|
|
|
descriptions.push(binding.keystrokes)
|
2015-08-15 07:41:52 +08:00
|
|
|
|
|
|
|
if descriptions.length is 0
|
|
|
|
value = 'None'
|
|
|
|
else
|
2015-12-02 10:31:12 +08:00
|
|
|
value = _.uniq(descriptions).map(@_renderKeystrokes)
|
2015-08-15 06:40:11 +08:00
|
|
|
|
|
|
|
<Flexbox className="shortcut" key={command}>
|
2015-12-02 10:31:12 +08:00
|
|
|
<div className="col-left shortcut-name">{label}</div>
|
|
|
|
<div className="col-right">{value}</div>
|
2015-08-15 06:40:11 +08:00
|
|
|
</Flexbox>
|
|
|
|
|
2015-12-02 10:31:12 +08:00
|
|
|
_renderKeystrokes: (keystrokes) =>
|
|
|
|
elements = []
|
|
|
|
keystrokes = keystrokes.split(' ')
|
|
|
|
|
|
|
|
for keystroke, idx in keystrokes
|
|
|
|
elements.push <span>{@_formatKeystrokes(keystroke)}</span>
|
|
|
|
elements.push <span className="then"> then </span> unless idx is keystrokes.length - 1
|
|
|
|
|
|
|
|
<span className="shortcut-value">{elements}</span>
|
2015-08-15 06:40:11 +08:00
|
|
|
|
2015-12-02 10:31:12 +08:00
|
|
|
_formatKeystrokes: (original) =>
|
2015-08-15 07:41:52 +08:00
|
|
|
if process.platform is 'win32'
|
|
|
|
# On Windows, display cmd-shift-c
|
2015-12-02 10:31:12 +08:00
|
|
|
return original
|
|
|
|
|
2015-08-15 07:41:52 +08:00
|
|
|
else
|
2015-12-02 10:31:12 +08:00
|
|
|
# Replace "cmd" => ⌘, etc.
|
|
|
|
modifiers = [[/-(?!$)/gi,''], [/cmd/gi, '⌘'], [/alt/gi, '⌥'], [/shift/gi, '⇧'], [/ctrl/gi, '^']]
|
|
|
|
clean = original
|
|
|
|
for [regexp, char] in modifiers
|
|
|
|
clean = clean.replace(regexp, char)
|
|
|
|
|
|
|
|
# ⌘⇧c => ⌘⇧C
|
|
|
|
if clean isnt original
|
|
|
|
clean = clean.toUpperCase()
|
|
|
|
|
|
|
|
# backspace => Backspace
|
|
|
|
if original.length > 1 and clean is original
|
|
|
|
clean = clean[0].toUpperCase() + clean[1..-1]
|
|
|
|
return clean
|
2015-08-15 07:41:52 +08:00
|
|
|
|
2015-08-15 06:40:11 +08:00
|
|
|
_onShowUserKeymaps: =>
|
2015-11-12 02:25:11 +08:00
|
|
|
keymapsFile = NylasEnv.keymaps.getUserKeymapPath()
|
2015-11-07 10:55:33 +08:00
|
|
|
if !fs.existsSync(keymapsFile)
|
|
|
|
fs.writeSync(fs.openSync(keymapsFile, 'w'), '')
|
|
|
|
require('shell').showItemInFolder(keymapsFile)
|
2015-08-15 06:40:11 +08:00
|
|
|
|
|
|
|
module.exports = PreferencesKeymaps
|