2017-11-06 20:35:04 +02:00
|
|
|
const React = require('react');
|
|
|
|
const { connect } = require('react-redux');
|
2017-11-06 22:54:58 +02:00
|
|
|
const { Header } = require('./Header.min.js');
|
2017-11-06 20:35:04 +02:00
|
|
|
const { SideBar } = require('./SideBar.min.js');
|
|
|
|
const { NoteList } = require('./NoteList.min.js');
|
|
|
|
const { NoteText } = require('./NoteText.min.js');
|
2020-03-10 01:24:57 +02:00
|
|
|
const NoteText2 = require('./NoteText2.js').default;
|
2017-11-08 19:51:55 +02:00
|
|
|
const { PromptDialog } = require('./PromptDialog.min.js');
|
2020-02-25 11:43:31 +02:00
|
|
|
const NoteContentPropertiesDialog = require('./NoteContentPropertiesDialog.js').default;
|
2018-09-16 20:37:31 +02:00
|
|
|
const NotePropertiesDialog = require('./NotePropertiesDialog.min.js');
|
2019-12-13 03:16:34 +02:00
|
|
|
const ShareNoteDialog = require('./ShareNoteDialog.js').default;
|
2017-12-14 20:12:14 +02:00
|
|
|
const Setting = require('lib/models/Setting.js');
|
|
|
|
const BaseModel = require('lib/BaseModel.js');
|
|
|
|
const Tag = require('lib/models/Tag.js');
|
|
|
|
const Note = require('lib/models/Note.js');
|
2017-11-17 20:57:27 +02:00
|
|
|
const { uuid } = require('lib/uuid.js');
|
2017-12-14 20:12:14 +02:00
|
|
|
const Folder = require('lib/models/Folder.js');
|
2017-11-06 22:54:58 +02:00
|
|
|
const { themeStyle } = require('../theme.js');
|
2017-11-08 19:51:55 +02:00
|
|
|
const { _ } = require('lib/locale.js');
|
|
|
|
const { bridge } = require('electron').remote.require('./bridge');
|
2017-11-30 01:03:10 +02:00
|
|
|
const eventManager = require('../eventManager');
|
2019-02-16 03:12:43 +02:00
|
|
|
const VerticalResizer = require('./VerticalResizer.min');
|
2019-04-01 21:43:13 +02:00
|
|
|
const PluginManager = require('lib/services/PluginManager');
|
2020-03-04 21:37:32 +02:00
|
|
|
const TemplateUtils = require('lib/TemplateUtils');
|
2020-03-13 19:42:50 +02:00
|
|
|
const EncryptionService = require('lib/services/EncryptionService');
|
2017-11-06 20:35:04 +02:00
|
|
|
|
|
|
|
class MainScreenComponent extends React.Component {
|
2018-09-16 20:37:31 +02:00
|
|
|
constructor() {
|
|
|
|
super();
|
|
|
|
|
|
|
|
this.notePropertiesDialog_close = this.notePropertiesDialog_close.bind(this);
|
2020-02-25 11:43:31 +02:00
|
|
|
this.noteContentPropertiesDialog_close = this.noteContentPropertiesDialog_close.bind(this);
|
2019-12-13 03:16:34 +02:00
|
|
|
this.shareNoteDialog_close = this.shareNoteDialog_close.bind(this);
|
2019-02-16 03:12:43 +02:00
|
|
|
this.sidebar_onDrag = this.sidebar_onDrag.bind(this);
|
|
|
|
this.noteList_onDrag = this.noteList_onDrag.bind(this);
|
|
|
|
}
|
|
|
|
|
|
|
|
sidebar_onDrag(event) {
|
|
|
|
Setting.setValue('style.sidebar.width', this.props.sidebarWidth + event.deltaX);
|
|
|
|
}
|
|
|
|
|
|
|
|
noteList_onDrag(event) {
|
|
|
|
Setting.setValue('style.noteList.width', Setting.value('style.noteList.width') + event.deltaX);
|
2018-09-16 20:37:31 +02:00
|
|
|
}
|
|
|
|
|
|
|
|
notePropertiesDialog_close() {
|
|
|
|
this.setState({ notePropertiesDialogOptions: {} });
|
|
|
|
}
|
|
|
|
|
2020-02-25 11:43:31 +02:00
|
|
|
noteContentPropertiesDialog_close() {
|
|
|
|
this.setState({ noteContentPropertiesDialogOptions: {} });
|
|
|
|
}
|
|
|
|
|
2019-12-13 03:16:34 +02:00
|
|
|
shareNoteDialog_close() {
|
|
|
|
this.setState({ shareNoteDialogOptions: {} });
|
|
|
|
}
|
|
|
|
|
|
|
|
UNSAFE_componentWillMount() {
|
2017-11-10 21:18:19 +02:00
|
|
|
this.setState({
|
2017-11-10 22:34:36 +02:00
|
|
|
promptOptions: null,
|
2018-02-27 22:04:38 +02:00
|
|
|
modalLayer: {
|
|
|
|
visible: false,
|
|
|
|
message: '',
|
2018-09-16 20:37:31 +02:00
|
|
|
},
|
|
|
|
notePropertiesDialogOptions: {},
|
2020-02-25 11:43:31 +02:00
|
|
|
noteContentPropertiesDialogOptions: {},
|
2019-12-13 03:16:34 +02:00
|
|
|
shareNoteDialogOptions: {},
|
2017-11-10 21:18:19 +02:00
|
|
|
});
|
|
|
|
}
|
|
|
|
|
2019-12-13 03:16:34 +02:00
|
|
|
UNSAFE_componentWillReceiveProps(newProps) {
|
2020-03-04 18:36:53 +02:00
|
|
|
// Execute a command if any, and if we haven't already executed it
|
|
|
|
if (newProps.windowCommand && newProps.windowCommand !== this.props.windowCommand) {
|
2017-11-11 19:36:47 +02:00
|
|
|
this.doCommand(newProps.windowCommand);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2017-11-10 21:18:19 +02:00
|
|
|
toggleVisiblePanes() {
|
2017-11-12 19:02:20 +02:00
|
|
|
this.props.dispatch({
|
|
|
|
type: 'NOTE_VISIBLE_PANES_TOGGLE',
|
|
|
|
});
|
2017-11-08 19:51:55 +02:00
|
|
|
}
|
|
|
|
|
2018-04-15 17:50:39 +02:00
|
|
|
toggleSidebar() {
|
|
|
|
this.props.dispatch({
|
|
|
|
type: 'SIDEBAR_VISIBILITY_TOGGLE',
|
|
|
|
});
|
|
|
|
}
|
|
|
|
|
2019-10-30 11:40:34 +02:00
|
|
|
toggleNoteList() {
|
|
|
|
this.props.dispatch({
|
|
|
|
type: 'NOTELIST_VISIBILITY_TOGGLE',
|
|
|
|
});
|
|
|
|
}
|
|
|
|
|
2017-11-12 01:13:14 +02:00
|
|
|
async doCommand(command) {
|
2017-11-11 19:36:47 +02:00
|
|
|
if (!command) return;
|
|
|
|
|
2019-07-20 23:13:10 +02:00
|
|
|
const createNewNote = async (template, isTodo) => {
|
2017-11-11 19:36:47 +02:00
|
|
|
const folderId = Setting.value('activeFolderId');
|
|
|
|
if (!folderId) return;
|
|
|
|
|
2020-03-04 21:37:32 +02:00
|
|
|
const body = template ? TemplateUtils.render(template) : '';
|
|
|
|
|
2020-02-29 14:39:15 +02:00
|
|
|
const newNote = await Note.save({
|
2017-11-11 19:36:47 +02:00
|
|
|
parent_id: folderId,
|
|
|
|
is_todo: isTodo ? 1 : 0,
|
2020-03-04 21:37:32 +02:00
|
|
|
body: body,
|
2020-02-29 14:39:15 +02:00
|
|
|
}, { provisional: true });
|
2017-11-11 19:36:47 +02:00
|
|
|
|
|
|
|
this.props.dispatch({
|
2020-02-29 14:39:15 +02:00
|
|
|
type: 'NOTE_SELECT',
|
|
|
|
id: newNote.id,
|
2017-11-11 19:36:47 +02:00
|
|
|
});
|
2019-07-29 14:13:23 +02:00
|
|
|
};
|
2017-11-11 19:36:47 +02:00
|
|
|
|
|
|
|
let commandProcessed = true;
|
|
|
|
|
|
|
|
if (command.name === 'newNote') {
|
2017-11-13 02:23:12 +02:00
|
|
|
if (!this.props.folders.length) {
|
|
|
|
bridge().showErrorMessageBox(_('Please create a notebook first.'));
|
2019-07-13 17:57:33 +02:00
|
|
|
} else {
|
|
|
|
await createNewNote(null, false);
|
2017-11-13 02:23:12 +02:00
|
|
|
}
|
2017-11-11 19:36:47 +02:00
|
|
|
} else if (command.name === 'newTodo') {
|
2017-11-13 02:23:12 +02:00
|
|
|
if (!this.props.folders.length) {
|
|
|
|
bridge().showErrorMessageBox(_('Please create a notebook first'));
|
2019-07-13 17:57:33 +02:00
|
|
|
} else {
|
|
|
|
await createNewNote(null, true);
|
2017-11-13 02:23:12 +02:00
|
|
|
}
|
2019-10-17 22:41:13 +02:00
|
|
|
} else if (command.name === 'newNotebook' || (command.name === 'newSubNotebook' && command.activeFolderId)) {
|
2017-11-11 19:36:47 +02:00
|
|
|
this.setState({
|
|
|
|
promptOptions: {
|
2017-11-12 01:13:14 +02:00
|
|
|
label: _('Notebook title:'),
|
2019-07-29 14:13:23 +02:00
|
|
|
onClose: async answer => {
|
2017-11-11 19:36:47 +02:00
|
|
|
if (answer) {
|
|
|
|
let folder = null;
|
|
|
|
try {
|
2018-04-15 17:50:39 +02:00
|
|
|
folder = await Folder.save({ title: answer }, { userSideValidation: true });
|
2019-10-17 22:41:13 +02:00
|
|
|
if (command.name === 'newSubNotebook') folder = await Folder.moveToFolder(folder.id, command.activeFolderId);
|
2017-11-11 19:36:47 +02:00
|
|
|
} catch (error) {
|
|
|
|
bridge().showErrorMessageBox(error.message);
|
|
|
|
}
|
|
|
|
|
2017-11-16 20:51:11 +02:00
|
|
|
if (folder) {
|
|
|
|
this.props.dispatch({
|
|
|
|
type: 'FOLDER_SELECT',
|
|
|
|
id: folder.id,
|
2020-03-15 11:40:57 +02:00
|
|
|
historyAction: 'goto',
|
2017-11-16 20:51:11 +02:00
|
|
|
});
|
|
|
|
}
|
2017-11-11 19:36:47 +02:00
|
|
|
}
|
|
|
|
|
2017-11-12 01:13:14 +02:00
|
|
|
this.setState({ promptOptions: null });
|
2019-07-29 14:13:23 +02:00
|
|
|
},
|
2017-11-12 01:13:14 +02:00
|
|
|
},
|
|
|
|
});
|
|
|
|
} else if (command.name === 'setTags') {
|
2020-02-05 23:24:12 +02:00
|
|
|
const tags = await Tag.commonTagsByNoteIds(command.noteIds);
|
|
|
|
const startTags = tags
|
2019-07-29 14:13:23 +02:00
|
|
|
.map(a => {
|
|
|
|
return { value: a.id, label: a.title };
|
|
|
|
})
|
|
|
|
.sort((a, b) => {
|
2019-08-29 18:36:53 +02:00
|
|
|
// sensitivity accent will treat accented characters as differemt
|
|
|
|
// but treats caps as equal
|
2020-02-05 00:09:34 +02:00
|
|
|
return a.label.localeCompare(b.label, undefined, { sensitivity: 'accent' });
|
2019-07-29 14:13:23 +02:00
|
|
|
});
|
2019-06-08 00:33:06 +02:00
|
|
|
const allTags = await Tag.allWithNotes();
|
2019-07-29 14:13:23 +02:00
|
|
|
const tagSuggestions = allTags.map(a => {
|
|
|
|
return { value: a.id, label: a.title };
|
2020-02-06 12:51:24 +02:00
|
|
|
})
|
|
|
|
.sort((a, b) => {
|
|
|
|
// sensitivity accent will treat accented characters as differemt
|
|
|
|
// but treats caps as equal
|
|
|
|
return a.label.localeCompare(b.label, undefined, { sensitivity: 'accent' });
|
|
|
|
});
|
2017-11-12 01:13:14 +02:00
|
|
|
|
|
|
|
this.setState({
|
|
|
|
promptOptions: {
|
|
|
|
label: _('Add or remove tags:'),
|
2019-06-08 00:33:06 +02:00
|
|
|
inputType: 'tags',
|
2020-02-05 23:24:12 +02:00
|
|
|
value: startTags,
|
2019-06-08 00:33:06 +02:00
|
|
|
autocomplete: tagSuggestions,
|
2019-07-29 14:13:23 +02:00
|
|
|
onClose: async answer => {
|
2017-11-12 01:13:14 +02:00
|
|
|
if (answer !== null) {
|
2020-02-05 23:24:12 +02:00
|
|
|
const endTagTitles = answer.map(a => {
|
2019-07-29 14:13:23 +02:00
|
|
|
return a.label.trim();
|
|
|
|
});
|
2020-02-05 23:24:12 +02:00
|
|
|
if (command.noteIds.length === 1) {
|
|
|
|
await Tag.setNoteTagsByTitles(command.noteIds[0], endTagTitles);
|
|
|
|
} else {
|
|
|
|
const startTagTitles = startTags.map(a => { return a.label.trim(); });
|
|
|
|
const addTags = endTagTitles.filter(value => !startTagTitles.includes(value));
|
|
|
|
const delTags = startTagTitles.filter(value => !endTagTitles.includes(value));
|
|
|
|
|
|
|
|
// apply the tag additions and deletions to each selected note
|
|
|
|
for (let i = 0; i < command.noteIds.length; i++) {
|
|
|
|
const tags = await Tag.tagsByNoteId(command.noteIds[i]);
|
|
|
|
let tagTitles = tags.map(a => { return a.title; });
|
|
|
|
tagTitles = tagTitles.concat(addTags);
|
|
|
|
tagTitles = tagTitles.filter(value => !delTags.includes(value));
|
|
|
|
await Tag.setNoteTagsByTitles(command.noteIds[i], tagTitles);
|
|
|
|
}
|
|
|
|
}
|
2017-11-12 01:13:14 +02:00
|
|
|
}
|
2017-11-11 19:36:47 +02:00
|
|
|
this.setState({ promptOptions: null });
|
2019-07-29 14:13:23 +02:00
|
|
|
},
|
2017-11-11 19:36:47 +02:00
|
|
|
},
|
|
|
|
});
|
2017-12-14 22:21:36 +02:00
|
|
|
} else if (command.name === 'renameFolder') {
|
2017-11-16 20:51:11 +02:00
|
|
|
const folder = await Folder.load(command.id);
|
2019-07-29 14:13:23 +02:00
|
|
|
|
2019-07-13 17:57:33 +02:00
|
|
|
if (folder) {
|
|
|
|
this.setState({
|
|
|
|
promptOptions: {
|
|
|
|
label: _('Rename notebook:'),
|
|
|
|
value: folder.title,
|
2019-07-29 14:13:23 +02:00
|
|
|
onClose: async answer => {
|
2019-07-13 17:57:33 +02:00
|
|
|
if (answer !== null) {
|
|
|
|
try {
|
|
|
|
folder.title = answer;
|
|
|
|
await Folder.save(folder, { fields: ['title'], userSideValidation: true });
|
|
|
|
} catch (error) {
|
|
|
|
bridge().showErrorMessageBox(error.message);
|
|
|
|
}
|
2017-11-16 20:51:11 +02:00
|
|
|
}
|
2019-07-13 17:57:33 +02:00
|
|
|
this.setState({ promptOptions: null });
|
2019-07-29 14:13:23 +02:00
|
|
|
},
|
2019-07-13 17:57:33 +02:00
|
|
|
},
|
|
|
|
});
|
|
|
|
}
|
2018-05-20 09:39:32 +02:00
|
|
|
} else if (command.name === 'renameTag') {
|
2018-11-08 00:16:05 +02:00
|
|
|
const tag = await Tag.load(command.id);
|
2019-07-13 17:57:33 +02:00
|
|
|
if (tag) {
|
|
|
|
this.setState({
|
|
|
|
promptOptions: {
|
|
|
|
label: _('Rename tag:'),
|
|
|
|
value: tag.title,
|
2019-07-29 14:13:23 +02:00
|
|
|
onClose: async answer => {
|
2019-07-13 17:57:33 +02:00
|
|
|
if (answer !== null) {
|
|
|
|
try {
|
|
|
|
tag.title = answer;
|
|
|
|
await Tag.save(tag, { fields: ['title'], userSideValidation: true });
|
|
|
|
} catch (error) {
|
|
|
|
bridge().showErrorMessageBox(error.message);
|
|
|
|
}
|
2018-05-20 09:39:32 +02:00
|
|
|
}
|
2019-07-29 14:13:23 +02:00
|
|
|
this.setState({ promptOptions: null });
|
|
|
|
},
|
|
|
|
},
|
|
|
|
});
|
2019-07-13 17:57:33 +02:00
|
|
|
}
|
2017-11-17 20:57:27 +02:00
|
|
|
} else if (command.name === 'search') {
|
2018-03-20 01:04:48 +02:00
|
|
|
if (!this.searchId_) this.searchId_ = uuid.create();
|
|
|
|
|
|
|
|
this.props.dispatch({
|
|
|
|
type: 'SEARCH_UPDATE',
|
|
|
|
search: {
|
|
|
|
id: this.searchId_,
|
|
|
|
title: command.query,
|
|
|
|
query_pattern: command.query,
|
|
|
|
query_folder_id: null,
|
|
|
|
type_: BaseModel.TYPE_SEARCH,
|
2017-11-28 00:50:46 +02:00
|
|
|
},
|
|
|
|
});
|
2018-03-20 01:04:48 +02:00
|
|
|
|
|
|
|
if (command.query) {
|
|
|
|
this.props.dispatch({
|
|
|
|
type: 'SEARCH_SELECT',
|
|
|
|
id: this.searchId_,
|
|
|
|
});
|
2019-03-15 23:57:58 +02:00
|
|
|
} else {
|
|
|
|
const note = await Note.load(this.props.selectedNoteId);
|
|
|
|
if (note) {
|
|
|
|
this.props.dispatch({
|
2019-07-29 12:55:50 +02:00
|
|
|
type: 'FOLDER_AND_NOTE_SELECT',
|
2019-03-15 23:57:58 +02:00
|
|
|
folderId: note.parent_id,
|
|
|
|
noteId: note.id,
|
|
|
|
});
|
|
|
|
}
|
2018-03-20 01:04:48 +02:00
|
|
|
}
|
2018-09-16 20:37:31 +02:00
|
|
|
} else if (command.name === 'commandNoteProperties') {
|
|
|
|
this.setState({
|
|
|
|
notePropertiesDialogOptions: {
|
|
|
|
noteId: command.noteId,
|
|
|
|
visible: true,
|
2019-05-06 22:35:29 +02:00
|
|
|
onRevisionLinkClick: command.onRevisionLinkClick,
|
2018-09-16 20:37:31 +02:00
|
|
|
},
|
|
|
|
});
|
2020-02-25 11:43:31 +02:00
|
|
|
} else if (command.name === 'commandContentProperties') {
|
|
|
|
this.setState({
|
|
|
|
noteContentPropertiesDialogOptions: {
|
|
|
|
visible: true,
|
|
|
|
text: command.text,
|
|
|
|
lines: command.lines,
|
|
|
|
},
|
|
|
|
});
|
2019-12-13 03:16:34 +02:00
|
|
|
} else if (command.name === 'commandShareNoteDialog') {
|
|
|
|
this.setState({
|
|
|
|
shareNoteDialogOptions: {
|
|
|
|
noteIds: command.noteIds,
|
|
|
|
visible: true,
|
|
|
|
},
|
|
|
|
});
|
2018-02-16 20:08:02 +02:00
|
|
|
} else if (command.name === 'toggleVisiblePanes') {
|
|
|
|
this.toggleVisiblePanes();
|
2018-04-15 17:50:39 +02:00
|
|
|
} else if (command.name === 'toggleSidebar') {
|
|
|
|
this.toggleSidebar();
|
2019-10-30 11:40:34 +02:00
|
|
|
} else if (command.name === 'toggleNoteList') {
|
|
|
|
this.toggleNoteList();
|
2018-02-27 22:04:38 +02:00
|
|
|
} else if (command.name === 'showModalMessage') {
|
2019-10-05 23:46:39 +02:00
|
|
|
this.setState({
|
|
|
|
modalLayer: {
|
|
|
|
visible: true,
|
|
|
|
message:
|
|
|
|
<div className="modal-message">
|
|
|
|
<div id="loading-animation" />
|
|
|
|
<div className="text">{command.message}</div>
|
|
|
|
</div>,
|
|
|
|
},
|
|
|
|
});
|
2018-02-27 22:04:38 +02:00
|
|
|
} else if (command.name === 'hideModalMessage') {
|
|
|
|
this.setState({ modalLayer: { visible: false, message: '' } });
|
2017-11-28 00:50:46 +02:00
|
|
|
} else if (command.name === 'editAlarm') {
|
|
|
|
const note = await Note.load(command.noteId);
|
|
|
|
|
2020-03-14 01:46:14 +02:00
|
|
|
const defaultDate = new Date(Date.now() + 2 * 3600 * 1000);
|
2017-12-01 23:55:02 +02:00
|
|
|
defaultDate.setMinutes(0);
|
|
|
|
defaultDate.setSeconds(0);
|
|
|
|
|
2017-11-28 00:50:46 +02:00
|
|
|
this.setState({
|
|
|
|
promptOptions: {
|
2017-12-01 20:56:35 +02:00
|
|
|
label: _('Set alarm:'),
|
2017-11-28 00:50:46 +02:00
|
|
|
inputType: 'datetime',
|
|
|
|
buttons: ['ok', 'cancel', 'clear'],
|
2017-12-01 23:55:02 +02:00
|
|
|
value: note.todo_due ? new Date(note.todo_due) : defaultDate,
|
2017-11-28 00:50:46 +02:00
|
|
|
onClose: async (answer, buttonType) => {
|
|
|
|
let newNote = null;
|
|
|
|
|
|
|
|
if (buttonType === 'clear') {
|
|
|
|
newNote = {
|
|
|
|
id: note.id,
|
|
|
|
todo_due: 0,
|
|
|
|
};
|
|
|
|
} else if (answer !== null) {
|
|
|
|
newNote = {
|
|
|
|
id: note.id,
|
|
|
|
todo_due: answer.getTime(),
|
|
|
|
};
|
|
|
|
}
|
|
|
|
|
|
|
|
if (newNote) {
|
|
|
|
await Note.save(newNote);
|
2017-11-30 01:03:10 +02:00
|
|
|
eventManager.emit('alarmChange', { noteId: note.id });
|
2017-11-28 00:50:46 +02:00
|
|
|
}
|
|
|
|
|
2019-07-20 23:13:10 +02:00
|
|
|
this.setState({ promptOptions: null });
|
2019-07-29 14:13:23 +02:00
|
|
|
},
|
2019-07-20 23:13:10 +02:00
|
|
|
},
|
|
|
|
});
|
|
|
|
} else if (command.name === 'selectTemplate') {
|
|
|
|
this.setState({
|
|
|
|
promptOptions: {
|
|
|
|
label: _('Template file:'),
|
|
|
|
inputType: 'dropdown',
|
|
|
|
value: this.props.templates[0], // Need to start with some value
|
|
|
|
autocomplete: this.props.templates,
|
2019-07-29 14:13:23 +02:00
|
|
|
onClose: async answer => {
|
2019-07-20 23:13:10 +02:00
|
|
|
if (answer) {
|
|
|
|
if (command.noteType === 'note' || command.noteType === 'todo') {
|
|
|
|
createNewNote(answer.value, command.noteType === 'todo');
|
|
|
|
} else {
|
|
|
|
this.props.dispatch({
|
|
|
|
type: 'WINDOW_COMMAND',
|
|
|
|
name: 'insertTemplate',
|
|
|
|
value: answer.value,
|
|
|
|
});
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2017-11-17 20:57:27 +02:00
|
|
|
this.setState({ promptOptions: null });
|
2019-07-29 14:13:23 +02:00
|
|
|
},
|
2017-11-17 20:57:27 +02:00
|
|
|
},
|
2018-04-15 17:50:39 +02:00
|
|
|
});
|
2017-11-11 19:36:47 +02:00
|
|
|
} else {
|
|
|
|
commandProcessed = false;
|
|
|
|
}
|
|
|
|
|
|
|
|
if (commandProcessed) {
|
|
|
|
this.props.dispatch({
|
|
|
|
type: 'WINDOW_COMMAND',
|
|
|
|
name: null,
|
|
|
|
});
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2019-10-30 11:40:34 +02:00
|
|
|
styles(themeId, width, height, messageBoxVisible, isSidebarVisible, isNoteListVisible, sidebarWidth, noteListWidth) {
|
|
|
|
const styleKey = [themeId, width, height, messageBoxVisible, +isSidebarVisible, +isNoteListVisible, sidebarWidth, noteListWidth].join('_');
|
2017-11-30 01:03:10 +02:00
|
|
|
if (styleKey === this.styleKey_) return this.styles_;
|
2017-11-06 22:54:58 +02:00
|
|
|
|
2017-11-30 01:03:10 +02:00
|
|
|
const theme = themeStyle(themeId);
|
2017-11-06 22:54:58 +02:00
|
|
|
|
2017-11-30 01:03:10 +02:00
|
|
|
this.styleKey_ = styleKey;
|
2017-11-06 20:35:04 +02:00
|
|
|
|
2017-11-30 01:03:10 +02:00
|
|
|
this.styles_ = {};
|
|
|
|
|
|
|
|
this.styles_.header = {
|
|
|
|
width: width,
|
|
|
|
};
|
|
|
|
|
2017-12-05 01:57:13 +02:00
|
|
|
this.styles_.messageBox = {
|
|
|
|
width: width,
|
|
|
|
height: 30,
|
|
|
|
display: 'flex',
|
|
|
|
alignItems: 'center',
|
|
|
|
paddingLeft: 10,
|
|
|
|
backgroundColor: theme.warningBackgroundColor,
|
2019-07-29 14:13:23 +02:00
|
|
|
};
|
2017-12-05 01:57:13 +02:00
|
|
|
|
2019-12-30 14:00:53 +02:00
|
|
|
const rowHeight = height - theme.headerHeight - (messageBoxVisible ? this.styles_.messageBox.height : 0);
|
|
|
|
|
2019-02-16 03:12:43 +02:00
|
|
|
this.styles_.verticalResizer = {
|
|
|
|
width: 5,
|
2019-12-30 16:10:43 +02:00
|
|
|
// HACK: For unknown reasons, the resizers are just a little bit taller than the other elements,
|
|
|
|
// making the whole window scroll vertically. So we remove 10 extra pixels here.
|
|
|
|
height: rowHeight - 10,
|
2019-02-16 03:12:43 +02:00
|
|
|
display: 'inline-block',
|
|
|
|
};
|
|
|
|
|
2017-11-30 01:03:10 +02:00
|
|
|
this.styles_.sideBar = {
|
2019-02-16 03:12:43 +02:00
|
|
|
width: sidebarWidth - this.styles_.verticalResizer.width,
|
2017-11-06 22:54:58 +02:00
|
|
|
height: rowHeight,
|
2017-11-06 20:35:04 +02:00
|
|
|
display: 'inline-block',
|
|
|
|
verticalAlign: 'top',
|
2019-07-29 12:55:50 +02:00
|
|
|
};
|
2018-04-15 17:50:39 +02:00
|
|
|
|
|
|
|
if (isSidebarVisible === false) {
|
|
|
|
this.styles_.sideBar.width = 0;
|
|
|
|
this.styles_.sideBar.display = 'none';
|
|
|
|
}
|
2017-11-06 20:35:04 +02:00
|
|
|
|
2017-11-30 01:03:10 +02:00
|
|
|
this.styles_.noteList = {
|
2019-02-16 03:12:43 +02:00
|
|
|
width: noteListWidth - this.styles_.verticalResizer.width,
|
2017-11-06 22:54:58 +02:00
|
|
|
height: rowHeight,
|
2017-11-06 20:35:04 +02:00
|
|
|
display: 'inline-block',
|
|
|
|
verticalAlign: 'top',
|
|
|
|
};
|
|
|
|
|
2019-10-30 11:40:34 +02:00
|
|
|
if (isNoteListVisible === false) {
|
2019-10-30 22:59:32 +02:00
|
|
|
this.styles_.noteList.width = 0;
|
2019-10-30 11:40:34 +02:00
|
|
|
this.styles_.noteList.display = 'none';
|
|
|
|
this.styles_.verticalResizer.display = 'none';
|
|
|
|
}
|
|
|
|
|
2017-11-30 01:03:10 +02:00
|
|
|
this.styles_.noteText = {
|
2019-02-16 03:12:43 +02:00
|
|
|
width: Math.floor(width - this.styles_.sideBar.width - this.styles_.noteList.width - 10),
|
2017-11-06 22:54:58 +02:00
|
|
|
height: rowHeight,
|
2017-11-06 20:35:04 +02:00
|
|
|
display: 'inline-block',
|
|
|
|
verticalAlign: 'top',
|
|
|
|
};
|
|
|
|
|
2017-11-30 01:03:10 +02:00
|
|
|
this.styles_.prompt = {
|
|
|
|
width: width,
|
|
|
|
height: height,
|
2017-11-08 19:51:55 +02:00
|
|
|
};
|
|
|
|
|
2018-02-27 22:04:38 +02:00
|
|
|
this.styles_.modalLayer = Object.assign({}, theme.textStyle, {
|
|
|
|
zIndex: 10000,
|
|
|
|
position: 'absolute',
|
|
|
|
top: 0,
|
|
|
|
left: 0,
|
2018-03-23 19:59:18 +02:00
|
|
|
backgroundColor: theme.backgroundColor,
|
2018-02-27 22:04:38 +02:00
|
|
|
width: width - 20,
|
|
|
|
height: height - 20,
|
|
|
|
padding: 10,
|
|
|
|
});
|
|
|
|
|
2017-11-30 01:03:10 +02:00
|
|
|
return this.styles_;
|
|
|
|
}
|
|
|
|
|
2020-03-13 19:42:50 +02:00
|
|
|
renderNotification(theme, styles) {
|
|
|
|
if (!this.messageBoxVisible()) return null;
|
|
|
|
|
|
|
|
const onViewStatusScreen = () => {
|
|
|
|
this.props.dispatch({
|
|
|
|
type: 'NAV_GO',
|
|
|
|
routeName: 'Status',
|
|
|
|
});
|
|
|
|
};
|
|
|
|
|
|
|
|
const onViewEncryptionConfigScreen = () => {
|
|
|
|
this.props.dispatch({
|
|
|
|
type: 'NAV_GO',
|
|
|
|
routeName: 'Config',
|
|
|
|
props: {
|
|
|
|
defaultSection: 'encryption',
|
|
|
|
},
|
|
|
|
});
|
|
|
|
};
|
|
|
|
|
|
|
|
let msg = null;
|
|
|
|
if (this.props.hasDisabledSyncItems) {
|
|
|
|
msg = (
|
|
|
|
<span>
|
|
|
|
{_('Some items cannot be synchronised.')}{' '}
|
|
|
|
<a href="#" onClick={() => onViewStatusScreen()}>
|
|
|
|
{_('View them now')}
|
|
|
|
</a>
|
|
|
|
</span>
|
|
|
|
);
|
|
|
|
} else if (this.props.hasDisabledEncryptionItems) {
|
|
|
|
msg = (
|
|
|
|
<span>
|
|
|
|
{_('Some items cannot be decrypted.')}{' '}
|
|
|
|
<a href="#" onClick={() => onViewStatusScreen()}>
|
|
|
|
{_('View them now')}
|
|
|
|
</a>
|
|
|
|
</span>
|
|
|
|
);
|
|
|
|
} else if (this.props.showMissingMasterKeyMessage) {
|
|
|
|
msg = (
|
|
|
|
<span>
|
|
|
|
{_('One or more master keys need a password.')}{' '}
|
|
|
|
<a href="#" onClick={() => onViewEncryptionConfigScreen()}>
|
|
|
|
{_('Set the password')}
|
|
|
|
</a>
|
|
|
|
</span>
|
|
|
|
);
|
|
|
|
} else if (this.props.showNeedUpgradingMasterKeyMessage) {
|
|
|
|
msg = (
|
|
|
|
<span>
|
|
|
|
{_('One of your master keys use an obsolete encryption method.')}{' '}
|
|
|
|
<a href="#" onClick={() => onViewEncryptionConfigScreen()}>
|
|
|
|
{_('View them now')}
|
|
|
|
</a>
|
|
|
|
</span>
|
|
|
|
);
|
|
|
|
} else if (this.props.showShouldReencryptMessage) {
|
|
|
|
msg = (
|
|
|
|
<span>
|
2020-03-14 02:52:28 +02:00
|
|
|
{_('The default encryption method has been changed, you should re-encrypt your data.')}{' '}
|
2020-03-13 19:42:50 +02:00
|
|
|
<a href="#" onClick={() => onViewEncryptionConfigScreen()}>
|
|
|
|
{_('More info')}
|
|
|
|
</a>
|
|
|
|
</span>
|
|
|
|
);
|
|
|
|
}
|
|
|
|
|
|
|
|
return (
|
|
|
|
<div style={styles.messageBox}>
|
|
|
|
<span style={theme.textStyle}>{msg}</span>
|
|
|
|
</div>
|
|
|
|
);
|
|
|
|
}
|
|
|
|
|
|
|
|
messageBoxVisible() {
|
|
|
|
return this.props.hasDisabledSyncItems || this.props.showMissingMasterKeyMessage || this.props.showNeedUpgradingMasterKeyMessage || this.props.showShouldReencryptMessage || this.props.hasDisabledEncryptionItems;
|
|
|
|
}
|
|
|
|
|
2017-11-30 01:03:10 +02:00
|
|
|
render() {
|
2018-11-08 00:37:13 +02:00
|
|
|
const theme = themeStyle(this.props.theme);
|
2019-07-29 14:13:23 +02:00
|
|
|
const style = Object.assign(
|
|
|
|
{
|
|
|
|
color: theme.color,
|
|
|
|
backgroundColor: theme.backgroundColor,
|
|
|
|
},
|
|
|
|
this.props.style
|
|
|
|
);
|
2017-11-30 01:03:10 +02:00
|
|
|
const promptOptions = this.state.promptOptions;
|
|
|
|
const folders = this.props.folders;
|
|
|
|
const notes = this.props.notes;
|
2018-04-15 17:50:39 +02:00
|
|
|
const sidebarVisibility = this.props.sidebarVisibility;
|
2019-10-30 11:40:34 +02:00
|
|
|
const noteListVisibility = this.props.noteListVisibility;
|
2020-03-13 19:42:50 +02:00
|
|
|
const styles = this.styles(this.props.theme, style.width, style.height, this.messageBoxVisible(), sidebarVisibility, noteListVisibility, this.props.sidebarWidth, this.props.noteListWidth);
|
2018-01-31 22:19:11 +02:00
|
|
|
const onConflictFolder = this.props.selectedFolderId === Folder.conflictFolderId();
|
2017-11-30 01:03:10 +02:00
|
|
|
|
2018-03-20 01:04:48 +02:00
|
|
|
const headerItems = [];
|
2017-11-10 22:34:36 +02:00
|
|
|
|
2018-04-15 17:50:39 +02:00
|
|
|
headerItems.push({
|
|
|
|
title: _('Toggle sidebar'),
|
|
|
|
iconName: 'fa-bars',
|
2018-04-16 15:32:33 +02:00
|
|
|
iconRotation: this.props.sidebarVisibility ? 0 : 90,
|
2019-07-29 14:13:23 +02:00
|
|
|
onClick: () => {
|
|
|
|
this.doCommand({ name: 'toggleSidebar' });
|
|
|
|
},
|
2018-04-15 17:50:39 +02:00
|
|
|
});
|
|
|
|
|
2019-10-30 11:40:34 +02:00
|
|
|
headerItems.push({
|
|
|
|
title: _('Toggle note list'),
|
|
|
|
iconName: 'fa-align-justify',
|
|
|
|
iconRotation: noteListVisibility ? 0 : 90,
|
|
|
|
onClick: () => {
|
|
|
|
this.doCommand({ name: 'toggleNoteList' });
|
|
|
|
},
|
|
|
|
});
|
|
|
|
|
2018-03-20 01:04:48 +02:00
|
|
|
headerItems.push({
|
2017-11-10 22:34:36 +02:00
|
|
|
title: _('New note'),
|
|
|
|
iconName: 'fa-file-o',
|
2018-01-31 22:19:11 +02:00
|
|
|
enabled: !!folders.length && !onConflictFolder,
|
2019-07-29 14:13:23 +02:00
|
|
|
onClick: () => {
|
|
|
|
this.doCommand({ name: 'newNote' });
|
|
|
|
},
|
2017-11-10 22:34:36 +02:00
|
|
|
});
|
2018-04-15 17:50:39 +02:00
|
|
|
|
2018-03-20 01:04:48 +02:00
|
|
|
headerItems.push({
|
2017-11-10 22:34:36 +02:00
|
|
|
title: _('New to-do'),
|
|
|
|
iconName: 'fa-check-square-o',
|
2018-01-31 22:19:11 +02:00
|
|
|
enabled: !!folders.length && !onConflictFolder,
|
2019-07-29 14:13:23 +02:00
|
|
|
onClick: () => {
|
|
|
|
this.doCommand({ name: 'newTodo' });
|
|
|
|
},
|
2017-11-10 22:34:36 +02:00
|
|
|
});
|
2017-11-08 19:51:55 +02:00
|
|
|
|
2018-03-20 01:04:48 +02:00
|
|
|
headerItems.push({
|
2017-11-10 22:34:36 +02:00
|
|
|
title: _('New notebook'),
|
2019-02-24 13:10:55 +02:00
|
|
|
iconName: 'fa-book',
|
2019-07-29 14:13:23 +02:00
|
|
|
onClick: () => {
|
|
|
|
this.doCommand({ name: 'newNotebook' });
|
|
|
|
},
|
2017-11-10 22:34:36 +02:00
|
|
|
});
|
2017-11-08 23:22:24 +02:00
|
|
|
|
2018-03-20 01:04:48 +02:00
|
|
|
headerItems.push({
|
2017-11-10 22:34:36 +02:00
|
|
|
title: _('Layout'),
|
|
|
|
iconName: 'fa-columns',
|
2017-11-13 02:23:12 +02:00
|
|
|
enabled: !!notes.length,
|
2019-07-29 14:13:23 +02:00
|
|
|
onClick: () => {
|
|
|
|
this.doCommand({ name: 'toggleVisiblePanes' });
|
|
|
|
},
|
2017-11-10 22:34:36 +02:00
|
|
|
});
|
2017-11-08 19:51:55 +02:00
|
|
|
|
2018-03-20 01:04:48 +02:00
|
|
|
headerItems.push({
|
|
|
|
title: _('Search...'),
|
|
|
|
iconName: 'fa-search',
|
2019-07-29 14:13:23 +02:00
|
|
|
onQuery: query => {
|
|
|
|
this.doCommand({ name: 'search', query: query });
|
|
|
|
},
|
2018-03-20 01:04:48 +02:00
|
|
|
type: 'search',
|
|
|
|
});
|
|
|
|
|
2017-11-30 01:03:10 +02:00
|
|
|
if (!this.promptOnClose_) {
|
|
|
|
this.promptOnClose_ = (answer, buttonType) => {
|
|
|
|
return this.state.promptOptions.onClose(answer, buttonType);
|
2019-07-29 14:13:23 +02:00
|
|
|
};
|
2017-11-30 01:03:10 +02:00
|
|
|
}
|
|
|
|
|
2020-03-13 19:42:50 +02:00
|
|
|
const messageComp = this.renderNotification(theme, styles);
|
2017-12-05 01:57:13 +02:00
|
|
|
|
2019-04-01 21:43:13 +02:00
|
|
|
const dialogInfo = PluginManager.instance().pluginDialogToShow(this.props.plugins);
|
2019-07-29 14:13:23 +02:00
|
|
|
const pluginDialog = !dialogInfo ? null : <dialogInfo.Dialog {...dialogInfo.props} />;
|
2019-04-01 21:43:13 +02:00
|
|
|
|
2018-02-27 22:04:38 +02:00
|
|
|
const modalLayerStyle = Object.assign({}, styles.modalLayer, { display: this.state.modalLayer.visible ? 'block' : 'none' });
|
|
|
|
|
2018-09-16 20:37:31 +02:00
|
|
|
const notePropertiesDialogOptions = this.state.notePropertiesDialogOptions;
|
2020-02-25 11:43:31 +02:00
|
|
|
const noteContentPropertiesDialogOptions = this.state.noteContentPropertiesDialogOptions;
|
2019-12-13 03:16:34 +02:00
|
|
|
const shareNoteDialogOptions = this.state.shareNoteDialogOptions;
|
2019-11-06 23:51:08 +02:00
|
|
|
const keyboardMode = Setting.value('editor.keyboardMode');
|
2018-09-16 20:37:31 +02:00
|
|
|
|
2020-03-10 01:24:57 +02:00
|
|
|
const isWYSIWYG = this.props.noteVisiblePanes.length && this.props.noteVisiblePanes[0] === 'wysiwyg';
|
|
|
|
const noteTextComp = isWYSIWYG ?
|
|
|
|
<NoteText2 editor="TinyMCE" style={styles.noteText} keyboardMode={keyboardMode} visiblePanes={this.props.noteVisiblePanes} />
|
|
|
|
:
|
|
|
|
<NoteText style={styles.noteText} keyboardMode={keyboardMode} visiblePanes={this.props.noteVisiblePanes} />;
|
|
|
|
|
2017-11-06 20:35:04 +02:00
|
|
|
return (
|
|
|
|
<div style={style}>
|
2018-02-27 22:04:38 +02:00
|
|
|
<div style={modalLayerStyle}>{this.state.modalLayer.message}</div>
|
|
|
|
|
2020-02-25 11:43:31 +02:00
|
|
|
{noteContentPropertiesDialogOptions.visible && <NoteContentPropertiesDialog theme={this.props.theme} onClose={this.noteContentPropertiesDialog_close} text={noteContentPropertiesDialogOptions.text} lines={noteContentPropertiesDialogOptions.lines}/>}
|
2019-07-29 14:13:23 +02:00
|
|
|
{notePropertiesDialogOptions.visible && <NotePropertiesDialog theme={this.props.theme} noteId={notePropertiesDialogOptions.noteId} onClose={this.notePropertiesDialog_close} onRevisionLinkClick={notePropertiesDialogOptions.onRevisionLinkClick} />}
|
2019-12-13 03:16:34 +02:00
|
|
|
{shareNoteDialogOptions.visible && <ShareNoteDialog theme={this.props.theme} noteIds={shareNoteDialogOptions.noteIds} onClose={this.shareNoteDialog_close} />}
|
2019-07-29 14:13:23 +02:00
|
|
|
|
|
|
|
<PromptDialog autocomplete={promptOptions && 'autocomplete' in promptOptions ? promptOptions.autocomplete : null} defaultValue={promptOptions && promptOptions.value ? promptOptions.value : ''} theme={this.props.theme} style={styles.prompt} onClose={this.promptOnClose_} label={promptOptions ? promptOptions.label : ''} description={promptOptions ? promptOptions.description : null} visible={!!this.state.promptOptions} buttons={promptOptions && 'buttons' in promptOptions ? promptOptions.buttons : null} inputType={promptOptions && 'inputType' in promptOptions ? promptOptions.inputType : null} />
|
2018-09-16 20:37:31 +02:00
|
|
|
|
2018-03-20 01:04:48 +02:00
|
|
|
<Header style={styles.header} showBackButton={false} items={headerItems} />
|
2017-12-05 01:57:13 +02:00
|
|
|
{messageComp}
|
2017-11-30 01:03:10 +02:00
|
|
|
<SideBar style={styles.sideBar} />
|
2019-07-29 14:13:23 +02:00
|
|
|
<VerticalResizer style={styles.verticalResizer} onDrag={this.sidebar_onDrag} />
|
2017-11-30 01:03:10 +02:00
|
|
|
<NoteList style={styles.noteList} />
|
2019-07-29 14:13:23 +02:00
|
|
|
<VerticalResizer style={styles.verticalResizer} onDrag={this.noteList_onDrag} />
|
2020-03-10 01:24:57 +02:00
|
|
|
{noteTextComp}
|
2019-07-29 14:13:23 +02:00
|
|
|
{pluginDialog}
|
2017-11-06 20:35:04 +02:00
|
|
|
</div>
|
|
|
|
);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2019-07-29 14:13:23 +02:00
|
|
|
const mapStateToProps = state => {
|
2017-11-06 22:54:58 +02:00
|
|
|
return {
|
2017-11-10 22:34:36 +02:00
|
|
|
theme: state.settings.theme,
|
2017-11-11 19:36:47 +02:00
|
|
|
windowCommand: state.windowCommand,
|
2017-11-12 19:02:20 +02:00
|
|
|
noteVisiblePanes: state.noteVisiblePanes,
|
2018-04-15 17:50:39 +02:00
|
|
|
sidebarVisibility: state.sidebarVisibility,
|
2019-10-30 11:40:34 +02:00
|
|
|
noteListVisibility: state.noteListVisibility,
|
2017-11-13 02:23:12 +02:00
|
|
|
folders: state.folders,
|
|
|
|
notes: state.notes,
|
2017-12-05 20:56:39 +02:00
|
|
|
hasDisabledSyncItems: state.hasDisabledSyncItems,
|
2020-03-13 19:42:50 +02:00
|
|
|
hasDisabledEncryptionItems: state.hasDisabledEncryptionItems,
|
2017-12-22 20:50:27 +02:00
|
|
|
showMissingMasterKeyMessage: state.notLoadedMasterKeys.length && state.masterKeys.length,
|
2020-03-13 19:42:50 +02:00
|
|
|
showNeedUpgradingMasterKeyMessage: !!EncryptionService.instance().masterKeysThatNeedUpgrading(state.masterKeys).length,
|
|
|
|
showShouldReencryptMessage: state.settings['encryption.shouldReencrypt'] >= Setting.SHOULD_REENCRYPT_YES,
|
2018-01-31 22:19:11 +02:00
|
|
|
selectedFolderId: state.selectedFolderId,
|
2019-02-16 03:12:43 +02:00
|
|
|
sidebarWidth: state.settings['style.sidebar.width'],
|
|
|
|
noteListWidth: state.settings['style.noteList.width'],
|
2019-03-15 23:57:58 +02:00
|
|
|
selectedNoteId: state.selectedNoteIds.length === 1 ? state.selectedNoteIds[0] : null,
|
2019-04-01 21:43:13 +02:00
|
|
|
plugins: state.plugins,
|
2019-07-20 23:13:10 +02:00
|
|
|
templates: state.templates,
|
2017-11-06 22:54:58 +02:00
|
|
|
};
|
2017-11-06 20:35:04 +02:00
|
|
|
};
|
|
|
|
|
|
|
|
const MainScreen = connect(mapStateToProps)(MainScreenComponent);
|
|
|
|
|
2018-04-15 17:50:39 +02:00
|
|
|
module.exports = { MainScreen };
|