Compare commits
40 Commits
| Author | SHA1 | Date | |
|---|---|---|---|
| 2502646a64 | |||
| 3d95d69f80 | |||
| df751f5d67 | |||
| 4f06b6de78 | |||
| d2177cd517 | |||
| 0affcf5ad2 | |||
| 7a416b107b | |||
| 1ff124dab7 | |||
| 4cb511bad0 | |||
| 73c8d145fa | |||
| ab79f24729 | |||
| cec71f65b3 | |||
| f75c008154 | |||
| 474baa7d95 | |||
| a155b6e8d5 | |||
| 229974e543 | |||
| 6fc19bfb93 | |||
| d389100611 | |||
| ea7257a5b2 | |||
| 0ebc947fbd | |||
| c89514f9bb | |||
| e0368e395c | |||
| 6986c201dd | |||
| bcf163f8a1 | |||
| 15aaead7b9 | |||
| d29c5c4758 | |||
| 81e2baeee5 | |||
| 4cececafc9 | |||
| 7c8e7a3f4b | |||
| 613d5f93e8 | |||
| 4f5b23fbf8 | |||
| a37b9cfc7b | |||
| 2bc18bc214 | |||
| f31a998c5d | |||
| 5552917533 | |||
| d1941cc650 | |||
| 0db3722ec2 | |||
| d47403c0e7 | |||
| 77311954a1 | |||
| b7cf4fe96b |
+32
-2
@@ -2,7 +2,7 @@
|
||||
<dataSource name="document.db">
|
||||
<database-model serializer="dbm" dbms="SQLITE" family-id="SQLITE" format-version="4.17">
|
||||
<root id="1">
|
||||
<ServerVersion>3.25.1</ServerVersion>
|
||||
<ServerVersion>3.16.1</ServerVersion>
|
||||
</root>
|
||||
<schema id="2" parent="1" name="main">
|
||||
<Current>1</Current>
|
||||
@@ -57,6 +57,7 @@
|
||||
<index id="24" parent="6" name="sqlite_autoindex_api_tokens_1">
|
||||
<NameSurrogate>1</NameSurrogate>
|
||||
<ColNames>apiTokenId</ColNames>
|
||||
<ColumnCollations></ColumnCollations>
|
||||
<Unique>1</Unique>
|
||||
</index>
|
||||
<key id="25" parent="6">
|
||||
@@ -125,17 +126,21 @@
|
||||
<index id="37" parent="7" name="sqlite_autoindex_attributes_1">
|
||||
<NameSurrogate>1</NameSurrogate>
|
||||
<ColNames>attributeId</ColNames>
|
||||
<ColumnCollations></ColumnCollations>
|
||||
<Unique>1</Unique>
|
||||
</index>
|
||||
<index id="38" parent="7" name="IDX_attributes_noteId_index">
|
||||
<ColNames>noteId</ColNames>
|
||||
<ColumnCollations></ColumnCollations>
|
||||
</index>
|
||||
<index id="39" parent="7" name="IDX_attributes_name_value">
|
||||
<ColNames>name
|
||||
value</ColNames>
|
||||
<ColumnCollations></ColumnCollations>
|
||||
</index>
|
||||
<index id="40" parent="7" name="IDX_attributes_value_index">
|
||||
<ColNames>value</ColNames>
|
||||
<ColumnCollations></ColumnCollations>
|
||||
</index>
|
||||
<key id="41" parent="7">
|
||||
<ColNames>attributeId</ColNames>
|
||||
@@ -197,14 +202,17 @@ value</ColNames>
|
||||
<index id="52" parent="8" name="sqlite_autoindex_branches_1">
|
||||
<NameSurrogate>1</NameSurrogate>
|
||||
<ColNames>branchId</ColNames>
|
||||
<ColumnCollations></ColumnCollations>
|
||||
<Unique>1</Unique>
|
||||
</index>
|
||||
<index id="53" parent="8" name="IDX_branches_noteId_parentNoteId">
|
||||
<ColNames>noteId
|
||||
parentNoteId</ColNames>
|
||||
<ColumnCollations></ColumnCollations>
|
||||
</index>
|
||||
<index id="54" parent="8" name="IDX_branches_parentNoteId">
|
||||
<ColNames>parentNoteId</ColNames>
|
||||
<ColumnCollations></ColumnCollations>
|
||||
</index>
|
||||
<key id="55" parent="8">
|
||||
<ColNames>branchId</ColNames>
|
||||
@@ -235,6 +243,7 @@ parentNoteId</ColNames>
|
||||
<index id="60" parent="9" name="sqlite_autoindex_note_contents_1">
|
||||
<NameSurrogate>1</NameSurrogate>
|
||||
<ColNames>noteId</ColNames>
|
||||
<ColumnCollations></ColumnCollations>
|
||||
<Unique>1</Unique>
|
||||
</index>
|
||||
<key id="61" parent="9">
|
||||
@@ -265,6 +274,7 @@ parentNoteId</ColNames>
|
||||
<index id="66" parent="10" name="sqlite_autoindex_note_revision_contents_1">
|
||||
<NameSurrogate>1</NameSurrogate>
|
||||
<ColNames>noteRevisionId</ColNames>
|
||||
<ColumnCollations></ColumnCollations>
|
||||
<Unique>1</Unique>
|
||||
</index>
|
||||
<key id="67" parent="10">
|
||||
@@ -349,22 +359,28 @@ parentNoteId</ColNames>
|
||||
<index id="82" parent="11" name="sqlite_autoindex_note_revisions_1">
|
||||
<NameSurrogate>1</NameSurrogate>
|
||||
<ColNames>noteRevisionId</ColNames>
|
||||
<ColumnCollations></ColumnCollations>
|
||||
<Unique>1</Unique>
|
||||
</index>
|
||||
<index id="83" parent="11" name="IDX_note_revisions_noteId">
|
||||
<ColNames>noteId</ColNames>
|
||||
<ColumnCollations></ColumnCollations>
|
||||
</index>
|
||||
<index id="84" parent="11" name="IDX_note_revisions_utcDateLastEdited">
|
||||
<ColNames>utcDateLastEdited</ColNames>
|
||||
<ColumnCollations></ColumnCollations>
|
||||
</index>
|
||||
<index id="85" parent="11" name="IDX_note_revisions_utcDateCreated">
|
||||
<ColNames>utcDateCreated</ColNames>
|
||||
<ColumnCollations></ColumnCollations>
|
||||
</index>
|
||||
<index id="86" parent="11" name="IDX_note_revisions_dateLastEdited">
|
||||
<ColNames>dateLastEdited</ColNames>
|
||||
<ColumnCollations></ColumnCollations>
|
||||
</index>
|
||||
<index id="87" parent="11" name="IDX_note_revisions_dateCreated">
|
||||
<ColNames>dateCreated</ColNames>
|
||||
<ColumnCollations></ColumnCollations>
|
||||
</index>
|
||||
<key id="88" parent="11">
|
||||
<ColNames>noteRevisionId</ColNames>
|
||||
@@ -446,28 +462,36 @@ parentNoteId</ColNames>
|
||||
<index id="102" parent="12" name="sqlite_autoindex_notes_1">
|
||||
<NameSurrogate>1</NameSurrogate>
|
||||
<ColNames>noteId</ColNames>
|
||||
<ColumnCollations></ColumnCollations>
|
||||
<Unique>1</Unique>
|
||||
</index>
|
||||
<index id="103" parent="12" name="IDX_notes_title">
|
||||
<ColNames>title</ColNames>
|
||||
<ColumnCollations></ColumnCollations>
|
||||
</index>
|
||||
<index id="104" parent="12" name="IDX_notes_type">
|
||||
<ColNames>type</ColNames>
|
||||
<ColumnCollations></ColumnCollations>
|
||||
</index>
|
||||
<index id="105" parent="12" name="IDX_notes_isDeleted">
|
||||
<ColNames>isDeleted</ColNames>
|
||||
<ColumnCollations></ColumnCollations>
|
||||
</index>
|
||||
<index id="106" parent="12" name="IDX_notes_dateCreated">
|
||||
<ColNames>dateCreated</ColNames>
|
||||
<ColumnCollations></ColumnCollations>
|
||||
</index>
|
||||
<index id="107" parent="12" name="IDX_notes_dateModified">
|
||||
<ColNames>dateModified</ColNames>
|
||||
<ColumnCollations></ColumnCollations>
|
||||
</index>
|
||||
<index id="108" parent="12" name="IDX_notes_utcDateCreated">
|
||||
<ColNames>utcDateCreated</ColNames>
|
||||
<ColumnCollations></ColumnCollations>
|
||||
</index>
|
||||
<index id="109" parent="12" name="IDX_notes_utcDateModified">
|
||||
<ColNames>utcDateModified</ColNames>
|
||||
<ColumnCollations></ColumnCollations>
|
||||
</index>
|
||||
<key id="110" parent="12">
|
||||
<ColNames>noteId</ColNames>
|
||||
@@ -508,6 +532,7 @@ parentNoteId</ColNames>
|
||||
<index id="117" parent="13" name="sqlite_autoindex_options_1">
|
||||
<NameSurrogate>1</NameSurrogate>
|
||||
<ColNames>name</ColNames>
|
||||
<ColumnCollations></ColumnCollations>
|
||||
<Unique>1</Unique>
|
||||
</index>
|
||||
<key id="118" parent="13">
|
||||
@@ -543,6 +568,7 @@ parentNoteId</ColNames>
|
||||
<index id="124" parent="14" name="sqlite_autoindex_recent_notes_1">
|
||||
<NameSurrogate>1</NameSurrogate>
|
||||
<ColNames>noteId</ColNames>
|
||||
<ColumnCollations></ColumnCollations>
|
||||
<Unique>1</Unique>
|
||||
</index>
|
||||
<key id="125" parent="14">
|
||||
@@ -563,10 +589,12 @@ parentNoteId</ColNames>
|
||||
<index id="128" parent="15" name="sqlite_autoindex_source_ids_1">
|
||||
<NameSurrogate>1</NameSurrogate>
|
||||
<ColNames>sourceId</ColNames>
|
||||
<ColumnCollations></ColumnCollations>
|
||||
<Unique>1</Unique>
|
||||
</index>
|
||||
<index id="129" parent="15" name="IDX_source_ids_utcDateCreated">
|
||||
<ColNames>utcDateCreated</ColNames>
|
||||
<ColumnCollations></ColumnCollations>
|
||||
</index>
|
||||
<key id="130" parent="15">
|
||||
<ColNames>sourceId</ColNames>
|
||||
@@ -587,7 +615,7 @@ parentNoteId</ColNames>
|
||||
</column>
|
||||
<column id="134" parent="16" name="rootpage">
|
||||
<Position>4</Position>
|
||||
<DataType>int|0s</DataType>
|
||||
<DataType>integer|0s</DataType>
|
||||
</column>
|
||||
<column id="135" parent="16" name="sql">
|
||||
<Position>5</Position>
|
||||
@@ -628,10 +656,12 @@ parentNoteId</ColNames>
|
||||
<index id="143" parent="18" name="IDX_sync_entityName_entityId">
|
||||
<ColNames>entityName
|
||||
entityId</ColNames>
|
||||
<ColumnCollations></ColumnCollations>
|
||||
<Unique>1</Unique>
|
||||
</index>
|
||||
<index id="144" parent="18" name="IDX_sync_utcSyncDate">
|
||||
<ColNames>utcSyncDate</ColNames>
|
||||
<ColumnCollations></ColumnCollations>
|
||||
</index>
|
||||
<key id="145" parent="18">
|
||||
<ColNames>id</ColNames>
|
||||
|
||||
+1
-1
@@ -1,4 +1,4 @@
|
||||
FROM node:12.13.1-alpine
|
||||
FROM node:12.14.0-alpine
|
||||
|
||||
# Create app directory
|
||||
WORKDIR /usr/src/app
|
||||
|
||||
+1
-1
@@ -1,7 +1,7 @@
|
||||
#!/usr/bin/env bash
|
||||
|
||||
PKG_DIR=dist/trilium-linux-x64-server
|
||||
NODE_VERSION=12.13.1
|
||||
NODE_VERSION=12.14.0
|
||||
|
||||
if [ "$1" != "DONTCOPY" ]
|
||||
then
|
||||
|
||||
BIN
Binary file not shown.
+15
-111
@@ -1,86 +1,17 @@
|
||||
'use strict';
|
||||
|
||||
const {app, globalShortcut, BrowserWindow} = require('electron');
|
||||
const path = require('path');
|
||||
const log = require('./src/services/log');
|
||||
const {app, globalShortcut} = require('electron');
|
||||
const sqlInit = require('./src/services/sql_init');
|
||||
const cls = require('./src/services/cls');
|
||||
const url = require("url");
|
||||
const port = require('./src/services/port');
|
||||
const env = require('./src/services/env');
|
||||
const keyboardActionsService = require('./src/services/keyboard_actions');
|
||||
const appIconService = require('./src/services/app_icon');
|
||||
const windowStateKeeper = require('electron-window-state');
|
||||
const windowService = require('./src/services/window');
|
||||
|
||||
// Adds debug features like hotkeys for triggering dev tools and reload
|
||||
require('electron-debug')();
|
||||
|
||||
appIconService.installLocalAppIcon();
|
||||
|
||||
// Prevent window being garbage collected
|
||||
let mainWindow;
|
||||
|
||||
require('electron-dl')({ saveAs: true });
|
||||
|
||||
function onClosed() {
|
||||
// Dereference the window
|
||||
// For multiple windows store them in an array
|
||||
mainWindow = null;
|
||||
}
|
||||
|
||||
async function createMainWindow() {
|
||||
await sqlInit.dbConnection;
|
||||
|
||||
// if schema doesn't exist -> setup process
|
||||
// if schema exists, then we need to wait until the migration process is finished
|
||||
if (await sqlInit.schemaExists()) {
|
||||
await sqlInit.dbReady;
|
||||
}
|
||||
|
||||
const mainWindowState = windowStateKeeper({
|
||||
// default window width & height so it's usable on 1600 * 900 display (including some extra panels etc.)
|
||||
defaultWidth: 1200,
|
||||
defaultHeight: 800
|
||||
});
|
||||
|
||||
const win = new BrowserWindow({
|
||||
x: mainWindowState.x,
|
||||
y: mainWindowState.y,
|
||||
width: mainWindowState.width,
|
||||
height: mainWindowState.height,
|
||||
title: 'Trilium Notes',
|
||||
webPreferences: {
|
||||
nodeIntegration: true
|
||||
},
|
||||
icon: path.join(__dirname, 'images/app-icons/png/256x256' + (env.isDev() ? '-dev' : '') + '.png')
|
||||
});
|
||||
|
||||
mainWindowState.manage(win);
|
||||
|
||||
win.setMenuBarVisibility(false);
|
||||
win.loadURL('http://127.0.0.1:' + await port);
|
||||
win.on('closed', onClosed);
|
||||
|
||||
win.webContents.on('new-window', (e, url) => {
|
||||
if (url !== win.webContents.getURL()) {
|
||||
e.preventDefault();
|
||||
require('electron').shell.openExternal(url);
|
||||
}
|
||||
});
|
||||
|
||||
// prevent drag & drop to navigate away from trilium
|
||||
win.webContents.on('will-navigate', (ev, targetUrl) => {
|
||||
const parsedUrl = url.parse(targetUrl);
|
||||
|
||||
// we still need to allow internal redirects from setup and migration pages
|
||||
if (!['localhost', '127.0.0.1'].includes(parsedUrl.hostname) || (parsedUrl.path && parsedUrl.path !== '/')) {
|
||||
ev.preventDefault();
|
||||
}
|
||||
});
|
||||
|
||||
return win;
|
||||
}
|
||||
|
||||
app.on('window-all-closed', () => {
|
||||
if (process.platform !== 'darwin') {
|
||||
app.quit();
|
||||
@@ -90,50 +21,23 @@ app.on('window-all-closed', () => {
|
||||
}
|
||||
});
|
||||
|
||||
app.on('activate', () => {
|
||||
if (!mainWindow) {
|
||||
mainWindow = createMainWindow();
|
||||
}
|
||||
});
|
||||
|
||||
async function registerGlobalShortcuts() {
|
||||
await sqlInit.dbReady;
|
||||
|
||||
const allActions = await keyboardActionsService.getKeyboardActions();
|
||||
|
||||
for (const action of allActions) {
|
||||
if (!action.effectiveShortcuts) {
|
||||
continue;
|
||||
}
|
||||
|
||||
for (const shortcut of action.effectiveShortcuts) {
|
||||
if (shortcut.startsWith('global:')) {
|
||||
const translatedShortcut = shortcut.substr(7);
|
||||
|
||||
const result = globalShortcut.register(translatedShortcut, cls.wrap(async () => {
|
||||
// window may be hidden / not in focus
|
||||
mainWindow.focus();
|
||||
|
||||
mainWindow.webContents.send('globalShortcut', action.actionName);
|
||||
}));
|
||||
|
||||
if (result) {
|
||||
log.info(`Registered global shortcut ${translatedShortcut} for action ${action.actionName}`);
|
||||
}
|
||||
else {
|
||||
log.info(`Could not register global shortcut ${translatedShortcut}`);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
app.on('ready', async () => {
|
||||
app.setAppUserModelId('com.github.zadam.trilium');
|
||||
|
||||
mainWindow = await createMainWindow();
|
||||
await sqlInit.dbConnection;
|
||||
|
||||
registerGlobalShortcuts();
|
||||
// if schema doesn't exist -> setup process
|
||||
// if schema exists, then we need to wait until the migration process is finished
|
||||
if (await sqlInit.schemaExists()) {
|
||||
await sqlInit.dbReady;
|
||||
|
||||
await windowService.createMainWindow();
|
||||
}
|
||||
else {
|
||||
await windowService.createSetupWindow();
|
||||
}
|
||||
|
||||
await windowService.registerGlobalShortcuts();
|
||||
});
|
||||
|
||||
app.on('will-quit', () => {
|
||||
|
||||
@@ -0,0 +1,310 @@
|
||||
/*
|
||||
* !!!!!!! This stylesheet is heavily modified compared to the original for similarity with in-editor look !!!!!!!
|
||||
* This is used for printing and tar HTML export
|
||||
*
|
||||
* CKEditor 5 (v15.0.0) content styles.
|
||||
* Generated on Wed, 27 Nov 2019 13:26:13 GMT.
|
||||
* For more information, check out https://ckeditor.com/docs/ckeditor5/latest/builds/guides/integration/content-styles.html
|
||||
*/
|
||||
|
||||
:root {
|
||||
--ck-highlight-marker-blue: #72cdfd;
|
||||
--ck-highlight-marker-green: #63f963;
|
||||
--ck-highlight-marker-pink: #fc7999;
|
||||
--ck-highlight-marker-yellow: #fdfd77;
|
||||
--ck-highlight-pen-green: #118800;
|
||||
--ck-highlight-pen-red: #e91313;
|
||||
--ck-image-style-spacing: 1.5em;
|
||||
--ck-todo-list-checkmark-size: 16px;
|
||||
font-family: Arial, Sans-Serif;
|
||||
}
|
||||
|
||||
/* ckeditor5-list/theme/todolist.css */
|
||||
.todo-list {
|
||||
list-style: none;
|
||||
}
|
||||
/* ckeditor5-list/theme/todolist.css */
|
||||
.todo-list li {
|
||||
margin-bottom: 5px;
|
||||
}
|
||||
/* ckeditor5-list/theme/todolist.css */
|
||||
.todo-list li .todo-list {
|
||||
margin-top: 5px;
|
||||
}
|
||||
/* ckeditor5-list/theme/todolist.css */
|
||||
.todo-list .todo-list__label > input {
|
||||
-webkit-appearance: none;
|
||||
display: inline-block;
|
||||
position: relative;
|
||||
width: var(--ck-todo-list-checkmark-size);
|
||||
height: var(--ck-todo-list-checkmark-size);
|
||||
vertical-align: middle;
|
||||
border: 0;
|
||||
left: -25px;
|
||||
margin-right: -15px;
|
||||
right: 0;
|
||||
margin-left: 0;
|
||||
}
|
||||
/* ckeditor5-list/theme/todolist.css */
|
||||
.todo-list .todo-list__label > input::before {
|
||||
display: block;
|
||||
position: absolute;
|
||||
box-sizing: border-box;
|
||||
content: '';
|
||||
width: 100%;
|
||||
height: 100%;
|
||||
border: 1px solid hsl(0, 0%, 20%);
|
||||
border-radius: 2px;
|
||||
transition: 250ms ease-in-out box-shadow, 250ms ease-in-out background, 250ms ease-in-out border;
|
||||
}
|
||||
/* ckeditor5-list/theme/todolist.css */
|
||||
.todo-list .todo-list__label > input::after {
|
||||
display: block;
|
||||
position: absolute;
|
||||
box-sizing: content-box;
|
||||
pointer-events: none;
|
||||
content: '';
|
||||
left: calc( var(--ck-todo-list-checkmark-size) / 3 );
|
||||
top: calc( var(--ck-todo-list-checkmark-size) / 5.3 );
|
||||
width: calc( var(--ck-todo-list-checkmark-size) / 5.3 );
|
||||
height: calc( var(--ck-todo-list-checkmark-size) / 2.6 );
|
||||
border-style: solid;
|
||||
border-color: transparent;
|
||||
border-width: 0 calc( var(--ck-todo-list-checkmark-size) / 8 ) calc( var(--ck-todo-list-checkmark-size) / 8 ) 0;
|
||||
transform: rotate(45deg);
|
||||
}
|
||||
/* ckeditor5-list/theme/todolist.css */
|
||||
.todo-list .todo-list__label > input[checked]::before {
|
||||
border-color: hsl(126, 64%, 41%);
|
||||
}
|
||||
/* ckeditor5-list/theme/todolist.css */
|
||||
.todo-list .todo-list__label > input[checked]::after {
|
||||
border-color: hsl(126, 64%, 41%);
|
||||
}
|
||||
/* ckeditor5-list/theme/todolist.css */
|
||||
.todo-list .todo-list__label .todo-list__label__description {
|
||||
vertical-align: middle;
|
||||
}
|
||||
/* ckeditor5-image/theme/image.css */
|
||||
.image {
|
||||
display: table;
|
||||
clear: both;
|
||||
text-align: center;
|
||||
margin: 1em auto;
|
||||
}
|
||||
/* ckeditor5-image/theme/image.css */
|
||||
.image > img {
|
||||
display: block;
|
||||
margin: 0 auto;
|
||||
max-width: 100%;
|
||||
min-width: 50px;
|
||||
}
|
||||
/* ckeditor5-block-quote/theme/blockquote.css */
|
||||
blockquote {
|
||||
overflow: hidden;
|
||||
padding-right: 1.5em;
|
||||
padding-left: 1.5em;
|
||||
margin-left: 0;
|
||||
margin-right: 0;
|
||||
font-style: italic;
|
||||
border-left: solid 5px hsl(0, 0%, 80%);
|
||||
}
|
||||
/* ckeditor5-block-quote/theme/blockquote.css */
|
||||
.ck-content[dir="rtl"] blockquote {
|
||||
border-left: 0;
|
||||
border-right: solid 5px hsl(0, 0%, 80%);
|
||||
}
|
||||
/* ckeditor5-image/theme/imageresize.css */
|
||||
.image.image_resized {
|
||||
max-width: 100%;
|
||||
display: block;
|
||||
box-sizing: border-box;
|
||||
}
|
||||
/* ckeditor5-image/theme/imageresize.css */
|
||||
.image.image_resized img {
|
||||
width: 100%;
|
||||
}
|
||||
/* ckeditor5-image/theme/imageresize.css */
|
||||
.image.image_resized > figcaption {
|
||||
display: block;
|
||||
}
|
||||
/* ckeditor5-image/theme/imagestyle.css */
|
||||
.image-style-side,
|
||||
.image-style-align-left,
|
||||
.image-style-align-center,
|
||||
.image-style-align-right {
|
||||
max-width: 50%;
|
||||
}
|
||||
/* ckeditor5-image/theme/imagestyle.css */
|
||||
.image-style-side {
|
||||
float: right;
|
||||
margin-left: var(--ck-image-style-spacing);
|
||||
}
|
||||
/* ckeditor5-image/theme/imagestyle.css */
|
||||
.image-style-align-left {
|
||||
float: left;
|
||||
margin-right: var(--ck-image-style-spacing);
|
||||
}
|
||||
/* ckeditor5-image/theme/imagestyle.css */
|
||||
.image-style-align-center {
|
||||
margin-left: auto;
|
||||
margin-right: auto;
|
||||
}
|
||||
/* ckeditor5-image/theme/imagestyle.css */
|
||||
.image-style-align-right {
|
||||
float: right;
|
||||
margin-left: var(--ck-image-style-spacing);
|
||||
}
|
||||
/* ckeditor5-media-embed/theme/mediaembed.css */
|
||||
.media {
|
||||
clear: both;
|
||||
margin: 1em 0;
|
||||
display: block;
|
||||
min-width: 15em;
|
||||
}
|
||||
/* ckeditor5-table/theme/table.css */
|
||||
.table {
|
||||
display: table;
|
||||
margin: 0;
|
||||
}
|
||||
/* ckeditor5-table/theme/table.css */
|
||||
.table table {
|
||||
border-collapse: collapse;
|
||||
border-spacing: 0;
|
||||
border: 1px double hsl(0, 0%, 70%);
|
||||
}
|
||||
/* ckeditor5-table/theme/table.css */
|
||||
.table table td,
|
||||
.table table th {
|
||||
min-width: 2em;
|
||||
padding: .4em;
|
||||
border: 1px solid #d9d9d9;
|
||||
}
|
||||
/* ckeditor5-table/theme/table.css */
|
||||
.table table th {
|
||||
font-weight: bold;
|
||||
background-color: #f5f5f5;
|
||||
text-align: left;
|
||||
}
|
||||
/* ckeditor5-highlight/theme/highlight.css */
|
||||
.marker-yellow {
|
||||
background-color: var(--ck-highlight-marker-yellow);
|
||||
}
|
||||
/* ckeditor5-highlight/theme/highlight.css */
|
||||
.marker-green {
|
||||
background-color: var(--ck-highlight-marker-green);
|
||||
}
|
||||
/* ckeditor5-highlight/theme/highlight.css */
|
||||
.marker-pink {
|
||||
background-color: var(--ck-highlight-marker-pink);
|
||||
}
|
||||
/* ckeditor5-highlight/theme/highlight.css */
|
||||
.marker-blue {
|
||||
background-color: var(--ck-highlight-marker-blue);
|
||||
}
|
||||
/* ckeditor5-highlight/theme/highlight.css */
|
||||
.pen-red {
|
||||
color: var(--ck-highlight-pen-red);
|
||||
background-color: transparent;
|
||||
}
|
||||
/* ckeditor5-highlight/theme/highlight.css */
|
||||
.pen-green {
|
||||
color: var(--ck-highlight-pen-green);
|
||||
background-color: transparent;
|
||||
}
|
||||
/* ckeditor5-page-break/theme/pagebreak.css */
|
||||
.page-break {
|
||||
position: relative;
|
||||
clear: both;
|
||||
padding: 5px 0;
|
||||
display: flex;
|
||||
align-items: center;
|
||||
justify-content: center;
|
||||
}
|
||||
/* ckeditor5-page-break/theme/pagebreak.css */
|
||||
.page-break::after {
|
||||
content: '';
|
||||
position: absolute;
|
||||
border-bottom: 2px dashed hsl(0, 0%, 77%);
|
||||
width: 100%;
|
||||
}
|
||||
/* ckeditor5-page-break/theme/pagebreak.css */
|
||||
.page-break__label {
|
||||
position: relative;
|
||||
z-index: 1;
|
||||
padding: .3em .6em;
|
||||
display: block;
|
||||
text-transform: uppercase;
|
||||
border: 1px solid hsl(0, 0%, 77%);
|
||||
border-radius: 2px;
|
||||
font-family: Helvetica, Arial, Tahoma, Verdana, Sans-Serif;
|
||||
font-size: 0.75em;
|
||||
font-weight: bold;
|
||||
color: hsl(0, 0%, 20%);
|
||||
background: #fff;
|
||||
box-shadow: 2px 2px 1px hsla(0, 0%, 0%, 0.15);
|
||||
-webkit-user-select: none;
|
||||
-moz-user-select: none;
|
||||
-ms-user-select: none;
|
||||
user-select: none;
|
||||
}
|
||||
/* ckeditor5-basic-styles/theme/code.css */
|
||||
code {
|
||||
background-color: hsla(0, 0%, 78%, 0.3);
|
||||
padding: .15em;
|
||||
border-radius: 2px;
|
||||
}
|
||||
/* ckeditor5-image/theme/imagecaption.css */
|
||||
.image > figcaption {
|
||||
display: table-caption;
|
||||
caption-side: bottom;
|
||||
word-break: break-word;
|
||||
color: hsl(0, 0%, 20%);
|
||||
background-color: hsl(0, 0%, 97%);
|
||||
padding: .6em;
|
||||
font-size: .75em;
|
||||
outline-offset: -1px;
|
||||
}
|
||||
/* ckeditor5-horizontal-line/theme/horizontalline.css */
|
||||
hr {
|
||||
border-width: 1px 0 0;
|
||||
border-style: solid;
|
||||
border-color: hsl(0, 0%, 37%);
|
||||
margin: 0;
|
||||
}
|
||||
/* ckeditor5-code-block/theme/codeblock.css */
|
||||
pre {
|
||||
padding: 1em;
|
||||
color: #353535;
|
||||
background: hsla(0, 0%, 78%, 0.3);
|
||||
border: 1px solid hsl(0, 0%, 77%);
|
||||
border-radius: 2px;
|
||||
text-align: left;
|
||||
direction: ltr;
|
||||
tab-size: 4;
|
||||
white-space: pre-wrap;
|
||||
font-style: normal;
|
||||
min-width: 200px;
|
||||
}
|
||||
/* ckeditor5-code-block/theme/codeblock.css */
|
||||
pre code {
|
||||
background: unset;
|
||||
padding: 0;
|
||||
border-radius: 0;
|
||||
}
|
||||
|
||||
.ck-widget__selection-handle {
|
||||
display: none;
|
||||
}
|
||||
|
||||
@media print {
|
||||
/* ckeditor5-page-break/theme/pagebreak.css */
|
||||
.page-break {
|
||||
padding: 0;
|
||||
}
|
||||
|
||||
/* ckeditor5-page-break/theme/pagebreak.css */
|
||||
.page-break::after {
|
||||
display: none;
|
||||
}
|
||||
}
|
||||
Vendored
+3
File diff suppressed because one or more lines are too long
Generated
+149
-153
@@ -1,6 +1,6 @@
|
||||
{
|
||||
"name": "trilium",
|
||||
"version": "0.38.2",
|
||||
"version": "0.39.0-beta",
|
||||
"lockfileVersion": 1,
|
||||
"requires": true,
|
||||
"dependencies": {
|
||||
@@ -629,12 +629,9 @@
|
||||
"integrity": "sha512-7evsyfH1cLOCdAzZAd43Cic04yKydNx0cF+7tiA19p1XnLLPU4dpCQOqpjqwokFe//vS0QqfqqjCS2JkiIs0cA=="
|
||||
},
|
||||
"agent-base": {
|
||||
"version": "4.3.0",
|
||||
"resolved": "https://registry.npmjs.org/agent-base/-/agent-base-4.3.0.tgz",
|
||||
"integrity": "sha512-salcGninV0nPrwpGNn4VTXBb1SOuXQBiqbrNXoeizJsHrsL6ERFM2Ne3JUSBWRE6aeNJI2ROP/WEEIDUiDe3cg==",
|
||||
"requires": {
|
||||
"es6-promisify": "^5.0.0"
|
||||
}
|
||||
"version": "5.1.1",
|
||||
"resolved": "https://registry.npmjs.org/agent-base/-/agent-base-5.1.1.tgz",
|
||||
"integrity": "sha512-TMeqbNl2fMW0nMjTEPOwe3J/PRFP4vqeoNuQMG0HlMrtm5QxKqdvAkZ1pRBQ/ulIyDD5Yq0nJ7YbdD8ey0TO3g=="
|
||||
},
|
||||
"ajv": {
|
||||
"version": "6.10.2",
|
||||
@@ -760,6 +757,12 @@
|
||||
"temp-file": "^3.3.4"
|
||||
},
|
||||
"dependencies": {
|
||||
"ejs": {
|
||||
"version": "2.7.4",
|
||||
"resolved": "https://registry.npmjs.org/ejs/-/ejs-2.7.4.tgz",
|
||||
"integrity": "sha512-7vmuyh5+kuUyJKePhQfRQBhXV5Ce+RnaeeQArKu1EAMpL3WbgMt5WG6uQZpEVvYSSsxMXRKOewtDk9RaTKXRlA==",
|
||||
"dev": true
|
||||
},
|
||||
"hosted-git-info": {
|
||||
"version": "3.0.2",
|
||||
"resolved": "https://registry.npmjs.org/hosted-git-info/-/hosted-git-info-3.0.2.tgz",
|
||||
@@ -768,6 +771,12 @@
|
||||
"requires": {
|
||||
"lru-cache": "^5.1.1"
|
||||
}
|
||||
},
|
||||
"semver": {
|
||||
"version": "6.3.0",
|
||||
"resolved": "https://registry.npmjs.org/semver/-/semver-6.3.0.tgz",
|
||||
"integrity": "sha512-b39TBaTSfV6yBrapU89p5fKekE2m/NwnDocOVruQFS1/veMgdzuPcnOM34M6CwxW8jH/lxEa5rBoDeUwu5HHTw==",
|
||||
"dev": true
|
||||
}
|
||||
}
|
||||
},
|
||||
@@ -871,7 +880,6 @@
|
||||
"version": "2.0.1",
|
||||
"resolved": "https://registry.npmjs.org/asar/-/asar-2.0.1.tgz",
|
||||
"integrity": "sha512-Vo9yTuUtyFahkVMFaI6uMuX6N7k5DWa6a/8+7ov0/f8Lq9TVR0tUjzSzxQSxT1Y+RJIZgnP7BVb6Uhi+9cjxqA==",
|
||||
"dev": true,
|
||||
"requires": {
|
||||
"chromium-pickle-js": "^0.2.0",
|
||||
"commander": "^2.20.0",
|
||||
@@ -885,14 +893,12 @@
|
||||
"commander": {
|
||||
"version": "2.20.1",
|
||||
"resolved": "https://registry.npmjs.org/commander/-/commander-2.20.1.tgz",
|
||||
"integrity": "sha512-cCuLsMhJeWQ/ZpsFTbE765kvVfoeSddc4nU3up4fV+fDBcfUXnbITJ+JzhkdjzOqhURjZgujxaioam4RM9yGUg==",
|
||||
"dev": true
|
||||
"integrity": "sha512-cCuLsMhJeWQ/ZpsFTbE765kvVfoeSddc4nU3up4fV+fDBcfUXnbITJ+JzhkdjzOqhURjZgujxaioam4RM9yGUg=="
|
||||
},
|
||||
"glob": {
|
||||
"version": "7.1.4",
|
||||
"resolved": "https://registry.npmjs.org/glob/-/glob-7.1.4.tgz",
|
||||
"integrity": "sha512-hkLPepehmnKk41pUGm3sYxoFs/umurYfYJCerbXEyFIWcAzvpipAgVkBqqT9RBKMGjnq6kMuyYwha6csxbiM1A==",
|
||||
"dev": true,
|
||||
"requires": {
|
||||
"fs.realpath": "^1.0.0",
|
||||
"inflight": "^1.0.4",
|
||||
@@ -906,7 +912,6 @@
|
||||
"version": "1.1.0",
|
||||
"resolved": "https://registry.npmjs.org/tmp-promise/-/tmp-promise-1.1.0.tgz",
|
||||
"integrity": "sha512-8+Ah9aB1IRXCnIOxXZ0uFozV1nMU5xiu7hhFVUSxZ3bYu+psD4TzagCzVbexUCgNNGJnsmNDQlS4nG3mTyoNkw==",
|
||||
"dev": true,
|
||||
"requires": {
|
||||
"bluebird": "^3.5.0",
|
||||
"tmp": "0.1.0"
|
||||
@@ -972,8 +977,7 @@
|
||||
"author-regex": {
|
||||
"version": "1.0.0",
|
||||
"resolved": "https://registry.npmjs.org/author-regex/-/author-regex-1.0.0.tgz",
|
||||
"integrity": "sha1-0IiFvmubv5Q5/gh8dihyRfCoFFA=",
|
||||
"dev": true
|
||||
"integrity": "sha1-0IiFvmubv5Q5/gh8dihyRfCoFFA="
|
||||
},
|
||||
"aws-sign2": {
|
||||
"version": "0.7.0",
|
||||
@@ -1137,8 +1141,7 @@
|
||||
"bluebird": {
|
||||
"version": "3.7.0",
|
||||
"resolved": "https://registry.npmjs.org/bluebird/-/bluebird-3.7.0.tgz",
|
||||
"integrity": "sha512-aBQ1FxIa7kSWCcmKHlcHFlT2jt6J/l4FzC7KcPELkOJOsPOb/bccdhmIrKDfXhwFrmc7vDoDrrepFvGqjyXGJg==",
|
||||
"dev": true
|
||||
"integrity": "sha512-aBQ1FxIa7kSWCcmKHlcHFlT2jt6J/l4FzC7KcPELkOJOsPOb/bccdhmIrKDfXhwFrmc7vDoDrrepFvGqjyXGJg=="
|
||||
},
|
||||
"bluebird-lst": {
|
||||
"version": "1.0.9",
|
||||
@@ -1592,8 +1595,7 @@
|
||||
"chromium-pickle-js": {
|
||||
"version": "0.2.0",
|
||||
"resolved": "https://registry.npmjs.org/chromium-pickle-js/-/chromium-pickle-js-0.2.0.tgz",
|
||||
"integrity": "sha1-BKEGZywYsIWrd02YPfo+oTjyIgU=",
|
||||
"dev": true
|
||||
"integrity": "sha1-BKEGZywYsIWrd02YPfo+oTjyIgU="
|
||||
},
|
||||
"ci-info": {
|
||||
"version": "2.0.0",
|
||||
@@ -1662,7 +1664,6 @@
|
||||
"version": "5.0.0",
|
||||
"resolved": "https://registry.npmjs.org/cliui/-/cliui-5.0.0.tgz",
|
||||
"integrity": "sha512-PYeGSEmmHM6zvoef2w8TPzlrnNpXIjTipYK780YswmIP9vjxmd6Y2a3CB2Ks6/AU8NHjZugXvo8w3oWM2qnwXA==",
|
||||
"dev": true,
|
||||
"requires": {
|
||||
"string-width": "^3.1.0",
|
||||
"strip-ansi": "^5.2.0",
|
||||
@@ -1672,20 +1673,17 @@
|
||||
"ansi-regex": {
|
||||
"version": "4.1.0",
|
||||
"resolved": "https://registry.npmjs.org/ansi-regex/-/ansi-regex-4.1.0.tgz",
|
||||
"integrity": "sha512-1apePfXM1UOSqw0o9IiFAovVz9M5S1Dg+4TrDwfMewQ6p/rmMueb7tWZjQ1rx4Loy1ArBggoqGpfqqdI4rondg==",
|
||||
"dev": true
|
||||
"integrity": "sha512-1apePfXM1UOSqw0o9IiFAovVz9M5S1Dg+4TrDwfMewQ6p/rmMueb7tWZjQ1rx4Loy1ArBggoqGpfqqdI4rondg=="
|
||||
},
|
||||
"is-fullwidth-code-point": {
|
||||
"version": "2.0.0",
|
||||
"resolved": "https://registry.npmjs.org/is-fullwidth-code-point/-/is-fullwidth-code-point-2.0.0.tgz",
|
||||
"integrity": "sha1-o7MKXE8ZkYMWeqq5O+764937ZU8=",
|
||||
"dev": true
|
||||
"integrity": "sha1-o7MKXE8ZkYMWeqq5O+764937ZU8="
|
||||
},
|
||||
"string-width": {
|
||||
"version": "3.1.0",
|
||||
"resolved": "https://registry.npmjs.org/string-width/-/string-width-3.1.0.tgz",
|
||||
"integrity": "sha512-vafcv6KjVZKSgz06oM/H6GDBrAtz8vdhQakGjFIvNrHA6y3HCF1CInLy+QLq8dTJPQ1b+KDUqDFctkdRW44e1w==",
|
||||
"dev": true,
|
||||
"requires": {
|
||||
"emoji-regex": "^7.0.1",
|
||||
"is-fullwidth-code-point": "^2.0.0",
|
||||
@@ -1696,7 +1694,6 @@
|
||||
"version": "5.2.0",
|
||||
"resolved": "https://registry.npmjs.org/strip-ansi/-/strip-ansi-5.2.0.tgz",
|
||||
"integrity": "sha512-DuRs1gKbBqsMKIZlrffwlug8MHkcnpjs5VPmL1PAh+mA30U0DTotfDZ0d2UUsXpPmPmMMJ6W773MaA3J+lbiWA==",
|
||||
"dev": true,
|
||||
"requires": {
|
||||
"ansi-regex": "^4.1.0"
|
||||
}
|
||||
@@ -1752,7 +1749,6 @@
|
||||
"version": "1.9.3",
|
||||
"resolved": "https://registry.npmjs.org/color-convert/-/color-convert-1.9.3.tgz",
|
||||
"integrity": "sha512-QfAUtd+vFdAtFQcC8CCyYt1fYWxSqAiK2cSD6zDB8N3cpsEBAvRxp9zOGg6G/SHHJYAT88/az/IuDGALsNVbGg==",
|
||||
"dev": true,
|
||||
"requires": {
|
||||
"color-name": "1.1.3"
|
||||
}
|
||||
@@ -1760,8 +1756,7 @@
|
||||
"color-name": {
|
||||
"version": "1.1.3",
|
||||
"resolved": "https://registry.npmjs.org/color-name/-/color-name-1.1.3.tgz",
|
||||
"integrity": "sha1-p9BVi9icQveV3UIyj3QIMcpTvCU=",
|
||||
"dev": true
|
||||
"integrity": "sha1-p9BVi9icQveV3UIyj3QIMcpTvCU="
|
||||
},
|
||||
"color-support": {
|
||||
"version": "1.1.3",
|
||||
@@ -1977,7 +1972,7 @@
|
||||
"version": "0.10.1",
|
||||
"resolved": "https://registry.npmjs.org/cross-spawn-promise/-/cross-spawn-promise-0.10.1.tgz",
|
||||
"integrity": "sha1-25y0xQxgtyoVvgSbeBIs44LYexA=",
|
||||
"dev": true,
|
||||
"optional": true,
|
||||
"requires": {
|
||||
"cross-spawn": "^5.1.0"
|
||||
}
|
||||
@@ -2050,8 +2045,7 @@
|
||||
"cuint": {
|
||||
"version": "0.2.2",
|
||||
"resolved": "https://registry.npmjs.org/cuint/-/cuint-0.2.2.tgz",
|
||||
"integrity": "sha1-QICG1AlVDCYxFVYZ6fp7ytw7mRs=",
|
||||
"dev": true
|
||||
"integrity": "sha1-QICG1AlVDCYxFVYZ6fp7ytw7mRs="
|
||||
},
|
||||
"currently-unhandled": {
|
||||
"version": "0.4.1",
|
||||
@@ -2102,9 +2096,9 @@
|
||||
"integrity": "sha1-QGXiATz5+5Ft39gu+1Bq1MZ2kGI="
|
||||
},
|
||||
"dayjs": {
|
||||
"version": "1.8.17",
|
||||
"resolved": "https://registry.npmjs.org/dayjs/-/dayjs-1.8.17.tgz",
|
||||
"integrity": "sha512-47VY/htqYqr9GHd7HW/h56PpQzRBSJcxIQFwqL3P20bMF/3az5c3PWdVY3LmPXFl6cQCYHL7c79b9ov+2bOBbw=="
|
||||
"version": "1.8.18",
|
||||
"resolved": "https://registry.npmjs.org/dayjs/-/dayjs-1.8.18.tgz",
|
||||
"integrity": "sha512-JBMJZghNK8TtuoPnKNIzW9xavVVigld/zmZNpZSyQbkb2Opp55YIfZUpE4OEqPF/iyUVQTKcn1bC2HtC8B7s3g=="
|
||||
},
|
||||
"debug": {
|
||||
"version": "4.1.1",
|
||||
@@ -2473,6 +2467,20 @@
|
||||
"sanitize-filename": "^1.6.2",
|
||||
"semver": "^6.3.0",
|
||||
"temp-file": "^3.3.4"
|
||||
},
|
||||
"dependencies": {
|
||||
"ejs": {
|
||||
"version": "2.7.4",
|
||||
"resolved": "https://registry.npmjs.org/ejs/-/ejs-2.7.4.tgz",
|
||||
"integrity": "sha512-7vmuyh5+kuUyJKePhQfRQBhXV5Ce+RnaeeQArKu1EAMpL3WbgMt5WG6uQZpEVvYSSsxMXRKOewtDk9RaTKXRlA==",
|
||||
"dev": true
|
||||
},
|
||||
"semver": {
|
||||
"version": "6.3.0",
|
||||
"resolved": "https://registry.npmjs.org/semver/-/semver-6.3.0.tgz",
|
||||
"integrity": "sha512-b39TBaTSfV6yBrapU89p5fKekE2m/NwnDocOVruQFS1/veMgdzuPcnOM34M6CwxW8jH/lxEa5rBoDeUwu5HHTw==",
|
||||
"dev": true
|
||||
}
|
||||
}
|
||||
},
|
||||
"builder-util": {
|
||||
@@ -2732,9 +2740,9 @@
|
||||
},
|
||||
"dependencies": {
|
||||
"@types/node": {
|
||||
"version": "10.17.0",
|
||||
"resolved": "https://registry.npmjs.org/@types/node/-/node-10.17.0.tgz",
|
||||
"integrity": "sha512-wuJwN2KV4tIRz1bu9vq5kSPasJ8IsEjZaP1ZR7KlmdUZvGF/rXy8DmXOVwUD0kAtvtJ7aqMKPqUXC0NUTDbrDg==",
|
||||
"version": "10.17.11",
|
||||
"resolved": "https://registry.npmjs.org/@types/node/-/node-10.17.11.tgz",
|
||||
"integrity": "sha512-dNd2pp8qTzzNLAs3O8nH3iU9DG9866KHq9L3ISPB7DOGERZN81nW/5/g/KzMJpCU8jrbCiMRBzV9/sCEdRosig==",
|
||||
"dev": true
|
||||
}
|
||||
}
|
||||
@@ -2877,13 +2885,13 @@
|
||||
}
|
||||
},
|
||||
"electron-dl": {
|
||||
"version": "1.14.0",
|
||||
"resolved": "https://registry.npmjs.org/electron-dl/-/electron-dl-1.14.0.tgz",
|
||||
"integrity": "sha512-4okyei42a1mLsvLK7hLrIfd20EQzB18nIlLTwBV992aMSmTGLUEFRTmO1MfSslGNrzD8nuPuy1l/VxO8so4lig==",
|
||||
"version": "2.0.0",
|
||||
"resolved": "https://registry.npmjs.org/electron-dl/-/electron-dl-2.0.0.tgz",
|
||||
"integrity": "sha512-crv64+Z2ZCsHCoJHBBOypDKx8cy+4jTGMc5/rDDzIajihDN/wITkJOdb6XG8b43YlWr3NS1/r6j+IdwaFNmMiQ==",
|
||||
"requires": {
|
||||
"ext-name": "^5.0.0",
|
||||
"pupa": "^1.0.0",
|
||||
"unused-filename": "^1.0.0"
|
||||
"pupa": "^2.0.1",
|
||||
"unused-filename": "^2.1.0"
|
||||
}
|
||||
},
|
||||
"electron-download": {
|
||||
@@ -2946,7 +2954,7 @@
|
||||
"version": "0.7.3",
|
||||
"resolved": "https://registry.npmjs.org/electron-installer-common/-/electron-installer-common-0.7.3.tgz",
|
||||
"integrity": "sha512-l4chYFTWr6uWODKYUXeC+Z4tqGa3b8e+Y2WUBf3F7Ruv6yYzZ+Ccic65oXreeotx09B7sUx1KTuwXRsRJHKlMw==",
|
||||
"dev": true,
|
||||
"optional": true,
|
||||
"requires": {
|
||||
"asar": "^2.0.1",
|
||||
"cross-spawn-promise": "^0.10.1",
|
||||
@@ -2963,7 +2971,7 @@
|
||||
"version": "7.1.4",
|
||||
"resolved": "https://registry.npmjs.org/glob/-/glob-7.1.4.tgz",
|
||||
"integrity": "sha512-hkLPepehmnKk41pUGm3sYxoFs/umurYfYJCerbXEyFIWcAzvpipAgVkBqqT9RBKMGjnq6kMuyYwha6csxbiM1A==",
|
||||
"dev": true,
|
||||
"optional": true,
|
||||
"requires": {
|
||||
"fs.realpath": "^1.0.0",
|
||||
"inflight": "^1.0.4",
|
||||
@@ -2972,6 +2980,12 @@
|
||||
"once": "^1.3.0",
|
||||
"path-is-absolute": "^1.0.0"
|
||||
}
|
||||
},
|
||||
"semver": {
|
||||
"version": "6.3.0",
|
||||
"resolved": "https://registry.npmjs.org/semver/-/semver-6.3.0.tgz",
|
||||
"integrity": "sha512-b39TBaTSfV6yBrapU89p5fKekE2m/NwnDocOVruQFS1/veMgdzuPcnOM34M6CwxW8jH/lxEa5rBoDeUwu5HHTw==",
|
||||
"optional": true
|
||||
}
|
||||
}
|
||||
},
|
||||
@@ -2979,7 +2993,7 @@
|
||||
"version": "2.0.1",
|
||||
"resolved": "https://registry.npmjs.org/electron-installer-debian/-/electron-installer-debian-2.0.1.tgz",
|
||||
"integrity": "sha512-6/rgdWoezE5/JKSu6Y1mK3TT2lUeRKpviVoh063DKSLwcDPHQFgJ0/uDxqGppi3AF4du8n1vVio0VEkCEwlM1A==",
|
||||
"dev": true,
|
||||
"optional": true,
|
||||
"requires": {
|
||||
"debug": "^4.1.1",
|
||||
"electron-installer-common": "^0.7.1",
|
||||
@@ -2994,19 +3008,19 @@
|
||||
"version": "4.1.0",
|
||||
"resolved": "https://registry.npmjs.org/ansi-regex/-/ansi-regex-4.1.0.tgz",
|
||||
"integrity": "sha512-1apePfXM1UOSqw0o9IiFAovVz9M5S1Dg+4TrDwfMewQ6p/rmMueb7tWZjQ1rx4Loy1ArBggoqGpfqqdI4rondg==",
|
||||
"dev": true
|
||||
"optional": true
|
||||
},
|
||||
"camelcase": {
|
||||
"version": "5.3.1",
|
||||
"resolved": "https://registry.npmjs.org/camelcase/-/camelcase-5.3.1.tgz",
|
||||
"integrity": "sha512-L28STB170nwWS63UjtlEOE3dldQApaJXZkOI1uMFfzf3rRuPegHaHesyee+YxQ+W6SvRDQV6UrdOdRiR153wJg==",
|
||||
"dev": true
|
||||
"optional": true
|
||||
},
|
||||
"find-up": {
|
||||
"version": "3.0.0",
|
||||
"resolved": "https://registry.npmjs.org/find-up/-/find-up-3.0.0.tgz",
|
||||
"integrity": "sha512-1yD6RmLI1XBfxugvORwlck6f75tYL+iR0jqwsOrOxMZyGYqUuDhJ0l4AXdO1iX/FTs9cBAMEk1gWSEx1kSbylg==",
|
||||
"dev": true,
|
||||
"optional": true,
|
||||
"requires": {
|
||||
"locate-path": "^3.0.0"
|
||||
}
|
||||
@@ -3015,13 +3029,13 @@
|
||||
"version": "2.0.0",
|
||||
"resolved": "https://registry.npmjs.org/is-fullwidth-code-point/-/is-fullwidth-code-point-2.0.0.tgz",
|
||||
"integrity": "sha1-o7MKXE8ZkYMWeqq5O+764937ZU8=",
|
||||
"dev": true
|
||||
"optional": true
|
||||
},
|
||||
"string-width": {
|
||||
"version": "3.1.0",
|
||||
"resolved": "https://registry.npmjs.org/string-width/-/string-width-3.1.0.tgz",
|
||||
"integrity": "sha512-vafcv6KjVZKSgz06oM/H6GDBrAtz8vdhQakGjFIvNrHA6y3HCF1CInLy+QLq8dTJPQ1b+KDUqDFctkdRW44e1w==",
|
||||
"dev": true,
|
||||
"optional": true,
|
||||
"requires": {
|
||||
"emoji-regex": "^7.0.1",
|
||||
"is-fullwidth-code-point": "^2.0.0",
|
||||
@@ -3032,7 +3046,7 @@
|
||||
"version": "5.2.0",
|
||||
"resolved": "https://registry.npmjs.org/strip-ansi/-/strip-ansi-5.2.0.tgz",
|
||||
"integrity": "sha512-DuRs1gKbBqsMKIZlrffwlug8MHkcnpjs5VPmL1PAh+mA30U0DTotfDZ0d2UUsXpPmPmMMJ6W773MaA3J+lbiWA==",
|
||||
"dev": true,
|
||||
"optional": true,
|
||||
"requires": {
|
||||
"ansi-regex": "^4.1.0"
|
||||
}
|
||||
@@ -3041,7 +3055,7 @@
|
||||
"version": "14.2.0",
|
||||
"resolved": "https://registry.npmjs.org/yargs/-/yargs-14.2.0.tgz",
|
||||
"integrity": "sha512-/is78VKbKs70bVZH7w4YaZea6xcJWOAwkhbR0CFuZBmYtfTYF0xjGJF43AYd8g2Uii1yJwmS5GR2vBmrc32sbg==",
|
||||
"dev": true,
|
||||
"optional": true,
|
||||
"requires": {
|
||||
"cliui": "^5.0.0",
|
||||
"decamelize": "^1.2.0",
|
||||
@@ -3060,7 +3074,7 @@
|
||||
"version": "15.0.0",
|
||||
"resolved": "https://registry.npmjs.org/yargs-parser/-/yargs-parser-15.0.0.tgz",
|
||||
"integrity": "sha512-xLTUnCMc4JhxrPEPUYD5IBR1mWCK/aT6+RJ/K29JY2y1vD+FhtgKK0AXRWvI262q3QSffAQuTouFIKUuHX89wQ==",
|
||||
"dev": true,
|
||||
"optional": true,
|
||||
"requires": {
|
||||
"camelcase": "^5.0.0",
|
||||
"decamelize": "^1.2.0"
|
||||
@@ -3166,6 +3180,14 @@
|
||||
"sanitize-filename": "^1.6.0",
|
||||
"semver": "^6.0.0",
|
||||
"yargs-parser": "^16.0.0"
|
||||
},
|
||||
"dependencies": {
|
||||
"semver": {
|
||||
"version": "6.3.0",
|
||||
"resolved": "https://registry.npmjs.org/semver/-/semver-6.3.0.tgz",
|
||||
"integrity": "sha512-b39TBaTSfV6yBrapU89p5fKekE2m/NwnDocOVruQFS1/veMgdzuPcnOM34M6CwxW8jH/lxEa5rBoDeUwu5HHTw==",
|
||||
"dev": true
|
||||
}
|
||||
}
|
||||
},
|
||||
"electron-publish": {
|
||||
@@ -3320,8 +3342,7 @@
|
||||
"emoji-regex": {
|
||||
"version": "7.0.3",
|
||||
"resolved": "https://registry.npmjs.org/emoji-regex/-/emoji-regex-7.0.3.tgz",
|
||||
"integrity": "sha512-CwBLREIQ7LvYFB0WyRvwhq5N5qPhc6PMjD6bYggFlI5YyDgl+0vxq5VHbMOFqLg7hfWzmu8T5Z1QofhmTIhItA==",
|
||||
"dev": true
|
||||
"integrity": "sha512-CwBLREIQ7LvYFB0WyRvwhq5N5qPhc6PMjD6bYggFlI5YyDgl+0vxq5VHbMOFqLg7hfWzmu8T5Z1QofhmTIhItA=="
|
||||
},
|
||||
"encodeurl": {
|
||||
"version": "1.0.2",
|
||||
@@ -3389,18 +3410,10 @@
|
||||
"dev": true,
|
||||
"optional": true
|
||||
},
|
||||
"es6-promise": {
|
||||
"version": "4.2.8",
|
||||
"resolved": "https://registry.npmjs.org/es6-promise/-/es6-promise-4.2.8.tgz",
|
||||
"integrity": "sha512-HJDGx5daxeIvxdBxvG2cb9g4tEvwIk3i8+nhX0yGrYmZUzbkdg8QbDevheDB8gd0//uPj4c1EQua8Q+MViT0/w=="
|
||||
},
|
||||
"es6-promisify": {
|
||||
"version": "5.0.0",
|
||||
"resolved": "https://registry.npmjs.org/es6-promisify/-/es6-promisify-5.0.0.tgz",
|
||||
"integrity": "sha1-UQnWLz5W6pZ8S2NQWu8IKRyKUgM=",
|
||||
"requires": {
|
||||
"es6-promise": "^4.0.3"
|
||||
}
|
||||
"escape-goat": {
|
||||
"version": "2.1.1",
|
||||
"resolved": "https://registry.npmjs.org/escape-goat/-/escape-goat-2.1.1.tgz",
|
||||
"integrity": "sha512-8/uIhbG12Csjy2JEW7D9pHbreaVaS/OpN3ycnyvElTdwM5n6GY6W6e2IPemfvGZeUMqZ9A/3GqIZMgKnBhAw/Q=="
|
||||
},
|
||||
"escape-html": {
|
||||
"version": "1.0.3",
|
||||
@@ -3834,9 +3847,9 @@
|
||||
}
|
||||
},
|
||||
"file-type": {
|
||||
"version": "12.4.0",
|
||||
"resolved": "https://registry.npmjs.org/file-type/-/file-type-12.4.0.tgz",
|
||||
"integrity": "sha512-WTvyKq8yjtNmUtVAD8LGcTkvtCdJglM6ks2HTqEClm6+65XTqM6MoZYA1Vtra50DLRWLiM38fEs1y56f5VhnUA=="
|
||||
"version": "12.4.2",
|
||||
"resolved": "https://registry.npmjs.org/file-type/-/file-type-12.4.2.tgz",
|
||||
"integrity": "sha512-UssQP5ZgIOKelfsaB5CuGAL+Y+q7EmONuiwF3N5HAH0t27rvrttgi6Ra9k/+DVaY9UF6+ybxu5pOXLUdA8N7Vg=="
|
||||
},
|
||||
"filename-regex": {
|
||||
"version": "2.0.1",
|
||||
@@ -4094,7 +4107,7 @@
|
||||
"version": "1.0.4",
|
||||
"resolved": "https://registry.npmjs.org/gar/-/gar-1.0.4.tgz",
|
||||
"integrity": "sha512-w4n9cPWyP7aHxKxYHFQMegj7WIAsL/YX/C4Bs5Rr8s1H9M1rNtRWRsw+ovYMkXDQ5S4ZbYHsHAPmevPjPgw44w==",
|
||||
"dev": true
|
||||
"optional": true
|
||||
},
|
||||
"gauge": {
|
||||
"version": "2.7.4",
|
||||
@@ -4121,14 +4134,13 @@
|
||||
"get-caller-file": {
|
||||
"version": "2.0.5",
|
||||
"resolved": "https://registry.npmjs.org/get-caller-file/-/get-caller-file-2.0.5.tgz",
|
||||
"integrity": "sha512-DyFP3BM/3YHTQOCUL/w0OZHR0lpKeGrxotcHWcqNEdnltqFwXVfhEBQ94eIo34AfQpo0rGki4cyIiftY06h2Fg==",
|
||||
"dev": true
|
||||
"integrity": "sha512-DyFP3BM/3YHTQOCUL/w0OZHR0lpKeGrxotcHWcqNEdnltqFwXVfhEBQ94eIo34AfQpo0rGki4cyIiftY06h2Fg=="
|
||||
},
|
||||
"get-folder-size": {
|
||||
"version": "2.0.1",
|
||||
"resolved": "https://registry.npmjs.org/get-folder-size/-/get-folder-size-2.0.1.tgz",
|
||||
"integrity": "sha512-+CEb+GDCM7tkOS2wdMKTn9vU7DgnKUTuDlehkNJKNSovdCOVxs14OfKCk4cvSaR3za4gj+OBdl9opPN9xrJ0zA==",
|
||||
"dev": true,
|
||||
"optional": true,
|
||||
"requires": {
|
||||
"gar": "^1.0.4",
|
||||
"tiny-each-async": "2.0.3"
|
||||
@@ -4452,6 +4464,13 @@
|
||||
"integrity": "sha512-vKea1DrcLA80Hrfc7AQgfoGvEaByfR5mH08t+zuWOWY94TFBmabdEL56mUbcijvadG9RxsXR2gUUFrfj4/iTcA==",
|
||||
"dev": true,
|
||||
"optional": true
|
||||
},
|
||||
"semver": {
|
||||
"version": "6.3.0",
|
||||
"resolved": "https://registry.npmjs.org/semver/-/semver-6.3.0.tgz",
|
||||
"integrity": "sha512-b39TBaTSfV6yBrapU89p5fKekE2m/NwnDocOVruQFS1/veMgdzuPcnOM34M6CwxW8jH/lxEa5rBoDeUwu5HHTw==",
|
||||
"dev": true,
|
||||
"optional": true
|
||||
}
|
||||
}
|
||||
},
|
||||
@@ -4896,22 +4915,12 @@
|
||||
}
|
||||
},
|
||||
"http-proxy-agent": {
|
||||
"version": "2.1.0",
|
||||
"resolved": "https://registry.npmjs.org/http-proxy-agent/-/http-proxy-agent-2.1.0.tgz",
|
||||
"integrity": "sha512-qwHbBLV7WviBl0rQsOzH6o5lwyOIvwp/BdFnvVxXORldu5TmjFfjzBcWUWS5kWAZhmv+JtiDhSuQCp4sBfbIgg==",
|
||||
"version": "3.0.0",
|
||||
"resolved": "https://registry.npmjs.org/http-proxy-agent/-/http-proxy-agent-3.0.0.tgz",
|
||||
"integrity": "sha512-uGuJaBWQWDQCJI5ip0d/VTYZW0nRrlLWXA4A7P1jrsa+f77rW2yXz315oBt6zGCF6l8C2tlMxY7ffULCj+5FhA==",
|
||||
"requires": {
|
||||
"agent-base": "4",
|
||||
"debug": "3.1.0"
|
||||
},
|
||||
"dependencies": {
|
||||
"debug": {
|
||||
"version": "3.1.0",
|
||||
"resolved": "https://registry.npmjs.org/debug/-/debug-3.1.0.tgz",
|
||||
"integrity": "sha512-OX8XqP7/1a9cqkxYw2yXss15f26NKWBpDXQd0/uK/KPqdQhxbPa994hnzjcE2VqQpDslf55723cKPUOGSmMY3g==",
|
||||
"requires": {
|
||||
"ms": "2.0.0"
|
||||
}
|
||||
}
|
||||
"agent-base": "5",
|
||||
"debug": "4"
|
||||
}
|
||||
},
|
||||
"http-signature": {
|
||||
@@ -4925,27 +4934,12 @@
|
||||
}
|
||||
},
|
||||
"https-proxy-agent": {
|
||||
"version": "3.0.1",
|
||||
"resolved": "https://registry.npmjs.org/https-proxy-agent/-/https-proxy-agent-3.0.1.tgz",
|
||||
"integrity": "sha512-+ML2Rbh6DAuee7d07tYGEKOEi2voWPUGan+ExdPbPW6Z3svq+JCqr0v8WmKPOkz1vOVykPCBSuobe7G8GJUtVg==",
|
||||
"version": "4.0.0",
|
||||
"resolved": "https://registry.npmjs.org/https-proxy-agent/-/https-proxy-agent-4.0.0.tgz",
|
||||
"integrity": "sha512-zoDhWrkR3of1l9QAL8/scJZyLu8j/gBkcwcaQOZh7Gyh/+uJQzGVETdgT30akuwkpL8HTRfssqI3BZuV18teDg==",
|
||||
"requires": {
|
||||
"agent-base": "^4.3.0",
|
||||
"debug": "^3.1.0"
|
||||
},
|
||||
"dependencies": {
|
||||
"debug": {
|
||||
"version": "3.2.6",
|
||||
"resolved": "https://registry.npmjs.org/debug/-/debug-3.2.6.tgz",
|
||||
"integrity": "sha512-mel+jf7nrtEl5Pn1Qx46zARXKDpBbvzezse7p7LqINmdoIk8PYP5SySaxEmYv6TZ0JyEKA1hsCId6DIhgITtWQ==",
|
||||
"requires": {
|
||||
"ms": "^2.1.1"
|
||||
}
|
||||
},
|
||||
"ms": {
|
||||
"version": "2.1.2",
|
||||
"resolved": "https://registry.npmjs.org/ms/-/ms-2.1.2.tgz",
|
||||
"integrity": "sha512-sGkPx+VjMtmA6MX27oA4FBFELFCZZ4S4XqeGOXCv68tT+jb3vk/RyaKWP0PTKyWtmLSM0b+adUTEvbs1PEaH2w=="
|
||||
}
|
||||
"agent-base": "5",
|
||||
"debug": "4"
|
||||
}
|
||||
},
|
||||
"iconv-lite": {
|
||||
@@ -5819,7 +5813,6 @@
|
||||
"version": "3.0.0",
|
||||
"resolved": "https://registry.npmjs.org/locate-path/-/locate-path-3.0.0.tgz",
|
||||
"integrity": "sha512-7AO748wWnIhNqAuaty2ZWHkQHRSNfPVIsPIfwEOWO22AmaoVrWavlOcMR5nzTLNYvp36X220/maaRsrec1G65A==",
|
||||
"dev": true,
|
||||
"requires": {
|
||||
"p-locate": "^3.0.0",
|
||||
"path-exists": "^3.0.0"
|
||||
@@ -6068,6 +6061,13 @@
|
||||
"integrity": "sha512-grNJDhb8b1Jm1qeqW5R/O63wUo4UXo2v2HMic6YT9i/HBlF93S8jkMgH7yugvY9ABDShH4VZMn8I+U8+fCNegw==",
|
||||
"requires": {
|
||||
"semver": "^6.0.0"
|
||||
},
|
||||
"dependencies": {
|
||||
"semver": {
|
||||
"version": "6.3.0",
|
||||
"resolved": "https://registry.npmjs.org/semver/-/semver-6.3.0.tgz",
|
||||
"integrity": "sha512-b39TBaTSfV6yBrapU89p5fKekE2m/NwnDocOVruQFS1/veMgdzuPcnOM34M6CwxW8jH/lxEa5rBoDeUwu5HHTw=="
|
||||
}
|
||||
}
|
||||
},
|
||||
"map-obj": {
|
||||
@@ -7399,7 +7399,6 @@
|
||||
"version": "2.2.1",
|
||||
"resolved": "https://registry.npmjs.org/p-limit/-/p-limit-2.2.1.tgz",
|
||||
"integrity": "sha512-85Tk+90UCVWvbDavCLKPOLC9vvY8OwEX/RtKF+/1OADJMVlFfEHOiMTPVyxg7mk/dKa+ipdHm0OUkTvCpMTuwg==",
|
||||
"dev": true,
|
||||
"requires": {
|
||||
"p-try": "^2.0.0"
|
||||
}
|
||||
@@ -7408,7 +7407,6 @@
|
||||
"version": "3.0.0",
|
||||
"resolved": "https://registry.npmjs.org/p-locate/-/p-locate-3.0.0.tgz",
|
||||
"integrity": "sha512-x+12w/To+4GFfgJhBEpiDcLozRJGegY+Ei7/z0tSLkMmxGZNybVMSfWj9aJn8Z5Fc7dBUNJOOVgPv2H7IwulSQ==",
|
||||
"dev": true,
|
||||
"requires": {
|
||||
"p-limit": "^2.0.0"
|
||||
}
|
||||
@@ -7442,8 +7440,7 @@
|
||||
"p-try": {
|
||||
"version": "2.2.0",
|
||||
"resolved": "https://registry.npmjs.org/p-try/-/p-try-2.2.0.tgz",
|
||||
"integrity": "sha512-R4nPAVTAU0B9D35/Gk3uJf/7XYbQcyohSKdvAxIRSNghFl4e71hVoGnBNQz9cWaXxO2I10KTC+3jMdvvoKw6dQ==",
|
||||
"dev": true
|
||||
"integrity": "sha512-R4nPAVTAU0B9D35/Gk3uJf/7XYbQcyohSKdvAxIRSNghFl4e71hVoGnBNQz9cWaXxO2I10KTC+3jMdvvoKw6dQ=="
|
||||
},
|
||||
"package-json": {
|
||||
"version": "6.5.0",
|
||||
@@ -7547,6 +7544,12 @@
|
||||
"integrity": "sha1-6SQ0v6XqjBn0HN/UAddBo8gZ2Jc=",
|
||||
"dev": true
|
||||
},
|
||||
"semver": {
|
||||
"version": "6.3.0",
|
||||
"resolved": "https://registry.npmjs.org/semver/-/semver-6.3.0.tgz",
|
||||
"integrity": "sha512-b39TBaTSfV6yBrapU89p5fKekE2m/NwnDocOVruQFS1/veMgdzuPcnOM34M6CwxW8jH/lxEa5rBoDeUwu5HHTw==",
|
||||
"dev": true
|
||||
},
|
||||
"url-parse-lax": {
|
||||
"version": "3.0.0",
|
||||
"resolved": "https://registry.npmjs.org/url-parse-lax/-/url-parse-lax-3.0.0.tgz",
|
||||
@@ -7567,7 +7570,6 @@
|
||||
"version": "2.0.0",
|
||||
"resolved": "https://registry.npmjs.org/parse-author/-/parse-author-2.0.0.tgz",
|
||||
"integrity": "sha1-00YL8d3Q367tQtp1QkLmX7aEqB8=",
|
||||
"dev": true,
|
||||
"requires": {
|
||||
"author-regex": "^1.0.0"
|
||||
}
|
||||
@@ -8496,9 +8498,12 @@
|
||||
"integrity": "sha512-XRsRjdf+j5ml+y/6GKHPZbrF/8p2Yga0JPtdqTIY2Xe5ohJPD9saDJJLPvp9+NSBprVvevdXZybnj2cv8OEd0A=="
|
||||
},
|
||||
"pupa": {
|
||||
"version": "1.0.0",
|
||||
"resolved": "https://registry.npmjs.org/pupa/-/pupa-1.0.0.tgz",
|
||||
"integrity": "sha1-mpVopa9+ZXuEYqbp1TKHQ1YM7/Y="
|
||||
"version": "2.0.1",
|
||||
"resolved": "https://registry.npmjs.org/pupa/-/pupa-2.0.1.tgz",
|
||||
"integrity": "sha512-hEJH0s8PXLY/cdXh66tNEQGndDrIKNqNC5xmrysZy3i5C3oEoLna7YAOad+7u125+zH1HNXUmGEkrhb3c2VriA==",
|
||||
"requires": {
|
||||
"escape-goat": "^2.0.0"
|
||||
}
|
||||
},
|
||||
"qs": {
|
||||
"version": "6.7.0",
|
||||
@@ -8796,14 +8801,12 @@
|
||||
"require-directory": {
|
||||
"version": "2.1.1",
|
||||
"resolved": "https://registry.npmjs.org/require-directory/-/require-directory-2.1.1.tgz",
|
||||
"integrity": "sha1-jGStX9MNqxyXbiNE/+f3kqam30I=",
|
||||
"dev": true
|
||||
"integrity": "sha1-jGStX9MNqxyXbiNE/+f3kqam30I="
|
||||
},
|
||||
"require-main-filename": {
|
||||
"version": "2.0.0",
|
||||
"resolved": "https://registry.npmjs.org/require-main-filename/-/require-main-filename-2.0.0.tgz",
|
||||
"integrity": "sha512-NKN5kMDylKuldxYLSUfrbo5Tuzh4hd+2E8NPPX02mZtn1VuREQToYe/ZdlJy+J3uCpfaiGF05e7B8W0iXbQHmg==",
|
||||
"dev": true
|
||||
"integrity": "sha512-NKN5kMDylKuldxYLSUfrbo5Tuzh4hd+2E8NPPX02mZtn1VuREQToYe/ZdlJy+J3uCpfaiGF05e7B8W0iXbQHmg=="
|
||||
},
|
||||
"requizzle": {
|
||||
"version": "0.2.3",
|
||||
@@ -8966,9 +8969,9 @@
|
||||
}
|
||||
},
|
||||
"semver": {
|
||||
"version": "6.3.0",
|
||||
"resolved": "https://registry.npmjs.org/semver/-/semver-6.3.0.tgz",
|
||||
"integrity": "sha512-b39TBaTSfV6yBrapU89p5fKekE2m/NwnDocOVruQFS1/veMgdzuPcnOM34M6CwxW8jH/lxEa5rBoDeUwu5HHTw=="
|
||||
"version": "7.1.1",
|
||||
"resolved": "https://registry.npmjs.org/semver/-/semver-7.1.1.tgz",
|
||||
"integrity": "sha512-WfuG+fl6eh3eZ2qAf6goB7nhiCd7NPXhmyFxigB/TOkQyeLP8w8GsVehvtGNtnNmyboz4TgeK40B1Kbql/8c5A=="
|
||||
},
|
||||
"semver-compare": {
|
||||
"version": "1.0.0",
|
||||
@@ -9706,7 +9709,7 @@
|
||||
"version": "2.0.3",
|
||||
"resolved": "https://registry.npmjs.org/tiny-each-async/-/tiny-each-async-2.0.3.tgz",
|
||||
"integrity": "sha1-jru/1tYpXxNwAD+7NxYq/loKUdE=",
|
||||
"dev": true
|
||||
"optional": true
|
||||
},
|
||||
"tinycolor2": {
|
||||
"version": "1.4.1",
|
||||
@@ -9717,7 +9720,6 @@
|
||||
"version": "0.1.0",
|
||||
"resolved": "https://registry.npmjs.org/tmp/-/tmp-0.1.0.tgz",
|
||||
"integrity": "sha512-J7Z2K08jbGcdA1kkQpJSqLF6T0tdQqpR2pnSUXsIchbPdTI9v3e85cLW0d6WDhwuAleOV71j2xWs8qMPfK7nKw==",
|
||||
"dev": true,
|
||||
"requires": {
|
||||
"rimraf": "^2.6.3"
|
||||
},
|
||||
@@ -9726,7 +9728,6 @@
|
||||
"version": "7.1.4",
|
||||
"resolved": "https://registry.npmjs.org/glob/-/glob-7.1.4.tgz",
|
||||
"integrity": "sha512-hkLPepehmnKk41pUGm3sYxoFs/umurYfYJCerbXEyFIWcAzvpipAgVkBqqT9RBKMGjnq6kMuyYwha6csxbiM1A==",
|
||||
"dev": true,
|
||||
"requires": {
|
||||
"fs.realpath": "^1.0.0",
|
||||
"inflight": "^1.0.4",
|
||||
@@ -9740,7 +9741,6 @@
|
||||
"version": "2.7.1",
|
||||
"resolved": "https://registry.npmjs.org/rimraf/-/rimraf-2.7.1.tgz",
|
||||
"integrity": "sha512-uWjbaKIK3T1OSVptzX7Nl6PvQ3qAGtKEtVRjRuazjfL3Bx5eI409VZSqgND+4UNnmzLVdPj9FqFJNPqBZFve4w==",
|
||||
"dev": true,
|
||||
"requires": {
|
||||
"glob": "^7.1.3"
|
||||
}
|
||||
@@ -9751,7 +9751,7 @@
|
||||
"version": "2.0.2",
|
||||
"resolved": "https://registry.npmjs.org/tmp-promise/-/tmp-promise-2.0.2.tgz",
|
||||
"integrity": "sha512-zl71nFWjPKW2KXs+73gEk8RmqvtAeXPxhWDkTUoa3MSMkjq3I+9OeknjF178MQoMYsdqL730hfzvNfEkePxq9Q==",
|
||||
"dev": true,
|
||||
"optional": true,
|
||||
"requires": {
|
||||
"tmp": "0.1.0"
|
||||
}
|
||||
@@ -9986,12 +9986,19 @@
|
||||
"integrity": "sha1-sr9O6FFKrmFltIF4KdIbLvSZBOw="
|
||||
},
|
||||
"unused-filename": {
|
||||
"version": "1.0.0",
|
||||
"resolved": "https://registry.npmjs.org/unused-filename/-/unused-filename-1.0.0.tgz",
|
||||
"integrity": "sha1-00CID3GuIRXrqhMlvvBcxmhEacY=",
|
||||
"version": "2.1.0",
|
||||
"resolved": "https://registry.npmjs.org/unused-filename/-/unused-filename-2.1.0.tgz",
|
||||
"integrity": "sha512-BMiNwJbuWmqCpAM1FqxCTD7lXF97AvfQC8Kr/DIeA6VtvhJaMDupZ82+inbjl5yVP44PcxOuCSxye1QMS0wZyg==",
|
||||
"requires": {
|
||||
"modify-filename": "^1.1.0",
|
||||
"path-exists": "^3.0.0"
|
||||
"path-exists": "^4.0.0"
|
||||
},
|
||||
"dependencies": {
|
||||
"path-exists": {
|
||||
"version": "4.0.0",
|
||||
"resolved": "https://registry.npmjs.org/path-exists/-/path-exists-4.0.0.tgz",
|
||||
"integrity": "sha512-ak9Qy5Q7jYb2Wwcey5Fpvg2KoAc/ZIhLSLOSBmRmygPsGwkVVt0fZa0qrtMz+m6tJTAHfZQ8FnmB4MG4LWy7/w=="
|
||||
}
|
||||
}
|
||||
},
|
||||
"unzip-response": {
|
||||
@@ -10288,8 +10295,7 @@
|
||||
"which-module": {
|
||||
"version": "2.0.0",
|
||||
"resolved": "https://registry.npmjs.org/which-module/-/which-module-2.0.0.tgz",
|
||||
"integrity": "sha1-2e8H3Od7mQK4o6j6SzHD4/fm6Ho=",
|
||||
"dev": true
|
||||
"integrity": "sha1-2e8H3Od7mQK4o6j6SzHD4/fm6Ho="
|
||||
},
|
||||
"wide-align": {
|
||||
"version": "1.1.3",
|
||||
@@ -10345,7 +10351,7 @@
|
||||
"version": "1.2.3",
|
||||
"resolved": "https://registry.npmjs.org/word-wrap/-/word-wrap-1.2.3.tgz",
|
||||
"integrity": "sha512-Hz/mrNwitNRh/HUAtM/VT/5VH+ygD6DV7mYKZAtHOrbs8U7lvPS6xf7EJKMF0uW1KJCl0H701g3ZGus+muE5vQ==",
|
||||
"dev": true
|
||||
"optional": true
|
||||
},
|
||||
"wordwrap": {
|
||||
"version": "1.0.0",
|
||||
@@ -10356,7 +10362,6 @@
|
||||
"version": "5.1.0",
|
||||
"resolved": "https://registry.npmjs.org/wrap-ansi/-/wrap-ansi-5.1.0.tgz",
|
||||
"integrity": "sha512-QC1/iN/2/RPVJ5jYK8BGttj5z83LmSKmvbvrXPNCLZSEb32KKVDJDl/MOt2N01qU2H/FkzEa9PKto1BqDjtd7Q==",
|
||||
"dev": true,
|
||||
"requires": {
|
||||
"ansi-styles": "^3.2.0",
|
||||
"string-width": "^3.0.0",
|
||||
@@ -10366,14 +10371,12 @@
|
||||
"ansi-regex": {
|
||||
"version": "4.1.0",
|
||||
"resolved": "https://registry.npmjs.org/ansi-regex/-/ansi-regex-4.1.0.tgz",
|
||||
"integrity": "sha512-1apePfXM1UOSqw0o9IiFAovVz9M5S1Dg+4TrDwfMewQ6p/rmMueb7tWZjQ1rx4Loy1ArBggoqGpfqqdI4rondg==",
|
||||
"dev": true
|
||||
"integrity": "sha512-1apePfXM1UOSqw0o9IiFAovVz9M5S1Dg+4TrDwfMewQ6p/rmMueb7tWZjQ1rx4Loy1ArBggoqGpfqqdI4rondg=="
|
||||
},
|
||||
"ansi-styles": {
|
||||
"version": "3.2.1",
|
||||
"resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-3.2.1.tgz",
|
||||
"integrity": "sha512-VT0ZI6kZRdTh8YyJw3SMbYm/u+NqfsAxEpWO0Pf9sq8/e94WxxOpPKx9FR1FlyCtOVDNOQ+8ntlqFxiRc+r5qA==",
|
||||
"dev": true,
|
||||
"requires": {
|
||||
"color-convert": "^1.9.0"
|
||||
}
|
||||
@@ -10381,14 +10384,12 @@
|
||||
"is-fullwidth-code-point": {
|
||||
"version": "2.0.0",
|
||||
"resolved": "https://registry.npmjs.org/is-fullwidth-code-point/-/is-fullwidth-code-point-2.0.0.tgz",
|
||||
"integrity": "sha1-o7MKXE8ZkYMWeqq5O+764937ZU8=",
|
||||
"dev": true
|
||||
"integrity": "sha1-o7MKXE8ZkYMWeqq5O+764937ZU8="
|
||||
},
|
||||
"string-width": {
|
||||
"version": "3.1.0",
|
||||
"resolved": "https://registry.npmjs.org/string-width/-/string-width-3.1.0.tgz",
|
||||
"integrity": "sha512-vafcv6KjVZKSgz06oM/H6GDBrAtz8vdhQakGjFIvNrHA6y3HCF1CInLy+QLq8dTJPQ1b+KDUqDFctkdRW44e1w==",
|
||||
"dev": true,
|
||||
"requires": {
|
||||
"emoji-regex": "^7.0.1",
|
||||
"is-fullwidth-code-point": "^2.0.0",
|
||||
@@ -10399,7 +10400,6 @@
|
||||
"version": "5.2.0",
|
||||
"resolved": "https://registry.npmjs.org/strip-ansi/-/strip-ansi-5.2.0.tgz",
|
||||
"integrity": "sha512-DuRs1gKbBqsMKIZlrffwlug8MHkcnpjs5VPmL1PAh+mA30U0DTotfDZ0d2UUsXpPmPmMMJ6W773MaA3J+lbiWA==",
|
||||
"dev": true,
|
||||
"requires": {
|
||||
"ansi-regex": "^4.1.0"
|
||||
}
|
||||
@@ -10430,12 +10430,9 @@
|
||||
}
|
||||
},
|
||||
"ws": {
|
||||
"version": "7.2.0",
|
||||
"resolved": "https://registry.npmjs.org/ws/-/ws-7.2.0.tgz",
|
||||
"integrity": "sha512-+SqNqFbwTm/0DC18KYzIsMTnEWpLwJsiasW/O17la4iDRRIO9uaHbvKiAS3AHgTiuuWerK/brj4O6MYZkei9xg==",
|
||||
"requires": {
|
||||
"async-limiter": "^1.0.0"
|
||||
}
|
||||
"version": "7.2.1",
|
||||
"resolved": "https://registry.npmjs.org/ws/-/ws-7.2.1.tgz",
|
||||
"integrity": "sha512-sucePNSafamSKoOqoNfBd8V0StlkzJKL2ZAhGQinCfNQ+oacw+Pk7lcdAElecBF2VkLNZRiIb5Oi1Q5lVUVt2A=="
|
||||
},
|
||||
"x-xss-protection": {
|
||||
"version": "1.3.0",
|
||||
@@ -10509,8 +10506,7 @@
|
||||
"y18n": {
|
||||
"version": "4.0.0",
|
||||
"resolved": "https://registry.npmjs.org/y18n/-/y18n-4.0.0.tgz",
|
||||
"integrity": "sha512-r9S/ZyXu/Xu9q1tYlpsLIsa3EeLXXk0VwlxqTcFRfg9EhMW+17kbt9G0NrgCmhGb5vT2hyhJZLfDGx+7+5Uj/w==",
|
||||
"dev": true
|
||||
"integrity": "sha512-r9S/ZyXu/Xu9q1tYlpsLIsa3EeLXXk0VwlxqTcFRfg9EhMW+17kbt9G0NrgCmhGb5vT2hyhJZLfDGx+7+5Uj/w=="
|
||||
},
|
||||
"yallist": {
|
||||
"version": "3.1.1",
|
||||
|
||||
+11
-9
@@ -2,7 +2,7 @@
|
||||
"name": "trilium",
|
||||
"productName": "Trilium Notes",
|
||||
"description": "Trilium Notes",
|
||||
"version": "0.38.3",
|
||||
"version": "0.39.1-beta",
|
||||
"license": "AGPL-3.0-only",
|
||||
"main": "electron.js",
|
||||
"bin": {
|
||||
@@ -27,23 +27,23 @@
|
||||
"commonmark": "0.29.0",
|
||||
"cookie-parser": "1.4.4",
|
||||
"csurf": "1.10.0",
|
||||
"dayjs": "1.8.17",
|
||||
"dayjs": "1.8.18",
|
||||
"debug": "4.1.1",
|
||||
"ejs": "2.7.4",
|
||||
"electron-debug": "3.0.1",
|
||||
"electron-dl": "1.14.0",
|
||||
"electron-dl": "2.0.0",
|
||||
"electron-find": "1.0.6",
|
||||
"electron-spellchecker": "2.2.1",
|
||||
"electron-window-state": "5.0.3",
|
||||
"express": "4.17.1",
|
||||
"express-session": "1.17.0",
|
||||
"file-type": "12.4.0",
|
||||
"file-type": "12.4.2",
|
||||
"fs-extra": "8.1.0",
|
||||
"helmet": "3.21.2",
|
||||
"html": "1.0.0",
|
||||
"html2plaintext": "2.1.2",
|
||||
"http-proxy-agent": "2.1.0",
|
||||
"https-proxy-agent": "3.0.1",
|
||||
"http-proxy-agent": "3.0.0",
|
||||
"https-proxy-agent": "4.0.0",
|
||||
"image-type": "4.1.0",
|
||||
"imagemin": "7.0.1",
|
||||
"imagemin-giflossy": "5.1.10",
|
||||
@@ -63,7 +63,7 @@
|
||||
"rimraf": "3.0.0",
|
||||
"sanitize-filename": "1.6.3",
|
||||
"sax": "1.2.4",
|
||||
"semver": "6.3.0",
|
||||
"semver": "7.1.1",
|
||||
"serve-favicon": "2.5.0",
|
||||
"session-file-store": "1.3.1",
|
||||
"simple-node-logger": "18.12.23",
|
||||
@@ -74,15 +74,17 @@
|
||||
"turndown": "5.0.3",
|
||||
"turndown-plugin-gfm": "1.0.2",
|
||||
"unescape": "1.0.1",
|
||||
"ws": "7.2.0"
|
||||
"ws": "7.2.1"
|
||||
},
|
||||
"devDependencies": {
|
||||
"electron": "6.0.12",
|
||||
"electron-builder": "22.1.0",
|
||||
"electron-installer-debian": "2.0.1",
|
||||
"electron-packager": "14.1.1",
|
||||
"electron-rebuild": "1.8.8",
|
||||
"jsdoc": "3.6.3",
|
||||
"lorem-ipsum": "2.0.3"
|
||||
},
|
||||
"optionalDependencies": {
|
||||
"electron-installer-debian": "2.0.1"
|
||||
}
|
||||
}
|
||||
|
||||
@@ -31,6 +31,8 @@ import dateNoteService from './services/date_notes.js';
|
||||
import sidebarService from './services/sidebar.js';
|
||||
import importService from './services/import.js';
|
||||
import keyboardActionService from "./services/keyboard_actions.js";
|
||||
import splitService from "./services/split.js";
|
||||
import optionService from "./services/options.js";
|
||||
|
||||
window.glob.isDesktop = utils.isDesktop;
|
||||
window.glob.isMobile = utils.isMobile;
|
||||
@@ -142,7 +144,10 @@ async function printActiveNote() {
|
||||
$tabContext.$tabContent.find('.note-detail-component:visible').printThis({
|
||||
header: $("<h2>").text($tabContext.note && $tabContext.note.title).prop('outerHTML') ,
|
||||
importCSS: false,
|
||||
loadCSS: "libraries/codemirror/codemirror.css",
|
||||
loadCSS: [
|
||||
"libraries/codemirror/codemirror.css",
|
||||
"libraries/ckeditor/ckeditor-content.css"
|
||||
],
|
||||
debug: true
|
||||
});
|
||||
}
|
||||
@@ -176,4 +181,34 @@ noteAutocompleteService.init();
|
||||
|
||||
if (utils.isElectron()) {
|
||||
import("./services/spell_check.js").then(spellCheckService => spellCheckService.initSpellCheck());
|
||||
}
|
||||
}
|
||||
|
||||
optionService.waitForOptions().then(options => {
|
||||
if (utils.isElectron() && !options.is('nativeTitleBarVisible')) {
|
||||
$("#title-bar-buttons").show();
|
||||
|
||||
$("#minimize-btn").on('click', () => {
|
||||
$("#minimize-btn").trigger('blur');
|
||||
const {remote} = require('electron');
|
||||
remote.BrowserWindow.getFocusedWindow().minimize();
|
||||
});
|
||||
|
||||
$("#maximize-btn").on('click', () => {
|
||||
$("#maximize-btn").trigger('blur');
|
||||
const {remote} = require('electron');
|
||||
const focusedWindow = remote.BrowserWindow.getFocusedWindow();
|
||||
|
||||
if (focusedWindow.isMaximized()) {
|
||||
focusedWindow.unmaximize();
|
||||
} else {
|
||||
focusedWindow.maximize();
|
||||
}
|
||||
});
|
||||
|
||||
$("#close-btn").on('click', () => {
|
||||
$("#close-btn").trigger('blur');
|
||||
const {remote} = require('electron');
|
||||
remote.BrowserWindow.getFocusedWindow().close();
|
||||
});
|
||||
}
|
||||
});
|
||||
@@ -19,12 +19,13 @@ const TPL = `
|
||||
|
||||
<input type="number" class="form-control" id="zoom-factor-select" min="0.3" max="2.0" step="0.1"/>
|
||||
</div>
|
||||
|
||||
|
||||
<div class="col-4">
|
||||
<label for="one-tab-display-select">If there's only one tab, then...</label>
|
||||
<select class="form-control" id="one-tab-display-select">
|
||||
<option value="show">show the tab bar</option>
|
||||
<option value="hide">hide the tab bar</option>
|
||||
<label for="native-title-bar-select">Native title bar (requires app restart)</label>
|
||||
|
||||
<select class="form-control" id="native-title-bar-select">
|
||||
<option value="show">enabled</option>
|
||||
<option value="hide">disabled</option>
|
||||
</select>
|
||||
</div>
|
||||
</div>
|
||||
@@ -69,37 +70,6 @@ const TPL = `
|
||||
</div>
|
||||
|
||||
<p>Note that tree and detail font sizing is relative to the main font size setting.</p>
|
||||
|
||||
<h4>Left pane sizing</h4>
|
||||
|
||||
<div class="form-group row">
|
||||
<div class="col-6">
|
||||
<label for="left-pane-min-width">Left pane minimum width (in pixels)</label>
|
||||
|
||||
<div class="input-group">
|
||||
<input type="number" class="form-control" id="left-pane-min-width" min="100" max="2000" step="1"/>
|
||||
|
||||
<div class="input-group-append">
|
||||
<span class="input-group-text">px</span>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="col-6">
|
||||
<label for="left-pane-min-width">Left pane width percent of window size</label>
|
||||
|
||||
<div class="input-group">
|
||||
<input type="number" class="form-control" id="left-pane-width-percent" min="0" max="99" step="1"/>
|
||||
|
||||
<div class="input-group-append">
|
||||
<span class="input-group-text">%</span>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<p>Left pane width is calculated from the percent of window size, if this is smaller than minimum width, then minimum width is used. If you want to have fixed width left pane, set minimum width to the desired width and set percent to 0.</p>
|
||||
|
||||
</form>`;
|
||||
|
||||
export default class ApperanceOptions {
|
||||
@@ -108,9 +78,7 @@ export default class ApperanceOptions {
|
||||
|
||||
this.$themeSelect = $("#theme-select");
|
||||
this.$zoomFactorSelect = $("#zoom-factor-select");
|
||||
this.$oneTabDisplaySelect = $("#one-tab-display-select");
|
||||
this.$leftPaneMinWidth = $("#left-pane-min-width");
|
||||
this.$leftPaneWidthPercent = $("#left-pane-width-percent");
|
||||
this.$nativeTitleBarSelect = $("#native-title-bar-select");
|
||||
this.$mainFontSize = $("#main-font-size");
|
||||
this.$treeFontSize = $("#tree-font-size");
|
||||
this.$detailFontSize = $("#detail-font-size");
|
||||
@@ -141,23 +109,10 @@ export default class ApperanceOptions {
|
||||
|
||||
this.$zoomFactorSelect.on('change', () => { zoomService.setZoomFactorAndSave(this.$zoomFactorSelect.val()); });
|
||||
|
||||
this.$oneTabDisplaySelect.on('change', () => {
|
||||
const hideTabRowForOneTab = this.$oneTabDisplaySelect.val() === 'hide' ? 'true' : 'false';
|
||||
this.$nativeTitleBarSelect.on('change', () => {
|
||||
const nativeTitleBarVisible = this.$nativeTitleBarSelect.val() === 'show' ? 'true' : 'false';
|
||||
|
||||
server.put('options/hideTabRowForOneTab/' + hideTabRowForOneTab)
|
||||
.then(optionsService.reloadOptions);
|
||||
});
|
||||
|
||||
this.$leftPaneMinWidth.on('change', async () => {
|
||||
await server.put('options/leftPaneMinWidth/' + this.$leftPaneMinWidth.val());
|
||||
|
||||
this.resizeLeftPanel();
|
||||
});
|
||||
|
||||
this.$leftPaneWidthPercent.on('change', async () => {
|
||||
await server.put('options/leftPaneWidthPercent/' + this.$leftPaneWidthPercent.val());
|
||||
|
||||
this.resizeLeftPanel();
|
||||
server.put('options/nativeTitleBarVisible/' + nativeTitleBarVisible);
|
||||
});
|
||||
|
||||
this.$mainFontSize.on('change', async () => {
|
||||
@@ -204,24 +159,13 @@ export default class ApperanceOptions {
|
||||
this.$zoomFactorSelect.prop('disabled', true);
|
||||
}
|
||||
|
||||
this.$oneTabDisplaySelect.val(options.hideTabRowForOneTab === 'true' ? 'hide' : 'show');
|
||||
|
||||
this.$leftPaneMinWidth.val(options.leftPaneMinWidth);
|
||||
this.$leftPaneWidthPercent.val(options.leftPaneWidthPercent);
|
||||
this.$nativeTitleBarSelect.val(options.nativeTitleBarVisible === 'true' ? 'show' : 'hide');
|
||||
|
||||
this.$mainFontSize.val(options.mainFontSize);
|
||||
this.$treeFontSize.val(options.treeFontSize);
|
||||
this.$detailFontSize.val(options.detailFontSize);
|
||||
}
|
||||
|
||||
resizeLeftPanel() {
|
||||
const leftPanePercent = parseInt(this.$leftPaneWidthPercent.val());
|
||||
const rightPanePercent = 100 - leftPanePercent;
|
||||
const leftPaneMinWidth = this.$leftPaneMinWidth.val();
|
||||
|
||||
this.$container.css("grid-template-columns", `minmax(${leftPaneMinWidth}px, ${leftPanePercent}fr) ${rightPanePercent}fr`);
|
||||
}
|
||||
|
||||
applyFontSizes() {
|
||||
this.$body.get(0).style.setProperty("--main-font-size", this.$mainFontSize.val() + "%");
|
||||
this.$body.get(0).style.setProperty("--tree-font-size", this.$treeFontSize.val() + "%");
|
||||
|
||||
@@ -3,45 +3,6 @@ import server from "../../services/server.js";
|
||||
import optionsService from "../../services/options.js";
|
||||
|
||||
const TPL = `
|
||||
<h4>Show sidebar in new tab</h4>
|
||||
|
||||
<div class="form-check">
|
||||
<input type="checkbox" class="form-check-input" id="show-sidebar-in-new-tab">
|
||||
<label class="form-check-label" for="show-sidebar-in-new-tab">Show sidebar in new tab</label>
|
||||
</div>
|
||||
|
||||
<br>
|
||||
|
||||
<h4>Sidebar sizing</h4>
|
||||
|
||||
<div class="form-group row">
|
||||
<div class="col-6">
|
||||
<label for="sidebar-min-width">Sidebar minimum width (in pixels)</label>
|
||||
|
||||
<div class="input-group">
|
||||
<input type="number" class="form-control" id="sidebar-min-width" min="100" max="2000" step="1"/>
|
||||
|
||||
<div class="input-group-append">
|
||||
<span class="input-group-text">px</span>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="col-6">
|
||||
<label for="left-pane-min-width">Sidebar width percent of the detail pane</label>
|
||||
|
||||
<div class="input-group">
|
||||
<input type="number" class="form-control" id="sidebar-width-percent" min="0" max="70" step="1"/>
|
||||
|
||||
<div class="input-group-append">
|
||||
<span class="input-group-text">%</span>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<p>Sidebar width is calculated from the percent of the detail pane, if this is smaller than minimum width, then minimum width is used. If you want to have fixed width sidebar, set minimum width to the desired width and set percent to 0.</p>
|
||||
|
||||
<h4>Widgets</h4>
|
||||
|
||||
<div id="widgets-configuration" class="row">
|
||||
@@ -58,48 +19,15 @@ export default class SidebarOptions {
|
||||
constructor() {
|
||||
$("#options-sidebar").html(TPL);
|
||||
|
||||
this.$sidebarMinWidth = $("#sidebar-min-width");
|
||||
this.$sidebarWidthPercent = $("#sidebar-width-percent");
|
||||
this.$showSidebarInNewTab = $("#show-sidebar-in-new-tab");
|
||||
this.$widgetsConfiguration = $("#widgets-configuration");
|
||||
this.$widgetsEnabled = $("#widgets-enabled");
|
||||
this.$widgetsDisabled = $("#widgets-disabled");
|
||||
|
||||
this.$sidebarMinWidth.on('change', async () => {
|
||||
await server.put('options/sidebarMinWidth/' + this.$sidebarMinWidth.val());
|
||||
|
||||
this.resizeSidebar();
|
||||
});
|
||||
|
||||
this.$sidebarWidthPercent.on('change', async () => {
|
||||
await server.put('options/sidebarWidthPercent/' + this.$sidebarWidthPercent.val());
|
||||
|
||||
this.resizeSidebar();
|
||||
});
|
||||
|
||||
this.$showSidebarInNewTab.on('change', async () => {
|
||||
const flag = this.$showSidebarInNewTab.is(":checked") ? 'true' : 'false';
|
||||
|
||||
await server.put('options/showSidebarInNewTab/' + flag);
|
||||
|
||||
optionsService.reloadOptions();
|
||||
});
|
||||
}
|
||||
|
||||
async optionsLoaded(options) {
|
||||
this.$widgetsEnabled.empty();
|
||||
this.$widgetsDisabled.empty();
|
||||
|
||||
this.$sidebarMinWidth.val(options.sidebarMinWidth);
|
||||
this.$sidebarWidthPercent.val(options.sidebarWidthPercent);
|
||||
|
||||
if (options.showSidebarInNewTab === 'true') {
|
||||
this.$showSidebarInNewTab.attr("checked", "checked");
|
||||
}
|
||||
else {
|
||||
this.$showSidebarInNewTab.removeAttr("checked");
|
||||
}
|
||||
|
||||
const widgets = [
|
||||
{name: 'attributes', title: 'Attributes'},
|
||||
{name: 'linkMap', title: 'Link map'},
|
||||
@@ -188,19 +116,4 @@ export default class SidebarOptions {
|
||||
return null;
|
||||
}
|
||||
}
|
||||
|
||||
resizeSidebar() {
|
||||
const sidebarWidthPercent = parseInt(this.$sidebarWidthPercent.val());
|
||||
const sidebarMinWidth = this.$sidebarMinWidth.val();
|
||||
|
||||
// need to find them dynamically since they change
|
||||
const $sidebar = $(".note-detail-sidebar");
|
||||
|
||||
const $content = $(".note-detail-content");
|
||||
|
||||
$sidebar.css("width", sidebarWidthPercent + '%');
|
||||
$sidebar.css("min-width", sidebarMinWidth + 'px');
|
||||
|
||||
$content.css("width", (100 - sidebarWidthPercent) + '%');
|
||||
}
|
||||
}
|
||||
@@ -112,10 +112,21 @@ function registerEntrypoints() {
|
||||
keyboardActionService.setGlobalActionHandler("ForwardInNoteHistory", window.history.forward);
|
||||
}
|
||||
|
||||
let zenModeActive = false;
|
||||
|
||||
// hide (toggle) everything except for the note content for zen mode
|
||||
const toggleZenMode = () => {
|
||||
$(".hide-in-zen-mode").toggle();
|
||||
$("#container").toggleClass("zen-mode");
|
||||
if (!zenModeActive) {
|
||||
$(".hide-in-zen-mode").addClass("hidden-by-zen-mode");
|
||||
$("#container").addClass("zen-mode");
|
||||
zenModeActive = true;
|
||||
}
|
||||
else {
|
||||
// not hiding / showing explicitly since element might be hidden also for other reasons
|
||||
$(".hide-in-zen-mode").removeClass("hidden-by-zen-mode");
|
||||
$("#container").removeClass("zen-mode");
|
||||
zenModeActive = false;
|
||||
}
|
||||
};
|
||||
|
||||
$("#toggle-zen-mode-button").on('click', toggleZenMode);
|
||||
|
||||
@@ -1,6 +1,47 @@
|
||||
import bundleService from "./bundle.js";
|
||||
import ws from "./ws.js";
|
||||
import optionsService from "./options.js";
|
||||
import splitService from "./split.js";
|
||||
import optionService from "./options.js";
|
||||
import server from "./server.js";
|
||||
import noteDetailService from "./note_detail.js";
|
||||
|
||||
const $sidebar = $("#right-pane");
|
||||
const $sidebarContainer = $('#sidebar-container');
|
||||
|
||||
const $showSidebarButton = $("#show-sidebar-button");
|
||||
const $hideSidebarButton = $("#hide-sidebar-button");
|
||||
|
||||
optionService.waitForOptions().then(options => toggleSidebar(options.is('rightPaneVisible')));
|
||||
|
||||
function toggleSidebar(show) {
|
||||
$sidebar.toggle(show);
|
||||
$showSidebarButton.toggle(!show);
|
||||
$hideSidebarButton.toggle(show);
|
||||
|
||||
if (show) {
|
||||
splitService.setupSplitWithSidebar();
|
||||
}
|
||||
else {
|
||||
splitService.setupSplitWithoutSidebar();
|
||||
}
|
||||
}
|
||||
|
||||
$hideSidebarButton.on('click', () => {
|
||||
toggleSidebar(false);
|
||||
|
||||
server.put('options/rightPaneVisible/false');
|
||||
});
|
||||
|
||||
$showSidebarButton.on('click', async () => {
|
||||
toggleSidebar(true);
|
||||
|
||||
await server.put('options/rightPaneVisible/true');
|
||||
|
||||
const {sidebar} = noteDetailService.getActiveTabContext();
|
||||
await sidebar.noteLoaded();
|
||||
sidebar.show();
|
||||
});
|
||||
|
||||
class Sidebar {
|
||||
/**
|
||||
@@ -14,30 +55,18 @@ class Sidebar {
|
||||
widgets: []
|
||||
}, state);
|
||||
this.widgets = [];
|
||||
this.$sidebar = ctx.$tabContent.find(".note-detail-sidebar");
|
||||
this.$widgetContainer = this.$sidebar.find(".note-detail-widget-container");
|
||||
this.$showSideBarButton = this.ctx.$tabContent.find(".show-sidebar-button");
|
||||
this.$hideSidebarButton = this.$sidebar.find(".hide-sidebar-button");
|
||||
|
||||
this.$hideSidebarButton.on('click', () => {
|
||||
this.$sidebar.hide();
|
||||
this.$showSideBarButton.show();
|
||||
this.ctx.stateChanged();
|
||||
});
|
||||
this.$widgetContainer = $sidebar.find(`.sidebar-widget-container[data-tab-id=${this.ctx.tabId}]`);
|
||||
|
||||
this.$showSideBarButton.on('click', () => {
|
||||
this.$sidebar.show();
|
||||
this.$showSideBarButton.hide();
|
||||
this.ctx.stateChanged();
|
||||
this.noteLoaded();
|
||||
});
|
||||
if (this.$widgetContainer.length === 0) {
|
||||
this.$widgetContainer = $(`<div class="sidebar-widget-container">`).attr('data-tab-id', this.ctx.tabId);
|
||||
|
||||
this.$showSideBarButton.toggle(!state.visible);
|
||||
this.$sidebar.toggle(state.visible);
|
||||
$sidebarContainer.append(this.$widgetContainer);
|
||||
}
|
||||
}
|
||||
|
||||
isVisible() {
|
||||
return this.$sidebar.css("display") !== "none";
|
||||
return $sidebar.css("display") !== "none";
|
||||
}
|
||||
|
||||
getSidebarState() {
|
||||
@@ -91,6 +120,12 @@ class Sidebar {
|
||||
this.renderWidgets(widgets);
|
||||
}
|
||||
|
||||
show() {
|
||||
$sidebarContainer.find('.sidebar-widget-container').each((i, el) => {
|
||||
$(el).toggle($(el).attr('data-tab-id') === this.ctx.tabId);
|
||||
});
|
||||
}
|
||||
|
||||
// it's important that this method is sync so that the whole render-update is atomic
|
||||
// otherwise we could get race issues (doubled widgets etc.)
|
||||
renderWidgets(widgets) {
|
||||
@@ -119,6 +154,12 @@ class Sidebar {
|
||||
this.$widgetContainer.empty().append(...widgetsToAppend);
|
||||
}
|
||||
|
||||
remove() {
|
||||
if (this.$widgetContainer) {
|
||||
this.$widgetContainer.remove();
|
||||
}
|
||||
}
|
||||
|
||||
eventReceived(name, data) {
|
||||
for (const widget of this.widgets) {
|
||||
if (widget.eventReceived) {
|
||||
|
||||
@@ -0,0 +1,51 @@
|
||||
import server from "./server.js";
|
||||
import optionService from "./options.js";
|
||||
|
||||
let instance;
|
||||
|
||||
async function getPaneWidths() {
|
||||
const options = await optionService.waitForOptions();
|
||||
|
||||
return {
|
||||
leftPaneWidth: options.getInt('leftPaneWidth'),
|
||||
rightPaneWidth: options.getInt('rightPaneWidth')
|
||||
};
|
||||
}
|
||||
|
||||
async function setupSplitWithSidebar() {
|
||||
if (instance) {
|
||||
instance.destroy();
|
||||
}
|
||||
|
||||
const {leftPaneWidth, rightPaneWidth} = await getPaneWidths();
|
||||
|
||||
instance = Split(['#left-pane', '#center-pane', '#right-pane'], {
|
||||
sizes: [leftPaneWidth, 100 - leftPaneWidth - rightPaneWidth, rightPaneWidth],
|
||||
gutterSize: 5,
|
||||
onDragEnd: sizes => {
|
||||
server.put('options/leftPaneWidth/' + Math.round(sizes[0]));
|
||||
server.put('options/rightPaneWidth/' + Math.round(sizes[2]));
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
async function setupSplitWithoutSidebar() {
|
||||
if (instance) {
|
||||
instance.destroy();
|
||||
}
|
||||
|
||||
const {leftPaneWidth} = await getPaneWidths();
|
||||
|
||||
instance = Split(['#left-pane', '#center-pane'], {
|
||||
sizes: [leftPaneWidth, 100 - leftPaneWidth],
|
||||
gutterSize: 5,
|
||||
onDragEnd: sizes => {
|
||||
server.put('options/leftPaneWidth/' + Math.round(sizes[0]));
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
export default {
|
||||
setupSplitWithSidebar,
|
||||
setupSplitWithoutSidebar
|
||||
};
|
||||
@@ -11,6 +11,8 @@ import protectedSessionService from "./protected_session.js";
|
||||
import optionsService from "./options.js";
|
||||
import linkService from "./link.js";
|
||||
import Sidebar from "./sidebar.js";
|
||||
import libraryLoader from "./library_loader.js";
|
||||
import noteAutocompleteService from "./note_autocomplete.js";
|
||||
|
||||
const $tabContentsContainer = $("#note-tab-container");
|
||||
|
||||
@@ -148,6 +150,10 @@ class TabContext {
|
||||
|
||||
this.setCurrentNotePathToHash();
|
||||
|
||||
if (this.sidebar) {
|
||||
this.sidebar.noteLoaded(); // load async
|
||||
}
|
||||
|
||||
this.noteChangeDisabled = true;
|
||||
|
||||
try {
|
||||
@@ -181,10 +187,6 @@ class TabContext {
|
||||
this.noteType.update();
|
||||
}
|
||||
|
||||
if (this.sidebar) {
|
||||
this.sidebar.noteLoaded(); // load async
|
||||
}
|
||||
|
||||
bundleService.executeRelationBundles(this.note, 'runOnNoteView', this);
|
||||
}
|
||||
|
||||
@@ -204,6 +206,10 @@ class TabContext {
|
||||
|
||||
this.$tabContent.show();
|
||||
|
||||
if (this.sidebar) {
|
||||
this.sidebar.show();
|
||||
}
|
||||
|
||||
this.setCurrentNotePathToHash();
|
||||
this.setTitleBar();
|
||||
}
|
||||
@@ -411,6 +417,16 @@ class TabContext {
|
||||
|
||||
await this.addPath(notePath, isCurrent);
|
||||
}
|
||||
|
||||
const cloneLink = $("<div>")
|
||||
.addClass("dropdown-item")
|
||||
.append(
|
||||
$('<button class="btn btn-sm">')
|
||||
.text('Clone note to new location...')
|
||||
.on('click', () => import("../dialogs/clone_to.js").then(d => d.showDialog([this.note.noteId])))
|
||||
);
|
||||
|
||||
this.$notePathList.append(cloneLink);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -422,6 +438,10 @@ class TabContext {
|
||||
await this.saveNoteIfChanged();
|
||||
this.$tabContent.remove();
|
||||
}
|
||||
|
||||
if (this.sidebar) {
|
||||
this.sidebar.remove();
|
||||
}
|
||||
}
|
||||
|
||||
cleanup() {
|
||||
|
||||
File diff suppressed because one or more lines are too long
@@ -81,7 +81,7 @@ function SetupModel() {
|
||||
password: password1,
|
||||
theme: theme
|
||||
}).then(() => {
|
||||
window.location.replace("./");
|
||||
window.location.replace("./setup");
|
||||
});
|
||||
}
|
||||
else if (this.setupType() === 'sync-from-server') {
|
||||
|
||||
@@ -6,31 +6,39 @@ body {
|
||||
margin: 0 auto; /* center */
|
||||
height: 100vh;
|
||||
|
||||
display: grid;
|
||||
grid-template-areas: "header header"
|
||||
"left-pane tabs"
|
||||
"left-pane tab-container";
|
||||
grid-template-rows: auto
|
||||
auto
|
||||
1fr;
|
||||
|
||||
justify-content: center;
|
||||
grid-gap: 0;
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
}
|
||||
|
||||
#container.zen-mode {
|
||||
grid-template-areas:
|
||||
"tab-container" !important;
|
||||
grid-template-rows: auto
|
||||
auto
|
||||
!important;
|
||||
grid-template-columns: 1fr !important;
|
||||
.hidden-by-zen-mode {
|
||||
display: none !important;
|
||||
}
|
||||
|
||||
.gutter {
|
||||
background: linear-gradient(to bottom, transparent, var(--accented-background-color), transparent);
|
||||
}
|
||||
|
||||
.gutter:hover {
|
||||
background: linear-gradient(to bottom, transparent, var(--main-border-color), transparent);
|
||||
}
|
||||
|
||||
.gutter.gutter-horizontal {
|
||||
cursor: col-resize;
|
||||
}
|
||||
|
||||
.gutter.gutter-vertical {
|
||||
cursor: row-resize;
|
||||
}
|
||||
|
||||
#center-pane {
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
}
|
||||
|
||||
#note-tab-container {
|
||||
grid-area: tab-container;
|
||||
min-height: 0;
|
||||
padding-left: 10px;
|
||||
width: 100%;
|
||||
}
|
||||
|
||||
#search-box {
|
||||
@@ -49,13 +57,11 @@ body {
|
||||
}
|
||||
|
||||
#left-pane {
|
||||
grid-area: left-pane;
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
}
|
||||
|
||||
#header {
|
||||
grid-area: header;
|
||||
background-color: var(--header-background-color);
|
||||
display: flex;
|
||||
align-items: center;
|
||||
@@ -90,7 +96,7 @@ body {
|
||||
padding: 3px 0 3px 0;
|
||||
border: 1px solid var(--main-border-color);
|
||||
border-radius: 7px;
|
||||
margin: 5px 15px 5px 5px;
|
||||
margin: 3px 5px 5px 5px;
|
||||
}
|
||||
|
||||
.dropdown-menu {
|
||||
@@ -191,7 +197,7 @@ body {
|
||||
.note-title-row {
|
||||
flex-grow: 0;
|
||||
flex-shrink: 0;
|
||||
margin-top: 10px;
|
||||
padding-top: 2px;
|
||||
}
|
||||
|
||||
.note-title {
|
||||
@@ -206,12 +212,13 @@ body {
|
||||
.note-tab-row {
|
||||
box-sizing: border-box;
|
||||
position: relative;
|
||||
height: 33px;
|
||||
height: 34px;
|
||||
min-height: 34px;
|
||||
width: 100%;
|
||||
background: var(--main-background-color);
|
||||
border-radius: 5px 5px 0 0;
|
||||
overflow: hidden;
|
||||
grid-area: tabs;
|
||||
margin-top: 5px;
|
||||
margin-top: 2px;
|
||||
}
|
||||
.note-tab-row * {
|
||||
box-sizing: inherit;
|
||||
@@ -244,7 +251,7 @@ body {
|
||||
text-align: center;
|
||||
font-size: 24px;
|
||||
cursor: pointer;
|
||||
border-bottom: 1px solid var(--button-border-color);
|
||||
border-bottom: 1px solid var(--main-border-color);
|
||||
}
|
||||
|
||||
.note-new-tab:hover {
|
||||
@@ -253,11 +260,24 @@ body {
|
||||
}
|
||||
|
||||
.tab-row-filler {
|
||||
-webkit-app-region: drag;
|
||||
position: absolute;
|
||||
left: 0;
|
||||
background: linear-gradient(to right, var(--button-border-color), transparent);
|
||||
height: 33px;
|
||||
}
|
||||
|
||||
.tab-row-filler .tab-row-border {
|
||||
position: relative;
|
||||
background: linear-gradient(to right, var(--main-border-color), transparent);
|
||||
height: 1px;
|
||||
margin-top: 32px;
|
||||
margin-top: 31px;
|
||||
}
|
||||
|
||||
/* hack for 1 pixel difference in handling between FF and chrome */
|
||||
@-moz-document url-prefix() {
|
||||
.tab-row-filler .tab-row-border {
|
||||
margin-top: 32px;
|
||||
}
|
||||
}
|
||||
|
||||
.note-tab-row .note-tab[active] {
|
||||
@@ -288,12 +308,12 @@ body {
|
||||
overflow: hidden;
|
||||
pointer-events: all;
|
||||
background-color: var(--accented-background-color);
|
||||
border-bottom: 1px solid var(--button-border-color);
|
||||
border-bottom: 1px solid var(--main-border-color);
|
||||
}
|
||||
|
||||
.note-tab-row .note-tab[active] .note-tab-wrapper {
|
||||
background-color: var(--main-background-color);
|
||||
border: 1px solid var(--button-border-color);
|
||||
border: 1px solid var(--main-border-color);
|
||||
border-bottom: 0;
|
||||
font-weight: bold;
|
||||
}
|
||||
@@ -385,30 +405,26 @@ body {
|
||||
transition: transform 120ms ease-in-out;
|
||||
}
|
||||
|
||||
.hide-sidebar-button {
|
||||
color: var(--main-text-color);
|
||||
background: none;
|
||||
border: 1px solid transparent;
|
||||
padding: 2px 8px 2px 8px;
|
||||
border-radius: 2px;
|
||||
#hide-sidebar-button, #show-sidebar-button {
|
||||
position: fixed;
|
||||
bottom: 10px;
|
||||
right: 10px;
|
||||
z-index: 100000;
|
||||
}
|
||||
|
||||
.hide-sidebar-button:hover {
|
||||
border-color: var(--button-border-color);
|
||||
}
|
||||
|
||||
.note-detail-sidebar {
|
||||
#right-pane {
|
||||
overflow: auto;
|
||||
padding-top: 12px;
|
||||
padding-top: 4px;
|
||||
padding-left: 7px;
|
||||
font-size: 90%;
|
||||
height: 100%;
|
||||
}
|
||||
|
||||
.note-detail-sidebar .card {
|
||||
#right-pane .card {
|
||||
border: 0;
|
||||
}
|
||||
|
||||
.note-detail-sidebar .card-header {
|
||||
#right-pane .card-header {
|
||||
background: inherit;
|
||||
padding: 5px 10px 5px 10px;
|
||||
width: 99%; /* to give minimal right margin */
|
||||
@@ -421,7 +437,7 @@ body {
|
||||
justify-content: space-between;
|
||||
}
|
||||
|
||||
.note-detail-sidebar .widget-title {
|
||||
#right-pane .widget-title {
|
||||
border-radius: 0;
|
||||
padding: 0;
|
||||
border: 0;
|
||||
@@ -431,29 +447,29 @@ body {
|
||||
color: var(--muted-text-color) !important;
|
||||
}
|
||||
|
||||
.note-detail-sidebar .widget-header-action {
|
||||
#right-pane .widget-header-action {
|
||||
color: var(--link-color) !important;
|
||||
cursor: pointer;
|
||||
}
|
||||
|
||||
.note-detail-sidebar .widget-help {
|
||||
#right-pane .widget-help {
|
||||
color: var(--muted-text-color);
|
||||
position: relative;
|
||||
top: 2px;
|
||||
}
|
||||
|
||||
.note-detail-sidebar .widget-help.no-link:hover {
|
||||
#right-pane .widget-help.no-link:hover {
|
||||
cursor: default;
|
||||
text-decoration: none;
|
||||
}
|
||||
|
||||
.note-detail-sidebar .card-body {
|
||||
#right-pane .card-body {
|
||||
width: 100%;
|
||||
padding: 8px;
|
||||
border: 0;
|
||||
}
|
||||
|
||||
.note-detail-sidebar .card-body ul {
|
||||
#right-pane .card-body ul {
|
||||
padding-left: 25px;
|
||||
margin-bottom: 5px;
|
||||
}
|
||||
@@ -485,4 +501,8 @@ body {
|
||||
overflow: hidden;
|
||||
text-overflow: ellipsis;
|
||||
white-space: nowrap;
|
||||
}
|
||||
|
||||
#title-bar-buttons {
|
||||
min-width: 100px;
|
||||
}
|
||||
@@ -333,7 +333,7 @@ div.ui-tooltip {
|
||||
color: #888 !important;
|
||||
}
|
||||
|
||||
.dropdown-menu a:hover:not(.disabled), li.dropdown-item:hover:not(.disabled) {
|
||||
.dropdown-menu a:hover:not(.disabled), li.dropdown-item:hover:not(.disabled), div.dropdown-item:hover:not(.disabled) {
|
||||
color: var(--hover-item-text-color) !important;
|
||||
background-color: var(--hover-item-background-color) !important;
|
||||
cursor: pointer;
|
||||
@@ -474,6 +474,17 @@ button.icon-button {
|
||||
width: 15em;
|
||||
}
|
||||
|
||||
#global-menu-wrapper {
|
||||
height: 35px;
|
||||
border-bottom: 1px solid var(--main-border-color);
|
||||
}
|
||||
|
||||
#global-menu button {
|
||||
margin-right: 10px;
|
||||
height: 33px;
|
||||
border-bottom: none;
|
||||
}
|
||||
|
||||
#global-menu .dropdown-menu {
|
||||
width: 20em;
|
||||
}
|
||||
|
||||
@@ -13,17 +13,11 @@ const ALLOWED_OPTIONS = new Set([
|
||||
'syncServerHost',
|
||||
'syncServerTimeout',
|
||||
'syncProxy',
|
||||
'leftPaneMinWidth',
|
||||
'leftPaneWidthPercent',
|
||||
'sidebarMinWidth',
|
||||
'sidebarWidthPercent',
|
||||
'showSidebarInNewTab',
|
||||
'hoistedNoteId',
|
||||
'mainFontSize',
|
||||
'treeFontSize',
|
||||
'detailFontSize',
|
||||
'openTabs',
|
||||
'hideTabRowForOneTab',
|
||||
'noteInfoWidget',
|
||||
'attributesWidget',
|
||||
'linkMapWidget',
|
||||
@@ -36,7 +30,11 @@ const ALLOWED_OPTIONS = new Set([
|
||||
'spellCheckEnabled',
|
||||
'spellCheckLanguageCode',
|
||||
'imageMaxWidthHeight',
|
||||
'imageJpegQuality'
|
||||
'imageJpegQuality',
|
||||
'leftPaneWidth',
|
||||
'rightPaneWidth',
|
||||
'rightPaneVisible',
|
||||
'nativeTitleBarVisible'
|
||||
]);
|
||||
|
||||
async function getOptions() {
|
||||
|
||||
+14
-2
@@ -10,6 +10,8 @@ const contentHashService = require('../../services/content_hash');
|
||||
const log = require('../../services/log');
|
||||
const syncOptions = require('../../services/sync_options');
|
||||
const dateUtils = require('../../services/date_utils');
|
||||
const entityConstructor = require('../../entities/entity_constructor');
|
||||
const utils = require('../../services/utils');
|
||||
|
||||
async function testSync() {
|
||||
try {
|
||||
@@ -47,7 +49,7 @@ async function getStats() {
|
||||
|
||||
async function checkSync() {
|
||||
return {
|
||||
hashes: await contentHashService.getHashes(),
|
||||
entityHashes: await contentHashService.getEntityHashes(),
|
||||
maxSyncId: await sql.getValue('SELECT MAX(id) FROM sync')
|
||||
};
|
||||
}
|
||||
@@ -137,6 +139,15 @@ async function syncFinished() {
|
||||
await sqlInit.dbInitialized();
|
||||
}
|
||||
|
||||
async function queueSector(req) {
|
||||
const entityName = utils.sanitizeSqlIdentifier(req.params.entityName);
|
||||
const sector = utils.sanitizeSqlIdentifier(req.params.sector);
|
||||
|
||||
const entityPrimaryKey = entityConstructor.getEntityFromEntityName(entityName).primaryKeyName;
|
||||
|
||||
await syncTableService.addEntitySyncsForSector(entityName, entityPrimaryKey, sector);
|
||||
}
|
||||
|
||||
module.exports = {
|
||||
testSync,
|
||||
checkSync,
|
||||
@@ -147,5 +158,6 @@ module.exports = {
|
||||
getChanged,
|
||||
update,
|
||||
getStats,
|
||||
syncFinished
|
||||
syncFinished,
|
||||
queueSector
|
||||
};
|
||||
@@ -18,12 +18,6 @@ async function index(req, res) {
|
||||
res.render(view, {
|
||||
csrfToken: csrfToken,
|
||||
theme: options.theme,
|
||||
leftPaneMinWidth: parseInt(options.leftPaneMinWidth),
|
||||
leftPaneWidthPercent: parseInt(options.leftPaneWidthPercent),
|
||||
rightPaneWidthPercent: 100 - parseInt(options.leftPaneWidthPercent),
|
||||
sidebarMinWidth: parseInt(options.sidebarMinWidth),
|
||||
sidebarWidthPercent: parseInt(options.sidebarWidthPercent),
|
||||
contentWidthPercent: 100 - parseInt(options.sidebarWidthPercent),
|
||||
mainFontSize: parseInt(options.mainFontSize),
|
||||
treeFontSize: parseInt(options.treeFontSize),
|
||||
detailFontSize: parseInt(options.detailFontSize),
|
||||
|
||||
@@ -114,7 +114,7 @@ function register(app) {
|
||||
route(GET, '/login', [auth.checkAppInitialized], loginRoute.loginPage);
|
||||
route(POST, '/login', [], loginRoute.login);
|
||||
route(POST, '/logout', [csrfMiddleware, auth.checkAuth], loginRoute.logout);
|
||||
route(GET, '/setup', [auth.checkAppNotInitialized], setupRoute.setupPage);
|
||||
route(GET, '/setup', [], setupRoute.setupPage);
|
||||
|
||||
apiRoute(GET, '/api/tree', treeApiRoute.getTree);
|
||||
apiRoute(POST, '/api/tree/load', treeApiRoute.load);
|
||||
@@ -199,6 +199,7 @@ function register(app) {
|
||||
route(GET, '/api/sync/changed', [auth.checkApiAuth], syncApiRoute.getChanged, apiResultHandler);
|
||||
route(PUT, '/api/sync/update', [auth.checkApiAuth], syncApiRoute.update, apiResultHandler);
|
||||
route(POST, '/api/sync/finished', [auth.checkApiAuth], syncApiRoute.syncFinished, apiResultHandler);
|
||||
route(POST, '/api/sync/queue-sector/:entityName/:sector', [auth.checkApiAuth], syncApiRoute.queueSector, apiResultHandler);
|
||||
route(GET, '/api/sync/stats', [], syncApiRoute.getStats, apiResultHandler);
|
||||
|
||||
apiRoute(POST, '/api/recent-notes', recentNotesRoute.addRecentNote);
|
||||
|
||||
+9
-1
@@ -2,10 +2,18 @@
|
||||
|
||||
const sqlInit = require('../services/sql_init');
|
||||
const setupService = require('../services/setup');
|
||||
const utils = require('../services/utils');
|
||||
const windowService = require('../services/window');
|
||||
|
||||
async function setupPage(req, res) {
|
||||
if (await sqlInit.isDbInitialized()) {
|
||||
res.redirect('/');
|
||||
if (utils.isElectron()) {
|
||||
await windowService.createMainWindow();
|
||||
windowService.closeSetupWindow();
|
||||
}
|
||||
else {
|
||||
res.redirect('/');
|
||||
}
|
||||
}
|
||||
|
||||
// we got here because DB is not completely initialized so if schema exists
|
||||
|
||||
@@ -5,7 +5,7 @@ const packageJson = require('../../package');
|
||||
const {TRILIUM_DATA_DIR} = require('./data_dir');
|
||||
|
||||
const APP_DB_VERSION = 155;
|
||||
const SYNC_VERSION = 12;
|
||||
const SYNC_VERSION = 13;
|
||||
const CLIPPER_PROTOCOL_VERSION = "1.0";
|
||||
|
||||
module.exports = {
|
||||
|
||||
@@ -1 +1 @@
|
||||
module.exports = { buildDate:"2019-12-24T10:51:51+01:00", buildRevision: "0a723834953f35e9be1d6f0480981cb3fc497801" };
|
||||
module.exports = { buildDate:"2019-12-27T21:21:57+01:00", buildRevision: "3d95d69f80805311816acd5adf677350c3ff22b8" };
|
||||
|
||||
@@ -3,7 +3,6 @@
|
||||
const sql = require('./sql');
|
||||
const utils = require('./utils');
|
||||
const log = require('./log');
|
||||
const ws = require('./ws.js');
|
||||
const ApiToken = require('../entities/api_token');
|
||||
const Branch = require('../entities/branch');
|
||||
const Note = require('../entities/note');
|
||||
@@ -12,65 +11,73 @@ const NoteRevision = require('../entities/note_revision');
|
||||
const RecentNote = require('../entities/recent_note');
|
||||
const Option = require('../entities/option');
|
||||
|
||||
async function getHash(tableName, primaryKeyName, whereBranch) {
|
||||
// subselect is necessary to have correct ordering in GROUP_CONCAT
|
||||
const query = `SELECT GROUP_CONCAT(hash) FROM (SELECT hash FROM ${tableName} `
|
||||
+ (whereBranch ? `WHERE ${whereBranch} ` : '') + `ORDER BY ${primaryKeyName})`;
|
||||
async function getSectorHashes(tableName, primaryKeyName, whereBranch) {
|
||||
const hashes = await sql.getRows(`SELECT ${primaryKeyName} AS id, hash FROM ${tableName} `
|
||||
+ (whereBranch ? `WHERE ${whereBranch} ` : '')
|
||||
+ ` ORDER BY ${primaryKeyName}`);
|
||||
|
||||
let contentToHash = await sql.getValue(query);
|
||||
const map = {};
|
||||
|
||||
if (!contentToHash) { // might be null in case of no rows
|
||||
contentToHash = "";
|
||||
for (const {id, hash} of hashes) {
|
||||
map[id[0]] = (map[id[0]] || "") + hash;
|
||||
}
|
||||
|
||||
return utils.hash(contentToHash);
|
||||
for (const key in map) {
|
||||
map[key] = utils.hash(map[key]);
|
||||
}
|
||||
|
||||
return map;
|
||||
}
|
||||
|
||||
async function getHashes() {
|
||||
async function getEntityHashes() {
|
||||
const startTime = new Date();
|
||||
|
||||
const hashes = {
|
||||
notes: await getHash(Note.entityName, Note.primaryKeyName),
|
||||
note_contents: await getHash("note_contents", "noteId"),
|
||||
branches: await getHash(Branch.entityName, Branch.primaryKeyName),
|
||||
note_revisions: await getHash(NoteRevision.entityName, NoteRevision.primaryKeyName),
|
||||
note_revision_contents: await getHash("note_revision_contents", "noteRevisionId"),
|
||||
recent_notes: await getHash(RecentNote.entityName, RecentNote.primaryKeyName),
|
||||
options: await getHash(Option.entityName, Option.primaryKeyName, "isSynced = 1"),
|
||||
attributes: await getHash(Attribute.entityName, Attribute.primaryKeyName),
|
||||
api_tokens: await getHash(ApiToken.entityName, ApiToken.primaryKeyName),
|
||||
notes: await getSectorHashes(Note.entityName, Note.primaryKeyName),
|
||||
note_contents: await getSectorHashes("note_contents", "noteId"),
|
||||
branches: await getSectorHashes(Branch.entityName, Branch.primaryKeyName),
|
||||
note_revisions: await getSectorHashes(NoteRevision.entityName, NoteRevision.primaryKeyName),
|
||||
note_revision_contents: await getSectorHashes("note_revision_contents", "noteRevisionId"),
|
||||
recent_notes: await getSectorHashes(RecentNote.entityName, RecentNote.primaryKeyName),
|
||||
options: await getSectorHashes(Option.entityName, Option.primaryKeyName, "isSynced = 1"),
|
||||
attributes: await getSectorHashes(Attribute.entityName, Attribute.primaryKeyName),
|
||||
api_tokens: await getSectorHashes(ApiToken.entityName, ApiToken.primaryKeyName),
|
||||
};
|
||||
|
||||
const elapseTimeMs = Date.now() - startTime.getTime();
|
||||
const elapsedTimeMs = Date.now() - startTime.getTime();
|
||||
|
||||
log.info(`Content hash computation took ${elapseTimeMs}ms`);
|
||||
log.info(`Content hash computation took ${elapsedTimeMs}ms`);
|
||||
|
||||
return hashes;
|
||||
}
|
||||
|
||||
async function checkContentHashes(otherHashes) {
|
||||
const hashes = await getHashes();
|
||||
let allChecksPassed = true;
|
||||
const entityHashes = await getEntityHashes();
|
||||
const failedChecks = [];
|
||||
|
||||
for (const key in hashes) {
|
||||
if (hashes[key] !== otherHashes[key]) {
|
||||
allChecksPassed = false;
|
||||
for (const entityName in entityHashes) {
|
||||
const thisSectorHashes = entityHashes[entityName];
|
||||
const otherSectorHashes = otherHashes[entityName];
|
||||
|
||||
log.info(`Content hash check for ${key} FAILED. Local is ${hashes[key]}, remote is ${otherHashes[key]}`);
|
||||
const sectors = new Set(Object.keys(thisSectorHashes).concat(Object.keys(otherSectorHashes)));
|
||||
|
||||
if (key !== 'recent_notes') {
|
||||
// let's not get alarmed about recent notes which get updated often and can cause failures in race conditions
|
||||
ws.sendMessageToAllClients({type: 'sync-hash-check-failed'});
|
||||
for (const sector of sectors) {
|
||||
if (thisSectorHashes[sector] !== otherSectorHashes[sector]) {
|
||||
log.info(`Content hash check for ${entityName} sector ${sector} FAILED. Local is ${thisSectorHashes[sector]}, remote is ${otherSectorHashes[sector]}`);
|
||||
|
||||
failedChecks.push({ entityName, sector });
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (allChecksPassed) {
|
||||
if (failedChecks.length === 0) {
|
||||
log.info("Content hash checks PASSED");
|
||||
}
|
||||
|
||||
return failedChecks;
|
||||
}
|
||||
|
||||
module.exports = {
|
||||
getHashes,
|
||||
getEntityHashes,
|
||||
checkContentHashes
|
||||
};
|
||||
+48
-10
@@ -2,6 +2,7 @@
|
||||
|
||||
const html = require('html');
|
||||
const repository = require('../repository');
|
||||
const dateUtils = require('../date_utils');
|
||||
const tar = require('tar-stream');
|
||||
const path = require('path');
|
||||
const mimeTypes = require('mime-types');
|
||||
@@ -10,6 +11,8 @@ const packageInfo = require('../../../package.json');
|
||||
const utils = require('../utils');
|
||||
const protectedSessionService = require('../protected_session');
|
||||
const sanitize = require("sanitize-filename");
|
||||
const fs = require("fs");
|
||||
const RESOURCE_DIR = require('../../services/resource_dir').RESOURCE_DIR;
|
||||
|
||||
/**
|
||||
* @param {TaskContext} taskContext
|
||||
@@ -187,13 +190,13 @@ async function exportToTar(taskContext, branch, format, res) {
|
||||
for (let i = 0; i < targetPath.length - 1; i++) {
|
||||
const meta = noteIdToMeta[targetPath[i]];
|
||||
|
||||
url += meta.dirFileName + '/';
|
||||
url += encodeURIComponent(meta.dirFileName) + '/';
|
||||
}
|
||||
|
||||
const meta = noteIdToMeta[targetPath[targetPath.length - 1]];
|
||||
|
||||
// link can target note which is only "folder-note" and as such will not have a file in an export
|
||||
url += meta.dataFileName || meta.dirFileName;
|
||||
url += encodeURIComponent(meta.dataFileName || meta.dirFileName);
|
||||
|
||||
return url;
|
||||
}
|
||||
@@ -202,13 +205,13 @@ async function exportToTar(taskContext, branch, format, res) {
|
||||
content = content.replace(/src="[^"]*api\/images\/([a-zA-Z0-9]+)\/[^"]*"/g, (match, targetNoteId) => {
|
||||
const url = getTargetUrl(targetNoteId, noteMeta);
|
||||
|
||||
return url ? `src="${encodeURIComponent(url)}"` : match;
|
||||
return url ? `src="${url}"` : match;
|
||||
});
|
||||
|
||||
content = content.replace(/href="[^"]*#root[a-zA-Z0-9\/]*\/([a-zA-Z0-9]+)\/?"/g, (match, targetNoteId) => {
|
||||
const url = getTargetUrl(targetNoteId, noteMeta);
|
||||
|
||||
return url ? `href="${encodeURIComponent(url)}"` : match;
|
||||
return url ? `href="${url}"` : match;
|
||||
});
|
||||
|
||||
return content;
|
||||
@@ -223,8 +226,13 @@ async function exportToTar(taskContext, branch, format, res) {
|
||||
|
||||
if (noteMeta.format === 'html') {
|
||||
if (!content.substr(0, 100).toLowerCase().includes("<html")) {
|
||||
const cssUrl = "../".repeat(noteMeta.notePath.length - 1) + 'style.css';
|
||||
|
||||
content = `<html>
|
||||
<head><meta charset="utf-8"></head>
|
||||
<head>
|
||||
<meta charset="utf-8">
|
||||
<link rel="stylesheet" href="${cssUrl}">
|
||||
</head>
|
||||
<body>
|
||||
<h1>${utils.escapeHtml(title)}</h1>
|
||||
${content}
|
||||
@@ -255,7 +263,7 @@ ${content}
|
||||
if (noteMeta.isClone) {
|
||||
const targetUrl = getTargetUrl(noteMeta.noteId, noteMeta);
|
||||
|
||||
let content = `<p>This is a clone of a note. Go to its <a href="${encodeURIComponent(targetUrl)}">primary location</a>.</p>`;
|
||||
let content = `<p>This is a clone of a note. Go to its <a href="${targetUrl}">primary location</a>.</p>`;
|
||||
|
||||
content = prepareContent(noteMeta.title, content, noteMeta);
|
||||
|
||||
@@ -270,7 +278,11 @@ ${content}
|
||||
if (noteMeta.dataFileName) {
|
||||
const content = prepareContent(noteMeta.title, await note.getContent(), noteMeta);
|
||||
|
||||
pack.entry({name: filePathPrefix + noteMeta.dataFileName, size: content.length}, content);
|
||||
pack.entry({
|
||||
name: filePathPrefix + noteMeta.dataFileName,
|
||||
size: content.length,
|
||||
mtime: dateUtils.parseDateTime(note.utcDateModified)
|
||||
}, content);
|
||||
}
|
||||
|
||||
taskContext.increaseProgressCount();
|
||||
@@ -278,7 +290,11 @@ ${content}
|
||||
if (noteMeta.children && noteMeta.children.length > 0) {
|
||||
const directoryPath = filePathPrefix + noteMeta.dirFileName;
|
||||
|
||||
pack.entry({name: directoryPath, type: 'directory'});
|
||||
pack.entry({
|
||||
name: directoryPath,
|
||||
type: 'directory',
|
||||
mtime: dateUtils.parseDateTime(note.utcDateModified)
|
||||
});
|
||||
|
||||
for (const childMeta of noteMeta.children) {
|
||||
await saveNote(childMeta, directoryPath + '/');
|
||||
@@ -314,7 +330,15 @@ ${content}
|
||||
return html + '</li>';
|
||||
}
|
||||
|
||||
const fullHtml = '<html><head><meta charset="utf-8"></head><body><ul>' + saveNavigationInner(rootMeta) + '</ul></body></html>'
|
||||
const fullHtml = `<html>
|
||||
<head>
|
||||
<meta charset="utf-8">
|
||||
<link rel="stylesheet" href="style.css">
|
||||
</head>
|
||||
<body>
|
||||
<ul>${saveNavigationInner(rootMeta)}</ul>
|
||||
</body>
|
||||
</html>`;
|
||||
const prettyHtml = html.prettyPrint(fullHtml, {indent_size: 2});
|
||||
|
||||
pack.entry({name: navigationMeta.dataFileName, size: prettyHtml.length}, prettyHtml);
|
||||
@@ -351,6 +375,12 @@ ${content}
|
||||
pack.entry({name: indexMeta.dataFileName, size: fullHtml.length}, fullHtml);
|
||||
}
|
||||
|
||||
function saveCss(rootMeta, cssMeta) {
|
||||
const cssContent = fs.readFileSync(RESOURCE_DIR + '/libraries/ckeditor/ckeditor-content.css');
|
||||
|
||||
pack.entry({name: cssMeta.dataFileName, size: cssContent.length}, cssContent);
|
||||
}
|
||||
|
||||
const existingFileNames = format === 'html' ? ['navigation', 'index'] : [];
|
||||
const rootMeta = await getNoteMeta(branch, { notePath: [] }, existingFileNames);
|
||||
|
||||
@@ -360,7 +390,7 @@ ${content}
|
||||
files: [ rootMeta ]
|
||||
};
|
||||
|
||||
let navigationMeta, indexMeta;
|
||||
let navigationMeta, indexMeta, cssMeta;
|
||||
|
||||
if (format === 'html') {
|
||||
navigationMeta = {
|
||||
@@ -376,6 +406,13 @@ ${content}
|
||||
};
|
||||
|
||||
metaFile.files.push(indexMeta);
|
||||
|
||||
cssMeta = {
|
||||
noImport: true,
|
||||
dataFileName: "style.css"
|
||||
};
|
||||
|
||||
metaFile.files.push(cssMeta);
|
||||
}
|
||||
|
||||
for (const noteMeta of Object.values(noteIdToMeta)) {
|
||||
@@ -397,6 +434,7 @@ ${content}
|
||||
if (format === 'html') {
|
||||
saveNavigation(rootMeta, navigationMeta);
|
||||
saveIndex(rootMeta, indexMeta);
|
||||
saveCss(rootMeta, cssMeta);
|
||||
}
|
||||
|
||||
pack.finalize();
|
||||
|
||||
@@ -274,6 +274,9 @@ async function importTar(taskContext, fileBuffer, importRootNote) {
|
||||
return /^(?:[a-z]+:)?\/\//i.test(url);
|
||||
}
|
||||
|
||||
content = content.replace(/<html.*<body[^>]*>/gis, "");
|
||||
content = content.replace(/<\/body>.*<\/html>/gis, "");
|
||||
|
||||
content = content.replace(/src="([^"]*)"/g, (match, url) => {
|
||||
url = decodeURIComponent(url);
|
||||
|
||||
@@ -298,9 +301,6 @@ async function importTar(taskContext, fileBuffer, importRootNote) {
|
||||
return `href="#root/${targetNoteId}"`;
|
||||
});
|
||||
|
||||
content = content.replace(/<html.*<body[^>]*>/gis, "");
|
||||
content = content.replace(/<\/body>.*<\/html>/gis, "");
|
||||
|
||||
content = content.replace(/<h1>([^<]*)<\/h1>/gi, (match, text) => {
|
||||
if (noteTitle.trim() === text.trim()) {
|
||||
return ""; // remove whole H1 tag
|
||||
|
||||
@@ -33,7 +33,6 @@ async function initNotSyncedOptions(initialized, startNotePath = 'root', opts =
|
||||
notePath: startNotePath,
|
||||
active: true,
|
||||
sidebar: {
|
||||
visible: true,
|
||||
widgets: []
|
||||
}
|
||||
}
|
||||
@@ -61,14 +60,9 @@ const defaultOptions = [
|
||||
{ name: 'protectedSessionTimeout', value: '600', isSynced: true },
|
||||
{ name: 'hoistedNoteId', value: 'root', isSynced: false },
|
||||
{ name: 'zoomFactor', value: '1.0', isSynced: false },
|
||||
{ name: 'leftPaneMinWidth', value: '350', isSynced: false },
|
||||
{ name: 'leftPaneWidthPercent', value: '20', isSynced: false },
|
||||
{ name: 'mainFontSize', value: '100', isSynced: false },
|
||||
{ name: 'treeFontSize', value: '100', isSynced: false },
|
||||
{ name: 'detailFontSize', value: '110', isSynced: false },
|
||||
{ name: 'sidebarMinWidth', value: '350', isSynced: false },
|
||||
{ name: 'sidebarWidthPercent', value: '25', isSynced: false },
|
||||
{ name: 'showSidebarInNewTab', value: 'true', isSynced: false },
|
||||
{ name: 'calendarWidget', value: '{"enabled":true,"expanded":true,"position":20}', isSynced: false },
|
||||
{ name: 'editedNotesWidget', value: '{"enabled":true,"expanded":true,"position":50}', isSynced: false },
|
||||
{ name: 'noteInfoWidget', value: '{"enabled":true,"expanded":true,"position":100}', isSynced: false },
|
||||
@@ -79,11 +73,14 @@ const defaultOptions = [
|
||||
{ name: 'similarNotesWidget', value: '{"enabled":true,"expanded":true,"position":600}', isSynced: false },
|
||||
{ name: 'spellCheckEnabled', value: 'true', isSynced: false },
|
||||
{ name: 'spellCheckLanguageCode', value: 'en-US', isSynced: false },
|
||||
{ name: 'hideTabRowForOneTab', value: 'false', isSynced: false },
|
||||
{ name: 'imageMaxWidthHeight', value: '1200', isSynced: true },
|
||||
{ name: 'imageJpegQuality', value: '75', isSynced: true },
|
||||
{ name: 'autoFixConsistencyIssues', value: 'true', isSynced: false },
|
||||
{ name: 'codeNotesMimeTypes', value: '["text/x-csrc","text/x-c++src","text/x-csharp","text/css","text/x-go","text/x-groovy","text/x-haskell","text/html","message/http","text/x-java","application/javascript;env=frontend","application/javascript;env=backend","application/json","text/x-kotlin","text/x-markdown","text/x-perl","text/x-php","text/x-python","text/x-ruby",null,"text/x-sql","text/x-swift","text/xml","text/x-yaml"]', isSynced: true }
|
||||
{ name: 'codeNotesMimeTypes', value: '["text/x-csrc","text/x-c++src","text/x-csharp","text/css","text/x-go","text/x-groovy","text/x-haskell","text/html","message/http","text/x-java","application/javascript;env=frontend","application/javascript;env=backend","application/json","text/x-kotlin","text/x-markdown","text/x-perl","text/x-php","text/x-python","text/x-ruby",null,"text/x-sql","text/x-swift","text/xml","text/x-yaml"]', isSynced: true },
|
||||
{ name: 'leftPaneWidth', value: '25', isSynced: false },
|
||||
{ name: 'rightPaneWidth', value: '25', isSynced: false },
|
||||
{ name: 'rightPaneVisible', value: 'true', isSynced: false },
|
||||
{ name: 'nativeTitleBarVisible', value: 'false', isSynced: false }
|
||||
];
|
||||
|
||||
async function initStartupOptions() {
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
const dayjs = require("dayjs");
|
||||
|
||||
const filterRegex = /(\b(AND|OR)\s+)?@(!?)([\p{L}\p{Number}_]+|"[^"]+")\s*((=|!=|<|<=|>|>=|!?\*=|!?=\*|!?\*=\*)\s*([\p{L}\p{Number}_/-]+|"[^"]+"))?/igu;
|
||||
const filterRegex = /(\b(AND|OR)\s+)?@(!?)([\p{L}\p{Number}_]+|"[^"]+")\s*((=|!=|<|<=|>|>=|!?\*=|!?=\*|!?\*=\*)\s*(\S+|"[^"]+"))?/igu;
|
||||
const smartValueRegex = /^(NOW|TODAY|WEEK|MONTH|YEAR) *([+\-] *\d+)?$/i;
|
||||
|
||||
function calculateSmartValue(v) {
|
||||
|
||||
+28
-9
@@ -15,6 +15,8 @@ const syncMutexService = require('./sync_mutex');
|
||||
const cls = require('./cls');
|
||||
const request = require('./request');
|
||||
const ws = require('./ws');
|
||||
const syncTableService = require('./sync_table');
|
||||
const entityConstructor = require('../entities/entity_constructor');
|
||||
|
||||
let proxyToggle = true;
|
||||
|
||||
@@ -30,17 +32,22 @@ async function sync() {
|
||||
return { success: false, message: 'Sync not configured' };
|
||||
}
|
||||
|
||||
const syncContext = await login();
|
||||
let continueSync = false;
|
||||
|
||||
await pushSync(syncContext);
|
||||
do {
|
||||
const syncContext = await login();
|
||||
|
||||
await pullSync(syncContext);
|
||||
await pushSync(syncContext);
|
||||
|
||||
await pushSync(syncContext);
|
||||
await pullSync(syncContext);
|
||||
|
||||
await syncFinished(syncContext);
|
||||
await pushSync(syncContext);
|
||||
|
||||
await checkContentHash(syncContext);
|
||||
await syncFinished(syncContext);
|
||||
|
||||
continueSync = await checkContentHash(syncContext);
|
||||
}
|
||||
while (continueSync);
|
||||
|
||||
return {
|
||||
success: true
|
||||
@@ -225,7 +232,7 @@ async function checkContentHash(syncContext) {
|
||||
if (await getLastSyncedPull() < resp.maxSyncId) {
|
||||
log.info("There are some outstanding pulls, skipping content check.");
|
||||
|
||||
return;
|
||||
return true;
|
||||
}
|
||||
|
||||
const notPushedSyncs = await sql.getValue("SELECT EXISTS(SELECT 1 FROM sync WHERE id > ?)", [await getLastSyncedPush()]);
|
||||
@@ -233,10 +240,22 @@ async function checkContentHash(syncContext) {
|
||||
if (notPushedSyncs) {
|
||||
log.info(`There's ${notPushedSyncs} outstanding pushes, skipping content check.`);
|
||||
|
||||
return;
|
||||
return true;
|
||||
}
|
||||
|
||||
await contentHashService.checkContentHashes(resp.hashes);
|
||||
const failedChecks = await contentHashService.checkContentHashes(resp.entityHashes);
|
||||
|
||||
for (const {entityName, sector} of failedChecks) {
|
||||
const entityPrimaryKey = entityConstructor.getEntityFromEntityName(entityName).primaryKeyName;
|
||||
|
||||
await syncTableService.addEntitySyncsForSector(entityName, entityPrimaryKey, sector);
|
||||
|
||||
await syncRequest(syncContext, 'POST', `/api/sync/queue-sector/${entityName}/${sector}`);
|
||||
|
||||
log.info(`Added sector ${sector} of ${entityName} to sync queue.`);
|
||||
}
|
||||
|
||||
return failedChecks.length > 0;
|
||||
}
|
||||
|
||||
async function syncRequest(syncContext, method, requestPath, body) {
|
||||
|
||||
@@ -6,7 +6,7 @@ const cls = require('./cls');
|
||||
|
||||
let syncs = [];
|
||||
|
||||
async function addEntitySync(entityName, entityId, sourceId) {
|
||||
async function insertEntitySync(entityName, entityId, sourceId) {
|
||||
const sync = {
|
||||
entityName: entityName,
|
||||
entityId: entityId,
|
||||
@@ -16,11 +16,25 @@ async function addEntitySync(entityName, entityId, sourceId) {
|
||||
|
||||
sync.id = await sql.replace("sync", sync);
|
||||
|
||||
return sync;
|
||||
}
|
||||
|
||||
async function addEntitySync(entityName, entityId, sourceId) {
|
||||
const sync = await insertEntitySync(entityName, entityId, sourceId);
|
||||
|
||||
syncs.push(sync);
|
||||
|
||||
setTimeout(() => require('./ws').sendPingToAllClients(), 50);
|
||||
}
|
||||
|
||||
async function addEntitySyncsForSector(entityName, entityPrimaryKey, sector) {
|
||||
const entityIds = await sql.getColumn(`SELECT ${entityPrimaryKey} FROM ${entityName} WHERE SUBSTR(${entityPrimaryKey}, 1, 1) = ?`, [sector]);
|
||||
|
||||
for (const entityId of entityIds) {
|
||||
await insertEntitySync(entityName, entityId, 'content-check');
|
||||
}
|
||||
}
|
||||
|
||||
function getMaxSyncId() {
|
||||
return syncs.length === 0 ? 0 : syncs[syncs.length - 1].id;
|
||||
}
|
||||
@@ -29,19 +43,19 @@ function getEntitySyncsNewerThan(syncId) {
|
||||
return syncs.filter(s => s.id > syncId);
|
||||
}
|
||||
|
||||
async function cleanupSyncRowsForMissingEntities(entityName, entityKey) {
|
||||
async function cleanupSyncRowsForMissingEntities(entityName, entityPrimaryKey) {
|
||||
await sql.execute(`
|
||||
DELETE
|
||||
FROM sync
|
||||
WHERE sync.entityName = '${entityName}'
|
||||
AND sync.entityId NOT IN (SELECT ${entityKey} FROM ${entityName})`);
|
||||
AND sync.entityId NOT IN (SELECT ${entityPrimaryKey} FROM ${entityName})`);
|
||||
}
|
||||
|
||||
async function fillSyncRows(entityName, entityKey, condition = '') {
|
||||
async function fillSyncRows(entityName, entityPrimaryKey, condition = '') {
|
||||
try {
|
||||
await cleanupSyncRowsForMissingEntities(entityName, entityKey);
|
||||
await cleanupSyncRowsForMissingEntities(entityName, entityPrimaryKey);
|
||||
|
||||
const entityIds = await sql.getColumn(`SELECT ${entityKey} FROM ${entityName}`
|
||||
const entityIds = await sql.getColumn(`SELECT ${entityPrimaryKey} FROM ${entityName}`
|
||||
+ (condition ? ` WHERE ${condition}` : ''));
|
||||
|
||||
let createdCount = 0;
|
||||
@@ -69,7 +83,7 @@ async function fillSyncRows(entityName, entityKey, condition = '') {
|
||||
catch (e) {
|
||||
// this is to fix migration from 0.30 to 0.32, can be removed later
|
||||
// see https://github.com/zadam/trilium/issues/557
|
||||
log.error(`Filling sync rows failed for ${entityName} ${entityKey} with error "${e.message}", continuing`);
|
||||
log.error(`Filling sync rows failed for ${entityName} ${entityPrimaryKey} with error "${e.message}", continuing`);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -101,5 +115,6 @@ module.exports = {
|
||||
addEntitySync,
|
||||
fillAllSyncRows,
|
||||
getEntitySyncsNewerThan,
|
||||
getMaxSyncId
|
||||
getMaxSyncId,
|
||||
addEntitySyncsForSector
|
||||
};
|
||||
+74
-54
@@ -50,135 +50,155 @@ async function updateEntity(sync, entity, sourceId) {
|
||||
}
|
||||
}
|
||||
|
||||
async function updateNote(entity, sourceId) {
|
||||
const origNote = await sql.getRow("SELECT * FROM notes WHERE noteId = ?", [entity.noteId]);
|
||||
function shouldWeUpdateEntity(localEntity, remoteEntity) {
|
||||
if (!localEntity) {
|
||||
return true;
|
||||
}
|
||||
|
||||
if (!origNote || origNote.utcDateModified < entity.utcDateModified) {
|
||||
const localDate = localEntity.utcDateModified || localEntity.utcDateCreated;
|
||||
const remoteDate = remoteEntity.utcDateModified || remoteEntity.utcDateCreated;
|
||||
|
||||
if (localDate < remoteDate) {
|
||||
return true;
|
||||
}
|
||||
|
||||
// this can happen in case of sync error when hashes are different but dates are the same - we should still update
|
||||
if (localEntity.hash !== remoteEntity.hash && localDate === remoteDate) {
|
||||
return true;
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
async function updateNote(remoteEntity, sourceId) {
|
||||
const localEntity = await sql.getRow("SELECT * FROM notes WHERE noteId = ?", [remoteEntity.noteId]);
|
||||
|
||||
if (shouldWeUpdateEntity(localEntity, remoteEntity)) {
|
||||
await sql.transactional(async () => {
|
||||
await sql.replace("notes", entity);
|
||||
await sql.replace("notes", remoteEntity);
|
||||
|
||||
await syncTableService.addNoteSync(entity.noteId, sourceId);
|
||||
await syncTableService.addNoteSync(remoteEntity.noteId, sourceId);
|
||||
});
|
||||
|
||||
log.info("Update/sync note " + entity.noteId);
|
||||
log.info("Update/sync note " + remoteEntity.noteId);
|
||||
}
|
||||
}
|
||||
|
||||
async function updateNoteContent(entity, sourceId) {
|
||||
const origNoteContent = await sql.getRow("SELECT * FROM note_contents WHERE noteId = ?", [entity.noteId]);
|
||||
async function updateNoteContent(remoteEntity, sourceId) {
|
||||
const localEntity = await sql.getRow("SELECT * FROM note_contents WHERE noteId = ?", [remoteEntity.noteId]);
|
||||
|
||||
if (!origNoteContent || origNoteContent.utcDateModified < entity.utcDateModified) {
|
||||
entity.content = entity.content === null ? null : Buffer.from(entity.content, 'base64');
|
||||
if (shouldWeUpdateEntity(localEntity, remoteEntity)) {
|
||||
remoteEntity.content = remoteEntity.content === null ? null : Buffer.from(remoteEntity.content, 'base64');
|
||||
|
||||
await sql.transactional(async () => {
|
||||
await sql.replace("note_contents", entity);
|
||||
await sql.replace("note_contents", remoteEntity);
|
||||
|
||||
await syncTableService.addNoteContentSync(entity.noteId, sourceId);
|
||||
await syncTableService.addNoteContentSync(remoteEntity.noteId, sourceId);
|
||||
});
|
||||
|
||||
log.info("Update/sync note content for noteId=" + entity.noteId);
|
||||
log.info("Update/sync note content for noteId=" + remoteEntity.noteId);
|
||||
}
|
||||
}
|
||||
|
||||
async function updateBranch(entity, sourceId) {
|
||||
const orig = await sql.getRowOrNull("SELECT * FROM branches WHERE branchId = ?", [entity.branchId]);
|
||||
async function updateBranch(remoteEntity, sourceId) {
|
||||
const localEntity = await sql.getRowOrNull("SELECT * FROM branches WHERE branchId = ?", [remoteEntity.branchId]);
|
||||
|
||||
await sql.transactional(async () => {
|
||||
if (orig === null || orig.utcDateModified < entity.utcDateModified) {
|
||||
if (shouldWeUpdateEntity(localEntity, remoteEntity)) {
|
||||
// isExpanded is not synced unless it's a new branch instance
|
||||
// otherwise in case of full new sync we'll get all branches (even root) collapsed.
|
||||
if (orig) {
|
||||
delete entity.isExpanded;
|
||||
if (localEntity) {
|
||||
delete remoteEntity.isExpanded;
|
||||
}
|
||||
|
||||
await sql.replace('branches', entity);
|
||||
await sql.replace('branches', remoteEntity);
|
||||
|
||||
await syncTableService.addBranchSync(entity.branchId, sourceId);
|
||||
await syncTableService.addBranchSync(remoteEntity.branchId, sourceId);
|
||||
|
||||
log.info("Update/sync branch " + entity.branchId);
|
||||
log.info("Update/sync branch " + remoteEntity.branchId);
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
async function updateNoteRevision(entity, sourceId) {
|
||||
const orig = await sql.getRowOrNull("SELECT * FROM note_revisions WHERE noteRevisionId = ?", [entity.noteRevisionId]);
|
||||
async function updateNoteRevision(remoteEntity, sourceId) {
|
||||
const localEntity = await sql.getRowOrNull("SELECT * FROM note_revisions WHERE noteRevisionId = ?", [remoteEntity.noteRevisionId]);
|
||||
|
||||
await sql.transactional(async () => {
|
||||
if (orig === null || orig.utcDateModified < entity.utcDateModified) {
|
||||
await sql.replace('note_revisions', entity);
|
||||
if (shouldWeUpdateEntity(localEntity, remoteEntity)) {
|
||||
await sql.replace('note_revisions', remoteEntity);
|
||||
|
||||
await syncTableService.addNoteRevisionSync(entity.noteRevisionId, sourceId);
|
||||
await syncTableService.addNoteRevisionSync(remoteEntity.noteRevisionId, sourceId);
|
||||
|
||||
log.info("Update/sync note revision " + entity.noteRevisionId);
|
||||
log.info("Update/sync note revision " + remoteEntity.noteRevisionId);
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
async function updateNoteRevisionContent(entity, sourceId) {
|
||||
const orig = await sql.getRowOrNull("SELECT * FROM note_revision_contents WHERE noteRevisionId = ?", [entity.noteRevisionId]);
|
||||
async function updateNoteRevisionContent(remoteEntity, sourceId) {
|
||||
const localEntity = await sql.getRowOrNull("SELECT * FROM note_revision_contents WHERE noteRevisionId = ?", [remoteEntity.noteRevisionId]);
|
||||
|
||||
await sql.transactional(async () => {
|
||||
if (orig === null || orig.utcDateModified < entity.utcDateModified) {
|
||||
entity.content = entity.content === null ? null : Buffer.from(entity.content, 'base64');
|
||||
if (shouldWeUpdateEntity(localEntity, remoteEntity)) {
|
||||
remoteEntity.content = remoteEntity.content === null ? null : Buffer.from(remoteEntity.content, 'base64');
|
||||
|
||||
await sql.replace('note_revision_contents', entity);
|
||||
await sql.replace('note_revision_contents', remoteEntity);
|
||||
|
||||
await syncTableService.addNoteRevisionContentSync(entity.noteRevisionId, sourceId);
|
||||
await syncTableService.addNoteRevisionContentSync(remoteEntity.noteRevisionId, sourceId);
|
||||
|
||||
log.info("Update/sync note revision content " + entity.noteRevisionId);
|
||||
log.info("Update/sync note revision content " + remoteEntity.noteRevisionId);
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
async function updateNoteReordering(entityId, entity, sourceId) {
|
||||
async function updateNoteReordering(entityId, remote, sourceId) {
|
||||
await sql.transactional(async () => {
|
||||
for (const key in entity) {
|
||||
await sql.execute("UPDATE branches SET notePosition = ? WHERE branchId = ?", [entity[key], key]);
|
||||
for (const key in remote) {
|
||||
await sql.execute("UPDATE branches SET notePosition = ? WHERE branchId = ?", [remote[key], key]);
|
||||
}
|
||||
|
||||
await syncTableService.addNoteReorderingSync(entityId, sourceId);
|
||||
});
|
||||
}
|
||||
|
||||
async function updateOptions(entity, sourceId) {
|
||||
const orig = await sql.getRowOrNull("SELECT * FROM options WHERE name = ?", [entity.name]);
|
||||
async function updateOptions(remoteEntity, sourceId) {
|
||||
const localEntity = await sql.getRowOrNull("SELECT * FROM options WHERE name = ?", [remoteEntity.name]);
|
||||
|
||||
if (orig && !orig.isSynced) {
|
||||
if (localEntity && !localEntity.isSynced) {
|
||||
return;
|
||||
}
|
||||
|
||||
await sql.transactional(async () => {
|
||||
if (orig === null || orig.utcDateModified < entity.utcDateModified) {
|
||||
await sql.replace('options', entity);
|
||||
if (shouldWeUpdateEntity(localEntity, remoteEntity)) {
|
||||
await sql.replace('options', remoteEntity);
|
||||
|
||||
await syncTableService.addOptionsSync(entity.name, sourceId);
|
||||
await syncTableService.addOptionsSync(remoteEntity.name, sourceId);
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
async function updateRecentNotes(entity, sourceId) {
|
||||
const orig = await sql.getRowOrNull("SELECT * FROM recent_notes WHERE noteId = ?", [entity.noteId]);
|
||||
async function updateRecentNotes(remoteEntity, sourceId) {
|
||||
const localEntity = await sql.getRowOrNull("SELECT * FROM recent_notes WHERE noteId = ?", [remoteEntity.noteId]);
|
||||
|
||||
if (orig === null || orig.utcDateCreated < entity.utcDateCreated) {
|
||||
if (shouldWeUpdateEntity(localEntity, remoteEntity)) {
|
||||
await sql.transactional(async () => {
|
||||
await sql.replace('recent_notes', entity);
|
||||
await sql.replace('recent_notes', remoteEntity);
|
||||
|
||||
await syncTableService.addRecentNoteSync(entity.noteId, sourceId);
|
||||
await syncTableService.addRecentNoteSync(remoteEntity.noteId, sourceId);
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
async function updateAttribute(entity, sourceId) {
|
||||
const origAttribute = await sql.getRow("SELECT * FROM attributes WHERE attributeId = ?", [entity.attributeId]);
|
||||
async function updateAttribute(remoteEntity, sourceId) {
|
||||
const localEntity = await sql.getRow("SELECT * FROM attributes WHERE attributeId = ?", [remoteEntity.attributeId]);
|
||||
|
||||
if (!origAttribute || origAttribute.utcDateModified <= entity.utcDateModified) {
|
||||
if (shouldWeUpdateEntity(localEntity, remoteEntity)) {
|
||||
await sql.transactional(async () => {
|
||||
await sql.replace("attributes", entity);
|
||||
await sql.replace("attributes", remoteEntity);
|
||||
|
||||
await syncTableService.addAttributeSync(entity.attributeId, sourceId);
|
||||
await syncTableService.addAttributeSync(remoteEntity.attributeId, sourceId);
|
||||
});
|
||||
|
||||
log.info("Update/sync attribute " + entity.attributeId);
|
||||
log.info("Update/sync attribute " + remoteEntity.attributeId);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -53,6 +53,10 @@ function sanitizeSql(str) {
|
||||
return str.replace(/'/g, "''");
|
||||
}
|
||||
|
||||
function sanitizeSqlIdentifier(str) {
|
||||
return str.replace(/[^A-Za-z0-9_]/g, "");
|
||||
}
|
||||
|
||||
function prepareSqlForLike(prefix, str, suffix) {
|
||||
const value = str
|
||||
.replace(/\\/g, "\\\\")
|
||||
@@ -174,6 +178,7 @@ module.exports = {
|
||||
hash,
|
||||
isEmptyOrWhitespace,
|
||||
sanitizeSql,
|
||||
sanitizeSqlIdentifier,
|
||||
prepareSqlForLike,
|
||||
stopWatch,
|
||||
escapeHtml,
|
||||
|
||||
@@ -0,0 +1,131 @@
|
||||
const path = require('path');
|
||||
const url = require("url");
|
||||
const port = require('./port');
|
||||
const optionService = require('./options');
|
||||
const env = require('./env');
|
||||
const log = require('./log');
|
||||
const sqlInit = require('./sql_init');
|
||||
const cls = require('./cls');
|
||||
const keyboardActionsService = require('./keyboard_actions');
|
||||
|
||||
// Prevent window being garbage collected
|
||||
/** @type {Electron.BrowserWindow} */
|
||||
let mainWindow;
|
||||
/** @type {Electron.BrowserWindow} */
|
||||
let setupWindow;
|
||||
|
||||
async function createMainWindow() {
|
||||
const windowStateKeeper = require('electron-window-state'); // should not be statically imported
|
||||
|
||||
const mainWindowState = windowStateKeeper({
|
||||
// default window width & height so it's usable on 1600 * 900 display (including some extra panels etc.)
|
||||
defaultWidth: 1200,
|
||||
defaultHeight: 800
|
||||
});
|
||||
|
||||
const {BrowserWindow} = require('electron'); // should not be statically imported
|
||||
mainWindow = new BrowserWindow({
|
||||
x: mainWindowState.x,
|
||||
y: mainWindowState.y,
|
||||
width: mainWindowState.width,
|
||||
height: mainWindowState.height,
|
||||
title: 'Trilium Notes',
|
||||
webPreferences: {
|
||||
nodeIntegration: true
|
||||
},
|
||||
frame: await optionService.getOptionBool('nativeTitleBarVisible'),
|
||||
icon: getIcon()
|
||||
});
|
||||
|
||||
mainWindowState.manage(mainWindow);
|
||||
|
||||
mainWindow.setMenuBarVisibility(false);
|
||||
mainWindow.loadURL('http://127.0.0.1:' + await port);
|
||||
mainWindow.on('closed', () => mainWindow = null);
|
||||
|
||||
mainWindow.webContents.on('new-window', (e, url) => {
|
||||
if (url !== mainWindow.webContents.getURL()) {
|
||||
e.preventDefault();
|
||||
require('electron').shell.openExternal(url);
|
||||
}
|
||||
});
|
||||
|
||||
// prevent drag & drop to navigate away from trilium
|
||||
mainWindow.webContents.on('will-navigate', (ev, targetUrl) => {
|
||||
const parsedUrl = url.parse(targetUrl);
|
||||
|
||||
// we still need to allow internal redirects from setup and migration pages
|
||||
if (!['localhost', '127.0.0.1'].includes(parsedUrl.hostname) || (parsedUrl.path && parsedUrl.path !== '/')) {
|
||||
ev.preventDefault();
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
function getIcon() {
|
||||
return path.join(__dirname, '../../images/app-icons/png/256x256' + (env.isDev() ? '-dev' : '') + '.png');
|
||||
}
|
||||
|
||||
async function createSetupWindow() {
|
||||
const {BrowserWindow} = require('electron'); // should not be statically imported
|
||||
setupWindow = new BrowserWindow({
|
||||
width: 800,
|
||||
height: 800,
|
||||
title: 'Trilium Notes Setup',
|
||||
icon: getIcon(),
|
||||
webPreferences: {
|
||||
// necessary for e.g. utils.isElectron()
|
||||
nodeIntegration: true
|
||||
}
|
||||
});
|
||||
|
||||
setupWindow.setMenuBarVisibility(false);
|
||||
setupWindow.loadURL('http://127.0.0.1:' + await port);
|
||||
setupWindow.on('closed', () => setupWindow = null);
|
||||
}
|
||||
|
||||
function closeSetupWindow() {
|
||||
if (setupWindow) {
|
||||
setupWindow.close();
|
||||
}
|
||||
}
|
||||
|
||||
async function registerGlobalShortcuts() {
|
||||
const {globalShortcut} = require('electron');
|
||||
|
||||
await sqlInit.dbReady;
|
||||
|
||||
const allActions = await keyboardActionsService.getKeyboardActions();
|
||||
|
||||
for (const action of allActions) {
|
||||
if (!action.effectiveShortcuts) {
|
||||
continue;
|
||||
}
|
||||
|
||||
for (const shortcut of action.effectiveShortcuts) {
|
||||
if (shortcut.startsWith('global:')) {
|
||||
const translatedShortcut = shortcut.substr(7);
|
||||
|
||||
const result = globalShortcut.register(translatedShortcut, cls.wrap(async () => {
|
||||
// window may be hidden / not in focus
|
||||
mainWindow.focus();
|
||||
|
||||
mainWindow.webContents.send('globalShortcut', action.actionName);
|
||||
}));
|
||||
|
||||
if (result) {
|
||||
log.info(`Registered global shortcut ${translatedShortcut} for action ${action.actionName}`);
|
||||
}
|
||||
else {
|
||||
log.info(`Could not register global shortcut ${translatedShortcut}`);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
module.exports = {
|
||||
createMainWindow,
|
||||
createSetupWindow,
|
||||
closeSetupWindow,
|
||||
registerGlobalShortcuts
|
||||
};
|
||||
@@ -0,0 +1,39 @@
|
||||
<div id="center-pane">
|
||||
<div id="note-tab-container">
|
||||
<div class="note-tab-content note-tab-content-template">
|
||||
<div class="note-detail-content">
|
||||
<% include title.ejs %>
|
||||
|
||||
<div class="note-detail-script-area"></div>
|
||||
|
||||
<table class="note-detail-promoted-attributes"></table>
|
||||
|
||||
<div class="note-detail-component-wrapper">
|
||||
<div class="note-detail-text note-detail-component">
|
||||
<div class="note-detail-text-editor" tabindex="10000"></div>
|
||||
</div>
|
||||
|
||||
<div class="note-detail-code note-detail-component">
|
||||
<div class="note-detail-code-editor"></div>
|
||||
</div>
|
||||
|
||||
<% include details/empty.ejs %>
|
||||
|
||||
<% include details/search.ejs %>
|
||||
|
||||
<% include details/render.ejs %>
|
||||
|
||||
<% include details/file.ejs %>
|
||||
|
||||
<% include details/image.ejs %>
|
||||
|
||||
<% include details/relation_map.ejs %>
|
||||
|
||||
<% include details/protected_session_password.ejs %>
|
||||
|
||||
<% include details/book.ejs %>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
+93
-75
@@ -10,48 +10,9 @@
|
||||
|
||||
<div id="toast-container" class="d-flex flex-column justify-content-center align-items-center"></div>
|
||||
|
||||
<div id="container" style="display: none; grid-template-columns: minmax(<%= leftPaneMinWidth %>px, <%= leftPaneWidthPercent %>fr) minmax(0, <%= rightPaneWidthPercent %>fr)">
|
||||
<div id="header" class="hide-in-zen-mode">
|
||||
<div id="history-navigation" style="display: none;">
|
||||
<a id="history-back-button" title="Go to previous note." class="icon-action bx bx-left-arrow-circle"></a>
|
||||
|
||||
<a id="history-forward-button" title="Go to next note." class="icon-action bx bx-right-arrow-circle"></a>
|
||||
</div>
|
||||
|
||||
<div style="flex-grow: 100; display: flex;">
|
||||
<button class="btn btn-sm" id="jump-to-note-dialog-button" data-kb-action="JumpToNote">
|
||||
<span class="bx bx-crosshair"></span>
|
||||
Jump to note
|
||||
</button>
|
||||
|
||||
<button class="btn btn-sm" id="recent-changes-button" data-kb-action="ShowRecentChanges">
|
||||
<span class="bx bx-history"></span>
|
||||
|
||||
Recent changes
|
||||
</button>
|
||||
|
||||
<button class="btn btn-sm"
|
||||
id="enter-protected-session-button"
|
||||
title="Enter protected session to be able to find and view protected notes">
|
||||
<span class="bx bx-log-in"></span>
|
||||
|
||||
Enter protected session
|
||||
</button>
|
||||
|
||||
<button class="btn btn-sm"
|
||||
id="leave-protected-session-button"
|
||||
title="Leave protected session so that protected notes are not accessible any more."
|
||||
style="display: none;">
|
||||
<span class="bx bx-log-out"></span>
|
||||
|
||||
Leave protected session
|
||||
</button>
|
||||
</div>
|
||||
|
||||
<div id="plugin-buttons">
|
||||
</div>
|
||||
|
||||
<div>
|
||||
<div id="container" style="display: none;">
|
||||
<div style="display: flex;">
|
||||
<div id="global-menu-wrapper">
|
||||
<div class="dropdown" id="global-menu">
|
||||
<button type="button" data-toggle="dropdown" aria-haspopup="true" aria-expanded="false" class="btn btn-sm dropdown-toggle">
|
||||
<span class="bx bx-menu"></span>
|
||||
@@ -123,54 +84,109 @@
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div id="left-pane" class="hide-in-zen-mode">
|
||||
<div id="global-buttons">
|
||||
<a id="create-top-level-note-button" title="Create new top level note" class="icon-action bx bx-folder-plus"></a>
|
||||
|
||||
<a id="collapse-tree-button" title="Collapse note tree" data-kb-action="CollapseTree" class="icon-action bx bx-layer-minus"></a>
|
||||
|
||||
<a id="scroll-to-active-note-button" title="Scroll to active note" data-kb-action="ScrollToActiveNote" class="icon-action bx bx-crosshair"></a>
|
||||
|
||||
<a id="toggle-search-button" title="Search in notes" data-kb-action="SearchNotes" class="icon-action bx bx-search"></a>
|
||||
<div class="note-tab-row hide-in-zen-mode">
|
||||
<div class="note-tab-row-content"></div>
|
||||
</div>
|
||||
|
||||
<div id="search-box">
|
||||
<div class="form-group">
|
||||
<div class="input-group">
|
||||
<input name="search-text" id="search-text" class="form-control"
|
||||
placeholder="Search text, labels" autocomplete="off">
|
||||
<div id="title-bar-buttons" style="display: none;">
|
||||
<button class="btn icon-action bx bx-minus" id="minimize-btn"></button>
|
||||
<button class="btn icon-action bx bx-checkbox" id="maximize-btn"></button>
|
||||
<button class="btn icon-action bx bx-x" id="close-btn"></button>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="input-group-append">
|
||||
<button id="do-search-button" class="btn btn-sm icon-button bx bx-search" title="Search (enter)"></button>
|
||||
<div id="header" class="hide-in-zen-mode">
|
||||
<div id="history-navigation" style="display: none;">
|
||||
<a id="history-back-button" title="Go to previous note." class="icon-action bx bx-left-arrow-circle"></a>
|
||||
|
||||
<a id="history-forward-button" title="Go to next note." class="icon-action bx bx-right-arrow-circle"></a>
|
||||
</div>
|
||||
|
||||
<div style="flex-grow: 100; display: flex;">
|
||||
<button class="btn btn-sm" id="jump-to-note-dialog-button" data-kb-action="JumpToNote">
|
||||
<span class="bx bx-crosshair"></span>
|
||||
Jump to note
|
||||
</button>
|
||||
|
||||
<button class="btn btn-sm" id="recent-changes-button" data-kb-action="ShowRecentChanges">
|
||||
<span class="bx bx-history"></span>
|
||||
|
||||
Recent changes
|
||||
</button>
|
||||
|
||||
<button class="btn btn-sm"
|
||||
id="enter-protected-session-button"
|
||||
title="Enter protected session to be able to find and view protected notes">
|
||||
<span class="bx bx-log-in"></span>
|
||||
|
||||
Enter protected session
|
||||
</button>
|
||||
|
||||
<button class="btn btn-sm"
|
||||
id="leave-protected-session-button"
|
||||
title="Leave protected session so that protected notes are not accessible any more."
|
||||
style="display: none;">
|
||||
<span class="bx bx-log-out"></span>
|
||||
|
||||
Leave protected session
|
||||
</button>
|
||||
</div>
|
||||
|
||||
<div id="plugin-buttons">
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div style="display: flex; height: 100%;">
|
||||
<div id="left-pane" class="hide-in-zen-mode">
|
||||
<div id="global-buttons">
|
||||
<a id="create-top-level-note-button" title="Create new top level note" class="icon-action bx bx-folder-plus"></a>
|
||||
|
||||
<a id="collapse-tree-button" title="Collapse note tree" data-kb-action="CollapseTree" class="icon-action bx bx-layer-minus"></a>
|
||||
|
||||
<a id="scroll-to-active-note-button" title="Scroll to active note" data-kb-action="ScrollToActiveNote" class="icon-action bx bx-crosshair"></a>
|
||||
|
||||
<a id="toggle-search-button" title="Search in notes" data-kb-action="SearchNotes" class="icon-action bx bx-search"></a>
|
||||
</div>
|
||||
|
||||
<div id="search-box">
|
||||
<div class="form-group">
|
||||
<div class="input-group">
|
||||
<input name="search-text" id="search-text" class="form-control"
|
||||
placeholder="Search text, labels" autocomplete="off">
|
||||
|
||||
<div class="input-group-append">
|
||||
<button id="do-search-button" class="btn btn-sm icon-button bx bx-search" title="Search (enter)"></button>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
|
||||
<div style="display: flex; align-items: center; justify-content: space-evenly; flex-wrap: wrap;">
|
||||
<button id="save-search-button" class="btn btn-sm"
|
||||
title="This will create new saved search note under active note.">
|
||||
<span class="bx bx-save"></span> Save search</button>
|
||||
|
||||
<button id="close-search-button" class="btn btn-sm"><span class="bx bx-x"></span> Close search</button>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div id="search-results">
|
||||
<strong>Search results:</strong>
|
||||
|
||||
<div style="display: flex; align-items: center; justify-content: space-evenly; flex-wrap: wrap;">
|
||||
<button id="save-search-button" class="btn btn-sm"
|
||||
title="This will create new saved search note under active note.">
|
||||
<span class="bx bx-save"></span> Save search</button>
|
||||
|
||||
<button id="close-search-button" class="btn btn-sm"><span class="bx bx-x"></span> Close search</button>
|
||||
<ul id="search-results-inner"></ul>
|
||||
</div>
|
||||
|
||||
<div id="tree"></div>
|
||||
|
||||
<div class="dropdown-menu dropdown-menu-sm" id="context-menu-container"></div>
|
||||
</div>
|
||||
|
||||
<div id="search-results">
|
||||
<strong>Search results:</strong>
|
||||
<% include center.ejs %>
|
||||
|
||||
<ul id="search-results-inner"></ul>
|
||||
</div>
|
||||
|
||||
<div id="tree"></div>
|
||||
|
||||
<div class="dropdown-menu dropdown-menu-sm" id="context-menu-container"></div>
|
||||
<% include sidebar.ejs %>
|
||||
</div>
|
||||
|
||||
<% include tabs.ejs %>
|
||||
|
||||
<% include dialogs/about.ejs %>
|
||||
<% include dialogs/add_link.ejs %>
|
||||
<% include dialogs/attributes.ejs %>
|
||||
@@ -228,6 +244,8 @@
|
||||
|
||||
<script src="libraries/dayjs.min.js"></script>
|
||||
|
||||
<script src="libraries/split.min.js"></script>
|
||||
|
||||
<link href="stylesheets/themes.css" rel="stylesheet">
|
||||
<link href="stylesheets/style.css" rel="stylesheet">
|
||||
<link href="stylesheets/desktop.css" rel="stylesheet">
|
||||
|
||||
@@ -1,7 +1,6 @@
|
||||
<div class="note-detail-sidebar hide-in-zen-mode" style="width: <%= sidebarWidthPercent %>%; min-width: <%= sidebarMinWidth %>px">
|
||||
<div style="text-align: center; margin-bottom: 5px;">
|
||||
<button class="hide-sidebar-button">hide sidebar <span class="bx bx-chevrons-right"></span></button>
|
||||
</div>
|
||||
<button id="hide-sidebar-button" class="btn btn-sm icon-button bx bx-chevrons-right" title="Hide sidebar"></button>
|
||||
<button id="show-sidebar-button" class="btn btn-sm icon-button bx bx-chevrons-left" title="Show sidebar"></button>
|
||||
|
||||
<div class="note-detail-widget-container"></div>
|
||||
<div id="right-pane" class="hide-in-zen-mode">
|
||||
<div id="sidebar-container"></div>
|
||||
</div>
|
||||
@@ -1,43 +0,0 @@
|
||||
<div class="note-tab-row hide-in-hide-in-zen-mode">
|
||||
<div class="note-tab-row-content"></div>
|
||||
</div>
|
||||
|
||||
<div id="note-tab-container">
|
||||
<div class="note-tab-content note-tab-content-template">
|
||||
<div class="note-detail-content" style="width: <%= contentWidthPercent %>%">
|
||||
<% include title.ejs %>
|
||||
|
||||
<div class="note-detail-script-area"></div>
|
||||
|
||||
<table class="note-detail-promoted-attributes"></table>
|
||||
|
||||
<div class="note-detail-component-wrapper">
|
||||
<div class="note-detail-text note-detail-component">
|
||||
<div class="note-detail-text-editor" tabindex="10000"></div>
|
||||
</div>
|
||||
|
||||
<div class="note-detail-code note-detail-component">
|
||||
<div class="note-detail-code-editor"></div>
|
||||
</div>
|
||||
|
||||
<% include details/empty.ejs %>
|
||||
|
||||
<% include details/search.ejs %>
|
||||
|
||||
<% include details/render.ejs %>
|
||||
|
||||
<% include details/file.ejs %>
|
||||
|
||||
<% include details/image.ejs %>
|
||||
|
||||
<% include details/relation_map.ejs %>
|
||||
|
||||
<% include details/protected_session_password.ejs %>
|
||||
|
||||
<% include details/book.ejs %>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<% include sidebar.ejs %>
|
||||
</div>
|
||||
</div>
|
||||
@@ -65,8 +65,6 @@
|
||||
<a class="dropdown-item show-note-info-button"><kbd data-kb-action="ShowNoteInfo"></kbd> Note info</a>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<button class="btn btn-sm icon-button bx bx-chevrons-left show-sidebar-button" title="Show sidebar"></button>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
Reference in New Issue
Block a user