becca_entities_bbranch.js.html 10 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333
  1. <!DOCTYPE html>
  2. <html lang="en">
  3. <head>
  4. <meta charset="utf-8">
  5. <title>JSDoc: Source: becca/entities/bbranch.js</title>
  6. <script src="scripts/prettify/prettify.js"> </script>
  7. <script src="scripts/prettify/lang-css.js"> </script>
  8. <!--[if lt IE 9]>
  9. <script src="//html5shiv.googlecode.com/svn/trunk/html5.js"></script>
  10. <![endif]-->
  11. <link type="text/css" rel="stylesheet" href="styles/prettify-tomorrow.css">
  12. <link type="text/css" rel="stylesheet" href="styles/jsdoc-default.css">
  13. </head>
  14. <body>
  15. <div id="main">
  16. <h1 class="page-title">Source: becca/entities/bbranch.js</h1>
  17. <section>
  18. <article>
  19. <pre class="prettyprint source linenums"><code>"use strict";
  20. const BNote = require('./bnote');
  21. const AbstractBeccaEntity = require("./abstract_becca_entity");
  22. const dateUtils = require("../../services/date_utils");
  23. const utils = require("../../services/utils");
  24. const TaskContext = require("../../services/task_context");
  25. const cls = require("../../services/cls");
  26. const log = require("../../services/log");
  27. /**
  28. * Branch represents a relationship between a child note and its parent note. Trilium allows a note to have multiple
  29. * parents.
  30. *
  31. * Note that you should not rely on the branch's identity, since it can change easily with a note's move.
  32. * Always check noteId instead.
  33. *
  34. * @extends AbstractBeccaEntity
  35. */
  36. class BBranch extends AbstractBeccaEntity {
  37. static get entityName() { return "branches"; }
  38. static get primaryKeyName() { return "branchId"; }
  39. // notePosition is not part of hash because it would produce a lot of updates in case of reordering
  40. static get hashedProperties() { return ["branchId", "noteId", "parentNoteId", "prefix"]; }
  41. constructor(row) {
  42. super();
  43. if (!row) {
  44. return;
  45. }
  46. this.updateFromRow(row);
  47. this.init();
  48. }
  49. updateFromRow(row) {
  50. this.update([
  51. row.branchId,
  52. row.noteId,
  53. row.parentNoteId,
  54. row.prefix,
  55. row.notePosition,
  56. row.isExpanded,
  57. row.utcDateModified
  58. ]);
  59. }
  60. update([branchId, noteId, parentNoteId, prefix, notePosition, isExpanded, utcDateModified]) {
  61. /** @type {string} */
  62. this.branchId = branchId;
  63. /** @type {string} */
  64. this.noteId = noteId;
  65. /** @type {string} */
  66. this.parentNoteId = parentNoteId;
  67. /** @type {string|null} */
  68. this.prefix = prefix;
  69. /** @type {int} */
  70. this.notePosition = notePosition;
  71. /** @type {boolean} */
  72. this.isExpanded = !!isExpanded;
  73. /** @type {string} */
  74. this.utcDateModified = utcDateModified;
  75. return this;
  76. }
  77. init() {
  78. if (this.branchId) {
  79. this.becca.branches[this.branchId] = this;
  80. }
  81. this.becca.childParentToBranch[`${this.noteId}-${this.parentNoteId}`] = this;
  82. const childNote = this.childNote;
  83. if (!childNote.parentBranches.includes(this)) {
  84. childNote.parentBranches.push(this);
  85. }
  86. if (this.noteId === 'root') {
  87. return;
  88. }
  89. const parentNote = this.parentNote;
  90. if (!childNote.parents.includes(parentNote)) {
  91. childNote.parents.push(parentNote);
  92. }
  93. if (!parentNote.children.includes(childNote)) {
  94. parentNote.children.push(childNote);
  95. }
  96. }
  97. /** @returns {BNote} */
  98. get childNote() {
  99. if (!(this.noteId in this.becca.notes)) {
  100. // entities can come out of order in sync/import, create skeleton which will be filled later
  101. this.becca.addNote(this.noteId, new BNote({noteId: this.noteId}));
  102. }
  103. return this.becca.notes[this.noteId];
  104. }
  105. /** @returns {BNote} */
  106. getNote() {
  107. return this.childNote;
  108. }
  109. /** @returns {BNote|undefined} - root branch will have undefined parent, all other branches have to have a parent note */
  110. get parentNote() {
  111. if (!(this.parentNoteId in this.becca.notes) &amp;&amp; this.parentNoteId !== 'none') {
  112. // entities can come out of order in sync/import, create skeleton which will be filled later
  113. this.becca.addNote(this.parentNoteId, new BNote({noteId: this.parentNoteId}));
  114. }
  115. return this.becca.notes[this.parentNoteId];
  116. }
  117. get isDeleted() {
  118. return !(this.branchId in this.becca.branches);
  119. }
  120. /**
  121. * Branch is weak when its existence should not hinder deletion of its note.
  122. * As a result, note with only weak branches should be immediately deleted.
  123. * An example is shared or bookmarked clones - they are created automatically and exist for technical reasons,
  124. * not as user-intended actions. From user perspective, they don't count as real clones and for the purpose
  125. * of deletion should not act as a clone.
  126. *
  127. * @returns {boolean}
  128. */
  129. get isWeak() {
  130. return ['_share', '_lbBookmarks'].includes(this.parentNoteId);
  131. }
  132. /**
  133. * Delete a branch. If this is a last note's branch, delete the note as well.
  134. *
  135. * @param {string} [deleteId] - optional delete identified
  136. * @param {TaskContext} [taskContext]
  137. *
  138. * @returns {boolean} - true if note has been deleted, false otherwise
  139. */
  140. deleteBranch(deleteId, taskContext) {
  141. if (!deleteId) {
  142. deleteId = utils.randomString(10);
  143. }
  144. if (!taskContext) {
  145. taskContext = new TaskContext('no-progress-reporting');
  146. }
  147. taskContext.increaseProgressCount();
  148. const note = this.getNote();
  149. if (!taskContext.noteDeletionHandlerTriggered) {
  150. const parentBranches = note.getParentBranches();
  151. if (parentBranches.length === 1 &amp;&amp; parentBranches[0] === this) {
  152. // needs to be run before branches and attributes are deleted and thus attached relations disappear
  153. const handlers = require("../../services/handlers");
  154. handlers.runAttachedRelations(note, 'runOnNoteDeletion', note);
  155. }
  156. }
  157. if (this.noteId === 'root'
  158. || this.noteId === cls.getHoistedNoteId()) {
  159. throw new Error("Can't delete root or hoisted branch/note");
  160. }
  161. this.markAsDeleted(deleteId);
  162. const notDeletedBranches = note.getStrongParentBranches();
  163. if (notDeletedBranches.length === 0) {
  164. for (const weakBranch of note.getParentBranches()) {
  165. weakBranch.markAsDeleted(deleteId);
  166. }
  167. for (const childBranch of note.getChildBranches()) {
  168. childBranch.deleteBranch(deleteId, taskContext);
  169. }
  170. // first delete children and then parent - this will show up better in recent changes
  171. log.info(`Deleting note '${note.noteId}'`);
  172. this.becca.notes[note.noteId].isBeingDeleted = true;
  173. for (const attribute of note.getOwnedAttributes().slice()) {
  174. attribute.markAsDeleted(deleteId);
  175. }
  176. for (const relation of note.getTargetRelations()) {
  177. relation.markAsDeleted(deleteId);
  178. }
  179. for (const attachment of note.getAttachments()) {
  180. attachment.markAsDeleted(deleteId);
  181. }
  182. note.markAsDeleted(deleteId);
  183. return true;
  184. }
  185. else {
  186. return false;
  187. }
  188. }
  189. beforeSaving() {
  190. if (!this.noteId || !this.parentNoteId) {
  191. throw new Error(`noteId and parentNoteId are mandatory properties for Branch`);
  192. }
  193. this.branchId = `${this.parentNoteId}_${this.noteId}`;
  194. if (this.notePosition === undefined || this.notePosition === null) {
  195. let maxNotePos = 0;
  196. for (const childBranch of this.parentNote.getChildBranches()) {
  197. if (maxNotePos &lt; childBranch.notePosition
  198. &amp;&amp; childBranch.noteId !== '_hidden' // hidden has a very large notePosition to always stay last
  199. ) {
  200. maxNotePos = childBranch.notePosition;
  201. }
  202. }
  203. this.notePosition = maxNotePos + 10;
  204. }
  205. if (!this.isExpanded) {
  206. this.isExpanded = false;
  207. }
  208. if (!this.prefix?.trim()) {
  209. this.prefix = null;
  210. }
  211. this.utcDateModified = dateUtils.utcNowDateTime();
  212. super.beforeSaving();
  213. this.becca.branches[this.branchId] = this;
  214. }
  215. getPojo() {
  216. return {
  217. branchId: this.branchId,
  218. noteId: this.noteId,
  219. parentNoteId: this.parentNoteId,
  220. prefix: this.prefix,
  221. notePosition: this.notePosition,
  222. isExpanded: this.isExpanded,
  223. isDeleted: false,
  224. utcDateModified: this.utcDateModified
  225. };
  226. }
  227. createClone(parentNoteId, notePosition) {
  228. const existingBranch = this.becca.getBranchFromChildAndParent(this.noteId, parentNoteId);
  229. if (existingBranch) {
  230. existingBranch.notePosition = notePosition;
  231. return existingBranch;
  232. } else {
  233. return new BBranch({
  234. noteId: this.noteId,
  235. parentNoteId: parentNoteId,
  236. notePosition: notePosition,
  237. prefix: this.prefix,
  238. isExpanded: this.isExpanded
  239. });
  240. }
  241. }
  242. }
  243. module.exports = BBranch;
  244. </code></pre>
  245. </article>
  246. </section>
  247. </div>
  248. <nav>
  249. <h2><a href="index.html">Home</a></h2><h3>Modules</h3><ul><li><a href="module-sql.html">sql</a></li></ul><h3>Classes</h3><ul><li><a href="AbstractBeccaEntity.html">AbstractBeccaEntity</a></li><li><a href="BAttachment.html">BAttachment</a></li><li><a href="BAttribute.html">BAttribute</a></li><li><a href="BBranch.html">BBranch</a></li><li><a href="BEtapiToken.html">BEtapiToken</a></li><li><a href="BNote.html">BNote</a></li><li><a href="BOption.html">BOption</a></li><li><a href="BRecentNote.html">BRecentNote</a></li><li><a href="BRevision.html">BRevision</a></li><li><a href="BackendScriptApi.html">BackendScriptApi</a></li></ul><h3>Global</h3><ul><li><a href="global.html#api">api</a></li></ul>
  250. </nav>
  251. <br class="clear">
  252. <footer>
  253. Documentation generated by <a href="https://github.com/jsdoc/jsdoc">JSDoc 4.0.2</a>
  254. </footer>
  255. <script> prettyPrint(); </script>
  256. <script src="scripts/linenumber.js"> </script>
  257. </body>
  258. </html>