mirror of
https://github.com/zadam/trilium.git
synced 2025-03-01 14:22:32 +01:00
store images in notes, basic structure
This commit is contained in:
parent
5f427e37fe
commit
d0d2a7fe47
56
db/migrations/0115__images_in_notes.sql
Normal file
56
db/migrations/0115__images_in_notes.sql
Normal file
@ -0,0 +1,56 @@
|
||||
-- allow null for note content (for deleted notes)
|
||||
CREATE TABLE IF NOT EXISTS "notes_mig" (
|
||||
`noteId` TEXT NOT NULL,
|
||||
`title` TEXT NOT NULL DEFAULT "note",
|
||||
`content` TEXT NULL DEFAULT NULL,
|
||||
`isProtected` INT NOT NULL DEFAULT 0,
|
||||
`type` TEXT NOT NULL DEFAULT 'text',
|
||||
`mime` TEXT NOT NULL DEFAULT 'text/html',
|
||||
`hash` TEXT DEFAULT "" NOT NULL,
|
||||
`isDeleted` INT NOT NULL DEFAULT 0,
|
||||
`dateCreated` TEXT NOT NULL,
|
||||
`dateModified` TEXT NOT NULL,
|
||||
PRIMARY KEY(`noteId`)
|
||||
);
|
||||
|
||||
INSERT INTO notes_mig (noteId, title, content, isProtected, isDeleted, dateCreated, dateModified, type, mime, hash)
|
||||
SELECT noteId, title, content, isProtected, isDeleted, dateCreated, dateModified, type, mime, hash FROM notes;
|
||||
|
||||
DROP TABLE notes;
|
||||
|
||||
ALTER TABLE notes_mig RENAME TO notes;
|
||||
|
||||
CREATE TABLE "links" (
|
||||
`linkId` TEXT NOT NULL,
|
||||
`noteId` TEXT NOT NULL,
|
||||
`targetNoteId` TEXT NOT NULL,
|
||||
`type` TEXT NOT NULL,
|
||||
`isDeleted` INTEGER NOT NULL DEFAULT 0,
|
||||
`dateCreated` TEXT NOT NULL,
|
||||
`dateModified` TEXT NOT NULL,
|
||||
PRIMARY KEY(`linkId`)
|
||||
);
|
||||
|
||||
INSERT INTO links (linkId, noteId, targetNoteId, type, isDeleted, dateCreated, dateModified)
|
||||
SELECT 'L' || SUBSTR(noteImageId, 1), noteId, imageId, 'image', isDeleted, dateCreated, dateModified FROM note_images;
|
||||
|
||||
INSERT INTO branches (branchId, noteId, parentNoteId, notePosition, prefix, isExpanded, isDeleted, dateModified, hash, dateCreated)
|
||||
SELECT 'B' || SUBSTR(noteImageId, 1), imageId, noteId, 100, '', 0, isDeleted, dateModified, hash, dateCreated FROM note_images;
|
||||
|
||||
DROP TABLE note_images;
|
||||
|
||||
INSERT INTO notes (noteId, title, content, isProtected, isDeleted, dateCreated, dateModified, type, mime, hash)
|
||||
SELECT imageId, name, data, 0, isDeleted, dateCreated, dateModified, 'image', 'image/' || format, hash FROM images;
|
||||
|
||||
DROP TABLE images;
|
||||
|
||||
UPDATE sync SET entityName = 'notes' WHERE entityName = 'images';
|
||||
|
||||
INSERT INTO sync (entityName, entityId, sourceId, syncDate)
|
||||
SELECT 'links', 'L' || SUBSTR(entityId, 1), sourceId, syncDate FROM sync WHERE entityName = 'note_images';
|
||||
|
||||
INSERT INTO sync (entityName, entityId, sourceId, syncDate)
|
||||
SELECT 'branches', 'B' || SUBSTR(entityId, 1), sourceId, syncDate FROM sync WHERE entityName = 'note_images';
|
||||
|
||||
DELETE FROM sync WHERE entityName = 'note_images';
|
||||
DELETE FROM sync WHERE entityName = 'images';
|
@ -2,6 +2,7 @@ const Note = require('../entities/note');
|
||||
const NoteRevision = require('../entities/note_revision');
|
||||
const Image = require('../entities/image');
|
||||
const NoteImage = require('../entities/note_image');
|
||||
const Link = require('../entities/link');
|
||||
const Branch = require('../entities/branch');
|
||||
const Attribute = require('../entities/attribute');
|
||||
const RecentNote = require('../entities/recent_note');
|
||||
@ -38,6 +39,9 @@ function createEntityFromRow(row) {
|
||||
else if (row.noteRevisionId) {
|
||||
entity = new NoteRevision(row);
|
||||
}
|
||||
else if (row.linkId) {
|
||||
entity = new Link(row);
|
||||
}
|
||||
else if (row.noteImageId) {
|
||||
entity = new NoteImage(row);
|
||||
}
|
||||
|
51
src/entities/link.js
Normal file
51
src/entities/link.js
Normal file
@ -0,0 +1,51 @@
|
||||
"use strict";
|
||||
|
||||
const Entity = require('./entity');
|
||||
const repository = require('../services/repository');
|
||||
const dateUtils = require('../services/date_utils');
|
||||
|
||||
/**
|
||||
* This class represents link from one note to another in the form of hyperlink or image reference. Note that
|
||||
* this is different concept than attribute/relation.
|
||||
*
|
||||
* @param {string} linkId
|
||||
* @param {string} noteId
|
||||
* @param {string} targetNoteId
|
||||
* @param {string} type
|
||||
* @param {boolean} isDeleted
|
||||
* @param {string} dateModified
|
||||
* @param {string} dateCreated
|
||||
*
|
||||
* @extends Entity
|
||||
*/
|
||||
class Link extends Entity {
|
||||
static get entityName() { return "links"; }
|
||||
static get primaryKeyName() { return "linkId"; }
|
||||
static get hashedProperties() { return ["linkId", "noteId", "targetNoteId", "type", "isDeleted", "dateCreated", "dateModified"]; }
|
||||
|
||||
async getNote() {
|
||||
return await repository.getEntity("SELECT * FROM notes WHERE noteId = ?", [this.noteId]);
|
||||
}
|
||||
|
||||
async getTargetNote() {
|
||||
return await repository.getEntity("SELECT * FROM notes WHERE noteId = ?", [this.targetNoteId]);
|
||||
}
|
||||
|
||||
beforeSaving() {
|
||||
if (!this.isDeleted) {
|
||||
this.isDeleted = false;
|
||||
}
|
||||
|
||||
if (!this.dateCreated) {
|
||||
this.dateCreated = dateUtils.nowDate();
|
||||
}
|
||||
|
||||
super.beforeSaving();
|
||||
|
||||
if (this.isChanged) {
|
||||
this.dateModified = dateUtils.nowDate();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
module.exports = Link;
|
@ -487,6 +487,13 @@ class Note extends Entity {
|
||||
return await repository.getEntities("SELECT * FROM note_images WHERE noteId = ? AND isDeleted = 0", [this.noteId]);
|
||||
}
|
||||
|
||||
/**
|
||||
* @returns {Promise<Link[]>}
|
||||
*/
|
||||
async getLinks() {
|
||||
return await repository.getEntities("SELECT * FROM links WHERE noteId = ? AND isDeleted = 0", [this.noteId]);
|
||||
}
|
||||
|
||||
/**
|
||||
* @returns {Promise<Branch[]>}
|
||||
*/
|
||||
|
BIN
src/public/images/icons/image-16.png
Normal file
BIN
src/public/images/icons/image-16.png
Normal file
Binary file not shown.
After Width: | Height: | Size: 392 B |
@ -31,8 +31,8 @@ $("#import-upload").change(async function() {
|
||||
data: formData,
|
||||
dataType: 'json',
|
||||
type: 'POST',
|
||||
contentType: false, // NEEDED, DON'T OMIT THIS
|
||||
processData: false, // NEEDED, DON'T OMIT THIS
|
||||
contentType: false, // NEEDED, DON'T REMOVE THIS
|
||||
processData: false, // NEEDED, DON'T REMOVE THIS
|
||||
})
|
||||
.fail((xhr, status, error) => alert('Import error: ' + xhr.responseText))
|
||||
.done(async note => {
|
||||
|
@ -238,7 +238,10 @@ async function loadNoteDetail(noteId) {
|
||||
async function showChildrenOverview() {
|
||||
const note = getCurrentNote();
|
||||
const attributes = await attributePromise;
|
||||
const hideChildrenOverview = attributes.some(attr => attr.type === 'label' && attr.name === 'hideChildrenOverview') || note.type === 'relation-map';
|
||||
const hideChildrenOverview = attributes.some(attr => attr.type === 'label' && attr.name === 'hideChildrenOverview')
|
||||
|| note.type === 'relation-map'
|
||||
|| note.type === 'image'
|
||||
|| note.type === 'file';
|
||||
|
||||
if (hideChildrenOverview) {
|
||||
$childrenOverview.hide();
|
||||
|
52
src/public/javascripts/services/note_detail_image.js
Normal file
52
src/public/javascripts/services/note_detail_image.js
Normal file
@ -0,0 +1,52 @@
|
||||
import utils from "./utils.js";
|
||||
import server from "./server.js";
|
||||
import protectedSessionHolder from "./protected_session_holder.js";
|
||||
import noteDetailService from "./note_detail.js";
|
||||
|
||||
const $noteDetailFile = $('#note-detail-file');
|
||||
|
||||
const $fileFileName = $("#file-filename");
|
||||
const $fileFileType = $("#file-filetype");
|
||||
const $fileFileSize = $("#file-filesize");
|
||||
const $fileDownload = $("#file-download");
|
||||
const $fileOpen = $("#file-open");
|
||||
|
||||
async function show() {
|
||||
const currentNote = noteDetailService.getCurrentNote();
|
||||
|
||||
const attributes = await server.get('notes/' + currentNote.noteId + '/attributes');
|
||||
const attributeMap = utils.toObject(attributes, l => [l.name, l.value]);
|
||||
|
||||
$noteDetailFile.show();
|
||||
|
||||
$fileFileName.text(attributeMap.originalFileName);
|
||||
$fileFileSize.text(attributeMap.fileSize + " bytes");
|
||||
$fileFileType.text(currentNote.mime);
|
||||
}
|
||||
|
||||
$fileDownload.click(() => utils.download(getFileUrl()));
|
||||
|
||||
$fileOpen.click(() => {
|
||||
if (utils.isElectron()) {
|
||||
const open = require("open");
|
||||
|
||||
open(getFileUrl());
|
||||
}
|
||||
else {
|
||||
window.location.href = getFileUrl();
|
||||
}
|
||||
});
|
||||
|
||||
function getFileUrl() {
|
||||
// electron needs absolute URL so we extract current host, port, protocol
|
||||
return utils.getHost() + "/api/notes/" + noteDetailService.getCurrentNoteId()
|
||||
+ "/download?protectedSessionId=" + encodeURIComponent(protectedSessionHolder.getProtectedSessionId());
|
||||
}
|
||||
|
||||
export default {
|
||||
show,
|
||||
getContent: () => null,
|
||||
focus: () => null,
|
||||
onNoteChange: () => null,
|
||||
cleanup: () => null
|
||||
}
|
@ -81,7 +81,10 @@ function NoteTypeModel() {
|
||||
return 'Relation Map';
|
||||
}
|
||||
else if (type === 'search') {
|
||||
// ignore and do nothing, "type" will be hidden since it's not possible to switch to and from search
|
||||
return 'Search note'
|
||||
}
|
||||
else if (type === 'image') {
|
||||
return 'Image'
|
||||
}
|
||||
else {
|
||||
infoService.throwError('Unrecognized type: ' + type);
|
||||
@ -89,7 +92,7 @@ function NoteTypeModel() {
|
||||
};
|
||||
|
||||
this.isDisabled = function() {
|
||||
return self.type() === "file";
|
||||
return ["file", "image", "search"].includes(self.type());
|
||||
};
|
||||
|
||||
async function save() {
|
||||
|
11240
src/public/libraries/fancytree/jquery.fancytree-all-deps.js
Normal file
11240
src/public/libraries/fancytree/jquery.fancytree-all-deps.js
Normal file
File diff suppressed because it is too large
Load Diff
File diff suppressed because one or more lines are too long
@ -136,6 +136,10 @@ span.fancytree-node.relation-map > span.fancytree-icon {
|
||||
background: url("../images/icons/relation-map-16.png") 0 0;
|
||||
}
|
||||
|
||||
span.fancytree-node.image > span.fancytree-icon {
|
||||
background: url("../images/icons/image-16.png") 0 0;
|
||||
}
|
||||
|
||||
span.fancytree-node.render > span.fancytree-icon {
|
||||
background: url("../images/icons/play-16.png") 0 0;
|
||||
}
|
||||
|
@ -12,8 +12,8 @@ async function getNote(req) {
|
||||
return [404, "Note " + noteId + " has not been found."];
|
||||
}
|
||||
|
||||
if (note.type === 'file') {
|
||||
// no need to transfer (potentially large) file payload for this request
|
||||
if (note.type === 'file' || note.type === 'image') {
|
||||
// no need to transfer (potentially large) file/image payload for this request
|
||||
note.content = null;
|
||||
}
|
||||
|
||||
|
@ -3,8 +3,8 @@
|
||||
const build = require('./build');
|
||||
const packageJson = require('../../package');
|
||||
|
||||
const APP_DB_VERSION = 114;
|
||||
const SYNC_VERSION = 1;
|
||||
const APP_DB_VERSION = 115;
|
||||
const SYNC_VERSION = 2;
|
||||
|
||||
module.exports = {
|
||||
appVersion: packageJson.version,
|
||||
|
@ -209,7 +209,13 @@ async function runAllChecks() {
|
||||
FROM
|
||||
notes
|
||||
WHERE
|
||||
type != 'text' AND type != 'code' AND type != 'render' AND type != 'file' AND type != 'search' AND type != 'relation-map'`,
|
||||
type != 'text'
|
||||
AND type != 'code'
|
||||
AND type != 'render'
|
||||
AND type != 'file'
|
||||
AND type != 'image'
|
||||
AND type != 'search'
|
||||
AND type != 'relation-map'`,
|
||||
"Note has invalid type", errorList);
|
||||
|
||||
await runCheck(`
|
||||
|
@ -247,7 +247,8 @@ const primaryKeys = {
|
||||
"note_images": "noteImageId",
|
||||
"api_tokens": "apiTokenId",
|
||||
"options": "name",
|
||||
"attributes": "attributeId"
|
||||
"attributes": "attributeId",
|
||||
"links": "linkId"
|
||||
};
|
||||
|
||||
async function getEntityRow(entityName, entityId) {
|
||||
|
@ -28,6 +28,10 @@ async function addRecentNoteSync(branchId, sourceId) {
|
||||
await addEntitySync("recent_notes", branchId, sourceId);
|
||||
}
|
||||
|
||||
async function addLinkSync(linkId, sourceId) {
|
||||
await addEntitySync("links", linkId, sourceId);
|
||||
}
|
||||
|
||||
async function addImageSync(imageId, sourceId) {
|
||||
await addEntitySync("images", imageId, sourceId);
|
||||
}
|
||||
@ -91,10 +95,9 @@ async function fillAllSyncRows() {
|
||||
await fillSyncRows("branches", "branchId");
|
||||
await fillSyncRows("note_revisions", "noteRevisionId");
|
||||
await fillSyncRows("recent_notes", "branchId");
|
||||
await fillSyncRows("images", "imageId");
|
||||
await fillSyncRows("note_images", "noteImageId");
|
||||
await fillSyncRows("attributes", "attributeId");
|
||||
await fillSyncRows("api_tokens", "apiTokenId");
|
||||
await fillSyncRows("links", "linkId");
|
||||
await fillSyncRows("options", "name", 'isSynced = 1');
|
||||
}
|
||||
|
||||
|
@ -24,6 +24,9 @@ async function updateEntity(sync, entity, sourceId) {
|
||||
else if (entityName === 'recent_notes') {
|
||||
await updateRecentNotes(entity, sourceId);
|
||||
}
|
||||
else if (entityName === 'links') {
|
||||
await updateLink(entity, sourceId);
|
||||
}
|
||||
else if (entityName === 'images') {
|
||||
await updateImage(entity, sourceId);
|
||||
}
|
||||
@ -139,6 +142,20 @@ async function updateRecentNotes(entity, sourceId) {
|
||||
}
|
||||
}
|
||||
|
||||
async function updateLink(entity, sourceId) {
|
||||
const origLink = await sql.getRow("SELECT * FROM links WHERE linkId = ?", [entity.linkId]);
|
||||
|
||||
if (!origLink || origLink.dateModified <= entity.dateModified) {
|
||||
await sql.transactional(async () => {
|
||||
await sql.replace("links", entity);
|
||||
|
||||
await syncTableService.addLinkSync(entity.linkId, sourceId);
|
||||
});
|
||||
|
||||
log.info("Update/sync link " + entity.linkId);
|
||||
}
|
||||
}
|
||||
|
||||
async function updateImage(entity, sourceId) {
|
||||
if (entity.data !== null) {
|
||||
entity.data = Buffer.from(entity.data, 'base64');
|
||||
|
28
src/views/details/detail.ejs
Normal file
28
src/views/details/detail.ejs
Normal file
@ -0,0 +1,28 @@
|
||||
<div id="note-detail-wrapper">
|
||||
<div id="note-detail-script-area"></div>
|
||||
|
||||
<table id="note-detail-promoted-attributes"></table>
|
||||
|
||||
<div id="note-detail-component-wrapper">
|
||||
<div id="note-detail-text" class="note-detail-component" tabindex="10000"></div>
|
||||
|
||||
<div id="note-detail-code" class="note-detail-component"></div>
|
||||
<input type="file" id="file-upload" style="display: none" />
|
||||
|
||||
<% include search.ejs %>
|
||||
|
||||
<% include render.ejs %>
|
||||
|
||||
<% include file.ejs %>
|
||||
|
||||
<% include relation_map.ejs %>
|
||||
</div>
|
||||
|
||||
<div id="children-overview"></div>
|
||||
|
||||
<div id="attribute-list">
|
||||
<button class="btn btn-sm show-attributes-button">Attributes:</button>
|
||||
|
||||
<span id="attribute-list-inner"></span>
|
||||
</div>
|
||||
</div>
|
23
src/views/details/file.ejs
Normal file
23
src/views/details/file.ejs
Normal file
@ -0,0 +1,23 @@
|
||||
<div id="note-detail-file" class="note-detail-component">
|
||||
<table id="file-table">
|
||||
<tr>
|
||||
<th>File name:</th>
|
||||
<td id="file-filename"></td>
|
||||
</tr>
|
||||
<tr>
|
||||
<th>File type:</th>
|
||||
<td id="file-filetype"></td>
|
||||
</tr>
|
||||
<tr>
|
||||
<th>File size:</th>
|
||||
<td id="file-filesize"></td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td>
|
||||
<button id="file-download" class="btn btn-primary" type="button">Download</button>
|
||||
|
||||
<button id="file-open" class="btn btn-primary" type="button">Open</button>
|
||||
</td>
|
||||
</tr>
|
||||
</table>
|
||||
</div>
|
25
src/views/details/relation_map.ejs
Normal file
25
src/views/details/relation_map.ejs
Normal file
@ -0,0 +1,25 @@
|
||||
<div id="note-detail-relation-map" class="note-detail-component">
|
||||
<button id="relation-map-add-child-notes" class="btn" type="button"
|
||||
title="Add all child notes of this relation map note">Add child notes</button>
|
||||
|
||||
|
||||
|
||||
<button id="relation-map-create-child-note" class="btn" type="button"
|
||||
title="Create new child note and add it into this relation map">Create child note</button>
|
||||
|
||||
<div class="btn-group" style="float: right; padding-right: 20px;">
|
||||
<button type="button"
|
||||
class="btn icon-button24"
|
||||
title="Zoom In"
|
||||
id="relation-map-zoom-in"
|
||||
style="background-image: url('/images/icons/zoom-in-24.png');"/>
|
||||
|
||||
<button type="button"
|
||||
class="btn icon-button24"
|
||||
title="Zoom Out"
|
||||
id="relation-map-zoom-out"
|
||||
style="background-image: url('/images/icons/zoom-out-24.png');"/>
|
||||
</div>
|
||||
|
||||
<div id="relation-map-canvas"></div>
|
||||
</div>
|
9
src/views/details/render.ejs
Normal file
9
src/views/details/render.ejs
Normal file
@ -0,0 +1,9 @@
|
||||
<div id="note-detail-render" class="note-detail-component">
|
||||
<div id="note-detail-render-help" class="alert alert-warning">
|
||||
<p><strong>This help note is shown because this note of type Render HTML doesn't have required relation to function properly.</strong></p>
|
||||
|
||||
<p>Render HTML note type is used for <a href="https://github.com/zadam/trilium/wiki/Scripts">scripting</a>. In short, you have a HTML code note (optionally with some JavaScript) and this note will render it. To make it work, you need to define a relation (in <a class="show-attributes-button">Attributes dialog</a>) called "renderNote" pointing to the HTML note to render. Once that's defined you can click on the "play" button to render.</p>
|
||||
</div>
|
||||
|
||||
<div id="note-detail-render-content"></div>
|
||||
</div>
|
39
src/views/details/search.ejs
Normal file
39
src/views/details/search.ejs
Normal file
@ -0,0 +1,39 @@
|
||||
<div id="note-detail-search" class="note-detail-component">
|
||||
<div style="display: flex; align-items: center;">
|
||||
<strong>Search string: </strong>
|
||||
<textarea rows="4" cols="50" id="search-string"></textarea>
|
||||
</div>
|
||||
|
||||
<br />
|
||||
|
||||
<h4>Help</h4>
|
||||
<p>
|
||||
<ul>
|
||||
<li>
|
||||
<code>@abc</code> - matches notes with label abc</li>
|
||||
<li>
|
||||
<code>@!abc</code> - matches notes without abc label (maybe not the best syntax)</li>
|
||||
<li>
|
||||
<code>@abc=true</code> - matches notes with label abc having value true</li>
|
||||
<li><code>@abc!=true</code></li>
|
||||
<li>
|
||||
<code>@"weird label"="weird value"</code> - works also with whitespace inside names values</li>
|
||||
<li>
|
||||
<code>@abc and @def</code> - matches notes with both abc and def</li>
|
||||
<li>
|
||||
<code>@abc @def</code> - AND relation is implicit when specifying multiple labels</li>
|
||||
<li>
|
||||
<code>@abc or @def</code> - OR relation</li>
|
||||
<li>
|
||||
<code>@abc<=5</code> - numerical comparison (also >, >=, <).</li>
|
||||
<li>
|
||||
<code>some search string @abc @def</code> - combination of fulltext and label search - both of them need to match (OR not supported)</li>
|
||||
<li>
|
||||
<code>@abc @def some search string</code> - same combination</li>
|
||||
</ul>
|
||||
|
||||
<button class="btn btn-sm" type="button" data-help-page="Search">
|
||||
<i class="glyphicon glyphicon-info-sign"></i> Complete help on search
|
||||
</button>
|
||||
</p>
|
||||
</div>
|
@ -95,6 +95,8 @@
|
||||
</div>
|
||||
|
||||
<div id="tree"></div>
|
||||
|
||||
<div class="dropdown-menu dropdown-menu-sm context-menu" id="tree-context-menu"></div>
|
||||
</div>
|
||||
|
||||
<div id="title-container">
|
||||
@ -140,7 +142,7 @@
|
||||
|
||||
|
||||
|
||||
<div class="dropdown" id="note-type" data-bind="visible: type() != 'search'">
|
||||
<div class="dropdown" id="note-type">
|
||||
<button data-bind="disable: isDisabled()" type="button" data-toggle="dropdown" aria-haspopup="true" aria-expanded="false" class="btn btn-sm dropdown-toggle">
|
||||
Type: <span data-bind="text: typeString()"></span>
|
||||
<span class="caret"></span>
|
||||
@ -176,133 +178,7 @@
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div id="note-detail-wrapper">
|
||||
<div id="note-detail-script-area"></div>
|
||||
|
||||
<table id="note-detail-promoted-attributes"></table>
|
||||
|
||||
<div id="note-detail-component-wrapper">
|
||||
<div id="note-detail-text" class="note-detail-component" tabindex="10000"></div>
|
||||
|
||||
<div id="note-detail-search" class="note-detail-component">
|
||||
<div style="display: flex; align-items: center;">
|
||||
<strong>Search string: </strong>
|
||||
<textarea rows="4" cols="50" id="search-string"></textarea>
|
||||
</div>
|
||||
|
||||
<br />
|
||||
|
||||
<h4>Help</h4>
|
||||
<p>
|
||||
<ul>
|
||||
<li>
|
||||
<code>@abc</code> - matches notes with label abc</li>
|
||||
<li>
|
||||
<code>@!abc</code> - matches notes without abc label (maybe not the best syntax)</li>
|
||||
<li>
|
||||
<code>@abc=true</code> - matches notes with label abc having value true</li>
|
||||
<li><code>@abc!=true</code></li>
|
||||
<li>
|
||||
<code>@"weird label"="weird value"</code> - works also with whitespace inside names values</li>
|
||||
<li>
|
||||
<code>@abc and @def</code> - matches notes with both abc and def</li>
|
||||
<li>
|
||||
<code>@abc @def</code> - AND relation is implicit when specifying multiple labels</li>
|
||||
<li>
|
||||
<code>@abc or @def</code> - OR relation</li>
|
||||
<li>
|
||||
<code>@abc<=5</code> - numerical comparison (also >, >=, <).</li>
|
||||
<li>
|
||||
<code>some search string @abc @def</code> - combination of fulltext and label search - both of them need to match (OR not supported)</li>
|
||||
<li>
|
||||
<code>@abc @def some search string</code> - same combination</li>
|
||||
</ul>
|
||||
|
||||
<button class="btn btn-sm" type="button" data-help-page="Search">
|
||||
<i class="glyphicon glyphicon-info-sign"></i> Complete help on search
|
||||
</button>
|
||||
</p>
|
||||
</div>
|
||||
|
||||
<div id="note-detail-code" class="note-detail-component"></div>
|
||||
|
||||
<div id="note-detail-render" class="note-detail-component">
|
||||
<div id="note-detail-render-help" class="alert alert-warning">
|
||||
<p><strong>This help note is shown because this note of type Render HTML doesn't have required relation to function properly.</strong></p>
|
||||
|
||||
<p>Render HTML note type is used for <a href="https://github.com/zadam/trilium/wiki/Scripts">scripting</a>. In short, you have a HTML code note (optionally with some JavaScript) and this note will render it. To make it work, you need to define a relation (in <a class="show-attributes-button">Attributes dialog</a>) called "renderNote" pointing to the HTML note to render. Once that's defined you can click on the "play" button to render.</p>
|
||||
</div>
|
||||
|
||||
<div id="note-detail-render-content"></div>
|
||||
</div>
|
||||
|
||||
<div id="note-detail-file" class="note-detail-component">
|
||||
<table id="file-table">
|
||||
<tr>
|
||||
<th>File name:</th>
|
||||
<td id="file-filename"></td>
|
||||
</tr>
|
||||
<tr>
|
||||
<th>File type:</th>
|
||||
<td id="file-filetype"></td>
|
||||
</tr>
|
||||
<tr>
|
||||
<th>File size:</th>
|
||||
<td id="file-filesize"></td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td>
|
||||
<button id="file-download" class="btn btn-primary" type="button">Download</button>
|
||||
|
||||
<button id="file-open" class="btn btn-primary" type="button">Open</button>
|
||||
</td>
|
||||
</tr>
|
||||
</table>
|
||||
</div>
|
||||
|
||||
<input type="file" id="file-upload" style="display: none" />
|
||||
|
||||
<div id="note-detail-relation-map" class="note-detail-component">
|
||||
<button id="relation-map-add-child-notes" class="btn" type="button"
|
||||
title="Add all child notes of this relation map note">Add child notes</button>
|
||||
|
||||
|
||||
|
||||
<button id="relation-map-create-child-note" class="btn" type="button"
|
||||
title="Create new child note and add it into this relation map">Create child note</button>
|
||||
|
||||
<div class="btn-group" style="float: right; padding-right: 20px;">
|
||||
<button type="button"
|
||||
class="btn icon-button24"
|
||||
title="Zoom In"
|
||||
id="relation-map-zoom-in"
|
||||
style="background-image: url('/images/icons/zoom-in-24.png');"/>
|
||||
|
||||
<button type="button"
|
||||
class="btn icon-button24"
|
||||
title="Zoom Out"
|
||||
id="relation-map-zoom-out"
|
||||
style="background-image: url('/images/icons/zoom-out-24.png');"/>
|
||||
</div>
|
||||
|
||||
<div id="relation-map-canvas"></div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div id="children-overview"></div>
|
||||
|
||||
<div id="attribute-list">
|
||||
<button class="btn btn-sm show-attributes-button">Attributes:</button>
|
||||
|
||||
<span id="attribute-list-inner"></span>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="dropdown-menu dropdown-menu-sm context-menu" id="tree-context-menu">
|
||||
<a class="dropdown-item" href="#">Action</a>
|
||||
<a class="dropdown-item" href="#">Another action</a>
|
||||
<a class="dropdown-item" href="#">Something else here</a>
|
||||
</div>
|
||||
<% include details/detail.ejs %>
|
||||
|
||||
<% include dialogs/add_link.ejs %>
|
||||
<% include dialogs/attributes.ejs %>
|
||||
|
Loading…
x
Reference in New Issue
Block a user