From 086f9e112316252a3dfe26395ca1f521f01dc935 Mon Sep 17 00:00:00 2001 From: Laurent Cozic Date: Mon, 29 Jul 2019 14:13:23 +0200 Subject: [PATCH] Started applying config to Electron app --- .../app/gui/ClipperConfigScreen.jsx | 74 +- ElectronClient/app/gui/ConfigScreen.jsx | 243 ++++--- ElectronClient/app/gui/DropboxLoginScreen.jsx | 24 +- .../app/gui/EncryptionConfigScreen.jsx | 66 +- ElectronClient/app/gui/Header.jsx | 106 ++- ElectronClient/app/gui/HelpButton.jsx | 17 +- ElectronClient/app/gui/IconButton.jsx | 43 +- ElectronClient/app/gui/ImportScreen.jsx | 38 +- ElectronClient/app/gui/ItemList.jsx | 11 +- ElectronClient/app/gui/MainScreen.jsx | 160 +++-- ElectronClient/app/gui/Navigator.jsx | 27 +- ElectronClient/app/gui/NoteList.jsx | 139 ++-- .../app/gui/NotePropertiesDialog.jsx | 141 ++-- ElectronClient/app/gui/NoteRevisionViewer.jsx | 70 +- ElectronClient/app/gui/NoteSearchBar.jsx | 41 +- ElectronClient/app/gui/NoteStatusBar.jsx | 16 +- ElectronClient/app/gui/NoteText.jsx | 649 ++++++++++-------- ElectronClient/app/gui/NoteTextViewer.jsx | 29 +- .../app/gui/OneDriveLoginScreen.jsx | 27 +- ElectronClient/app/gui/PromptDialog.jsx | 187 +++-- ElectronClient/app/gui/Root.jsx | 37 +- ElectronClient/app/gui/SideBar.jsx | 315 +++++---- ElectronClient/app/gui/StatusScreen.jsx | 61 +- ElectronClient/app/gui/TagItem.jsx | 2 +- ElectronClient/app/gui/TagList.jsx | 14 +- ElectronClient/app/gui/Toolbar.jsx | 23 +- ElectronClient/app/gui/ToolbarButton.jsx | 20 +- ElectronClient/app/gui/ToolbarSpace.jsx | 12 +- ElectronClient/app/gui/VerticalResizer.jsx | 62 +- ElectronClient/app/gui/dialogs.js | 2 - ElectronClient/app/gui/note-viewer/preload.js | 2 +- ElectronClient/app/gui/utils/NoteListUtils.js | 164 +++-- 32 files changed, 1560 insertions(+), 1262 deletions(-) diff --git a/ElectronClient/app/gui/ClipperConfigScreen.jsx b/ElectronClient/app/gui/ClipperConfigScreen.jsx index 2da088c6d..e845d117f 100644 --- a/ElectronClient/app/gui/ClipperConfigScreen.jsx +++ b/ElectronClient/app/gui/ClipperConfigScreen.jsx @@ -1,6 +1,5 @@ const React = require('react'); const { connect } = require('react-redux'); -const { reg } = require('lib/registry.js'); const { bridge } = require('electron').remote.require('./bridge'); const { Header } = require('./Header.min.js'); const { themeStyle } = require('../theme.js'); @@ -10,7 +9,6 @@ const Setting = require('lib/models/Setting'); const { clipboard } = require('electron'); class ClipperConfigScreenComponent extends React.Component { - constructor() { super(); @@ -28,11 +26,11 @@ class ClipperConfigScreenComponent extends React.Component { } chromeButton_click() { - bridge().openExternal("https://chrome.google.com/webstore/detail/joplin-web-clipper/alofnhikmmkdbbbgpnglcpdollgjjfek") + bridge().openExternal('https://chrome.google.com/webstore/detail/joplin-web-clipper/alofnhikmmkdbbbgpnglcpdollgjjfek'); } firefoxButton_click() { - bridge().openExternal("https://addons.mozilla.org/en-US/firefox/addon/joplin-web-clipper/"); + bridge().openExternal('https://addons.mozilla.org/en-US/firefox/addon/joplin-web-clipper/'); } copyToken_click() { @@ -49,13 +47,13 @@ class ClipperConfigScreenComponent extends React.Component { const containerStyle = Object.assign({}, theme.containerStyle, { overflowY: 'scroll', - height:style.height, + height: style.height, }); const buttonStyle = Object.assign({}, theme.buttonStyle, { marginRight: 10 }); const stepBoxStyle = { - border: "1px solid #ccc", + border: '1px solid #ccc', padding: 15, paddingTop: 0, marginBottom: 15, @@ -65,16 +63,40 @@ class ClipperConfigScreenComponent extends React.Component { let webClipperStatusComps = []; if (this.props.clipperServerAutoStart) { - webClipperStatusComps.push(

{_('The web clipper service is enabled and set to auto-start.')}

) + webClipperStatusComps.push( +

+ {_('The web clipper service is enabled and set to auto-start.')} +

+ ); if (this.props.clipperServer.startState === 'started') { - webClipperStatusComps.push(

{_('Status: Started on port %d', this.props.clipperServer.port)}

) + webClipperStatusComps.push( +

+ {_('Status: Started on port %d', this.props.clipperServer.port)} +

+ ); } else { - webClipperStatusComps.push(

{_('Status: %s', this.props.clipperServer.startState)}

) + webClipperStatusComps.push( +

+ {_('Status: %s', this.props.clipperServer.startState)} +

+ ); } - webClipperStatusComps.push() + webClipperStatusComps.push( + + ); } else { - webClipperStatusComps.push(

{_('The web clipper service is not enabled.')}

) - webClipperStatusComps.push() + webClipperStatusComps.push( +

+ {_('The web clipper service is not enabled.')} +

+ ); + webClipperStatusComps.push( + + ); } const apiTokenStyle = Object.assign({}, theme.textStyle, { @@ -88,31 +110,42 @@ class ClipperConfigScreenComponent extends React.Component {
-
+

{_('Joplin Web Clipper allows saving web pages and screenshots from your browser to Joplin.')}

{_('In order to use the web clipper, you need to do the following:')}

{_('Step 1: Enable the clipper service')}

{_('This service allows the browser extension to communicate with Joplin. When enabling it your firewall may ask you to give permission to Joplin to listen to a particular port.')}

-
- {webClipperStatusComps} -
+
{webClipperStatusComps}

{_('Step 2: Install the extension')}

{_('Download and install the relevant extension for your browser:')}

-

-

+

+ + + +

+

+ + + +

{_('Advanced options')}

{_('Authorisation token:')}

-

{this.props.apiToken} {_('Copy token')}

+

+ {this.props.apiToken}{' '} + + {_('Copy token')} + +

{_('This authorisation token is only needed to allow third-party applications to access Joplin.')}

@@ -120,10 +153,9 @@ class ClipperConfigScreenComponent extends React.Component {
); } - } -const mapStateToProps = (state) => { +const mapStateToProps = state => { return { theme: state.settings.theme, clipperServer: state.clipperServer, diff --git a/ElectronClient/app/gui/ConfigScreen.jsx b/ElectronClient/app/gui/ConfigScreen.jsx index dd818bab1..4496905d1 100644 --- a/ElectronClient/app/gui/ConfigScreen.jsx +++ b/ElectronClient/app/gui/ConfigScreen.jsx @@ -1,18 +1,14 @@ const React = require('react'); const { connect } = require('react-redux'); -const { reg } = require('lib/registry.js'); const Setting = require('lib/models/Setting.js'); const { bridge } = require('electron').remote.require('./bridge'); -const { Header } = require('./Header.min.js'); const { themeStyle } = require('../theme.js'); const pathUtils = require('lib/path-utils.js'); const { _ } = require('lib/locale.js'); -const { commandArgumentsToString } = require('lib/string-utils'); const SyncTargetRegistry = require('lib/SyncTargetRegistry'); const shared = require('lib/components/shared/config-shared.js'); class ConfigScreenComponent extends React.Component { - constructor() { super(); @@ -20,7 +16,7 @@ class ConfigScreenComponent extends React.Component { this.checkSyncConfig_ = async () => { await shared.checkSyncConfig(this, this.state.settings); - } + }; this.rowStyle_ = { marginBottom: 10, @@ -70,11 +66,7 @@ class ConfigScreenComponent extends React.Component { sectionStyle.borderTopWidth = 0; } - const noteComp = section.name !== 'general' ? null : ( -
- {_('Notes and settings are stored in: %s', pathUtils.toSystemSlashes(Setting.value('profileDir'), process.platform))} -
- ); + const noteComp = section.name !== 'general' ? null :
{_('Notes and settings are stored in: %s', pathUtils.toSystemSlashes(Setting.value('profileDir'), process.platform))}
; if (section.name === 'sync') { const syncTargetMd = SyncTargetRegistry.idToMetadata(settings['sync.target']); @@ -85,14 +77,18 @@ class ConfigScreenComponent extends React.Component { const statusComp = !messages.length ? null : (
{messages[0]} - {messages.length >= 1 ? (

{messages[1]}

) : null} -
); + {messages.length >= 1 ?

{messages[1]}

: null} +
+ ); settingComps.push(
- - { statusComp } -
); + + {statusComp} +
+ ); } } @@ -100,9 +96,7 @@ class ConfigScreenComponent extends React.Component {

{Setting.sectionNameToLabel(section.name)}

{noteComp} -
- {settingComps} -
+
{settingComps}
); } @@ -145,18 +139,14 @@ class ConfigScreenComponent extends React.Component { const updateSettingValue = (key, value) => { // console.info(key + ' = ' + value); return shared.updateSettingValue(this, key, value); - } + }; // Component key needs to be key+value otherwise it doesn't update when the settings change. const md = Setting.settingMetadata(key); const descriptionText = Setting.keyDescription(key, 'desktop'); - const descriptionComp = descriptionText ? ( -
- {descriptionText} -
- ) : null; + const descriptionComp = descriptionText ?
{descriptionText}
: null; if (md.isEnum) { let items = []; @@ -164,31 +154,59 @@ class ConfigScreenComponent extends React.Component { let array = this.keyValueToArray(settingOptions); for (let i = 0; i < array.length; i++) { const e = array[i]; - items.push(); + items.push( + + ); } return (
-
- { + updateSettingValue(key, event.target.value); + }} + > {items} - { descriptionComp } + {descriptionComp}
); } else if (md.type === Setting.TYPE_BOOL) { - const onCheckboxClick = (event) => { - updateSettingValue(key, !value) - } + const onCheckboxClick = event => { + updateSettingValue(key, !value); + }; // Hack: The {key+value.toString()} is needed as otherwise the checkbox doesn't update when the state changes. // There's probably a better way to do this but can't figure it out. return ( -
+
- { onCheckboxClick(event) }}/> - { descriptionComp } + { + onCheckboxClick(event); + }} + /> + + {descriptionComp}
); @@ -196,7 +214,8 @@ class ConfigScreenComponent extends React.Component { const inputStyle = Object.assign({}, controlStyle, { width: '50%', minWidth: '20em', - border: '1px solid' }); + border: '1px solid', + }); const inputType = md.secure === true ? 'password' : 'text'; if (md.subType === 'file_path_and_args') { @@ -206,7 +225,7 @@ class ConfigScreenComponent extends React.Component { const path = pathUtils.extractExecutablePath(cmdString); const args = cmdString.substr(path.length + 1); return [pathUtils.unquotePath(path), args]; - } + }; const joinCmd = cmdArray => { if (!cmdArray[0] && !cmdArray[1]) return ''; @@ -214,74 +233,101 @@ class ConfigScreenComponent extends React.Component { if (!cmdString) cmdString = '""'; if (cmdArray[1]) cmdString += ' ' + cmdArray[1]; return cmdString; - } + }; const onPathChange = event => { const cmd = splitCmd(this.state.settings[key]); cmd[0] = event.target.value; updateSettingValue(key, joinCmd(cmd)); - } + }; const onArgsChange = event => { const cmd = splitCmd(this.state.settings[key]); cmd[1] = event.target.value; updateSettingValue(key, joinCmd(cmd)); - } + }; const browseButtonClick = () => { const paths = bridge().showOpenDialog(); if (!paths || !paths.length) return; const cmd = splitCmd(this.state.settings[key]); - cmd[0] = paths[0] + cmd[0] = paths[0]; updateSettingValue(key, joinCmd(cmd)); - } + }; const cmd = splitCmd(this.state.settings[key]); return (
-
-
-
+
+
+
+ +
-
+
Path:
Arguments:
-
-
- {onPathChange(event)}} value={cmd[0]} /> - +
+
+ { + onPathChange(event); + }} + value={cmd[0]} + /> +
- {onArgsChange(event)}} value={cmd[1]}/> + { + onArgsChange(event); + }} + value={cmd[1]} + />
-
-
-
-
-
- { descriptionComp } +
+
+
+ +
+
{descriptionComp}
); } else { - const onTextChange = (event) => { + const onTextChange = event => { updateSettingValue(key, event.target.value); - } + }; return (
-
- {onTextChange(event)}} /> - { descriptionComp } +
+ +
+ { + onTextChange(event); + }} + /> + {descriptionComp}
); } } else if (md.type === Setting.TYPE_INT) { - const onNumChange = (event) => { + const onNumChange = event => { updateSettingValue(key, event.target.value); }; @@ -290,9 +336,21 @@ class ConfigScreenComponent extends React.Component { return (
-
- {onNumChange(event)}} min={md.minimum} max={md.maximum} step={md.step}/> - { descriptionComp } +
+ +
+ { + onNumChange(event); + }} + min={md.minimum} + max={md.maximum} + step={md.step} + /> + {descriptionComp}
); } else { @@ -318,13 +376,17 @@ class ConfigScreenComponent extends React.Component { render() { const theme = themeStyle(this.props.theme); - const style = Object.assign({ - backgroundColor: theme.backgroundColor - }, this.props.style, { - overflow: 'hidden', - display: 'flex', - flexDirection: 'column', - }); + const style = Object.assign( + { + backgroundColor: theme.backgroundColor, + }, + this.props.style, + { + overflow: 'hidden', + display: 'flex', + flexDirection: 'column', + } + ); let settings = this.state.settings; @@ -355,20 +417,41 @@ class ConfigScreenComponent extends React.Component { return (
- - - -
-
- { settingComps } + + +
+
{settingComps}
); } - } -const mapStateToProps = (state) => { +const mapStateToProps = state => { return { theme: state.settings.theme, settings: state.settings, diff --git a/ElectronClient/app/gui/DropboxLoginScreen.jsx b/ElectronClient/app/gui/DropboxLoginScreen.jsx index ffad734b3..18b8cf761 100644 --- a/ElectronClient/app/gui/DropboxLoginScreen.jsx +++ b/ElectronClient/app/gui/DropboxLoginScreen.jsx @@ -1,23 +1,16 @@ const React = require('react'); const { connect } = require('react-redux'); -const { reg } = require('lib/registry.js'); const { bridge } = require('electron').remote.require('./bridge'); const { Header } = require('./Header.min.js'); const { themeStyle } = require('../theme.js'); -const SyncTargetRegistry = require('lib/SyncTargetRegistry'); const { _ } = require('lib/locale.js'); const Shared = require('lib/components/shared/dropbox-login-shared'); class DropboxLoginScreenComponent extends React.Component { - constructor() { super(); - this.shared_ = new Shared( - this, - (msg) => bridge().showInfoMessageBox(msg), - (msg) => bridge().showErrorMessageBox(msg) - ); + this.shared_ = new Shared(this, msg => bridge().showInfoMessageBox(msg), msg => bridge().showErrorMessageBox(msg)); } componentWillMount() { @@ -42,18 +35,23 @@ class DropboxLoginScreenComponent extends React.Component {

{_('To allow Joplin to synchronise with Dropbox, please follow the steps below:')}

{_('Step 1: Open this URL in your browser to authorise the application:')}

- {this.state.loginUrl} + + {this.state.loginUrl} +

{_('Step 2: Enter the code provided by Dropbox:')}

-

- +

+ +

+
); } - } -const mapStateToProps = (state) => { +const mapStateToProps = state => { return { theme: state.settings.theme, }; diff --git a/ElectronClient/app/gui/EncryptionConfigScreen.jsx b/ElectronClient/app/gui/EncryptionConfigScreen.jsx index e4dd2dd35..c6971d77d 100644 --- a/ElectronClient/app/gui/EncryptionConfigScreen.jsx +++ b/ElectronClient/app/gui/EncryptionConfigScreen.jsx @@ -1,7 +1,6 @@ const React = require('react'); const { connect } = require('react-redux'); const Setting = require('lib/models/Setting'); -const BaseItem = require('lib/models/BaseItem'); const EncryptionService = require('lib/services/EncryptionService'); const { Header } = require('./Header.min.js'); const { themeStyle } = require('../theme.js'); @@ -9,11 +8,9 @@ const { _ } = require('lib/locale.js'); const { time } = require('lib/time-utils.js'); const dialogs = require('./dialogs'); const shared = require('lib/components/shared/encryption-config-shared.js'); -const pathUtils = require('lib/path-utils.js'); const { bridge } = require('electron').remote.require('./bridge'); class EncryptionConfigScreenComponent extends React.Component { - constructor() { super(); shared.constructor(this); @@ -55,15 +52,15 @@ class EncryptionConfigScreenComponent extends React.Component { backgroundColor: theme.backgroundColor, border: '1px solid', borderColor: theme.dividerColor, - } + }; const onSaveClick = () => { return shared.onSavePasswordClick(this, mk); - } + }; - const onPasswordChange = (event) => { + const onPasswordChange = event => { return shared.onPasswordChange(this, mk, event.target.value); - } + }; const password = this.state.passwords[mk.id] ? this.state.passwords[mk.id] : ''; const active = this.props.activeMasterKeyId === mk.id ? '✔' : ''; @@ -76,7 +73,12 @@ class EncryptionConfigScreenComponent extends React.Component { {mk.source_application} {time.formatMsToLocal(mk.created_time)} {time.formatMsToLocal(mk.updated_time)} - onPasswordChange(event)}/> + + onPasswordChange(event)} />{' '} + + {passwordOk} ); @@ -128,10 +130,19 @@ class EncryptionConfigScreenComponent extends React.Component { } catch (error) { await dialogs.alert(error.message); } - } + }; const decryptedItemsInfo =

{shared.decryptedStatText(this)}

; - const toggleButton = + const toggleButton = ( + + ); let masterKeySection = null; @@ -164,7 +175,11 @@ class EncryptionConfigScreenComponent extends React.Component { const rows = []; for (let i = 0; i < nonExistingMasterKeyIds.length; i++) { const id = nonExistingMasterKeyIds[i]; - rows.push({id}); + rows.push( + + {id} + + ); } nonExistingMasterKeySection = ( @@ -176,7 +191,7 @@ class EncryptionConfigScreenComponent extends React.Component { {_('ID')} - { rows } + {rows}
@@ -187,13 +202,25 @@ class EncryptionConfigScreenComponent extends React.Component {
- {
-

- {_('For more information about End-To-End Encryption (E2EE) and advices on how to enable it please check the documentation:')} {bridge().openExternal('https://joplinapp.org/e2ee/')}} href="#">https://joplinapp.org/e2ee/ -

-
} + { +
+

+ {_('For more information about End-To-End Encryption (E2EE) and advices on how to enable it please check the documentation:')}{' '} + { + bridge().openExternal('https://joplinapp.org/e2ee/'); + }} + href="#" + > + https://joplinapp.org/e2ee/ + +

+
+ }

{_('Status')}

-

{_('Encryption is:')} {this.props.encryptionEnabled ? _('Enabled') : _('Disabled')}

+

+ {_('Encryption is:')} {this.props.encryptionEnabled ? _('Enabled') : _('Disabled')} +

{decryptedItemsInfo} {toggleButton} {masterKeySection} @@ -202,10 +229,9 @@ class EncryptionConfigScreenComponent extends React.Component {
); } - } -const mapStateToProps = (state) => { +const mapStateToProps = state => { return { theme: state.settings.theme, masterKeys: state.masterKeys, diff --git a/ElectronClient/app/gui/Header.jsx b/ElectronClient/app/gui/Header.jsx index fc6003300..3ffbeb474 100644 --- a/ElectronClient/app/gui/Header.jsx +++ b/ElectronClient/app/gui/Header.jsx @@ -1,12 +1,10 @@ const React = require('react'); const { connect } = require('react-redux'); -const { reg } = require('lib/registry.js'); const { themeStyle } = require('../theme.js'); const { _ } = require('lib/locale.js'); const { bridge } = require('electron').remote.require('./bridge'); class HeaderComponent extends React.Component { - constructor() { super(); this.state = { @@ -18,13 +16,13 @@ class HeaderComponent extends React.Component { this.searchOnQuery_ = null; this.searchElement_ = null; - const triggerOnQuery = (query) => { + const triggerOnQuery = query => { clearTimeout(this.scheduleSearchChangeEventIid_); if (this.searchOnQuery_) this.searchOnQuery_(query); this.scheduleSearchChangeEventIid_ = null; - } + }; - this.search_onChange = (event) => { + this.search_onChange = event => { this.setState({ searchQuery: event.target.value }); if (this.scheduleSearchChangeEventIid_) clearTimeout(this.scheduleSearchChangeEventIid_); @@ -34,10 +32,10 @@ class HeaderComponent extends React.Component { }, 500); }; - this.search_onClear = (event) => { + this.search_onClear = event => { this.resetSearch(); if (this.searchElement_) this.searchElement_.focus(); - } + }; this.search_onFocus = event => { if (this.hideSearchUsageLinkIID_) { @@ -46,7 +44,7 @@ class HeaderComponent extends React.Component { } this.setState({ showSearchUsageLink: true }); - } + }; this.search_onBlur = event => { if (this.hideSearchUsageLinkIID_) return; @@ -54,22 +52,23 @@ class HeaderComponent extends React.Component { this.hideSearchUsageLinkIID_ = setTimeout(() => { this.setState({ showSearchUsageLink: false }); }, 5000); - } - + }; + this.search_keyDown = event => { - if (event.keyCode === 27) { // ESCAPE + if (event.keyCode === 27) { + // ESCAPE this.resetSearch(); } - } - + }; + this.resetSearch = () => { this.setState({ searchQuery: '' }); triggerOnQuery(''); - } + }; this.searchUsageLink_click = event => { bridge().openExternal('https://joplinapp.org/#searching'); - } + }; } async componentWillReceiveProps(nextProps) { @@ -79,11 +78,11 @@ class HeaderComponent extends React.Component { } componentDidUpdate(prevProps) { - if(prevProps.notesParentType !== this.props.notesParentType && this.props.notesParentType !== 'Search' && this.state.searchQuery) { + if (prevProps.notesParentType !== this.props.notesParentType && this.props.notesParentType !== 'Search' && this.state.searchQuery) { this.resetSearch(); } } - + componentWillUnmount() { if (this.hideSearchUsageLinkIID_) { clearTimeout(this.hideSearchUsageLinkIID_); @@ -122,14 +121,14 @@ class HeaderComponent extends React.Component { color: style.color, }; if (options.title) iconStyle.marginRight = 5; - if("undefined" != typeof(options.iconRotation)) { - iconStyle.transition = "transform 0.15s ease-in-out"; + if ('undefined' != typeof options.iconRotation) { + iconStyle.transition = 'transform 0.15s ease-in-out'; iconStyle.transform = 'rotate(' + options.iconRotation + 'deg)'; } - icon = + icon = ; } - const isEnabled = (!('enabled' in options) || options.enabled); + const isEnabled = !('enabled' in options) || options.enabled; let classes = ['button']; if (!isEnabled) classes.push('disabled'); @@ -139,16 +138,21 @@ class HeaderComponent extends React.Component { const title = options.title ? options.title : ''; - return { if (isEnabled) options.onClick() }} - > - {icon}{title} - + return ( + { + if (isEnabled) options.onClick(); + }} + > + {icon} + {title} + + ); } makeSearch(key, style, options, state) { @@ -159,8 +163,8 @@ class HeaderComponent extends React.Component { flex: 1, paddingLeft: 6, paddingRight: 6, - paddingTop: 1, // vertical alignment with buttons - paddingBottom: 0, // vertical alignment with buttons + paddingTop: 1, // vertical alignment with buttons + paddingBottom: 0, // vertical alignment with buttons height: style.fontSize * 2, color: style.color, fontSize: style.fontSize, @@ -191,33 +195,24 @@ class HeaderComponent extends React.Component { }; const iconName = state.searchQuery ? 'fa-times' : 'fa-search'; - const icon = + const icon = ; if (options.onQuery) this.searchOnQuery_ = options.onQuery; const usageLink = !this.state.showSearchUsageLink ? null : ( - {_('Usage')} + + {_('Usage')} + ); return (
- this.searchElement_ = elem} - onFocus={this.search_onFocus} - onBlur={this.search_onBlur} - onKeyDown={this.search_keyDown} - /> - {icon} + (this.searchElement_ = elem)} onFocus={this.search_onFocus} onBlur={this.search_onBlur} onKeyDown={this.search_keyDown} /> + + {icon} + {usageLink} -
); +
+ ); } render() { @@ -226,7 +221,7 @@ class HeaderComponent extends React.Component { const showBackButton = this.props.showBackButton === undefined || this.props.showBackButton === true; style.height = theme.headerHeight; style.display = 'flex'; - style.flexDirection = 'row'; + style.flexDirection = 'row'; style.borderBottom = '1px solid ' + theme.dividerColor; style.boxSizing = 'border-box'; @@ -266,14 +261,13 @@ class HeaderComponent extends React.Component { return (
- { items } + {items}
); } - } -const mapStateToProps = (state) => { +const mapStateToProps = state => { return { theme: state.settings.theme, windowCommand: state.windowCommand, diff --git a/ElectronClient/app/gui/HelpButton.jsx b/ElectronClient/app/gui/HelpButton.jsx index 7389c8884..923ff84a4 100644 --- a/ElectronClient/app/gui/HelpButton.jsx +++ b/ElectronClient/app/gui/HelpButton.jsx @@ -1,12 +1,8 @@ const React = require('react'); const { connect } = require('react-redux'); -const { reg } = require('lib/registry.js'); const { themeStyle } = require('../theme.js'); -const { _ } = require('lib/locale.js'); -const { bridge } = require('electron').remote.require('./bridge'); class HelpButtonComponent extends React.Component { - constructor() { super(); @@ -19,16 +15,19 @@ class HelpButtonComponent extends React.Component { render() { const theme = themeStyle(this.props.theme); - let style = Object.assign({}, this.props.style, {color: theme.color, textDecoration: 'none'}); - const helpIconStyle = {flex:0, width: 16, height: 16, marginLeft: 10}; + let style = Object.assign({}, this.props.style, { color: theme.color, textDecoration: 'none' }); + const helpIconStyle = { flex: 0, width: 16, height: 16, marginLeft: 10 }; const extraProps = {}; if (this.props.tip) extraProps['data-tip'] = this.props.tip; - return + return ( + + + + ); } - } -const mapStateToProps = (state) => { +const mapStateToProps = state => { return { theme: state.settings.theme, }; diff --git a/ElectronClient/app/gui/IconButton.jsx b/ElectronClient/app/gui/IconButton.jsx index f1f1244f5..b39461558 100644 --- a/ElectronClient/app/gui/IconButton.jsx +++ b/ElectronClient/app/gui/IconButton.jsx @@ -1,9 +1,7 @@ const React = require('react'); -const { connect } = require('react-redux'); const { themeStyle } = require('../theme.js'); class IconButton extends React.Component { - render() { const style = this.props.style; const theme = themeStyle(this.props.theme); @@ -11,28 +9,37 @@ class IconButton extends React.Component { color: theme.color, fontSize: theme.fontSize * 1.4, }; - const icon = + const icon = ; - const rootStyle = Object.assign({ - display: 'flex', - textDecoration: 'none', - padding: 10, - width: theme.buttonMinHeight, - height: theme.buttonMinHeight, - boxSizing: 'border-box', - alignItems: 'center', - justifyContent: 'center', - backgroundColor: theme.backgroundColor, - cursor: 'default', - }, style); + const rootStyle = Object.assign( + { + display: 'flex', + textDecoration: 'none', + padding: 10, + width: theme.buttonMinHeight, + height: theme.buttonMinHeight, + boxSizing: 'border-box', + alignItems: 'center', + justifyContent: 'center', + backgroundColor: theme.backgroundColor, + cursor: 'default', + }, + style + ); return ( - { if (this.props.onClick) this.props.onClick() }}> - { icon } + { + if (this.props.onClick) this.props.onClick(); + }} + > + {icon} ); } - } module.exports = { IconButton }; diff --git a/ElectronClient/app/gui/ImportScreen.jsx b/ElectronClient/app/gui/ImportScreen.jsx index 9fe902e0a..6bd2a8a4c 100644 --- a/ElectronClient/app/gui/ImportScreen.jsx +++ b/ElectronClient/app/gui/ImportScreen.jsx @@ -1,8 +1,6 @@ const React = require('react'); const { connect } = require('react-redux'); -const { reg } = require('lib/registry.js'); const Folder = require('lib/models/Folder.js'); -const { bridge } = require('electron').remote.require('./bridge'); const { Header } = require('./Header.min.js'); const { themeStyle } = require('../theme.js'); const { _ } = require('lib/locale.js'); @@ -10,7 +8,6 @@ const { filename, basename } = require('lib/path-utils.js'); const { importEnex } = require('lib/import-enex'); class ImportScreenComponent extends React.Component { - componentWillMount() { this.setState({ doImport: true, @@ -21,11 +18,16 @@ class ImportScreenComponent extends React.Component { componentWillReceiveProps(newProps) { if (newProps.filePath) { - this.setState({ - doImport: true, - filePath: newProps.filePath, - messages: [], - }, () => { this.doImport() }); + this.setState( + { + doImport: true, + filePath: newProps.filePath, + messages: [], + }, + () => { + this.doImport(); + } + ); } } @@ -37,7 +39,6 @@ class ImportScreenComponent extends React.Component { addMessage(key, text) { const messages = this.state.messages.slice(); - let found = false; messages.push({ key: key, text: text }); @@ -60,15 +61,13 @@ class ImportScreenComponent extends React.Component { async doImport() { const filePath = this.props.filePath; const folderTitle = await Folder.findUniqueItemTitle(filename(filePath)); - const messages = this.state.messages.slice(); this.addMessage('start', _('New notebook "%s" will be created and file "%s" will be imported into it', folderTitle, basename(filePath))); let lastProgress = ''; - let progressCount = 0; const options = { - onProgress: (progressState) => { + onProgress: progressState => { let line = []; line.push(_('Found: %d.', progressState.loaded)); line.push(_('Created: %d.', progressState.created)); @@ -79,15 +78,15 @@ class ImportScreenComponent extends React.Component { lastProgress = line.join(' '); this.addMessage('progress', lastProgress); }, - onError: (error) => { + onError: error => { // Don't display the error directly because most of the time it doesn't matter // (eg. for weird broken HTML, but the note is still imported) console.warn('When importing ENEX file', error); }, - } + }; const folder = await Folder.save({ title: folderTitle }); - + await importEnex(folder.id, filePath, options); this.addMessage('done', _('The notes have been imported: %s', lastProgress)); @@ -118,16 +117,13 @@ class ImportScreenComponent extends React.Component { return (
-
- {messageComps} -
+
{messageComps}
); } - } -const mapStateToProps = (state) => { +const mapStateToProps = state => { return { theme: state.settings.theme, }; @@ -135,4 +131,4 @@ const mapStateToProps = (state) => { const ImportScreen = connect(mapStateToProps)(ImportScreenComponent); -module.exports = { ImportScreen }; \ No newline at end of file +module.exports = { ImportScreen }; diff --git a/ElectronClient/app/gui/ItemList.jsx b/ElectronClient/app/gui/ItemList.jsx index 686d3760b..297ada294 100644 --- a/ElectronClient/app/gui/ItemList.jsx +++ b/ElectronClient/app/gui/ItemList.jsx @@ -1,7 +1,6 @@ const React = require('react'); class ItemList extends React.Component { - constructor() { super(); @@ -52,7 +51,7 @@ class ItemList extends React.Component { makeItemIndexVisible(itemIndex) { const top = Math.min(this.props.items.length - 1, this.state.topItemIndex + 1); - const bottom = Math.max(0, this.state.bottomItemIndex) + const bottom = Math.max(0, this.state.bottomItemIndex); if (itemIndex >= top && itemIndex <= bottom) return; @@ -81,8 +80,8 @@ class ItemList extends React.Component { if (!this.props.itemHeight) throw new Error('itemHeight is required'); const blankItem = function(key, height) { - return
- } + return
; + }; let itemComps = [blankItem('top', this.state.topItemIndex * this.props.itemHeight)]; @@ -98,10 +97,10 @@ class ItemList extends React.Component { return (
- { itemComps } + {itemComps}
); } } -module.exports = { ItemList }; \ No newline at end of file +module.exports = { ItemList }; diff --git a/ElectronClient/app/gui/MainScreen.jsx b/ElectronClient/app/gui/MainScreen.jsx index de3d055e8..df8a9b22c 100644 --- a/ElectronClient/app/gui/MainScreen.jsx +++ b/ElectronClient/app/gui/MainScreen.jsx @@ -20,7 +20,6 @@ const VerticalResizer = require('./VerticalResizer.min'); const PluginManager = require('lib/services/PluginManager'); class MainScreenComponent extends React.Component { - constructor() { super(); @@ -87,7 +86,7 @@ class MainScreenComponent extends React.Component { type: 'NOTE_SET_NEW_ONE', item: newNote, }); - } + }; let commandProcessed = true; @@ -107,7 +106,7 @@ class MainScreenComponent extends React.Component { this.setState({ promptOptions: { label: _('Notebook title:'), - onClose: async (answer) => { + onClose: async answer => { if (answer) { let folder = null; try { @@ -125,14 +124,22 @@ class MainScreenComponent extends React.Component { } this.setState({ promptOptions: null }); - } + }, }, }); } else if (command.name === 'setTags') { const tags = await Tag.tagsByNoteId(command.noteId); - const noteTags = tags.map((a) => { return {value: a.id, label: a.title } }).sort((a, b) => { return a.label.localeCompare(b.label); }); + const noteTags = tags + .map(a => { + return { value: a.id, label: a.title }; + }) + .sort((a, b) => { + return a.label.localeCompare(b.label); + }); const allTags = await Tag.allWithNotes(); - const tagSuggestions = allTags.map((a) => { return {value: a.id, label: a.title } }); + const tagSuggestions = allTags.map(a => { + return { value: a.id, label: a.title }; + }); this.setState({ promptOptions: { @@ -140,24 +147,26 @@ class MainScreenComponent extends React.Component { inputType: 'tags', value: noteTags, autocomplete: tagSuggestions, - onClose: async (answer) => { + onClose: async answer => { if (answer !== null) { - const tagTitles = answer.map((a) => { return a.label.trim() }); + const tagTitles = answer.map(a => { + return a.label.trim(); + }); await Tag.setNoteTagsByTitles(command.noteId, tagTitles); } this.setState({ promptOptions: null }); - } + }, }, }); } else if (command.name === 'renameFolder') { const folder = await Folder.load(command.id); - + if (folder) { this.setState({ promptOptions: { label: _('Rename notebook:'), value: folder.title, - onClose: async (answer) => { + onClose: async answer => { if (answer !== null) { try { folder.title = answer; @@ -167,7 +176,7 @@ class MainScreenComponent extends React.Component { } } this.setState({ promptOptions: null }); - } + }, }, }); } @@ -178,7 +187,7 @@ class MainScreenComponent extends React.Component { promptOptions: { label: _('Rename tag:'), value: tag.title, - onClose: async (answer) => { + onClose: async answer => { if (answer !== null) { try { tag.title = answer; @@ -187,13 +196,12 @@ class MainScreenComponent extends React.Component { bridge().showErrorMessageBox(error.message); } } - this.setState({promptOptions: null }); - } - } - }) + this.setState({ promptOptions: null }); + }, + }, + }); } } else if (command.name === 'search') { - if (!this.searchId_) this.searchId_ = uuid.create(); this.props.dispatch({ @@ -222,7 +230,6 @@ class MainScreenComponent extends React.Component { }); } } - } else if (command.name === 'commandNoteProperties') { this.setState({ notePropertiesDialogOptions: { @@ -273,7 +280,7 @@ class MainScreenComponent extends React.Component { } this.setState({ promptOptions: null }); - } + }, }, }); } else if (command.name === 'selectTemplate') { @@ -283,7 +290,7 @@ class MainScreenComponent extends React.Component { inputType: 'dropdown', value: this.props.templates[0], // Need to start with some value autocomplete: this.props.templates, - onClose: async (answer) => { + onClose: async answer => { if (answer) { if (command.noteType === 'note' || command.noteType === 'todo') { createNewNote(answer.value, command.noteType === 'todo'); @@ -297,7 +304,7 @@ class MainScreenComponent extends React.Component { } this.setState({ promptOptions: null }); - } + }, }, }); } else { @@ -313,7 +320,7 @@ class MainScreenComponent extends React.Component { } styles(themeId, width, height, messageBoxVisible, isSidebarVisible, sidebarWidth, noteListWidth) { - const styleKey = [themeId, width, height, messageBoxVisible, (+isSidebarVisible), sidebarWidth, noteListWidth].join('_'); + const styleKey = [themeId, width, height, messageBoxVisible, +isSidebarVisible, sidebarWidth, noteListWidth].join('_'); if (styleKey === this.styleKey_) return this.styles_; const theme = themeStyle(themeId); @@ -333,7 +340,7 @@ class MainScreenComponent extends React.Component { alignItems: 'center', paddingLeft: 10, backgroundColor: theme.warningBackgroundColor, - } + }; this.styles_.verticalResizer = { width: 5, @@ -390,10 +397,13 @@ class MainScreenComponent extends React.Component { render() { const theme = themeStyle(this.props.theme); - const style = Object.assign({ - color: theme.color, - backgroundColor: theme.backgroundColor, - }, this.props.style); + const style = Object.assign( + { + color: theme.color, + backgroundColor: theme.backgroundColor, + }, + this.props.style + ); const promptOptions = this.state.promptOptions; const folders = this.props.folders; const notes = this.props.notes; @@ -408,47 +418,59 @@ class MainScreenComponent extends React.Component { title: _('Toggle sidebar'), iconName: 'fa-bars', iconRotation: this.props.sidebarVisibility ? 0 : 90, - onClick: () => { this.doCommand({ name: 'toggleSidebar'}) } + onClick: () => { + this.doCommand({ name: 'toggleSidebar' }); + }, }); headerItems.push({ title: _('New note'), iconName: 'fa-file-o', enabled: !!folders.length && !onConflictFolder, - onClick: () => { this.doCommand({ name: 'newNote' }) }, + onClick: () => { + this.doCommand({ name: 'newNote' }); + }, }); headerItems.push({ title: _('New to-do'), iconName: 'fa-check-square-o', enabled: !!folders.length && !onConflictFolder, - onClick: () => { this.doCommand({ name: 'newTodo' }) }, + onClick: () => { + this.doCommand({ name: 'newTodo' }); + }, }); headerItems.push({ title: _('New notebook'), iconName: 'fa-book', - onClick: () => { this.doCommand({ name: 'newNotebook' }) }, + onClick: () => { + this.doCommand({ name: 'newNotebook' }); + }, }); headerItems.push({ title: _('Layout'), iconName: 'fa-columns', enabled: !!notes.length, - onClick: () => { this.doCommand({ name: 'toggleVisiblePanes' }) }, + onClick: () => { + this.doCommand({ name: 'toggleVisiblePanes' }); + }, }); headerItems.push({ title: _('Search...'), iconName: 'fa-search', - onQuery: (query) => { this.doCommand({ name: 'search', query: query }) }, + onQuery: query => { + this.doCommand({ name: 'search', query: query }); + }, type: 'search', }); if (!this.promptOnClose_) { this.promptOnClose_ = (answer, buttonType) => { return this.state.promptOptions.onClose(answer, buttonType); - } + }; } const onViewDisabledItemsClick = () => { @@ -456,36 +478,58 @@ class MainScreenComponent extends React.Component { type: 'NAV_GO', routeName: 'Status', }); - } + }; const onViewMasterKeysClick = () => { this.props.dispatch({ type: 'NAV_GO', routeName: 'EncryptionConfig', }); - } + }; let messageComp = null; if (messageBoxVisible) { let msg = null; if (this.props.hasDisabledSyncItems) { - msg = {_('Some items cannot be synchronised.')} { onViewDisabledItemsClick() }}>{_('View them now')} + msg = ( + + {_('Some items cannot be synchronised.')}{' '} + { + onViewDisabledItemsClick(); + }} + > + {_('View them now')} + + + ); } else if (this.props.showMissingMasterKeyMessage) { - msg = {_('One or more master keys need a password.')} { onViewMasterKeysClick() }}>{_('Set the password')} + msg = ( + + {_('One or more master keys need a password.')}{' '} + { + onViewMasterKeysClick(); + }} + > + {_('Set the password')} + + + ); } messageComp = (
- - {msg} - + {msg}
); } const dialogInfo = PluginManager.instance().pluginDialogToShow(this.props.plugins); - const pluginDialog = !dialogInfo ? null : ; + const pluginDialog = !dialogInfo ? null : ; const modalLayerStyle = Object.assign({}, styles.modalLayer, { display: this.state.modalLayer.visible ? 'block' : 'none' }); @@ -495,41 +539,25 @@ class MainScreenComponent extends React.Component {
{this.state.modalLayer.message}
- { notePropertiesDialogOptions.visible && } + {notePropertiesDialogOptions.visible && } - +
{messageComp} - + - - + + - {pluginDialog} + {pluginDialog}
); } - } -const mapStateToProps = (state) => { +const mapStateToProps = state => { return { theme: state.settings.theme, windowCommand: state.windowCommand, diff --git a/ElectronClient/app/gui/Navigator.jsx b/ElectronClient/app/gui/Navigator.jsx index 5905f8c5b..b69883376 100644 --- a/ElectronClient/app/gui/Navigator.jsx +++ b/ElectronClient/app/gui/Navigator.jsx @@ -1,10 +1,9 @@ -const React = require('react'); const Component = React.Component; +const React = require('react'); +const Component = React.Component; const { connect } = require('react-redux'); -const { app } = require('../app.js'); const { bridge } = require('electron').remote.require('./bridge'); class NavigatorComponent extends Component { - componentWillReceiveProps(newProps) { if (newProps.route) { const screenInfo = this.props.screens[newProps.route.routeName]; @@ -18,7 +17,10 @@ class NavigatorComponent extends Component { updateWindowTitle(title) { try { - if (bridge().window()) bridge().window().setTitle(title); + if (bridge().window()) + bridge() + .window() + .setTitle(title); } catch (error) { console.warn('updateWindowTitle', error); } @@ -39,19 +41,16 @@ class NavigatorComponent extends Component { return (
- +
); } - } -const Navigator = connect( - (state) => { - return { - route: state.route, - }; - } -)(NavigatorComponent) +const Navigator = connect(state => { + return { + route: state.route, + }; +})(NavigatorComponent); -module.exports = { Navigator }; \ No newline at end of file +module.exports = { Navigator }; diff --git a/ElectronClient/app/gui/NoteList.jsx b/ElectronClient/app/gui/NoteList.jsx index ec0ad8c0c..76665bdfa 100644 --- a/ElectronClient/app/gui/NoteList.jsx +++ b/ElectronClient/app/gui/NoteList.jsx @@ -7,20 +7,14 @@ const BaseModel = require('lib/BaseModel'); const markJsUtils = require('lib/markJsUtils'); const { _ } = require('lib/locale.js'); const { bridge } = require('electron').remote.require('./bridge'); -const Menu = bridge().Menu; -const MenuItem = bridge().MenuItem; const eventManager = require('../eventManager'); -const InteropService = require('lib/services/InteropService'); -const InteropServiceHelper = require('../InteropServiceHelper.js'); -const Search = require('lib/models/Search'); -const { stateUtils } = require('lib/reducer'); const Mark = require('mark.js/dist/mark.min.js'); const SearchEngine = require('lib/services/SearchEngine'); +const Note = require('lib/models/Note'); const NoteListUtils = require('./utils/NoteListUtils'); const { replaceRegexDiacritics, pregQuote } = require('lib/string-utils'); class NoteListComponent extends React.Component { - constructor() { super(); @@ -116,9 +110,9 @@ class NoteListComponent extends React.Component { id: item.id, }); } - } + }; - const onDragStart = (event) => { + const onDragStart = event => { let noteIds = []; // Here there is two cases: @@ -132,21 +126,21 @@ class NoteListComponent extends React.Component { } if (!noteIds.length) return; - + event.dataTransfer.setDragImage(new Image(), 1, 1); event.dataTransfer.clearData(); event.dataTransfer.setData('text/x-jop-note-ids', JSON.stringify(noteIds)); - } + }; - const onCheckboxClick = async (event) => { + const onCheckboxClick = async event => { const checked = event.target.checked; const newNote = { id: item.id, todo_completed: checked ? time.unixMs() : 0, - } + }; await Note.save(newNote, { userSideValidation: true }); eventManager.emit('todoToggle', { noteId: item.id }); - } + }; const hPadding = 10; @@ -167,11 +161,18 @@ class NoteListComponent extends React.Component { // Setting marginBottom = 1 because it makes the checkbox looks more centered, at least on Windows // but don't know how it will look in other OSes. - const checkbox = item.is_todo ? -
- { onCheckboxClick(event, item) }}/> + const checkbox = item.is_todo ? ( +
+ { + onCheckboxClick(event, item); + }} + />
- : null; + ) : null; let listItemTitleStyle = Object.assign({}, this.style().listItemTitle); listItemTitleStyle.paddingLeft = !checkbox ? hPadding : 4; @@ -204,41 +205,43 @@ class NoteListComponent extends React.Component { // with `textContent` so it cannot contain any XSS attacks. We use this feature because // mark.js can only deal with DOM elements. // https://reactjs.org/docs/dom-elements.html#dangerouslysetinnerhtml - titleComp = + titleComp = ; } else { - titleComp = {displayTitle} + titleComp = {displayTitle}; } const watchedIconStyle = { paddingRight: 4, color: theme.color, }; - const watchedIcon = this.props.watchedNoteFiles.indexOf(item.id) < 0 ? null : ( - - ); + const watchedIcon = this.props.watchedNoteFiles.indexOf(item.id) < 0 ? null : ; if (!this.itemAnchorRefs_[item.id]) this.itemAnchorRefs_[item.id] = React.createRef(); const ref = this.itemAnchorRefs_[item.id]; // Need to include "todo_completed" in key so that checkbox is updated when - // item is changed via sync. - return + // item is changed via sync. + return ( + + ); } itemAnchorRef(itemId) { @@ -279,7 +282,7 @@ class NoteListComponent extends React.Component { if (this.props.notes[i].id === id) { this.itemListRef.current.makeItemIndexVisible(i); break; - } + } } } } @@ -288,7 +291,8 @@ class NoteListComponent extends React.Component { const keyCode = event.keyCode; const noteIds = this.props.selectedNoteIds; - if (noteIds.length === 1 && (keyCode === 40 || keyCode === 38)) { // DOWN / UP + if (noteIds.length === 1 && (keyCode === 40 || keyCode === 38)) { + // DOWN / UP const noteId = noteIds[0]; let noteIndex = BaseModel.modelIndexById(this.props.notes, noteId); const inc = keyCode === 38 ? -1 : +1; @@ -312,12 +316,14 @@ class NoteListComponent extends React.Component { event.preventDefault(); } - if (noteIds.length && (keyCode === 46 || (keyCode === 8 && event.metaKey))) { // DELETE / CMD+Backspace + if (noteIds.length && (keyCode === 46 || (keyCode === 8 && event.metaKey))) { + // DELETE / CMD+Backspace event.preventDefault(); await NoteListUtils.confirmDeleteNotes(noteIds); } - if (noteIds.length && keyCode === 32) { // SPACE + if (noteIds.length && keyCode === 32) { + // SPACE event.preventDefault(); const notes = BaseModel.modelsByIds(this.props.notes, noteIds); @@ -332,7 +338,8 @@ class NoteListComponent extends React.Component { this.focusNoteId_(todos[0].id); } - if (keyCode === 9) { // TAB + if (keyCode === 9) { + // TAB event.preventDefault(); if (event.shiftKey) { @@ -361,7 +368,7 @@ class NoteListComponent extends React.Component { this.focusItemIID_ = setInterval(() => { if (this.itemAnchorRef(noteId)) { this.itemAnchorRef(noteId).focus(); - clearInterval(this.focusItemIID_) + clearInterval(this.focusItemIID_); this.focusItemIID_ = null; } }, 10); @@ -381,37 +388,29 @@ class NoteListComponent extends React.Component { const theme = themeStyle(this.props.theme); const style = this.props.style; let notes = this.props.notes.slice(); - + if (!notes.length) { const padding = 10; - const emptyDivStyle = Object.assign({ - padding: padding + 'px', - fontSize: theme.fontSize, - color: theme.color, - backgroundColor: theme.backgroundColor, - fontFamily: theme.fontFamily, - }, style); + const emptyDivStyle = Object.assign( + { + padding: padding + 'px', + fontSize: theme.fontSize, + color: theme.color, + backgroundColor: theme.backgroundColor, + fontFamily: theme.fontFamily, + }, + style + ); emptyDivStyle.width = emptyDivStyle.width - padding * 2; emptyDivStyle.height = emptyDivStyle.height - padding * 2; - return
{ this.props.folders.length ? _('No notes in here. Create one by clicking on "New note".') : _('There is currently no notebook. Create one by clicking on "New notebook".')}
+ return
{this.props.folders.length ? _('No notes in here. Create one by clicking on "New note".') : _('There is currently no notebook. Create one by clicking on "New notebook".')}
; } - return ( - - ); + return ; } - } -const mapStateToProps = (state) => { +const mapStateToProps = state => { return { notes: state.notes, folders: state.folders, @@ -427,4 +426,4 @@ const mapStateToProps = (state) => { const NoteList = connect(mapStateToProps)(NoteListComponent); -module.exports = { NoteList }; \ No newline at end of file +module.exports = { NoteList }; diff --git a/ElectronClient/app/gui/NotePropertiesDialog.jsx b/ElectronClient/app/gui/NotePropertiesDialog.jsx index 76fe03814..2f8ae7b7a 100644 --- a/ElectronClient/app/gui/NotePropertiesDialog.jsx +++ b/ElectronClient/app/gui/NotePropertiesDialog.jsx @@ -1,7 +1,5 @@ const React = require('react'); -const { connect } = require('react-redux'); const { _ } = require('lib/locale.js'); -const moment = require('moment'); const { themeStyle } = require('../theme.js'); const { time } = require('lib/time-utils.js'); const Datetime = require('react-datetime'); @@ -10,7 +8,6 @@ const formatcoords = require('formatcoords'); const { bridge } = require('electron').remote.require('./bridge'); class NotePropertiesDialog extends React.Component { - constructor() { super(); @@ -129,9 +126,9 @@ class NotePropertiesDialog extends React.Component { border: '1px solid', borderColor: theme.dividerColor, }; - + this.styles_.input = { - display:'inline-block', + display: 'inline-block', color: theme.color, backgroundColor: theme.backgroundColor, border: '1px solid', @@ -205,68 +202,86 @@ class NotePropertiesDialog extends React.Component { newFormNote[this.state.editedKey] = this.state.editedValue; } - this.setState({ - formNote: newFormNote, - editedKey: null, - editedValue: null - }, () => { resolve() }); + this.setState( + { + formNote: newFormNote, + editedKey: null, + editedValue: null, + }, + () => { + resolve(); + } + ); }); } async cancelProperty() { return new Promise((resolve, reject) => { this.okButton.current.focus(); - this.setState({ - editedKey: null, - editedValue: null - }, () => { resolve() }); + this.setState( + { + editedKey: null, + editedValue: null, + }, + () => { + resolve(); + } + ); }); } createNoteField(key, value) { const styles = this.styles(this.props.theme); const theme = themeStyle(this.props.theme); - const labelComp = ; + const labelComp = ; let controlComp = null; let editComp = null; let editCompHandler = null; let editCompIcon = null; - const onKeyDown = (event) => { + const onKeyDown = event => { if (event.keyCode === 13) { this.saveProperty(); } else if (event.keyCode === 27) { this.cancelProperty(); } - } + }; if (this.state.editedKey === key) { if (key.indexOf('_time') >= 0) { + controlComp = ( + onKeyDown(event, key), + style: styles.input, + }} + onChange={momentObject => { + this.setState({ editedValue: momentObject }); + }} + /> + ); - controlComp = onKeyDown(event, key), - style: styles.input - }} - onChange={(momentObject) => {this.setState({ editedValue: momentObject })}} - /> - - editCompHandler = () => {this.saveProperty()}; + editCompHandler = () => { + this.saveProperty(); + }; editCompIcon = 'fa-save'; } else { - - controlComp = {this.setState({ editedValue: event.target.value })}} - onKeyDown={(event) => onKeyDown(event)} - style={styles.input} - /> + controlComp = ( + { + this.setState({ editedValue: event.target.value }); + }} + onKeyDown={event => onKeyDown(event)} + style={styles.input} + /> + ); } } else { let displayedValue = value; @@ -287,15 +302,25 @@ class NotePropertiesDialog extends React.Component { const ll = this.latLongFromLocation(value); url = Note.geoLocationUrlFromLatLong(ll.latitude, ll.longitude); } - controlComp = bridge().openExternal(url)} style={theme.urlStyle}>{displayedValue} + controlComp = ( + bridge().openExternal(url)} style={theme.urlStyle}> + {displayedValue} + + ); } else if (key === 'revisionsLink') { - controlComp = {_('Previous versions of this note')} + controlComp = ( + + {_('Previous versions of this note')} + + ); } else { - controlComp =
{displayedValue}
+ controlComp =
{displayedValue}
; } if (['id', 'revisionsLink', 'markup_language'].indexOf(key) < 0) { - editCompHandler = () => {this.editPropertyButtonClick(key, value)}; + editCompHandler = () => { + this.editPropertyButtonClick(key, value); + }; editCompIcon = 'fa-edit'; } } @@ -303,16 +328,16 @@ class NotePropertiesDialog extends React.Component { if (editCompHandler) { editComp = ( - + ); } return (
- { labelComp } - { controlComp } - { editComp } + {labelComp} + {controlComp} + {editComp}
); } @@ -325,7 +350,7 @@ class NotePropertiesDialog extends React.Component { formatValue(key, note) { if (key === 'location') { if (!Number(note.latitude) && !Number(note.longitude)) return null; - const dms = formatcoords(Number(note.latitude), Number(note.longitude)) + const dms = formatcoords(Number(note.latitude), Number(note.longitude)); return dms.format('DDMMss', { decimalPlaces: 0 }); } @@ -337,24 +362,21 @@ class NotePropertiesDialog extends React.Component { } render() { - const style = this.props.style; const theme = themeStyle(this.props.theme); const styles = this.styles(this.props.theme); const formNote = this.state.formNote; const buttonComps = []; buttonComps.push( - ); - buttonComps.push(); + buttonComps.push( + + ); const noteComps = []; @@ -371,14 +393,11 @@ class NotePropertiesDialog extends React.Component {
{_('Note properties')}
{noteComps}
-
- {buttonComps} -
+
{buttonComps}
); } - } module.exports = NotePropertiesDialog; diff --git a/ElectronClient/app/gui/NoteRevisionViewer.jsx b/ElectronClient/app/gui/NoteRevisionViewer.jsx index f2f1d9908..4ca1e1aba 100644 --- a/ElectronClient/app/gui/NoteRevisionViewer.jsx +++ b/ElectronClient/app/gui/NoteRevisionViewer.jsx @@ -6,6 +6,7 @@ const NoteTextViewer = require('./NoteTextViewer.min'); const HelpButton = require('./HelpButton.min'); const BaseModel = require('lib/BaseModel'); const Revision = require('lib/models/Revision'); +const Note = require('lib/models/Note'); const Setting = require('lib/models/Setting'); const RevisionService = require('lib/services/RevisionService'); const shared = require('lib/components/shared/note-screen-shared.js'); @@ -15,7 +16,6 @@ const ReactTooltip = require('react-tooltip'); const { substrWithEllipsis } = require('lib/string-utils'); class NoteRevisionViewerComponent extends React.PureComponent { - constructor() { super(); @@ -55,13 +55,16 @@ class NoteRevisionViewerComponent extends React.PureComponent { // this.viewerRef_.current.wrappedInstance.openDevTools(); const revisions = await Revision.allByType(BaseModel.TYPE_NOTE, this.props.noteId); - - this.setState({ - revisions: revisions, - currentRevId: revisions.length ? revisions[revisions.length - 1].id : '', - }, () => { - this.reloadNote(); - }); + + this.setState( + { + revisions: revisions, + currentRevId: revisions.length ? revisions[revisions.length - 1].id : '', + }, + () => { + this.reloadNote(); + } + ); } async importButton_onClick() { @@ -82,11 +85,14 @@ class NoteRevisionViewerComponent extends React.PureComponent { if (!value) { if (this.props.onBack) this.props.onBack(); } else { - this.setState({ - currentRevId: value, - }, () => { - this.reloadNote(); - }); + this.setState( + { + currentRevId: value, + }, + () => { + this.reloadNote(); + } + ); } } @@ -117,7 +123,7 @@ class NoteRevisionViewerComponent extends React.PureComponent { resources: await shared.attachedResources(noteBody), }); - this.viewerRef_.current.wrappedInstance.send('setHtml', result.html, { cssFiles: result.cssFiles }); + this.viewerRef_.current.wrappedInstance.send('setHtml', result.html, { cssFiles: result.cssFiles }); } render() { @@ -130,45 +136,45 @@ class NoteRevisionViewerComponent extends React.PureComponent { const rev = revs[i]; const stats = Revision.revisionPatchStatsText(rev); - revisionListItems.push(); + revisionListItems.push( + + ); } const restoreButtonTitle = _('Restore'); const helpMessage = _('Click "%s" to restore the note. It will be copied in the notebook named "%s". The current version of the note will not be replaced or modified.', restoreButtonTitle, RevisionService.instance().restoreFolderTitle()); const titleInput = ( -
- - +
+ + - - + +
); - const viewer = + const viewer = ; return (
{titleInput} {viewer} - +
); } - } -const mapStateToProps = (state) => { +const mapStateToProps = state => { return { theme: state.settings.theme, }; @@ -176,4 +182,4 @@ const mapStateToProps = (state) => { const NoteRevisionViewer = connect(mapStateToProps)(NoteRevisionViewerComponent); -module.exports = NoteRevisionViewer; \ No newline at end of file +module.exports = NoteRevisionViewer; diff --git a/ElectronClient/app/gui/NoteSearchBar.jsx b/ElectronClient/app/gui/NoteSearchBar.jsx index 78e67929c..c09bdd31c 100644 --- a/ElectronClient/app/gui/NoteSearchBar.jsx +++ b/ElectronClient/app/gui/NoteSearchBar.jsx @@ -4,7 +4,6 @@ const { themeStyle } = require('../theme.js'); const { _ } = require('lib/locale.js'); class NoteSearchBarComponent extends React.Component { - constructor() { super(); @@ -54,14 +53,12 @@ class NoteSearchBarComponent extends React.Component { color: theme.color, }; - const icon = + const icon = ; return ( - {icon} + + {icon} + ); } @@ -72,7 +69,8 @@ class NoteSearchBarComponent extends React.Component { } searchInput_keyDown(event) { - if (event.keyCode === 13) { // ENTER + if (event.keyCode === 13) { + // ENTER event.preventDefault(); if (!event.shiftKey) { @@ -82,7 +80,8 @@ class NoteSearchBarComponent extends React.Component { } } - if (event.keyCode === 27) { // ESCAPE + if (event.keyCode === 27) { + // ESCAPE event.preventDefault(); if (this.props.onClose) this.props.onClose(); @@ -110,32 +109,34 @@ class NoteSearchBarComponent extends React.Component { } render() { - const theme = themeStyle(this.props.theme); - const closeButton = this.buttonIconComponent('fa-times', this.closeButton_click); const previousButton = this.buttonIconComponent('fa-chevron-up', this.previousButton_click); const nextButton = this.buttonIconComponent('fa-chevron-down', this.nextButton_click); return (
-
- { closeButton } - - { nextButton } - { previousButton } +
+ {closeButton} + + {nextButton} + {previousButton}
); } - } -const mapStateToProps = (state) => { +const mapStateToProps = state => { return { theme: state.settings.theme, }; }; -const NoteSearchBar = connect(mapStateToProps, null, null, { withRef: true })(NoteSearchBarComponent); +const NoteSearchBar = connect( + mapStateToProps, + null, + null, + { withRef: true } +)(NoteSearchBarComponent); -module.exports = NoteSearchBar; \ No newline at end of file +module.exports = NoteSearchBar; diff --git a/ElectronClient/app/gui/NoteStatusBar.jsx b/ElectronClient/app/gui/NoteStatusBar.jsx index fe5ce30d8..714fd8594 100644 --- a/ElectronClient/app/gui/NoteStatusBar.jsx +++ b/ElectronClient/app/gui/NoteStatusBar.jsx @@ -2,15 +2,11 @@ const React = require('react'); const { connect } = require('react-redux'); const { time } = require('lib/time-utils.js'); const { themeStyle } = require('../theme.js'); -const { _ } = require('lib/locale.js'); class NoteStatusBarComponent extends React.Component { - style() { const theme = themeStyle(this.props.theme); - const itemHeight = 34; - let style = { root: Object.assign({}, theme.textStyle, { backgroundColor: theme.backgroundColor, @@ -22,18 +18,12 @@ class NoteStatusBarComponent extends React.Component { } render() { - const theme = themeStyle(this.props.theme); - const style = this.props.style; const note = this.props.note; - - return ( -
{time.formatMsToLocal(note.user_updated_time)}
- ); + return
{time.formatMsToLocal(note.user_updated_time)}
; } - } -const mapStateToProps = (state) => { +const mapStateToProps = state => { return { // notes: state.notes, // folders: state.folders, @@ -44,4 +34,4 @@ const mapStateToProps = (state) => { const NoteStatusBar = connect(mapStateToProps)(NoteStatusBarComponent); -module.exports = { NoteStatusBar }; \ No newline at end of file +module.exports = { NoteStatusBar }; diff --git a/ElectronClient/app/gui/NoteText.jsx b/ElectronClient/app/gui/NoteText.jsx index 647adbec3..fd02d6145 100644 --- a/ElectronClient/app/gui/NoteText.jsx +++ b/ElectronClient/app/gui/NoteText.jsx @@ -2,11 +2,13 @@ const React = require('react'); const Note = require('lib/models/Note.js'); const BaseItem = require('lib/models/BaseItem.js'); const BaseModel = require('lib/BaseModel.js'); -const Search = require('lib/models/Search.js'); +const Resource = require('lib/models/Resource.js'); +const Folder = require('lib/models/Folder.js'); +const Tag = require('lib/models/Tag.js'); const { time } = require('lib/time-utils.js'); const Setting = require('lib/models/Setting.js'); const { IconButton } = require('./IconButton.min.js'); -const { urlDecode, escapeHtml, pregQuote, scriptType, substrWithEllipsis } = require('lib/string-utils'); +const { urlDecode, substrWithEllipsis } = require('lib/string-utils'); const Toolbar = require('./Toolbar.min.js'); const TagList = require('./TagList.min.js'); const { connect } = require('react-redux'); @@ -24,7 +26,6 @@ const eventManager = require('../eventManager'); const fs = require('fs-extra'); const md5 = require('md5'); const mimeUtils = require('lib/mime-utils.js').mime; -const ArrayUtils = require('lib/ArrayUtils'); const ObjectUtils = require('lib/ObjectUtils'); const urlUtils = require('lib/urlUtils'); const dialogs = require('./dialogs'); @@ -36,8 +37,6 @@ const ResourceFetcher = require('lib/services/ResourceFetcher'); const { toSystemSlashes, safeFilename } = require('lib/path-utils'); const { clipboard } = require('electron'); const SearchEngine = require('lib/services/SearchEngine'); -const DecryptionWorker = require('lib/services/DecryptionWorker'); -const ModelCache = require('lib/services/ModelCache'); const NoteTextViewer = require('./NoteTextViewer.min'); const NoteRevisionViewer = require('./NoteRevisionViewer.min'); const TemplateUtils = require('lib/TemplateUtils'); @@ -53,7 +52,6 @@ require('brace/theme/twilight'); const NOTE_TAG_BAR_FEATURE_ENABLED = false; class NoteTextComponent extends React.Component { - constructor() { super(); @@ -84,7 +82,7 @@ class NoteTextComponent extends React.Component { lastRenderCssFiles: [], lastKeys: [], showLocalSearch: false, - localSearch: Object.assign({}, this.localSearchDefaultState), + localSearch: Object.assign({}, this.localSearchDefaultState), }; this.webviewRef_ = React.createRef(); @@ -113,17 +111,23 @@ class NoteTextComponent extends React.Component { this.editorSetScrollTop(this.restoreScrollTop_); this.restoreScrollTop_ = null; } - } + }; - this.onAlarmChange_ = (event) => { if (event.noteId === this.props.noteId) this.scheduleReloadNote(this.props); } - this.onNoteTypeToggle_ = (event) => { if (event.noteId === this.props.noteId) this.scheduleReloadNote(this.props); } - this.onTodoToggle_ = (event) => { if (event.noteId === this.props.noteId) this.scheduleReloadNote(this.props); } + this.onAlarmChange_ = event => { + if (event.noteId === this.props.noteId) this.scheduleReloadNote(this.props); + }; + this.onNoteTypeToggle_ = event => { + if (event.noteId === this.props.noteId) this.scheduleReloadNote(this.props); + }; + this.onTodoToggle_ = event => { + if (event.noteId === this.props.noteId) this.scheduleReloadNote(this.props); + }; this.onEditorPaste_ = async (event = null) => { const formats = clipboard.availableFormats(); for (let i = 0; i < formats.length; i++) { const format = formats[i].toLowerCase(); - const formatType = format.split('/')[0] + const formatType = format.split('/')[0]; if (formatType === 'image') { if (event) event.preventDefault(); @@ -138,54 +142,72 @@ class NoteTextComponent extends React.Component { await shim.fsDriver().remove(filePath); } } - } + }; - this.onEditorKeyDown_ = (event) => { + this.onEditorKeyDown_ = event => { const lastKeys = this.state.lastKeys.slice(); lastKeys.push(event.key); while (lastKeys.length > 2) lastKeys.splice(0, 1); this.setState({ lastKeys: lastKeys }); - } + }; - this.onEditorContextMenu_ = (event) => { + this.onEditorContextMenu_ = event => { const menu = new Menu(); const selectedText = this.selectedText(); const clipboardText = clipboard.readText(); - menu.append(new MenuItem({label: _('Cut'), enabled: !!selectedText, click: async () => { - this.editorCutText(); - }})); + menu.append( + new MenuItem({ + label: _('Cut'), + enabled: !!selectedText, + click: async () => { + this.editorCutText(); + }, + }) + ); - menu.append(new MenuItem({label: _('Copy'), enabled: !!selectedText, click: async () => { - this.editorCopyText(); - }})); + menu.append( + new MenuItem({ + label: _('Copy'), + enabled: !!selectedText, + click: async () => { + this.editorCopyText(); + }, + }) + ); - menu.append(new MenuItem({label: _('Paste'), enabled: true, click: async () => { - if (clipboardText) { - this.editorPasteText(); - } else { - // To handle pasting images - this.onEditorPaste_(); - } - }})); + menu.append( + new MenuItem({ + label: _('Paste'), + enabled: true, + click: async () => { + if (clipboardText) { + this.editorPasteText(); + } else { + // To handle pasting images + this.onEditorPaste_(); + } + }, + }) + ); menu.popup(bridge().window()); - } + }; - this.onDrop_ = async (event) => { + this.onDrop_ = async event => { const dt = event.dataTransfer; const createFileURL = event.altKey; - if (dt.types.indexOf("text/x-jop-note-ids") >= 0) { - const noteIds = JSON.parse(dt.getData("text/x-jop-note-ids")); + if (dt.types.indexOf('text/x-jop-note-ids') >= 0) { + const noteIds = JSON.parse(dt.getData('text/x-jop-note-ids')); const linkText = []; for (let i = 0; i < noteIds.length; i++) { const note = await Note.load(noteIds[i]); linkText.push(Note.markdownTag(note)); } - this.wrapSelectionWithStrings("", "", '', linkText.join('\n')); + this.wrapSelectionWithStrings('', '', '', linkText.join('\n')); } const files = dt.files; @@ -200,7 +222,7 @@ class NoteTextComponent extends React.Component { } await this.commandAttachFile(filesToAttach, createFileURL); - } + }; const updateSelectionRange = () => { if (!this.rawEditor()) { @@ -208,30 +230,32 @@ class NoteTextComponent extends React.Component { return; } - const ranges = this.rawEditor().getSelection().getAllRanges(); + const ranges = this.rawEditor() + .getSelection() + .getAllRanges(); if (!ranges || !ranges.length || !this.state.note) { this.selectionRange_ = null; } else { this.selectionRange_ = ranges[0]; } - } + }; - this.aceEditor_selectionChange = (selection) => { + this.aceEditor_selectionChange = () => { updateSelectionRange(); - } + }; - this.aceEditor_focus = (event) => { + this.aceEditor_focus = event => { updateSelectionRange(); - } + }; - this.externalEditWatcher_noteChange = (event) => { + this.externalEditWatcher_noteChange = event => { if (!this.state.note || !this.state.note.id) return; if (event.id === this.state.note.id) { this.scheduleReloadNote(this.props); } - } + }; - this.refreshResource = async (event) => { + this.refreshResource = async event => { if (!this.state.note || !this.state.note.body) return; const resourceIds = await Note.linkedResourceIds(this.state.note.body); if (resourceIds.indexOf(event.id) >= 0) { @@ -239,37 +263,39 @@ class NoteTextComponent extends React.Component { this.lastSetHtml_ = ''; this.scheduleHtmlUpdate(); } - } + }; - this.noteSearchBar_change = (query) => { - this.setState({ localSearch: { - query: query, - selectedIndex: 0, - }}); - } + this.noteSearchBar_change = query => { + this.setState({ + localSearch: { + query: query, + selectedIndex: 0, + }, + }); + }; - const noteSearchBarNextPrevious = (inc) => { + const noteSearchBarNextPrevious = inc => { const ls = Object.assign({}, this.state.localSearch); ls.selectedIndex += inc; if (ls.selectedIndex < 0) ls.selectedIndex = ls.resultCount - 1; if (ls.selectedIndex >= ls.resultCount) ls.selectedIndex = 0; this.setState({ localSearch: ls }); - } + }; this.noteSearchBar_next = () => { noteSearchBarNextPrevious(+1); - } + }; this.noteSearchBar_previous = () => { noteSearchBarNextPrevious(-1); - } + }; this.noteSearchBar_close = () => { this.setState({ showLocalSearch: false, }); - } + }; this.titleField_keyDown = this.titleField_keyDown.bind(this); this.webview_ipcMessage = this.webview_ipcMessage.bind(this); @@ -323,7 +349,7 @@ class NoteTextComponent extends React.Component { return { row: row, column: offset - currentOffset, - } + }; } row++; @@ -356,7 +382,7 @@ class NoteTextComponent extends React.Component { note: note, folder: folder, isLoading: false, - noteTags: noteTags + noteTags: noteTags, }); this.lastLoadedNoteId_ = note ? note.id : null; @@ -386,7 +412,7 @@ class NoteTextComponent extends React.Component { ExternalEditWatcher.instance().off('noteChange', this.externalEditWatcher_noteChange); } - componentDidUpdate(prevProps) { + componentDidUpdate() { if (this.webviewRef() && this.props.noteDevToolsVisible !== this.webviewRef().isDevToolsOpened()) { if (this.props.noteDevToolsVisible) { this.webviewRef().openDevTools(); @@ -465,16 +491,13 @@ class NoteTextComponent extends React.Component { const defer = () => { this.setState({ loading: false }); - } + }; this.setState({ loading: true }); - const previousNote = this.state.note ? Object.assign({}, this.state.note) : null; - const stateNoteId = this.state.note ? this.state.note.id : null; let noteId = null; let note = null; - let newNote = null; let loadingNewNote = true; let parentFolder = null; let noteTags = []; @@ -482,10 +505,9 @@ class NoteTextComponent extends React.Component { if (props.newNote) { // assign new note and prevent body from being null - note = Object.assign({}, props.newNote, {body: ''}); + note = Object.assign({}, props.newNote, { body: '' }); this.lastLoadedNoteId_ = null; - if (note.template) - note.body = TemplateUtils.render(note.template); + if (note.template) note.body = TemplateUtils.render(note.template); } else { noteId = props.noteId; @@ -517,7 +539,7 @@ class NoteTextComponent extends React.Component { // Scroll back to top when loading new note if (loadingNewNote) { shared.clearResourceCache(); - + this.editorMaxScrollTop_ = 0; // HACK: To go around a bug in Ace editor, we first set the scroll position to 1 @@ -529,7 +551,7 @@ class NoteTextComponent extends React.Component { // Only force focus on notes when creating a new note/todo if (this.props.newNote) { - const focusSettingName = !!note.is_todo ? 'newTodoFocus' : 'newNoteFocus'; + const focusSettingName = note.is_todo ? 'newTodoFocus' : 'newNoteFocus'; requestAnimationFrame(() => { if (Setting.value(focusSettingName) === 'title') { @@ -542,7 +564,7 @@ class NoteTextComponent extends React.Component { if (this.editor_) { this.editor_.editor.clearSelection(); - this.editor_.editor.moveCursorTo(0,0); + this.editor_.editor.moveCursorTo(0, 0); setTimeout(() => { this.setEditorPercentScroll(scrollPercent ? scrollPercent : 0); @@ -597,7 +619,7 @@ class NoteTextComponent extends React.Component { if (NOTE_TAG_BAR_FEATURE_ENABLED) { if (!this.props.newNote) { this.props.dispatch({ - type: "SET_NOTE_TAGS", + type: 'SET_NOTE_TAGS', items: noteTags, }); } @@ -613,15 +635,15 @@ class NoteTextComponent extends React.Component { async componentWillReceiveProps(nextProps) { if (this.props.newNote !== nextProps.newNote && nextProps.newNote) { await this.scheduleReloadNote(nextProps); - } else if (('noteId' in nextProps) && nextProps.noteId !== this.props.noteId) { + } else if ('noteId' in nextProps && nextProps.noteId !== this.props.noteId) { await this.scheduleReloadNote(nextProps); } else if ('noteTags' in nextProps && this.areNoteTagsModified(nextProps.noteTags, this.state.noteTags)) { this.setState({ - noteTags: nextProps.noteTags + noteTags: nextProps.noteTags, }); } - if ((nextProps.syncStarted !== this.props.syncStarted) && ('syncStarted' in nextProps) && !nextProps.syncStarted && !this.isModified()) { + if (nextProps.syncStarted !== this.props.syncStarted && 'syncStarted' in nextProps && !nextProps.syncStarted && !this.isModified()) { await this.scheduleReloadNote(nextProps, { noReloadIfLocalChanges: true }); } @@ -674,9 +696,8 @@ class NoteTextComponent extends React.Component { async webview_ipcMessage(event) { const msg = event.channel ? event.channel : ''; - const args = event.args; + const args = event.args; const arg0 = args && args.length >= 1 ? args[0] : null; - const arg1 = args && args.length >= 2 ? args[1] : null; if (msg !== 'percentScroll') console.info('Got ipc-message: ' + msg, args); @@ -707,36 +728,61 @@ class NoteTextComponent extends React.Component { } else if (msg === 'contextMenu') { const itemType = arg0 && arg0.type; - const menu = new Menu() + const menu = new Menu(); - if (itemType === "image" || itemType === "resource") { + if (itemType === 'image' || itemType === 'resource') { const resource = await Resource.load(arg0.resourceId); const resourcePath = Resource.fullPath(resource); - menu.append(new MenuItem({label: _('Open...'), click: async () => { - const ok = bridge().openExternal('file://' + resourcePath); - if (!ok) bridge().showErrorMessageBox(_('This file could not be opened: %s', resourcePath)); - }})); + menu.append( + new MenuItem({ + label: _('Open...'), + click: async () => { + const ok = bridge().openExternal('file://' + resourcePath); + if (!ok) bridge().showErrorMessageBox(_('This file could not be opened: %s', resourcePath)); + }, + }) + ); - menu.append(new MenuItem({label: _('Save as...'), click: async () => { - const filePath = bridge().showSaveDialog({ - defaultPath: resource.filename ? resource.filename : resource.title, - }); - if (!filePath) return; - await fs.copy(resourcePath, filePath); - }})); + menu.append( + new MenuItem({ + label: _('Save as...'), + click: async () => { + const filePath = bridge().showSaveDialog({ + defaultPath: resource.filename ? resource.filename : resource.title, + }); + if (!filePath) return; + await fs.copy(resourcePath, filePath); + }, + }) + ); - menu.append(new MenuItem({label: _('Copy path to clipboard'), click: async () => { - clipboard.writeText(toSystemSlashes(resourcePath)); - }})); - } else if (itemType === "text") { - menu.append(new MenuItem({label: _('Copy'), click: async () => { - clipboard.writeText(arg0.textToCopy); - }})); - } else if (itemType === "link") { - menu.append(new MenuItem({label: _('Copy Link Address'), click: async () => { - clipboard.writeText(arg0.textToCopy); - }})); + menu.append( + new MenuItem({ + label: _('Copy path to clipboard'), + click: async () => { + clipboard.writeText(toSystemSlashes(resourcePath)); + }, + }) + ); + } else if (itemType === 'text') { + menu.append( + new MenuItem({ + label: _('Copy'), + click: async () => { + clipboard.writeText(arg0.textToCopy); + }, + }) + ); + } else if (itemType === 'link') { + menu.append( + new MenuItem({ + label: _('Copy Link Address'), + click: async () => { + clipboard.writeText(arg0.textToCopy); + }, + }) + ); } else { reg.logger().error('Unhandled item type: ' + itemType); return; @@ -759,7 +805,7 @@ class NoteTextComponent extends React.Component { bridge().openItem(filePath); } else if (item.type_ === BaseModel.TYPE_NOTE) { this.props.dispatch({ - type: "FOLDER_AND_NOTE_SELECT", + type: 'FOLDER_AND_NOTE_SELECT', folderId: item.parent_id, noteId: item.id, historyNoteAction: { @@ -897,7 +943,7 @@ class NoteTextComponent extends React.Component { } } return output; - } + }; // Disable Markdown auto-completion (eg. auto-adding a dash after a line with a dash. // https://github.com/ajaxorg/ace/issues/2754 @@ -967,8 +1013,6 @@ class NoteTextComponent extends React.Component { codeHighlightCacheKey: this.state.note ? this.state.note.id : null, }; - let bodyHtml = ''; - const visiblePanes = this.props.visiblePanes || ['editor', 'viewer']; if (!bodyToRender.trim() && visiblePanes.indexOf('viewer') >= 0 && visiblePanes.indexOf('editor') < 0) { @@ -987,7 +1031,8 @@ class NoteTextComponent extends React.Component { titleField_keyDown(event) { const keyCode = event.keyCode; - if (keyCode === 9) { // TAB + if (keyCode === 9) { + // TAB event.preventDefault(); if (event.shiftKey) { @@ -1033,7 +1078,9 @@ class NoteTextComponent extends React.Component { } else if (command.name === 'textCode') { fn = this.commandTextCode; } else if (command.name === 'insertTemplate') { - fn = () => { return this.commandTemplate(command.value); }; + fn = () => { + return this.commandTemplate(command.value); + }; } } @@ -1041,14 +1088,14 @@ class NoteTextComponent extends React.Component { fn = () => { if (!this.titleField_) return; this.titleField_.focus(); - } + }; } if (command.name === 'focusElement' && command.target === 'noteBody') { fn = () => { if (!this.editor_) return; this.editor_.editor.focus(); - } + }; } if (!fn) return; @@ -1130,7 +1177,7 @@ class NoteTextComponent extends React.Component { } const previousBody = this.state.note.body; - const tempBody = this.title_(this.state.note.title) + "\n\n" + previousBody; + const tempBody = this.title_(this.state.note.title) + '\n\n' + previousBody; const previousTheme = Setting.value('theme'); Setting.setValue('theme', Setting.THEME_LIGHT); @@ -1143,7 +1190,7 @@ class NoteTextComponent extends React.Component { this.lastSetHtml_ = ''; await this.updateHtml(this.state.note.markup_language, previousBody); this.forceUpdate(); - } + }; setTimeout(() => { if (target === 'pdf') { @@ -1160,7 +1207,7 @@ class NoteTextComponent extends React.Component { this.webviewRef_.current.wrappedInstance.print({ printBackground: true }); restoreSettings(); } - }, 100); + }, 100); } async commandSavePdf() { @@ -1168,7 +1215,7 @@ class NoteTextComponent extends React.Component { if (!this.state.note) throw new Error(_('Only one note can be printed or exported to PDF at a time.')); const path = bridge().showSaveDialog({ - filters: [{ name: _('PDF File'), extensions: ['pdf']}], + filters: [{ name: _('PDF File'), extensions: ['pdf'] }], defaultPath: safeFilename(this.state.note.title), }); @@ -1185,7 +1232,7 @@ class NoteTextComponent extends React.Component { await this.printTo_('printer'); } catch (error) { bridge().showErrorMessageBox(error.message); - } + } } async commandStartExternalEditing() { @@ -1227,7 +1274,7 @@ class NoteTextComponent extends React.Component { lineAtRow(row) { if (!this.state.note) return ''; - const body = this.state.note.body + const body = this.state.note.body; const lines = body.split('\n'); if (row < 0 || row >= lines.length) return ''; return lines[row]; @@ -1260,20 +1307,20 @@ class NoteTextComponent extends React.Component { shared.noteComponent_change(this, 'body', s1 + s2); - this.updateEditorWithDelay((editor) => { + this.updateEditorWithDelay(editor => { const range = this.selectionRange_; range.setStart(range.start.row, range.start.column); range.setEnd(range.start.row, range.start.column); - editor.getSession().getSelection().setSelectionRange(range, false); + editor + .getSession() + .getSelection() + .setSelectionRange(range, false); editor.focus(); }, 10); } editorPasteText() { - const s = this.textOffsetSelection(); - const s1 = this.state.note.body.substr(0, s.start); - const s2 = this.state.note.body.substr(s.end); - this.wrapSelectionWithStrings("", "", '', clipboard.readText()); + this.wrapSelectionWithStrings('', '', '', clipboard.readText()); } selectionRangePreviousLine() { @@ -1308,8 +1355,8 @@ class NoteTextComponent extends React.Component { const r = this.selectionRange_; const newRange = { - start: { row: r.start.row, column: r.start.column + string1.length}, - end: { row: r.end.row, column: r.end.column + string1.length}, + start: { row: r.start.row, column: r.start.column + string1.length }, + end: { row: r.end.row, column: r.end.column + string1.length }, }; if (replacementText) { @@ -1317,11 +1364,14 @@ class NoteTextComponent extends React.Component { newRange.end.column += diff; } - this.updateEditorWithDelay((editor) => { + this.updateEditorWithDelay(editor => { const range = this.selectionRange_; range.setStart(newRange.start.row, newRange.start.column); range.setEnd(newRange.end.row, newRange.end.column); - editor.getSession().getSelection().setSelectionRange(range, false); + editor + .getSession() + .getSelection() + .setSelectionRange(range, false); editor.focus(); }); } else { @@ -1340,15 +1390,21 @@ class NoteTextComponent extends React.Component { // BUG!! If replacementText contains newline characters, the logic // to select the new text will not work. - this.updateEditorWithDelay((editor) => { + this.updateEditorWithDelay(editor => { if (middleText && newRange) { const range = this.selectionRange_; range.setStart(newRange.start.row, newRange.start.column); range.setEnd(newRange.end.row, newRange.end.column); - editor.getSession().getSelection().setSelectionRange(range, false); + editor + .getSession() + .getSelection() + .setSelectionRange(range, false); } else { for (let i = 0; i < string1.length; i++) { - editor.getSession().getSelection().moveCursorRight(); + editor + .getSession() + .getSelection() + .moveCursorRight(); } } editor.focus(); @@ -1382,7 +1438,7 @@ class NoteTextComponent extends React.Component { addListItem(string1, string2 = '', defaultText = '') { const currentLine = this.selectionRangeCurrentLine(); - let newLine = '\n' + let newLine = '\n'; if (!currentLine) newLine = ''; this.wrapSelectionWithStrings(newLine + string1, string2, defaultText); } @@ -1399,7 +1455,7 @@ class NoteTextComponent extends React.Component { let bulletNumber = markdownUtils.olLineNumber(this.selectionRangeCurrentLine()); if (!bulletNumber) bulletNumber = markdownUtils.olLineNumber(this.selectionRangePreviousLine()); if (!bulletNumber) bulletNumber = 0; - this.addListItem((bulletNumber + 1) + '. ', '', _('List item')); + this.addListItem(bulletNumber + 1 + '. ', '', _('List item')); } commandTextHeading() { @@ -1419,28 +1475,41 @@ class NoteTextComponent extends React.Component { const note = this.state.note; if (!note) return; - const menu = new Menu() + const menu = new Menu(); - menu.append(new MenuItem({label: _('Attach file'), click: async () => { - return this.commandAttachFile(); - }})); + menu.append( + new MenuItem({ + label: _('Attach file'), + click: async () => { + return this.commandAttachFile(); + }, + }) + ); - menu.append(new MenuItem({label: _('Tags'), click: async () => { - return this.commandSetTags(); - }})); + menu.append( + new MenuItem({ + label: _('Tags'), + click: async () => { + return this.commandSetTags(); + }, + }) + ); - if (!!note.is_todo) { - menu.append(new MenuItem({label: _('Set alarm'), click: async () => { - return this.commandSetAlarm(); - }})); + if (note.is_todo) { + menu.append( + new MenuItem({ + label: _('Set alarm'), + click: async () => { + return this.commandSetAlarm(); + }, + }) + ); } menu.popup(bridge().window()); } createToolbarItems(note) { - const markupLanguage = note.markup_language; - const toolbarItems = []; if (note && this.state.folder && ['Search', 'Tag'].includes(this.props.notesParentType)) { toolbarItems.push({ @@ -1448,7 +1517,7 @@ class NoteTextComponent extends React.Component { iconName: 'fa-book', onClick: () => { this.props.dispatch({ - type: "FOLDER_AND_NOTE_SELECT", + type: 'FOLDER_AND_NOTE_SELECT', folderId: this.state.folder.id, noteId: note.id, }); @@ -1466,11 +1535,11 @@ class NoteTextComponent extends React.Component { const lastItem = this.props.historyNotes[this.props.historyNotes.length - 1]; this.props.dispatch({ - type: "FOLDER_AND_NOTE_SELECT", + type: 'FOLDER_AND_NOTE_SELECT', folderId: lastItem.parent_id, noteId: lastItem.id, historyNoteAction: 'pop', - }); + }); }, }); } @@ -1479,13 +1548,17 @@ class NoteTextComponent extends React.Component { toolbarItems.push({ tooltip: _('Bold'), iconName: 'fa-bold', - onClick: () => { return this.commandTextBold(); }, + onClick: () => { + return this.commandTextBold(); + }, }); toolbarItems.push({ tooltip: _('Italic'), iconName: 'fa-italic', - onClick: () => { return this.commandTextItalic(); }, + onClick: () => { + return this.commandTextItalic(); + }, }); toolbarItems.push({ @@ -1495,19 +1568,25 @@ class NoteTextComponent extends React.Component { toolbarItems.push({ tooltip: _('Hyperlink'), iconName: 'fa-link', - onClick: () => { return this.commandTextLink(); }, + onClick: () => { + return this.commandTextLink(); + }, }); toolbarItems.push({ tooltip: _('Code'), iconName: 'fa-code', - onClick: () => { return this.commandTextCode(); }, + onClick: () => { + return this.commandTextCode(); + }, }); toolbarItems.push({ tooltip: _('Attach file'), iconName: 'fa-paperclip', - onClick: () => { return this.commandAttachFile(); }, + onClick: () => { + return this.commandAttachFile(); + }, }); toolbarItems.push({ @@ -1517,37 +1596,49 @@ class NoteTextComponent extends React.Component { toolbarItems.push({ tooltip: _('Numbered List'), iconName: 'fa-list-ol', - onClick: () => { return this.commandTextListOl(); }, + onClick: () => { + return this.commandTextListOl(); + }, }); toolbarItems.push({ tooltip: _('Bulleted List'), iconName: 'fa-list-ul', - onClick: () => { return this.commandTextListUl(); }, + onClick: () => { + return this.commandTextListUl(); + }, }); toolbarItems.push({ tooltip: _('Checkbox'), iconName: 'fa-check-square', - onClick: () => { return this.commandTextCheckbox(); }, + onClick: () => { + return this.commandTextCheckbox(); + }, }); toolbarItems.push({ tooltip: _('Heading'), iconName: 'fa-header', - onClick: () => { return this.commandTextHeading(); }, + onClick: () => { + return this.commandTextHeading(); + }, }); toolbarItems.push({ tooltip: _('Horizontal Rule'), iconName: 'fa-ellipsis-h', - onClick: () => { return this.commandTextHorizontalRule(); }, + onClick: () => { + return this.commandTextHorizontalRule(); + }, }); toolbarItems.push({ tooltip: _('Insert Date Time'), iconName: 'fa-calendar-plus-o', - onClick: () => { return this.commandDateTime(); }, + onClick: () => { + return this.commandDateTime(); + }, }); toolbarItems.push({ @@ -1560,28 +1651,36 @@ class NoteTextComponent extends React.Component { tooltip: _('Click to stop external editing'), title: _('Watching...'), iconName: 'fa-external-link', - onClick: () => { return this.commandStopExternalEditing(); }, + onClick: () => { + return this.commandStopExternalEditing(); + }, }); } else { toolbarItems.push({ tooltip: _('Edit in external editor'), iconName: 'fa-external-link', - onClick: () => { return this.commandStartExternalEditing(); }, + onClick: () => { + return this.commandStartExternalEditing(); + }, }); } toolbarItems.push({ tooltip: _('Tags'), iconName: 'fa-tags', - onClick: () => { return this.commandSetTags(); }, + onClick: () => { + return this.commandSetTags(); + }, }); if (note.is_todo) { const item = { iconName: 'fa-clock-o', enabled: !note.todo_completed, - onClick: () => { return this.commandSetAlarm(); }, - } + onClick: () => { + return this.commandSetAlarm(); + }, + }; if (Note.needAlarm(note)) { item.title = time.formatMsToLocal(note.todo_due); } else { @@ -1590,7 +1689,6 @@ class NoteTextComponent extends React.Component { toolbarItems.push(item); } - toolbarItems.push({ tooltip: _('Note properties'), iconName: 'fa-info-circle', @@ -1602,7 +1700,9 @@ class NoteTextComponent extends React.Component { type: 'WINDOW_COMMAND', name: 'commandNoteProperties', noteId: n.id, - onRevisionLinkClick: () => { this.setState({ showRevisions: true}) }, + onRevisionLinkClick: () => { + this.setState({ showRevisions: true }); + }, }); }, }); @@ -1611,11 +1711,14 @@ class NoteTextComponent extends React.Component { } renderNoNotes(rootStyle) { - const emptyDivStyle = Object.assign({ - backgroundColor: 'black', - opacity: 0.1, - }, rootStyle); - return
+ const emptyDivStyle = Object.assign( + { + backgroundColor: 'black', + opacity: 0.1, + }, + rootStyle + ); + return
; } renderMultiNotes(rootStyle) { @@ -1627,7 +1730,7 @@ class NoteTextComponent extends React.Component { } else { item.click(); } - } + }; const menu = NoteListUtils.makeContextMenu(this.props.selectedNoteIds, { notes: this.props.notes, @@ -1645,11 +1748,11 @@ class NoteTextComponent extends React.Component { const item = menuItems[i]; if (!item.enabled) continue; - itemComps.push(); + itemComps.push( + + ); } rootStyle = Object.assign({}, rootStyle, { @@ -1658,11 +1761,11 @@ class NoteTextComponent extends React.Component { justifyContent: 'center', }); - return (
-
- {itemComps} + return ( +
+
{itemComps}
-
); + ); } render() { @@ -1676,12 +1779,15 @@ class NoteTextComponent extends React.Component { const borderWidth = 1; - const rootStyle = Object.assign({ - borderLeft: borderWidth + 'px solid ' + theme.dividerColor, - boxSizing: 'border-box', - paddingLeft: 10, - paddingRight: 0, - }, style); + const rootStyle = Object.assign( + { + borderLeft: borderWidth + 'px solid ' + theme.dividerColor, + boxSizing: 'border-box', + paddingLeft: 10, + paddingRight: 0, + }, + style + ); const innerWidth = rootStyle.width - rootStyle.paddingLeft - rootStyle.paddingRight - borderWidth; @@ -1692,14 +1798,15 @@ class NoteTextComponent extends React.Component { rootStyle.display = 'inline-flex'; return (
- +
); } if (this.props.selectedNoteIds.length > 1) { return this.renderMultiNotes(rootStyle); - } else if (!note || !!note.encryption_applied) { //|| (note && !this.props.newNote && this.props.noteId && note.id !== this.props.noteId)) { // note.id !== props.noteId is when the note has not been loaded yet, and the previous one is still in the state + } else if (!note || !!note.encryption_applied) { + //|| (note && !this.props.newNote && this.props.noteId && note.id !== this.props.noteId)) { // note.id !== props.noteId is when the note has not been loaded yet, and the previous one is still in the state return this.renderNoNotes(rootStyle); } @@ -1715,7 +1822,6 @@ class NoteTextComponent extends React.Component { }; const titleEditorStyle = { - display: 'flex', flex: 1, display: 'inline-block', paddingTop: 5, @@ -1730,12 +1836,11 @@ class NoteTextComponent extends React.Component { fontSize: theme.fontSize, }; - const toolbarStyle = { - }; + const toolbarStyle = {}; const tagStyle = { marginBottom: 10, - height: 30 + height: 30, }; const searchBarHeight = this.state.showLocalSearch ? 35 : 0; @@ -1749,7 +1854,7 @@ class NoteTextComponent extends React.Component { } bottomRowHeight -= searchBarHeight; - + const viewerStyle = { width: Math.floor(innerWidth / 2), height: bottomRowHeight, @@ -1802,7 +1907,7 @@ class NoteTextComponent extends React.Component { let html = this.state.bodyHtml; const htmlHasChanged = this.lastSetHtml_ !== html; - if (htmlHasChanged) { + if (htmlHasChanged) { let options = { cssFiles: this.state.lastRenderCssFiles, downloadResources: Setting.value('sync.resourceDownloadMode'), @@ -1815,11 +1920,13 @@ class NoteTextComponent extends React.Component { const markerOptions = {}; if (this.state.showLocalSearch) { - keywords = [{ - type: 'text', - value: this.state.localSearch.query, - accuracy: 'partially', - }] + keywords = [ + { + type: 'text', + value: this.state.localSearch.query, + accuracy: 'partially', + }, + ]; markerOptions.selectedIndex = this.state.localSearch.selectedIndex; markerOptions.separateWordSearch = false; } else { @@ -1840,102 +1947,102 @@ class NoteTextComponent extends React.Component { const toolbarItems = this.createToolbarItems(note); - const toolbar = + const toolbar = ; - const titleEditor = { this.titleField_ = elem; } } - style={titleEditorStyle} - value={note && note.title ? note.title : ''} - onChange={(event) => { this.title_changeText(event); }} - onKeyDown={this.titleField_keyDown} - placeholder={ this.props.newNote ? _('Creating new %s...', isTodo ? _('to-do') : _('note')) : '' } - /> + const titleEditor = ( + { + this.titleField_ = elem; + }} + style={titleEditorStyle} + value={note && note.title ? note.title : ''} + onChange={event => { + this.title_changeText(event); + }} + onKeyDown={this.titleField_keyDown} + placeholder={this.props.newNote ? _('Creating new %s...', isTodo ? _('to-do') : _('note')) : ''} + /> + ); - const tagList = !NOTE_TAG_BAR_FEATURE_ENABLED ? null : ; + const tagList = !NOTE_TAG_BAR_FEATURE_ENABLED ? null : ; - const titleBarMenuButton = { this.itemContextMenu() }} /> + const titleBarMenuButton = ( + { + this.itemContextMenu(); + }} + /> + ); - const titleBarDate = {time.formatMsToLocal(note.user_updated_time)} + const titleBarDate = {time.formatMsToLocal(note.user_updated_time)}; - const viewer = + const viewer = ; const editorRootStyle = Object.assign({}, editorStyle); delete editorRootStyle.width; delete editorRootStyle.height; delete editorRootStyle.fontSize; - const editor = { this.editor_scroll(); }} - ref={(elem) => { this.editor_ref(elem); } } - onChange={(body) => { this.aceEditor_change(body) }} - showPrintMargin={false} - onSelectionChange={this.aceEditor_selectionChange} - onFocus={this.aceEditor_focus} - readOnly={visiblePanes.indexOf('editor') < 0} - - // Disable warning: "Automatically scrolling cursor into view after - // selection change this will be disabled in the next version set - // editor.$blockScrolling = Infinity to disable this message" - editorProps={{$blockScrolling: Infinity}} - - // This is buggy (gets outside the container) - highlightActiveLine={false} - /> - - const noteSearchBarComp = !this.state.showLocalSearch ? null : ( - { + this.editor_scroll(); + }} + ref={elem => { + this.editor_ref(elem); + }} + onChange={body => { + this.aceEditor_change(body); + }} + showPrintMargin={false} + onSelectionChange={this.aceEditor_selectionChange} + onFocus={this.aceEditor_focus} + readOnly={visiblePanes.indexOf('editor') < 0} + // Disable warning: "Automatically scrolling cursor into view after + // selection change this will be disabled in the next version set + // editor.$blockScrolling = Infinity to disable this message" + editorProps={{ $blockScrolling: Infinity }} + // This is buggy (gets outside the container) + highlightActiveLine={false} /> ); + const noteSearchBarComp = !this.state.showLocalSearch ? null : ; + return (
- { titleEditor } - { titleBarDate } - { false ? titleBarMenuButton : null } + {titleEditor} + {titleBarDate} + {false ? titleBarMenuButton : null}
- { toolbar } - { tagList } - { editor } - { viewer } -
- { noteSearchBarComp } + {toolbar} + {tagList} + {editor} + {viewer} +
+ {noteSearchBarComp}
); } - } -const mapStateToProps = (state) => { +const mapStateToProps = state => { return { noteId: state.selectedNoteIds.length === 1 ? state.selectedNoteIds[0] : null, notes: state.notes, diff --git a/ElectronClient/app/gui/NoteTextViewer.jsx b/ElectronClient/app/gui/NoteTextViewer.jsx index bde80f4c8..e88e49c44 100644 --- a/ElectronClient/app/gui/NoteTextViewer.jsx +++ b/ElectronClient/app/gui/NoteTextViewer.jsx @@ -1,10 +1,7 @@ const React = require('react'); const { connect } = require('react-redux'); -const { themeStyle } = require('../theme.js'); -const { _ } = require('lib/locale.js'); class NoteTextViewerComponent extends React.Component { - constructor() { super(); @@ -49,7 +46,7 @@ class NoteTextViewerComponent extends React.Component { let isAlreadyReady = false; try { - isAlreadyReady = !this.webviewRef_.current.isLoading() + isAlreadyReady = !this.webviewRef_.current.isLoading(); } catch (error) { // Ignore - it means the view has not started loading, and the DOM ready event has not been emitted yet // Error is "The WebView must be attached to the DOM and the dom-ready event emitted before this method can be called." @@ -111,14 +108,14 @@ class NoteTextViewerComponent extends React.Component { return this.webviewRef_.current.getWebContents().printToPDF(options, callback); } - print(options = {}) { + print() { // In Electron 4x, print is broken so need to use this hack: // https://github.com/electron/electron/issues/16219#issuecomment-451454948 // Note that this is not a perfect workaround since it means the options are ignored // In particular it means that background images and colours won't be printed (printBackground property will be ignored) // return this.webviewRef_.current.getWebContents().print({}); - return this.webviewRef_.current.getWebContents().executeJavaScript("window.print()") + return this.webviewRef_.current.getWebContents().executeJavaScript('window.print()'); } openDevTools() { @@ -138,23 +135,21 @@ class NoteTextViewerComponent extends React.Component { // ---------------------------------------------------------------- render() { - return + return ; } - } -const mapStateToProps = (state) => { +const mapStateToProps = state => { return { theme: state.settings.theme, }; }; -const NoteTextViewer = connect(mapStateToProps, null, null, { withRef: true })(NoteTextViewerComponent); +const NoteTextViewer = connect( + mapStateToProps, + null, + null, + { withRef: true } +)(NoteTextViewerComponent); -module.exports = NoteTextViewer; \ No newline at end of file +module.exports = NoteTextViewer; diff --git a/ElectronClient/app/gui/OneDriveLoginScreen.jsx b/ElectronClient/app/gui/OneDriveLoginScreen.jsx index faf94dbc2..e06096fa3 100644 --- a/ElectronClient/app/gui/OneDriveLoginScreen.jsx +++ b/ElectronClient/app/gui/OneDriveLoginScreen.jsx @@ -7,7 +7,6 @@ const { themeStyle } = require('../theme.js'); const { _ } = require('lib/locale.js'); class OneDriveLoginScreenComponent extends React.Component { - constructor() { super(); this.webview_ = null; @@ -36,8 +35,8 @@ class OneDriveLoginScreenComponent extends React.Component { webview_domReady() { this.setState({ webviewReady: true }); - - this.webview_.addEventListener('did-navigate', async (event) => { + + this.webview_.addEventListener('did-navigate', async event => { const url = event.url; if (this.authCode_) return; @@ -50,11 +49,14 @@ class OneDriveLoginScreenComponent extends React.Component { this.authCode_ = parsedUrl.query.code; try { - await reg.syncTarget().api().execTokenRequest(this.authCode_, this.redirectUrl(), true); + await reg + .syncTarget() + .api() + .execTokenRequest(this.authCode_, this.redirectUrl(), true); this.props.dispatch({ type: 'NAV_BACK' }); reg.scheduleSync(0); } catch (error) { - bridge().showErrorMessageBox('Could not login to OneDrive. Please try again.\n\n' + error.message + "\n\n" + url.match(/.{1,64}/g).join('\n')); + bridge().showErrorMessageBox('Could not login to OneDrive. Please try again.\n\n' + error.message + '\n\n' + url.match(/.{1,64}/g).join('\n')); } this.authCode_ = null; @@ -62,11 +64,17 @@ class OneDriveLoginScreenComponent extends React.Component { } startUrl() { - return reg.syncTarget().api().authCodeUrl(this.redirectUrl()); + return reg + .syncTarget() + .api() + .authCodeUrl(this.redirectUrl()); } redirectUrl() { - return reg.syncTarget().api().nativeClientRedirectUrl(); + return reg + .syncTarget() + .api() + .nativeClientRedirectUrl(); } render() { @@ -94,14 +102,13 @@ class OneDriveLoginScreenComponent extends React.Component { return (
- this.webview_ = elem} /> + (this.webview_ = elem)} />
); } - } -const mapStateToProps = (state) => { +const mapStateToProps = state => { return { theme: state.settings.theme, }; diff --git a/ElectronClient/app/gui/PromptDialog.jsx b/ElectronClient/app/gui/PromptDialog.jsx index 17dbcca43..19b1e7a2d 100644 --- a/ElectronClient/app/gui/PromptDialog.jsx +++ b/ElectronClient/app/gui/PromptDialog.jsx @@ -1,7 +1,5 @@ const React = require('react'); -const { connect } = require('react-redux'); const { _ } = require('lib/locale.js'); -const moment = require('moment'); const { themeStyle } = require('../theme.js'); const { time } = require('lib/time-utils.js'); const Datetime = require('react-datetime'); @@ -10,7 +8,6 @@ const Select = require('react-select').default; const makeAnimated = require('react-select/lib/animated').default; class PromptDialog extends React.Component { - constructor() { super(); @@ -103,51 +100,58 @@ class PromptDialog extends React.Component { }; this.styles_.select = { - control: (provided) => (Object.assign(provided, { - minWidth: width * 0.2, - maxWidth: width * 0.5, - })), - input: (provided) => (Object.assign(provided, { - minWidth: '20px', - color: theme.color, - })), - menu: (provided) => (Object.assign(provided, { - color: theme.color, - fontFamily: theme.fontFamily, - backgroundColor: theme.backgroundColor, - })), - option: (provided) => (Object.assign(provided, { - color: theme.color, - fontFamily: theme.fontFamily, - })), - multiValueLabel: (provided) => (Object.assign(provided, { - fontFamily: theme.fontFamily, - })), - multiValueRemove: (provided) => (Object.assign(provided, { - color: theme.color, - })), + control: provided => + Object.assign(provided, { + minWidth: width * 0.2, + maxWidth: width * 0.5, + }), + input: provided => + Object.assign(provided, { + minWidth: '20px', + color: theme.color, + }), + menu: provided => + Object.assign(provided, { + color: theme.color, + fontFamily: theme.fontFamily, + backgroundColor: theme.backgroundColor, + }), + option: provided => + Object.assign(provided, { + color: theme.color, + fontFamily: theme.fontFamily, + }), + multiValueLabel: provided => + Object.assign(provided, { + fontFamily: theme.fontFamily, + }), + multiValueRemove: provided => + Object.assign(provided, { + color: theme.color, + }), }; - this.styles_.selectTheme = (tagTheme) => (Object.assign(tagTheme, { - borderRadius: 2, - colors: Object.assign(tagTheme.colors, { - primary: theme.raisedBackgroundColor, - primary25: theme.raisedBackgroundColor, - neutral0: theme.backgroundColor, - neutral5: theme.backgroundColor, - neutral10: theme.raisedBackgroundColor, - neutral20: theme.raisedBackgroundColor, - neutral30: theme.raisedBackgroundColor, - neutral40: theme.color, - neutral50: theme.color, - neutral60: theme.color, - neutral70: theme.color, - neutral80: theme.color, - neutral90: theme.color, - danger: theme.backgroundColor, - dangerLight: theme.colorError2, - }), - })); + this.styles_.selectTheme = tagTheme => + Object.assign(tagTheme, { + borderRadius: 2, + colors: Object.assign(tagTheme.colors, { + primary: theme.raisedBackgroundColor, + primary25: theme.raisedBackgroundColor, + neutral0: theme.backgroundColor, + neutral5: theme.backgroundColor, + neutral10: theme.raisedBackgroundColor, + neutral20: theme.raisedBackgroundColor, + neutral30: theme.raisedBackgroundColor, + neutral40: theme.color, + neutral50: theme.color, + neutral60: theme.color, + neutral70: theme.color, + neutral80: theme.color, + neutral90: theme.color, + danger: theme.backgroundColor, + dangerLight: theme.colorError2, + }), + }); this.styles_.desc = Object.assign({}, theme.textStyle, { marginTop: 10, @@ -173,11 +177,11 @@ class PromptDialog extends React.Component { this.props.onClose(accept ? outputAnswer : null, buttonType); } this.setState({ visible: false, answer: '' }); - } + }; - const onChange = (event) => { + const onChange = event => { this.setState({ answer: event.target.value }); - } + }; // const anythingToDate = (o) => { // if (o && o.toDate) return o.toDate(); @@ -188,16 +192,16 @@ class PromptDialog extends React.Component { // return m.isValid() ? m.toDate() : null; // } - const onDateTimeChange = (momentObject) => { + const onDateTimeChange = momentObject => { this.setState({ answer: momentObject }); - } + }; - const onSelectChange = (newValue) => { + const onSelectChange = newValue => { this.setState({ answer: newValue }); this.focusInput_ = true; - } + }; - const onKeyDown = (event) => { + const onKeyDown = event => { if (event.key === 'Enter') { if (this.props.inputType !== 'tags' && this.props.inputType !== 'dropdown') { onClose(true); @@ -208,80 +212,55 @@ class PromptDialog extends React.Component { } else if (event.key === 'Escape') { onClose(false); } - } + }; const descComp = this.props.description ?
{this.props.description}
: null; let inputComp = null; if (this.props.inputType === 'datetime') { - inputComp = onDateTimeChange(momentObject)} - /> + inputComp = onDateTimeChange(momentObject)} />; } else if (this.props.inputType === 'tags') { - inputComp = onKeyDown(event)} - /> + inputComp = onKeyDown(event)} />; } else if (this.props.inputType === 'dropdown') { - inputComp = onKeyDown(event)} />; } else { - inputComp = onChange(event)} - onKeyDown={(event) => onKeyDown(event)} - /> + inputComp = onChange(event)} onKeyDown={event => onKeyDown(event)} />; } const buttonComps = []; - if (buttonTypes.indexOf('ok') >= 0) buttonComps.push(); - if (buttonTypes.indexOf('cancel') >= 0) buttonComps.push(); - if (buttonTypes.indexOf('clear') >= 0) buttonComps.push(); + if (buttonTypes.indexOf('ok') >= 0) + buttonComps.push( + + ); + if (buttonTypes.indexOf('cancel') >= 0) + buttonComps.push( + + ); + if (buttonTypes.indexOf('clear') >= 0) + buttonComps.push( + + ); return (
-
+
{inputComp} {descComp}
-
- {buttonComps} -
+
{buttonComps}
); } - } module.exports = { PromptDialog }; diff --git a/ElectronClient/app/gui/Root.jsx b/ElectronClient/app/gui/Root.jsx index 57f7c490e..f6d9a340d 100644 --- a/ElectronClient/app/gui/Root.jsx +++ b/ElectronClient/app/gui/Root.jsx @@ -1,6 +1,5 @@ const React = require('react'); const { render } = require('react-dom'); -const { createStore } = require('redux'); const { connect, Provider } = require('react-redux'); const { _ } = require('lib/locale.js'); @@ -21,20 +20,22 @@ const { app } = require('../app'); const { bridge } = require('electron').remote.require('./bridge'); -async function initialize(dispatch) { +async function initialize() { this.wcsTimeoutId_ = null; - bridge().window().on('resize', function() { - if (this.wcsTimeoutId_) clearTimeout(this.wcsTimeoutId_); + bridge() + .window() + .on('resize', function() { + if (this.wcsTimeoutId_) clearTimeout(this.wcsTimeoutId_); - this.wcsTimeoutId_ = setTimeout(() => { - store.dispatch({ - type: 'WINDOW_CONTENT_SIZE_SET', - size: bridge().windowContentSize(), - }); - this.wcsTimeoutId_ = null; - }, 10); - }); + this.wcsTimeoutId_ = setTimeout(() => { + store.dispatch({ + type: 'WINDOW_CONTENT_SIZE_SET', + size: bridge().windowContentSize(), + }); + this.wcsTimeoutId_ = null; + }, 10); + }); // Need to dispatch this to make sure the components are // displayed at the right size. The windowContentSize is @@ -52,12 +53,11 @@ async function initialize(dispatch) { store.dispatch({ type: 'SIDEBAR_VISIBILITY_SET', - visibility: Setting.value('sidebarVisibility') + visibility: Setting.value('sidebarVisibility'), }); } class RootComponent extends React.Component { - async componentDidMount() { if (this.props.appState == 'starting') { this.props.dispatch({ @@ -93,14 +93,11 @@ class RootComponent extends React.Component { ClipperConfig: { screen: ClipperConfigScreen, title: () => _('Clipper Options') }, }; - return ( - - ); + return ; } - } -const mapStateToProps = (state) => { +const mapStateToProps = state => { return { size: state.windowContentSize, appState: state.appState, @@ -116,4 +113,4 @@ render( , document.getElementById('react-root') -) \ No newline at end of file +); diff --git a/ElectronClient/app/gui/SideBar.jsx b/ElectronClient/app/gui/SideBar.jsx index 02a883358..f8247a600 100644 --- a/ElectronClient/app/gui/SideBar.jsx +++ b/ElectronClient/app/gui/SideBar.jsx @@ -1,28 +1,25 @@ -const React = require("react"); -const { connect } = require("react-redux"); -const shared = require("lib/components/shared/side-menu-shared.js"); -const { Synchronizer } = require("lib/synchronizer.js"); -const BaseModel = require("lib/BaseModel.js"); +const React = require('react'); +const { connect } = require('react-redux'); +const shared = require('lib/components/shared/side-menu-shared.js'); +const { Synchronizer } = require('lib/synchronizer.js'); +const BaseModel = require('lib/BaseModel.js'); const Setting = require('lib/models/Setting.js'); -const Folder = require("lib/models/Folder.js"); -const Note = require("lib/models/Note.js"); -const Tag = require("lib/models/Tag.js"); -const { _ } = require("lib/locale.js"); -const { themeStyle } = require("../theme.js"); -const { bridge } = require("electron").remote.require("./bridge"); +const Folder = require('lib/models/Folder.js'); +const Note = require('lib/models/Note.js'); +const Tag = require('lib/models/Tag.js'); +const { _ } = require('lib/locale.js'); +const { themeStyle } = require('../theme.js'); +const { bridge } = require('electron').remote.require('./bridge'); const Menu = bridge().Menu; const MenuItem = bridge().MenuItem; -const InteropServiceHelper = require("../InteropServiceHelper.js"); +const InteropServiceHelper = require('../InteropServiceHelper.js'); const { substrWithEllipsis } = require('lib/string-utils'); -const { shim } = require('lib/shim'); class SideBarComponent extends React.Component { - - constructor() { super(); - this.onFolderDragStart_ = (event) => { + this.onFolderDragStart_ = event => { const folderId = event.currentTarget.getAttribute('folderid'); if (!folderId) return; @@ -31,12 +28,12 @@ class SideBarComponent extends React.Component { event.dataTransfer.setData('text/x-jop-folder-ids', JSON.stringify([folderId])); }; - this.onFolderDragOver_ = (event) => { - if (event.dataTransfer.types.indexOf("text/x-jop-note-ids") >= 0) event.preventDefault(); - if (event.dataTransfer.types.indexOf("text/x-jop-folder-ids") >= 0) event.preventDefault(); + this.onFolderDragOver_ = event => { + if (event.dataTransfer.types.indexOf('text/x-jop-note-ids') >= 0) event.preventDefault(); + if (event.dataTransfer.types.indexOf('text/x-jop-folder-ids') >= 0) event.preventDefault(); }; - this.onFolderDrop_ = async (event) => { + this.onFolderDrop_ = async event => { const folderId = event.currentTarget.getAttribute('folderid'); const dt = event.dataTransfer; if (!dt) return; @@ -45,41 +42,41 @@ class SideBarComponent extends React.Component { // to put the dropped folder at the root. But for notes, folderId needs to always be defined // since there's no such thing as a root note. - if (dt.types.indexOf("text/x-jop-note-ids") >= 0) { + if (dt.types.indexOf('text/x-jop-note-ids') >= 0) { event.preventDefault(); if (!folderId) return; - const noteIds = JSON.parse(dt.getData("text/x-jop-note-ids")); + const noteIds = JSON.parse(dt.getData('text/x-jop-note-ids')); for (let i = 0; i < noteIds.length; i++) { await Note.moveToFolder(noteIds[i], folderId); } - } else if (dt.types.indexOf("text/x-jop-folder-ids") >= 0) { + } else if (dt.types.indexOf('text/x-jop-folder-ids') >= 0) { event.preventDefault(); - const folderIds = JSON.parse(dt.getData("text/x-jop-folder-ids")); + const folderIds = JSON.parse(dt.getData('text/x-jop-folder-ids')); for (let i = 0; i < folderIds.length; i++) { await Folder.moveToFolder(folderIds[i], folderId); } } }; - this.onTagDrop_ = async (event) => { + this.onTagDrop_ = async event => { const tagId = event.currentTarget.getAttribute('tagid'); const dt = event.dataTransfer; if (!dt) return; - if (dt.types.indexOf("text/x-jop-note-ids") >= 0) { + if (dt.types.indexOf('text/x-jop-note-ids') >= 0) { event.preventDefault(); - const noteIds = JSON.parse(dt.getData("text/x-jop-note-ids")); + const noteIds = JSON.parse(dt.getData('text/x-jop-note-ids')); for (let i = 0; i < noteIds.length; i++) { await Tag.addNote(tagId, noteIds[i]); } } - } + }; - this.onFolderToggleClick_ = async (event) => { + this.onFolderToggleClick_ = async event => { const folderId = event.currentTarget.getAttribute('folderid'); this.props.dispatch({ @@ -99,7 +96,7 @@ class SideBarComponent extends React.Component { this.state = { tagHeaderIsExpanded: Setting.value('tagHeaderIsExpanded'), - folderHeaderIsExpanded: Setting.value('folderHeaderIsExpanded') + folderHeaderIsExpanded: Setting.value('folderHeaderIsExpanded'), }; } @@ -113,23 +110,23 @@ class SideBarComponent extends React.Component { backgroundColor: theme.backgroundColor2, }, listItemContainer: { - boxSizing: "border-box", + boxSizing: 'border-box', height: itemHeight, // paddingLeft: 14, - display: "flex", - alignItems: "stretch", + display: 'flex', + alignItems: 'stretch', // Allow 3 levels of color depth backgroundColor: theme.depthColor.replace('OPACITY', Math.min(depth * 0.1, 0.3)), }, listItem: { fontFamily: theme.fontFamily, fontSize: theme.fontSize, - textDecoration: "none", + textDecoration: 'none', color: theme.color2, - cursor: "default", + cursor: 'default', opacity: 0.8, - whiteSpace: "nowrap", - display: "flex", + whiteSpace: 'nowrap', + display: 'flex', flex: 1, alignItems: 'center', }, @@ -138,60 +135,60 @@ class SideBarComponent extends React.Component { }, listItemExpandIcon: { color: theme.color2, - cursor: "default", + cursor: 'default', opacity: 0.8, // fontFamily: theme.fontFamily, fontSize: theme.fontSize, - textDecoration: "none", + textDecoration: 'none', paddingRight: 5, - display: "flex", + display: 'flex', alignItems: 'center', }, conflictFolder: { color: theme.colorError2, - fontWeight: "bold", + fontWeight: 'bold', }, header: { height: itemHeight * 1.8, fontFamily: theme.fontFamily, fontSize: theme.fontSize * 1.16, - textDecoration: "none", - boxSizing: "border-box", + textDecoration: 'none', + boxSizing: 'border-box', color: theme.color2, paddingLeft: 8, - display: "flex", - alignItems: "center", + display: 'flex', + alignItems: 'center', }, button: { padding: 6, fontFamily: theme.fontFamily, fontSize: theme.fontSize, - textDecoration: "none", - boxSizing: "border-box", + textDecoration: 'none', + boxSizing: 'border-box', color: theme.color2, - display: "flex", - alignItems: "center", - justifyContent: "center", - border: "1px solid rgba(255,255,255,0.2)", + display: 'flex', + alignItems: 'center', + justifyContent: 'center', + border: '1px solid rgba(255,255,255,0.2)', marginTop: 10, marginLeft: 5, marginRight: 5, - cursor: "default", + cursor: 'default', }, syncReport: { fontFamily: theme.fontFamily, fontSize: Math.round(theme.fontSize * 0.9), color: theme.color2, opacity: 0.5, - display: "flex", - alignItems: "left", - justifyContent: "top", - flexDirection: "column", + display: 'flex', + alignItems: 'left', + justifyContent: 'top', + flexDirection: 'column', marginTop: 10, marginLeft: 5, marginRight: 5, marginBottom: 10, - wordWrap: "break-word", + wordWrap: 'break-word', }, }; @@ -236,42 +233,40 @@ class SideBarComponent extends React.Component { } } - componentDidUpdate(prevProps) { - if (shim.isLinux()) { - // For some reason, the UI seems to sleep in some Linux distro during - // sync. Cannot find the reason for it and cannot replicate, so here - // as a test force the update at regular intervals. - // https://github.com/laurent22/joplin/issues/312#issuecomment-429472193 - if (!prevProps.syncStarted && this.props.syncStarted) { - this.clearForceUpdateDuringSync(); - - this.forceUpdateDuringSyncIID_ = setInterval(() => { - this.forceUpdate(); - }, 2000); - } - - if (prevProps.syncStarted && !this.props.syncStarted) this.clearForceUpdateDuringSync(); - } - } - componentWillUnmount() { this.clearForceUpdateDuringSync(); } - componentDidUpdate(prevProps, prevState, snapshot) { + componentDidUpdate(prevProps) { if (prevProps.windowCommand !== this.props.windowCommand) { this.doCommand(this.props.windowCommand); } + + // if (shim.isLinux()) { + // // For some reason, the UI seems to sleep in some Linux distro during + // // sync. Cannot find the reason for it and cannot replicate, so here + // // as a test force the update at regular intervals. + // // https://github.com/laurent22/joplin/issues/312#issuecomment-429472193 + // if (!prevProps.syncStarted && this.props.syncStarted) { + // this.clearForceUpdateDuringSync(); + + // this.forceUpdateDuringSyncIID_ = setInterval(() => { + // this.forceUpdate(); + // }, 2000); + // } + + // if (prevProps.syncStarted && !this.props.syncStarted) this.clearForceUpdateDuringSync(); + // } } async itemContextMenu(event) { - const itemId = event.target.getAttribute("data-id"); + const itemId = event.target.getAttribute('data-id'); if (itemId === Folder.conflictFolderId()) return; - const itemType = Number(event.target.getAttribute("data-type")); - if (!itemId || !itemType) throw new Error("No data on element"); + const itemType = Number(event.target.getAttribute('data-type')); + if (!itemId || !itemType) throw new Error('No data on element'); - let deleteMessage = ""; + let deleteMessage = ''; if (itemType === BaseModel.TYPE_FOLDER) { const folder = await Folder.load(itemId); deleteMessage = _('Delete notebook "%s"?\n\nAll notes and sub-notebooks within this notebook will also be deleted.', substrWithEllipsis(folder.title, 0, 32)); @@ -279,7 +274,7 @@ class SideBarComponent extends React.Component { const tag = await Tag.load(itemId); deleteMessage = _('Remove tag "%s" from all notes?', substrWithEllipsis(tag.title, 0, 32)); } else if (itemType === BaseModel.TYPE_SEARCH) { - deleteMessage = _("Remove this search from the sidebar?"); + deleteMessage = _('Remove this search from the sidebar?'); } const menu = new Menu(); @@ -291,7 +286,7 @@ class SideBarComponent extends React.Component { menu.append( new MenuItem({ - label: _("Delete"), + label: _('Delete'), click: async () => { const ok = bridge().showConfirmMessageBox(deleteMessage); if (!ok) return; @@ -302,7 +297,7 @@ class SideBarComponent extends React.Component { await Tag.untagAll(itemId); } else if (itemType === BaseModel.TYPE_SEARCH) { this.props.dispatch({ - type: "SEARCH_DELETE", + type: 'SEARCH_DELETE', id: itemId, }); } @@ -313,11 +308,11 @@ class SideBarComponent extends React.Component { if (itemType === BaseModel.TYPE_FOLDER && !item.encryption_applied) { menu.append( new MenuItem({ - label: _("Rename"), + label: _('Rename'), click: async () => { this.props.dispatch({ - type: "WINDOW_COMMAND", - name: "renameFolder", + type: 'WINDOW_COMMAND', + name: 'renameFolder', id: itemId, }); }, @@ -337,9 +332,9 @@ class SideBarComponent extends React.Component { // }) // ); - menu.append(new MenuItem({ type: "separator" })); + menu.append(new MenuItem({ type: 'separator' })); - const InteropService = require("lib/services/InteropService.js"); + const InteropService = require('lib/services/InteropService.js'); const exportMenu = new Menu(); const ioService = new InteropService(); @@ -348,14 +343,19 @@ class SideBarComponent extends React.Component { const module = ioModules[i]; if (module.type !== 'exporter') continue; - exportMenu.append(new MenuItem({ label: module.fullLabel() , click: async () => { - await InteropServiceHelper.export(this.props.dispatch.bind(this), module, { sourceFolderIds: [itemId] }); - }})); + exportMenu.append( + new MenuItem({ + label: module.fullLabel(), + click: async () => { + await InteropServiceHelper.export(this.props.dispatch.bind(this), module, { sourceFolderIds: [itemId] }); + }, + }) + ); } menu.append( new MenuItem({ - label: _("Export"), + label: _('Export'), submenu: exportMenu, }) ); @@ -367,9 +367,9 @@ class SideBarComponent extends React.Component { label: _('Rename'), click: async () => { this.props.dispatch({ - type: "WINDOW_COMMAND", - name: "renameTag", - id: itemId + type: 'WINDOW_COMMAND', + name: 'renameTag', + id: itemId, }); }, }) @@ -381,14 +381,14 @@ class SideBarComponent extends React.Component { folderItem_click(folder) { this.props.dispatch({ - type: "FOLDER_SELECT", + type: 'FOLDER_SELECT', id: folder ? folder.id : null, }); } tagItem_click(tag) { this.props.dispatch({ - type: "TAG_SELECT", + type: 'TAG_SELECT', id: tag ? tag.id : null, }); } @@ -405,8 +405,6 @@ class SideBarComponent extends React.Component { } anchorItemRef(type, id) { - let refs = null; - if (!this.anchorItemRefs[type]) this.anchorItemRefs[type] = {}; if (this.anchorItemRefs[type][id]) return this.anchorItemRefs[type][id]; this.anchorItemRefs[type][id] = React.createRef(); @@ -426,17 +424,23 @@ class SideBarComponent extends React.Component { let expandIconStyle = { visibility: hasChildren ? 'visible' : 'hidden', paddingLeft: 8 + depth * 10, - } + }; const iconName = this.props.collapsedFolderIds.indexOf(folder.id) >= 0 ? 'fa-plus-square' : 'fa-minus-square'; - const expandIcon = - const expandLink = hasChildren ? {expandIcon} : {expandIcon} + const expandIcon = ; + const expandLink = hasChildren ? ( + + {expandIcon} + + ) : ( + {expandIcon} + ); const anchorRef = this.anchorItemRef('folder', folder.id); return (
- { expandLink } + {expandLink} ; + return
; } makeHeader(key, label, iconName, extraProps = {}) { const style = this.style().header; - const icon = ; + const icon = ; if (extraProps.toggleblock || extraProps.onClick) { - style.cursor = "pointer"; + style.cursor = 'pointer'; } let headerClick = extraProps.onClick || null; @@ -525,22 +529,27 @@ class SideBarComponent extends React.Component { const toggleKey = `${key}IsExpanded`; if (extraProps.toggleblock) { let isExpanded = this.state[toggleKey]; - toggleIcon = ; + toggleIcon = ; } const ref = this.anchorItemRef('headers', key); return ( -
{ - // if a custom click event is attached, trigger that. +
{ + // if a custom click event is attached, trigger that. if (headerClick) { - headerClick(key, event); + headerClick(key, event); } - this.onHeaderClick_(key, event); - }}> + this.onHeaderClick_(key, event); + }} + > {icon} - {label} + {label} {toggleIcon}
); @@ -562,7 +571,8 @@ class SideBarComponent extends React.Component { const keyCode = event.keyCode; const selectedItem = this.selectedItem(); - if (keyCode === 40 || keyCode === 38) { // DOWN / UP + if (keyCode === 40 || keyCode === 38) { + // DOWN / UP event.preventDefault(); const focusItems = []; @@ -603,7 +613,8 @@ class SideBarComponent extends React.Component { focusItem.ref.current.focus(); } - if (keyCode === 9) { // TAB + if (keyCode === 9) { + // TAB event.preventDefault(); if (event.shiftKey) { @@ -621,7 +632,8 @@ class SideBarComponent extends React.Component { } } - if (selectedItem && selectedItem.type === 'folder' && keyCode === 32) { // SPACE + if (selectedItem && selectedItem.type === 'folder' && keyCode === 32) { + // SPACE event.preventDefault(); this.props.dispatch({ @@ -631,28 +643,28 @@ class SideBarComponent extends React.Component { } } - onHeaderClick_(key, event) { + onHeaderClick_(key, event) { const currentHeader = event.currentTarget; const toggleBlock = +currentHeader.getAttribute('toggleblock'); if (toggleBlock) { - const toggleKey = `${key}IsExpanded`; - const isExpanded = this.state[toggleKey]; - this.setState({ [toggleKey]: !isExpanded }); - Setting.setValue(toggleKey, !isExpanded); + const toggleKey = `${key}IsExpanded`; + const isExpanded = this.state[toggleKey]; + this.setState({ [toggleKey]: !isExpanded }); + Setting.setValue(toggleKey, !isExpanded); } } synchronizeButton(type) { const style = Object.assign({}, this.style().button, { marginBottom: 5 }); - const iconName = "fa-refresh"; - const label = type === "sync" ? _("Synchronise") : _("Cancel"); + const iconName = 'fa-refresh'; + const label = type === 'sync' ? _('Synchronise') : _('Cancel'); let iconStyle = { fontSize: style.fontSize, marginRight: 5 }; - if(type !== 'sync'){ + if (type !== 'sync') { iconStyle.animation = 'icon-infinite-rotation 1s linear infinite'; } - const icon = ; + const icon = ; return (
- {folderItems}
); + items.push( +
+ {folderItems} +
+ ); } - items.push(this.makeHeader("tagHeader", _("Tags"), "fa-tags", { - toggleblock: 1 - })); + items.push( + this.makeHeader('tagHeader', _('Tags'), 'fa-tags', { + toggleblock: 1, + }) + ); if (this.props.tags.length) { const result = shared.renderTags(this.props, this.tagItem.bind(this)); @@ -703,7 +721,7 @@ class SideBarComponent extends React.Component { this.tagItemsOrder_ = result.order; items.push( -
+
{tagItems}
); @@ -725,27 +743,24 @@ class SideBarComponent extends React.Component { const syncReportText = []; for (let i = 0; i < lines.length; i++) { syncReportText.push( -
+
{lines[i]}
); } - const syncButton = this.synchronizeButton(this.props.syncStarted ? "cancel" : "sync"); + const syncButton = this.synchronizeButton(this.props.syncStarted ? 'cancel' : 'sync'); const syncReportComp = !syncReportText.length ? null : (
- {syncReportText} -
- ); + {syncReportText} +
+ ); return (
- -
- {items} -
-
+
{items}
+
{syncReportComp} {syncButton}
diff --git a/ElectronClient/app/gui/StatusScreen.jsx b/ElectronClient/app/gui/StatusScreen.jsx index 88e85ec9b..4a592b817 100644 --- a/ElectronClient/app/gui/StatusScreen.jsx +++ b/ElectronClient/app/gui/StatusScreen.jsx @@ -1,6 +1,5 @@ const React = require('react'); const { connect } = require('react-redux'); -const { reg } = require('lib/registry.js'); const Setting = require('lib/models/Setting.js'); const { bridge } = require('electron').remote.require('./bridge'); const { Header } = require('./Header.min.js'); @@ -10,7 +9,6 @@ const { ReportService } = require('lib/services/report.js'); const fs = require('fs-extra'); class StatusScreenComponent extends React.Component { - constructor() { super(); this.state = { @@ -29,7 +27,7 @@ class StatusScreenComponent extends React.Component { } async exportDebugReportClick() { - const filename = 'syncReport-' + (new Date()).getTime() + '.csv'; + const filename = 'syncReport-' + new Date().getTime() + '.csv'; const filePath = bridge().showSaveDialog({ title: _('Please select where the sync status should be exported to'), @@ -48,7 +46,7 @@ class StatusScreenComponent extends React.Component { const style = this.props.style; const headerStyle = Object.assign({}, theme.headerStyle, { width: style.width }); - const retryStyle = Object.assign({}, theme.urlStyle, {marginLeft: 5}); + const retryStyle = Object.assign({}, theme.urlStyle, { marginLeft: 5 }); const containerPadding = 10; @@ -58,7 +56,11 @@ class StatusScreenComponent extends React.Component { }); function renderSectionTitleHtml(key, title) { - return

{title}

+ return ( +

+ {title} +

+ ); } const renderSectionHtml = (key, section) => { @@ -77,9 +79,13 @@ class StatusScreenComponent extends React.Component { const onClick = async () => { await item.retryHandler(); this.resfreshScreen(); - } + }; - retryLink =
{_('Retry')}; + retryLink = ( + + {_('Retry')} + + ); } text = item.text; } else { @@ -88,28 +94,18 @@ class StatusScreenComponent extends React.Component { if (!text) text = '\xa0'; - itemsHtml.push(
{text}{retryLink}
); + itemsHtml.push( +
+ {text} + {retryLink} +
+ ); } - return ( -
- {itemsHtml} -
- ); - } + return
{itemsHtml}
; + }; function renderBodyHtml(report) { - let output = []; - let baseStyle = { - paddingLeft: 6, - paddingRight: 6, - paddingTop: 2, - paddingBottom: 2, - flex: 0, - color: theme.color, - fontSize: theme.fontSize, - }; - let sectionsHtml = []; for (let i = 0; i < report.length; i++) { @@ -118,29 +114,26 @@ class StatusScreenComponent extends React.Component { sectionsHtml.push(renderSectionHtml(i, section)); } - return ( -
- {sectionsHtml} -
- ); + return
{sectionsHtml}
; } let body = renderBodyHtml(this.state.report); - + return ( ); } - } -const mapStateToProps = (state) => { +const mapStateToProps = state => { return { theme: state.settings.theme, settings: state.settings, diff --git a/ElectronClient/app/gui/TagItem.jsx b/ElectronClient/app/gui/TagItem.jsx index a321cdef5..ebad306d9 100644 --- a/ElectronClient/app/gui/TagItem.jsx +++ b/ElectronClient/app/gui/TagItem.jsx @@ -12,7 +12,7 @@ class TagItemComponent extends React.Component { } } -const mapStateToProps = (state) => { +const mapStateToProps = state => { return { theme: state.settings.theme }; }; diff --git a/ElectronClient/app/gui/TagList.jsx b/ElectronClient/app/gui/TagList.jsx index 6475c2c48..78bca0310 100644 --- a/ElectronClient/app/gui/TagList.jsx +++ b/ElectronClient/app/gui/TagList.jsx @@ -10,7 +10,7 @@ class TagListComponent extends React.Component { const tags = this.props.items; style.display = 'flex'; - style.flexDirection = 'row'; + style.flexDirection = 'row'; style.borderBottom = '1px solid ' + theme.dividerColor; style.boxSizing = 'border-box'; style.fontSize = theme.fontSize; @@ -18,12 +18,14 @@ class TagListComponent extends React.Component { const tagItems = []; if (tags || tags.length > 0) { // Sort by id for now, but probably needs to be changed in the future. - tags.sort((a, b) => { return a.title < b.title ? -1 : +1; }); + tags.sort((a, b) => { + return a.title < b.title ? -1 : +1; + }); for (let i = 0; i < tags.length; i++) { const props = { title: tags[i].title, - key: tags[i].id + key: tags[i].id, }; tagItems.push(); } @@ -35,13 +37,13 @@ class TagListComponent extends React.Component { return (
- { tagItems } + {tagItems}
- ) + ); } } -const mapStateToProps = (state) => { +const mapStateToProps = state => { return { theme: state.settings.theme }; }; diff --git a/ElectronClient/app/gui/Toolbar.jsx b/ElectronClient/app/gui/Toolbar.jsx index f755fd766..fe8e8ea1a 100644 --- a/ElectronClient/app/gui/Toolbar.jsx +++ b/ElectronClient/app/gui/Toolbar.jsx @@ -1,19 +1,16 @@ const React = require('react'); const { connect } = require('react-redux'); -const { reg } = require('lib/registry.js'); const { themeStyle } = require('../theme.js'); -const { _ } = require('lib/locale.js'); const ToolbarButton = require('./ToolbarButton.min.js'); const ToolbarSpace = require('./ToolbarSpace.min.js'); class ToolbarComponent extends React.Component { - render() { const style = this.props.style; const theme = themeStyle(this.props.theme); style.height = theme.toolbarHeight; style.display = 'flex'; - style.flexDirection = 'row'; + style.flexDirection = 'row'; style.borderBottom = '1px solid ' + theme.dividerColor; style.boxSizing = 'border-box'; @@ -28,10 +25,13 @@ class ToolbarComponent extends React.Component { if (!key) key = o.type + '_' + i; - const props = Object.assign({ - key: key, - theme: this.props.theme, - }, o); + const props = Object.assign( + { + key: key, + theme: this.props.theme, + }, + o + ); if (itemType === 'button') { itemComps.push(); @@ -43,17 +43,16 @@ class ToolbarComponent extends React.Component { return (
- { itemComps } + {itemComps}
); } - } -const mapStateToProps = (state) => { +const mapStateToProps = state => { return { theme: state.settings.theme }; }; const Toolbar = connect(mapStateToProps)(ToolbarComponent); -module.exports = Toolbar; \ No newline at end of file +module.exports = Toolbar; diff --git a/ElectronClient/app/gui/ToolbarButton.jsx b/ElectronClient/app/gui/ToolbarButton.jsx index 330299721..966681813 100644 --- a/ElectronClient/app/gui/ToolbarButton.jsx +++ b/ElectronClient/app/gui/ToolbarButton.jsx @@ -1,9 +1,7 @@ const React = require('react'); -const { connect } = require('react-redux'); const { themeStyle } = require('../theme.js'); class ToolbarButton extends React.Component { - render() { const theme = themeStyle(this.props.theme); @@ -16,13 +14,13 @@ class ToolbarButton extends React.Component { if (this.props.iconName) { const iconStyle = { fontSize: Math.round(theme.fontSize * 1.5), - color: theme.color + color: theme.color, }; if (title) iconStyle.marginRight = 5; - icon = + icon = ; } - const isEnabled = (!('enabled' in this.props) || this.props.enabled === true); + const isEnabled = !('enabled' in this.props) || this.props.enabled === true; let classes = ['button']; if (!isEnabled) classes.push('disabled'); @@ -36,13 +34,15 @@ class ToolbarButton extends React.Component { style={finalStyle} title={tooltip} href="#" - onClick={() => { if (isEnabled && this.props.onClick) this.props.onClick() }} - > - {icon}{title} + onClick={() => { + if (isEnabled && this.props.onClick) this.props.onClick(); + }} + > + {icon} + {title} ); } - } -module.exports = ToolbarButton; \ No newline at end of file +module.exports = ToolbarButton; diff --git a/ElectronClient/app/gui/ToolbarSpace.jsx b/ElectronClient/app/gui/ToolbarSpace.jsx index 4699f5c28..92d7a7a1e 100644 --- a/ElectronClient/app/gui/ToolbarSpace.jsx +++ b/ElectronClient/app/gui/ToolbarSpace.jsx @@ -1,22 +1,14 @@ const React = require('react'); -const { connect } = require('react-redux'); const { themeStyle } = require('../theme.js'); class ToolbarSpace extends React.Component { - render() { const theme = themeStyle(this.props.theme); const style = Object.assign({}, theme.toolbarStyle); style.minWidth = style.height / 2; - return ( - - - ); + return ; } - } -module.exports = ToolbarSpace; \ No newline at end of file +module.exports = ToolbarSpace; diff --git a/ElectronClient/app/gui/VerticalResizer.jsx b/ElectronClient/app/gui/VerticalResizer.jsx index 03154dd5c..f64d5830a 100644 --- a/ElectronClient/app/gui/VerticalResizer.jsx +++ b/ElectronClient/app/gui/VerticalResizer.jsx @@ -1,12 +1,11 @@ -const React = require("react"); +const React = require('react'); const electron = require('electron'); class VerticalResizer extends React.PureComponent { - constructor() { super(); - this.state = { + this.state = { parentRight: 0, parentHeight: 0, parentWidth: 0, @@ -29,17 +28,17 @@ class VerticalResizer extends React.PureComponent { } onDragStart(event) { - document.addEventListener('dragover', this.document_onDragOver) + document.addEventListener('dragover', this.document_onDragOver); - event.dataTransfer.dropEffect= 'none'; + event.dataTransfer.dropEffect = 'none'; + + const cursor = electron.screen.getCursorScreenPoint(); - const cursor = electron.screen.getCursorScreenPoint(); - this.setState({ drag: { startX: cursor.x, lastX: cursor.x, - } + }, }); if (this.props.onDragStart) this.props.onDragStart({}); @@ -58,11 +57,14 @@ class VerticalResizer extends React.PureComponent { const delta = newX - this.state.drag.lastX; if (!delta) return; - this.setState({ - drag: Object.assign({}, this.state.drag, { lastX: newX }), - }, () => { - this.props.onDrag({ deltaX: delta }); - }); + this.setState( + { + drag: Object.assign({}, this.state.drag, { lastX: newX }), + }, + () => { + this.props.onDrag({ deltaX: delta }); + } + ); } onDragEnd(event) { @@ -76,26 +78,22 @@ class VerticalResizer extends React.PureComponent { render() { const debug = false; - const rootStyle = Object.assign({}, { - height: '100%', - width:5, - borderColor:'red', - borderWidth: debug ? 1 : 0, - borderStyle:'solid', - cursor: 'col-resize', - boxSizing: 'border-box', - opacity: 0, - }, this.props.style); - - return ( -
+ const rootStyle = Object.assign( + {}, + { + height: '100%', + width: 5, + borderColor: 'red', + borderWidth: debug ? 1 : 0, + borderStyle: 'solid', + cursor: 'col-resize', + boxSizing: 'border-box', + opacity: 0, + }, + this.props.style ); + + return
; } } diff --git a/ElectronClient/app/gui/dialogs.js b/ElectronClient/app/gui/dialogs.js index c30a0ea2b..6d36acec1 100644 --- a/ElectronClient/app/gui/dialogs.js +++ b/ElectronClient/app/gui/dialogs.js @@ -1,7 +1,6 @@ const smalltalk = require('smalltalk'); class Dialogs { - async alert(message, title = '') { await smalltalk.alert(title, message); } @@ -25,7 +24,6 @@ class Dialogs { return null; } } - } const dialogs = new Dialogs(); diff --git a/ElectronClient/app/gui/note-viewer/preload.js b/ElectronClient/app/gui/note-viewer/preload.js index deceda30f..65de92a97 100644 --- a/ElectronClient/app/gui/note-viewer/preload.js +++ b/ElectronClient/app/gui/note-viewer/preload.js @@ -17,7 +17,7 @@ ipcRenderer.on('setMarkers', (event, keywords, options) => { window.postMessage({ target: 'webview', name: 'setMarkers', data: { keywords: keywords, options: options } }, '*'); }); -window.addEventListener('message', (event) => { +window.addEventListener('message', event => { // Here we only deal with messages that are sent from the webview to the main Electron process if (!event.data || event.data.target !== 'main') return; diff --git a/ElectronClient/app/gui/utils/NoteListUtils.js b/ElectronClient/app/gui/utils/NoteListUtils.js index 73aa78831..425000ffc 100644 --- a/ElectronClient/app/gui/utils/NoteListUtils.js +++ b/ElectronClient/app/gui/utils/NoteListUtils.js @@ -1,6 +1,4 @@ -const { time } = require('lib/time-utils.js'); const BaseModel = require('lib/BaseModel'); -const markJsUtils = require('lib/markJsUtils'); const { _ } = require('lib/locale.js'); const { bridge } = require('electron').remote.require('./bridge'); const Menu = bridge().Menu; @@ -8,49 +6,62 @@ const MenuItem = bridge().MenuItem; const eventManager = require('../../eventManager'); const InteropService = require('lib/services/InteropService'); const InteropServiceHelper = require('../../InteropServiceHelper.js'); -const Search = require('lib/models/Search'); const Note = require('lib/models/Note'); -const SearchEngine = require('lib/services/SearchEngine'); -const { replaceRegexDiacritics, pregQuote, substrWithEllipsis } = require('lib/string-utils'); +const { substrWithEllipsis } = require('lib/string-utils'); class NoteListUtils { - static makeContextMenu(noteIds, props) { - const notes = noteIds.map((id) => BaseModel.byId(props.notes, id)); + const notes = noteIds.map(id => BaseModel.byId(props.notes, id)); let hasEncrypted = false; for (let i = 0; i < notes.length; i++) { - if (!!notes[i].encryption_applied) hasEncrypted = true; + if (notes[i].encryption_applied) hasEncrypted = true; } - const menu = new Menu() + const menu = new Menu(); if (!hasEncrypted) { - menu.append(new MenuItem({label: _('Add or remove tags'), enabled: noteIds.length === 1, click: async () => { - props.dispatch({ - type: 'WINDOW_COMMAND', - name: 'setTags', - noteId: noteIds[0], - }); - }})); + menu.append( + new MenuItem({ + label: _('Add or remove tags'), + enabled: noteIds.length === 1, + click: async () => { + props.dispatch({ + type: 'WINDOW_COMMAND', + name: 'setTags', + noteId: noteIds[0], + }); + }, + }) + ); - menu.append(new MenuItem({label: _('Duplicate'), click: async () => { - for (let i = 0; i < noteIds.length; i++) { - const note = await Note.load(noteIds[i]); - await Note.duplicate(noteIds[i], { - uniqueTitle: _('%s - Copy', note.title), - }); - } - }})); + menu.append( + new MenuItem({ + label: _('Duplicate'), + click: async () => { + for (let i = 0; i < noteIds.length; i++) { + const note = await Note.load(noteIds[i]); + await Note.duplicate(noteIds[i], { + uniqueTitle: _('%s - Copy', note.title), + }); + } + }, + }) + ); if (noteIds.length <= 1) { - menu.append(new MenuItem({label: _('Switch between note and to-do type'), click: async () => { - for (let i = 0; i < noteIds.length; i++) { - const note = await Note.load(noteIds[i]); - await Note.save(Note.toggleIsTodo(note), { userSideValidation: true }); - eventManager.emit('noteTypeToggle', { noteId: note.id }); - } - }})); + menu.append( + new MenuItem({ + label: _('Switch between note and to-do type'), + click: async () => { + for (let i = 0; i < noteIds.length; i++) { + const note = await Note.load(noteIds[i]); + await Note.save(Note.toggleIsTodo(note), { userSideValidation: true }); + eventManager.emit('noteTypeToggle', { noteId: note.id }); + } + }, + }) + ); } else { const switchNoteType = async (noteIds, type) => { for (let i = 0; i < noteIds.length; i++) { @@ -60,26 +71,41 @@ class NoteListUtils { await Note.save(newNote, { userSideValidation: true }); eventManager.emit('noteTypeToggle', { noteId: note.id }); } - } + }; - menu.append(new MenuItem({label: _('Switch to note type'), click: async () => { - await switchNoteType(noteIds, 'note'); - }})); + menu.append( + new MenuItem({ + label: _('Switch to note type'), + click: async () => { + await switchNoteType(noteIds, 'note'); + }, + }) + ); - menu.append(new MenuItem({label: _('Switch to to-do type'), click: async () => { - await switchNoteType(noteIds, 'todo'); - }})); + menu.append( + new MenuItem({ + label: _('Switch to to-do type'), + click: async () => { + await switchNoteType(noteIds, 'todo'); + }, + }) + ); } - menu.append(new MenuItem({label: _('Copy Markdown link'), click: async () => { - const { clipboard } = require('electron'); - const links = []; - for (let i = 0; i < noteIds.length; i++) { - const note = await Note.load(noteIds[i]); - links.push(Note.markdownTag(note)); - } - clipboard.writeText(links.join(' ')); - }})); + menu.append( + new MenuItem({ + label: _('Copy Markdown link'), + click: async () => { + const { clipboard } = require('electron'); + const links = []; + for (let i = 0; i < noteIds.length; i++) { + const note = await Note.load(noteIds[i]); + links.push(Note.markdownTag(note)); + } + clipboard.writeText(links.join(' ')); + }, + }) + ); const exportMenu = new Menu(); @@ -89,28 +115,43 @@ class NoteListUtils { const module = ioModules[i]; if (module.type !== 'exporter') continue; - exportMenu.append(new MenuItem({ label: module.fullLabel() , click: async () => { - await InteropServiceHelper.export(props.dispatch.bind(this), module, { sourceNoteIds: noteIds }); - }})); + exportMenu.append( + new MenuItem({ + label: module.fullLabel(), + click: async () => { + await InteropServiceHelper.export(props.dispatch.bind(this), module, { sourceNoteIds: noteIds }); + }, + }) + ); } if (noteIds.length === 1) { - exportMenu.append(new MenuItem({ label: 'PDF - ' + _('PDF File') , click: () => { - props.dispatch({ - type: 'WINDOW_COMMAND', - name: 'exportPdf', - }); - }})); + exportMenu.append( + new MenuItem({ + label: 'PDF - ' + _('PDF File'), + click: () => { + props.dispatch({ + type: 'WINDOW_COMMAND', + name: 'exportPdf', + }); + }, + }) + ); } - const exportMenuItem = new MenuItem({label: _('Export'), submenu: exportMenu}); + const exportMenuItem = new MenuItem({ label: _('Export'), submenu: exportMenu }); menu.append(exportMenuItem); } - menu.append(new MenuItem({label: _('Delete'), click: async () => { - await this.confirmDeleteNotes(noteIds); - }})); + menu.append( + new MenuItem({ + label: _('Delete'), + click: async () => { + await this.confirmDeleteNotes(noteIds); + }, + }) + ); return menu; } @@ -135,7 +176,6 @@ class NoteListUtils { if (!ok) return; await Note.batchDelete(noteIds); } - } -module.exports = NoteListUtils; \ No newline at end of file +module.exports = NoteListUtils;