2020-02-03 23:53:58 +05:00
|
|
|
import CachedCollection from "../database/cached-collection";
|
2020-02-03 12:03:07 +05:00
|
|
|
import fuzzysearch from "fuzzysearch";
|
|
|
|
|
import Tags from "./tags";
|
|
|
|
|
import { groupBy } from "../utils";
|
2020-02-03 23:53:58 +05:00
|
|
|
import sort from "fast-sort";
|
2020-02-03 12:03:07 +05:00
|
|
|
import {
|
|
|
|
|
getWeekGroupFromTimestamp,
|
|
|
|
|
months,
|
|
|
|
|
getLastWeekTimestamp
|
|
|
|
|
} from "../utils/date";
|
2020-02-03 23:53:58 +05:00
|
|
|
import Storage from "../database/storage";
|
2020-02-05 00:17:12 +05:00
|
|
|
import Notebooks from "./notebooks";
|
2020-02-05 20:57:43 +05:00
|
|
|
import Note from "../models/note";
|
2020-02-06 16:46:23 +05:00
|
|
|
import Trash from "./trash";
|
2020-02-03 12:03:07 +05:00
|
|
|
var tfun = require("transfun/transfun.js").tfun;
|
|
|
|
|
if (!tfun) {
|
|
|
|
|
tfun = global.tfun;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
export default class Notes {
|
|
|
|
|
constructor(context) {
|
2020-02-22 21:53:56 +05:00
|
|
|
this._collection = new CachedCollection(context, "notes");
|
|
|
|
|
this._deltaStorage = new Storage(context);
|
2020-02-03 12:03:07 +05:00
|
|
|
}
|
|
|
|
|
|
2020-02-05 00:17:12 +05:00
|
|
|
/**
|
|
|
|
|
*
|
|
|
|
|
* @param {Notebooks} notebooks
|
2020-02-06 16:46:23 +05:00
|
|
|
* @param {Trash} trash
|
2020-02-05 00:17:12 +05:00
|
|
|
*/
|
2020-02-21 22:06:13 +05:00
|
|
|
async init(notebooks, trash, tags, colors) {
|
2020-02-22 21:53:56 +05:00
|
|
|
await this._collection.init();
|
|
|
|
|
this._notebooks = notebooks;
|
|
|
|
|
this._trash = trash;
|
|
|
|
|
this._tagsCollection = tags;
|
|
|
|
|
this._colorsCollection = colors;
|
2020-02-03 12:03:07 +05:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
async add(noteArg) {
|
|
|
|
|
if (!noteArg) return;
|
|
|
|
|
|
2020-02-03 23:53:58 +05:00
|
|
|
let id = noteArg.id || Date.now().toString() + "_note";
|
2020-02-22 21:53:56 +05:00
|
|
|
let oldNote = this._collection.getItem(id);
|
2020-02-03 12:03:07 +05:00
|
|
|
let note = {
|
|
|
|
|
...oldNote,
|
|
|
|
|
...noteArg
|
|
|
|
|
};
|
|
|
|
|
|
|
|
|
|
if (isNoteEmpty(note)) {
|
|
|
|
|
if (oldNote) await this.delete(id);
|
|
|
|
|
return;
|
|
|
|
|
}
|
|
|
|
|
|
2020-02-20 11:28:16 +05:00
|
|
|
if (!(note.content.delta instanceof String)) {
|
2020-02-22 21:53:56 +05:00
|
|
|
await this._deltaStorage.write(id + "_delta", note.content.delta);
|
2020-02-20 11:28:16 +05:00
|
|
|
}
|
2020-02-03 23:53:58 +05:00
|
|
|
|
2020-02-03 12:03:07 +05:00
|
|
|
note = {
|
|
|
|
|
id,
|
|
|
|
|
type: "note",
|
|
|
|
|
title: getNoteTitle(note),
|
2020-02-03 23:53:58 +05:00
|
|
|
content: getNoteContent(note, id),
|
2020-02-03 12:03:07 +05:00
|
|
|
pinned: !!note.pinned,
|
|
|
|
|
locked: !!note.locked,
|
|
|
|
|
notebook: note.notebook || {},
|
|
|
|
|
colors: note.colors || [],
|
|
|
|
|
tags: note.tags || [],
|
|
|
|
|
favorite: !!note.favorite,
|
|
|
|
|
headline: getNoteHeadline(note),
|
2020-02-11 11:10:08 +05:00
|
|
|
dateCreated: note.dateCreated
|
2020-02-03 12:03:07 +05:00
|
|
|
};
|
|
|
|
|
|
2020-02-06 22:35:53 +05:00
|
|
|
if (!oldNote) {
|
|
|
|
|
for (let color of note.colors) {
|
2020-02-22 21:53:56 +05:00
|
|
|
await this._colorsCollection.add(color);
|
2020-02-06 22:35:53 +05:00
|
|
|
}
|
|
|
|
|
|
2020-02-03 12:03:07 +05:00
|
|
|
for (let tag of note.tags) {
|
2020-02-22 21:53:56 +05:00
|
|
|
await this._tagsCollection.add(tag);
|
2020-02-03 12:03:07 +05:00
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
2020-02-22 21:53:56 +05:00
|
|
|
await this._collection.addItem(note);
|
2020-02-03 23:53:58 +05:00
|
|
|
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) {
|
2020-02-22 21:53:56 +05:00
|
|
|
let note = this._collection.getItem(id);
|
2020-02-05 20:57:43 +05:00
|
|
|
if (!note) return undefined;
|
|
|
|
|
return new Note(this, note);
|
2020-02-03 12:03:07 +05:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
get all() {
|
2020-02-22 21:53:56 +05:00
|
|
|
return this._collection.getAllItems();
|
2020-02-03 12:03:07 +05:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
get pinned() {
|
|
|
|
|
return tfun.filter(".pinned === true")(this.all);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
get favorites() {
|
|
|
|
|
return tfun.filter(".favorite === true")(this.all);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
tagged(tag) {
|
|
|
|
|
return tfun.filter(`.tags.includes('${tag}')`)(this.all);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
colored(color) {
|
|
|
|
|
return tfun.filter(`.colors.includes('${color}')`)(this.all);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
filter(query) {
|
|
|
|
|
if (!query) return [];
|
2020-02-11 16:28:28 +05:00
|
|
|
let queryFn = v => fuzzysearch(query, v.title + " " + v.content.text);
|
|
|
|
|
if (query instanceof Function) queryFn = query;
|
2020-02-22 21:53:56 +05:00
|
|
|
return tfun.filter(queryFn)(this.all);
|
2020-02-03 12:03:07 +05:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
group(by, special = false) {
|
|
|
|
|
let notes = !special
|
|
|
|
|
? tfun.filter(".pinned === false")(this.all)
|
|
|
|
|
: this.all;
|
|
|
|
|
switch (by) {
|
|
|
|
|
case "abc":
|
|
|
|
|
return groupBy(
|
2020-02-03 23:53:58 +05:00
|
|
|
//notes.sort((a, b) => a.title.localeCompare(b.title)),
|
|
|
|
|
sort(notes).asc(t => t.title),
|
2020-02-03 12:03:07 +05:00
|
|
|
note => note.title[0].toUpperCase(),
|
|
|
|
|
special
|
|
|
|
|
);
|
|
|
|
|
case "month":
|
|
|
|
|
return groupBy(
|
|
|
|
|
notes,
|
|
|
|
|
note => months[new Date(note.dateCreated).getMonth()],
|
|
|
|
|
special
|
|
|
|
|
);
|
|
|
|
|
case "week":
|
|
|
|
|
return groupBy(
|
|
|
|
|
notes,
|
|
|
|
|
note => getWeekGroupFromTimestamp(note.dateCreated),
|
|
|
|
|
special
|
|
|
|
|
);
|
|
|
|
|
case "year":
|
|
|
|
|
return groupBy(
|
|
|
|
|
notes,
|
|
|
|
|
note => new Date(note.dateCreated).getFullYear().toString(),
|
|
|
|
|
special
|
|
|
|
|
);
|
|
|
|
|
default:
|
|
|
|
|
let timestamps = {
|
|
|
|
|
recent: getLastWeekTimestamp(7),
|
|
|
|
|
lastWeek: getLastWeekTimestamp(7) - 604800000 //seven day timestamp value
|
|
|
|
|
};
|
|
|
|
|
return groupBy(
|
|
|
|
|
notes,
|
|
|
|
|
note =>
|
|
|
|
|
note.dateCreated >= timestamps.recent
|
|
|
|
|
? "Recent"
|
|
|
|
|
: note.dateCreated >= timestamps.lastWeek
|
|
|
|
|
? "Last week"
|
|
|
|
|
: "Older",
|
|
|
|
|
special
|
|
|
|
|
);
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
async delete(...ids) {
|
|
|
|
|
for (let id of ids) {
|
2020-02-05 20:57:43 +05:00
|
|
|
let item = this.note(id);
|
|
|
|
|
if (!item) continue;
|
2020-02-05 01:12:36 +05:00
|
|
|
if (item.notebook && item.notebook.id && item.notebook.topic) {
|
2020-02-22 21:53:56 +05:00
|
|
|
await this._collection.transaction(() =>
|
|
|
|
|
this._notebooks
|
2020-02-05 20:57:43 +05:00
|
|
|
.notebook(item.notebook.id)
|
|
|
|
|
.topics.topic(item.notebook.topic)
|
2020-02-05 01:12:36 +05:00
|
|
|
.delete(id)
|
|
|
|
|
);
|
2020-02-03 12:03:07 +05:00
|
|
|
}
|
|
|
|
|
for (let tag of item.tags) {
|
2020-02-22 21:53:56 +05:00
|
|
|
await this._tagsCollection.remove(tag);
|
2020-02-03 12:03:07 +05:00
|
|
|
}
|
2020-02-22 21:53:56 +05:00
|
|
|
await this._collection.removeItem(id);
|
|
|
|
|
await this._trash.add(item.data);
|
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."
|
|
|
|
|
);
|
2020-02-22 21:53:56 +05:00
|
|
|
let topic = this._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.");
|
|
|
|
|
await topic.transaction(async () => {
|
2020-02-05 01:12:36 +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) {
|
|
|
|
|
return (
|
|
|
|
|
!note.content ||
|
|
|
|
|
!note.content.delta ||
|
|
|
|
|
(!note.locked &&
|
|
|
|
|
(!note.title || note.title.trim().length <= 0) &&
|
|
|
|
|
(!note.content.text || note.content.text.trim().length <= 0))
|
|
|
|
|
);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
function getNoteHeadline(note) {
|
|
|
|
|
if (note.locked) return "";
|
|
|
|
|
return (
|
|
|
|
|
note.content.text.substring(0, 150) +
|
|
|
|
|
(note.content.text.length > 150 ? "..." : "")
|
|
|
|
|
);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
function getNoteTitle(note) {
|
|
|
|
|
if (note.title && note.title.length > 0) return note.title.trim();
|
|
|
|
|
return note.content.text
|
|
|
|
|
.split(" ")
|
|
|
|
|
.slice(0, 3)
|
|
|
|
|
.join(" ")
|
|
|
|
|
.trim();
|
|
|
|
|
}
|
|
|
|
|
|
2020-02-03 23:53:58 +05:00
|
|
|
function getNoteContent(note, id) {
|
2020-02-03 12:03:07 +05:00
|
|
|
if (note.locked) {
|
|
|
|
|
return note.content;
|
|
|
|
|
}
|
2020-02-03 23:53:58 +05:00
|
|
|
|
2020-02-03 12:03:07 +05:00
|
|
|
return {
|
|
|
|
|
text: note.content.text.trim(),
|
2020-02-03 23:53:58 +05:00
|
|
|
delta: id + "_delta"
|
2020-02-03 12:03:07 +05:00
|
|
|
};
|
|
|
|
|
}
|