mirror of
https://github.com/laurent22/joplin.git
synced 2024-12-24 10:27:10 +02:00
All: Allow sorting notes by various fields
This commit is contained in:
parent
74d255c056
commit
8a96cf3434
@ -175,6 +175,22 @@ class Application extends BaseApplication {
|
||||
updateMenu(screen) {
|
||||
if (this.lastMenuScreen_ === screen) return;
|
||||
|
||||
const sortNoteItems = [];
|
||||
const sortNoteOptions = Setting.enumOptions('notes.sortOrder.field');
|
||||
for (let field in sortNoteOptions) {
|
||||
if (!sortNoteOptions.hasOwnProperty(field)) continue;
|
||||
sortNoteItems.push({
|
||||
label: sortNoteOptions[field],
|
||||
screens: ['Main'],
|
||||
type: 'checkbox',
|
||||
checked: Setting.value('notes.sortOrder.field') === field,
|
||||
click: () => {
|
||||
Setting.setValue('notes.sortOrder.field', field);
|
||||
this.refreshMenu();
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
const template = [
|
||||
{
|
||||
label: _('File'),
|
||||
@ -287,6 +303,29 @@ class Application extends BaseApplication {
|
||||
name: 'toggleVisiblePanes',
|
||||
});
|
||||
}
|
||||
}, {
|
||||
type: 'separator',
|
||||
screens: ['Main'],
|
||||
}, {
|
||||
label: Setting.settingMetadata('notes.sortOrder.field').label(),
|
||||
screens: ['Main'],
|
||||
submenu: sortNoteItems,
|
||||
}, {
|
||||
label: Setting.settingMetadata('notes.sortOrder.reverse').label(),
|
||||
type: 'checkbox',
|
||||
checked: Setting.setValue('notes.sortOrder.reverse'),
|
||||
screens: ['Main'],
|
||||
click: () => {
|
||||
Setting.setValue('notes.sortOrder.reverse', !Setting.value('notes.sortOrder.reverse'));
|
||||
},
|
||||
}, {
|
||||
label: Setting.settingMetadata('uncompletedTodosOnTop').label(),
|
||||
type: 'checkbox',
|
||||
checked: Setting.setValue('uncompletedTodosOnTop'),
|
||||
screens: ['Main'],
|
||||
click: () => {
|
||||
Setting.setValue('uncompletedTodosOnTop', !Setting.value('uncompletedTodosOnTop'));
|
||||
},
|
||||
}],
|
||||
}, {
|
||||
label: _('Tools'),
|
||||
|
@ -604,7 +604,7 @@ class NoteTextComponent extends React.Component {
|
||||
let bodyToRender = body;
|
||||
if (!bodyToRender.trim() && visiblePanes.indexOf('viewer') >= 0 && visiblePanes.indexOf('editor') < 0) {
|
||||
// Fixes https://github.com/laurent22/joplin/issues/217
|
||||
bodyToRender = '*' + _('This not has no content. Click on "%s" to toggle the editor and edit the note.', _('Layout')) + '*';
|
||||
bodyToRender = '*' + _('This note has no content. Click on "%s" to toggle the editor and edit the note.', _('Layout')) + '*';
|
||||
}
|
||||
|
||||
const html = this.mdToHtml().render(bodyToRender, theme, mdOptions);
|
||||
|
@ -1,5 +1,5 @@
|
||||
const { createStore, applyMiddleware } = require('redux');
|
||||
const { reducer, defaultState } = require('lib/reducer.js');
|
||||
const { reducer, defaultState, stateUtils } = require('lib/reducer.js');
|
||||
const { JoplinDatabase } = require('lib/joplin-database.js');
|
||||
const { Database } = require('lib/database.js');
|
||||
const { FoldersScreenUtils } = require('lib/folders-screen-utils.js');
|
||||
@ -184,8 +184,9 @@ class BaseApplication {
|
||||
this.logger().debug('Refreshing notes:', parentType, parentId);
|
||||
|
||||
let options = {
|
||||
order: state.notesOrder,
|
||||
order: stateUtils.notesOrder(state.settings),
|
||||
uncompletedTodosOnTop: Setting.value('uncompletedTodosOnTop'),
|
||||
caseInsensitive: true,
|
||||
};
|
||||
|
||||
const source = JSON.stringify({
|
||||
@ -255,14 +256,31 @@ class BaseApplication {
|
||||
|
||||
const result = next(action);
|
||||
const newState = store.getState();
|
||||
let refreshNotes = false;
|
||||
|
||||
if (action.type == 'FOLDER_SELECT' || action.type === 'FOLDER_DELETE') {
|
||||
Setting.setValue('activeFolderId', newState.selectedFolderId);
|
||||
this.currentFolder_ = newState.selectedFolderId ? await Folder.load(newState.selectedFolderId) : null;
|
||||
await this.refreshNotes(newState);
|
||||
refreshNotes = true;
|
||||
}
|
||||
|
||||
if (this.hasGui() && action.type == 'SETTING_UPDATE_ONE' && action.key == 'uncompletedTodosOnTop' || action.type == 'SETTING_UPDATE_ALL') {
|
||||
if (this.hasGui() && ((action.type == 'SETTING_UPDATE_ONE' && action.key == 'uncompletedTodosOnTop') || action.type == 'SETTING_UPDATE_ALL')) {
|
||||
refreshNotes = true;
|
||||
}
|
||||
|
||||
if (this.hasGui() && ((action.type == 'SETTING_UPDATE_ONE' && action.key.indexOf('notes.sortOrder') === 0) || action.type == 'SETTING_UPDATE_ALL')) {
|
||||
refreshNotes = true;
|
||||
}
|
||||
|
||||
if (action.type == 'TAG_SELECT' || action.type === 'TAG_DELETE') {
|
||||
refreshNotes = true;
|
||||
}
|
||||
|
||||
if (action.type == 'SEARCH_SELECT' || action.type === 'SEARCH_DELETE') {
|
||||
refreshNotes = true;
|
||||
}
|
||||
|
||||
if (refreshNotes) {
|
||||
await this.refreshNotes(newState);
|
||||
}
|
||||
|
||||
@ -288,14 +306,6 @@ class BaseApplication {
|
||||
}
|
||||
}
|
||||
|
||||
if (action.type == 'TAG_SELECT' || action.type === 'TAG_DELETE') {
|
||||
await this.refreshNotes(newState);
|
||||
}
|
||||
|
||||
if (action.type == 'SEARCH_SELECT' || action.type === 'SEARCH_DELETE') {
|
||||
await this.refreshNotes(newState);
|
||||
}
|
||||
|
||||
if (action.type === 'NOTE_UPDATE_ONE') {
|
||||
// If there is a conflict, we refresh the folders so as to display "Conflicts" folder
|
||||
if (action.note && action.note.is_conflict) {
|
||||
@ -303,11 +313,6 @@ class BaseApplication {
|
||||
}
|
||||
}
|
||||
|
||||
// if (action.type === 'NOTE_DELETE') {
|
||||
// // Update folders if a note is deleted in case the deleted note was a conflict
|
||||
// await FoldersScreenUtils.refreshFolders();
|
||||
// }
|
||||
|
||||
if (this.hasGui() && action.type == 'SETTING_UPDATE_ONE' && action.key == 'sync.interval' || action.type == 'SETTING_UPDATE_ALL') {
|
||||
reg.setupRecurrentSync();
|
||||
}
|
||||
|
81
ReactNativeClient/lib/components/ModalDialog.js
Normal file
81
ReactNativeClient/lib/components/ModalDialog.js
Normal file
@ -0,0 +1,81 @@
|
||||
const React = require('react');
|
||||
const { Text, Modal, View, StyleSheet, Button } = require('react-native');
|
||||
const { themeStyle } = require('lib/components/global-style.js');
|
||||
const { _ } = require('lib/locale');
|
||||
|
||||
class ModalDialog extends React.Component {
|
||||
|
||||
constructor() {
|
||||
super();
|
||||
this.styles_ = {};
|
||||
}
|
||||
|
||||
styles() {
|
||||
const themeId = this.props.theme;
|
||||
const theme = themeStyle(themeId);
|
||||
|
||||
if (this.styles_[themeId]) return this.styles_[themeId];
|
||||
this.styles_ = {};
|
||||
|
||||
let styles = {
|
||||
modalWrapper: {
|
||||
flex: 1,
|
||||
justifyContent: 'center',
|
||||
},
|
||||
modalContentWrapper: {
|
||||
flex:1,
|
||||
flexDirection: 'column',
|
||||
backgroundColor: theme.backgroundColor,
|
||||
borderWidth: 1,
|
||||
borderColor:theme.dividerColor,
|
||||
margin: 20,
|
||||
padding: 10,
|
||||
},
|
||||
modalContentWrapper2: {
|
||||
paddingTop: 10,
|
||||
flex:1,
|
||||
},
|
||||
title: {
|
||||
borderBottomWidth: 1,
|
||||
borderBottomColor: theme.dividerColor,
|
||||
paddingBottom: 10,
|
||||
},
|
||||
buttonRow: {
|
||||
flexDirection: 'row',
|
||||
borderTopWidth: 1,
|
||||
borderTopColor: theme.dividerColor,
|
||||
paddingTop: 10,
|
||||
},
|
||||
};
|
||||
|
||||
this.styles_[themeId] = StyleSheet.create(styles);
|
||||
return this.styles_[themeId];
|
||||
}
|
||||
|
||||
render() {
|
||||
const ContentComponent = this.props.ContentComponent;
|
||||
|
||||
return (
|
||||
<View style={this.styles().modalWrapper}>
|
||||
<Modal transparent={true} visible={true} onRequestClose={() => { }} >
|
||||
<View style={this.styles().modalContentWrapper}>
|
||||
<Text style={this.styles().title}>Title</Text>
|
||||
<View style={this.styles().modalContentWrapper2}>
|
||||
{ContentComponent}
|
||||
</View>
|
||||
<View style={this.styles().buttonRow}>
|
||||
<View style={{flex:1}}>
|
||||
<Button title={_('OK')} onPress={() => {}}></Button>
|
||||
</View>
|
||||
<View style={{flex:1, marginLeft: 5}}>
|
||||
<Button title={_('Cancel')} onPress={() => {}}></Button>
|
||||
</View>
|
||||
</View>
|
||||
</View>
|
||||
</Modal>
|
||||
</View>
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
module.exports = ModalDialog;
|
@ -283,6 +283,16 @@ class ScreenHeaderComponent extends Component {
|
||||
);
|
||||
}
|
||||
|
||||
function sortButton(styles, onPress) {
|
||||
return (
|
||||
<TouchableOpacity onPress={onPress}>
|
||||
<View style={styles.iconButton}>
|
||||
<Icon name='md-funnel' style={styles.topIcon} />
|
||||
</View>
|
||||
</TouchableOpacity>
|
||||
);
|
||||
}
|
||||
|
||||
let key = 0;
|
||||
let menuOptionComponents = [];
|
||||
|
||||
@ -424,6 +434,7 @@ class ScreenHeaderComponent extends Component {
|
||||
const backButtonComp = backButton(this.styles(), () => this.backButton_press(), !this.props.historyCanGoBack);
|
||||
const searchButtonComp = this.props.noteSelectionEnabled ? null : searchButton(this.styles(), () => this.searchButton_press());
|
||||
const deleteButtonComp = this.props.noteSelectionEnabled ? deleteButton(this.styles(), () => this.deleteButton_press()) : null;
|
||||
const sortButtonComp = this.props.sortButton_press ? sortButton(this.styles(), () => this.props.sortButton_press()) : null;
|
||||
const windowHeight = Dimensions.get('window').height - 50;
|
||||
|
||||
const menuComp = (
|
||||
@ -448,6 +459,7 @@ class ScreenHeaderComponent extends Component {
|
||||
{ titleComp }
|
||||
{ searchButtonComp }
|
||||
{ deleteButtonComp }
|
||||
{ sortButtonComp }
|
||||
{ menuComp }
|
||||
</View>
|
||||
{ warningComp }
|
||||
|
@ -65,9 +65,9 @@ class NoteScreenComponent extends BaseScreenComponent {
|
||||
const saveDialog = async () => {
|
||||
if (this.isModified()) {
|
||||
let buttonId = await dialogs.pop(this, _('This note has been modified:'), [
|
||||
{ title: _('Save changes'), id: 'save' },
|
||||
{ title: _('Discard changes'), id: 'discard' },
|
||||
{ title: _('Cancel'), id: 'cancel' },
|
||||
{ text: _('Save changes'), id: 'save' },
|
||||
{ text: _('Discard changes'), id: 'discard' },
|
||||
{ text: _('Cancel'), id: 'cancel' },
|
||||
]);
|
||||
|
||||
if (buttonId == 'cancel') return true;
|
||||
|
@ -1,5 +1,6 @@
|
||||
const React = require('react'); const Component = React.Component;
|
||||
const { View, Button } = require('react-native');
|
||||
const { View, Button, Text } = require('react-native');
|
||||
const { stateUtils } = require('lib/reducer.js');
|
||||
const { connect } = require('react-redux');
|
||||
const { reg } = require('lib/registry.js');
|
||||
const { Log } = require('lib/log.js');
|
||||
@ -10,7 +11,7 @@ const Note = require('lib/models/Note.js');
|
||||
const Setting = require('lib/models/Setting.js');
|
||||
const { themeStyle } = require('lib/components/global-style.js');
|
||||
const { ScreenHeader } = require('lib/components/screen-header.js');
|
||||
const { MenuOption, Text } = require('react-native-popup-menu');
|
||||
const { MenuOption } = require('react-native-popup-menu');
|
||||
const { _ } = require('lib/locale.js');
|
||||
const { ActionButton } = require('lib/components/action-button.js');
|
||||
const { dialogs } = require('lib/dialogs.js');
|
||||
@ -23,6 +24,43 @@ class NotesScreenComponent extends BaseScreenComponent {
|
||||
return { header: null };
|
||||
}
|
||||
|
||||
constructor() {
|
||||
super();
|
||||
|
||||
this.sortButton_press = async () => {
|
||||
const buttons = [];
|
||||
const sortNoteOptions = Setting.enumOptions('notes.sortOrder.field');
|
||||
|
||||
const makeCheckboxText = function(selected, sign, label) {
|
||||
const s = sign === 'tick' ? '✓' : '⬤'
|
||||
return (selected ? (s + ' ') : '') + label;
|
||||
}
|
||||
|
||||
for (let field in sortNoteOptions) {
|
||||
if (!sortNoteOptions.hasOwnProperty(field)) continue;
|
||||
buttons.push({
|
||||
text: makeCheckboxText(Setting.value('notes.sortOrder.field') === field, 'bullet', sortNoteOptions[field]),
|
||||
id: { name: 'notes.sortOrder.field', value: field },
|
||||
});
|
||||
}
|
||||
|
||||
buttons.push({
|
||||
text: makeCheckboxText(Setting.value('notes.sortOrder.reverse'), 'tick', '[ ' + Setting.settingMetadata('notes.sortOrder.reverse').label() + ' ]'),
|
||||
id: { name: 'notes.sortOrder.reverse', value: !Setting.value('notes.sortOrder.reverse') },
|
||||
});
|
||||
|
||||
buttons.push({
|
||||
text: makeCheckboxText(Setting.value('uncompletedTodosOnTop'), 'tick', '[ ' + Setting.settingMetadata('uncompletedTodosOnTop').label() + ' ]'),
|
||||
id: { name: 'uncompletedTodosOnTop', value: !Setting.value('uncompletedTodosOnTop') },
|
||||
});
|
||||
|
||||
const r = await dialogs.pop(this, Setting.settingMetadata('notes.sortOrder.field').label(), buttons);
|
||||
if (!r) return;
|
||||
|
||||
Setting.setValue(r.name, r.value);
|
||||
}
|
||||
}
|
||||
|
||||
async componentDidMount() {
|
||||
await this.refreshNotes();
|
||||
}
|
||||
@ -42,6 +80,7 @@ class NotesScreenComponent extends BaseScreenComponent {
|
||||
let options = {
|
||||
order: props.notesOrder,
|
||||
uncompletedTodosOnTop: props.uncompletedTodosOnTop,
|
||||
caseInsensitive: true,
|
||||
};
|
||||
|
||||
const parent = this.parentItem(props);
|
||||
@ -155,6 +194,7 @@ class NotesScreenComponent extends BaseScreenComponent {
|
||||
title={title}
|
||||
menuOptions={this.menuOptions()}
|
||||
parentComponent={thisComp}
|
||||
sortButton_press={this.sortButton_press}
|
||||
folderPickerOptions={{
|
||||
enabled: this.props.noteSelectionEnabled,
|
||||
mustSelect: true,
|
||||
@ -178,11 +218,11 @@ const NotesScreen = connect(
|
||||
selectedTagId: state.selectedTagId,
|
||||
notesParentType: state.notesParentType,
|
||||
notes: state.notes,
|
||||
notesOrder: state.notesOrder,
|
||||
notesSource: state.notesSource,
|
||||
uncompletedTodosOnTop: state.settings.uncompletedTodosOnTop,
|
||||
theme: state.settings.theme,
|
||||
noteSelectionEnabled: state.noteSelectionEnabled,
|
||||
notesOrder: stateUtils.notesOrder(state.settings),
|
||||
};
|
||||
}
|
||||
)(NotesScreenComponent)
|
||||
|
@ -33,17 +33,20 @@ dialogs.confirm = (parentComponent, message) => {
|
||||
});
|
||||
};
|
||||
|
||||
dialogs.pop = (parentComponent, message, buttons) => {
|
||||
dialogs.pop = (parentComponent, message, buttons, options = null) => {
|
||||
if (!parentComponent) throw new Error('parentComponent is required');
|
||||
if (!('dialogbox' in parentComponent)) throw new Error('A "dialogbox" component must be defined on the parent component!');
|
||||
|
||||
if (!options) options = {};
|
||||
if (!('buttonFlow' in options)) options.buttonFlow = 'auto';
|
||||
|
||||
return new Promise((resolve, reject) => {
|
||||
Keyboard.dismiss();
|
||||
|
||||
let btns = [];
|
||||
for (let i = 0; i < buttons.length; i++) {
|
||||
btns.push({
|
||||
text: buttons[i].title,
|
||||
text: buttons[i].text,
|
||||
callback: () => {
|
||||
parentComponent.dialogbox.close();
|
||||
resolve(buttons[i].id);
|
||||
@ -54,6 +57,7 @@ dialogs.pop = (parentComponent, message, buttons) => {
|
||||
parentComponent.dialogbox.pop({
|
||||
content: message,
|
||||
btns: btns,
|
||||
buttonFlow: options.buttonFlow,
|
||||
});
|
||||
});
|
||||
}
|
||||
|
@ -15,6 +15,16 @@ class Note extends BaseItem {
|
||||
return 'notes';
|
||||
}
|
||||
|
||||
static fieldToLabel(field) {
|
||||
const fieldsToLabels = {
|
||||
title: 'title',
|
||||
user_updated_time: 'updated date',
|
||||
user_created_time: 'created date',
|
||||
};
|
||||
|
||||
return field in fieldsToLabels ? fieldsToLabels[field] : field;
|
||||
}
|
||||
|
||||
static async serialize(note, type = null, shownKeys = null) {
|
||||
let fieldNames = this.fieldNames();
|
||||
fieldNames.push('type_');
|
||||
|
@ -5,6 +5,7 @@ const SyncTargetRegistry = require('lib/SyncTargetRegistry.js');
|
||||
const { time } = require('lib/time-utils.js');
|
||||
const { sprintf } = require('sprintf-js');
|
||||
const ObjectUtils = require('lib/ObjectUtils');
|
||||
const { toTitleCase } = require('lib/string-utils.js');
|
||||
const { _, supportedLocalesToLanguages, defaultLocale } = require('lib/locale.js');
|
||||
|
||||
class Setting extends BaseModel {
|
||||
@ -20,6 +21,10 @@ class Setting extends BaseModel {
|
||||
static metadata() {
|
||||
if (this.metadata_) return this.metadata_;
|
||||
|
||||
// A "public" setting means that it will show up in the various config screens (or config command for the CLI tool), however
|
||||
// if if private a setting might still be handled and modified by the app. For instance, the settings related to sorting notes are not
|
||||
// public for the mobile and desktop apps because they are handled separately in menus.
|
||||
|
||||
this.metadata_ = {
|
||||
'activeFolderId': { value: '', type: Setting.TYPE_STRING, public: false },
|
||||
'firstStart': { value: true, type: Setting.TYPE_BOOL, public: false },
|
||||
@ -50,16 +55,17 @@ class Setting extends BaseModel {
|
||||
output[Setting.THEME_DARK] = _('Dark');
|
||||
return output;
|
||||
}},
|
||||
// 'logLevel': { value: Logger.LEVEL_INFO, type: Setting.TYPE_STRING, isEnum: true, public: true, label: () => _('Log level'), options: () => {
|
||||
// return Logger.levelEnum();
|
||||
// }},
|
||||
// Not used for now:
|
||||
// 'todoFilter': { value: 'all', type: Setting.TYPE_STRING, isEnum: true, public: false, appTypes: ['mobile'], label: () => _('Todo filter'), options: () => ({
|
||||
// all: _('Show all'),
|
||||
// recent: _('Non-completed and recently completed ones'),
|
||||
// nonCompleted: _('Non-completed ones only'),
|
||||
// })},
|
||||
'uncompletedTodosOnTop': { value: true, type: Setting.TYPE_BOOL, public: true, label: () => _('Show uncompleted to-dos on top of the lists') },
|
||||
'uncompletedTodosOnTop': { value: true, type: Setting.TYPE_BOOL, public: true, appTypes: ['cli'], label: () => _('Uncompleted to-dos on top') },
|
||||
'notes.sortOrder.field': { value: 'user_updated_time', type: Setting.TYPE_STRING, isEnum: true, public: true, appTypes: ['cli'], label: () => _('Sort notes by'), options: () => {
|
||||
const Note = require('lib/models/Note');
|
||||
const noteSortFields = ['user_updated_time', 'user_created_time', 'title'];
|
||||
const options = {};
|
||||
for (let i = 0; i < noteSortFields.length; i++) {
|
||||
options[noteSortFields[i]] = toTitleCase(Note.fieldToLabel(noteSortFields[i]));
|
||||
}
|
||||
return options;
|
||||
}},
|
||||
'notes.sortOrder.reverse': { value: true, type: Setting.TYPE_BOOL, public: true, label: () => _('Reverse sort order'), appTypes: ['cli'] },
|
||||
'trackLocation': { value: true, type: Setting.TYPE_BOOL, public: true, label: () => _('Save geo-location with notes') },
|
||||
'newTodoFocus': { value: 'title', type: Setting.TYPE_STRING, isEnum: true, public: true, appTypes: ['desktop'], label: () => _('When creating a new to-do:'), options: () => {
|
||||
return {
|
||||
|
@ -19,19 +19,24 @@ const defaultState = {
|
||||
showSideMenu: false,
|
||||
screens: {},
|
||||
historyCanGoBack: false,
|
||||
notesOrder: [
|
||||
{ by: 'user_updated_time', dir: 'DESC' },
|
||||
],
|
||||
syncStarted: false,
|
||||
syncReport: {},
|
||||
searchQuery: '',
|
||||
settings: {},
|
||||
appState: 'starting',
|
||||
//windowContentSize: { width: 0, height: 0 },
|
||||
hasDisabledSyncItems: false,
|
||||
newNote: null,
|
||||
};
|
||||
|
||||
const stateUtils = {};
|
||||
|
||||
stateUtils.notesOrder = function(stateSettings) {
|
||||
return [{
|
||||
by: stateSettings['notes.sortOrder.field'],
|
||||
dir: stateSettings['notes.sortOrder.reverse'] ? 'DESC' : 'ASC',
|
||||
}];
|
||||
}
|
||||
|
||||
function arrayHasEncryptedItems(array) {
|
||||
for (let i = 0; i < array.length; i++) {
|
||||
if (!!array[i].encryption_applied) return true;
|
||||
@ -90,8 +95,6 @@ function handleItemDelete(state, action) {
|
||||
}
|
||||
|
||||
function updateOneItem(state, action) {
|
||||
// let newItems = action.type === 'TAG_UPDATE_ONE' ? state.tags.splice(0) : state.folders.splice(0);
|
||||
// let item = action.type === 'TAG_UPDATE_ONE' ? action.tag : action.folder;
|
||||
let itemsKey = null;
|
||||
if (action.type === 'TAG_UPDATE_ONE') itemsKey = 'tags';
|
||||
if (action.type === 'FOLDER_UPDATE_ONE') itemsKey = 'folders';
|
||||
@ -116,12 +119,6 @@ function updateOneItem(state, action) {
|
||||
|
||||
newState[itemsKey] = newItems;
|
||||
|
||||
// if (action.type === 'TAG_UPDATE_ONE') {
|
||||
// newState.tags = newItems;
|
||||
// } else {
|
||||
// newState.folders = newItems;
|
||||
// }
|
||||
|
||||
return newState;
|
||||
}
|
||||
|
||||
@ -316,7 +313,8 @@ const reducer = (state = defaultState, action) => {
|
||||
}
|
||||
}
|
||||
|
||||
newNotes = Note.sortNotes(newNotes, state.notesOrder, newState.settings.uncompletedTodosOnTop);
|
||||
//newNotes = Note.sortNotes(newNotes, state.notesOrder, newState.settings.uncompletedTodosOnTop);
|
||||
newNotes = Note.sortNotes(newNotes, stateUtils.notesOrder(state.settings), newState.settings.uncompletedTodosOnTop);
|
||||
newState = Object.assign({}, state);
|
||||
newState.notes = newNotes;
|
||||
|
||||
@ -481,4 +479,4 @@ const reducer = (state = defaultState, action) => {
|
||||
return newState;
|
||||
}
|
||||
|
||||
module.exports = { reducer, defaultState };
|
||||
module.exports = { reducer, defaultState, stateUtils };
|
@ -201,4 +201,9 @@ function padLeft(string, length, padString) {
|
||||
return string;
|
||||
}
|
||||
|
||||
module.exports = { removeDiacritics, escapeFilename, wrap, splitCommandString, padLeft };
|
||||
function toTitleCase(string) {
|
||||
if (!string) return string;
|
||||
return string.charAt(0).toUpperCase() + string.slice(1);
|
||||
}
|
||||
|
||||
module.exports = { removeDiacritics, escapeFilename, wrap, splitCommandString, padLeft, toTitleCase };
|
@ -21,6 +21,7 @@
|
||||
"docs/*.html",
|
||||
"docs/*.svg",
|
||||
"ReactNativeClient/lib/mime-utils.js",
|
||||
"_mydocs/EnexSamples/*.enex",
|
||||
],
|
||||
"folder_exclude_patterns":
|
||||
[
|
||||
|
Loading…
Reference in New Issue
Block a user