mirror of
https://github.com/zadam/trilium.git
synced 2025-03-01 14:22:32 +01:00
Merge branch 'master' into excalidraw
This commit is contained in:
commit
8df3b0a5bd
@ -0,0 +1,2 @@
|
|||||||
|
-- removing potential remnants of recent notes in entity changes, see https://github.com/zadam/trilium/issues/2842
|
||||||
|
DELETE FROM entity_changes WHERE entityName = 'recent_notes';
|
@ -266,7 +266,7 @@ class Note extends AbstractEntity {
|
|||||||
|
|
||||||
setContent(content, ignoreMissingProtectedSession = false) {
|
setContent(content, ignoreMissingProtectedSession = false) {
|
||||||
if (content === null || content === undefined) {
|
if (content === null || content === undefined) {
|
||||||
throw new Error(`Cannot set null content to note ${this.noteId}`);
|
throw new Error(`Cannot set null content to note '${this.noteId}'`);
|
||||||
}
|
}
|
||||||
|
|
||||||
if (this.isStringNote()) {
|
if (this.isStringNote()) {
|
||||||
@ -288,7 +288,7 @@ class Note extends AbstractEntity {
|
|||||||
pojo.content = protectedSessionService.encrypt(pojo.content);
|
pojo.content = protectedSessionService.encrypt(pojo.content);
|
||||||
}
|
}
|
||||||
else if (!ignoreMissingProtectedSession) {
|
else if (!ignoreMissingProtectedSession) {
|
||||||
throw new Error(`Cannot update content of noteId=${this.noteId} since we're out of protected session.`);
|
throw new Error(`Cannot update content of noteId '${this.noteId}' since we're out of protected session.`);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -1928,7 +1928,7 @@
|
|||||||
|
|
||||||
<dt class="tag-source">Source:</dt>
|
<dt class="tag-source">Source:</dt>
|
||||||
<dd class="tag-source"><ul class="dummy"><li>
|
<dd class="tag-source"><ul class="dummy"><li>
|
||||||
<a href="services_frontend_script_api.js.html">services/frontend_script_api.js</a>, <a href="services_frontend_script_api.js.html#line457">line 457</a>
|
<a href="services_frontend_script_api.js.html">services/frontend_script_api.js</a>, <a href="services_frontend_script_api.js.html#line484">line 484</a>
|
||||||
</li></ul></dd>
|
</li></ul></dd>
|
||||||
|
|
||||||
|
|
||||||
@ -2479,6 +2479,223 @@
|
|||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
<h4 class="name" id="getActiveNoteDetailWidget"><span class="type-signature"></span>getActiveNoteDetailWidget<span class="signature">()</span><span class="type-signature"> → {Promise.<NoteDetailWidget>}</span></h4>
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
<div class="description">
|
||||||
|
Get access to the widget handling note detail. Methods like `getWidgetType()` and `getTypeWidget()` to get to the
|
||||||
|
implementation of actual widget type.
|
||||||
|
</div>
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
<dl class="details">
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
<dt class="tag-source">Source:</dt>
|
||||||
|
<dd class="tag-source"><ul class="dummy"><li>
|
||||||
|
<a href="services_frontend_script_api.js.html">services/frontend_script_api.js</a>, <a href="services_frontend_script_api.js.html#line359">line 359</a>
|
||||||
|
</li></ul></dd>
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
</dl>
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
<h5>Returns:</h5>
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
<dl>
|
||||||
|
<dt>
|
||||||
|
Type
|
||||||
|
</dt>
|
||||||
|
<dd>
|
||||||
|
|
||||||
|
<span class="param-type">Promise.<NoteDetailWidget></span>
|
||||||
|
|
||||||
|
|
||||||
|
</dd>
|
||||||
|
</dl>
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
<h4 class="name" id="getActiveTabCodeEditor"><span class="type-signature"></span>getActiveTabCodeEditor<span class="signature">()</span><span class="type-signature"> → {Promise.<CodeMirror>}</span></h4>
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
<div class="description">
|
||||||
|
See https://codemirror.net/doc/manual.html#api
|
||||||
|
</div>
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
<dl class="details">
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
<dt class="tag-source">Source:</dt>
|
||||||
|
<dd class="tag-source"><ul class="dummy"><li>
|
||||||
|
<a href="services_frontend_script_api.js.html">services/frontend_script_api.js</a>, <a href="services_frontend_script_api.js.html#line350">line 350</a>
|
||||||
|
</li></ul></dd>
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
</dl>
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
<h5>Returns:</h5>
|
||||||
|
|
||||||
|
|
||||||
|
<div class="param-desc">
|
||||||
|
instance of CodeMirror
|
||||||
|
</div>
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
<dl>
|
||||||
|
<dt>
|
||||||
|
Type
|
||||||
|
</dt>
|
||||||
|
<dd>
|
||||||
|
|
||||||
|
<span class="param-type">Promise.<CodeMirror></span>
|
||||||
|
|
||||||
|
|
||||||
|
</dd>
|
||||||
|
</dl>
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
<h4 class="name" id="getActiveTabNote"><span class="type-signature"></span>getActiveTabNote<span class="signature">()</span><span class="type-signature"> → {<a href="NoteShort.html">NoteShort</a>}</span></h4>
|
<h4 class="name" id="getActiveTabNote"><span class="type-signature"></span>getActiveTabNote<span class="signature">()</span><span class="type-signature"> → {<a href="NoteShort.html">NoteShort</a>}</span></h4>
|
||||||
|
|
||||||
|
|
||||||
@ -2633,7 +2850,7 @@
|
|||||||
|
|
||||||
<dt class="tag-source">Source:</dt>
|
<dt class="tag-source">Source:</dt>
|
||||||
<dd class="tag-source"><ul class="dummy"><li>
|
<dd class="tag-source"><ul class="dummy"><li>
|
||||||
<a href="services_frontend_script_api.js.html">services/frontend_script_api.js</a>, <a href="services_frontend_script_api.js.html#line347">line 347</a>
|
<a href="services_frontend_script_api.js.html">services/frontend_script_api.js</a>, <a href="services_frontend_script_api.js.html#line365">line 365</a>
|
||||||
</li></ul></dd>
|
</li></ul></dd>
|
||||||
|
|
||||||
|
|
||||||
@ -2691,7 +2908,7 @@
|
|||||||
|
|
||||||
|
|
||||||
|
|
||||||
<h4 class="name" id="getActiveTabTextEditor"><span class="type-signature"></span>getActiveTabTextEditor<span class="signature">(callback)</span><span class="type-signature"></span></h4>
|
<h4 class="name" id="getActiveTabTextEditor"><span class="type-signature"></span>getActiveTabTextEditor<span class="signature">(callback<span class="signature-attributes">opt</span>)</span><span class="type-signature"> → {Promise.<CKEditor>}</span></h4>
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
@ -2723,6 +2940,8 @@
|
|||||||
<th>Type</th>
|
<th>Type</th>
|
||||||
|
|
||||||
|
|
||||||
|
<th>Attributes</th>
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
@ -2743,10 +2962,20 @@
|
|||||||
</td>
|
</td>
|
||||||
|
|
||||||
|
|
||||||
|
<td class="attributes">
|
||||||
|
|
||||||
|
<optional><br>
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
</td>
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
<td class="description last">method receiving "textEditor" instance</td>
|
<td class="description last">deprecated (use returned promise): callback receiving "textEditor" instance</td>
|
||||||
</tr>
|
</tr>
|
||||||
|
|
||||||
|
|
||||||
@ -2787,7 +3016,7 @@
|
|||||||
|
|
||||||
<dt class="tag-source">Source:</dt>
|
<dt class="tag-source">Source:</dt>
|
||||||
<dd class="tag-source"><ul class="dummy"><li>
|
<dd class="tag-source"><ul class="dummy"><li>
|
||||||
<a href="services_frontend_script_api.js.html">services/frontend_script_api.js</a>, <a href="services_frontend_script_api.js.html#line341">line 341</a>
|
<a href="services_frontend_script_api.js.html">services/frontend_script_api.js</a>, <a href="services_frontend_script_api.js.html#line342">line 342</a>
|
||||||
</li></ul></dd>
|
</li></ul></dd>
|
||||||
|
|
||||||
|
|
||||||
@ -2812,6 +3041,183 @@
|
|||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
<h5>Returns:</h5>
|
||||||
|
|
||||||
|
|
||||||
|
<div class="param-desc">
|
||||||
|
instance of CKEditor
|
||||||
|
</div>
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
<dl>
|
||||||
|
<dt>
|
||||||
|
Type
|
||||||
|
</dt>
|
||||||
|
<dd>
|
||||||
|
|
||||||
|
<span class="param-type">Promise.<CKEditor></span>
|
||||||
|
|
||||||
|
|
||||||
|
</dd>
|
||||||
|
</dl>
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
<h4 class="name" id="getComponentByEl"><span class="type-signature"></span>getComponentByEl<span class="signature">(el)</span><span class="type-signature"> → {Component}</span></h4>
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
<div class="description">
|
||||||
|
Returns component which owns given DOM element (the nearest parent component in DOM tree)
|
||||||
|
</div>
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
<h5>Parameters:</h5>
|
||||||
|
|
||||||
|
|
||||||
|
<table class="params">
|
||||||
|
<thead>
|
||||||
|
<tr>
|
||||||
|
|
||||||
|
<th>Name</th>
|
||||||
|
|
||||||
|
|
||||||
|
<th>Type</th>
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
<th class="last">Description</th>
|
||||||
|
</tr>
|
||||||
|
</thead>
|
||||||
|
|
||||||
|
<tbody>
|
||||||
|
|
||||||
|
|
||||||
|
<tr>
|
||||||
|
|
||||||
|
<td class="name"><code>el</code></td>
|
||||||
|
|
||||||
|
|
||||||
|
<td class="type">
|
||||||
|
|
||||||
|
|
||||||
|
<span class="param-type">Element</span>
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
</td>
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
<td class="description last">DOM element</td>
|
||||||
|
</tr>
|
||||||
|
|
||||||
|
|
||||||
|
</tbody>
|
||||||
|
</table>
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
<dl class="details">
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
<dt class="tag-source">Source:</dt>
|
||||||
|
<dd class="tag-source"><ul class="dummy"><li>
|
||||||
|
<a href="services_frontend_script_api.js.html">services/frontend_script_api.js</a>, <a href="services_frontend_script_api.js.html#line374">line 374</a>
|
||||||
|
</li></ul></dd>
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
</dl>
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
<h5>Returns:</h5>
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
<dl>
|
||||||
|
<dt>
|
||||||
|
Type
|
||||||
|
</dt>
|
||||||
|
<dd>
|
||||||
|
|
||||||
|
<span class="param-type">Component</span>
|
||||||
|
|
||||||
|
|
||||||
|
</dd>
|
||||||
|
</dl>
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
@ -2926,7 +3332,7 @@
|
|||||||
|
|
||||||
<dt class="tag-source">Source:</dt>
|
<dt class="tag-source">Source:</dt>
|
||||||
<dd class="tag-source"><ul class="dummy"><li>
|
<dd class="tag-source"><ul class="dummy"><li>
|
||||||
<a href="services_frontend_script_api.js.html">services/frontend_script_api.js</a>, <a href="services_frontend_script_api.js.html#line399">line 399</a>
|
<a href="services_frontend_script_api.js.html">services/frontend_script_api.js</a>, <a href="services_frontend_script_api.js.html#line426">line 426</a>
|
||||||
</li></ul></dd>
|
</li></ul></dd>
|
||||||
|
|
||||||
|
|
||||||
@ -3081,7 +3487,7 @@
|
|||||||
|
|
||||||
<dt class="tag-source">Source:</dt>
|
<dt class="tag-source">Source:</dt>
|
||||||
<dd class="tag-source"><ul class="dummy"><li>
|
<dd class="tag-source"><ul class="dummy"><li>
|
||||||
<a href="services_frontend_script_api.js.html">services/frontend_script_api.js</a>, <a href="services_frontend_script_api.js.html#line408">line 408</a>
|
<a href="services_frontend_script_api.js.html">services/frontend_script_api.js</a>, <a href="services_frontend_script_api.js.html#line435">line 435</a>
|
||||||
</li></ul></dd>
|
</li></ul></dd>
|
||||||
|
|
||||||
|
|
||||||
@ -3343,7 +3749,7 @@ if some action needs to happen on only one specific instance.
|
|||||||
|
|
||||||
<dt class="tag-source">Source:</dt>
|
<dt class="tag-source">Source:</dt>
|
||||||
<dd class="tag-source"><ul class="dummy"><li>
|
<dd class="tag-source"><ul class="dummy"><li>
|
||||||
<a href="services_frontend_script_api.js.html">services/frontend_script_api.js</a>, <a href="services_frontend_script_api.js.html#line426">line 426</a>
|
<a href="services_frontend_script_api.js.html">services/frontend_script_api.js</a>, <a href="services_frontend_script_api.js.html#line453">line 453</a>
|
||||||
</li></ul></dd>
|
</li></ul></dd>
|
||||||
|
|
||||||
|
|
||||||
@ -3806,7 +4212,7 @@ otherwise (by e.g. createNoteLink())
|
|||||||
|
|
||||||
<dt class="tag-source">Source:</dt>
|
<dt class="tag-source">Source:</dt>
|
||||||
<dd class="tag-source"><ul class="dummy"><li>
|
<dd class="tag-source"><ul class="dummy"><li>
|
||||||
<a href="services_frontend_script_api.js.html">services/frontend_script_api.js</a>, <a href="services_frontend_script_api.js.html#line389">line 389</a>
|
<a href="services_frontend_script_api.js.html">services/frontend_script_api.js</a>, <a href="services_frontend_script_api.js.html#line416">line 416</a>
|
||||||
</li></ul></dd>
|
</li></ul></dd>
|
||||||
|
|
||||||
|
|
||||||
@ -3961,7 +4367,7 @@ otherwise (by e.g. createNoteLink())
|
|||||||
|
|
||||||
<dt class="tag-source">Source:</dt>
|
<dt class="tag-source">Source:</dt>
|
||||||
<dd class="tag-source"><ul class="dummy"><li>
|
<dd class="tag-source"><ul class="dummy"><li>
|
||||||
<a href="services_frontend_script_api.js.html">services/frontend_script_api.js</a>, <a href="services_frontend_script_api.js.html#line417">line 417</a>
|
<a href="services_frontend_script_api.js.html">services/frontend_script_api.js</a>, <a href="services_frontend_script_api.js.html#line444">line 444</a>
|
||||||
</li></ul></dd>
|
</li></ul></dd>
|
||||||
|
|
||||||
|
|
||||||
@ -4116,7 +4522,7 @@ otherwise (by e.g. createNoteLink())
|
|||||||
|
|
||||||
<dt class="tag-source">Source:</dt>
|
<dt class="tag-source">Source:</dt>
|
||||||
<dd class="tag-source"><ul class="dummy"><li>
|
<dd class="tag-source"><ul class="dummy"><li>
|
||||||
<a href="services_frontend_script_api.js.html">services/frontend_script_api.js</a>, <a href="services_frontend_script_api.js.html#line435">line 435</a>
|
<a href="services_frontend_script_api.js.html">services/frontend_script_api.js</a>, <a href="services_frontend_script_api.js.html#line462">line 462</a>
|
||||||
</li></ul></dd>
|
</li></ul></dd>
|
||||||
|
|
||||||
|
|
||||||
@ -4553,7 +4959,7 @@ otherwise (by e.g. createNoteLink())
|
|||||||
|
|
||||||
<dt class="tag-source">Source:</dt>
|
<dt class="tag-source">Source:</dt>
|
||||||
<dd class="tag-source"><ul class="dummy"><li>
|
<dd class="tag-source"><ul class="dummy"><li>
|
||||||
<a href="services_frontend_script_api.js.html">services/frontend_script_api.js</a>, <a href="services_frontend_script_api.js.html#line359">line 359</a>
|
<a href="services_frontend_script_api.js.html">services/frontend_script_api.js</a>, <a href="services_frontend_script_api.js.html#line386">line 386</a>
|
||||||
</li></ul></dd>
|
</li></ul></dd>
|
||||||
|
|
||||||
|
|
||||||
@ -4709,7 +5115,7 @@ otherwise (by e.g. createNoteLink())
|
|||||||
|
|
||||||
<dt class="tag-source">Source:</dt>
|
<dt class="tag-source">Source:</dt>
|
||||||
<dd class="tag-source"><ul class="dummy"><li>
|
<dd class="tag-source"><ul class="dummy"><li>
|
||||||
<a href="services_frontend_script_api.js.html">services/frontend_script_api.js</a>, <a href="services_frontend_script_api.js.html#line370">line 370</a>
|
<a href="services_frontend_script_api.js.html">services/frontend_script_api.js</a>, <a href="services_frontend_script_api.js.html#line397">line 397</a>
|
||||||
</li></ul></dd>
|
</li></ul></dd>
|
||||||
|
|
||||||
|
|
||||||
@ -4865,7 +5271,7 @@ otherwise (by e.g. createNoteLink())
|
|||||||
|
|
||||||
<dt class="tag-source">Source:</dt>
|
<dt class="tag-source">Source:</dt>
|
||||||
<dd class="tag-source"><ul class="dummy"><li>
|
<dd class="tag-source"><ul class="dummy"><li>
|
||||||
<a href="services_frontend_script_api.js.html">services/frontend_script_api.js</a>, <a href="services_frontend_script_api.js.html#line379">line 379</a>
|
<a href="services_frontend_script_api.js.html">services/frontend_script_api.js</a>, <a href="services_frontend_script_api.js.html#line406">line 406</a>
|
||||||
</li></ul></dd>
|
</li></ul></dd>
|
||||||
|
|
||||||
|
|
||||||
@ -5002,7 +5408,7 @@ otherwise (by e.g. createNoteLink())
|
|||||||
|
|
||||||
<dt class="tag-source">Source:</dt>
|
<dt class="tag-source">Source:</dt>
|
||||||
<dd class="tag-source"><ul class="dummy"><li>
|
<dd class="tag-source"><ul class="dummy"><li>
|
||||||
<a href="services_frontend_script_api.js.html">services/frontend_script_api.js</a>, <a href="services_frontend_script_api.js.html#line484">line 484</a>
|
<a href="services_frontend_script_api.js.html">services/frontend_script_api.js</a>, <a href="services_frontend_script_api.js.html#line511">line 511</a>
|
||||||
</li></ul></dd>
|
</li></ul></dd>
|
||||||
|
|
||||||
|
|
||||||
@ -5156,7 +5562,7 @@ otherwise (by e.g. createNoteLink())
|
|||||||
|
|
||||||
<dt class="tag-source">Source:</dt>
|
<dt class="tag-source">Source:</dt>
|
||||||
<dd class="tag-source"><ul class="dummy"><li>
|
<dd class="tag-source"><ul class="dummy"><li>
|
||||||
<a href="services_frontend_script_api.js.html">services/frontend_script_api.js</a>, <a href="services_frontend_script_api.js.html#line475">line 475</a>
|
<a href="services_frontend_script_api.js.html">services/frontend_script_api.js</a>, <a href="services_frontend_script_api.js.html#line502">line 502</a>
|
||||||
</li></ul></dd>
|
</li></ul></dd>
|
||||||
|
|
||||||
|
|
||||||
@ -6097,7 +6503,7 @@ Internally this serializes the anonymous function into string and sends it to ba
|
|||||||
|
|
||||||
<dt class="tag-source">Source:</dt>
|
<dt class="tag-source">Source:</dt>
|
||||||
<dd class="tag-source"><ul class="dummy"><li>
|
<dd class="tag-source"><ul class="dummy"><li>
|
||||||
<a href="services_frontend_script_api.js.html">services/frontend_script_api.js</a>, <a href="services_frontend_script_api.js.html#line444">line 444</a>
|
<a href="services_frontend_script_api.js.html">services/frontend_script_api.js</a>, <a href="services_frontend_script_api.js.html#line471">line 471</a>
|
||||||
</li></ul></dd>
|
</li></ul></dd>
|
||||||
|
|
||||||
|
|
||||||
@ -6248,7 +6654,7 @@ Internally this serializes the anonymous function into string and sends it to ba
|
|||||||
|
|
||||||
<dt class="tag-source">Source:</dt>
|
<dt class="tag-source">Source:</dt>
|
||||||
<dd class="tag-source"><ul class="dummy"><li>
|
<dd class="tag-source"><ul class="dummy"><li>
|
||||||
<a href="services_frontend_script_api.js.html">services/frontend_script_api.js</a>, <a href="services_frontend_script_api.js.html#line353">line 353</a>
|
<a href="services_frontend_script_api.js.html">services/frontend_script_api.js</a>, <a href="services_frontend_script_api.js.html#line380">line 380</a>
|
||||||
</li></ul></dd>
|
</li></ul></dd>
|
||||||
|
|
||||||
|
|
||||||
@ -6614,7 +7020,7 @@ Typical use case is when new note has been created, we should wait until it is s
|
|||||||
|
|
||||||
<dt class="tag-source">Source:</dt>
|
<dt class="tag-source">Source:</dt>
|
||||||
<dd class="tag-source"><ul class="dummy"><li>
|
<dd class="tag-source"><ul class="dummy"><li>
|
||||||
<a href="services_frontend_script_api.js.html">services/frontend_script_api.js</a>, <a href="services_frontend_script_api.js.html#line468">line 468</a>
|
<a href="services_frontend_script_api.js.html">services/frontend_script_api.js</a>, <a href="services_frontend_script_api.js.html#line495">line 495</a>
|
||||||
</li></ul></dd>
|
</li></ul></dd>
|
||||||
|
|
||||||
|
|
||||||
|
@ -152,7 +152,7 @@ class NoteShort {
|
|||||||
return JSON.parse(content);
|
return JSON.parse(content);
|
||||||
}
|
}
|
||||||
catch (e) {
|
catch (e) {
|
||||||
console.log(`Cannot parse content of note ${this.noteId}: `, e.message);
|
console.log(`Cannot parse content of note '${this.noteId}': `, e.message);
|
||||||
|
|
||||||
return null;
|
return null;
|
||||||
}
|
}
|
||||||
|
@ -364,9 +364,27 @@ function FrontendScriptApi(startNote, currentNote, originEntity = null, $contain
|
|||||||
* See https://ckeditor.com/docs/ckeditor5/latest/api/module_core_editor_editor-Editor.html for a documentation on the returned instance.
|
* See https://ckeditor.com/docs/ckeditor5/latest/api/module_core_editor_editor-Editor.html for a documentation on the returned instance.
|
||||||
*
|
*
|
||||||
* @method
|
* @method
|
||||||
* @param callback - method receiving "textEditor" instance
|
* @param [callback] - deprecated (use returned promise): callback receiving "textEditor" instance
|
||||||
|
* @returns {Promise<CKEditor>} instance of CKEditor
|
||||||
*/
|
*/
|
||||||
this.getActiveTabTextEditor = callback => appContext.triggerCommand('executeInActiveEditor', {callback});
|
this.getActiveTabTextEditor = callback => new Promise(resolve => appContext.triggerCommand('executeInActiveTextEditor', {callback, resolve}));
|
||||||
|
|
||||||
|
/**
|
||||||
|
* See https://codemirror.net/doc/manual.html#api
|
||||||
|
*
|
||||||
|
* @method
|
||||||
|
* @returns {Promise<CodeMirror>} instance of CodeMirror
|
||||||
|
*/
|
||||||
|
this.getActiveTabCodeEditor = () => new Promise(resolve => appContext.triggerCommand('executeInActiveCodeEditor', {callback: resolve}));
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Get access to the widget handling note detail. Methods like `getWidgetType()` and `getTypeWidget()` to get to the
|
||||||
|
* implementation of actual widget type.
|
||||||
|
*
|
||||||
|
* @method
|
||||||
|
* @returns {Promise<NoteDetailWidget>}
|
||||||
|
*/
|
||||||
|
this.getActiveNoteDetailWidget = () => new Promise(resolve => appContext.triggerCommand('executeInActiveNoteDetailWidget', {callback: resolve}));
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @method
|
* @method
|
||||||
@ -374,6 +392,15 @@ function FrontendScriptApi(startNote, currentNote, originEntity = null, $contain
|
|||||||
*/
|
*/
|
||||||
this.getActiveTabNotePath = () => appContext.tabManager.getActiveContextNotePath();
|
this.getActiveTabNotePath = () => appContext.tabManager.getActiveContextNotePath();
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Returns component which owns given DOM element (the nearest parent component in DOM tree)
|
||||||
|
*
|
||||||
|
* @method
|
||||||
|
* @param {Element} el - DOM element
|
||||||
|
* @returns {Component}
|
||||||
|
*/
|
||||||
|
this.getComponentByEl = el => appContext.getComponentByEl(el);
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @method
|
* @method
|
||||||
* @param {object} $el - jquery object on which to setup the tooltip
|
* @param {object} $el - jquery object on which to setup the tooltip
|
||||||
|
20
package.json
20
package.json
@ -27,24 +27,24 @@
|
|||||||
"@excalidraw/excalidraw": "0.11.0",
|
"@excalidraw/excalidraw": "0.11.0",
|
||||||
"archiver": "5.3.1",
|
"archiver": "5.3.1",
|
||||||
"async-mutex": "0.3.2",
|
"async-mutex": "0.3.2",
|
||||||
"axios": "0.26.1",
|
"axios": "0.27.2",
|
||||||
"better-sqlite3": "7.4.5",
|
"better-sqlite3": "7.4.5",
|
||||||
"chokidar": "3.5.3",
|
"chokidar": "3.5.3",
|
||||||
"cls-hooked": "4.2.2",
|
"cls-hooked": "4.2.2",
|
||||||
"commonmark": "0.30.0",
|
"commonmark": "0.30.0",
|
||||||
"cookie-parser": "1.4.6",
|
"cookie-parser": "1.4.6",
|
||||||
"csurf": "1.11.0",
|
"csurf": "1.11.0",
|
||||||
"dayjs": "1.11.1",
|
"dayjs": "1.11.2",
|
||||||
"ejs": "3.1.6",
|
"ejs": "3.1.8",
|
||||||
"electron-debug": "3.2.0",
|
"electron-debug": "3.2.0",
|
||||||
"electron-dl": "3.3.1",
|
"electron-dl": "3.3.1",
|
||||||
"electron-find": "1.0.7",
|
"electron-find": "1.0.7",
|
||||||
"electron-window-state": "5.0.3",
|
"electron-window-state": "5.0.3",
|
||||||
"@electron/remote": "2.0.8",
|
"@electron/remote": "2.0.8",
|
||||||
"express": "4.17.3",
|
"express": "4.18.1",
|
||||||
"express-partial-content": "1.0.2",
|
"express-partial-content": "1.0.2",
|
||||||
"express-rate-limit": "6.3.0",
|
"express-rate-limit": "6.4.0",
|
||||||
"express-session": "1.17.2",
|
"express-session": "1.17.3",
|
||||||
"fs-extra": "10.1.0",
|
"fs-extra": "10.1.0",
|
||||||
"helmet": "5.0.2",
|
"helmet": "5.0.2",
|
||||||
"html": "1.0.0",
|
"html": "1.0.0",
|
||||||
@ -80,21 +80,21 @@
|
|||||||
"tmp": "0.2.1",
|
"tmp": "0.2.1",
|
||||||
"turndown": "7.1.1",
|
"turndown": "7.1.1",
|
||||||
"unescape": "1.0.1",
|
"unescape": "1.0.1",
|
||||||
"ws": "8.5.0",
|
"ws": "8.6.0",
|
||||||
"yauzl": "2.10.0"
|
"yauzl": "2.10.0"
|
||||||
},
|
},
|
||||||
"devDependencies": {
|
"devDependencies": {
|
||||||
"cross-env": "7.0.3",
|
"cross-env": "7.0.3",
|
||||||
"electron": "16.2.1",
|
"electron": "16.2.6",
|
||||||
"electron-builder": "23.0.3",
|
"electron-builder": "23.0.3",
|
||||||
"electron-packager": "15.5.0",
|
"electron-packager": "15.5.1",
|
||||||
"electron-rebuild": "3.2.7",
|
"electron-rebuild": "3.2.7",
|
||||||
"esm": "3.2.25",
|
"esm": "3.2.25",
|
||||||
"jasmine": "4.1.0",
|
"jasmine": "4.1.0",
|
||||||
"jsdoc": "3.6.10",
|
"jsdoc": "3.6.10",
|
||||||
"lorem-ipsum": "2.0.4",
|
"lorem-ipsum": "2.0.4",
|
||||||
"rcedit": "3.0.1",
|
"rcedit": "3.0.1",
|
||||||
"webpack": "5.72.0",
|
"webpack": "5.72.1",
|
||||||
"webpack-cli": "4.9.2"
|
"webpack-cli": "4.9.2"
|
||||||
},
|
},
|
||||||
"optionalDependencies": {
|
"optionalDependencies": {
|
||||||
|
@ -58,11 +58,8 @@ describe("Parser", () => {
|
|||||||
expect(subs[0].constructor.name).toEqual("NoteFlatTextExp");
|
expect(subs[0].constructor.name).toEqual("NoteFlatTextExp");
|
||||||
expect(subs[0].tokens).toEqual(["hello", "hi"]);
|
expect(subs[0].tokens).toEqual(["hello", "hi"]);
|
||||||
|
|
||||||
expect(subs[1].constructor.name).toEqual("NoteContentProtectedFulltextExp");
|
expect(subs[1].constructor.name).toEqual("NoteContentFulltextExp");
|
||||||
expect(subs[1].tokens).toEqual(["hello", "hi"]);
|
expect(subs[1].tokens).toEqual(["hello", "hi"]);
|
||||||
|
|
||||||
expect(subs[2].constructor.name).toEqual("NoteContentUnprotectedFulltextExp");
|
|
||||||
expect(subs[2].tokens).toEqual(["hello", "hi"]);
|
|
||||||
});
|
});
|
||||||
|
|
||||||
it("simple label comparison", () => {
|
it("simple label comparison", () => {
|
||||||
|
@ -16,7 +16,7 @@ async function convertMarkdownToHtml(text) {
|
|||||||
|
|
||||||
const result = writer.render(parsed);
|
const result = writer.render(parsed);
|
||||||
|
|
||||||
appContext.triggerCommand('executeInActiveEditor', {
|
appContext.triggerCommand('executeInActiveTextEditor', {
|
||||||
callback: textEditor => {
|
callback: textEditor => {
|
||||||
const viewFragment = textEditor.data.processor.toView(result);
|
const viewFragment = textEditor.data.processor.toView(result);
|
||||||
const modelFragment = textEditor.data.toModel(viewFragment);
|
const modelFragment = textEditor.data.toModel(viewFragment);
|
||||||
|
@ -336,9 +336,27 @@ function FrontendScriptApi(startNote, currentNote, originEntity = null, $contain
|
|||||||
* See https://ckeditor.com/docs/ckeditor5/latest/api/module_core_editor_editor-Editor.html for a documentation on the returned instance.
|
* See https://ckeditor.com/docs/ckeditor5/latest/api/module_core_editor_editor-Editor.html for a documentation on the returned instance.
|
||||||
*
|
*
|
||||||
* @method
|
* @method
|
||||||
* @param callback - method receiving "textEditor" instance
|
* @param [callback] - deprecated (use returned promise): callback receiving "textEditor" instance
|
||||||
|
* @returns {Promise<CKEditor>} instance of CKEditor
|
||||||
*/
|
*/
|
||||||
this.getActiveTabTextEditor = callback => appContext.triggerCommand('executeInActiveEditor', {callback});
|
this.getActiveTabTextEditor = callback => new Promise(resolve => appContext.triggerCommand('executeInActiveTextEditor', {callback, resolve}));
|
||||||
|
|
||||||
|
/**
|
||||||
|
* See https://codemirror.net/doc/manual.html#api
|
||||||
|
*
|
||||||
|
* @method
|
||||||
|
* @returns {Promise<CodeMirror>} instance of CodeMirror
|
||||||
|
*/
|
||||||
|
this.getActiveTabCodeEditor = () => new Promise(resolve => appContext.triggerCommand('executeInActiveCodeEditor', {callback: resolve}));
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Get access to the widget handling note detail. Methods like `getWidgetType()` and `getTypeWidget()` to get to the
|
||||||
|
* implementation of actual widget type.
|
||||||
|
*
|
||||||
|
* @method
|
||||||
|
* @returns {Promise<NoteDetailWidget>}
|
||||||
|
*/
|
||||||
|
this.getActiveNoteDetailWidget = () => new Promise(resolve => appContext.triggerCommand('executeInActiveNoteDetailWidget', {callback: resolve}));
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @method
|
* @method
|
||||||
@ -346,6 +364,15 @@ function FrontendScriptApi(startNote, currentNote, originEntity = null, $contain
|
|||||||
*/
|
*/
|
||||||
this.getActiveTabNotePath = () => appContext.tabManager.getActiveContextNotePath();
|
this.getActiveTabNotePath = () => appContext.tabManager.getActiveContextNotePath();
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Returns component which owns given DOM element (the nearest parent component in DOM tree)
|
||||||
|
*
|
||||||
|
* @method
|
||||||
|
* @param {Element} el - DOM element
|
||||||
|
* @returns {Component}
|
||||||
|
*/
|
||||||
|
this.getComponentByEl = el => appContext.getComponentByEl(el);
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @method
|
* @method
|
||||||
* @param {object} $el - jquery object on which to setup the tooltip
|
* @param {object} $el - jquery object on which to setup the tooltip
|
||||||
|
@ -307,6 +307,16 @@ export default class NoteDetailWidget extends NoteContextAwareWidget {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
async executeInActiveNoteDetailWidgetEvent({callback}) {
|
||||||
|
if (!this.isActiveNoteContext()) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
await this.initialized;
|
||||||
|
|
||||||
|
callback(this);
|
||||||
|
}
|
||||||
|
|
||||||
async cutIntoNoteCommand() {
|
async cutIntoNoteCommand() {
|
||||||
const note = appContext.tabManager.getActiveContextNote();
|
const note = appContext.tabManager.getActiveContextNote();
|
||||||
|
|
||||||
|
@ -170,4 +170,14 @@ export default class EditableCodeTypeWidget extends TypeWidget {
|
|||||||
});
|
});
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
async executeInActiveCodeEditorEvent({callback}) {
|
||||||
|
if (!this.isActive()) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
await this.initialized;
|
||||||
|
|
||||||
|
callback(this.codeEditor);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
@ -229,14 +229,18 @@ export default class EditableTextTypeWidget extends AbstractTextTypeWidget {
|
|||||||
return !selection.isCollapsed;
|
return !selection.isCollapsed;
|
||||||
}
|
}
|
||||||
|
|
||||||
async executeInActiveEditorEvent({callback}) {
|
async executeInActiveTextEditorEvent({callback, resolve}) {
|
||||||
if (!this.isActive()) {
|
if (!this.isActive()) {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
await this.initialized;
|
await this.initialized;
|
||||||
|
|
||||||
callback(this.textEditor);
|
if (callback) {
|
||||||
|
callback(this.textEditor);
|
||||||
|
}
|
||||||
|
|
||||||
|
resolve(this.textEditor);
|
||||||
}
|
}
|
||||||
|
|
||||||
addLinkToTextCommand() {
|
addLinkToTextCommand() {
|
||||||
|
@ -135,7 +135,6 @@ function fillAllEntityChanges() {
|
|||||||
fillEntityChanges("branches", "branchId");
|
fillEntityChanges("branches", "branchId");
|
||||||
fillEntityChanges("note_revisions", "noteRevisionId");
|
fillEntityChanges("note_revisions", "noteRevisionId");
|
||||||
fillEntityChanges("note_revision_contents", "noteRevisionId");
|
fillEntityChanges("note_revision_contents", "noteRevisionId");
|
||||||
fillEntityChanges("recent_notes", "noteId");
|
|
||||||
fillEntityChanges("attributes", "attributeId");
|
fillEntityChanges("attributes", "attributeId");
|
||||||
fillEntityChanges("etapi_tokens", "etapiTokenId");
|
fillEntityChanges("etapi_tokens", "etapiTokenId");
|
||||||
fillEntityChanges("options", "name", 'isSynced = 1');
|
fillEntityChanges("options", "name", 'isSynced = 1');
|
||||||
|
116
src/services/search/expressions/note_content_fulltext.js
Normal file
116
src/services/search/expressions/note_content_fulltext.js
Normal file
@ -0,0 +1,116 @@
|
|||||||
|
"use strict";
|
||||||
|
|
||||||
|
const Expression = require('./expression');
|
||||||
|
const NoteSet = require('../note_set');
|
||||||
|
const log = require('../../log');
|
||||||
|
const becca = require('../../../becca/becca');
|
||||||
|
const protectedSessionService = require('../../protected_session');
|
||||||
|
const striptags = require('striptags');
|
||||||
|
const utils = require("../../utils");
|
||||||
|
|
||||||
|
const ALLOWED_OPERATORS = ['*=*', '=', '*=', '=*', '%='];
|
||||||
|
|
||||||
|
const cachedRegexes = {};
|
||||||
|
|
||||||
|
function getRegex(str) {
|
||||||
|
if (!(str in cachedRegexes)) {
|
||||||
|
cachedRegexes[str] = new RegExp(str, 'ms'); // multiline, dot-all
|
||||||
|
}
|
||||||
|
|
||||||
|
return cachedRegexes[str];
|
||||||
|
}
|
||||||
|
|
||||||
|
class NoteContentFulltextExp extends Expression {
|
||||||
|
constructor(operator, {tokens, raw, flatText}) {
|
||||||
|
super();
|
||||||
|
|
||||||
|
if (!ALLOWED_OPERATORS.includes(operator)) {
|
||||||
|
throw new Error(`Note content can be searched only with operators: ` + ALLOWED_OPERATORS.join(", ") + `, operator ${operator} given.`);
|
||||||
|
}
|
||||||
|
|
||||||
|
this.operator = operator;
|
||||||
|
this.tokens = tokens;
|
||||||
|
this.raw = !!raw;
|
||||||
|
this.flatText = !!flatText;
|
||||||
|
}
|
||||||
|
|
||||||
|
execute(inputNoteSet) {
|
||||||
|
const resultNoteSet = new NoteSet();
|
||||||
|
const sql = require('../../sql');
|
||||||
|
|
||||||
|
for (let {noteId, type, mime, content, isProtected} of sql.iterateRows(`
|
||||||
|
SELECT noteId, type, mime, content, isProtected
|
||||||
|
FROM notes JOIN note_contents USING (noteId)
|
||||||
|
WHERE type IN ('text', 'code', 'mermaid') AND isDeleted = 0`)) {
|
||||||
|
|
||||||
|
if (!inputNoteSet.hasNoteId(noteId) || !(noteId in becca.notes)) {
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (isProtected) {
|
||||||
|
if (!protectedSessionService.isProtectedSessionAvailable()) {
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
|
try {
|
||||||
|
content = protectedSessionService.decryptString(content);
|
||||||
|
} catch (e) {
|
||||||
|
log.info(`Cannot decrypt content of note ${noteId}`);
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
content = this.preprocessContent(content, type, mime);
|
||||||
|
|
||||||
|
if (this.tokens.length === 1) {
|
||||||
|
const [token] = this.tokens;
|
||||||
|
|
||||||
|
if ((this.operator === '=' && token === content)
|
||||||
|
|| (this.operator === '*=' && content.endsWith(token))
|
||||||
|
|| (this.operator === '=*' && content.startsWith(token))
|
||||||
|
|| (this.operator === '*=*' && content.includes(token))
|
||||||
|
|| (this.operator === '%=' && getRegex(token).test(content))) {
|
||||||
|
|
||||||
|
resultNoteSet.add(becca.notes[noteId]);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
const nonMatchingToken = this.tokens.find(token =>
|
||||||
|
!content.includes(token) &&
|
||||||
|
(
|
||||||
|
// in case of default fulltext search we should consider both title, attrs and content
|
||||||
|
// so e.g. "hello world" should match when "hello" is in title and "world" in content
|
||||||
|
!this.flatText
|
||||||
|
|| !becca.notes[noteId].getFlatText().includes(token)
|
||||||
|
)
|
||||||
|
);
|
||||||
|
|
||||||
|
if (!nonMatchingToken) {
|
||||||
|
resultNoteSet.add(becca.notes[noteId]);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return resultNoteSet;
|
||||||
|
}
|
||||||
|
|
||||||
|
preprocessContent(content, type, mime) {
|
||||||
|
content = utils.normalize(content.toString());
|
||||||
|
|
||||||
|
if (type === 'text' && mime === 'text/html') {
|
||||||
|
if (!this.raw && content.length < 20000) { // striptags is slow for very large notes
|
||||||
|
// allow link to preserve URLs: https://github.com/zadam/trilium/issues/2412
|
||||||
|
content = striptags(content, ['a']);
|
||||||
|
|
||||||
|
// at least the closing tag can be easily stripped
|
||||||
|
content = content.replace(/<\/a>/ig, "");
|
||||||
|
}
|
||||||
|
|
||||||
|
content = content.replace(/ /g, ' ');
|
||||||
|
}
|
||||||
|
|
||||||
|
return content.trim();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
module.exports = NoteContentFulltextExp;
|
@ -1,89 +0,0 @@
|
|||||||
"use strict";
|
|
||||||
|
|
||||||
const Expression = require('./expression');
|
|
||||||
const NoteSet = require('../note_set');
|
|
||||||
const log = require('../../log');
|
|
||||||
const becca = require('../../../becca/becca');
|
|
||||||
const protectedSessionService = require('../../protected_session');
|
|
||||||
const striptags = require('striptags');
|
|
||||||
const utils = require("../../utils");
|
|
||||||
|
|
||||||
// FIXME: create common subclass with NoteContentUnprotectedFulltextExp to avoid duplication
|
|
||||||
class NoteContentProtectedFulltextExp extends Expression {
|
|
||||||
constructor(operator, {tokens, raw, flatText}) {
|
|
||||||
super();
|
|
||||||
|
|
||||||
if (operator !== '*=*') {
|
|
||||||
throw new Error(`Note content can be searched only with *=* operator`);
|
|
||||||
}
|
|
||||||
|
|
||||||
this.tokens = tokens;
|
|
||||||
this.raw = !!raw;
|
|
||||||
this.flatText = !!flatText;
|
|
||||||
}
|
|
||||||
|
|
||||||
execute(inputNoteSet) {
|
|
||||||
const resultNoteSet = new NoteSet();
|
|
||||||
|
|
||||||
if (!protectedSessionService.isProtectedSessionAvailable()) {
|
|
||||||
return resultNoteSet;
|
|
||||||
}
|
|
||||||
|
|
||||||
const sql = require('../../sql');
|
|
||||||
|
|
||||||
for (let {noteId, type, mime, content} of sql.iterateRows(`
|
|
||||||
SELECT noteId, type, mime, content
|
|
||||||
FROM notes JOIN note_contents USING (noteId)
|
|
||||||
WHERE type IN ('text', 'code', 'mermaid') AND isDeleted = 0 AND isProtected = 1`)) {
|
|
||||||
|
|
||||||
if (!inputNoteSet.hasNoteId(noteId) || !(noteId in becca.notes)) {
|
|
||||||
continue;
|
|
||||||
}
|
|
||||||
|
|
||||||
try {
|
|
||||||
content = protectedSessionService.decryptString(content);
|
|
||||||
}
|
|
||||||
catch (e) {
|
|
||||||
log.info(`Cannot decrypt content of note ${noteId}`);
|
|
||||||
continue;
|
|
||||||
}
|
|
||||||
|
|
||||||
content = this.preprocessContent(content, type, mime);
|
|
||||||
|
|
||||||
const nonMatchingToken = this.tokens.find(token =>
|
|
||||||
!content.includes(token) &&
|
|
||||||
(
|
|
||||||
// in case of default fulltext search we should consider both title, attrs and content
|
|
||||||
// so e.g. "hello world" should match when "hello" is in title and "world" in content
|
|
||||||
!this.flatText
|
|
||||||
|| !becca.notes[noteId].getFlatText().includes(token)
|
|
||||||
)
|
|
||||||
);
|
|
||||||
|
|
||||||
if (!nonMatchingToken) {
|
|
||||||
resultNoteSet.add(becca.notes[noteId]);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
return resultNoteSet;
|
|
||||||
}
|
|
||||||
|
|
||||||
preprocessContent(content, type, mime) {
|
|
||||||
content = utils.normalize(content.toString());
|
|
||||||
|
|
||||||
if (type === 'text' && mime === 'text/html') {
|
|
||||||
if (!this.raw && content.length < 20000) { // striptags is slow for very large notes
|
|
||||||
// allow link to preserve URLs: https://github.com/zadam/trilium/issues/2412
|
|
||||||
content = striptags(content, ['a']);
|
|
||||||
|
|
||||||
// at least the closing tag can be easily stripped
|
|
||||||
content = content.replace(/<\/a>/ig, "");
|
|
||||||
}
|
|
||||||
|
|
||||||
content = content.replace(/ /g, ' ');
|
|
||||||
}
|
|
||||||
return content;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
module.exports = NoteContentProtectedFulltextExp;
|
|
@ -1,75 +0,0 @@
|
|||||||
"use strict";
|
|
||||||
|
|
||||||
const Expression = require('./expression');
|
|
||||||
const NoteSet = require('../note_set');
|
|
||||||
const becca = require('../../../becca/becca');
|
|
||||||
const striptags = require('striptags');
|
|
||||||
const utils = require("../../utils");
|
|
||||||
|
|
||||||
// FIXME: create common subclass with NoteContentProtectedFulltextExp to avoid duplication
|
|
||||||
class NoteContentUnprotectedFulltextExp extends Expression {
|
|
||||||
constructor(operator, {tokens, raw, flatText}) {
|
|
||||||
super();
|
|
||||||
|
|
||||||
if (operator !== '*=*') {
|
|
||||||
throw new Error(`Note content can be searched only with *=* operator`);
|
|
||||||
}
|
|
||||||
|
|
||||||
this.tokens = tokens;
|
|
||||||
this.raw = !!raw;
|
|
||||||
this.flatText = !!flatText;
|
|
||||||
}
|
|
||||||
|
|
||||||
execute(inputNoteSet) {
|
|
||||||
const resultNoteSet = new NoteSet();
|
|
||||||
|
|
||||||
const sql = require('../../sql');
|
|
||||||
|
|
||||||
for (let {noteId, type, mime, content} of sql.iterateRows(`
|
|
||||||
SELECT noteId, type, mime, content
|
|
||||||
FROM notes JOIN note_contents USING (noteId)
|
|
||||||
WHERE type IN ('text', 'code', 'mermaid') AND isDeleted = 0 AND isProtected = 0`)) {
|
|
||||||
|
|
||||||
if (!inputNoteSet.hasNoteId(noteId) || !(noteId in becca.notes)) {
|
|
||||||
continue;
|
|
||||||
}
|
|
||||||
|
|
||||||
content = this.preprocessContent(content, type, mime);
|
|
||||||
|
|
||||||
const nonMatchingToken = this.tokens.find(token =>
|
|
||||||
!content.includes(token) &&
|
|
||||||
(
|
|
||||||
// in case of default fulltext search we should consider both title, attrs and content
|
|
||||||
// so e.g. "hello world" should match when "hello" is in title and "world" in content
|
|
||||||
!this.flatText
|
|
||||||
|| !becca.notes[noteId].getFlatText().includes(token)
|
|
||||||
)
|
|
||||||
);
|
|
||||||
|
|
||||||
if (!nonMatchingToken) {
|
|
||||||
resultNoteSet.add(becca.notes[noteId]);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
return resultNoteSet;
|
|
||||||
}
|
|
||||||
|
|
||||||
preprocessContent(content, type, mime) {
|
|
||||||
content = utils.normalize(content.toString());
|
|
||||||
|
|
||||||
if (type === 'text' && mime === 'text/html') {
|
|
||||||
if (!this.raw && content.length < 20000) { // striptags is slow for very large notes
|
|
||||||
// allow link to preserve URLs: https://github.com/zadam/trilium/issues/2412
|
|
||||||
content = striptags(content, ['a']);
|
|
||||||
|
|
||||||
// at least the closing tag can be easily stripped
|
|
||||||
content = content.replace(/<\/a>/ig, "");
|
|
||||||
}
|
|
||||||
|
|
||||||
content = content.replace(/ /g, ' ');
|
|
||||||
}
|
|
||||||
return content;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
module.exports = NoteContentUnprotectedFulltextExp;
|
|
@ -1,3 +1,13 @@
|
|||||||
|
const cachedRegexes = {};
|
||||||
|
|
||||||
|
function getRegex(str) {
|
||||||
|
if (!(str in cachedRegexes)) {
|
||||||
|
cachedRegexes[str] = new RegExp(str);
|
||||||
|
}
|
||||||
|
|
||||||
|
return cachedRegexes[str];
|
||||||
|
}
|
||||||
|
|
||||||
const stringComparators = {
|
const stringComparators = {
|
||||||
"=": comparedValue => (val => val === comparedValue),
|
"=": comparedValue => (val => val === comparedValue),
|
||||||
"!=": comparedValue => (val => val !== comparedValue),
|
"!=": comparedValue => (val => val !== comparedValue),
|
||||||
@ -8,6 +18,7 @@ const stringComparators = {
|
|||||||
"*=": comparedValue => (val => val && val.endsWith(comparedValue)),
|
"*=": comparedValue => (val => val && val.endsWith(comparedValue)),
|
||||||
"=*": comparedValue => (val => val && val.startsWith(comparedValue)),
|
"=*": comparedValue => (val => val && val.startsWith(comparedValue)),
|
||||||
"*=*": comparedValue => (val => val && val.includes(comparedValue)),
|
"*=*": comparedValue => (val => val && val.includes(comparedValue)),
|
||||||
|
"%=": comparedValue => (val => val && !!getRegex(comparedValue).test(val)),
|
||||||
};
|
};
|
||||||
|
|
||||||
const numericComparators = {
|
const numericComparators = {
|
||||||
|
@ -9,7 +9,7 @@ function lex(str) {
|
|||||||
let currentWord = '';
|
let currentWord = '';
|
||||||
|
|
||||||
function isSymbolAnOperator(chr) {
|
function isSymbolAnOperator(chr) {
|
||||||
return ['=', '*', '>', '<', '!', "-", "+"].includes(chr);
|
return ['=', '*', '>', '<', '!', "-", "+", '%'].includes(chr);
|
||||||
}
|
}
|
||||||
|
|
||||||
function isPreviousSymbolAnOperator() {
|
function isPreviousSymbolAnOperator() {
|
||||||
|
@ -12,8 +12,7 @@ const PropertyComparisonExp = require('../expressions/property_comparison');
|
|||||||
const AttributeExistsExp = require('../expressions/attribute_exists');
|
const AttributeExistsExp = require('../expressions/attribute_exists');
|
||||||
const LabelComparisonExp = require('../expressions/label_comparison');
|
const LabelComparisonExp = require('../expressions/label_comparison');
|
||||||
const NoteFlatTextExp = require('../expressions/note_flat_text');
|
const NoteFlatTextExp = require('../expressions/note_flat_text');
|
||||||
const NoteContentProtectedFulltextExp = require('../expressions/note_content_protected_fulltext');
|
const NoteContentFulltextExp = require('../expressions/note_content_fulltext.js');
|
||||||
const NoteContentUnprotectedFulltextExp = require('../expressions/note_content_unprotected_fulltext');
|
|
||||||
const OrderByAndLimitExp = require('../expressions/order_by_and_limit');
|
const OrderByAndLimitExp = require('../expressions/order_by_and_limit');
|
||||||
const AncestorExp = require("../expressions/ancestor");
|
const AncestorExp = require("../expressions/ancestor");
|
||||||
const buildComparator = require('./build_comparator');
|
const buildComparator = require('./build_comparator');
|
||||||
@ -32,8 +31,7 @@ function getFulltext(tokens, searchContext) {
|
|||||||
if (!searchContext.fastSearch) {
|
if (!searchContext.fastSearch) {
|
||||||
return new OrExp([
|
return new OrExp([
|
||||||
new NoteFlatTextExp(tokens),
|
new NoteFlatTextExp(tokens),
|
||||||
new NoteContentProtectedFulltextExp('*=*', {tokens, flatText: true}),
|
new NoteContentFulltextExp('*=*', {tokens, flatText: true})
|
||||||
new NoteContentUnprotectedFulltextExp('*=*', {tokens, flatText: true})
|
|
||||||
]);
|
]);
|
||||||
}
|
}
|
||||||
else {
|
else {
|
||||||
@ -42,7 +40,7 @@ function getFulltext(tokens, searchContext) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
function isOperator(str) {
|
function isOperator(str) {
|
||||||
return str.match(/^[!=<>*]+$/);
|
return str.match(/^[!=<>*%]+$/);
|
||||||
}
|
}
|
||||||
|
|
||||||
function getExpression(tokens, searchContext, level = 0) {
|
function getExpression(tokens, searchContext, level = 0) {
|
||||||
@ -140,10 +138,7 @@ function getExpression(tokens, searchContext, level = 0) {
|
|||||||
|
|
||||||
i++;
|
i++;
|
||||||
|
|
||||||
return new OrExp([
|
return new NoteContentFulltextExp(operator, {tokens: [tokens[i].token], raw });
|
||||||
new NoteContentUnprotectedFulltextExp(operator, {tokens: [tokens[i].token], raw }),
|
|
||||||
new NoteContentProtectedFulltextExp(operator, {tokens: [tokens[i].token], raw })
|
|
||||||
]);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
if (tokens[i].token === 'parents') {
|
if (tokens[i].token === 'parents') {
|
||||||
@ -196,8 +191,7 @@ function getExpression(tokens, searchContext, level = 0) {
|
|||||||
|
|
||||||
return new OrExp([
|
return new OrExp([
|
||||||
new PropertyComparisonExp(searchContext, 'title', '*=*', tokens[i].token),
|
new PropertyComparisonExp(searchContext, 'title', '*=*', tokens[i].token),
|
||||||
new NoteContentProtectedFulltextExp('*=*', {tokens: [tokens[i].token]}),
|
new NoteContentFulltextExp('*=*', {tokens: [tokens[i].token]})
|
||||||
new NoteContentUnprotectedFulltextExp('*=*', {tokens: [tokens[i].token]})
|
|
||||||
]);
|
]);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -13,9 +13,10 @@
|
|||||||
<excludeFolder url="file://$MODULE_DIR$/libraries" />
|
<excludeFolder url="file://$MODULE_DIR$/libraries" />
|
||||||
<excludeFolder url="file://$MODULE_DIR$/docs" />
|
<excludeFolder url="file://$MODULE_DIR$/docs" />
|
||||||
<excludeFolder url="file://$MODULE_DIR$/bin/better-sqlite3" />
|
<excludeFolder url="file://$MODULE_DIR$/bin/better-sqlite3" />
|
||||||
|
<excludeFolder url="file://$MODULE_DIR$/data" />
|
||||||
</content>
|
</content>
|
||||||
<orderEntry type="inheritedJdk" />
|
<orderEntry type="inheritedJdk" />
|
||||||
<orderEntry type="sourceFolder" forTests="false" />
|
<orderEntry type="sourceFolder" forTests="false" />
|
||||||
<orderEntry type="library" name="@types/jquery" level="application" />
|
<orderEntry type="library" name="@types/jquery" level="application" />
|
||||||
</component>
|
</component>
|
||||||
</module>
|
</module>
|
Loading…
x
Reference in New Issue
Block a user