This note has no content.
<% } else { %> <% - content = content.replace(/diff --git a/.gitignore b/.gitignore
index b2c4e3c464..54d5e67282 100644
--- a/.gitignore
+++ b/.gitignore
@@ -8,6 +8,7 @@ out-tsc
# dependencies
node_modules
+.pnpm-store
# IDEs and editors
/.idea
@@ -18,6 +19,7 @@ node_modules
*.launch
.settings/
*.sublime-workspace
+.devcontainer
# misc
/.sass-cache
diff --git a/README.md b/README.md
index be62b5370d..ad7e8b56d6 100644
--- a/README.md
+++ b/README.md
@@ -146,6 +146,21 @@ Here's the language coverage we have so far:
### Code
+General (OS / docker / podman, etc.) dependencies:
+
+Debian
+```
+apt update
+apt install -y build-essential python3 make g++ libsqlite3-dev
+corepack enable
+```
+
+Alpine
+```
+apk add --no-cache build-base python3 python3-dev sqlite-dev
+corepack enable
+```
+
Download the repository, install dependencies using `pnpm` and then run the server (available at http://localhost:8080):
```shell
git clone https://github.com/TriliumNext/Trilium.git
@@ -154,6 +169,10 @@ pnpm install
pnpm run server:start
```
+> If you faced with some problems, try to delete all `node_modules` and `.pnpm-store` folders, not only from the root, from every directory, like `apps/{app_name}/node_modules`and `/packages/{package_name}/node_modules` and then reinstall it by the `pnpm install`.
+
+Share styles not compiling by default, if you see share page without styles, make `pnpm run server:build` and then run development server.
+
### Documentation
Download the repository, install dependencies using `pnpm` and then run the environment required to edit the documentation:
diff --git a/apps/server/src/share/content_renderer.ts b/apps/server/src/share/content_renderer.ts
index 96e228cc04..819f7bbe63 100644
--- a/apps/server/src/share/content_renderer.ts
+++ b/apps/server/src/share/content_renderer.ts
@@ -40,15 +40,21 @@ interface Subroot {
type GetNoteFunction = (id: string) => SNote | BNote | null;
-function getSharedSubTreeRoot(note: SNote | BNote | undefined): Subroot {
+function addContentAccessQuery(note: SNote | BNote, secondEl?:boolean) {
+ if (!(note instanceof BNote) && note.contentAccessor && note.contentAccessor?.type === "query") {
+ return secondEl ? `&cat=${note.contentAccessor.getToken()}` : `?cat=${note.contentAccessor.getToken()}`;
+ }
+ return ""
+}
+
+export function getSharedSubTreeRoot(note: SNote | BNote | undefined, parentId: string | undefined = undefined): Subroot {
if (!note || note.noteId === shareRoot.SHARE_ROOT_NOTE_ID) {
// share root itself is not shared
return {};
}
- // every path leads to share root, but which one to choose?
- // for the sake of simplicity, URLs are not note paths
- const parentBranch = note.getParentBranches()[0];
+ const parentBranches = note.getParentBranches()
+ const parentBranch = (parentId ? parentBranches.find((pb: SBranch | BBranch) => pb.parentNoteId === parentId) : undefined) || parentBranches[0];
if (note instanceof BNote) {
return {
@@ -64,7 +70,7 @@ function getSharedSubTreeRoot(note: SNote | BNote | undefined): Subroot {
};
}
- return getSharedSubTreeRoot(parentBranch.getParentNote());
+ return getSharedSubTreeRoot(parentBranch.getParentNote(), parentId);
}
export function renderNoteForExport(note: BNote, parentBranch: BBranch, basePath: string, ancestors: string[]) {
@@ -91,7 +97,7 @@ export function renderNoteForExport(note: BNote, parentBranch: BBranch, basePath
}
export function renderNoteContent(note: SNote) {
- const subRoot = getSharedSubTreeRoot(note);
+ const subRoot = getSharedSubTreeRoot(note, note.parentId);
const ancestors: string[] = [];
let notePointer = note;
@@ -107,23 +113,23 @@ export function renderNoteContent(note: SNote) {
// Determine CSS to load.
const cssToLoad: string[] = [];
if (!note.isLabelTruthy("shareOmitDefaultCss")) {
- cssToLoad.push(`assets/styles.css`);
- cssToLoad.push(`assets/scripts.css`);
+ cssToLoad.push(`../assets/styles.css`);
+ cssToLoad.push(`../assets/scripts.css`);
}
for (const cssRelation of note.getRelations("shareCss")) {
- cssToLoad.push(`api/notes/${cssRelation.value}/download`);
+ cssToLoad.push(`../api/notes/${cssRelation.value}/download${addContentAccessQuery(note)}`);
}
// Determine JS to load.
const jsToLoad: string[] = [
- "assets/scripts.js"
+ "../assets/scripts.js"
];
for (const jsRelation of note.getRelations("shareJs")) {
- jsToLoad.push(`api/notes/${jsRelation.value}/download`);
+ jsToLoad.push(`../api/notes/${jsRelation.value}/download${addContentAccessQuery(note)}`);
}
const customLogoId = note.getRelation("shareLogo")?.value;
- const logoUrl = customLogoId ? `api/images/${customLogoId}/image.png` : `../${assetUrlFragment}/images/icon-color.svg`;
+ const logoUrl = customLogoId ? `../api/images/${customLogoId}/image.png${addContentAccessQuery(note)}` : `../../${assetUrlFragment}/images/icon-color.svg`;
return renderNoteContentInternal(note, {
subRoot,
@@ -133,7 +139,7 @@ export function renderNoteContent(note: SNote) {
logoUrl,
ancestors,
isStatic: false,
- faviconUrl: note.hasRelation("shareFavicon") ? `api/notes/${note.getRelationValue("shareFavicon")}/download` : `../favicon.ico`
+ faviconUrl: note.hasRelation("shareFavicon") ? `../api/notes/${note.getRelationValue("shareFavicon")}/download${addContentAccessQuery(note)}` : `../../favicon.ico`
});
}
@@ -158,6 +164,7 @@ function renderNoteContentInternal(note: SNote | BNote, renderArgs: RenderArgs)
isEmpty,
assetPath: shareAdjustedAssetPath,
assetUrlFragment,
+ addContentAccessQuery: (second: boolean | undefined) => addContentAccessQuery(note, second),
showLoginInShareTheme,
t,
isDev,
@@ -325,7 +332,7 @@ function renderText(result: Result, note: SNote | BNote) {
}
if (href?.startsWith("#")) {
- handleAttachmentLink(linkEl, href, getNote, getAttachment);
+ handleAttachmentLink(linkEl, href, getNote, getAttachment, note);
}
}
@@ -349,7 +356,7 @@ function renderText(result: Result, note: SNote | BNote) {
}
}
-function handleAttachmentLink(linkEl: HTMLElement, href: string, getNote: GetNoteFunction, getAttachment: (id: string) => BAttachment | SAttachment | null) {
+function handleAttachmentLink(linkEl: HTMLElement, href: string, getNote: GetNoteFunction, getAttachment: (id: string) => BAttachment | SAttachment | null, note: SNote | BNote) {
const linkRegExp = /attachmentId=([a-zA-Z0-9_]+)/g;
let attachmentMatch;
if ((attachmentMatch = linkRegExp.exec(href))) {
@@ -357,7 +364,7 @@ function handleAttachmentLink(linkEl: HTMLElement, href: string, getNote: GetNot
const attachment = getAttachment(attachmentId);
if (attachment) {
- linkEl.setAttribute("href", `api/attachments/${attachmentId}/download`);
+ linkEl.setAttribute("href", `../api/attachments/${attachmentId}/download${addContentAccessQuery(note)}`);
linkEl.classList.add(`attachment-link`);
linkEl.classList.add(`role-${attachment.role}`);
linkEl.childNodes.length = 0;
@@ -373,7 +380,7 @@ function handleAttachmentLink(linkEl: HTMLElement, href: string, getNote: GetNot
const linkedNote = getNote(noteId);
if (linkedNote) {
const isExternalLink = linkedNote.hasLabel("shareExternalLink");
- const href = isExternalLink ? linkedNote.getLabelValue("shareExternalLink") : `./${linkedNote.shareId}`;
+ const href = isExternalLink ? linkedNote.getLabelValue("shareExternalLink") : `../${linkedNote.shareId}`;
if (href) {
linkEl.setAttribute("href", href);
}
@@ -430,7 +437,7 @@ function renderMermaid(result: Result, note: SNote | BNote) {
}
result.content = `
-
+
| Attribute | Description |
|---|---|
#shareHiddenFromTree | this note is hidden from left navigation tree, but still accessible with its URL |
#shareExternalLink | note will act as a link to an external website in the share tree |
#shareAlias | define an alias using which the note will be available under https://your_trilium_host/share/[your_alias] |
#shareOmitDefaultCss | default share page CSS will be omitted. Use when you make extensive styling changes. |
#shareRoot | marks note which is served on /share root. |
#shareDescription | define text to be added to the HTML meta tag for description |
#shareRaw | Note will be served in its raw format, without HTML wrapper. See also Serving directly the content of a note for an alternative method without setting an attribute. |
#shareDisallowRobotIndexing | Indicates to web crawlers that the page should not be indexed of this note by:
|
#shareCredentials | require credentials to access this shared note. Value is expected to be in format username:password. Don't forget to make this inheritable to apply to child-notes/images. |
#shareIndex | Note with this label will list all roots of shared notes. |
#shareHtmlLocation | defines where custom HTML injected via ~shareHtml relation should be placed. Applied to the HTML snippet note itself. Format: location:position where location is head, body, or content and position is start or end. Defaults to content:end. |
| Attribute | Description |
|---|---|
#shareHiddenFromTree | this note is hidden from left navigation tree, but still accessible with its URL |
#shareTemplateNoPrevNext | hide bottom page navigation prev and next page. |
#shareTemplateNoLeftPanel | hide left panel fully. |
#shareExclude | this note will be excluded from share, not accessible via direct URL (implemented to hide scripts from share) |
#shareContentAccess | method for attachments authorization in case when note protected with login and password (#shareCredentials). Could be cookie (the cookie will be provided when page loads) / query (every url will be updated with token) / basic (only basic header authorization)). By default for browser used cookie. |
#shareAccessTokenTimeout | token expiration timeout in seconds, by default 10 minutes. While token not expired user could download attachment, after that he will get message `Access is expired. Return back and update the page.` |
#shareExternalLink | note will act as a link to an external website in the share tree |
#shareAlias | define an alias using which the note will be available under https://your_trilium_host/share/[your_alias] |
#shareOmitDefaultCss | default share page CSS will be omitted. Use when you make extensive styling changes. |
#shareRoot | marks note which is served on /share root. |
#shareDescription | define text to be added to the HTML meta tag for description |
#shareRaw | Note will be served in its raw format, without HTML wrapper. See also Serving directly the content of a note for an alternative method without setting an attribute. |
#shareDisallowRobotIndexing | Indicates to web crawlers that the page should not be indexed of this note by:
|
#shareCredentials | require credentials to access this shared note. Value is expected to be in format username:password. Don't forget to make this inheritable to apply to child-notes/images. |
#shareIndex | Note with this label will list all roots of shared notes. |
#shareHtmlLocation | defines where custom HTML injected via ~shareHtml relation should be placed. Applied to the HTML snippet note itself. Format: location:position where location is head, body, or content and position is start or end. Defaults to content:end. |