Optimize digest cycle by reloading state only upon explicit data change

This commit is contained in:
Mo Bitar
2019-01-30 17:00:16 -06:00
parent 4f42330167
commit 595ce94295
7 changed files with 103 additions and 78 deletions

View File

@@ -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;
};
});

View File

@@ -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;
}
});

View File

@@ -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;
};
});

View File

@@ -1,5 +0,0 @@
angular.module('app').filter('startFrom', function() {
return function(input, start) {
return input.slice(start);
};
});

View File

@@ -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() {