hoisting support in mobile view WIP

This commit is contained in:
zadam 2022-12-13 16:57:46 +01:00
parent 2957e1d78a
commit ca968a9e31
10 changed files with 63 additions and 52 deletions

4
package-lock.json generated
View File

@ -1,11 +1,11 @@
{ {
"name": "trilium", "name": "trilium",
"version": "0.57.3", "version": "0.57.4",
"lockfileVersion": 2, "lockfileVersion": 2,
"requires": true, "requires": true,
"packages": { "packages": {
"": { "": {
"version": "0.57.3", "version": "0.57.4",
"hasInstallScript": true, "hasInstallScript": true,
"license": "AGPL-3.0-only", "license": "AGPL-3.0-only",
"dependencies": { "dependencies": {

View File

@ -150,19 +150,11 @@ $(window).on('beforeunload', () => {
} }
}); });
function isNotePathInAddress() {
const [notePath, ntxId] = treeService.getHashValueFromAddress();
return notePath.startsWith("root")
// empty string is for empty/uninitialized tab
|| (notePath === '' && !!ntxId);
}
$(window).on('hashchange', function() { $(window).on('hashchange', function() {
if (isNotePathInAddress()) { if (treeService.isNotePathInAddress()) {
const [notePath, ntxId] = treeService.getHashValueFromAddress(); const [notePath, ntxId] = treeService.getHashValueFromAddress();
if (!notePath) { if (!notePath && !ntxId) {
console.log(`Invalid hash value "${document.location.hash}", ignoring.`); console.log(`Invalid hash value "${document.location.hash}", ignoring.`);
return; return;
} }

View File

@ -190,16 +190,20 @@ export default class Entrypoints extends Component {
toastService.showMessage("Note executed"); toastService.showMessage("Note executed");
} }
hideAllTooltips() { hideAllPopups() {
$(".tooltip").removeClass("show"); $(".tooltip").removeClass("show");
if (utils.isDesktop()) {
$(".aa-input").autocomplete("close");
}
} }
noteSwitchedEvent() { noteSwitchedEvent() {
this.hideAllTooltips(); this.hideAllPopups();
} }
activeContextChangedEvent() { activeContextChangedEvent() {
this.hideAllTooltips(); this.hideAllPopups();
} }
async forceSaveNoteRevisionCommand() { async forceSaveNoteRevisionCommand() {

View File

@ -1,4 +1,5 @@
import Component from "./component.js"; import Component from "./component.js";
import appContext from "./app_context.js";
export default class MobileScreenSwitcherExecutor extends Component { export default class MobileScreenSwitcherExecutor extends Component {
setActiveScreenCommand({screen}) { setActiveScreenCommand({screen}) {
@ -6,7 +7,9 @@ export default class MobileScreenSwitcherExecutor extends Component {
this.activeScreen = screen; this.activeScreen = screen;
if (screen === 'tree') { if (screen === 'tree') {
document.location.hash = ''; const activeNoteContext = appContext.tabManager.getActiveContext();
activeNoteContext.setEmpty();
} }
this.triggerEvent('activeScreenChanged', {activeScreen: screen}); this.triggerEvent('activeScreenChanged', {activeScreen: screen});

View File

@ -80,10 +80,7 @@ class NoteContext extends Component {
await this.setHoistedNoteId(hoistedNoteId); await this.setHoistedNoteId(hoistedNoteId);
} }
if (utils.isDesktop()) { if (utils.isMobile()) {
// close dangling autocompletes after closing the tab
$(".aa-input").autocomplete("close");
} else if (utils.isMobile()) {
this.triggerCommand('setActiveScreen', {screen: 'detail'}); this.triggerCommand('setActiveScreen', {screen: 'detail'});
} }
} }
@ -171,7 +168,8 @@ class NoteContext extends Component {
} }
getTabState() { getTabState() {
if (!this.notePath) { if (!this.notePath && this.hoistedNoteId === 'root') {
// keeping empty hoisted tab is esp. important for mobile (e.g. opened launcher config)
return null; return null;
} }

View File

@ -25,10 +25,14 @@ export default class TabManager extends Component {
return; return;
} }
console.log("Pre-saving", this.noteContexts);
const openTabs = this.noteContexts const openTabs = this.noteContexts
.map(nc => nc.getTabState()) .map(nc => nc.getTabState())
.filter(t => !!t); .filter(t => !!t);
console.log("Saving", openTabs);
await server.put('options', { await server.put('options', {
openTabs: JSON.stringify(openTabs) openTabs: JSON.stringify(openTabs)
}); });
@ -52,34 +56,10 @@ export default class TabManager extends Component {
? (options.getJson('openTabs') || []) ? (options.getJson('openTabs') || [])
: []; : [];
// if there's notePath in the URL, make sure it's open and active
// (useful, among others, for opening clipped notes from clipper)
if (window.location.hash) {
const notePath = window.location.hash.substr(1);
const noteId = treeService.getNoteIdFromNotePath(notePath);
if (noteId && await froca.noteExists(noteId)) {
for (const tab of tabsToOpen) {
tab.active = false;
}
const foundTab = tabsToOpen.find(tab => noteId === treeService.getNoteIdFromNotePath(tab.notePath));
if (foundTab) {
foundTab.active = true;
}
else {
tabsToOpen.push({
notePath: notePath,
active: true,
hoistedNoteId: glob.extraHoistedNoteId || 'root'
});
}
}
}
let filteredTabs = []; let filteredTabs = [];
console.log(document.location.hash, tabsToOpen);
for (const openTab of tabsToOpen) { for (const openTab of tabsToOpen) {
const noteId = treeService.getNoteIdFromNotePath(openTab.notePath); const noteId = treeService.getNoteIdFromNotePath(openTab.notePath);
@ -111,6 +91,14 @@ export default class TabManager extends Component {
await this.openContextWithNote(tab.notePath, tab.active, tab.ntxId, tab.hoistedNoteId, tab.mainNtxId); await this.openContextWithNote(tab.notePath, tab.active, tab.ntxId, tab.hoistedNoteId, tab.mainNtxId);
} }
}); });
// if there's notePath in the URL, make sure it's open and active
// (useful, among others, for opening clipped notes from clipper)
if (treeService.isNotePathInAddress()) {
const [notePath, ntxId] = treeService.getHashValueFromAddress();
await appContext.tabManager.switchToNoteContext(ntxId, notePath);
}
} }
noteSwitchedEvent({noteContext}) { noteSwitchedEvent({noteContext}) {
@ -205,11 +193,19 @@ export default class TabManager extends Component {
} }
async switchToNoteContext(ntxId, notePath) { async switchToNoteContext(ntxId, notePath) {
console.log("Looking for " + ntxId);
console.log("Existing", this.noteContexts);
const noteContext = this.noteContexts.find(nc => nc.ntxId === ntxId) const noteContext = this.noteContexts.find(nc => nc.ntxId === ntxId)
|| await this.openEmptyTab(); || await this.openEmptyTab();
this.activateNoteContext(noteContext.ntxId); console.log(noteContext);
await noteContext.setNote(notePath);
await this.activateNoteContext(noteContext.ntxId);
if (notePath) {
await noteContext.setNote(notePath);
}
} }
async openAndActivateEmptyTab() { async openAndActivateEmptyTab() {

View File

@ -101,6 +101,11 @@ span.fancytree-expander {
margin-right: 16px; margin-right: 16px;
display: none; display: none;
} }
.tree-wrapper .unhoist-button {
display: block;
font-size: 200%;
}
</style>`; </style>`;
export default class MobileLayout { export default class MobileLayout {
@ -119,13 +124,16 @@ export default class MobileLayout {
.child(new ScreenContainer("tree", 'column') .child(new ScreenContainer("tree", 'column')
.class("d-sm-flex d-md-flex d-lg-flex d-xl-flex col-12 col-sm-5 col-md-4 col-lg-3 col-xl-3") .class("d-sm-flex d-md-flex d-lg-flex d-xl-flex col-12 col-sm-5 col-md-4 col-lg-3 col-xl-3")
.css("max-height", "100%") .css("max-height", "100%")
.css('padding-left', 0) .css('padding-left', "0")
.css('padding-right', "0")
.css('contain', 'content') .css('contain', 'content')
.child(new QuickSearchWidget()) .child(new QuickSearchWidget())
.child(new NoteTreeWidget() .child(new NoteTreeWidget()
.cssBlock(FANCYTREE_CSS))) .cssBlock(FANCYTREE_CSS)))
.child(new ScreenContainer("detail", "column") .child(new ScreenContainer("detail", "column")
.class("d-sm-flex d-md-flex d-lg-flex d-xl-flex col-12 col-sm-7 col-md-8 col-lg-9") .class("d-sm-flex d-md-flex d-lg-flex d-xl-flex col-12 col-sm-7 col-md-8 col-lg-9")
.css("padding-left", "0")
.css("padding-right", "0")
.css('max-height', '100%') .css('max-height', '100%')
.child(new FlexContainer('row').contentSized() .child(new FlexContainer('row').contentSized()
.css('font-size', 'larger') .css('font-size', 'larger')

View File

@ -304,6 +304,14 @@ function getHashValueFromAddress() {
return str.split("-"); return str.split("-");
} }
function isNotePathInAddress() {
const [notePath, ntxId] = getHashValueFromAddress();
return notePath.startsWith("root")
// empty string is for empty/uninitialized tab
|| (notePath === '' && !!ntxId);
}
function parseNotePath(notePath) { function parseNotePath(notePath) {
let noteIds = notePath.split('/'); let noteIds = notePath.split('/');
@ -332,6 +340,7 @@ export default {
getNotePathTitle, getNotePathTitle,
getNoteTitleWithPathAsSuffix, getNoteTitleWithPathAsSuffix,
getHashValueFromAddress, getHashValueFromAddress,
isNotePathInAddress,
parseNotePath, parseNotePath,
isNotePathInHiddenSubtree isNotePathInHiddenSubtree
}; };

View File

@ -535,7 +535,7 @@ export default class NoteTreeWidget extends NoteContextAwareWidget {
const note = await froca.getNote(node.data.noteId, true); const note = await froca.getNote(node.data.noteId, true);
if (!note || note.isDeleted || note.isLaunchBarConfig()) { if (!note || note.isDeleted) {
return; return;
} }

View File

@ -116,7 +116,8 @@
isDev: <%= isDev %>, isDev: <%= isDev %>,
appCssNoteIds: <%- JSON.stringify(appCssNoteIds) %>, appCssNoteIds: <%- JSON.stringify(appCssNoteIds) %>,
isProtectedSessionAvailable: <%= isProtectedSessionAvailable %>, isProtectedSessionAvailable: <%= isProtectedSessionAvailable %>,
assetPath: "<%= assetPath %>" assetPath: "<%= assetPath %>",
isMainWindow: true
}; };
</script> </script>