mirror of
https://github.com/BoostIo/Boostnote
synced 2025-12-15 18:56:22 +00:00
fixed eslint error & integrated with prettier as well as formatted the whole codebase (#3450)
This commit is contained in:
@@ -10,7 +10,7 @@ import AwsMobileAnalyticsConfig from 'browser/main/lib/AwsMobileAnalyticsConfig'
|
||||
import i18n from 'browser/lib/i18n'
|
||||
|
||||
class CreateFolderModal extends React.Component {
|
||||
constructor (props) {
|
||||
constructor(props) {
|
||||
super(props)
|
||||
|
||||
this.state = {
|
||||
@@ -18,39 +18,39 @@ class CreateFolderModal extends React.Component {
|
||||
}
|
||||
}
|
||||
|
||||
componentDidMount () {
|
||||
componentDidMount() {
|
||||
this.refs.name.focus()
|
||||
this.refs.name.select()
|
||||
}
|
||||
|
||||
handleCloseButtonClick (e) {
|
||||
handleCloseButtonClick(e) {
|
||||
this.props.close()
|
||||
}
|
||||
|
||||
handleChange (e) {
|
||||
handleChange(e) {
|
||||
this.setState({
|
||||
name: this.refs.name.value
|
||||
})
|
||||
}
|
||||
|
||||
handleKeyDown (e) {
|
||||
handleKeyDown(e) {
|
||||
if (e.keyCode === 27) {
|
||||
this.props.close()
|
||||
}
|
||||
}
|
||||
|
||||
handleInputKeyDown (e) {
|
||||
handleInputKeyDown(e) {
|
||||
switch (e.keyCode) {
|
||||
case 13:
|
||||
this.confirm()
|
||||
}
|
||||
}
|
||||
|
||||
handleConfirmButtonClick (e) {
|
||||
handleConfirmButtonClick(e) {
|
||||
this.confirm()
|
||||
}
|
||||
|
||||
confirm () {
|
||||
confirm() {
|
||||
AwsMobileAnalyticsConfig.recordDynamicCustomEvent('ADD_FOLDER')
|
||||
if (this.state.name.trim().length > 0) {
|
||||
const { storage } = this.props
|
||||
@@ -59,42 +59,48 @@ class CreateFolderModal extends React.Component {
|
||||
color: consts.FOLDER_COLORS[Math.floor(Math.random() * 7) % 7]
|
||||
}
|
||||
|
||||
dataApi.createFolder(storage.key, input)
|
||||
.then((data) => {
|
||||
dataApi
|
||||
.createFolder(storage.key, input)
|
||||
.then(data => {
|
||||
store.dispatch({
|
||||
type: 'UPDATE_FOLDER',
|
||||
storage: data.storage
|
||||
})
|
||||
this.props.close()
|
||||
})
|
||||
.catch((err) => {
|
||||
.catch(err => {
|
||||
console.error(err)
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
render () {
|
||||
render() {
|
||||
return (
|
||||
<div styleName='root'
|
||||
<div
|
||||
styleName='root'
|
||||
tabIndex='-1'
|
||||
onKeyDown={(e) => this.handleKeyDown(e)}
|
||||
onKeyDown={e => this.handleKeyDown(e)}
|
||||
>
|
||||
<div styleName='header'>
|
||||
<div styleName='title'>{i18n.__('Create new folder')}</div>
|
||||
</div>
|
||||
<ModalEscButton handleEscButtonClick={(e) => this.handleCloseButtonClick(e)} />
|
||||
<ModalEscButton
|
||||
handleEscButtonClick={e => this.handleCloseButtonClick(e)}
|
||||
/>
|
||||
<div styleName='control'>
|
||||
<div styleName='control-folder'>
|
||||
<div styleName='control-folder-label'>{i18n.__('Folder name')}</div>
|
||||
<input styleName='control-folder-input'
|
||||
<input
|
||||
styleName='control-folder-input'
|
||||
ref='name'
|
||||
value={this.state.name}
|
||||
onChange={(e) => this.handleChange(e)}
|
||||
onKeyDown={(e) => this.handleInputKeyDown(e)}
|
||||
onChange={e => this.handleChange(e)}
|
||||
onKeyDown={e => this.handleInputKeyDown(e)}
|
||||
/>
|
||||
</div>
|
||||
<button styleName='control-confirmButton'
|
||||
onClick={(e) => this.handleConfirmButtonClick(e)}
|
||||
<button
|
||||
styleName='control-confirmButton'
|
||||
onClick={e => this.handleConfirmButtonClick(e)}
|
||||
>
|
||||
{i18n.__('Create')}
|
||||
</button>
|
||||
|
||||
@@ -7,7 +7,7 @@ import ModalEscButton from 'browser/components/ModalEscButton'
|
||||
import i18n from 'browser/lib/i18n'
|
||||
|
||||
class CreateMarkdownFromURLModal extends React.Component {
|
||||
constructor (props) {
|
||||
constructor(props) {
|
||||
super(props)
|
||||
|
||||
this.state = {
|
||||
@@ -17,89 +17,101 @@ class CreateMarkdownFromURLModal extends React.Component {
|
||||
}
|
||||
}
|
||||
|
||||
componentDidMount () {
|
||||
componentDidMount() {
|
||||
this.refs.name.focus()
|
||||
this.refs.name.select()
|
||||
}
|
||||
|
||||
handleCloseButtonClick (e) {
|
||||
handleCloseButtonClick(e) {
|
||||
this.props.close()
|
||||
}
|
||||
|
||||
handleChange (e) {
|
||||
handleChange(e) {
|
||||
this.setState({
|
||||
name: this.refs.name.value
|
||||
})
|
||||
}
|
||||
|
||||
handleKeyDown (e) {
|
||||
handleKeyDown(e) {
|
||||
if (e.keyCode === 27) {
|
||||
this.props.close()
|
||||
}
|
||||
}
|
||||
|
||||
handleInputKeyDown (e) {
|
||||
handleInputKeyDown(e) {
|
||||
switch (e.keyCode) {
|
||||
case 13:
|
||||
this.confirm()
|
||||
}
|
||||
}
|
||||
|
||||
handleConfirmButtonClick (e) {
|
||||
handleConfirmButtonClick(e) {
|
||||
this.confirm()
|
||||
}
|
||||
|
||||
showError (message) {
|
||||
showError(message) {
|
||||
this.setState({
|
||||
showerror: true,
|
||||
errormessage: message
|
||||
})
|
||||
}
|
||||
|
||||
hideError () {
|
||||
hideError() {
|
||||
this.setState({
|
||||
showerror: false,
|
||||
errormessage: ''
|
||||
})
|
||||
}
|
||||
|
||||
confirm () {
|
||||
confirm() {
|
||||
this.hideError()
|
||||
const { storage, folder, dispatch, location } = this.props
|
||||
|
||||
dataApi.createNoteFromUrl(this.state.name, storage, folder, dispatch, location).then((result) => {
|
||||
this.props.close()
|
||||
}).catch((result) => {
|
||||
this.showError(result.error)
|
||||
})
|
||||
dataApi
|
||||
.createNoteFromUrl(this.state.name, storage, folder, dispatch, location)
|
||||
.then(result => {
|
||||
this.props.close()
|
||||
})
|
||||
.catch(result => {
|
||||
this.showError(result.error)
|
||||
})
|
||||
}
|
||||
|
||||
render () {
|
||||
render() {
|
||||
return (
|
||||
<div styleName='root'
|
||||
<div
|
||||
styleName='root'
|
||||
tabIndex='-1'
|
||||
onKeyDown={(e) => this.handleKeyDown(e)}
|
||||
onKeyDown={e => this.handleKeyDown(e)}
|
||||
>
|
||||
<div styleName='header'>
|
||||
<div styleName='title'>{i18n.__('Import Markdown From URL')}</div>
|
||||
</div>
|
||||
<ModalEscButton handleEscButtonClick={(e) => this.handleCloseButtonClick(e)} />
|
||||
<ModalEscButton
|
||||
handleEscButtonClick={e => this.handleCloseButtonClick(e)}
|
||||
/>
|
||||
<div styleName='control'>
|
||||
<div styleName='control-folder'>
|
||||
<div styleName='control-folder-label'>{i18n.__('Insert URL Here')}</div>
|
||||
<input styleName='control-folder-input'
|
||||
<div styleName='control-folder-label'>
|
||||
{i18n.__('Insert URL Here')}
|
||||
</div>
|
||||
<input
|
||||
styleName='control-folder-input'
|
||||
ref='name'
|
||||
value={this.state.name}
|
||||
onChange={(e) => this.handleChange(e)}
|
||||
onKeyDown={(e) => this.handleInputKeyDown(e)}
|
||||
onChange={e => this.handleChange(e)}
|
||||
onKeyDown={e => this.handleInputKeyDown(e)}
|
||||
/>
|
||||
</div>
|
||||
<button styleName='control-confirmButton'
|
||||
onClick={(e) => this.handleConfirmButtonClick(e)}
|
||||
<button
|
||||
styleName='control-confirmButton'
|
||||
onClick={e => this.handleConfirmButtonClick(e)}
|
||||
>
|
||||
{i18n.__('Import')}
|
||||
</button>
|
||||
<div className='error' styleName='error'>{this.state.errormessage}</div>
|
||||
<div className='error' styleName='error'>
|
||||
{this.state.errormessage}
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
)
|
||||
|
||||
@@ -9,21 +9,21 @@ import { createMarkdownNote, createSnippetNote } from 'browser/lib/newNote'
|
||||
import queryString from 'query-string'
|
||||
|
||||
class NewNoteModal extends React.Component {
|
||||
constructor (props) {
|
||||
constructor(props) {
|
||||
super(props)
|
||||
this.lock = false
|
||||
this.state = {}
|
||||
}
|
||||
|
||||
componentDidMount () {
|
||||
componentDidMount() {
|
||||
this.refs.markdownButton.focus()
|
||||
}
|
||||
|
||||
handleCloseButtonClick (e) {
|
||||
handleCloseButtonClick(e) {
|
||||
this.props.close()
|
||||
}
|
||||
|
||||
handleCreateMarkdownFromUrlClick (e) {
|
||||
handleCreateMarkdownFromUrlClick(e) {
|
||||
this.props.close()
|
||||
|
||||
const { storage, folder, dispatch, location } = this.props
|
||||
@@ -35,49 +35,63 @@ class NewNoteModal extends React.Component {
|
||||
})
|
||||
}
|
||||
|
||||
handleMarkdownNoteButtonClick (e) {
|
||||
handleMarkdownNoteButtonClick(e) {
|
||||
const { storage, folder, dispatch, location, config } = this.props
|
||||
const params = location.search !== '' && queryString.parse(location.search)
|
||||
if (!this.lock) {
|
||||
this.lock = true
|
||||
createMarkdownNote(storage, folder, dispatch, location, params, config).then(() => {
|
||||
createMarkdownNote(
|
||||
storage,
|
||||
folder,
|
||||
dispatch,
|
||||
location,
|
||||
params,
|
||||
config
|
||||
).then(() => {
|
||||
setTimeout(this.props.close, 200)
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
handleMarkdownNoteButtonKeyDown (e) {
|
||||
handleMarkdownNoteButtonKeyDown(e) {
|
||||
if (e.keyCode === 9) {
|
||||
e.preventDefault()
|
||||
this.refs.snippetButton.focus()
|
||||
}
|
||||
}
|
||||
|
||||
handleSnippetNoteButtonClick (e) {
|
||||
handleSnippetNoteButtonClick(e) {
|
||||
const { storage, folder, dispatch, location, config } = this.props
|
||||
const params = location.search !== '' && queryString.parse(location.search)
|
||||
if (!this.lock) {
|
||||
this.lock = true
|
||||
createSnippetNote(storage, folder, dispatch, location, params, config).then(() => {
|
||||
createSnippetNote(
|
||||
storage,
|
||||
folder,
|
||||
dispatch,
|
||||
location,
|
||||
params,
|
||||
config
|
||||
).then(() => {
|
||||
setTimeout(this.props.close, 200)
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
handleSnippetNoteButtonKeyDown (e) {
|
||||
handleSnippetNoteButtonKeyDown(e) {
|
||||
if (e.keyCode === 9) {
|
||||
e.preventDefault()
|
||||
this.refs.markdownButton.focus()
|
||||
}
|
||||
}
|
||||
|
||||
handleKeyDown (e) {
|
||||
handleKeyDown(e) {
|
||||
if (e.keyCode === 27) {
|
||||
this.props.close()
|
||||
}
|
||||
}
|
||||
|
||||
render () {
|
||||
render() {
|
||||
return (
|
||||
<div
|
||||
styleName='root'
|
||||
@@ -116,7 +130,8 @@ class NewNoteModal extends React.Component {
|
||||
onKeyDown={e => this.handleSnippetNoteButtonKeyDown(e)}
|
||||
ref='snippetButton'
|
||||
>
|
||||
<i styleName='control-button-icon' className='fa fa-code' /><br />
|
||||
<i styleName='control-button-icon' className='fa fa-code' />
|
||||
<br />
|
||||
<span styleName='control-button-label'>
|
||||
{i18n.__('Snippet Note')}
|
||||
</span>
|
||||
@@ -127,10 +142,17 @@ class NewNoteModal extends React.Component {
|
||||
)}
|
||||
</span>
|
||||
</button>
|
||||
|
||||
</div>
|
||||
<div styleName='description'><i className='fa fa-arrows-h' />{i18n.__('Tab to switch format')}</div>
|
||||
<div styleName='from-url' onClick={(e) => this.handleCreateMarkdownFromUrlClick(e)}>Or, create a new markdown note from a URL</div>
|
||||
<div styleName='description'>
|
||||
<i className='fa fa-arrows-h' />
|
||||
{i18n.__('Tab to switch format')}
|
||||
</div>
|
||||
<div
|
||||
styleName='from-url'
|
||||
onClick={e => this.handleCreateMarkdownFromUrlClick(e)}
|
||||
>
|
||||
Or, create a new markdown note from a URL
|
||||
</div>
|
||||
</div>
|
||||
)
|
||||
}
|
||||
|
||||
@@ -11,7 +11,7 @@ const electron = require('electron')
|
||||
const { shell } = electron
|
||||
const ipc = electron.ipcRenderer
|
||||
class Blog extends React.Component {
|
||||
constructor (props) {
|
||||
constructor(props) {
|
||||
super(props)
|
||||
|
||||
this.state = {
|
||||
@@ -20,12 +20,12 @@ class Blog extends React.Component {
|
||||
}
|
||||
}
|
||||
|
||||
handleLinkClick (e) {
|
||||
handleLinkClick(e) {
|
||||
shell.openExternal(e.currentTarget.href)
|
||||
e.preventDefault()
|
||||
}
|
||||
|
||||
clearMessage () {
|
||||
clearMessage() {
|
||||
_.debounce(() => {
|
||||
this.setState({
|
||||
BlogAlert: null
|
||||
@@ -33,30 +33,41 @@ class Blog extends React.Component {
|
||||
}, 2000)()
|
||||
}
|
||||
|
||||
componentDidMount () {
|
||||
componentDidMount() {
|
||||
this.handleSettingDone = () => {
|
||||
this.setState({BlogAlert: {
|
||||
type: 'success',
|
||||
message: i18n.__('Successfully applied!')
|
||||
}})
|
||||
this.setState({
|
||||
BlogAlert: {
|
||||
type: 'success',
|
||||
message: i18n.__('Successfully applied!')
|
||||
}
|
||||
})
|
||||
}
|
||||
this.handleSettingError = (err) => {
|
||||
this.setState({BlogAlert: {
|
||||
type: 'error',
|
||||
message: err.message != null ? err.message : i18n.__('An error occurred!')
|
||||
}})
|
||||
this.handleSettingError = err => {
|
||||
this.setState({
|
||||
BlogAlert: {
|
||||
type: 'error',
|
||||
message:
|
||||
err.message != null ? err.message : i18n.__('An error occurred!')
|
||||
}
|
||||
})
|
||||
}
|
||||
this.oldBlog = this.state.config.blog
|
||||
ipc.addListener('APP_SETTING_DONE', this.handleSettingDone)
|
||||
ipc.addListener('APP_SETTING_ERROR', this.handleSettingError)
|
||||
}
|
||||
|
||||
handleBlogChange (e) {
|
||||
handleBlogChange(e) {
|
||||
const { config } = this.state
|
||||
config.blog = {
|
||||
password: !_.isNil(this.refs.passwordInput) ? this.refs.passwordInput.value : config.blog.password,
|
||||
username: !_.isNil(this.refs.usernameInput) ? this.refs.usernameInput.value : config.blog.username,
|
||||
token: !_.isNil(this.refs.tokenInput) ? this.refs.tokenInput.value : config.blog.token,
|
||||
password: !_.isNil(this.refs.passwordInput)
|
||||
? this.refs.passwordInput.value
|
||||
: config.blog.password,
|
||||
username: !_.isNil(this.refs.usernameInput)
|
||||
? this.refs.usernameInput.value
|
||||
: config.blog.username,
|
||||
token: !_.isNil(this.refs.tokenInput)
|
||||
? this.refs.tokenInput.value
|
||||
: config.blog.token,
|
||||
authMethod: this.refs.authMethodDropdown.value,
|
||||
address: this.refs.addressInput.value,
|
||||
type: this.refs.typeDropdown.value
|
||||
@@ -75,7 +86,7 @@ class Blog extends React.Component {
|
||||
}
|
||||
}
|
||||
|
||||
handleSaveButtonClick (e) {
|
||||
handleSaveButtonClick(e) {
|
||||
const newConfig = {
|
||||
blog: this.state.config.blog
|
||||
}
|
||||
@@ -90,36 +101,36 @@ class Blog extends React.Component {
|
||||
this.props.haveToSave()
|
||||
}
|
||||
|
||||
render () {
|
||||
const {config, BlogAlert} = this.state
|
||||
const blogAlertElement = BlogAlert != null
|
||||
? <p className={`alert ${BlogAlert.type}`}>
|
||||
{BlogAlert.message}
|
||||
</p>
|
||||
: null
|
||||
render() {
|
||||
const { config, BlogAlert } = this.state
|
||||
const blogAlertElement =
|
||||
BlogAlert != null ? (
|
||||
<p className={`alert ${BlogAlert.type}`}>{BlogAlert.message}</p>
|
||||
) : null
|
||||
return (
|
||||
<div styleName='root'>
|
||||
<div styleName='group'>
|
||||
<div styleName='group-header'>{i18n.__('Blog')}</div>
|
||||
<div styleName='group-section'>
|
||||
<div styleName='group-section-label'>
|
||||
{i18n.__('Blog Type')}
|
||||
</div>
|
||||
<div styleName='group-section-label'>{i18n.__('Blog Type')}</div>
|
||||
<div styleName='group-section-control'>
|
||||
<select
|
||||
value={config.blog.type}
|
||||
ref='typeDropdown'
|
||||
onChange={(e) => this.handleBlogChange(e)}
|
||||
onChange={e => this.handleBlogChange(e)}
|
||||
>
|
||||
<option value='wordpress' key='wordpress'>{i18n.__('wordpress')}</option>
|
||||
<option value='wordpress' key='wordpress'>
|
||||
{i18n.__('wordpress')}
|
||||
</option>
|
||||
</select>
|
||||
</div>
|
||||
</div>
|
||||
<div styleName='group-section'>
|
||||
<div styleName='group-section-label'>{i18n.__('Blog Address')}</div>
|
||||
<div styleName='group-section-control'>
|
||||
<input styleName='group-section-control-input'
|
||||
onChange={(e) => this.handleBlogChange(e)}
|
||||
<input
|
||||
styleName='group-section-control-input'
|
||||
onChange={e => this.handleBlogChange(e)}
|
||||
ref='addressInput'
|
||||
value={config.blog.address}
|
||||
type='text'
|
||||
@@ -127,8 +138,11 @@ class Blog extends React.Component {
|
||||
</div>
|
||||
</div>
|
||||
<div styleName='group-control'>
|
||||
<button styleName='group-control-rightButton'
|
||||
onClick={(e) => this.handleSaveButtonClick(e)}>{i18n.__('Save')}
|
||||
<button
|
||||
styleName='group-control-rightButton'
|
||||
onClick={e => this.handleSaveButtonClick(e)}
|
||||
>
|
||||
{i18n.__('Save')}
|
||||
</button>
|
||||
{blogAlertElement}
|
||||
</div>
|
||||
@@ -143,49 +157,59 @@ class Blog extends React.Component {
|
||||
<select
|
||||
value={config.blog.authMethod}
|
||||
ref='authMethodDropdown'
|
||||
onChange={(e) => this.handleBlogChange(e)}
|
||||
onChange={e => this.handleBlogChange(e)}
|
||||
>
|
||||
<option value='JWT' key='JWT'>{i18n.__('JWT')}</option>
|
||||
<option value='USER' key='USER'>{i18n.__('USER')}</option>
|
||||
<option value='JWT' key='JWT'>
|
||||
{i18n.__('JWT')}
|
||||
</option>
|
||||
<option value='USER' key='USER'>
|
||||
{i18n.__('USER')}
|
||||
</option>
|
||||
</select>
|
||||
</div>
|
||||
</div>
|
||||
{ config.blog.authMethod === 'JWT' &&
|
||||
{config.blog.authMethod === 'JWT' && (
|
||||
<div styleName='group-section'>
|
||||
<div styleName='group-section-label'>{i18n.__('Token')}</div>
|
||||
<div styleName='group-section-control'>
|
||||
<input styleName='group-section-control-input'
|
||||
onChange={(e) => this.handleBlogChange(e)}
|
||||
<input
|
||||
styleName='group-section-control-input'
|
||||
onChange={e => this.handleBlogChange(e)}
|
||||
ref='tokenInput'
|
||||
value={config.blog.token}
|
||||
type='text' />
|
||||
type='text'
|
||||
/>
|
||||
</div>
|
||||
</div>
|
||||
}
|
||||
{ config.blog.authMethod === 'USER' &&
|
||||
)}
|
||||
{config.blog.authMethod === 'USER' && (
|
||||
<div>
|
||||
<div styleName='group-section'>
|
||||
<div styleName='group-section-label'>{i18n.__('UserName')}</div>
|
||||
<div styleName='group-section-control'>
|
||||
<input styleName='group-section-control-input'
|
||||
onChange={(e) => this.handleBlogChange(e)}
|
||||
<input
|
||||
styleName='group-section-control-input'
|
||||
onChange={e => this.handleBlogChange(e)}
|
||||
ref='usernameInput'
|
||||
value={config.blog.username}
|
||||
type='text' />
|
||||
type='text'
|
||||
/>
|
||||
</div>
|
||||
</div>
|
||||
<div styleName='group-section'>
|
||||
<div styleName='group-section-label'>{i18n.__('Password')}</div>
|
||||
<div styleName='group-section-control'>
|
||||
<input styleName='group-section-control-input'
|
||||
onChange={(e) => this.handleBlogChange(e)}
|
||||
<input
|
||||
styleName='group-section-control-input'
|
||||
onChange={e => this.handleBlogChange(e)}
|
||||
ref='passwordInput'
|
||||
value={config.blog.password}
|
||||
type='password' />
|
||||
type='password'
|
||||
/>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
}
|
||||
)}
|
||||
</div>
|
||||
)
|
||||
}
|
||||
|
||||
@@ -7,50 +7,93 @@ const electron = require('electron')
|
||||
const { shell } = electron
|
||||
|
||||
class Crowdfunding extends React.Component {
|
||||
constructor (props) {
|
||||
constructor(props) {
|
||||
super(props)
|
||||
|
||||
this.state = {
|
||||
}
|
||||
this.state = {}
|
||||
}
|
||||
|
||||
handleLinkClick (e) {
|
||||
handleLinkClick(e) {
|
||||
shell.openExternal(e.currentTarget.href)
|
||||
e.preventDefault()
|
||||
}
|
||||
|
||||
render () {
|
||||
render() {
|
||||
return (
|
||||
<div styleName='root'>
|
||||
<div styleName='group-header'>{i18n.__('Crowdfunding')}</div>
|
||||
<p>{i18n.__('Thank you for using Boostnote!')}</p>
|
||||
<br />
|
||||
<p>{i18n.__('We launched IssueHunt which is an issue-based crowdfunding / sourcing platform for open source projects.')}</p>
|
||||
<p>{i18n.__('Anyone can put a bounty on not only a bug but also on OSS feature requests listed on IssueHunt. Collected funds will be distributed to project owners and contributors.')}</p>
|
||||
<div styleName='group-header2--sub'>{i18n.__('Sustainable Open Source Ecosystem')}</div>
|
||||
<p>{i18n.__('We discussed about open-source ecosystem and IssueHunt concept with the Boostnote team repeatedly. We actually also discussed with Matz who father of Ruby.')}</p>
|
||||
<p>{i18n.__('The original reason why we made IssueHunt was to reward our contributors of Boostnote project. We’ve got tons of Github stars and hundred of contributors in two years.')}</p>
|
||||
<p>{i18n.__('We thought that it will be nice if we can pay reward for our contributors.')}</p>
|
||||
<div styleName='group-header2--sub'>{i18n.__('We believe Meritocracy')}</div>
|
||||
<p>{i18n.__('We think developers who have skills and do great things must be rewarded properly.')}</p>
|
||||
<p>{i18n.__('OSS projects are used in everywhere on the internet, but no matter how they great, most of owners of those projects need to have another job to sustain their living.')}</p>
|
||||
<p>
|
||||
{i18n.__(
|
||||
'We launched IssueHunt which is an issue-based crowdfunding / sourcing platform for open source projects.'
|
||||
)}
|
||||
</p>
|
||||
<p>
|
||||
{i18n.__(
|
||||
'Anyone can put a bounty on not only a bug but also on OSS feature requests listed on IssueHunt. Collected funds will be distributed to project owners and contributors.'
|
||||
)}
|
||||
</p>
|
||||
<div styleName='group-header2--sub'>
|
||||
{i18n.__('Sustainable Open Source Ecosystem')}
|
||||
</div>
|
||||
<p>
|
||||
{i18n.__(
|
||||
'We discussed about open-source ecosystem and IssueHunt concept with the Boostnote team repeatedly. We actually also discussed with Matz who father of Ruby.'
|
||||
)}
|
||||
</p>
|
||||
<p>
|
||||
{i18n.__(
|
||||
'The original reason why we made IssueHunt was to reward our contributors of Boostnote project. We’ve got tons of Github stars and hundred of contributors in two years.'
|
||||
)}
|
||||
</p>
|
||||
<p>
|
||||
{i18n.__(
|
||||
'We thought that it will be nice if we can pay reward for our contributors.'
|
||||
)}
|
||||
</p>
|
||||
<div styleName='group-header2--sub'>
|
||||
{i18n.__('We believe Meritocracy')}
|
||||
</div>
|
||||
<p>
|
||||
{i18n.__(
|
||||
'We think developers who have skills and do great things must be rewarded properly.'
|
||||
)}
|
||||
</p>
|
||||
<p>
|
||||
{i18n.__(
|
||||
'OSS projects are used in everywhere on the internet, but no matter how they great, most of owners of those projects need to have another job to sustain their living.'
|
||||
)}
|
||||
</p>
|
||||
<p>{i18n.__('It sometimes looks like exploitation.')}</p>
|
||||
<p>{i18n.__('We’ve realized IssueHunt could enhance sustainability of open-source ecosystem.')}</p>
|
||||
<p>
|
||||
{i18n.__(
|
||||
'We’ve realized IssueHunt could enhance sustainability of open-source ecosystem.'
|
||||
)}
|
||||
</p>
|
||||
<br />
|
||||
<p>{i18n.__('As same as issues of Boostnote are already funded on IssueHunt, your open-source projects can be also started funding from now.')}</p>
|
||||
<p>
|
||||
{i18n.__(
|
||||
'As same as issues of Boostnote are already funded on IssueHunt, your open-source projects can be also started funding from now.'
|
||||
)}
|
||||
</p>
|
||||
<br />
|
||||
<p>{i18n.__('Thank you,')}</p>
|
||||
<p>{i18n.__('The Boostnote Team')}</p>
|
||||
<br />
|
||||
<button styleName='cf-link'>
|
||||
<a href='http://bit.ly/issuehunt-from-boostnote-app' onClick={(e) => this.handleLinkClick(e)}>{i18n.__('See IssueHunt')}</a>
|
||||
<a
|
||||
href='http://bit.ly/issuehunt-from-boostnote-app'
|
||||
onClick={e => this.handleLinkClick(e)}
|
||||
>
|
||||
{i18n.__('See IssueHunt')}
|
||||
</a>
|
||||
</button>
|
||||
</div>
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
Crowdfunding.propTypes = {
|
||||
}
|
||||
Crowdfunding.propTypes = {}
|
||||
|
||||
export default CSSModules(Crowdfunding, styles)
|
||||
|
||||
@@ -10,7 +10,7 @@ import { SortableElement, SortableHandle } from 'react-sortable-hoc'
|
||||
import i18n from 'browser/lib/i18n'
|
||||
|
||||
class FolderItem extends React.Component {
|
||||
constructor (props) {
|
||||
constructor(props) {
|
||||
super(props)
|
||||
|
||||
this.state = {
|
||||
@@ -24,7 +24,7 @@ class FolderItem extends React.Component {
|
||||
}
|
||||
}
|
||||
|
||||
handleEditChange (e) {
|
||||
handleEditChange(e) {
|
||||
const { folder } = this.state
|
||||
|
||||
folder.name = this.refs.nameInput.value
|
||||
@@ -33,18 +33,18 @@ class FolderItem extends React.Component {
|
||||
})
|
||||
}
|
||||
|
||||
handleConfirmButtonClick (e) {
|
||||
handleConfirmButtonClick(e) {
|
||||
this.confirm()
|
||||
}
|
||||
|
||||
confirm () {
|
||||
confirm() {
|
||||
const { storage, folder } = this.props
|
||||
dataApi
|
||||
.updateFolder(storage.key, folder.key, {
|
||||
color: this.state.folder.color,
|
||||
name: this.state.folder.name
|
||||
})
|
||||
.then((data) => {
|
||||
.then(data => {
|
||||
store.dispatch({
|
||||
type: 'UPDATE_FOLDER',
|
||||
storage: data.storage
|
||||
@@ -55,9 +55,12 @@ class FolderItem extends React.Component {
|
||||
})
|
||||
}
|
||||
|
||||
handleColorButtonClick (e) {
|
||||
const folder = Object.assign({}, this.state.folder, { showColumnPicker: true, colorPickerPos: { left: 0, top: 0 } })
|
||||
this.setState({ folder }, function () {
|
||||
handleColorButtonClick(e) {
|
||||
const folder = Object.assign({}, this.state.folder, {
|
||||
showColumnPicker: true,
|
||||
colorPickerPos: { left: 0, top: 0 }
|
||||
})
|
||||
this.setState({ folder }, function() {
|
||||
// After the color picker has been painted, re-calculate its position
|
||||
// by comparing its dimensions to the host dimensions.
|
||||
const { hostBoundingBox } = this.props
|
||||
@@ -67,30 +70,32 @@ class FolderItem extends React.Component {
|
||||
const folder = Object.assign({}, this.state.folder, {
|
||||
colorPickerPos: {
|
||||
left: 25,
|
||||
top: offsetTop < 0 ? offsetTop - 5 : 0 // subtract 5px for aestetics
|
||||
top: offsetTop < 0 ? offsetTop - 5 : 0 // subtract 5px for aestetics
|
||||
}
|
||||
})
|
||||
this.setState({ folder })
|
||||
})
|
||||
}
|
||||
|
||||
handleColorChange (color) {
|
||||
handleColorChange(color) {
|
||||
const folder = Object.assign({}, this.state.folder, { color: color.hex })
|
||||
this.setState({ folder })
|
||||
}
|
||||
|
||||
handleColorPickerClose (event) {
|
||||
const folder = Object.assign({}, this.state.folder, { showColumnPicker: false })
|
||||
handleColorPickerClose(event) {
|
||||
const folder = Object.assign({}, this.state.folder, {
|
||||
showColumnPicker: false
|
||||
})
|
||||
this.setState({ folder })
|
||||
}
|
||||
|
||||
handleCancelButtonClick (e) {
|
||||
handleCancelButtonClick(e) {
|
||||
this.setState({
|
||||
status: 'IDLE'
|
||||
})
|
||||
}
|
||||
|
||||
handleFolderItemBlur (e) {
|
||||
handleFolderItemBlur(e) {
|
||||
let el = e.relatedTarget
|
||||
while (el != null) {
|
||||
if (el === this.refs.root) {
|
||||
@@ -101,7 +106,7 @@ class FolderItem extends React.Component {
|
||||
this.confirm()
|
||||
}
|
||||
|
||||
renderEdit (e) {
|
||||
renderEdit(e) {
|
||||
const popover = { position: 'absolute', zIndex: 2 }
|
||||
const cover = {
|
||||
position: 'fixed',
|
||||
@@ -110,51 +115,64 @@ class FolderItem extends React.Component {
|
||||
bottom: 0,
|
||||
left: 0
|
||||
}
|
||||
const pickerStyle = Object.assign({}, {
|
||||
position: 'absolute'
|
||||
}, this.state.folder.colorPickerPos)
|
||||
const pickerStyle = Object.assign(
|
||||
{},
|
||||
{
|
||||
position: 'absolute'
|
||||
},
|
||||
this.state.folder.colorPickerPos
|
||||
)
|
||||
return (
|
||||
<div styleName='folderItem'
|
||||
onBlur={(e) => this.handleFolderItemBlur(e)}
|
||||
<div
|
||||
styleName='folderItem'
|
||||
onBlur={e => this.handleFolderItemBlur(e)}
|
||||
tabIndex='-1'
|
||||
ref='root'
|
||||
>
|
||||
<div styleName='folderItem-left'>
|
||||
<button styleName='folderItem-left-colorButton' style={{color: this.state.folder.color}}
|
||||
onClick={(e) => !this.state.folder.showColumnPicker && this.handleColorButtonClick(e)}
|
||||
<button
|
||||
styleName='folderItem-left-colorButton'
|
||||
style={{ color: this.state.folder.color }}
|
||||
onClick={e =>
|
||||
!this.state.folder.showColumnPicker &&
|
||||
this.handleColorButtonClick(e)
|
||||
}
|
||||
>
|
||||
{this.state.folder.showColumnPicker
|
||||
? <div style={popover}>
|
||||
<div style={cover}
|
||||
{this.state.folder.showColumnPicker ? (
|
||||
<div style={popover}>
|
||||
<div
|
||||
style={cover}
|
||||
onClick={() => this.handleColorPickerClose()}
|
||||
/>
|
||||
<div style={pickerStyle}>
|
||||
<SketchPicker
|
||||
ref='colorPicker'
|
||||
color={this.state.folder.color}
|
||||
onChange={(color) => this.handleColorChange(color)}
|
||||
onChangeComplete={(color) => this.handleColorChange(color)}
|
||||
onChange={color => this.handleColorChange(color)}
|
||||
onChangeComplete={color => this.handleColorChange(color)}
|
||||
/>
|
||||
</div>
|
||||
</div>
|
||||
: null
|
||||
}
|
||||
) : null}
|
||||
<i className='fa fa-square' />
|
||||
</button>
|
||||
<input styleName='folderItem-left-nameInput'
|
||||
<input
|
||||
styleName='folderItem-left-nameInput'
|
||||
value={this.state.folder.name}
|
||||
ref='nameInput'
|
||||
onChange={(e) => this.handleEditChange(e)}
|
||||
onChange={e => this.handleEditChange(e)}
|
||||
/>
|
||||
</div>
|
||||
<div styleName='folderItem-right'>
|
||||
<button styleName='folderItem-right-confirmButton'
|
||||
onClick={(e) => this.handleConfirmButtonClick(e)}
|
||||
<button
|
||||
styleName='folderItem-right-confirmButton'
|
||||
onClick={e => this.handleConfirmButtonClick(e)}
|
||||
>
|
||||
{i18n.__('Confirm')}
|
||||
</button>
|
||||
<button styleName='folderItem-right-button'
|
||||
onClick={(e) => this.handleCancelButtonClick(e)}
|
||||
<button
|
||||
styleName='folderItem-right-button'
|
||||
onClick={e => this.handleCancelButtonClick(e)}
|
||||
>
|
||||
{i18n.__('Cancel')}
|
||||
</button>
|
||||
@@ -163,79 +181,85 @@ class FolderItem extends React.Component {
|
||||
)
|
||||
}
|
||||
|
||||
handleDeleteConfirmButtonClick (e) {
|
||||
handleDeleteConfirmButtonClick(e) {
|
||||
const { storage, folder } = this.props
|
||||
dataApi
|
||||
.deleteFolder(storage.key, folder.key)
|
||||
.then((data) => {
|
||||
store.dispatch({
|
||||
type: 'DELETE_FOLDER',
|
||||
storage: data.storage,
|
||||
folderKey: data.folderKey
|
||||
})
|
||||
dataApi.deleteFolder(storage.key, folder.key).then(data => {
|
||||
store.dispatch({
|
||||
type: 'DELETE_FOLDER',
|
||||
storage: data.storage,
|
||||
folderKey: data.folderKey
|
||||
})
|
||||
}
|
||||
|
||||
renderDelete () {
|
||||
return (
|
||||
<div styleName='folderItem'>
|
||||
<div styleName='folderItem-left'>
|
||||
{i18n.__('Are you sure to ')} <span styleName='folderItem-left-danger'>{i18n.__(' delete')}</span> {i18n.__('this folder?')}
|
||||
</div>
|
||||
<div styleName='folderItem-right'>
|
||||
<button styleName='folderItem-right-dangerButton'
|
||||
onClick={(e) => this.handleDeleteConfirmButtonClick(e)}
|
||||
>
|
||||
{i18n.__('Confirm')}
|
||||
</button>
|
||||
<button styleName='folderItem-right-button'
|
||||
onClick={(e) => this.handleCancelButtonClick(e)}
|
||||
>
|
||||
{i18n.__('Cancel')}
|
||||
</button>
|
||||
</div>
|
||||
</div>
|
||||
)
|
||||
}
|
||||
|
||||
handleEditButtonClick (e) {
|
||||
const { folder: propsFolder } = this.props
|
||||
const { folder: stateFolder } = this.state
|
||||
const folder = Object.assign({}, stateFolder, propsFolder)
|
||||
this.setState({
|
||||
status: 'EDIT',
|
||||
folder
|
||||
}, () => {
|
||||
this.refs.nameInput.select()
|
||||
})
|
||||
}
|
||||
|
||||
handleDeleteButtonClick (e) {
|
||||
renderDelete() {
|
||||
return (
|
||||
<div styleName='folderItem'>
|
||||
<div styleName='folderItem-left'>
|
||||
{i18n.__('Are you sure to ')}{' '}
|
||||
<span styleName='folderItem-left-danger'>{i18n.__(' delete')}</span>{' '}
|
||||
{i18n.__('this folder?')}
|
||||
</div>
|
||||
<div styleName='folderItem-right'>
|
||||
<button
|
||||
styleName='folderItem-right-dangerButton'
|
||||
onClick={e => this.handleDeleteConfirmButtonClick(e)}
|
||||
>
|
||||
{i18n.__('Confirm')}
|
||||
</button>
|
||||
<button
|
||||
styleName='folderItem-right-button'
|
||||
onClick={e => this.handleCancelButtonClick(e)}
|
||||
>
|
||||
{i18n.__('Cancel')}
|
||||
</button>
|
||||
</div>
|
||||
</div>
|
||||
)
|
||||
}
|
||||
|
||||
handleEditButtonClick(e) {
|
||||
const { folder: propsFolder } = this.props
|
||||
const { folder: stateFolder } = this.state
|
||||
const folder = Object.assign({}, stateFolder, propsFolder)
|
||||
this.setState(
|
||||
{
|
||||
status: 'EDIT',
|
||||
folder
|
||||
},
|
||||
() => {
|
||||
this.refs.nameInput.select()
|
||||
}
|
||||
)
|
||||
}
|
||||
|
||||
handleDeleteButtonClick(e) {
|
||||
this.setState({
|
||||
status: 'DELETE'
|
||||
})
|
||||
}
|
||||
|
||||
renderIdle () {
|
||||
renderIdle() {
|
||||
const { folder } = this.props
|
||||
return (
|
||||
<div styleName='folderItem'
|
||||
onDoubleClick={(e) => this.handleEditButtonClick(e)}
|
||||
<div
|
||||
styleName='folderItem'
|
||||
onDoubleClick={e => this.handleEditButtonClick(e)}
|
||||
>
|
||||
<div styleName='folderItem-left'
|
||||
style={{borderColor: folder.color}}
|
||||
>
|
||||
<div styleName='folderItem-left' style={{ borderColor: folder.color }}>
|
||||
<span>{folder.name}</span>
|
||||
<span styleName='folderItem-left-key'>({folder.key})</span>
|
||||
</div>
|
||||
<div styleName='folderItem-right'>
|
||||
<button styleName='folderItem-right-button'
|
||||
onClick={(e) => this.handleEditButtonClick(e)}
|
||||
<button
|
||||
styleName='folderItem-right-button'
|
||||
onClick={e => this.handleEditButtonClick(e)}
|
||||
>
|
||||
{i18n.__('Edit')}
|
||||
</button>
|
||||
<button styleName='folderItem-right-button'
|
||||
onClick={(e) => this.handleDeleteButtonClick(e)}
|
||||
<button
|
||||
styleName='folderItem-right-button'
|
||||
onClick={e => this.handleDeleteButtonClick(e)}
|
||||
>
|
||||
{i18n.__('Delete')}
|
||||
</button>
|
||||
@@ -244,7 +268,7 @@ class FolderItem extends React.Component {
|
||||
)
|
||||
}
|
||||
|
||||
render () {
|
||||
render() {
|
||||
switch (this.state.status) {
|
||||
case 'DELETE':
|
||||
return this.renderDelete()
|
||||
@@ -277,7 +301,7 @@ FolderItem.propTypes = {
|
||||
}
|
||||
|
||||
class Handle extends React.Component {
|
||||
render () {
|
||||
render() {
|
||||
return (
|
||||
<div styleName='folderItem-drag-handle'>
|
||||
<i className='fa fa-reorder' />
|
||||
@@ -287,7 +311,7 @@ class Handle extends React.Component {
|
||||
}
|
||||
|
||||
class SortableFolderItemComponent extends React.Component {
|
||||
render () {
|
||||
render() {
|
||||
const StyledHandle = CSSModules(Handle, styles)
|
||||
const DragHandle = SortableHandle(StyledHandle)
|
||||
|
||||
|
||||
@@ -9,24 +9,28 @@ import { SortableContainer } from 'react-sortable-hoc'
|
||||
import i18n from 'browser/lib/i18n'
|
||||
|
||||
class FolderList extends React.Component {
|
||||
render () {
|
||||
render() {
|
||||
const { storage, hostBoundingBox } = this.props
|
||||
|
||||
const folderList = storage.folders.map((folder, index) => {
|
||||
return <FolderItem key={folder.key}
|
||||
folder={folder}
|
||||
storage={storage}
|
||||
index={index}
|
||||
hostBoundingBox={hostBoundingBox}
|
||||
/>
|
||||
return (
|
||||
<FolderItem
|
||||
key={folder.key}
|
||||
folder={folder}
|
||||
storage={storage}
|
||||
index={index}
|
||||
hostBoundingBox={hostBoundingBox}
|
||||
/>
|
||||
)
|
||||
})
|
||||
|
||||
return (
|
||||
<div>
|
||||
{folderList.length > 0
|
||||
? folderList
|
||||
: <div styleName='folderList-empty'>{i18n.__('No Folders')}</div>
|
||||
}
|
||||
{folderList.length > 0 ? (
|
||||
folderList
|
||||
) : (
|
||||
<div styleName='folderList-empty'>{i18n.__('No Folders')}</div>
|
||||
)}
|
||||
</div>
|
||||
)
|
||||
}
|
||||
@@ -52,23 +56,21 @@ FolderList.propTypes = {
|
||||
}
|
||||
|
||||
class SortableFolderListComponent extends React.Component {
|
||||
constructor (props) {
|
||||
constructor(props) {
|
||||
super(props)
|
||||
this.onSortEnd = ({oldIndex, newIndex}) => {
|
||||
this.onSortEnd = ({ oldIndex, newIndex }) => {
|
||||
const { storage } = this.props
|
||||
dataApi
|
||||
.reorderFolder(storage.key, oldIndex, newIndex)
|
||||
.then((data) => {
|
||||
store.dispatch({
|
||||
type: 'REORDER_FOLDER',
|
||||
storage: data.storage
|
||||
})
|
||||
this.setState()
|
||||
dataApi.reorderFolder(storage.key, oldIndex, newIndex).then(data => {
|
||||
store.dispatch({
|
||||
type: 'REORDER_FOLDER',
|
||||
storage: data.storage
|
||||
})
|
||||
this.setState()
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
render () {
|
||||
render() {
|
||||
const StyledFolderList = CSSModules(FolderList, this.props.styles)
|
||||
const SortableFolderList = SortableContainer(StyledFolderList)
|
||||
|
||||
|
||||
@@ -11,7 +11,7 @@ const electron = require('electron')
|
||||
const ipc = electron.ipcRenderer
|
||||
|
||||
class HotkeyTab extends React.Component {
|
||||
constructor (props) {
|
||||
constructor(props) {
|
||||
super(props)
|
||||
|
||||
this.state = {
|
||||
@@ -20,28 +20,35 @@ class HotkeyTab extends React.Component {
|
||||
}
|
||||
}
|
||||
|
||||
componentDidMount () {
|
||||
componentDidMount() {
|
||||
this.handleSettingDone = () => {
|
||||
this.setState({keymapAlert: {
|
||||
type: 'success',
|
||||
message: i18n.__('Successfully applied!')
|
||||
}})
|
||||
this.setState({
|
||||
keymapAlert: {
|
||||
type: 'success',
|
||||
message: i18n.__('Successfully applied!')
|
||||
}
|
||||
})
|
||||
}
|
||||
this.handleSettingError = (err) => {
|
||||
this.handleSettingError = err => {
|
||||
if (
|
||||
this.state.config.hotkey.toggleMain === '' ||
|
||||
this.state.config.hotkey.toggleMode === '' ||
|
||||
this.state.config.hotkey.toggleDirection === ''
|
||||
) {
|
||||
this.setState({keymapAlert: {
|
||||
type: 'success',
|
||||
message: i18n.__('Successfully applied!')
|
||||
}})
|
||||
this.setState({
|
||||
keymapAlert: {
|
||||
type: 'success',
|
||||
message: i18n.__('Successfully applied!')
|
||||
}
|
||||
})
|
||||
} else {
|
||||
this.setState({keymapAlert: {
|
||||
type: 'error',
|
||||
message: err.message != null ? err.message : i18n.__('An error occurred!')
|
||||
}})
|
||||
this.setState({
|
||||
keymapAlert: {
|
||||
type: 'error',
|
||||
message:
|
||||
err.message != null ? err.message : i18n.__('An error occurred!')
|
||||
}
|
||||
})
|
||||
}
|
||||
}
|
||||
this.oldHotkey = this.state.config.hotkey
|
||||
@@ -49,12 +56,12 @@ class HotkeyTab extends React.Component {
|
||||
ipc.addListener('APP_SETTING_ERROR', this.handleSettingError)
|
||||
}
|
||||
|
||||
componentWillUnmount () {
|
||||
componentWillUnmount() {
|
||||
ipc.removeListener('APP_SETTING_DONE', this.handleSettingDone)
|
||||
ipc.removeListener('APP_SETTING_ERROR', this.handleSettingError)
|
||||
}
|
||||
|
||||
handleSaveButtonClick (e) {
|
||||
handleSaveButtonClick(e) {
|
||||
const newConfig = {
|
||||
hotkey: this.state.config.hotkey
|
||||
}
|
||||
@@ -69,13 +76,13 @@ class HotkeyTab extends React.Component {
|
||||
this.props.haveToSave()
|
||||
}
|
||||
|
||||
handleHintToggleButtonClick (e) {
|
||||
handleHintToggleButtonClick(e) {
|
||||
this.setState({
|
||||
isHotkeyHintOpen: !this.state.isHotkeyHintOpen
|
||||
})
|
||||
}
|
||||
|
||||
handleHotkeyChange (e) {
|
||||
handleHotkeyChange(e) {
|
||||
const { config } = this.state
|
||||
config.hotkey = Object.assign({}, config.hotkey, {
|
||||
toggleMain: this.refs.toggleMain.value,
|
||||
@@ -102,7 +109,7 @@ class HotkeyTab extends React.Component {
|
||||
}
|
||||
}
|
||||
|
||||
clearMessage () {
|
||||
clearMessage() {
|
||||
_.debounce(() => {
|
||||
this.setState({
|
||||
keymapAlert: null
|
||||
@@ -110,13 +117,12 @@ class HotkeyTab extends React.Component {
|
||||
}, 2000)()
|
||||
}
|
||||
|
||||
render () {
|
||||
render() {
|
||||
const keymapAlert = this.state.keymapAlert
|
||||
const keymapAlertElement = keymapAlert != null
|
||||
? <p className={`alert ${keymapAlert.type}`}>
|
||||
{keymapAlert.message}
|
||||
</p>
|
||||
: null
|
||||
const keymapAlertElement =
|
||||
keymapAlert != null ? (
|
||||
<p className={`alert ${keymapAlert.type}`}>{keymapAlert.message}</p>
|
||||
) : null
|
||||
const { config } = this.state
|
||||
|
||||
return (
|
||||
@@ -124,10 +130,13 @@ class HotkeyTab extends React.Component {
|
||||
<div styleName='group'>
|
||||
<div styleName='group-header'>{i18n.__('Hotkeys')}</div>
|
||||
<div styleName='group-section'>
|
||||
<div styleName='group-section-label'>{i18n.__('Show/Hide Boostnote')}</div>
|
||||
<div styleName='group-section-label'>
|
||||
{i18n.__('Show/Hide Boostnote')}
|
||||
</div>
|
||||
<div styleName='group-section-control'>
|
||||
<input styleName='group-section-control-input'
|
||||
onChange={(e) => this.handleHotkeyChange(e)}
|
||||
<input
|
||||
styleName='group-section-control-input'
|
||||
onChange={e => this.handleHotkeyChange(e)}
|
||||
ref='toggleMain'
|
||||
value={config.hotkey.toggleMain}
|
||||
type='text'
|
||||
@@ -135,10 +144,13 @@ class HotkeyTab extends React.Component {
|
||||
</div>
|
||||
</div>
|
||||
<div styleName='group-section'>
|
||||
<div styleName='group-section-label'>{i18n.__('Show/Hide Menu Bar')}</div>
|
||||
<div styleName='group-section-label'>
|
||||
{i18n.__('Show/Hide Menu Bar')}
|
||||
</div>
|
||||
<div styleName='group-section-control'>
|
||||
<input styleName='group-section-control-input'
|
||||
onChange={(e) => this.handleHotkeyChange(e)}
|
||||
<input
|
||||
styleName='group-section-control-input'
|
||||
onChange={e => this.handleHotkeyChange(e)}
|
||||
ref='toggleMenuBar'
|
||||
value={config.hotkey.toggleMenuBar}
|
||||
type='text'
|
||||
@@ -146,10 +158,13 @@ class HotkeyTab extends React.Component {
|
||||
</div>
|
||||
</div>
|
||||
<div styleName='group-section'>
|
||||
<div styleName='group-section-label'>{i18n.__('Toggle Editor Mode')}</div>
|
||||
<div styleName='group-section-label'>
|
||||
{i18n.__('Toggle Editor Mode')}
|
||||
</div>
|
||||
<div styleName='group-section-control'>
|
||||
<input styleName='group-section-control-input'
|
||||
onChange={(e) => this.handleHotkeyChange(e)}
|
||||
<input
|
||||
styleName='group-section-control-input'
|
||||
onChange={e => this.handleHotkeyChange(e)}
|
||||
ref='toggleMode'
|
||||
value={config.hotkey.toggleMode}
|
||||
type='text'
|
||||
@@ -157,10 +172,13 @@ class HotkeyTab extends React.Component {
|
||||
</div>
|
||||
</div>
|
||||
<div styleName='group-section'>
|
||||
<div styleName='group-section-label'>{i18n.__('Toggle Direction')}</div>
|
||||
<div styleName='group-section-label'>
|
||||
{i18n.__('Toggle Direction')}
|
||||
</div>
|
||||
<div styleName='group-section-control'>
|
||||
<input styleName='group-section-control-input'
|
||||
onChange={(e) => this.handleHotkeyChange(e)}
|
||||
<input
|
||||
styleName='group-section-control-input'
|
||||
onChange={e => this.handleHotkeyChange(e)}
|
||||
ref='toggleDirection'
|
||||
value={config.hotkey.toggleDirection}
|
||||
type='text'
|
||||
@@ -170,8 +188,9 @@ class HotkeyTab extends React.Component {
|
||||
<div styleName='group-section'>
|
||||
<div styleName='group-section-label'>{i18n.__('Delete Note')}</div>
|
||||
<div styleName='group-section-control'>
|
||||
<input styleName='group-section-control-input'
|
||||
onChange={(e) => this.handleHotkeyChange(e)}
|
||||
<input
|
||||
styleName='group-section-control-input'
|
||||
onChange={e => this.handleHotkeyChange(e)}
|
||||
ref='deleteNote'
|
||||
value={config.hotkey.deleteNote}
|
||||
type='text'
|
||||
@@ -181,8 +200,9 @@ class HotkeyTab extends React.Component {
|
||||
<div styleName='group-section'>
|
||||
<div styleName='group-section-label'>{i18n.__('Paste HTML')}</div>
|
||||
<div styleName='group-section-control'>
|
||||
<input styleName='group-section-control-input'
|
||||
onChange={(e) => this.handleHotkeyChange(e)}
|
||||
<input
|
||||
styleName='group-section-control-input'
|
||||
onChange={e => this.handleHotkeyChange(e)}
|
||||
ref='pasteSmartly'
|
||||
value={config.hotkey.pasteSmartly}
|
||||
type='text'
|
||||
@@ -190,19 +210,26 @@ class HotkeyTab extends React.Component {
|
||||
</div>
|
||||
</div>
|
||||
<div styleName='group-section'>
|
||||
<div styleName='group-section-label'>{i18n.__('Prettify Markdown')}</div>
|
||||
<div styleName='group-section-label'>
|
||||
{i18n.__('Prettify Markdown')}
|
||||
</div>
|
||||
<div styleName='group-section-control'>
|
||||
<input styleName='group-section-control-input'
|
||||
onChange={(e) => this.handleHotkeyChange(e)}
|
||||
<input
|
||||
styleName='group-section-control-input'
|
||||
onChange={e => this.handleHotkeyChange(e)}
|
||||
ref='prettifyMarkdown'
|
||||
value={config.hotkey.prettifyMarkdown}
|
||||
type='text' />
|
||||
type='text'
|
||||
/>
|
||||
</div>
|
||||
</div>
|
||||
<div styleName='group-section'>
|
||||
<div styleName='group-section-label'>{i18n.__('Insert Current Date')}</div>
|
||||
<div styleName='group-section-label'>
|
||||
{i18n.__('Insert Current Date')}
|
||||
</div>
|
||||
<div styleName='group-section-control'>
|
||||
<input styleName='group-section-control-input'
|
||||
<input
|
||||
styleName='group-section-control-input'
|
||||
ref='insertDate'
|
||||
value={config.hotkey.insertDate}
|
||||
type='text'
|
||||
@@ -211,9 +238,12 @@ class HotkeyTab extends React.Component {
|
||||
</div>
|
||||
</div>
|
||||
<div styleName='group-section'>
|
||||
<div styleName='group-section-label'>{i18n.__('Insert Current Date and Time')}</div>
|
||||
<div styleName='group-section-label'>
|
||||
{i18n.__('Insert Current Date and Time')}
|
||||
</div>
|
||||
<div styleName='group-section-control'>
|
||||
<input styleName='group-section-control-input'
|
||||
<input
|
||||
styleName='group-section-control-input'
|
||||
ref='insertDateTime'
|
||||
value={config.hotkey.insertDateTime}
|
||||
type='text'
|
||||
@@ -222,44 +252,87 @@ class HotkeyTab extends React.Component {
|
||||
</div>
|
||||
</div>
|
||||
<div styleName='group-control'>
|
||||
<button styleName='group-control-leftButton'
|
||||
onClick={(e) => this.handleHintToggleButtonClick(e)}
|
||||
<button
|
||||
styleName='group-control-leftButton'
|
||||
onClick={e => this.handleHintToggleButtonClick(e)}
|
||||
>
|
||||
{this.state.isHotkeyHintOpen
|
||||
? i18n.__('Hide Help')
|
||||
: i18n.__('Help')
|
||||
}
|
||||
: i18n.__('Help')}
|
||||
</button>
|
||||
<button styleName='group-control-rightButton'
|
||||
onClick={(e) => this.handleSaveButtonClick(e)}>{i18n.__('Save')}
|
||||
<button
|
||||
styleName='group-control-rightButton'
|
||||
onClick={e => this.handleSaveButtonClick(e)}
|
||||
>
|
||||
{i18n.__('Save')}
|
||||
</button>
|
||||
{keymapAlertElement}
|
||||
</div>
|
||||
{this.state.isHotkeyHintOpen &&
|
||||
{this.state.isHotkeyHintOpen && (
|
||||
<div styleName='group-hint'>
|
||||
<p>{i18n.__('Available Keys')}</p>
|
||||
<ul>
|
||||
<li><code>0</code> to <code>9</code></li>
|
||||
<li><code>A</code> to <code>Z</code></li>
|
||||
<li><code>F1</code> to <code>F24</code></li>
|
||||
<li>Punctuations like <code>~</code>, <code>!</code>, <code>@</code>, <code>#</code>, <code>$</code>, etc.</li>
|
||||
<li><code>Plus</code></li>
|
||||
<li><code>Space</code></li>
|
||||
<li><code>Backspace</code></li>
|
||||
<li><code>Delete</code></li>
|
||||
<li><code>Insert</code></li>
|
||||
<li><code>Return</code> (or <code>Enter</code> as alias)</li>
|
||||
<li><code>Up</code>, <code>Down</code>, <code>Left</code> and <code>Right</code></li>
|
||||
<li><code>Home</code> and <code>End</code></li>
|
||||
<li><code>PageUp</code> and <code>PageDown</code></li>
|
||||
<li><code>Escape</code> (or <code>Esc</code> for short)</li>
|
||||
<li><code>VolumeUp</code>, <code>VolumeDown</code> and <code>VolumeMute</code></li>
|
||||
<li><code>MediaNextTrack</code>, <code>MediaPreviousTrack</code>, <code>MediaStop</code> and <code>MediaPlayPause</code></li>
|
||||
<li><code>Control</code> (or <code>Ctrl</code> for short)</li>
|
||||
<li><code>Shift</code></li>
|
||||
<li>
|
||||
<code>0</code> to <code>9</code>
|
||||
</li>
|
||||
<li>
|
||||
<code>A</code> to <code>Z</code>
|
||||
</li>
|
||||
<li>
|
||||
<code>F1</code> to <code>F24</code>
|
||||
</li>
|
||||
<li>
|
||||
Punctuations like <code>~</code>, <code>!</code>,{' '}
|
||||
<code>@</code>, <code>#</code>, <code>$</code>, etc.
|
||||
</li>
|
||||
<li>
|
||||
<code>Plus</code>
|
||||
</li>
|
||||
<li>
|
||||
<code>Space</code>
|
||||
</li>
|
||||
<li>
|
||||
<code>Backspace</code>
|
||||
</li>
|
||||
<li>
|
||||
<code>Delete</code>
|
||||
</li>
|
||||
<li>
|
||||
<code>Insert</code>
|
||||
</li>
|
||||
<li>
|
||||
<code>Return</code> (or <code>Enter</code> as alias)
|
||||
</li>
|
||||
<li>
|
||||
<code>Up</code>, <code>Down</code>, <code>Left</code> and{' '}
|
||||
<code>Right</code>
|
||||
</li>
|
||||
<li>
|
||||
<code>Home</code> and <code>End</code>
|
||||
</li>
|
||||
<li>
|
||||
<code>PageUp</code> and <code>PageDown</code>
|
||||
</li>
|
||||
<li>
|
||||
<code>Escape</code> (or <code>Esc</code> for short)
|
||||
</li>
|
||||
<li>
|
||||
<code>VolumeUp</code>, <code>VolumeDown</code> and{' '}
|
||||
<code>VolumeMute</code>
|
||||
</li>
|
||||
<li>
|
||||
<code>MediaNextTrack</code>, <code>MediaPreviousTrack</code>,{' '}
|
||||
<code>MediaStop</code> and <code>MediaPlayPause</code>
|
||||
</li>
|
||||
<li>
|
||||
<code>Control</code> (or <code>Ctrl</code> for short)
|
||||
</li>
|
||||
<li>
|
||||
<code>Shift</code>
|
||||
</li>
|
||||
</ul>
|
||||
</div>
|
||||
}
|
||||
)}
|
||||
</div>
|
||||
</div>
|
||||
)
|
||||
|
||||
@@ -12,7 +12,7 @@ const { shell, remote } = electron
|
||||
const appVersion = remote.app.getVersion()
|
||||
|
||||
class InfoTab extends React.Component {
|
||||
constructor (props) {
|
||||
constructor(props) {
|
||||
super(props)
|
||||
|
||||
this.state = {
|
||||
@@ -20,18 +20,18 @@ class InfoTab extends React.Component {
|
||||
}
|
||||
}
|
||||
|
||||
handleLinkClick (e) {
|
||||
handleLinkClick(e) {
|
||||
shell.openExternal(e.currentTarget.href)
|
||||
e.preventDefault()
|
||||
}
|
||||
|
||||
handleConfigChange (e) {
|
||||
handleConfigChange(e) {
|
||||
const newConfig = { amaEnabled: this.refs.amaEnabled.checked }
|
||||
|
||||
this.setState({ config: newConfig })
|
||||
}
|
||||
|
||||
handleSaveButtonClick (e) {
|
||||
handleSaveButtonClick(e) {
|
||||
const newConfig = {
|
||||
amaEnabled: this.state.config.amaEnabled
|
||||
}
|
||||
@@ -43,7 +43,7 @@ class InfoTab extends React.Component {
|
||||
})
|
||||
} else {
|
||||
this.setState({
|
||||
amaMessage: i18n.__('Thank\'s for trusting us')
|
||||
amaMessage: i18n.__("Thank's for trusting us")
|
||||
})
|
||||
}
|
||||
|
||||
@@ -61,7 +61,7 @@ class InfoTab extends React.Component {
|
||||
})
|
||||
}
|
||||
|
||||
toggleAutoUpdate () {
|
||||
toggleAutoUpdate() {
|
||||
const newConfig = {
|
||||
autoUpdateEnabled: !this.state.config.autoUpdateEnabled
|
||||
}
|
||||
@@ -70,46 +70,64 @@ class InfoTab extends React.Component {
|
||||
ConfigManager.set(newConfig)
|
||||
}
|
||||
|
||||
infoMessage () {
|
||||
infoMessage() {
|
||||
const { amaMessage } = this.state
|
||||
return amaMessage ? <p styleName='policy-confirm'>{amaMessage}</p> : null
|
||||
}
|
||||
|
||||
render () {
|
||||
render() {
|
||||
return (
|
||||
<div styleName='root'>
|
||||
<div styleName='group-header'>{i18n.__('Community')}</div>
|
||||
<div styleName='top'>
|
||||
<ul styleName='list'>
|
||||
<li>
|
||||
<a href='https://issuehunt.io/repos/53266139'
|
||||
onClick={(e) => this.handleLinkClick(e)}
|
||||
>{i18n.__('Bounty on IssueHunt')}</a>
|
||||
<a
|
||||
href='https://issuehunt.io/repos/53266139'
|
||||
onClick={e => this.handleLinkClick(e)}
|
||||
>
|
||||
{i18n.__('Bounty on IssueHunt')}
|
||||
</a>
|
||||
</li>
|
||||
<li>
|
||||
<a href='https://boostnote.io/#subscribe'
|
||||
onClick={(e) => this.handleLinkClick(e)}
|
||||
>{i18n.__('Subscribe to Newsletter')}</a>
|
||||
<a
|
||||
href='https://boostnote.io/#subscribe'
|
||||
onClick={e => this.handleLinkClick(e)}
|
||||
>
|
||||
{i18n.__('Subscribe to Newsletter')}
|
||||
</a>
|
||||
</li>
|
||||
<li>
|
||||
<a href='https://github.com/BoostIO/Boostnote/issues'
|
||||
onClick={(e) => this.handleLinkClick(e)}
|
||||
>{i18n.__('GitHub')}</a>
|
||||
<a
|
||||
href='https://github.com/BoostIO/Boostnote/issues'
|
||||
onClick={e => this.handleLinkClick(e)}
|
||||
>
|
||||
{i18n.__('GitHub')}
|
||||
</a>
|
||||
</li>
|
||||
<li>
|
||||
<a href='https://medium.com/boostnote'
|
||||
onClick={(e) => this.handleLinkClick(e)}
|
||||
>{i18n.__('Blog')}</a>
|
||||
<a
|
||||
href='https://medium.com/boostnote'
|
||||
onClick={e => this.handleLinkClick(e)}
|
||||
>
|
||||
{i18n.__('Blog')}
|
||||
</a>
|
||||
</li>
|
||||
<li>
|
||||
<a href='https://www.facebook.com/groups/boostnote'
|
||||
onClick={(e) => this.handleLinkClick(e)}
|
||||
>{i18n.__('Facebook Group')}</a>
|
||||
<a
|
||||
href='https://www.facebook.com/groups/boostnote'
|
||||
onClick={e => this.handleLinkClick(e)}
|
||||
>
|
||||
{i18n.__('Facebook Group')}
|
||||
</a>
|
||||
</li>
|
||||
<li>
|
||||
<a href='https://twitter.com/boostnoteapp'
|
||||
onClick={(e) => this.handleLinkClick(e)}
|
||||
>{i18n.__('Twitter')}</a>
|
||||
<a
|
||||
href='https://twitter.com/boostnoteapp'
|
||||
onClick={e => this.handleLinkClick(e)}
|
||||
>
|
||||
{i18n.__('Twitter')}
|
||||
</a>
|
||||
</li>
|
||||
</ul>
|
||||
</div>
|
||||
@@ -120,11 +138,20 @@ class InfoTab extends React.Component {
|
||||
|
||||
<div styleName='top'>
|
||||
<div styleName='icon-space'>
|
||||
<img styleName='icon' src='../resources/app.png' width='92' height='92' />
|
||||
<img
|
||||
styleName='icon'
|
||||
src='../resources/app.png'
|
||||
width='92'
|
||||
height='92'
|
||||
/>
|
||||
<div styleName='icon-right'>
|
||||
<div styleName='appId'>{i18n.__('Boostnote')} {appVersion}</div>
|
||||
<div styleName='appId'>
|
||||
{i18n.__('Boostnote')} {appVersion}
|
||||
</div>
|
||||
<div styleName='description'>
|
||||
{i18n.__('An open source note-taking app made for programmers just like you.')}
|
||||
{i18n.__(
|
||||
'An open source note-taking app made for programmers just like you.'
|
||||
)}
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
@@ -132,39 +159,71 @@ class InfoTab extends React.Component {
|
||||
|
||||
<ul styleName='list'>
|
||||
<li>
|
||||
<a href='https://boostnote.io'
|
||||
onClick={(e) => this.handleLinkClick(e)}
|
||||
>{i18n.__('Website')}</a>
|
||||
<a
|
||||
href='https://boostnote.io'
|
||||
onClick={e => this.handleLinkClick(e)}
|
||||
>
|
||||
{i18n.__('Website')}
|
||||
</a>
|
||||
</li>
|
||||
<li>
|
||||
<a href='https://github.com/BoostIO/Boostnote/blob/master/docs/build.md'
|
||||
onClick={(e) => this.handleLinkClick(e)}
|
||||
>{i18n.__('Development')}</a>{i18n.__(' : Development configurations for Boostnote.')}
|
||||
</li>
|
||||
<li styleName='cc'>
|
||||
{i18n.__('Copyright (C) 2017 - 2020 BoostIO')}
|
||||
</li>
|
||||
<li styleName='cc'>
|
||||
{i18n.__('License: GPL v3')}
|
||||
<a
|
||||
href='https://github.com/BoostIO/Boostnote/blob/master/docs/build.md'
|
||||
onClick={e => this.handleLinkClick(e)}
|
||||
>
|
||||
{i18n.__('Development')}
|
||||
</a>
|
||||
{i18n.__(' : Development configurations for Boostnote.')}
|
||||
</li>
|
||||
<li styleName='cc'>{i18n.__('Copyright (C) 2017 - 2020 BoostIO')}</li>
|
||||
<li styleName='cc'>{i18n.__('License: GPL v3')}</li>
|
||||
</ul>
|
||||
|
||||
<div><label><input type='checkbox' onChange={this.toggleAutoUpdate.bind(this)} checked={this.state.config.autoUpdateEnabled} />{i18n.__('Enable Auto Update')}</label></div>
|
||||
<div>
|
||||
<label>
|
||||
<input
|
||||
type='checkbox'
|
||||
onChange={this.toggleAutoUpdate.bind(this)}
|
||||
checked={this.state.config.autoUpdateEnabled}
|
||||
/>
|
||||
{i18n.__('Enable Auto Update')}
|
||||
</label>
|
||||
</div>
|
||||
|
||||
<hr styleName='separate-line' />
|
||||
|
||||
<div styleName='group-header2--sub'>{i18n.__('Analytics')}</div>
|
||||
<div>{i18n.__('Boostnote collects anonymous data for the sole purpose of improving the application, and strictly does not collect any personal information such the contents of your notes.')}</div>
|
||||
<div>{i18n.__('You can see how it works on ')}<a href='https://github.com/BoostIO/Boostnote' onClick={(e) => this.handleLinkClick(e)}>GitHub</a>.</div>
|
||||
<div>
|
||||
{i18n.__(
|
||||
'Boostnote collects anonymous data for the sole purpose of improving the application, and strictly does not collect any personal information such the contents of your notes.'
|
||||
)}
|
||||
</div>
|
||||
<div>
|
||||
{i18n.__('You can see how it works on ')}
|
||||
<a
|
||||
href='https://github.com/BoostIO/Boostnote'
|
||||
onClick={e => this.handleLinkClick(e)}
|
||||
>
|
||||
GitHub
|
||||
</a>
|
||||
.
|
||||
</div>
|
||||
<br />
|
||||
<div>{i18n.__('You can choose to enable or disable this option.')}</div>
|
||||
<input onChange={(e) => this.handleConfigChange(e)}
|
||||
<input
|
||||
onChange={e => this.handleConfigChange(e)}
|
||||
checked={this.state.config.amaEnabled}
|
||||
ref='amaEnabled'
|
||||
type='checkbox'
|
||||
/>
|
||||
{i18n.__('Enable analytics to help improve Boostnote')}<br />
|
||||
<button styleName='policy-submit' onClick={(e) => this.handleSaveButtonClick(e)}>{i18n.__('Save')}</button>
|
||||
{i18n.__('Enable analytics to help improve Boostnote')}
|
||||
<br />
|
||||
<button
|
||||
styleName='policy-submit'
|
||||
onClick={e => this.handleSaveButtonClick(e)}
|
||||
>
|
||||
{i18n.__('Save')}
|
||||
</button>
|
||||
<br />
|
||||
{this.infoMessage()}
|
||||
</div>
|
||||
@@ -172,7 +231,6 @@ class InfoTab extends React.Component {
|
||||
}
|
||||
}
|
||||
|
||||
InfoTab.propTypes = {
|
||||
}
|
||||
InfoTab.propTypes = {}
|
||||
|
||||
export default CSSModules(InfoTab, styles)
|
||||
|
||||
@@ -6,13 +6,19 @@ import CSSModules from 'browser/lib/CSSModules'
|
||||
import dataApi from 'browser/main/lib/dataApi'
|
||||
import snippetManager from '../../../lib/SnippetManager'
|
||||
|
||||
const defaultEditorFontFamily = ['Monaco', 'Menlo', 'Ubuntu Mono', 'Consolas', 'source-code-pro', 'monospace']
|
||||
const defaultEditorFontFamily = [
|
||||
'Monaco',
|
||||
'Menlo',
|
||||
'Ubuntu Mono',
|
||||
'Consolas',
|
||||
'source-code-pro',
|
||||
'monospace'
|
||||
]
|
||||
const buildCMRulers = (rulers, enableRulers) =>
|
||||
enableRulers ? rulers.map(ruler => ({ column: ruler })) : []
|
||||
|
||||
class SnippetEditor extends React.Component {
|
||||
|
||||
componentDidMount () {
|
||||
componentDidMount() {
|
||||
this.props.onRef(this)
|
||||
const { rulers, enableRulers } = this.props
|
||||
this.cm = CodeMirror(this.refs.root, {
|
||||
@@ -49,38 +55,50 @@ class SnippetEditor extends React.Component {
|
||||
})
|
||||
}
|
||||
|
||||
componentWillUnmount () {
|
||||
componentWillUnmount() {
|
||||
this.props.onRef(undefined)
|
||||
}
|
||||
|
||||
onSnippetChanged (newSnippet) {
|
||||
onSnippetChanged(newSnippet) {
|
||||
this.snippet = newSnippet
|
||||
this.cm.setValue(this.snippet.content)
|
||||
}
|
||||
|
||||
onSnippetNameOrPrefixChanged (newSnippet) {
|
||||
onSnippetNameOrPrefixChanged(newSnippet) {
|
||||
this.snippet.name = newSnippet.name
|
||||
this.snippet.prefix = newSnippet.prefix.toString().replace(/\s/g, '').split(',')
|
||||
this.snippet.prefix = newSnippet.prefix
|
||||
.toString()
|
||||
.replace(/\s/g, '')
|
||||
.split(',')
|
||||
this.saveSnippet()
|
||||
}
|
||||
|
||||
saveSnippet () {
|
||||
dataApi.updateSnippet(this.snippet)
|
||||
saveSnippet() {
|
||||
dataApi
|
||||
.updateSnippet(this.snippet)
|
||||
.then(snippets => snippetManager.assignSnippets(snippets))
|
||||
.catch((err) => { throw err })
|
||||
.catch(err => {
|
||||
throw err
|
||||
})
|
||||
}
|
||||
|
||||
render () {
|
||||
render() {
|
||||
const { fontSize } = this.props
|
||||
let fontFamily = this.props.fontFamily
|
||||
fontFamily = _.isString(fontFamily) && fontFamily.length > 0
|
||||
? [fontFamily].concat(defaultEditorFontFamily)
|
||||
: defaultEditorFontFamily
|
||||
fontFamily =
|
||||
_.isString(fontFamily) && fontFamily.length > 0
|
||||
? [fontFamily].concat(defaultEditorFontFamily)
|
||||
: defaultEditorFontFamily
|
||||
return (
|
||||
<div styleName='SnippetEditor' ref='root' tabIndex='-1' style={{
|
||||
fontFamily: fontFamily.join(', '),
|
||||
fontSize: fontSize
|
||||
}} />
|
||||
<div
|
||||
styleName='SnippetEditor'
|
||||
ref='root'
|
||||
tabIndex='-1'
|
||||
style={{
|
||||
fontFamily: fontFamily.join(', '),
|
||||
fontSize: fontSize
|
||||
}}
|
||||
/>
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
@@ -7,53 +7,65 @@ import eventEmitter from 'browser/main/lib/eventEmitter'
|
||||
import context from 'browser/lib/context'
|
||||
|
||||
class SnippetList extends React.Component {
|
||||
constructor (props) {
|
||||
constructor(props) {
|
||||
super(props)
|
||||
this.state = {
|
||||
snippets: []
|
||||
}
|
||||
}
|
||||
|
||||
componentDidMount () {
|
||||
componentDidMount() {
|
||||
this.reloadSnippetList()
|
||||
eventEmitter.on('snippetList:reload', this.reloadSnippetList.bind(this))
|
||||
}
|
||||
|
||||
reloadSnippetList () {
|
||||
reloadSnippetList() {
|
||||
dataApi.fetchSnippet().then(snippets => {
|
||||
this.setState({snippets})
|
||||
this.setState({ snippets })
|
||||
this.props.onSnippetSelect(this.props.currentSnippet)
|
||||
})
|
||||
}
|
||||
|
||||
handleSnippetContextMenu (snippet) {
|
||||
context.popup([{
|
||||
label: i18n.__('Delete snippet'),
|
||||
click: () => this.deleteSnippet(snippet)
|
||||
}])
|
||||
handleSnippetContextMenu(snippet) {
|
||||
context.popup([
|
||||
{
|
||||
label: i18n.__('Delete snippet'),
|
||||
click: () => this.deleteSnippet(snippet)
|
||||
}
|
||||
])
|
||||
}
|
||||
|
||||
deleteSnippet (snippet) {
|
||||
dataApi.deleteSnippet(snippet).then(() => {
|
||||
this.reloadSnippetList()
|
||||
this.props.onSnippetDeleted(snippet)
|
||||
}).catch(err => { throw err })
|
||||
deleteSnippet(snippet) {
|
||||
dataApi
|
||||
.deleteSnippet(snippet)
|
||||
.then(() => {
|
||||
this.reloadSnippetList()
|
||||
this.props.onSnippetDeleted(snippet)
|
||||
})
|
||||
.catch(err => {
|
||||
throw err
|
||||
})
|
||||
}
|
||||
|
||||
handleSnippetClick (snippet) {
|
||||
handleSnippetClick(snippet) {
|
||||
this.props.onSnippetSelect(snippet)
|
||||
}
|
||||
|
||||
createSnippet () {
|
||||
dataApi.createSnippet().then(() => {
|
||||
this.reloadSnippetList()
|
||||
// scroll to end of list when added new snippet
|
||||
const snippetList = document.getElementById('snippets')
|
||||
snippetList.scrollTop = snippetList.scrollHeight
|
||||
}).catch(err => { throw err })
|
||||
createSnippet() {
|
||||
dataApi
|
||||
.createSnippet()
|
||||
.then(() => {
|
||||
this.reloadSnippetList()
|
||||
// scroll to end of list when added new snippet
|
||||
const snippetList = document.getElementById('snippets')
|
||||
snippetList.scrollTop = snippetList.scrollHeight
|
||||
})
|
||||
.catch(err => {
|
||||
throw err
|
||||
})
|
||||
}
|
||||
|
||||
defineSnippetStyleName (snippet) {
|
||||
defineSnippetStyleName(snippet) {
|
||||
const { currentSnippet } = this.props
|
||||
|
||||
if (currentSnippet == null) {
|
||||
@@ -67,29 +79,31 @@ class SnippetList extends React.Component {
|
||||
}
|
||||
}
|
||||
|
||||
render () {
|
||||
render() {
|
||||
const { snippets } = this.state
|
||||
return (
|
||||
<div styleName='snippet-list'>
|
||||
<div styleName='group-section'>
|
||||
<div styleName='group-section-control'>
|
||||
<button styleName='group-control-button' onClick={() => this.createSnippet()}>
|
||||
<button
|
||||
styleName='group-control-button'
|
||||
onClick={() => this.createSnippet()}
|
||||
>
|
||||
<i className='fa fa-plus' /> {i18n.__('New Snippet')}
|
||||
</button>
|
||||
</div>
|
||||
</div>
|
||||
<ul id='snippets' styleName='snippets'>
|
||||
{
|
||||
snippets.map((snippet) => (
|
||||
<li
|
||||
styleName={this.defineSnippetStyleName(snippet)}
|
||||
key={snippet.id}
|
||||
onContextMenu={() => this.handleSnippetContextMenu(snippet)}
|
||||
onClick={() => this.handleSnippetClick(snippet)}>
|
||||
{snippet.name}
|
||||
</li>
|
||||
))
|
||||
}
|
||||
{snippets.map(snippet => (
|
||||
<li
|
||||
styleName={this.defineSnippetStyleName(snippet)}
|
||||
key={snippet.id}
|
||||
onContextMenu={() => this.handleSnippetContextMenu(snippet)}
|
||||
onClick={() => this.handleSnippetClick(snippet)}
|
||||
>
|
||||
{snippet.name}
|
||||
</li>
|
||||
))}
|
||||
</ul>
|
||||
</div>
|
||||
)
|
||||
|
||||
@@ -11,7 +11,7 @@ import copy from 'copy-to-clipboard'
|
||||
const path = require('path')
|
||||
|
||||
class SnippetTab extends React.Component {
|
||||
constructor (props) {
|
||||
constructor(props) {
|
||||
super(props)
|
||||
this.state = {
|
||||
currentSnippet: null
|
||||
@@ -19,7 +19,7 @@ class SnippetTab extends React.Component {
|
||||
this.changeDelay = null
|
||||
}
|
||||
|
||||
notify (title, options) {
|
||||
notify(title, options) {
|
||||
if (global.process.platform === 'win32') {
|
||||
options.icon = path.join(
|
||||
'file://',
|
||||
@@ -30,7 +30,7 @@ class SnippetTab extends React.Component {
|
||||
return new window.Notification(title, options)
|
||||
}
|
||||
|
||||
handleSnippetNameOrPrefixChange () {
|
||||
handleSnippetNameOrPrefixChange() {
|
||||
clearTimeout(this.changeDelay)
|
||||
this.changeDelay = setTimeout(() => {
|
||||
// notify the snippet editor that the name or prefix of snippet has been changed
|
||||
@@ -39,20 +39,20 @@ class SnippetTab extends React.Component {
|
||||
}, 500)
|
||||
}
|
||||
|
||||
handleSnippetSelect (snippet) {
|
||||
handleSnippetSelect(snippet) {
|
||||
const { currentSnippet } = this.state
|
||||
if (snippet !== null) {
|
||||
if (currentSnippet === null || currentSnippet.id !== snippet.id) {
|
||||
dataApi.fetchSnippet(snippet.id).then(changedSnippet => {
|
||||
// notify the snippet editor to load the content of the new snippet
|
||||
this.snippetEditor.onSnippetChanged(changedSnippet)
|
||||
this.setState({currentSnippet: changedSnippet})
|
||||
this.setState({ currentSnippet: changedSnippet })
|
||||
})
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
onSnippetNameOrPrefixChanged (e, type) {
|
||||
onSnippetNameOrPrefixChanged(e, type) {
|
||||
const newSnippet = Object.assign({}, this.state.currentSnippet)
|
||||
if (type === 'name') {
|
||||
newSnippet.name = e.target.value
|
||||
@@ -63,14 +63,14 @@ class SnippetTab extends React.Component {
|
||||
this.handleSnippetNameOrPrefixChange()
|
||||
}
|
||||
|
||||
handleDeleteSnippet (snippet) {
|
||||
handleDeleteSnippet(snippet) {
|
||||
// prevent old snippet still display when deleted
|
||||
if (snippet.id === this.state.currentSnippet.id) {
|
||||
this.setState({currentSnippet: null})
|
||||
this.setState({ currentSnippet: null })
|
||||
}
|
||||
}
|
||||
|
||||
handleCopySnippet (e) {
|
||||
handleCopySnippet(e) {
|
||||
const showCopyNotification = this.props.config.ui.showCopyNotification
|
||||
copy(this.state.currentSnippet.content)
|
||||
if (showCopyNotification) {
|
||||
@@ -81,7 +81,7 @@ class SnippetTab extends React.Component {
|
||||
}
|
||||
}
|
||||
|
||||
render () {
|
||||
render() {
|
||||
const { config, storageKey } = this.props
|
||||
const { currentSnippet } = this.state
|
||||
|
||||
@@ -95,12 +95,19 @@ class SnippetTab extends React.Component {
|
||||
<SnippetList
|
||||
onSnippetSelect={this.handleSnippetSelect.bind(this)}
|
||||
onSnippetDeleted={this.handleDeleteSnippet.bind(this)}
|
||||
currentSnippet={currentSnippet} />
|
||||
<div styleName='snippet-detail' style={{visibility: currentSnippet ? 'visible' : 'hidden'}}>
|
||||
currentSnippet={currentSnippet}
|
||||
/>
|
||||
<div
|
||||
styleName='snippet-detail'
|
||||
style={{ visibility: currentSnippet ? 'visible' : 'hidden' }}
|
||||
>
|
||||
<div styleName='group-section'>
|
||||
<div styleName='group-section-control'>
|
||||
<button styleName='group-control-rightButton'
|
||||
onClick={e => this.handleCopySnippet(e)}>{i18n.__('Copy')}
|
||||
<button
|
||||
styleName='group-control-rightButton'
|
||||
onClick={e => this.handleCopySnippet(e)}
|
||||
>
|
||||
{i18n.__('Copy')}
|
||||
</button>
|
||||
</div>
|
||||
</div>
|
||||
@@ -110,18 +117,26 @@ class SnippetTab extends React.Component {
|
||||
<input
|
||||
styleName='group-section-control-input'
|
||||
value={currentSnippet ? currentSnippet.name : ''}
|
||||
onChange={e => { this.onSnippetNameOrPrefixChanged(e, 'name') }}
|
||||
type='text' />
|
||||
onChange={e => {
|
||||
this.onSnippetNameOrPrefixChanged(e, 'name')
|
||||
}}
|
||||
type='text'
|
||||
/>
|
||||
</div>
|
||||
</div>
|
||||
<div styleName='group-section'>
|
||||
<div styleName='group-section-label'>{i18n.__('Snippet prefix')}</div>
|
||||
<div styleName='group-section-label'>
|
||||
{i18n.__('Snippet prefix')}
|
||||
</div>
|
||||
<div styleName='group-section-control'>
|
||||
<input
|
||||
styleName='group-section-control-input'
|
||||
value={currentSnippet ? currentSnippet.prefix : ''}
|
||||
onChange={e => { this.onSnippetNameOrPrefixChanged(e, 'prefix') }}
|
||||
type='text' />
|
||||
onChange={e => {
|
||||
this.onSnippetNameOrPrefixChanged(e, 'prefix')
|
||||
}}
|
||||
type='text'
|
||||
/>
|
||||
</div>
|
||||
</div>
|
||||
<div styleName='snippet-editor-section'>
|
||||
@@ -140,7 +155,10 @@ class SnippetTab extends React.Component {
|
||||
matchingTriples={config.editor.matchingTriples}
|
||||
explodingPairs={config.editor.explodingPairs}
|
||||
scrollPastEnd={config.editor.scrollPastEnd}
|
||||
onRef={ref => { this.snippetEditor = ref }} />
|
||||
onRef={ref => {
|
||||
this.snippetEditor = ref
|
||||
}}
|
||||
/>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
@@ -148,7 +166,6 @@ class SnippetTab extends React.Component {
|
||||
}
|
||||
}
|
||||
|
||||
SnippetTab.PropTypes = {
|
||||
}
|
||||
SnippetTab.PropTypes = {}
|
||||
|
||||
export default CSSModules(SnippetTab, styles)
|
||||
|
||||
@@ -12,7 +12,7 @@ const { shell, remote } = require('electron')
|
||||
const { dialog } = remote
|
||||
|
||||
class StorageItem extends React.Component {
|
||||
constructor (props) {
|
||||
constructor(props) {
|
||||
super(props)
|
||||
|
||||
this.state = {
|
||||
@@ -20,137 +20,156 @@ class StorageItem extends React.Component {
|
||||
}
|
||||
}
|
||||
|
||||
handleNewFolderButtonClick (e) {
|
||||
handleNewFolderButtonClick(e) {
|
||||
const { storage } = this.props
|
||||
const input = {
|
||||
name: i18n.__('New Folder'),
|
||||
color: consts.FOLDER_COLORS[Math.floor(Math.random() * 7) % 7]
|
||||
}
|
||||
|
||||
dataApi.createFolder(storage.key, input)
|
||||
.then((data) => {
|
||||
dataApi
|
||||
.createFolder(storage.key, input)
|
||||
.then(data => {
|
||||
store.dispatch({
|
||||
type: 'UPDATE_FOLDER',
|
||||
storage: data.storage
|
||||
})
|
||||
})
|
||||
.catch((err) => {
|
||||
.catch(err => {
|
||||
console.error(err)
|
||||
})
|
||||
}
|
||||
|
||||
handleExternalButtonClick () {
|
||||
handleExternalButtonClick() {
|
||||
const { storage } = this.props
|
||||
shell.showItemInFolder(storage.path)
|
||||
}
|
||||
|
||||
handleUnlinkButtonClick (e) {
|
||||
handleUnlinkButtonClick(e) {
|
||||
const index = dialog.showMessageBox(remote.getCurrentWindow(), {
|
||||
type: 'warning',
|
||||
message: i18n.__('Unlink Storage'),
|
||||
detail: i18n.__('Unlinking removes this linked storage from Boostnote. No data is removed, please manually delete the folder from your hard drive if needed.'),
|
||||
detail: i18n.__(
|
||||
'Unlinking removes this linked storage from Boostnote. No data is removed, please manually delete the folder from your hard drive if needed.'
|
||||
),
|
||||
buttons: [i18n.__('Unlink'), i18n.__('Cancel')]
|
||||
})
|
||||
|
||||
if (index === 0) {
|
||||
const { storage } = this.props
|
||||
dataApi.removeStorage(storage.key)
|
||||
dataApi
|
||||
.removeStorage(storage.key)
|
||||
.then(() => {
|
||||
store.dispatch({
|
||||
type: 'REMOVE_STORAGE',
|
||||
storageKey: storage.key
|
||||
})
|
||||
})
|
||||
.catch((err) => {
|
||||
.catch(err => {
|
||||
throw err
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
handleLabelClick (e) {
|
||||
handleLabelClick(e) {
|
||||
const { storage } = this.props
|
||||
this.setState({
|
||||
isLabelEditing: true,
|
||||
name: storage.name
|
||||
}, () => {
|
||||
this.refs.label.focus()
|
||||
})
|
||||
this.setState(
|
||||
{
|
||||
isLabelEditing: true,
|
||||
name: storage.name
|
||||
},
|
||||
() => {
|
||||
this.refs.label.focus()
|
||||
}
|
||||
)
|
||||
}
|
||||
handleLabelChange (e) {
|
||||
handleLabelChange(e) {
|
||||
this.setState({
|
||||
name: this.refs.label.value
|
||||
})
|
||||
}
|
||||
|
||||
handleLabelBlur (e) {
|
||||
handleLabelBlur(e) {
|
||||
const { storage } = this.props
|
||||
dataApi
|
||||
.renameStorage(storage.key, this.state.name)
|
||||
.then((_storage) => {
|
||||
store.dispatch({
|
||||
type: 'RENAME_STORAGE',
|
||||
storage: _storage
|
||||
})
|
||||
this.setState({
|
||||
isLabelEditing: false
|
||||
})
|
||||
dataApi.renameStorage(storage.key, this.state.name).then(_storage => {
|
||||
store.dispatch({
|
||||
type: 'RENAME_STORAGE',
|
||||
storage: _storage
|
||||
})
|
||||
this.setState({
|
||||
isLabelEditing: false
|
||||
})
|
||||
})
|
||||
}
|
||||
|
||||
render () {
|
||||
render() {
|
||||
const { storage, hostBoundingBox } = this.props
|
||||
|
||||
return (
|
||||
<div styleName='root' key={storage.key}>
|
||||
<div styleName='header'>
|
||||
{this.state.isLabelEditing
|
||||
? <div styleName='header-label--edit'>
|
||||
<input styleName='header-label-input'
|
||||
{this.state.isLabelEditing ? (
|
||||
<div styleName='header-label--edit'>
|
||||
<input
|
||||
styleName='header-label-input'
|
||||
value={this.state.name}
|
||||
ref='label'
|
||||
onChange={(e) => this.handleLabelChange(e)}
|
||||
onBlur={(e) => this.handleLabelBlur(e)}
|
||||
onChange={e => this.handleLabelChange(e)}
|
||||
onBlur={e => this.handleLabelBlur(e)}
|
||||
/>
|
||||
</div>
|
||||
: <div styleName='header-label'
|
||||
onClick={(e) => this.handleLabelClick(e)}
|
||||
) : (
|
||||
<div
|
||||
styleName='header-label'
|
||||
onClick={e => this.handleLabelClick(e)}
|
||||
>
|
||||
<i className='fa fa-folder-open' />
|
||||
<i className='fa fa-folder-open' />
|
||||
|
||||
{storage.name}
|
||||
<span styleName='header-label-path'>({storage.path})</span>
|
||||
<i styleName='header-label-editButton' className='fa fa-pencil' />
|
||||
</div>
|
||||
}
|
||||
)}
|
||||
<div styleName='header-control'>
|
||||
<button styleName='header-control-button'
|
||||
onClick={(e) => this.handleNewFolderButtonClick(e)}
|
||||
<button
|
||||
styleName='header-control-button'
|
||||
onClick={e => this.handleNewFolderButtonClick(e)}
|
||||
>
|
||||
<i className='fa fa-plus' />
|
||||
<span styleName='header-control-button-tooltip'
|
||||
style={{left: -20}}
|
||||
>{i18n.__('Add Folder')}</span>
|
||||
<span
|
||||
styleName='header-control-button-tooltip'
|
||||
style={{ left: -20 }}
|
||||
>
|
||||
{i18n.__('Add Folder')}
|
||||
</span>
|
||||
</button>
|
||||
<button styleName='header-control-button'
|
||||
onClick={(e) => this.handleExternalButtonClick(e)}
|
||||
<button
|
||||
styleName='header-control-button'
|
||||
onClick={e => this.handleExternalButtonClick(e)}
|
||||
>
|
||||
<i className='fa fa-external-link' />
|
||||
<span styleName='header-control-button-tooltip'
|
||||
style={{left: -50}}
|
||||
>{i18n.__('Open Storage folder')}</span>
|
||||
<span
|
||||
styleName='header-control-button-tooltip'
|
||||
style={{ left: -50 }}
|
||||
>
|
||||
{i18n.__('Open Storage folder')}
|
||||
</span>
|
||||
</button>
|
||||
<button styleName='header-control-button'
|
||||
onClick={(e) => this.handleUnlinkButtonClick(e)}
|
||||
<button
|
||||
styleName='header-control-button'
|
||||
onClick={e => this.handleUnlinkButtonClick(e)}
|
||||
>
|
||||
<i className='fa fa-unlink' />
|
||||
<span styleName='header-control-button-tooltip'
|
||||
style={{left: -10}}
|
||||
>{i18n.__('Unlink')}</span>
|
||||
<span
|
||||
styleName='header-control-button-tooltip'
|
||||
style={{ left: -10 }}
|
||||
>
|
||||
{i18n.__('Unlink')}
|
||||
</span>
|
||||
</button>
|
||||
</div>
|
||||
</div>
|
||||
<FolderList storage={storage}
|
||||
hostBoundingBox={hostBoundingBox}
|
||||
/>
|
||||
<FolderList storage={storage} hostBoundingBox={hostBoundingBox} />
|
||||
</div>
|
||||
)
|
||||
}
|
||||
|
||||
@@ -12,24 +12,27 @@ import fs from 'fs'
|
||||
const electron = require('electron')
|
||||
const { shell, remote } = electron
|
||||
|
||||
function browseFolder () {
|
||||
function browseFolder() {
|
||||
const dialog = remote.dialog
|
||||
|
||||
const defaultPath = remote.app.getPath('home')
|
||||
return new Promise((resolve, reject) => {
|
||||
dialog.showOpenDialog({
|
||||
title: i18n.__('Select Directory'),
|
||||
defaultPath,
|
||||
properties: ['openDirectory', 'createDirectory']
|
||||
}, function (targetPaths) {
|
||||
if (targetPaths == null) return resolve('')
|
||||
resolve(targetPaths[0])
|
||||
})
|
||||
dialog.showOpenDialog(
|
||||
{
|
||||
title: i18n.__('Select Directory'),
|
||||
defaultPath,
|
||||
properties: ['openDirectory', 'createDirectory']
|
||||
},
|
||||
function(targetPaths) {
|
||||
if (targetPaths == null) return resolve('')
|
||||
resolve(targetPaths[0])
|
||||
}
|
||||
)
|
||||
})
|
||||
}
|
||||
|
||||
class StoragesTab extends React.Component {
|
||||
constructor (props) {
|
||||
constructor(props) {
|
||||
super(props)
|
||||
|
||||
this.state = {
|
||||
@@ -44,7 +47,7 @@ class StoragesTab extends React.Component {
|
||||
this.loadAttachmentStorage()
|
||||
}
|
||||
|
||||
loadAttachmentStorage () {
|
||||
loadAttachmentStorage() {
|
||||
const promises = []
|
||||
this.props.data.noteMap.map(note => {
|
||||
const promise = attachmentManagement.getAttachmentsPathAndStatus(
|
||||
@@ -58,106 +61,128 @@ class StoragesTab extends React.Component {
|
||||
Promise.all(promises)
|
||||
.then(data => {
|
||||
const result = data.reduce((acc, curr) => acc.concat(curr), [])
|
||||
this.setState({attachments: result})
|
||||
this.setState({ attachments: result })
|
||||
})
|
||||
.catch(console.error)
|
||||
}
|
||||
|
||||
handleAddStorageButton (e) {
|
||||
this.setState({
|
||||
page: 'ADD_STORAGE',
|
||||
newStorage: {
|
||||
name: 'Unnamed',
|
||||
type: 'FILESYSTEM',
|
||||
path: ''
|
||||
handleAddStorageButton(e) {
|
||||
this.setState(
|
||||
{
|
||||
page: 'ADD_STORAGE',
|
||||
newStorage: {
|
||||
name: 'Unnamed',
|
||||
type: 'FILESYSTEM',
|
||||
path: ''
|
||||
}
|
||||
},
|
||||
() => {
|
||||
this.refs.addStorageName.select()
|
||||
}
|
||||
}, () => {
|
||||
this.refs.addStorageName.select()
|
||||
})
|
||||
)
|
||||
}
|
||||
|
||||
handleLinkClick (e) {
|
||||
handleLinkClick(e) {
|
||||
shell.openExternal(e.currentTarget.href)
|
||||
e.preventDefault()
|
||||
}
|
||||
|
||||
handleRemoveUnusedAttachments (attachments) {
|
||||
attachmentManagement.removeAttachmentsByPaths(attachments)
|
||||
handleRemoveUnusedAttachments(attachments) {
|
||||
attachmentManagement
|
||||
.removeAttachmentsByPaths(attachments)
|
||||
.then(() => this.loadAttachmentStorage())
|
||||
.catch(console.error)
|
||||
}
|
||||
|
||||
renderList () {
|
||||
renderList() {
|
||||
const { data, boundingBox } = this.props
|
||||
const { attachments } = this.state
|
||||
|
||||
const unusedAttachments = attachments.filter(attachment => !attachment.isInUse)
|
||||
const inUseAttachments = attachments.filter(attachment => attachment.isInUse)
|
||||
const unusedAttachments = attachments.filter(
|
||||
attachment => !attachment.isInUse
|
||||
)
|
||||
const inUseAttachments = attachments.filter(
|
||||
attachment => attachment.isInUse
|
||||
)
|
||||
|
||||
const totalUnusedAttachments = unusedAttachments.length
|
||||
const totalInuseAttachments = inUseAttachments.length
|
||||
const totalAttachments = totalUnusedAttachments + totalInuseAttachments
|
||||
|
||||
const totalUnusedAttachmentsSize = unusedAttachments
|
||||
.reduce((acc, curr) => {
|
||||
const stats = fs.statSync(curr.path)
|
||||
const fileSizeInBytes = stats.size
|
||||
return acc + fileSizeInBytes
|
||||
}, 0)
|
||||
const totalInuseAttachmentsSize = inUseAttachments
|
||||
.reduce((acc, curr) => {
|
||||
const stats = fs.statSync(curr.path)
|
||||
const fileSizeInBytes = stats.size
|
||||
return acc + fileSizeInBytes
|
||||
}, 0)
|
||||
const totalAttachmentsSize = totalUnusedAttachmentsSize + totalInuseAttachmentsSize
|
||||
const totalUnusedAttachmentsSize = unusedAttachments.reduce((acc, curr) => {
|
||||
const stats = fs.statSync(curr.path)
|
||||
const fileSizeInBytes = stats.size
|
||||
return acc + fileSizeInBytes
|
||||
}, 0)
|
||||
const totalInuseAttachmentsSize = inUseAttachments.reduce((acc, curr) => {
|
||||
const stats = fs.statSync(curr.path)
|
||||
const fileSizeInBytes = stats.size
|
||||
return acc + fileSizeInBytes
|
||||
}, 0)
|
||||
const totalAttachmentsSize =
|
||||
totalUnusedAttachmentsSize + totalInuseAttachmentsSize
|
||||
|
||||
const unusedAttachmentPaths = unusedAttachments
|
||||
.reduce((acc, curr) => acc.concat(curr.path), [])
|
||||
const unusedAttachmentPaths = unusedAttachments.reduce(
|
||||
(acc, curr) => acc.concat(curr.path),
|
||||
[]
|
||||
)
|
||||
|
||||
if (!boundingBox) { return null }
|
||||
const storageList = data.storageMap.map((storage) => {
|
||||
return <StorageItem
|
||||
key={storage.key}
|
||||
storage={storage}
|
||||
hostBoundingBox={boundingBox}
|
||||
/>
|
||||
if (!boundingBox) {
|
||||
return null
|
||||
}
|
||||
const storageList = data.storageMap.map(storage => {
|
||||
return (
|
||||
<StorageItem
|
||||
key={storage.key}
|
||||
storage={storage}
|
||||
hostBoundingBox={boundingBox}
|
||||
/>
|
||||
)
|
||||
})
|
||||
return (
|
||||
<div styleName='list'>
|
||||
<div styleName='header'>{i18n.__('Storage Locations')}</div>
|
||||
{storageList.length > 0
|
||||
? storageList
|
||||
: <div styleName='list-empty'>{i18n.__('No storage found.')}</div>
|
||||
}
|
||||
{storageList.length > 0 ? (
|
||||
storageList
|
||||
) : (
|
||||
<div styleName='list-empty'>{i18n.__('No storage found.')}</div>
|
||||
)}
|
||||
<div styleName='list-control'>
|
||||
<button styleName='list-control-addStorageButton'
|
||||
onClick={(e) => this.handleAddStorageButton(e)}
|
||||
<button
|
||||
styleName='list-control-addStorageButton'
|
||||
onClick={e => this.handleAddStorageButton(e)}
|
||||
>
|
||||
<i className='fa fa-plus' /> {i18n.__('Add Storage Location')}
|
||||
</button>
|
||||
</div>
|
||||
<div styleName='header'>{i18n.__('Attachment storage')}</div>
|
||||
<p styleName='list-attachment-label'>
|
||||
Unused attachments size: {humanFileSize(totalUnusedAttachmentsSize)} ({totalUnusedAttachments} items)
|
||||
Unused attachments size: {humanFileSize(totalUnusedAttachmentsSize)} (
|
||||
{totalUnusedAttachments} items)
|
||||
</p>
|
||||
<p styleName='list-attachment-label'>
|
||||
In use attachments size: {humanFileSize(totalInuseAttachmentsSize)} ({totalInuseAttachments} items)
|
||||
In use attachments size: {humanFileSize(totalInuseAttachmentsSize)} (
|
||||
{totalInuseAttachments} items)
|
||||
</p>
|
||||
<p styleName='list-attachment-label'>
|
||||
Total attachments size: {humanFileSize(totalAttachmentsSize)} ({totalAttachments} items)
|
||||
Total attachments size: {humanFileSize(totalAttachmentsSize)} (
|
||||
{totalAttachments} items)
|
||||
</p>
|
||||
<button styleName='list-attachement-clear-button'
|
||||
onClick={() => this.handleRemoveUnusedAttachments(unusedAttachmentPaths)}>
|
||||
<button
|
||||
styleName='list-attachement-clear-button'
|
||||
onClick={() =>
|
||||
this.handleRemoveUnusedAttachments(unusedAttachmentPaths)
|
||||
}
|
||||
>
|
||||
{i18n.__('Clear unused attachments')}
|
||||
</button>
|
||||
</div>
|
||||
)
|
||||
}
|
||||
|
||||
handleAddStorageBrowseButtonClick (e) {
|
||||
handleAddStorageBrowseButtonClick(e) {
|
||||
browseFolder()
|
||||
.then((targetPath) => {
|
||||
.then(targetPath => {
|
||||
if (targetPath.length > 0) {
|
||||
const { newStorage } = this.state
|
||||
newStorage.path = targetPath
|
||||
@@ -166,13 +191,13 @@ class StoragesTab extends React.Component {
|
||||
})
|
||||
}
|
||||
})
|
||||
.catch((err) => {
|
||||
.catch(err => {
|
||||
console.error('BrowseFAILED')
|
||||
console.error(err)
|
||||
})
|
||||
}
|
||||
|
||||
handleAddStorageChange (e) {
|
||||
handleAddStorageChange(e) {
|
||||
const { newStorage } = this.state
|
||||
newStorage.name = this.refs.addStorageName.value
|
||||
newStorage.path = this.refs.addStoragePath.value
|
||||
@@ -181,13 +206,13 @@ class StoragesTab extends React.Component {
|
||||
})
|
||||
}
|
||||
|
||||
handleAddStorageCreateButton (e) {
|
||||
handleAddStorageCreateButton(e) {
|
||||
dataApi
|
||||
.addStorage({
|
||||
name: this.state.newStorage.name,
|
||||
path: this.state.newStorage.path
|
||||
})
|
||||
.then((data) => {
|
||||
.then(data => {
|
||||
const { dispatch } = this.props
|
||||
dispatch({
|
||||
type: 'ADD_STORAGE',
|
||||
@@ -200,37 +225,39 @@ class StoragesTab extends React.Component {
|
||||
})
|
||||
}
|
||||
|
||||
handleAddStorageCancelButton (e) {
|
||||
handleAddStorageCancelButton(e) {
|
||||
this.setState({
|
||||
page: 'LIST'
|
||||
})
|
||||
}
|
||||
|
||||
renderAddStorage () {
|
||||
renderAddStorage() {
|
||||
return (
|
||||
<div styleName='addStorage'>
|
||||
|
||||
<div styleName='addStorage-header'>{i18n.__('Add Storage')}</div>
|
||||
|
||||
<div styleName='addStorage-body'>
|
||||
|
||||
<div styleName='addStorage-body-section'>
|
||||
<div styleName='addStorage-body-section-label'>
|
||||
{i18n.__('Name')}
|
||||
</div>
|
||||
<div styleName='addStorage-body-section-name'>
|
||||
<input styleName='addStorage-body-section-name-input'
|
||||
<input
|
||||
styleName='addStorage-body-section-name-input'
|
||||
ref='addStorageName'
|
||||
value={this.state.newStorage.name}
|
||||
onChange={(e) => this.handleAddStorageChange(e)}
|
||||
onChange={e => this.handleAddStorageChange(e)}
|
||||
/>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div styleName='addStorage-body-section'>
|
||||
<div styleName='addStorage-body-section-label'>{i18n.__('Type')}</div>
|
||||
<div styleName='addStorage-body-section-label'>
|
||||
{i18n.__('Type')}
|
||||
</div>
|
||||
<div styleName='addStorage-body-section-type'>
|
||||
<select styleName='addStorage-body-section-type-select'
|
||||
<select
|
||||
styleName='addStorage-body-section-type-select'
|
||||
value={this.state.newStorage.type}
|
||||
readOnly
|
||||
>
|
||||
@@ -238,25 +265,31 @@ class StoragesTab extends React.Component {
|
||||
</select>
|
||||
<div styleName='addStorage-body-section-type-description'>
|
||||
{i18n.__('Setting up 3rd-party cloud storage integration:')}{' '}
|
||||
<a href='https://github.com/BoostIO/Boostnote/wiki/Cloud-Syncing-and-Backup'
|
||||
onClick={(e) => this.handleLinkClick(e)}
|
||||
>{i18n.__('Cloud-Syncing-and-Backup')}</a>
|
||||
<a
|
||||
href='https://github.com/BoostIO/Boostnote/wiki/Cloud-Syncing-and-Backup'
|
||||
onClick={e => this.handleLinkClick(e)}
|
||||
>
|
||||
{i18n.__('Cloud-Syncing-and-Backup')}
|
||||
</a>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div styleName='addStorage-body-section'>
|
||||
<div styleName='addStorage-body-section-label'>{i18n.__('Location')}
|
||||
<div styleName='addStorage-body-section-label'>
|
||||
{i18n.__('Location')}
|
||||
</div>
|
||||
<div styleName='addStorage-body-section-path'>
|
||||
<input styleName='addStorage-body-section-path-input'
|
||||
<input
|
||||
styleName='addStorage-body-section-path-input'
|
||||
ref='addStoragePath'
|
||||
placeholder={i18n.__('Select Folder')}
|
||||
value={this.state.newStorage.path}
|
||||
onChange={(e) => this.handleAddStorageChange(e)}
|
||||
onChange={e => this.handleAddStorageChange(e)}
|
||||
/>
|
||||
<button styleName='addStorage-body-section-path-button'
|
||||
onClick={(e) => this.handleAddStorageBrowseButtonClick(e)}
|
||||
<button
|
||||
styleName='addStorage-body-section-path-button'
|
||||
onClick={e => this.handleAddStorageBrowseButtonClick(e)}
|
||||
>
|
||||
...
|
||||
</button>
|
||||
@@ -264,21 +297,25 @@ class StoragesTab extends React.Component {
|
||||
</div>
|
||||
|
||||
<div styleName='addStorage-body-control'>
|
||||
<button styleName='addStorage-body-control-createButton'
|
||||
onClick={(e) => this.handleAddStorageCreateButton(e)}
|
||||
>{i18n.__('Add')}</button>
|
||||
<button styleName='addStorage-body-control-cancelButton'
|
||||
onClick={(e) => this.handleAddStorageCancelButton(e)}
|
||||
>{i18n.__('Cancel')}</button>
|
||||
<button
|
||||
styleName='addStorage-body-control-createButton'
|
||||
onClick={e => this.handleAddStorageCreateButton(e)}
|
||||
>
|
||||
{i18n.__('Add')}
|
||||
</button>
|
||||
<button
|
||||
styleName='addStorage-body-control-cancelButton'
|
||||
onClick={e => this.handleAddStorageCancelButton(e)}
|
||||
>
|
||||
{i18n.__('Cancel')}
|
||||
</button>
|
||||
</div>
|
||||
|
||||
</div>
|
||||
|
||||
</div>
|
||||
)
|
||||
}
|
||||
|
||||
renderContent () {
|
||||
renderContent() {
|
||||
switch (this.state.page) {
|
||||
case 'ADD_STORAGE':
|
||||
case 'ADD_FOLDER':
|
||||
@@ -289,12 +326,8 @@ class StoragesTab extends React.Component {
|
||||
}
|
||||
}
|
||||
|
||||
render () {
|
||||
return (
|
||||
<div styleName='root'>
|
||||
{this.renderContent()}
|
||||
</div>
|
||||
)
|
||||
render() {
|
||||
return <div styleName='root'>{this.renderContent()}</div>
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
File diff suppressed because it is too large
Load Diff
@@ -16,7 +16,7 @@ import _ from 'lodash'
|
||||
import i18n from 'browser/lib/i18n'
|
||||
|
||||
class Preferences extends React.Component {
|
||||
constructor (props) {
|
||||
constructor(props) {
|
||||
super(props)
|
||||
|
||||
this.state = {
|
||||
@@ -27,44 +27,39 @@ class Preferences extends React.Component {
|
||||
}
|
||||
}
|
||||
|
||||
componentDidMount () {
|
||||
componentDidMount() {
|
||||
this.refs.root.focus()
|
||||
const boundingBox = this.getContentBoundingBox()
|
||||
this.setState({ boundingBox })
|
||||
}
|
||||
|
||||
switchTeam (teamId) {
|
||||
this.setState({currentTeamId: teamId})
|
||||
switchTeam(teamId) {
|
||||
this.setState({ currentTeamId: teamId })
|
||||
}
|
||||
|
||||
handleNavButtonClick (tab) {
|
||||
return (e) => {
|
||||
this.setState({currentTab: tab})
|
||||
handleNavButtonClick(tab) {
|
||||
return e => {
|
||||
this.setState({ currentTab: tab })
|
||||
}
|
||||
}
|
||||
|
||||
handleEscButtonClick () {
|
||||
handleEscButtonClick() {
|
||||
this.props.close()
|
||||
}
|
||||
|
||||
renderContent () {
|
||||
renderContent() {
|
||||
const { boundingBox } = this.state
|
||||
const { dispatch, config, data } = this.props
|
||||
|
||||
switch (this.state.currentTab) {
|
||||
case 'INFO':
|
||||
return (
|
||||
<InfoTab
|
||||
dispatch={dispatch}
|
||||
config={config}
|
||||
/>
|
||||
)
|
||||
return <InfoTab dispatch={dispatch} config={config} />
|
||||
case 'HOTKEY':
|
||||
return (
|
||||
<HotkeyTab
|
||||
dispatch={dispatch}
|
||||
config={config}
|
||||
haveToSave={alert => this.setState({HotkeyAlert: alert})}
|
||||
haveToSave={alert => this.setState({ HotkeyAlert: alert })}
|
||||
/>
|
||||
)
|
||||
case 'UI':
|
||||
@@ -72,29 +67,21 @@ class Preferences extends React.Component {
|
||||
<UiTab
|
||||
dispatch={dispatch}
|
||||
config={config}
|
||||
haveToSave={alert => this.setState({UIAlert: alert})}
|
||||
haveToSave={alert => this.setState({ UIAlert: alert })}
|
||||
/>
|
||||
)
|
||||
case 'CROWDFUNDING':
|
||||
return (
|
||||
<Crowdfunding />
|
||||
)
|
||||
return <Crowdfunding />
|
||||
case 'BLOG':
|
||||
return (
|
||||
<Blog
|
||||
dispatch={dispatch}
|
||||
config={config}
|
||||
haveToSave={alert => this.setState({BlogAlert: alert})}
|
||||
haveToSave={alert => this.setState({ BlogAlert: alert })}
|
||||
/>
|
||||
)
|
||||
case 'SNIPPET':
|
||||
return (
|
||||
<SnippetTab
|
||||
dispatch={dispatch}
|
||||
config={config}
|
||||
data={data}
|
||||
/>
|
||||
)
|
||||
return <SnippetTab dispatch={dispatch} config={config} data={data} />
|
||||
case 'STORAGES':
|
||||
default:
|
||||
return (
|
||||
@@ -107,67 +94,69 @@ class Preferences extends React.Component {
|
||||
}
|
||||
}
|
||||
|
||||
handleKeyDown (e) {
|
||||
handleKeyDown(e) {
|
||||
if (e.keyCode === 27) {
|
||||
this.props.close()
|
||||
}
|
||||
}
|
||||
|
||||
getContentBoundingBox () {
|
||||
getContentBoundingBox() {
|
||||
return this.refs.content.getBoundingClientRect()
|
||||
}
|
||||
|
||||
haveToSaveNotif (type, message) {
|
||||
return (
|
||||
<p styleName={`saving--${type}`}>{message}</p>
|
||||
)
|
||||
haveToSaveNotif(type, message) {
|
||||
return <p styleName={`saving--${type}`}>{message}</p>
|
||||
}
|
||||
|
||||
render () {
|
||||
render() {
|
||||
const content = this.renderContent()
|
||||
|
||||
const tabs = [
|
||||
{target: 'STORAGES', label: i18n.__('Storage')},
|
||||
{target: 'HOTKEY', label: i18n.__('Hotkeys'), Hotkey: this.state.HotkeyAlert},
|
||||
{target: 'UI', label: i18n.__('Interface'), UI: this.state.UIAlert},
|
||||
{target: 'INFO', label: i18n.__('About')},
|
||||
{target: 'CROWDFUNDING', label: i18n.__('Crowdfunding')},
|
||||
{target: 'BLOG', label: i18n.__('Blog'), Blog: this.state.BlogAlert},
|
||||
{target: 'SNIPPET', label: i18n.__('Snippets')}
|
||||
{ target: 'STORAGES', label: i18n.__('Storage') },
|
||||
{
|
||||
target: 'HOTKEY',
|
||||
label: i18n.__('Hotkeys'),
|
||||
Hotkey: this.state.HotkeyAlert
|
||||
},
|
||||
{ target: 'UI', label: i18n.__('Interface'), UI: this.state.UIAlert },
|
||||
{ target: 'INFO', label: i18n.__('About') },
|
||||
{ target: 'CROWDFUNDING', label: i18n.__('Crowdfunding') },
|
||||
{ target: 'BLOG', label: i18n.__('Blog'), Blog: this.state.BlogAlert },
|
||||
{ target: 'SNIPPET', label: i18n.__('Snippets') }
|
||||
]
|
||||
|
||||
const navButtons = tabs.map((tab) => {
|
||||
const navButtons = tabs.map(tab => {
|
||||
const isActive = this.state.currentTab === tab.target
|
||||
const isUiHotkeyTab = _.isObject(tab[tab.label]) && tab.label === tab[tab.label].tab
|
||||
const isUiHotkeyTab =
|
||||
_.isObject(tab[tab.label]) && tab.label === tab[tab.label].tab
|
||||
return (
|
||||
<button styleName={isActive
|
||||
? 'nav-button--active'
|
||||
: 'nav-button'
|
||||
}
|
||||
<button
|
||||
styleName={isActive ? 'nav-button--active' : 'nav-button'}
|
||||
key={tab.target}
|
||||
onClick={(e) => this.handleNavButtonClick(tab.target)(e)}
|
||||
onClick={e => this.handleNavButtonClick(tab.target)(e)}
|
||||
>
|
||||
<span>
|
||||
{tab.label}
|
||||
</span>
|
||||
{isUiHotkeyTab ? this.haveToSaveNotif(tab[tab.label].type, tab[tab.label].message) : null}
|
||||
<span>{tab.label}</span>
|
||||
{isUiHotkeyTab
|
||||
? this.haveToSaveNotif(tab[tab.label].type, tab[tab.label].message)
|
||||
: null}
|
||||
</button>
|
||||
)
|
||||
})
|
||||
|
||||
return (
|
||||
<div styleName='root'
|
||||
<div
|
||||
styleName='root'
|
||||
ref='root'
|
||||
tabIndex='-1'
|
||||
onKeyDown={(e) => this.handleKeyDown(e)}
|
||||
onKeyDown={e => this.handleKeyDown(e)}
|
||||
>
|
||||
<div styleName='top-bar'>
|
||||
<p>{i18n.__('Your preferences for Boostnote')}</p>
|
||||
</div>
|
||||
<ModalEscButton handleEscButtonClick={(e) => this.handleEscButtonClick(e)} />
|
||||
<div styleName='nav'>
|
||||
{navButtons}
|
||||
</div>
|
||||
<ModalEscButton
|
||||
handleEscButtonClick={e => this.handleEscButtonClick(e)}
|
||||
/>
|
||||
<div styleName='nav'>{navButtons}</div>
|
||||
<div ref='content' styleName='content'>
|
||||
{content}
|
||||
</div>
|
||||
@@ -181,4 +170,4 @@ Preferences.propTypes = {
|
||||
dispatch: PropTypes.func
|
||||
}
|
||||
|
||||
export default connect((x) => x)(CSSModules(Preferences, styles))
|
||||
export default connect(x => x)(CSSModules(Preferences, styles))
|
||||
|
||||
@@ -8,7 +8,7 @@ import ModalEscButton from 'browser/components/ModalEscButton'
|
||||
import i18n from 'browser/lib/i18n'
|
||||
|
||||
class RenameFolderModal extends React.Component {
|
||||
constructor (props) {
|
||||
constructor(props) {
|
||||
super(props)
|
||||
|
||||
this.state = {
|
||||
@@ -16,39 +16,39 @@ class RenameFolderModal extends React.Component {
|
||||
}
|
||||
}
|
||||
|
||||
componentDidMount () {
|
||||
componentDidMount() {
|
||||
this.refs.name.focus()
|
||||
this.refs.name.select()
|
||||
}
|
||||
|
||||
handleCloseButtonClick (e) {
|
||||
handleCloseButtonClick(e) {
|
||||
this.props.close()
|
||||
}
|
||||
|
||||
handleChange (e) {
|
||||
handleChange(e) {
|
||||
this.setState({
|
||||
name: this.refs.name.value
|
||||
})
|
||||
}
|
||||
|
||||
handleKeyDown (e) {
|
||||
handleKeyDown(e) {
|
||||
if (e.keyCode === 27) {
|
||||
this.props.close()
|
||||
}
|
||||
}
|
||||
|
||||
handleInputKeyDown (e) {
|
||||
handleInputKeyDown(e) {
|
||||
switch (e.keyCode) {
|
||||
case 13:
|
||||
this.confirm()
|
||||
}
|
||||
}
|
||||
|
||||
handleConfirmButtonClick (e) {
|
||||
handleConfirmButtonClick(e) {
|
||||
this.confirm()
|
||||
}
|
||||
|
||||
confirm () {
|
||||
confirm() {
|
||||
if (this.state.name.trim().length > 0) {
|
||||
const { storage, folder } = this.props
|
||||
dataApi
|
||||
@@ -56,7 +56,7 @@ class RenameFolderModal extends React.Component {
|
||||
name: this.state.name,
|
||||
color: folder.color
|
||||
})
|
||||
.then((data) => {
|
||||
.then(data => {
|
||||
store.dispatch({
|
||||
type: 'UPDATE_FOLDER',
|
||||
storage: data.storage
|
||||
@@ -66,27 +66,32 @@ class RenameFolderModal extends React.Component {
|
||||
}
|
||||
}
|
||||
|
||||
render () {
|
||||
render() {
|
||||
return (
|
||||
<div styleName='root'
|
||||
<div
|
||||
styleName='root'
|
||||
tabIndex='-1'
|
||||
onKeyDown={(e) => this.handleKeyDown(e)}
|
||||
onKeyDown={e => this.handleKeyDown(e)}
|
||||
>
|
||||
<div styleName='header'>
|
||||
<div styleName='title'>{i18n.__('Rename Folder')}</div>
|
||||
</div>
|
||||
<ModalEscButton handleEscButtonClick={(e) => this.handleCloseButtonClick(e)} />
|
||||
<ModalEscButton
|
||||
handleEscButtonClick={e => this.handleCloseButtonClick(e)}
|
||||
/>
|
||||
|
||||
<div styleName='control'>
|
||||
<input styleName='control-input'
|
||||
<input
|
||||
styleName='control-input'
|
||||
placeholder={i18n.__('Folder Name')}
|
||||
ref='name'
|
||||
value={this.state.name}
|
||||
onChange={(e) => this.handleChange(e)}
|
||||
onKeyDown={(e) => this.handleInputKeyDown(e)}
|
||||
onChange={e => this.handleChange(e)}
|
||||
onKeyDown={e => this.handleInputKeyDown(e)}
|
||||
/>
|
||||
<button styleName='control-confirmButton'
|
||||
onClick={(e) => this.handleConfirmButtonClick(e)}
|
||||
<button
|
||||
styleName='control-confirmButton'
|
||||
onClick={e => this.handleConfirmButtonClick(e)}
|
||||
>
|
||||
{i18n.__('Confirm')}
|
||||
</button>
|
||||
|
||||
Reference in New Issue
Block a user