wip attachment support

This commit is contained in:
zadam
2023-04-03 23:47:24 +02:00
parent 2bc78ccafb
commit 5d6d9ab6d6
27 changed files with 289 additions and 63 deletions

View File

@@ -6,6 +6,8 @@ const becca = require('../becca');
const AbstractBeccaEntity = require("./abstract_becca_entity");
/**
* FIXME: how to order attachments?
*
* Attachment represent data related/attached to the note. Conceptually similar to attributes, but intended for
* larger amounts of data and generally not accessible to the user.
*
@@ -45,9 +47,11 @@ class BAttachment extends AbstractBeccaEntity {
/** @type {boolean} */
this.isProtected = !!row.isProtected;
/** @type {string} */
this.utcDateScheduledForDeletionSince = row.utcDateScheduledForDeletionSince;
this.dateModified = row.dateModified;
/** @type {string} */
this.utcDateModified = row.utcDateModified;
/** @type {string} */
this.utcDateScheduledForDeletionSince = row.utcDateScheduledForDeletionSince;
}
getNote() {
@@ -76,6 +80,7 @@ class BAttachment extends AbstractBeccaEntity {
beforeSaving() {
super.beforeSaving();
this.dateModified = dateUtils.localNowDateTime();
this.utcDateModified = dateUtils.utcNowDateTime();
}
@@ -89,8 +94,9 @@ class BAttachment extends AbstractBeccaEntity {
blobId: this.blobId,
isProtected: !!this.isProtected,
isDeleted: false,
utcDateScheduledForDeletionSince: this.utcDateScheduledForDeletionSince,
utcDateModified: this.utcDateModified
dateModified: this.dateModified,
utcDateModified: this.utcDateModified,
utcDateScheduledForDeletionSince: this.utcDateScheduledForDeletionSince
};
}

View File

@@ -38,7 +38,7 @@ export default class Entrypoints extends Component {
await ws.waitForMaxKnownEntityChangeId();
await appContext.tabManager.openTabWithNoteWithHoisting(note.noteId, true);
await appContext.tabManager.openTabWithNoteWithHoisting(note.noteId, {activate: true});
appContext.triggerEvent('focusAndSelectTitle', {isNewNote: true});
}
@@ -135,7 +135,7 @@ export default class Entrypoints extends Component {
utils.reloadFrontendApp("Switching to mobile version");
}
async openInWindowCommand({notePath, hoistedNoteId}) {
async openInWindowCommand({notePath, hoistedNoteId, viewScope}) {
if (!hoistedNoteId) {
hoistedNoteId = 'root';
}
@@ -143,10 +143,10 @@ export default class Entrypoints extends Component {
if (utils.isElectron()) {
const {ipcRenderer} = utils.dynamicRequire('electron');
ipcRenderer.send('create-extra-window', {notePath, hoistedNoteId});
ipcRenderer.send('create-extra-window', {notePath, hoistedNoteId, viewScope});
}
else {
const url = `${window.location.protocol}//${window.location.host}${window.location.pathname}?extra=1#${notePath}`;
const url = `${window.location.protocol}//${window.location.host}${window.location.pathname}?extraWindow=1&extraHoistedNoteId=${hoistedNoteId}&extraViewScope=${JSON.stringify(viewScope)}#${notePath}`;
window.open(url, '', 'width=1000,height=800');
}

View File

@@ -53,8 +53,8 @@ class NoteContext extends Component {
this.notePath = resolvedNotePath;
({noteId: this.noteId, parentNoteId: this.parentNoteId} = treeService.getNoteIdAndParentIdFromNotePath(resolvedNotePath));
this.resetViewScope();
this.viewScope.viewMode = opts.viewMode || "default";
this.viewScope = opts.viewScope || {};
this.viewScope.viewMode = this.viewScope.viewMode || "default";
this.saveToRecentNotes(resolvedNotePath);
@@ -187,7 +187,7 @@ class NoteContext extends Component {
notePath: this.notePath,
hoistedNoteId: this.hoistedNoteId,
active: this.isActive(),
viewMode: this.viewScope.viewMode
viewScope: this.viewScope
}
}

View File

@@ -117,7 +117,12 @@ export default class RootCommandExecutor extends Component {
const notePath = appContext.tabManager.getActiveContextNotePath();
if (notePath) {
await appContext.tabManager.openContextWithNote(notePath, { activate: true, viewMode: 'source' });
await appContext.tabManager.openContextWithNote(notePath, {
activate: true,
viewScope: {
viewMode: 'source'
}
});
}
}
@@ -125,7 +130,25 @@ export default class RootCommandExecutor extends Component {
const notePath = appContext.tabManager.getActiveContextNotePath();
if (notePath) {
await appContext.tabManager.openContextWithNote(notePath, { activate: true, viewMode: 'attachments' });
await appContext.tabManager.openContextWithNote(notePath, {
activate: true,
viewScope: {
viewMode: 'attachments'
}
});
}
}
async showAttachmentDetailCommand() {
const notePath = appContext.tabManager.getActiveContextNotePath();
if (notePath) {
await appContext.tabManager.openContextWithNote(notePath, {
activate: true,
viewScope: {
viewMode: 'attachments'
}
});
}
}
}

View File

@@ -86,7 +86,8 @@ export default class TabManager extends Component {
filteredTabs.push({
notePath: notePathInUrl || 'root',
active: true,
hoistedNoteId: glob.extraHoistedNoteId || 'root'
hoistedNoteId: glob.extraHoistedNoteId || 'root',
viewScope: glob.extraViewScope || {}
});
}
@@ -101,7 +102,7 @@ export default class TabManager extends Component {
ntxId: tab.ntxId,
mainNtxId: tab.mainNtxId,
hoistedNoteId: tab.hoistedNoteId,
viewMode: tab.viewMode
viewScope: tab.viewScope
});
}
});
@@ -271,7 +272,7 @@ export default class TabManager extends Component {
/**
* If the requested notePath is within current note hoisting scope then keep the note hoisting also for the new tab.
*/
async openTabWithNoteWithHoisting(notePath, activate = false) {
async openTabWithNoteWithHoisting(notePath, opts = {}) {
const noteContext = this.getActiveContext();
let hoistedNoteId = 'root';
@@ -283,7 +284,9 @@ export default class TabManager extends Component {
}
}
return this.openContextWithNote(notePath, { activate, hoistedNoteId });
opts.hoistedNoteId = hoistedNoteId;
return this.openContextWithNote(notePath, opts);
}
async openContextWithNote(notePath, opts = {}) {
@@ -291,7 +294,7 @@ export default class TabManager extends Component {
const ntxId = opts.ntxId || null;
const mainNtxId = opts.mainNtxId || null;
const hoistedNoteId = opts.hoistedNoteId || 'root';
const viewMode = opts.viewMode || "default";
const viewScope = opts.viewScope || { viewMode: "default" };
const noteContext = await this.openEmptyTab(ntxId, hoistedNoteId, mainNtxId);
@@ -299,7 +302,7 @@ export default class TabManager extends Component {
await noteContext.setNote(notePath, {
// if activate is false then send normal noteSwitched event
triggerSwitchEvent: !activate,
viewMode: viewMode
viewScope: viewScope
});
}

View File

@@ -0,0 +1,33 @@
class FAttachment {
constructor(froca, row) {
this.froca = froca;
this.update(row);
}
update(row) {
/** @type {string} */
this.attachmentId = row.attachmentId;
/** @type {string} */
this.parentId = row.parentId;
/** @type {string} */
this.role = row.role;
/** @type {string} */
this.mime = row.mime;
/** @type {string} */
this.title = row.title;
/** @type {string} */
this.dateModified = row.dateModified;
/** @type {string} */
this.utcDateModified = row.utcDateModified;
/** @type {string} */
this.utcDateScheduledForDeletionSince = row.utcDateScheduledForDeletionSince;
this.froca.attachments[this.attachmentId] = this;
}
/** @returns {FNote} */
getNote() {
return this.froca.notes[this.parentId];
}
}

View File

@@ -51,6 +51,9 @@ class FNote {
/** @type {Object.<string, string>} */
this.childToBranch = {};
/** @type {FAttachment[]|null} */
this.attachments = null; // lazy loaded
this.update(row);
}
@@ -225,6 +228,23 @@ class FNote {
return await this.froca.getNotes(this.children);
}
/** @returns {Promise<FAttachment[]>} */
async getAttachments() {
if (!this.attachments) {
this.attachments = (await server.get(`notes/${this.noteId}/attachments`))
.map(row => new FAttachment(froca, row));
}
return this.attachments;
}
/** @returns {Promise<FAttachment>} */
async getAttachmentById(attachmentId) {
const attachments = await this.getAttachments();
return attachments.find(att => att.attachmentId === attachmentId);
}
/**
* @param {string} [type] - (optional) attribute type to filter
* @param {string} [name] - (optional) attribute name to filter

View File

@@ -1,4 +1,5 @@
/**
* FIXME: probably make it a FBlob
* Complements the FNote with the main note content and other extra attributes
*/
class FNoteComplement {

View File

@@ -1,7 +1,7 @@
import contextMenu from "./context_menu.js";
import appContext from "../components/app_context.js";
function openContextMenu(notePath, hoistedNoteId, e) {
function openContextMenu(notePath, e, viewScope = {}, hoistedNoteId = null) {
contextMenu.show({
x: e.pageX,
y: e.pageY,
@@ -16,16 +16,16 @@ function openContextMenu(notePath, hoistedNoteId, e) {
}
if (command === 'openNoteInNewTab') {
appContext.tabManager.openContextWithNote(notePath, { hoistedNoteId });
appContext.tabManager.openContextWithNote(notePath, { hoistedNoteId, viewScope });
}
else if (command === 'openNoteInNewSplit') {
const subContexts = appContext.tabManager.getActiveContext().getSubContexts();
const {ntxId} = subContexts[subContexts.length - 1];
appContext.triggerCommand("openNewNoteSplit", {ntxId, notePath, hoistedNoteId});
appContext.triggerCommand("openNewNoteSplit", {ntxId, notePath, hoistedNoteId, viewScope});
}
else if (command === 'openNoteInNewWindow') {
appContext.triggerCommand('openInWindow', {notePath, hoistedNoteId});
appContext.triggerCommand('openInWindow', {notePath, hoistedNoteId, viewScope});
}
}
});

View File

@@ -34,6 +34,10 @@ class Froca {
/** @type {Object.<string, FAttribute>} */
this.attributes = {};
/** @type {Object.<string, FAttachment>} */
this.attachments = {};
// FIXME
/** @type {Object.<string, Promise<FNoteComplement>>} */
this.blobPromises = {};
@@ -311,6 +315,7 @@ class Froca {
}
/**
* // FIXME
* @returns {Promise<FNoteComplement>}
*/
async getNoteComplement(noteId) {

View File

@@ -34,7 +34,7 @@ async function processEntityChanges(entityChanges) {
loadResults.addOption(ec.entity.name);
} else if (ec.entityName === 'attachments') {
loadResults.addAttachment(ec.entity);
processAttachment(loadResults, ec);
} else if (ec.entityName === 'etapi_tokens') {
// NOOP
}
@@ -231,6 +231,43 @@ function processAttributeChange(loadResults, ec) {
}
}
function processAttachment(loadResults, ec) {
if (ec.isErased && ec.entityId in froca.attachments) {
utils.reloadFrontendApp(`${ec.entityName} ${ec.entityId} is erased, need to do complete reload.`);
return;
}
const attachment = froca.attachments[ec.entityId];
if (ec.isErased || ec.entity?.isDeleted) {
if (attachment) {
const note = attachment.getNote();
if (note && note.attachments) {
note.attachments = note.attachments.filter(att => att.attachmentId !== attachment.attachmentId);
}
loadResults.addAttachment(ec.entity);
delete froca.attachments[ec.entityId];
}
return;
}
if (attachment) {
attachment.update(ec.entity);
} else {
const note = froca.notes[ec.entity.parentId];
if (note && note.attachments) {
note.attachments.push(new FAttachment(froca, ec.entity));
}
}
loadResults.addAttachment(ec.entity);
}
export default {
processEntityChanges
}

View File

@@ -87,7 +87,16 @@ function getNotePathFromLink($link) {
const url = $link.attr('href');
return url ? getNotePathFromUrl(url) : null;
const notePath = url ? getNotePathFromUrl(url) : null;
const viewScope = {
viewMode: $link.attr('data-view-mode'),
attachmentId: $link.attr('data-attachment-id'),
};
return {
notePath,
viewScope
};
}
function goToLink(evt) {
@@ -101,22 +110,25 @@ function goToLink(evt) {
evt.preventDefault();
evt.stopPropagation();
const notePath = getNotePathFromLink($link);
const {notePath, viewScope} = getNotePathFromLink($link);
const ctrlKey = utils.isCtrlKey(evt);
const isLeftClick = evt.which === 1;
const isMiddleClick = evt.which === 2;
const openInNewTab = (isLeftClick && ctrlKey) || isMiddleClick;
if (notePath) {
if ((evt.which === 1 && ctrlKey) || evt.which === 2) {
appContext.tabManager.openTabWithNoteWithHoisting(notePath);
if (openInNewTab) {
appContext.tabManager.openTabWithNoteWithHoisting(notePath, { viewScope });
}
else if (evt.which === 1) {
else if (isLeftClick) {
const ntxId = $(evt.target).closest("[data-ntx-id]").attr("data-ntx-id");
const noteContext = ntxId
? appContext.tabManager.getNoteContextById(ntxId)
: appContext.tabManager.getActiveContext();
noteContext.setNote(notePath).then(() => {
noteContext.setNote(notePath, { viewScope }).then(() => {
if (noteContext !== appContext.tabManager.getActiveContext()) {
appContext.tabManager.activateNoteContext(noteContext.ntxId);
}
@@ -124,7 +136,7 @@ function goToLink(evt) {
}
}
else {
if ((evt.which === 1 && ctrlKey) || evt.which === 2
if (openInNewTab
|| $link.hasClass("ck-link-actions__preview") // within edit link dialog single click suffices
|| $link.closest("[contenteditable]").length === 0 // outside of CKEditor single click suffices
) {
@@ -147,7 +159,7 @@ function goToLink(evt) {
function linkContextMenu(e) {
const $link = $(e.target).closest("a");
const notePath = getNotePathFromLink($link);
const {notePath, viewScope} = getNotePathFromLink($link);
if (!notePath) {
return;
@@ -155,7 +167,7 @@ function linkContextMenu(e) {
e.preventDefault();
linkContextMenuService.openContextMenu(notePath, null, e);
linkContextMenuService.openContextMenu(notePath, e, viewScope, null);
}
async function loadReferenceLinkTitle(noteId, $el) {

View File

@@ -37,7 +37,7 @@ const TPL = `
<div class="attachment-detail-wrapper">
<div class="attachment-title-line">
<h4 class="attachment-title"></h4>
<h4 class="attachment-title"><a href="javascript:" data-trigger-command="openAttachmentDetail"></a></h4>
<div class="attachment-details"></div>
<div style="flex: 1 1;"></div>
<div class="attachment-actions-container"></div>
@@ -73,7 +73,7 @@ export default class AttachmentDetailWidget extends BasicWidget {
.html()
);
this.$wrapper = this.$widget.find('.attachment-detail-wrapper');
this.$wrapper.find('.attachment-title').text(this.attachment.title);
this.$wrapper.find('.attachment-title a').text(this.attachment.title);
this.$wrapper.find('.attachment-details')
.text(`Role: ${this.attachment.role}, Size: ${utils.formatSize(this.attachment.contentLength)}`);
this.$wrapper.find('.attachment-actions-container').append(this.attachmentActionsWidget.render());
@@ -90,9 +90,11 @@ export default class AttachmentDetailWidget extends BasicWidget {
}
}
async entitiesReloadedEvent({loadResults}) {
console.log("AttachmentDetailWidget: entitiesReloadedEvent");
openAttachmentDetailCommand() {
}
async entitiesReloadedEvent({loadResults}) {
const attachmentChange = loadResults.getAttachments().find(att => att.attachmentId === this.attachment.attachmentId);
if (attachmentChange) {

View File

@@ -27,7 +27,7 @@ export default class NoteLauncher extends AbstractLauncher {
const hoistedNoteId = this.getHoistedNoteId();
linkContextMenuService.openContextMenu(targetNoteId, hoistedNoteId, evt);
linkContextMenuService.openContextMenu(targetNoteId, evt, {}, hoistedNoteId);
});
}

View File

@@ -13,7 +13,7 @@ export default class OpenNoteButtonWidget extends OnClickButtonWidget {
.icon(() => this.noteToOpen.getIcon())
.onClick((widget, evt) => this.launch(evt))
.onAuxClick((widget, evt) => this.launch(evt))
.onContextMenu(evt => linkContextMenuService.openContextMenu(this.noteToOpen.noteId, null, evt));
.onContextMenu(evt => linkContextMenuService.openContextMenu(this.noteToOpen.noteId, evt));
}
async launch(evt) {

View File

@@ -34,7 +34,7 @@ export default class SplitNoteContainer extends FlexContainer {
this.child(widget);
}
async openNewNoteSplitEvent({ntxId, notePath, hoistedNoteId}) {
async openNewNoteSplitEvent({ntxId, notePath, hoistedNoteId, viewScope}) {
const mainNtxId = appContext.tabManager.getActiveMainContext().ntxId;
if (!ntxId) {
@@ -63,7 +63,7 @@ export default class SplitNoteContainer extends FlexContainer {
await appContext.tabManager.activateNoteContext(noteContext.ntxId);
if (notePath) {
await noteContext.setNote(notePath);
await noteContext.setNote(notePath, viewScope);
}
else {
await noteContext.setEmpty();

View File

@@ -61,6 +61,10 @@ export default class NoteContextAwareWidget extends BasicWidget {
}
}
/**
* @param {FNote} note
* @returns {Promise<void>}
*/
async refreshWithNote(note) {}
async noteSwitchedEvent({noteContext, notePath}) {

View File

@@ -27,7 +27,8 @@ import NoteMapTypeWidget from "./type_widgets/note_map.js";
import WebViewTypeWidget from "./type_widgets/web_view.js";
import DocTypeWidget from "./type_widgets/doc.js";
import ContentWidgetTypeWidget from "./type_widgets/content_widget.js";
import AttachmentsTypeWidget from "./type_widgets/attachments.js";
import AttachmentListTypeWidget from "./type_widgets/attachment_list.js";
import AttachmentDetailTypeWidget from "./type_widgets/attachment_detail.js";
const TPL = `
<div class="note-detail">
@@ -63,7 +64,8 @@ const typeWidgetClasses = {
'webView': WebViewTypeWidget,
'doc': DocTypeWidget,
'contentWidget': ContentWidgetTypeWidget,
'attachments': AttachmentsTypeWidget
'attachmentDetail': AttachmentDetailTypeWidget,
'attachmentList': AttachmentListTypeWidget
};
export default class NoteDetailWidget extends NoteContextAwareWidget {
@@ -188,11 +190,12 @@ export default class NoteDetailWidget extends NoteContextAwareWidget {
}
let type = note.type;
const viewScope = this.noteContext.viewScope;
if (type === 'text' && this.noteContext.viewScope.viewMode === 'source') {
if (type === 'text' && viewScope.viewMode === 'source') {
type = 'readOnlyCode';
} else if (this.noteContext.viewScope.viewMode === 'attachments') {
type = 'attachments';
} else if (viewScope.viewMode === 'attachments') {
type = viewScope.attachmentId ? 'attachmentDetail' : 'attachmentList';
} else if (type === 'text' && await this.noteContext.isReadOnly()) {
type = 'readOnlyText';
} else if ((type === 'code' || type === 'mermaid') && await this.noteContext.isReadOnly()) {

View File

@@ -113,7 +113,7 @@ export default class NoteMapWidget extends NoteContextAwareWidget {
.linkWidth(1)
.linkColor(() => this.css.mutedTextColor)
.onNodeClick(node => appContext.tabManager.getActiveContext().setNote(node.id))
.onNodeRightClick((node, e) => linkContextMenuService.openContextMenu(node.id, null, e));
.onNodeRightClick((node, e) => linkContextMenuService.openContextMenu(node.id, e));
if (this.mapType === 'link') {
this.graph

View File

@@ -70,20 +70,38 @@ export default class NoteTitleWidget extends NoteContextAwareWidget {
}
async refreshWithNote(note) {
const viewMode = this.noteContext.viewScope.viewMode;
this.$noteTitle.val(viewMode === 'default'
? note.title
: `${viewMode}: ${note.title}`);
this.$noteTitle.val(await this.getTitleText(note));
this.$noteTitle.prop("readonly",
(note.isProtected && !protectedSessionHolder.isProtectedSessionAvailable())
|| ['_lbRoot', '_lbAvailableLaunchers', '_lbVisibleLaunchers'].includes(note.noteId)
|| viewMode !== 'default'
|| this.noteContext.viewScope.viewMode !== 'default'
);
this.setProtectedStatus(note);
}
/** @param {FNote} note */
async getTitleText(note) {
const viewScope = this.noteContext.viewScope;
let title = viewScope.viewMode === 'default'
? note.title
: `${note.title}: ${viewScope.viewMode}`;
if (viewScope.attachmentId) {
// assuming the attachment has been already loaded
const attachment = await note.getAttachmentById(viewScope.attachmentId);
if (attachment) {
title += `: ${attachment.title}`;
}
}
return title;
}
/** @param {FNote} note */
setProtectedStatus(note) {
this.$noteTitle.toggleClass("protected", !!note.isProtected);
}

View File

@@ -0,0 +1,54 @@
import TypeWidget from "./type_widget.js";
import server from "../../services/server.js";
import AttachmentDetailWidget from "../attachment_detail.js";
const TPL = `
<div class="attachment-detail note-detail-printable">
<style>
.attachment-detail {
padding: 15px;
}
</style>
<div class="attachment-wrapper"></div>
</div>`;
export default class AttachmentDetailTypeWidget extends TypeWidget {
static getType() {
return "attachmentDetail";
}
doRender() {
this.$widget = $(TPL);
this.$wrapper = this.$widget.find('.attachment-wrapper');
super.doRender();
}
async doRefresh(note) {
this.$wrapper.empty();
this.children = [];
this.renderedAttachmentIds = new Set();
const attachment = await server.get(`notes/${this.noteId}/attachments/${this.noteContext.viewScope.attachment.attachmentId}/?includeContent=true`);
if (!attachment) {
this.$list.html("<strong>This attachment has been deleted.</strong>");
return;
}
const attachmentDetailWidget = new AttachmentDetailWidget(attachment);
this.child(attachmentDetailWidget);
this.$list.append(attachmentDetailWidget.render());
}
async entitiesReloadedEvent({loadResults}) {
const attachmentChange = loadResults.getAttachments().find(att => att.attachmentId === this.attachment.attachmentId);
if (attachmentChange.isDeleted) {
this.refresh(); // all other updates are handled within AttachmentDetailWidget
}
}
}

View File

@@ -3,24 +3,24 @@ import server from "../../services/server.js";
import AttachmentDetailWidget from "../attachment_detail.js";
const TPL = `
<div class="attachments note-detail-printable">
<div class="attachment-list note-detail-printable">
<style>
.attachments {
.attachment-list {
padding: 15px;
}
</style>
<div class="attachment-list"></div>
<div class="attachment-list-wrapper"></div>
</div>`;
export default class AttachmentsTypeWidget extends TypeWidget {
export default class AttachmentListTypeWidget extends TypeWidget {
static getType() {
return "attachments";
return "attachmentList";
}
doRender() {
this.$widget = $(TPL);
this.$list = this.$widget.find('.attachment-list');
this.$list = this.$widget.find('.attachment-list-wrapper');
super.doRender();
}

View File

@@ -34,8 +34,10 @@ function index(req, res) {
instanceName: config.General ? config.General.instanceName : null,
appCssNoteIds: getAppCssNoteIds(),
isDev: env.isDev(),
isMainWindow: !req.query.extra,
isMainWindow: !req.query.extraWindow,
extraHoistedNoteId: req.query.extraHoistedNoteId,
// make sure only valid JSON gets rendered
extraViewScope: JSON.stringify(req.query.extraViewScope ? JSON.parse(req.query.extraViewScope) : {}),
isProtectedSessionAvailable: protectedSessionService.isProtectedSessionAvailable(),
maxContentWidth: parseInt(options.maxContentWidth),
triliumVersion: packageJson.version,

View File

@@ -15,7 +15,7 @@ let mainWindow;
/** @type {Electron.BrowserWindow} */
let setupWindow;
async function createExtraWindow(notePath, hoistedNoteId = 'root') {
async function createExtraWindow(notePath, hoistedNoteId = 'root', viewScope = {}) {
const spellcheckEnabled = optionService.getOptionBool('spellCheckEnabled');
const {BrowserWindow} = require('electron');
@@ -35,13 +35,13 @@ async function createExtraWindow(notePath, hoistedNoteId = 'root') {
});
win.setMenuBarVisibility(false);
win.loadURL(`http://127.0.0.1:${port}/?extra=1&extraHoistedNoteId=${hoistedNoteId}#${notePath}`);
win.loadURL(`http://127.0.0.1:${port}/?extraWindow=1&extraHoistedNoteId=${hoistedNoteId}&extraViewScope=${JSON.stringify(viewScope)}#${notePath}`);
configureWebContents(win.webContents, spellcheckEnabled);
}
ipcMain.on('create-extra-window', (event, arg) => {
createExtraWindow(arg.notePath, arg.hoistedNoteId);
createExtraWindow(arg.notePath, arg.hoistedNoteId, arg.viewScope);
});
async function createMainWindow(app) {

View File

@@ -33,6 +33,7 @@
appCssNoteIds: <%- JSON.stringify(appCssNoteIds) %>,
isMainWindow: <%= isMainWindow %>,
extraHoistedNoteId: '<%= extraHoistedNoteId %>',
extraViewScope: <%- extraViewScope %>,
isProtectedSessionAvailable: <%= isProtectedSessionAvailable %>,
triliumVersion: "<%= triliumVersion %>",
assetPath: "<%= assetPath %>",