Files
notesnook/packages/core/collections/notes.js

284 lines
7.1 KiB
JavaScript
Raw Normal View History

import Collection from "./collection";
2020-02-05 20:57:43 +05:00
import Note from "../models/note";
2020-03-19 11:30:05 +05:00
import getId from "../utils/id";
import { getContentFromData } from "../content-types";
2020-12-07 11:19:36 +05:00
import qclone from "qclone/src/qclone";
import sort from "fast-sort";
import { deleteItem } from "../utils/array";
2020-02-03 12:03:07 +05:00
export default class Notes extends Collection {
2021-12-20 09:28:17 +05:00
async merge(remoteNote) {
if (!remoteNote) return;
if (remoteNote.deleted) return await this._collection.addItem(remoteNote);
2020-02-03 12:03:07 +05:00
2021-12-20 09:28:17 +05:00
const id = remoteNote.id;
const localNote = this._collection.getItem(id);
if (localNote) {
if (localNote.color) await this._db.colors.untag(localNote.color, id);
2020-03-19 11:30:05 +05:00
2021-12-20 09:28:17 +05:00
for (let tag of localNote.tags || []) {
await this._db.tags.untag(tag, id);
2020-12-29 12:31:26 +05:00
}
2021-12-20 09:28:17 +05:00
}
2020-12-29 12:31:26 +05:00
2021-12-20 09:28:17 +05:00
await this._resolveColorAndTags(remoteNote);
2020-12-29 12:31:26 +05:00
2021-12-20 09:28:17 +05:00
return await this._collection.addItem(remoteNote);
}
2021-12-20 09:28:17 +05:00
async add(noteArg) {
if (!noteArg) return;
if (noteArg.remote)
throw new Error("Please use db.notes.merge to merge remote notes.");
let id = noteArg.id || getId();
let oldNote = this._collection.getItem(id);
2020-12-29 12:31:26 +05:00
2020-02-03 12:03:07 +05:00
let note = {
...oldNote,
2020-04-04 13:29:33 +05:00
...noteArg,
2020-02-03 12:03:07 +05:00
};
2021-06-01 09:47:42 +05:00
if (oldNote) note.contentId = oldNote.contentId;
if (!oldNote && !noteArg.content && !noteArg.contentId) return;
2020-02-03 12:03:07 +05:00
if (noteArg.content && noteArg.content.data && noteArg.content.type) {
2021-12-20 14:37:06 +05:00
const { type, data, conflicted, dateEdited, dateResolved } =
noteArg.content;
2020-03-21 11:15:24 +05:00
let content = getContentFromData(type, data);
if (!content) throw new Error("Invalid content type.");
note.contentId = await this._db.content.add({
2020-03-19 12:38:33 +05:00
noteId: id,
sessionId: note.sessionId,
id: note.contentId,
type,
data,
localOnly: !!note.localOnly,
dateEdited,
dateResolved,
conflicted,
2020-03-19 11:30:05 +05:00
});
2021-12-20 14:37:06 +05:00
note.headline = getNoteHeadline(note, content);
note.dateEdited = Date.now();
2020-02-20 11:28:16 +05:00
}
2021-12-20 14:37:06 +05:00
const noteTitle = getNoteTitle(note, oldNote);
if (!oldNote || oldNote.title !== noteTitle) note.dateEdited = Date.now();
2020-02-03 12:03:07 +05:00
note = {
id,
contentId: note.contentId,
2020-02-03 12:03:07 +05:00
type: "note",
2021-12-20 14:37:06 +05:00
title: noteTitle,
headline: note.headline,
2021-12-20 14:37:06 +05:00
tags: note.tags || [],
notebooks: note.notebooks || undefined,
color: note.color,
2021-12-20 14:37:06 +05:00
pinned: !!note.pinned,
locked: !!note.locked,
2020-02-03 12:03:07 +05:00
favorite: !!note.favorite,
2021-04-06 09:13:06 +05:00
localOnly: !!note.localOnly,
conflicted: !!note.conflicted,
2021-12-20 14:37:06 +05:00
dateCreated: note.dateCreated,
dateEdited: note.dateEdited,
dateModified: note.dateModified,
2020-02-03 12:03:07 +05:00
};
2021-12-20 09:28:17 +05:00
await this.merge(note);
return note.id;
}
2020-02-06 22:46:57 +05:00
/**
*
* @param {string} id The id of note
* @returns {Note} The note of the given id
*/
2020-02-05 20:57:43 +05:00
note(id) {
if (!id) return;
let note = id.type ? id : this._collection.getItem(id);
2020-04-07 15:50:39 +05:00
if (!note || note.deleted) return;
2020-04-16 02:14:53 +05:00
return new Note(note, this._db);
2020-02-03 12:03:07 +05:00
}
2020-03-23 15:06:12 +05:00
get raw() {
return this._collection.getRaw();
}
2020-02-03 12:03:07 +05:00
get all() {
return this._collection.getItems();
2020-02-03 12:03:07 +05:00
}
get pinned() {
return this.all.filter((item) => item.pinned === true);
2020-02-03 12:03:07 +05:00
}
2020-04-04 13:29:33 +05:00
get conflicted() {
return this.all.filter((item) => item.conflicted === true);
2020-04-04 13:29:33 +05:00
}
2020-02-03 12:03:07 +05:00
get favorites() {
return this.all.filter((item) => item.favorite === true);
2020-02-03 12:03:07 +05:00
}
2021-02-16 16:56:06 +05:00
get deleted() {
return this.raw.filter((item) => item.dateDeleted > 0);
2021-02-16 16:56:06 +05:00
}
get locked() {
return this.all.filter((item) => item.locked === true);
}
tagged(tagId) {
return this._getTagItems(tagId, "tags");
2020-02-03 12:03:07 +05:00
}
2020-12-01 10:57:31 +05:00
colored(colorId) {
return this._getTagItems(colorId, "colors");
}
/**
* @private
*/
_getTagItems(tagId, collection) {
const tag = this._db[collection].tag(tagId);
if (!tag || tag.noteIds.length <= 0) return [];
const array = tag.noteIds.reduce((arr, id) => {
const item = this.note(id);
if (item) arr.push(item.data);
return arr;
}, []);
return sort(array).desc((note) => note.dateCreated);
2020-02-03 12:03:07 +05:00
}
2020-09-09 11:14:35 +05:00
delete(...ids) {
return this._delete(true, ...ids);
}
remove(...ids) {
return this._delete(false, ...ids);
}
/**
* @private
*/
async _delete(moveToTrash = true, ...ids) {
2020-02-03 12:03:07 +05:00
for (let id of ids) {
2020-02-05 20:57:43 +05:00
let item = this.note(id);
if (!item) continue;
const itemData = qclone(item.data);
2021-09-13 11:51:03 +05:00
if (itemData.notebooks) {
for (let notebook of itemData.notebooks) {
const notebookRef = this._db.notebooks.notebook(notebook.id);
if (!notebookRef) continue;
for (let topicId of notebook.topics) {
const topic = notebookRef.topics.topic(topicId);
if (!topic) continue;
await topic.delete(id);
2020-12-07 11:19:36 +05:00
}
}
2020-02-03 12:03:07 +05:00
}
2021-09-13 11:51:03 +05:00
for (let tag of itemData.tags) {
2021-07-12 10:32:35 +05:00
await this._db.tags.untag(tag, id);
2020-02-03 12:03:07 +05:00
}
2021-09-13 11:51:03 +05:00
if (itemData.color) {
await this._db.colors.untag(itemData.color, id);
}
2021-02-16 16:56:06 +05:00
// await this._collection.removeItem(id);
2020-12-07 11:19:36 +05:00
if (moveToTrash) await this._db.trash.add(itemData);
else {
await this._collection.removeItem(id);
await this._db.content.remove(itemData.contentId);
}
2020-02-03 12:03:07 +05:00
}
}
2020-02-05 00:17:12 +05:00
async move(to, ...noteIds) {
if (!to) throw new Error("The destination notebook cannot be undefined.");
if (!to.id || !to.topic)
throw new Error(
"The destination notebook must contain notebookId and topic."
);
let topic = this._db.notebooks.notebook(to.id).topics.topic(to.topic);
2020-02-05 00:17:12 +05:00
if (!topic) throw new Error("No such topic exists.");
2020-03-02 10:29:29 +05:00
await topic.add(...noteIds);
2020-02-05 00:17:12 +05:00
}
async repairReferences() {
const notes = this.all;
for (let note of notes) {
const { notebooks } = note;
if (!notebooks) continue;
for (let notebook of notebooks) {
const nb = this._db.notebooks.notebook(notebook.id);
if (nb) {
for (let topic of notebook.topics) {
const _topic = nb.topics.topic(topic);
if (!_topic || !_topic.has(note.id)) {
deleteItem(notebook.topics, topic);
await this.add(note);
continue;
}
}
}
if (!nb || !notebook.topics.length) {
deleteItem(notebooks, notebook);
await this.add(note);
continue;
}
}
}
}
2021-12-20 09:28:17 +05:00
async _resolveColorAndTags(note) {
const { color, tags, id } = note;
if (color) await this._db.colors.add(color, id);
if (tags && tags.length) {
for (let i = 0; i < tags.length; ++i) {
const tag = tags[i];
const addedTag = await this._db.tags.add(tag, id).catch(() => void 0);
if (!addedTag) {
tags.splice(i, 1);
continue;
}
if (addedTag.title !== tag) tags[i] = addedTag.title;
}
}
}
2020-02-03 12:03:07 +05:00
}
function getNoteHeadline(note, content) {
2020-02-03 12:03:07 +05:00
if (note.locked) return "";
return content.toHeadline();
}
2021-12-20 14:37:06 +05:00
const NEWLINE_STRIP_REGEX = /[\r\n\t\v]+/gm;
function getNoteTitle(note, oldNote) {
2021-12-20 14:37:06 +05:00
if (note.title && note.title.trim().length > 0) {
return note.title.replace(NEWLINE_STRIP_REGEX, " ");
} else if (oldNote && oldNote.title && oldNote.title.trim().length > 0) {
return oldNote.title.replace(NEWLINE_STRIP_REGEX, " ");
}
return `Note ${new Date().toLocaleString(undefined, {
2021-12-20 14:37:06 +05:00
dateStyle: "short",
timeStyle: "short",
})}`;
2020-02-03 12:03:07 +05:00
}