mirror of
https://github.com/laurent22/joplin.git
synced 2025-01-26 18:58:21 +02:00
All: Handle saving collapsed states of sub-notebook
This commit is contained in:
parent
567596643c
commit
da6fdad2de
@ -615,6 +615,11 @@ class Application extends BaseApplication {
|
|||||||
id: Setting.value('activeFolderId'),
|
id: Setting.value('activeFolderId'),
|
||||||
});
|
});
|
||||||
|
|
||||||
|
this.store().dispatch({
|
||||||
|
type: 'FOLDER_SET_COLLAPSED_ALL',
|
||||||
|
ids: Setting.value('collapsedFolderIds'),
|
||||||
|
});
|
||||||
|
|
||||||
// Note: Auto-update currently doesn't work in Linux: it downloads the update
|
// Note: Auto-update currently doesn't work in Linux: it downloads the update
|
||||||
// but then doesn't install it on exit.
|
// but then doesn't install it on exit.
|
||||||
if (shim.isWindows() || shim.isMac()) {
|
if (shim.isWindows() || shim.isMac()) {
|
||||||
|
@ -54,6 +54,15 @@ class SideBarComponent extends React.Component {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
|
this.onFolderToggleClick_ = async (event) => {
|
||||||
|
const folderId = event.currentTarget.getAttribute('folderid');
|
||||||
|
|
||||||
|
this.props.dispatch({
|
||||||
|
type: 'FOLDER_TOGGLE',
|
||||||
|
id: folderId,
|
||||||
|
});
|
||||||
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
style() {
|
style() {
|
||||||
@ -68,7 +77,7 @@ class SideBarComponent extends React.Component {
|
|||||||
listItemContainer: {
|
listItemContainer: {
|
||||||
boxSizing: "border-box",
|
boxSizing: "border-box",
|
||||||
height: itemHeight,
|
height: itemHeight,
|
||||||
paddingLeft: 14,
|
// paddingLeft: 14,
|
||||||
display: "flex",
|
display: "flex",
|
||||||
alignItems: "stretch",
|
alignItems: "stretch",
|
||||||
},
|
},
|
||||||
@ -272,19 +281,22 @@ class SideBarComponent extends React.Component {
|
|||||||
const itemTitle = Folder.displayTitle(folder);
|
const itemTitle = Folder.displayTitle(folder);
|
||||||
|
|
||||||
let containerStyle = Object.assign({}, this.style().listItemContainer);
|
let containerStyle = Object.assign({}, this.style().listItemContainer);
|
||||||
containerStyle.paddingLeft = containerStyle.paddingLeft + depth * 10;
|
// containerStyle.paddingLeft = containerStyle.paddingLeft + depth * 10;
|
||||||
|
|
||||||
if (selected) containerStyle = Object.assign(containerStyle, this.style().listItemSelected);
|
if (selected) containerStyle = Object.assign(containerStyle, this.style().listItemSelected);
|
||||||
|
|
||||||
let expandLinkStyle = Object.assign({}, this.style().listItemExpandIcon);
|
let expandLinkStyle = Object.assign({}, this.style().listItemExpandIcon);
|
||||||
let expandIconStyle = {
|
let expandIconStyle = {
|
||||||
visibility: hasChildren ? 'visible' : 'hidden',
|
visibility: hasChildren ? 'visible' : 'hidden',
|
||||||
|
paddingLeft: 8 + depth * 10,
|
||||||
}
|
}
|
||||||
const expandIcon = <i style={expandIconStyle} className="fa fa-plus-square"></i>
|
|
||||||
const expandLink = hasChildren ? <a style={expandLinkStyle} href="#" onClick={() => console.info('click')}>{expandIcon}</a> : <span style={expandLinkStyle}>{expandIcon}</span>
|
const iconName = this.props.collapsedFolderIds.indexOf(folder.id) >= 0 ? 'fa-minus-square' : 'fa-plus-square';
|
||||||
|
const expandIcon = <i style={expandIconStyle} className={"fa " + iconName}></i>
|
||||||
|
const expandLink = hasChildren ? <a style={expandLinkStyle} href="#" folderid={folder.id} onClick={this.onFolderToggleClick_}>{expandIcon}</a> : <span style={expandLinkStyle}>{expandIcon}</span>
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<div style={containerStyle} key={folder.id} onDragStart={this.onFolderDragStart_} onDragOver={this.onFolderDragOver_} onDrop={this.onFolderDrop_} draggable={true} folderid={folder.id}>
|
<div className="list-item-container" style={containerStyle} key={folder.id} onDragStart={this.onFolderDragStart_} onDragOver={this.onFolderDragOver_} onDrop={this.onFolderDrop_} draggable={true} folderid={folder.id}>
|
||||||
{ expandLink }
|
{ expandLink }
|
||||||
<a
|
<a
|
||||||
className="list-item"
|
className="list-item"
|
||||||
@ -293,9 +305,11 @@ class SideBarComponent extends React.Component {
|
|||||||
data-type={BaseModel.TYPE_FOLDER}
|
data-type={BaseModel.TYPE_FOLDER}
|
||||||
onContextMenu={event => this.itemContextMenu(event)}
|
onContextMenu={event => this.itemContextMenu(event)}
|
||||||
style={style}
|
style={style}
|
||||||
|
folderid={folder.id}
|
||||||
onClick={() => {
|
onClick={() => {
|
||||||
this.folderItem_click(folder);
|
this.folderItem_click(folder);
|
||||||
}}
|
}}
|
||||||
|
onDoubleClick={this.onFolderToggleClick_}
|
||||||
>
|
>
|
||||||
{itemTitle}
|
{itemTitle}
|
||||||
</a>
|
</a>
|
||||||
@ -451,6 +465,7 @@ const mapStateToProps = state => {
|
|||||||
notesParentType: state.notesParentType,
|
notesParentType: state.notesParentType,
|
||||||
locale: state.settings.locale,
|
locale: state.settings.locale,
|
||||||
theme: state.settings.theme,
|
theme: state.settings.theme,
|
||||||
|
collapsedFolderIds: state.collapsedFolderIds,
|
||||||
};
|
};
|
||||||
};
|
};
|
||||||
|
|
||||||
|
@ -34,17 +34,15 @@ table td, table th {
|
|||||||
background-color: rgba(0,160,255,0.1) !important;
|
background-color: rgba(0,160,255,0.1) !important;
|
||||||
}
|
}
|
||||||
|
|
||||||
.side-bar .list-item:hover,
|
/*.side-bar .list-item:hover,
|
||||||
.side-bar .synchronize-button:hover {
|
.side-bar .synchronize-button:hover {
|
||||||
/*background-color: #453E53;*/
|
|
||||||
background-color: #01427B;
|
background-color: #01427B;
|
||||||
}
|
}
|
||||||
|
|
||||||
.side-bar .list-item:active,
|
.side-bar .list-item:active,
|
||||||
.side-bar .synchronize-button:active {
|
.side-bar .synchronize-button:active {
|
||||||
/*background-color: #564B6C;*/
|
|
||||||
background-color: #0465BB;
|
background-color: #0465BB;
|
||||||
}
|
}*/
|
||||||
|
|
||||||
.editor-toolbar .button:not(.disabled):hover,
|
.editor-toolbar .button:not(.disabled):hover,
|
||||||
.header .button:not(.disabled):hover {
|
.header .button:not(.disabled):hover {
|
||||||
|
@ -19,6 +19,7 @@ const BaseSyncTarget = require('lib/BaseSyncTarget.js');
|
|||||||
const { fileExtension } = require('lib/path-utils.js');
|
const { fileExtension } = require('lib/path-utils.js');
|
||||||
const { shim } = require('lib/shim.js');
|
const { shim } = require('lib/shim.js');
|
||||||
const { _, setLocale, defaultLocale, closestSupportedLocale } = require('lib/locale.js');
|
const { _, setLocale, defaultLocale, closestSupportedLocale } = require('lib/locale.js');
|
||||||
|
const reduxSharedMiddleware = require('lib/components/shared/reduxSharedMiddleware');
|
||||||
const os = require('os');
|
const os = require('os');
|
||||||
const fs = require('fs-extra');
|
const fs = require('fs-extra');
|
||||||
const JoplinError = require('lib/JoplinError');
|
const JoplinError = require('lib/JoplinError');
|
||||||
@ -270,6 +271,8 @@ class BaseApplication {
|
|||||||
const newState = store.getState();
|
const newState = store.getState();
|
||||||
let refreshNotes = false;
|
let refreshNotes = false;
|
||||||
|
|
||||||
|
reduxSharedMiddleware(store, next, action);
|
||||||
|
|
||||||
if (action.type == 'FOLDER_SELECT' || action.type === 'FOLDER_DELETE' || (action.type === 'SEARCH_UPDATE' && newState.notesParentType === 'Folder')) {
|
if (action.type == 'FOLDER_SELECT' || action.type === 'FOLDER_DELETE' || (action.type === 'SEARCH_UPDATE' && newState.notesParentType === 'Folder')) {
|
||||||
Setting.setValue('activeFolderId', newState.selectedFolderId);
|
Setting.setValue('activeFolderId', newState.selectedFolderId);
|
||||||
this.currentFolder_ = newState.selectedFolderId ? await Folder.load(newState.selectedFolderId) : null;
|
this.currentFolder_ = newState.selectedFolderId ? await Folder.load(newState.selectedFolderId) : null;
|
||||||
|
@ -0,0 +1,9 @@
|
|||||||
|
const reduxSharedMiddleware = function(store, next, action) {
|
||||||
|
const newState = store.getState();
|
||||||
|
|
||||||
|
if (action.type == 'FOLDER_SET_COLLAPSED' || action.type == 'FOLDER_TOGGLE') {
|
||||||
|
Setting.setValue('collapsedFolderIds', newState.collapsedFolderIds);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
module.exports = reduxSharedMiddleware;
|
@ -1,5 +1,6 @@
|
|||||||
const ArrayUtils = require('lib/ArrayUtils');
|
const ArrayUtils = require('lib/ArrayUtils');
|
||||||
const Folder = require('lib/models/Folder');
|
const Folder = require('lib/models/Folder');
|
||||||
|
const BaseModel = require('lib/BaseModel');
|
||||||
|
|
||||||
let shared = {};
|
let shared = {};
|
||||||
|
|
||||||
@ -11,11 +12,26 @@ function folderHasChildren_(folders, folderId) {
|
|||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
function folderIsVisible(folders, folderId, collapsedFolderIds) {
|
||||||
|
if (!collapsedFolderIds || !collapsedFolderIds.length) return true;
|
||||||
|
|
||||||
|
while (true) {
|
||||||
|
let folder = BaseModel.byId(folders, folderId);
|
||||||
|
if (!folder) throw new Error('No folder with id ' + folder.id);
|
||||||
|
if (!folder.parent_id) return true;
|
||||||
|
if (collapsedFolderIds.indexOf(folder.parent_id) >= 0) return false;
|
||||||
|
folderId = folder.parent_id;
|
||||||
|
}
|
||||||
|
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
function renderFoldersRecursive_(props, renderItem, items, parentId, depth) {
|
function renderFoldersRecursive_(props, renderItem, items, parentId, depth) {
|
||||||
const folders = props.folders;
|
const folders = props.folders;
|
||||||
for (let i = 0; i < folders.length; i++) {
|
for (let i = 0; i < folders.length; i++) {
|
||||||
let folder = folders[i];
|
let folder = folders[i];
|
||||||
if (!Folder.idsEqual(folder.parent_id, parentId)) continue;
|
if (!Folder.idsEqual(folder.parent_id, parentId)) continue;
|
||||||
|
if (!folderIsVisible(props.folders, folder.id, props.collapsedFolderIds)) continue;
|
||||||
const hasChildren = folderHasChildren_(folders, folder.id);
|
const hasChildren = folderHasChildren_(folders, folder.id);
|
||||||
items.push(renderItem(folder, props.selectedFolderId == folder.id && props.notesParentType == 'Folder', hasChildren, depth));
|
items.push(renderItem(folder, props.selectedFolderId == folder.id && props.notesParentType == 'Folder', hasChildren, depth));
|
||||||
if (hasChildren) items = renderFoldersRecursive_(props, renderItem, items, folder.id, depth + 1);
|
if (hasChildren) items = renderFoldersRecursive_(props, renderItem, items, folder.id, depth + 1);
|
||||||
|
@ -92,6 +92,8 @@ class Setting extends BaseModel {
|
|||||||
return platform === 'linux' ? _('Note: Does not work in all desktop environments.') : null;
|
return platform === 'linux' ? _('Note: Does not work in all desktop environments.') : null;
|
||||||
}},
|
}},
|
||||||
|
|
||||||
|
'collapsedFolderIds': { value: [], type: Setting.TYPE_ARRAY, public: false },
|
||||||
|
|
||||||
'encryption.enabled': { value: false, type: Setting.TYPE_BOOL, public: false },
|
'encryption.enabled': { value: false, type: Setting.TYPE_BOOL, public: false },
|
||||||
'encryption.activeMasterKeyId': { value: '', type: Setting.TYPE_STRING, public: false },
|
'encryption.activeMasterKeyId': { value: '', type: Setting.TYPE_STRING, public: false },
|
||||||
'encryption.passwordCache': { value: {}, type: Setting.TYPE_OBJECT, public: false },
|
'encryption.passwordCache': { value: {}, type: Setting.TYPE_OBJECT, public: false },
|
||||||
|
@ -26,6 +26,7 @@ const defaultState = {
|
|||||||
appState: 'starting',
|
appState: 'starting',
|
||||||
hasDisabledSyncItems: false,
|
hasDisabledSyncItems: false,
|
||||||
newNote: null,
|
newNote: null,
|
||||||
|
collapsedFolderIds: [],
|
||||||
};
|
};
|
||||||
|
|
||||||
const stateUtils = {};
|
const stateUtils = {};
|
||||||
@ -51,6 +52,23 @@ function stateHasEncryptedItems(state) {
|
|||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
function folderSetCollapsed(state, action) {
|
||||||
|
const collapsedFolderIds = state.collapsedFolderIds.slice();
|
||||||
|
const idx = collapsedFolderIds.indexOf(action.id);
|
||||||
|
|
||||||
|
if (action.collapsed) {
|
||||||
|
if (idx >= 0) return state;
|
||||||
|
collapsedFolderIds.push(action.id);
|
||||||
|
} else {
|
||||||
|
if (idx < 0) return state;
|
||||||
|
collapsedFolderIds.splice(idx, 1);
|
||||||
|
}
|
||||||
|
|
||||||
|
newState = Object.assign({}, state);
|
||||||
|
newState.collapsedFolderIds = collapsedFolderIds;
|
||||||
|
return newState;
|
||||||
|
}
|
||||||
|
|
||||||
// When deleting a note, tag or folder
|
// When deleting a note, tag or folder
|
||||||
function handleItemDelete(state, action) {
|
function handleItemDelete(state, action) {
|
||||||
let newState = Object.assign({}, state);
|
let newState = Object.assign({}, state);
|
||||||
@ -339,6 +357,26 @@ const reducer = (state = defaultState, action) => {
|
|||||||
newState.folders = action.items;
|
newState.folders = action.items;
|
||||||
break;
|
break;
|
||||||
|
|
||||||
|
case 'FOLDER_SET_COLLAPSED':
|
||||||
|
|
||||||
|
newState = folderSetCollapsed(state, action);
|
||||||
|
break;
|
||||||
|
|
||||||
|
case 'FOLDER_TOGGLE':
|
||||||
|
|
||||||
|
if (state.collapsedFolderIds.indexOf(action.id) >= 0) {
|
||||||
|
newState = folderSetCollapsed(state, Object.assign({ collapsed: false }, action));
|
||||||
|
} else {
|
||||||
|
newState = folderSetCollapsed(state, Object.assign({ collapsed: true }, action));
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
|
||||||
|
case 'FOLDER_SET_COLLAPSED_ALL':
|
||||||
|
|
||||||
|
newState = Object.assign({}, state);
|
||||||
|
newState.collapsedFolderIds = action.ids.slice();
|
||||||
|
break;
|
||||||
|
|
||||||
case 'TAG_UPDATE_ALL':
|
case 'TAG_UPDATE_ALL':
|
||||||
|
|
||||||
newState = Object.assign({}, state);
|
newState = Object.assign({}, state);
|
||||||
|
Loading…
x
Reference in New Issue
Block a user