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

277 lines
6.9 KiB
JavaScript
Raw Normal View History

2020-03-21 11:15:24 +05:00
import { groupBy, isHex } from "../utils";
import Collection from "./collection";
2020-02-03 12:03:07 +05:00
import {
getWeekGroupFromTimestamp,
months,
getLastWeekTimestamp,
2020-04-04 13:29:33 +05:00
get7DayTimestamp,
2020-02-03 12:03:07 +05:00
} from "../utils/date";
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 { EV, EVENTS } from "../common";
import { getContentFromData } from "../content-types";
2020-12-07 11:19:36 +05:00
import qclone from "qclone/src/qclone";
2020-02-03 12:03:07 +05:00
var tfun = require("transfun/transfun.js").tfun;
if (!tfun) {
tfun = global.tfun;
}
export default class Notes extends Collection {
2020-02-03 12:03:07 +05:00
async add(noteArg) {
if (!noteArg) return;
2020-03-18 14:06:20 +05:00
let id = noteArg.id || getId();
let oldNote = this._collection.getItem(id);
2020-03-19 11:30:05 +05:00
2020-12-29 12:31:26 +05:00
if (noteArg.remote || noteArg.migrated) {
if (oldNote) {
if (oldNote.color !== noteArg.color) {
await this._db.colors.remove(oldNote.color, id);
}
if (oldNote.tags) {
for (let tag of oldNote.tags) {
await this._db.tags.remove(tag, id);
}
}
}
if (noteArg.color) {
await this._db.colors.add(noteArg.color, id);
}
if (noteArg.tags && noteArg.tags.length) {
2020-12-29 12:31:26 +05:00
for (let tag of noteArg.tags) {
await this._db.tags.add(tag, id);
}
}
return await this._collection.addItem(noteArg);
}
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
};
if (!oldNote && !noteArg.content && !noteArg.contentId) return;
2020-02-03 12:03:07 +05:00
if (noteArg.content && noteArg.content.data && noteArg.content.type) {
const { type, data, conflicted, resolved } = noteArg.content;
2020-03-21 11:15:24 +05:00
let content = getContentFromData(type, data);
if (!content) throw new Error("Invalid content type.");
note.title = getNoteTitle(note, content);
note.headline = getNoteHeadline(note, content);
2020-03-21 11:15:24 +05:00
if (isNoteEmpty(note, content)) {
if (oldNote) {
EV.publish(EVENTS.noteRemoved, id);
await this.remove(id);
}
return;
}
2020-03-19 11:30:05 +05:00
note.contentId = await this._db.content.add({
2020-03-19 12:38:33 +05:00
noteId: id,
id: note.contentId,
type,
data,
conflicted,
resolved,
2020-03-19 11:30:05 +05:00
});
2020-02-20 11:28:16 +05:00
}
2020-02-03 12:03:07 +05:00
note = {
id,
contentId: note.contentId,
2020-02-03 12:03:07 +05:00
type: "note",
2020-03-19 11:30:05 +05:00
title: note.title,
headline: note.headline,
2020-02-03 12:03:07 +05:00
pinned: !!note.pinned,
locked: !!note.locked,
notebooks: note.notebooks || undefined,
color: note.color,
2020-02-03 12:03:07 +05:00
tags: note.tags || [],
favorite: !!note.favorite,
2020-03-29 19:20:12 +05:00
dateCreated: note.dateCreated,
2020-04-04 13:29:33 +05:00
conflicted: !!note.conflicted,
2020-02-03 12:03:07 +05:00
};
if (!oldNote || oldNote.deleted) {
if (note.color) await this._db.colors.add(note.color, id);
2020-02-06 22:35:53 +05:00
2020-02-03 12:03:07 +05:00
for (let tag of note.tags) {
await this._db.tags.add(tag, id);
2020-02-03 12:03:07 +05:00
}
}
await this._collection.addItem(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 tfun.filter(".pinned === true")(this.all);
}
2020-04-04 13:29:33 +05:00
get conflicted() {
return tfun.filter(".conflicted === true")(this.all);
}
2020-02-03 12:03:07 +05:00
get favorites() {
return tfun.filter(".favorite === true")(this.all);
}
tagged(tagId) {
const tag = this._db.tags.tag(tagId);
if (!tag || tag.noteIds.length <= 0) return [];
return tag.noteIds.map((id) => this._collection.getItem(id));
2020-02-03 12:03:07 +05:00
}
2020-12-01 10:57:31 +05:00
colored(colorId) {
const color = this._db.colors.tag(colorId);
if (!color || color.noteIds.length <= 0) return [];
return color.noteIds.map((id) => this._collection.getItem(id));
2020-02-03 12:03:07 +05:00
}
2020-11-21 10:19:44 +05:00
/**
*
* @param {"abc"|"month"|"year"|"week"|undefined} by
* @param {"asc"|"desc"} sort
*/
group(by, sort = "desc") {
2021-01-11 12:23:12 +05:00
let notes = this.all;
2020-09-20 09:26:08 +05:00
2020-02-03 12:03:07 +05:00
switch (by) {
case "abc":
2020-09-20 09:26:08 +05:00
return groupBy(
notes,
(note) => note.title[0].toUpperCase(),
2020-11-21 10:19:44 +05:00
(t) => t.title[0],
sort
2020-09-20 09:26:08 +05:00
);
2020-02-03 12:03:07 +05:00
case "month":
return groupBy(
notes,
2020-09-20 09:26:08 +05:00
(note) => months[new Date(note.dateCreated).getMonth()],
2020-11-21 10:19:44 +05:00
(t) => t.dateCreated,
sort
2020-02-03 12:03:07 +05:00
);
case "week":
2020-09-20 09:26:08 +05:00
return groupBy(
notes,
(note) => getWeekGroupFromTimestamp(note.dateCreated),
2020-11-21 10:19:44 +05:00
(t) => t.dateCreated,
sort
2020-02-03 12:03:07 +05:00
);
case "year":
2020-09-20 09:26:08 +05:00
return groupBy(
notes,
(note) => new Date(note.dateCreated).getFullYear().toString(),
2020-11-21 10:19:44 +05:00
(t) => t.dateCreated,
sort
2020-02-03 12:03:07 +05:00
);
default:
let timestamps = {
recent: getLastWeekTimestamp(7),
2020-04-04 13:29:33 +05:00
lastWeek: getLastWeekTimestamp(7) - get7DayTimestamp(), //seven day timestamp value
2020-02-03 12:03:07 +05:00
};
2020-09-20 09:26:08 +05:00
return groupBy(
notes,
(note) =>
note.dateCreated >= timestamps.recent
? "Recent"
: note.dateCreated >= timestamps.lastWeek
? "Last week"
: "Older",
2020-11-21 10:19:44 +05:00
(t) => t.dateCreated,
sort
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);
2020-12-07 11:19:36 +05:00
if (item.notebooks) {
for (let notebook of item.notebooks) {
for (let topic of notebook.topics) {
await this._db.notebooks
.notebook(notebook.id)
.topics.topic(topic)
.delete(id);
}
}
2020-02-03 12:03:07 +05:00
}
for (let tag of item.tags) {
await this._db.tags.remove(tag, id);
2020-02-03 12:03:07 +05:00
}
if (item.data.color) {
await this._db.colors.remove(item.data.color, id);
}
2020-03-23 13:22:28 +05:00
await this._collection.removeItem(id);
2020-12-07 11:19:36 +05:00
if (moveToTrash) await this._db.trash.add(itemData);
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
}
2020-02-03 12:03:07 +05:00
}
function isNoteEmpty(note, content) {
const { title, locked } = note;
2020-03-09 09:45:54 +05:00
const isTitleEmpty = !title || !title.trim().length;
return !locked && isTitleEmpty && content.isEmpty();
}
function getNoteHeadline(note, content) {
2020-02-03 12:03:07 +05:00
if (note.locked) return "";
return content.toHeadline();
}
function getNoteTitle(note, content) {
2020-11-20 22:20:51 +05:00
if (note.title && note.title.trim().length > 0)
return note.title.replace(/\r?\n/g, " ");
return content.toTitle();
2020-02-03 12:03:07 +05:00
}