förälder
73118e30de
incheckning
4201def4ee
@ -0,0 +1,304 @@
|
||||
/*
|
||||
* This Source Code Form is subject to the terms of the Mozilla Public
|
||||
* License, v. 2.0. If a copy of the MPL was not distributed with this
|
||||
* file, You can obtain one at http://mozilla.org/MPL/2.0/.
|
||||
*/
|
||||
|
||||
class Note {
|
||||
|
||||
constructor(content, color, noteid) {
|
||||
if (typeof content != 'string') {
|
||||
content = "";
|
||||
}
|
||||
if (typeof color != 'string') {
|
||||
color = "FFF59D";
|
||||
}
|
||||
if (typeof noteid != 'number') {
|
||||
noteid = null;
|
||||
}
|
||||
this.noteid = noteid;
|
||||
this.color = color;
|
||||
this.content = content;
|
||||
this.title = "";
|
||||
this.modified = null;
|
||||
this.favorite = false;
|
||||
this.status = "NONE";
|
||||
}
|
||||
|
||||
static loadNote(noteid) {
|
||||
var notes = JSON.parse(localStorage.getItem("notes"));
|
||||
if (notes == null) {
|
||||
console.log("localStorage.notes is null");
|
||||
return null;
|
||||
}
|
||||
for (var n in notes) {
|
||||
if (notes[n].noteid == noteid) {
|
||||
var note = new Note(notes[n].content, notes[n].color, notes[n].noteid);
|
||||
note.setModified(notes[n].modified);
|
||||
note.setFavorite(notes[n].favorite == true);
|
||||
note.setSyncStatus(notes[n].syncstatus);
|
||||
note.setTitle();
|
||||
return note;
|
||||
}
|
||||
}
|
||||
return null;
|
||||
}
|
||||
|
||||
saveNote() {
|
||||
var noteid = this.getID();
|
||||
console.log("Saving note: ", this);
|
||||
var syncstatus = this.getSyncStatus();
|
||||
if (noteid == null) {
|
||||
noteid = Math.floor(Math.random() * (9999999999 - 1000000000) + 1000000000);
|
||||
syncstatus = "LOCAL_ONLY";
|
||||
}
|
||||
var jsonobj = {
|
||||
noteid: noteid,
|
||||
color: this.getColor(),
|
||||
content: this.getText(),
|
||||
modified: this.getModified(),
|
||||
favorite: this.getFavorite(),
|
||||
syncstatus: syncstatus
|
||||
};
|
||||
|
||||
var notes = JSON.parse(localStorage.getItem("notes"));
|
||||
if (notes == null) {
|
||||
console.log("localStorage.notes is null, using empty array");
|
||||
notes = [];
|
||||
}
|
||||
for (var n in notes) {
|
||||
if (notes[n].noteid == noteid) {
|
||||
if (notes[n].syncstatus == "LOCAL_DELETED") {
|
||||
// If this note was previously saved as deleted, don't save again
|
||||
return;
|
||||
}
|
||||
notes[n] = jsonobj;
|
||||
console.log(notes);
|
||||
localStorage.setItem("notes", JSON.stringify(notes));
|
||||
return;
|
||||
}
|
||||
}
|
||||
notes.push(jsonobj);
|
||||
console.log(notes);
|
||||
localStorage.setItem("notes", JSON.stringify(notes));
|
||||
}
|
||||
|
||||
/**
|
||||
* Save the note to NotePost.
|
||||
*/
|
||||
saveToNotePost(success, error, add) {
|
||||
var self = this;
|
||||
var data = {
|
||||
text: this.getText(),
|
||||
color: this.getColor(),
|
||||
modified: this.getModified(),
|
||||
favorite: this.getFavorite() ? "1" : "0",
|
||||
};
|
||||
|
||||
if (typeof add != 'boolean' || add != true) {
|
||||
data.id = this.getID();
|
||||
}
|
||||
|
||||
console.log("uploading: ", data);
|
||||
|
||||
return APICLIENT.post("savenote", data, function (val) {
|
||||
if (val.status == "OK") {
|
||||
self.noteid = val.note.noteid;
|
||||
self.setText(val.note.content);
|
||||
self.setColor(val.note.color);
|
||||
self.setModified(val.note.modified);
|
||||
self.setFavorite(val.note.favorite);
|
||||
self.setSyncStatus("SYNCED");
|
||||
if (typeof success == 'function') {
|
||||
success(self);
|
||||
}
|
||||
} else {
|
||||
if (typeof error == 'function') {
|
||||
error(val.msg);
|
||||
}
|
||||
}
|
||||
}, function () {
|
||||
if (typeof error == 'function') {
|
||||
error();
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
/**
|
||||
* Delete this note on the server.
|
||||
*/
|
||||
deleteOnNotePost(success, error) {
|
||||
var self = this;
|
||||
return APICLIENT.post("deletenote", {id: this.getID()}, function (val) {
|
||||
if (val.status == "OK") {
|
||||
if (typeof success == 'function') {
|
||||
success(self);
|
||||
}
|
||||
} else {
|
||||
if (typeof error == 'function') {
|
||||
error(val.msg);
|
||||
}
|
||||
}
|
||||
}, function () {
|
||||
if (typeof error == 'function') {
|
||||
error();
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
deleteme() {
|
||||
this.setSyncStatus("LOCAL_DELETED");
|
||||
this.saveNote();
|
||||
}
|
||||
|
||||
getSyncStatus() {
|
||||
return this.status;
|
||||
}
|
||||
|
||||
getID() {
|
||||
return this.noteid;
|
||||
}
|
||||
|
||||
getText() {
|
||||
return this.content;
|
||||
}
|
||||
|
||||
getHTML() {
|
||||
return marked(this.content);
|
||||
}
|
||||
|
||||
getColor() {
|
||||
this.setColor(this.color);
|
||||
return this.color;
|
||||
}
|
||||
|
||||
getTitle() {
|
||||
this.setTitle(this.title);
|
||||
return this.title;
|
||||
}
|
||||
|
||||
getModified() {
|
||||
return this.modified;
|
||||
}
|
||||
|
||||
getFavorite() {
|
||||
return this.favorite == true;
|
||||
}
|
||||
|
||||
getTextColor() {
|
||||
var color = this.getColor();
|
||||
var r = parseInt(color.substring(0, 2), 16);
|
||||
var g = parseInt(color.substring(2, 4), 16);
|
||||
var b = parseInt(color.substring(4, 6), 16);
|
||||
var contrast = Math.sqrt(r * r * 0.241 + g * g * 0.691 + b * b * 0.068);
|
||||
|
||||
if (contrast > 130) {
|
||||
return "000000";
|
||||
} else {
|
||||
return "FFFFFF";
|
||||
}
|
||||
}
|
||||
|
||||
setSyncStatus(status) {
|
||||
this.status = status;
|
||||
}
|
||||
|
||||
setText(markdown) {
|
||||
this.content = markdown;
|
||||
}
|
||||
|
||||
setColor(color) {
|
||||
if (typeof color !== 'string') {
|
||||
color = "FFF59D";
|
||||
}
|
||||
this.color = color;
|
||||
}
|
||||
|
||||
setTitle(title) {
|
||||
if (typeof title != 'string' || title.trim() == "") {
|
||||
if (typeof this.content != 'string' || this.content.trim() == "") {
|
||||
title = "New note";
|
||||
} else {
|
||||
title = this.content.split('\n')[0];
|
||||
title = title.replace(/[\*#_`]/, "");
|
||||
title = title.replace(/^- \[[x ]\] /i, "");
|
||||
}
|
||||
}
|
||||
this.title = title.trim();
|
||||
}
|
||||
|
||||
setModified(timestamp) {
|
||||
if (typeof timestamp == 'undefined' || timestamp == null) {
|
||||
this.setModified(Math.round(new Date().getTime() / 1000));
|
||||
} else {
|
||||
this.modified = timestamp;
|
||||
}
|
||||
}
|
||||
|
||||
setFavorite(favorite) {
|
||||
this.favorite = favorite == true;
|
||||
}
|
||||
|
||||
toChecklist() {
|
||||
var text = this.getText().split('\n');
|
||||
for (var i = 0; i < text.length; i++) {
|
||||
if (text[i].match(/^[^\s\=\#\-<](.+)/)) {
|
||||
if (text.length > i && text[i + 1].match(/^[\=-](.+)/)) {
|
||||
// Don't do it if the next line makes this one a heading
|
||||
continue;
|
||||
}
|
||||
text[i] = "- [ ] " + text[i];
|
||||
}
|
||||
}
|
||||
this.setText(text.join("\n"));
|
||||
}
|
||||
|
||||
fromChecklist() {
|
||||
var text = this.getText();
|
||||
this.setText(text.replace(/^- \[[ x]\] /im, ""));
|
||||
}
|
||||
|
||||
toggleChecklistItem(item) {
|
||||
item = item.trim();
|
||||
var text = this.getText().split("\n");
|
||||
var finalCheckState = false;
|
||||
for (var i in text) {
|
||||
var li = text[i].trim();
|
||||
if (!li.match(/^- \[[x ]\] .*/i)) {
|
||||
continue;
|
||||
}
|
||||
var linecleaned = li.replace(/^- \[[x ]\] /i, '').trim();
|
||||
if (item != linecleaned) {
|
||||
continue;
|
||||
}
|
||||
if (li.match(/^- \[[x]\] .*/i)) {
|
||||
text[i] = li.replace(/^- \[[x]\] /i, "- [ ] ");
|
||||
finalCheckState = false;
|
||||
} else if (li.match(/^- \[[ ]\] .*/i)) {
|
||||
text[i] = li.replace(/^- \[[ ]\] /i, "- [x] ");
|
||||
finalCheckState = true;
|
||||
}
|
||||
}
|
||||
this.setText(text.join("\n"));
|
||||
return finalCheckState;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns true if the notes appear to be the same to the user.
|
||||
* Does not check "hidden" attributes such as modified time.
|
||||
* @param {Note} othernote
|
||||
* @returns {boolean}
|
||||
*/
|
||||
compareTo(othernote) {
|
||||
if (this.getText() != othernote.getText()) {
|
||||
return false;
|
||||
}
|
||||
if (this.getFavorite() != othernote.getFavorite()) {
|
||||
return false;
|
||||
}
|
||||
if (this.getColor() != othernote.getColor()) {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
}
|
@ -0,0 +1,37 @@
|
||||
/*
|
||||
* This Source Code Form is subject to the terms of the Mozilla Public
|
||||
* License, v. 2.0. If a copy of the MPL was not distributed with this
|
||||
* file, You can obtain one at http://mozilla.org/MPL/2.0/.
|
||||
*/
|
||||
|
||||
|
||||
class NotePostAPI {
|
||||
constructor(server, username, password) {
|
||||
this.server = server;
|
||||
this.username = username;
|
||||
this.password = password;
|
||||
}
|
||||
|
||||
post(action, data, success, error) {
|
||||
var self = this;
|
||||
return $.ajax({
|
||||
url: this.server + "/api/" + action,
|
||||
dataType: "json",
|
||||
method: "POST",
|
||||
data: data,
|
||||
beforeSend: function (xhr) {
|
||||
xhr.setRequestHeader("Authorization", "Basic " + btoa(self.username + ":" + self.password));
|
||||
},
|
||||
success: function (val) {
|
||||
if (typeof success == 'function') {
|
||||
success(val);
|
||||
}
|
||||
},
|
||||
error: function () {
|
||||
if (typeof error == 'function') {
|
||||
error();
|
||||
}
|
||||
}
|
||||
});
|
||||
}
|
||||
}
|
@ -1,187 +0,0 @@
|
||||
/*
|
||||
* This Source Code Form is subject to the terms of the Mozilla Public
|
||||
* License, v. 2.0. If a copy of the MPL was not distributed with this
|
||||
* file, You can obtain one at http://mozilla.org/MPL/2.0/.
|
||||
*/
|
||||
class NotePostNotes extends Notes {
|
||||
constructor(server, username, password) {
|
||||
super();
|
||||
this.server = server;
|
||||
this.username = username;
|
||||
this.password = password;
|
||||
}
|
||||
|
||||
del(noteid, success, error) {
|
||||
super.del(noteid);
|
||||
var self = this;
|
||||
return $.ajax({
|
||||
url: this.server + "/api/deletenote",
|
||||
dataType: "json",
|
||||
cache: false,
|
||||
method: "POST",
|
||||
data: {
|
||||
id: noteid
|
||||
},
|
||||
beforeSend: function (xhr) {
|
||||
xhr.setRequestHeader("Authorization", "Basic " + btoa(self.username + ":" + self.password));
|
||||
},
|
||||
success: function (val) {
|
||||
if (val.status == "OK") {
|
||||
self.notes = val.notes;
|
||||
}
|
||||
|
||||
if (typeof success == 'function') {
|
||||
success();
|
||||
}
|
||||
},
|
||||
error: function () {
|
||||
if (typeof error == 'function') {
|
||||
error();
|
||||
}
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
add(note, success, error) {
|
||||
note.norealid = true;
|
||||
this.saveNote(note, success, error);
|
||||
}
|
||||
|
||||
getNote(noteid, success, error) {
|
||||
return $.ajax({
|
||||
url: this.server + "/api/getnote",
|
||||
dataType: "json",
|
||||
method: "POST",
|
||||
data: {
|
||||
id: noteid
|
||||
},
|
||||
beforeSend: function (xhr) {
|
||||
xhr.setRequestHeader("Authorization", "Basic " + btoa(self.username + ":" + self.password));
|
||||
},
|
||||
success: function (val) {
|
||||
if (val.status == "OK") {
|
||||
if (typeof success == 'function') {
|
||||
success(val.note);
|
||||
}
|
||||
} else {
|
||||
if (typeof error == 'function') {
|
||||
error(val.msg);
|
||||
}
|
||||
}
|
||||
},
|
||||
error: function () {
|
||||
if (typeof error == 'function') {
|
||||
error();
|
||||
}
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
saveNote(note, success, error) {
|
||||
var self = this;
|
||||
var data = {
|
||||
text: note.content,
|
||||
color: note.color,
|
||||
modified: note.modified,
|
||||
favorite: note.favorite ? "1" : "0"
|
||||
}; // Don't send ID if it's a locally-made note
|
||||
|
||||
if (note.norealid != true) {
|
||||
data.id = note.noteid;
|
||||
}
|
||||
|
||||
return $.ajax({
|
||||
url: this.server + "/api/savenote",
|
||||
dataType: "json",
|
||||
method: "POST",
|
||||
data: data,
|
||||
beforeSend: function (xhr) {
|
||||
xhr.setRequestHeader("Authorization", "Basic " + btoa(self.username + ":" + self.password));
|
||||
},
|
||||
success: function (val) {
|
||||
if (val.status == "OK") {
|
||||
if (typeof success == 'function') {
|
||||
success(val.note);
|
||||
}
|
||||
} else {
|
||||
if (typeof error == 'function') {
|
||||
error(val.msg);
|
||||
}
|
||||
}
|
||||
},
|
||||
error: function () {
|
||||
if (typeof error == 'function') {
|
||||
error();
|
||||
}
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
/**
|
||||
* Sync notes with the NotePost server, resolving conflicts in the process.
|
||||
*
|
||||
* @param {function} success(notes) called when everything's synced up.
|
||||
* @param {function} error
|
||||
* @returns {undefined}
|
||||
*/
|
||||
sync(success, error) {
|
||||
super.sync();
|
||||
var self = this;
|
||||
$.ajax({
|
||||
url: this.server + "/api/getnotes",
|
||||
dataType: "json",
|
||||
cache: false,
|
||||
method: "POST",
|
||||
beforeSend: function (xhr) {
|
||||
xhr.setRequestHeader("Authorization", "Basic " + btoa(self.username + ":" + self.password));
|
||||
},
|
||||
success: function (val) {
|
||||
if (val.status == "OK") {
|
||||
console.log("Comparing notes...");
|
||||
console.log("Local copy:", self.notes);
|
||||
console.log("Remote copy:", val.notes);
|
||||
var delta = getDelta(self.notes, val.notes);
|
||||
console.log("Comparison: ", delta);
|
||||
var notes = delta.noChange;
|
||||
notes = notes.concat(delta.addedRemote);
|
||||
notes = notes.concat(delta.changedRemote); // Sync locally-created or modified notes
|
||||
|
||||
var notesToUpload = delta.addedLocal;
|
||||
notesToUpload = notesToUpload.concat(delta.changedLocal);
|
||||
var addedOrChangedLocallyAjax = [];
|
||||
|
||||
for (var i = 0; i < notesToUpload.length; i++) {
|
||||
addedOrChangedLocallyAjax.push(self.saveNote(self.fix(notesToUpload[i]), function (n) {
|
||||
notes.push(n);
|
||||
}, function (err) {
|
||||
if (typeof err === "string") {
|
||||
app.dialog.alert(err, "Error");
|
||||
}
|
||||
}));
|
||||
}
|
||||
|
||||
$.when(addedOrChangedLocallyAjax).always(function () {
|
||||
self.notes = notes;
|
||||
self.fixAll();
|
||||
localStorage.setItem("notes", JSON.stringify(notes));
|
||||
console.log(JSON.parse(localStorage.getItem("notes")));
|
||||
}).then(function () {
|
||||
if (typeof success == 'function') {
|
||||
success(notes);
|
||||
}
|
||||
}, function () {
|
||||
if (typeof error == 'function') {
|
||||
error(notes);
|
||||
}
|
||||
});
|
||||
}
|
||||
},
|
||||
error: function () {
|
||||
if (typeof error == 'function') {
|
||||
error();
|
||||
}
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
}
|
@ -1,83 +0,0 @@
|
||||
/*
|
||||
* The code in this file is by StackOverflow user Juan Mendes.
|
||||
* License: Creative Commons Attribution-ShareAlike 3.0 Unported (CC BY-SA 3.0).
|
||||
* Source: https://stackoverflow.com/a/14966749
|
||||
*/
|
||||
|
||||
|
||||
/**
|
||||
* Creates a map out of an array be choosing what property to key by
|
||||
* @param {object[]} array Array that will be converted into a map
|
||||
* @param {string} prop Name of property to key by
|
||||
* @return {object} The mapped array. Example:
|
||||
* mapFromArray([{a:1,b:2}, {a:3,b:4}], 'a')
|
||||
* returns {1: {a:1,b:2}, 3: {a:3,b:4}}
|
||||
*/
|
||||
function mapFromArray(array, prop) {
|
||||
var map = {};
|
||||
for (var i = 0; i < array.length; i++) {
|
||||
map[ array[i][prop] ] = array[i];
|
||||
}
|
||||
return map;
|
||||
}
|
||||
|
||||
/**
|
||||
* @param {object[]} o old array of notes (local copy)
|
||||
* @param {object[]} n new array of notes (remote copy)
|
||||
* @param {object} An object with changes
|
||||
*/
|
||||
function getDelta(o, n) {
|
||||
var delta = {
|
||||
addedRemote: [],
|
||||
addedLocal: [],
|
||||
deletedRemote: [],
|
||||
deletedLocal: [],
|
||||
changedRemote: [],
|
||||
changedLocal: [],
|
||||
noChange: []
|
||||
};
|
||||
oSane = [];
|
||||
for (var i = 0; i < o.length; i++) {
|
||||
if (o[i].noteid == null) { // Note has no real `noteid`
|
||||
delta.addedLocal.push(o[i]);
|
||||
} else {
|
||||
oSane.push(o[i]);
|
||||
}
|
||||
}
|
||||
var local = mapFromArray(oSane, 'noteid');
|
||||
var remote = mapFromArray(n, 'noteid');
|
||||
|
||||
for (var id in local) {
|
||||
if (!remote.hasOwnProperty(id)) { // Notes that are only present locally
|
||||
delta.addedLocal.push(local[id]);
|
||||
// TODO: Figure out which notes were actually added locally and which were deleted on the server
|
||||
/*if (local[id].norealid) { // Note hasn't been synced to the remote yet
|
||||
delta.addedLocal.push(local[id]);
|
||||
} else { // Note has been synced to remote but isn't there anymore
|
||||
delta.deletedRemote.push(local[id]);
|
||||
}*/
|
||||
} else { // Notes that are present on both
|
||||
if (local[id].modified > remote[id].modified) { // Local copy is newer
|
||||
delta.changedLocal.push(local[id]);
|
||||
} else if (local[id].modified < remote[id].modified) { // Remote copy is newer
|
||||
delta.changedRemote.push(remote[id]);
|
||||
} else { // Modified date is same, let's check content
|
||||
if (local[id].content == remote[id].content) {
|
||||
delta.noChange.push(local[id]);
|
||||
} else if (local[id].content.length > remote[id].content.length) {
|
||||
delta.changedLocal.push(local[id]);
|
||||
} else {
|
||||
delta.changedRemote.push(remote[id]);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Add notes that are only on the remote
|
||||
for (var id in remote) {
|
||||
if (!local.hasOwnProperty(id)) {
|
||||
delta.addedRemote.push(remote[id]);
|
||||
}
|
||||
}
|
||||
return delta;
|
||||
}
|
@ -1,36 +0,0 @@
|
||||
/*
|
||||
* This Source Code Form is subject to the terms of the Mozilla Public
|
||||
* License, v. 2.0. If a copy of the MPL was not distributed with this
|
||||
* file, You can obtain one at http://mozilla.org/MPL/2.0/.
|
||||
*/
|
||||
|
||||
function createNotesObject(callback) {
|
||||
if (localStorage.getItem("serverurl") == null) {
|
||||
callback(new Notes());
|
||||
} else {
|
||||
var checkurl = localStorage.getItem("serverurl") + "/api/ping";
|
||||
$.ajax({
|
||||
url: checkurl,
|
||||
dataType: "json",
|
||||
cache: false,
|
||||
method: "POST",
|
||||
beforeSend: function (xhr) {
|
||||
xhr.setRequestHeader("Authorization", "Basic " + btoa(localStorage.getItem("username") + ":" + localStorage.getItem("password")));
|
||||
}, success: function (data) {
|
||||
if (data.status == "OK") {
|
||||
callback(new NotePostNotes(localStorage.getItem("serverurl"), localStorage.getItem("username"), localStorage.getItem("password")));
|
||||
} else if (data.status == "ERROR") {
|
||||
app.dialog.alert(data.msg, "Error");
|
||||
OFFLINE = true;
|
||||
callback(new Notes());
|
||||
} else {
|
||||
OFFLINE = true;
|
||||
callback(new Notes());
|
||||
}
|
||||
}, error: function () {
|
||||
OFFLINE = true;
|
||||
callback(new Notes());
|
||||
}
|
||||
});
|
||||
}
|
||||
}
|
Laddar…
Referens i nytt ärende