Optimize digest cycle by reloading state only upon explicit data change
This commit is contained in:
@@ -35,15 +35,19 @@ angular.module('app')
|
||||
syncManager.addEventHandler((syncEvent, data) => {
|
||||
if(syncEvent == "local-data-loaded") {
|
||||
this.localDataLoaded = true;
|
||||
if(this.tag && this.tag.notes.length == 0) {
|
||||
if(this.tag && this.notes.length == 0) {
|
||||
this.createNewNote();
|
||||
}
|
||||
}
|
||||
});
|
||||
|
||||
modelManager.addItemSyncObserver("note-list", "Note", (allItems, validItems, deletedItems, source, sourceKey) => {
|
||||
modelManager.addItemSyncObserver("note-list", "*", (allItems, validItems, deletedItems, source, sourceKey) => {
|
||||
// reload our notes
|
||||
this.setNotes(this.tag.notes);
|
||||
|
||||
// Note has changed values, reset its flags
|
||||
for(var note of allItems) {
|
||||
let notes = allItems.filter((item) => item.content_type == "Note");
|
||||
for(let note of notes) {
|
||||
note.flags = null;
|
||||
}
|
||||
|
||||
@@ -53,6 +57,14 @@ angular.module('app')
|
||||
}
|
||||
});
|
||||
|
||||
this.setNotes = function(notes) {
|
||||
this.notes = this.sortNotes(notes, this.sortBy, this.sortReverse);
|
||||
}
|
||||
|
||||
this.reorderNotes = function() {
|
||||
this.setNotes(this.notes);
|
||||
}
|
||||
|
||||
this.loadPreferences = function() {
|
||||
let prevSortValue = this.sortBy;
|
||||
|
||||
@@ -147,7 +159,7 @@ angular.module('app')
|
||||
|
||||
this.panelTitle = function() {
|
||||
if(this.isFiltering()) {
|
||||
return `${this.tag.notes.filter((i) => {return i.visible;}).length} search results`;
|
||||
return `${this.notes.filter((i) => {return i.visible;}).length} search results`;
|
||||
} else if(this.tag) {
|
||||
return `${this.tag.title}`;
|
||||
}
|
||||
@@ -245,16 +257,21 @@ angular.module('app')
|
||||
|
||||
this.noteFilter.text = "";
|
||||
|
||||
if(tag.notes.length > 0) {
|
||||
tag.notes.forEach((note) => { note.visible = true; })
|
||||
this.selectFirstNote();
|
||||
} else if(this.localDataLoaded) {
|
||||
this.createNewNote();
|
||||
}
|
||||
this.setNotes(tag.notes);
|
||||
|
||||
// perform in timeout since visibleNotes relies on renderedNotes which relies on render to complete
|
||||
$timeout(() => {
|
||||
if(this.notes.length > 0) {
|
||||
this.notes.forEach((note) => { note.visible = true; })
|
||||
this.selectFirstNote();
|
||||
} else if(this.localDataLoaded) {
|
||||
this.createNewNote();
|
||||
}
|
||||
})
|
||||
}
|
||||
|
||||
this.visibleNotes = function() {
|
||||
return this.sortedNotes.filter(function(note){
|
||||
return this.renderedNotes.filter(function(note){
|
||||
return note.visible;
|
||||
});
|
||||
}
|
||||
@@ -298,9 +315,9 @@ angular.module('app')
|
||||
}
|
||||
|
||||
this.createNewNote = function() {
|
||||
// The "Note X" counter is based off this.tag.notes.length, but sometimes, what you see in the list is only a subset.
|
||||
// The "Note X" counter is based off this.notes.length, but sometimes, what you see in the list is only a subset.
|
||||
// We can use this.visibleNotes().length, but that only accounts for non-paginated results, so first 15 or so.
|
||||
var title = "Note" + (this.tag.notes ? (" " + (this.tag.notes.length + 1)) : "");
|
||||
var title = "Note" + (this.notes ? (" " + (this.notes.length + 1)) : "");
|
||||
let newNote = modelManager.createItem({content_type: "Note", content: {text: "", title: title}});
|
||||
newNote.dummy = true;
|
||||
this.newNote = newNote;
|
||||
@@ -389,12 +406,14 @@ angular.module('app')
|
||||
this.toggleReverseSort = function() {
|
||||
this.selectedMenuItem();
|
||||
this.sortReverse = !this.sortReverse;
|
||||
this.reorderNotes();
|
||||
authManager.setUserPrefValue("sortReverse", this.sortReverse);
|
||||
authManager.syncUserPreferences();
|
||||
}
|
||||
|
||||
this.setSortBy = function(type) {
|
||||
this.sortBy = type;
|
||||
this.reorderNotes();
|
||||
authManager.setUserPrefValue("sortBy", this.sortBy);
|
||||
authManager.syncUserPreferences();
|
||||
}
|
||||
@@ -416,4 +435,50 @@ angular.module('app')
|
||||
return note.tags && note.tags.length > 1;
|
||||
}
|
||||
|
||||
this.sortNotes = function(items, sortBy, reverse) {
|
||||
let sortValueFn = (a, b, pinCheck = false) => {
|
||||
if(!pinCheck) {
|
||||
if(a.pinned && b.pinned) {
|
||||
return sortValueFn(a, b, true);
|
||||
}
|
||||
if(a.pinned) { return -1; }
|
||||
if(b.pinned) { return 1; }
|
||||
}
|
||||
|
||||
var aValue = a[sortBy] || "";
|
||||
var bValue = b[sortBy] || "";
|
||||
|
||||
let vector = 1;
|
||||
|
||||
if(reverse) {
|
||||
vector *= -1;
|
||||
}
|
||||
|
||||
if(sortBy == "title") {
|
||||
aValue = aValue.toLowerCase();
|
||||
bValue = bValue.toLowerCase();
|
||||
|
||||
if(aValue.length == 0 && bValue.length == 0) {
|
||||
return 0;
|
||||
} else if(aValue.length == 0 && bValue.length != 0) {
|
||||
return 1 * vector;
|
||||
} else if(aValue.length != 0 && bValue.length == 0) {
|
||||
return -1 * vector;
|
||||
} else {
|
||||
vector *= -1;
|
||||
}
|
||||
}
|
||||
|
||||
if(aValue > bValue) { return -1 * vector;}
|
||||
else if(aValue < bValue) { return 1 * vector;}
|
||||
return 0;
|
||||
}
|
||||
|
||||
items = items || [];
|
||||
var result = items.sort(function(a, b){
|
||||
return sortValueFn(a, b);
|
||||
})
|
||||
return result;
|
||||
};
|
||||
|
||||
});
|
||||
|
||||
@@ -33,6 +33,26 @@ angular.module('app')
|
||||
}
|
||||
});
|
||||
|
||||
modelManager.addItemSyncObserver("note-list", "*", (allItems, validItems, deletedItems, source, sourceKey) => {
|
||||
// recompute note counts
|
||||
let tags = [];
|
||||
if(this.tags) {
|
||||
tags = tags.concat(this.tags);
|
||||
}
|
||||
if(this.smartTags) {
|
||||
tags = tags.concat(this.smartTags);
|
||||
}
|
||||
|
||||
for(let tag of tags) {
|
||||
var validNotes = SNNote.filterDummyNotes(tag.notes).filter(function(note){
|
||||
return !note.archived && !note.content.trashed;
|
||||
});
|
||||
|
||||
tag.cachedNoteCount = validNotes.length;
|
||||
}
|
||||
});
|
||||
|
||||
|
||||
this.panelController = {};
|
||||
|
||||
$rootScope.$on("user-preferences-changed", () => {
|
||||
@@ -146,12 +166,4 @@ angular.module('app')
|
||||
this.removeTag()(tag);
|
||||
this.selectTag(this.smartTags[0]);
|
||||
}
|
||||
|
||||
this.noteCount = function(tag) {
|
||||
var validNotes = SNNote.filterDummyNotes(tag.notes).filter(function(note){
|
||||
return !note.archived && !note.content.trashed;
|
||||
});
|
||||
return validNotes.length;
|
||||
}
|
||||
|
||||
});
|
||||
|
||||
@@ -1,48 +0,0 @@
|
||||
angular.module('app')
|
||||
.filter('sortBy', function ($filter) {
|
||||
return function(items, sortBy, reverse) {
|
||||
let sortValueFn = (a, b, pinCheck = false) => {
|
||||
if(!pinCheck) {
|
||||
if(a.pinned && b.pinned) {
|
||||
return sortValueFn(a, b, true);
|
||||
}
|
||||
if(a.pinned) { return -1; }
|
||||
if(b.pinned) { return 1; }
|
||||
}
|
||||
|
||||
var aValue = a[sortBy] || "";
|
||||
var bValue = b[sortBy] || "";
|
||||
|
||||
let vector = 1;
|
||||
|
||||
if(reverse) {
|
||||
vector *= -1;
|
||||
}
|
||||
|
||||
if(sortBy == "title") {
|
||||
aValue = aValue.toLowerCase();
|
||||
bValue = bValue.toLowerCase();
|
||||
|
||||
if(aValue.length == 0 && bValue.length == 0) {
|
||||
return 0;
|
||||
} else if(aValue.length == 0 && bValue.length != 0) {
|
||||
return 1 * vector;
|
||||
} else if(aValue.length != 0 && bValue.length == 0) {
|
||||
return -1 * vector;
|
||||
} else {
|
||||
vector *= -1;
|
||||
}
|
||||
}
|
||||
|
||||
if(aValue > bValue) { return -1 * vector;}
|
||||
else if(aValue < bValue) { return 1 * vector;}
|
||||
return 0;
|
||||
}
|
||||
|
||||
items = items || [];
|
||||
var result = items.sort(function(a, b){
|
||||
return sortValueFn(a, b);
|
||||
})
|
||||
return result;
|
||||
};
|
||||
});
|
||||
@@ -1,5 +0,0 @@
|
||||
angular.module('app').filter('startFrom', function() {
|
||||
return function(input, start) {
|
||||
return input.slice(start);
|
||||
};
|
||||
});
|
||||
@@ -123,7 +123,8 @@ class ModelManager extends SFModelManager {
|
||||
let notTrashedPredicate = new SFPredicate("content.trashed", "=", false);
|
||||
predicates.push(notTrashedPredicate);
|
||||
}
|
||||
return this.itemsMatchingPredicates(predicates);
|
||||
let results = this.itemsMatchingPredicates(predicates);
|
||||
return results;
|
||||
}
|
||||
|
||||
trashSmartTag() {
|
||||
|
||||
@@ -45,7 +45,7 @@
|
||||
|
||||
.scrollable
|
||||
.infinite-scroll#notes-scrollable{"infinite-scroll" => "ctrl.paginate()", "can-load" => "true", "threshold" => "200"}
|
||||
.note{"ng-repeat" => "note in (ctrl.sortedNotes = (ctrl.tag.notes | filter: ctrl.filterNotes | sortBy: ctrl.sortBy:ctrl.sortReverse | limitTo:ctrl.notesToDisplay)) track by note.uuid",
|
||||
.note{"ng-repeat" => "note in (ctrl.renderedNotes = (ctrl.notes | filter: ctrl.filterNotes | limitTo:ctrl.notesToDisplay)) track by note.uuid",
|
||||
"ng-click" => "ctrl.selectNote(note, true)", "ng-class" => "{'selected' : ctrl.selectedNote == note}"}
|
||||
%strong.red.medium-text{"ng-if" => "note.conflict_of"} Conflicted copy
|
||||
%strong.red.medium-text{"ng-if" => "note.errorDecrypting"} Unable to Decrypt
|
||||
|
||||
@@ -17,7 +17,7 @@
|
||||
"ng-class" => "{'selected' : ctrl.selectedTag == tag, 'faded' : !tag.content.isAllTag}"}
|
||||
.info
|
||||
%input.title{"ng-disabled" => "true", "ng-model" => "tag.title"}
|
||||
.count{"ng-show" => "tag.content.isAllTag"} {{ctrl.noteCount(tag)}}
|
||||
.count{"ng-show" => "tag.content.isAllTag"} {{tag.cachedNoteCount}}
|
||||
|
||||
.tags-title-section.section-title-bar
|
||||
.section-title-bar-header
|
||||
@@ -28,7 +28,7 @@
|
||||
%input.title{"ng-attr-id" => "tag-{{tag.uuid}}", "ng-click" => "ctrl.selectTag(tag)", "ng-model" => "tag.title",
|
||||
"ng-keyup" => "$event.keyCode == 13 && $event.target.blur()", "sn-autofocus" => "true", "should-focus" => "ctrl.newTag || ctrl.editingTag == tag",
|
||||
"ng-change" => "ctrl.tagTitleDidChange(tag)", "ng-blur" => "ctrl.saveTag($event, tag)", "spellcheck" => "false"}
|
||||
.count {{ctrl.noteCount(tag)}}
|
||||
.count {{tag.cachedNoteCount}}
|
||||
|
||||
.red.small-text.bold{"ng-if" => "tag.conflict_of"} Conflicted copy
|
||||
.red.small-text.bold{"ng-if" => "tag.errorDecrypting"} Unable to Decrypt
|
||||
|
||||
Reference in New Issue
Block a user