mirror of
https://github.com/BoostIo/Boostnote
synced 2025-12-15 02:36:36 +00:00
ModeSelect
This commit is contained in:
@@ -1,5 +1,7 @@
|
||||
import React from 'react'
|
||||
import ReactDOM from 'react-dom'
|
||||
import modes from 'boost/vars/modes'
|
||||
import _ from 'lodash'
|
||||
var ace = window.ace
|
||||
|
||||
module.exports = React.createClass({
|
||||
@@ -32,11 +34,12 @@ module.exports = React.createClass({
|
||||
editor.setReadOnly(!!this.props.readOnly)
|
||||
|
||||
var session = editor.getSession()
|
||||
if (this.props.mode != null && this.props.mode.length > 0) {
|
||||
session.setMode('ace/mode/' + this.props.mode)
|
||||
} else {
|
||||
session.setMode('ace/mode/text')
|
||||
}
|
||||
let mode = _.findWhere(modes, {name: this.props.mode})
|
||||
let syntaxMode = mode != null
|
||||
? mode.mode
|
||||
: 'text'
|
||||
session.setMode('ace/mode/' + syntaxMode)
|
||||
|
||||
session.setUseSoftTabs(true)
|
||||
session.setOption('useWorker', false)
|
||||
session.setUseWrapMode(true)
|
||||
@@ -57,11 +60,11 @@ module.exports = React.createClass({
|
||||
}
|
||||
if (prevProps.mode !== this.props.mode) {
|
||||
var session = this.state.editor.getSession()
|
||||
if (this.props.mode != null && this.props.mode.length > 0) {
|
||||
session.setMode('ace/mode/' + this.props.mode)
|
||||
} else {
|
||||
session.setMode('ace/mode/text')
|
||||
}
|
||||
let mode = _.findWhere(modes, {name: this.props.mode})
|
||||
let syntaxMode = mode != null
|
||||
? mode.mode
|
||||
: 'text'
|
||||
session.setMode('ace/mode/' + syntaxMode)
|
||||
}
|
||||
},
|
||||
render: function () {
|
||||
|
||||
@@ -32,8 +32,10 @@ export default class ModeIcon extends React.Component {
|
||||
return 'devicon-sass-original'
|
||||
|
||||
// Compile
|
||||
case 'c_cpp':
|
||||
case 'c':
|
||||
return 'devicon-c-plain'
|
||||
case 'cpp':
|
||||
return 'devicon-cplusplus-plain'
|
||||
case 'csharp':
|
||||
return 'devicon-csharp-plain'
|
||||
case 'objc':
|
||||
@@ -60,7 +62,6 @@ export default class ModeIcon extends React.Component {
|
||||
return 'fa fa-fw fa-terminal'
|
||||
|
||||
case 'text':
|
||||
case 'plain_text':
|
||||
case 'markdown':
|
||||
return 'fa fa-fw fa-file-text-o'
|
||||
}
|
||||
@@ -68,9 +69,9 @@ export default class ModeIcon extends React.Component {
|
||||
}
|
||||
|
||||
render () {
|
||||
var className = this.getClassName()
|
||||
let className = `ModeIcon ${this.getClassName()} ${this.props.className}`
|
||||
return (
|
||||
<i className={this.props.className + ' ' + className}/>
|
||||
<i className={className}/>
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
190
lib/components/ModeSelect.js
Normal file
190
lib/components/ModeSelect.js
Normal file
@@ -0,0 +1,190 @@
|
||||
import React, { PropTypes } from 'react'
|
||||
import ReactDOM from 'react-dom'
|
||||
import ModeIcon from 'boost/components/ModeIcon'
|
||||
import modes from 'boost/vars/modes'
|
||||
import _ from 'lodash'
|
||||
|
||||
const IDLE_MODE = 'IDLE_MODE'
|
||||
const EDIT_MODE = 'EDIT_MODE'
|
||||
|
||||
export default class ModeSelect extends React.Component {
|
||||
constructor (props) {
|
||||
super(props)
|
||||
|
||||
this.state = {
|
||||
mode: IDLE_MODE,
|
||||
search: '',
|
||||
focusIndex: 0
|
||||
}
|
||||
}
|
||||
|
||||
componentDidMount (e) {
|
||||
this.blurHandler = e => {
|
||||
let searchElement = ReactDOM.findDOMNode(this.refs.search)
|
||||
if (this.state.mode === EDIT_MODE && document.activeElement !== searchElement) {
|
||||
this.handleBlur()
|
||||
}
|
||||
}
|
||||
window.addEventListener('click', this.blurHandler)
|
||||
}
|
||||
|
||||
componentWillUnmount (e) {
|
||||
window.removeEventListener('click', this.blurHandler)
|
||||
let searchElement = ReactDOM.findDOMNode(this.refs.search)
|
||||
if (searchElement != null && this.searchKeyDownListener != null) {
|
||||
searchElement.removeEventListener('keydown', this.searchKeyDownListener)
|
||||
}
|
||||
}
|
||||
|
||||
handleIdleSelectClick (e) {
|
||||
this.setState({mode: EDIT_MODE})
|
||||
}
|
||||
|
||||
componentDidUpdate (prevProps, prevState) {
|
||||
if (prevState.mode !== this.state.mode && this.state.mode === EDIT_MODE) {
|
||||
let searchElement = ReactDOM.findDOMNode(this.refs.search)
|
||||
searchElement.focus()
|
||||
if (this.searchKeyDownListener == null) {
|
||||
this.searchKeyDownListener = e => this.handleSearchKeyDown
|
||||
}
|
||||
searchElement.addEventListener('keydown', this.searchKeyDownListener)
|
||||
}
|
||||
}
|
||||
|
||||
componentWillUpdate (nextProps, nextState) {
|
||||
if (nextProps.mode !== this.state.mode && nextState.mode === IDLE_MODE) {
|
||||
let searchElement = ReactDOM.findDOMNode(this.refs.search)
|
||||
if (searchElement != null && this.searchKeyDownListener != null) {
|
||||
searchElement.removeEventListener('keydown', this.searchKeyDownListener)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
handleModeOptionClick (modeName) {
|
||||
return e => {
|
||||
this.props.onChange(modeName)
|
||||
this.setState({
|
||||
mode: IDLE_MODE,
|
||||
search: '',
|
||||
focusIndex: 0
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
handleSearchKeyDown (e) {
|
||||
switch (e.keyCode) {
|
||||
// up
|
||||
case 38:
|
||||
e.preventDefault()
|
||||
if (this.state.focusIndex > 0) this.setState({focusIndex: this.state.focusIndex - 1})
|
||||
break
|
||||
// down
|
||||
case 40:
|
||||
e.preventDefault()
|
||||
{
|
||||
let filteredModes = modes
|
||||
.filter(mode => {
|
||||
let search = this.state.search
|
||||
let nameMatched = mode.name.match(search)
|
||||
let aliasMatched = _.some(mode.alias, alias => alias.match(search))
|
||||
return nameMatched || aliasMatched
|
||||
})
|
||||
if (filteredModes.length === this.state.focusIndex + 1) this.setState({focusIndex: filteredModes.length - 1})
|
||||
else this.setState({focusIndex: this.state.focusIndex + 1})
|
||||
}
|
||||
break
|
||||
// enter
|
||||
case 13:
|
||||
e.preventDefault()
|
||||
{
|
||||
let filteredModes = modes
|
||||
.filter(mode => {
|
||||
let search = this.state.search
|
||||
let nameMatched = mode.name.match(search)
|
||||
let aliasMatched = _.some(mode.alias, alias => alias.match(search))
|
||||
return nameMatched || aliasMatched
|
||||
})
|
||||
let targetMode = filteredModes[this.state.focusIndex]
|
||||
if (targetMode != null) {
|
||||
this.props.onChange(targetMode.name)
|
||||
this.handleBlur()
|
||||
}
|
||||
}
|
||||
break
|
||||
// esc
|
||||
case 27:
|
||||
e.preventDefault()
|
||||
e.stopPropagation()
|
||||
this.handleBlur()
|
||||
break
|
||||
case 9:
|
||||
this.handleBlur()
|
||||
}
|
||||
}
|
||||
|
||||
handleSearchChange (e) {
|
||||
this.setState({
|
||||
search: e.target.value,
|
||||
focusIndex: 0
|
||||
})
|
||||
}
|
||||
|
||||
handleBlur () {
|
||||
if (this.state.mode === EDIT_MODE) {
|
||||
this.setState({
|
||||
mode: IDLE_MODE,
|
||||
search: '',
|
||||
focusIndex: 0
|
||||
})
|
||||
}
|
||||
if (this.props.onBlur != null) this.props.onBlur()
|
||||
}
|
||||
|
||||
render () {
|
||||
let className = this.props.className != null
|
||||
? `ModeSelect ${this.props.className}`
|
||||
: this.props.className
|
||||
|
||||
if (this.state.mode === IDLE_MODE) {
|
||||
let mode = _.findWhere(modes, {name: this.props.value})
|
||||
let modeName = mode != null ? mode.name : 'text'
|
||||
let modeLabel = mode != null ? mode.label : 'Plain text'
|
||||
|
||||
return (
|
||||
<div className={className + ' idle'} onClick={e => this.handleIdleSelectClick(e)}>
|
||||
<ModeIcon mode={modeName}/>
|
||||
<span className='modeLabel'>{modeLabel}</span>
|
||||
</div>
|
||||
)
|
||||
}
|
||||
|
||||
let filteredOptions = modes
|
||||
.filter(mode => {
|
||||
let search = this.state.search
|
||||
let nameMatched = mode.name.match(search)
|
||||
let aliasMatched = _.some(mode.alias, alias => alias.match(search))
|
||||
return nameMatched || aliasMatched
|
||||
})
|
||||
.map((mode, index) => {
|
||||
return (
|
||||
<div key={mode.name} className={index === this.state.focusIndex ? 'option active' : 'option'} onClick={e => this.handleModeOptionClick(mode.name)(e)}><ModeIcon mode={mode.name}/>{mode.label}</div>
|
||||
)
|
||||
})
|
||||
|
||||
return (
|
||||
<div className={className + ' edit'}>
|
||||
<input onKeyDown={e => this.handleSearchKeyDown(e)} ref='search' onChange={e => this.handleSearchChange(e)} value={this.state.search} type='text'/>
|
||||
<div ref='options' className='modeOptions hide'>
|
||||
{filteredOptions}
|
||||
</div>
|
||||
</div>
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
ModeSelect.propTypes = {
|
||||
className: PropTypes.string,
|
||||
value: PropTypes.string,
|
||||
onChange: PropTypes.func,
|
||||
onBlur: PropTypes.func
|
||||
}
|
||||
Reference in New Issue
Block a user