Integrate SFJS model management

This commit is contained in:
Mo Bitar
2018-06-27 15:40:57 -05:00
parent 0e5f1f6478
commit e7ea390fd4
39 changed files with 3996 additions and 613 deletions

View File

@@ -64,7 +64,7 @@ angular.module('app')
return;
}
if(!ModelManager.isMappingSourceRetrieved(source)) {
if(!SFModelManager.isMappingSourceRetrieved(source)) {
return;
}
@@ -554,7 +554,7 @@ angular.module('app')
// Currently extensions are not notified of association until a full server sync completes.
// We need a better system for this, but for now, we'll manually notify observers
modelManager.notifySyncObserversOfModels([this.note], ModelManager.MappingSourceLocalSaved);
modelManager.notifySyncObserversOfModels([this.note], SFModelManager.MappingSourceLocalSaved);
}
}
@@ -564,7 +564,7 @@ angular.module('app')
// Currently extensions are not notified of association until a full server sync completes.
// We need a better system for this, but for now, we'll manually notify observers
modelManager.notifySyncObserversOfModels([this.note], ModelManager.MappingSourceLocalSaved);
modelManager.notifySyncObserversOfModels([this.note], SFModelManager.MappingSourceLocalSaved);
}
else if(action === "save-items" || action === "save-success" || action == "save-error") {

View File

@@ -87,7 +87,8 @@ angular.module('app')
}
function loadAllTag() {
var allTag = new Tag({all: true, title: "All"});
var allTag = new Tag({content: {title: "All"}});
allTag.all = true;
allTag.needsLoad = true;
$scope.allTag = allTag;
$scope.tags = modelManager.tags;
@@ -95,7 +96,8 @@ angular.module('app')
}
function loadArchivedTag() {
var archiveTag = new Tag({archiveTag: true, title: "Archived"});
var archiveTag = new Tag({content: {title: "Archived"}});
archiveTag.archiveTag = true;
$scope.archiveTag = archiveTag;
$scope.archiveTag.notes = modelManager.notes;
}
@@ -115,8 +117,6 @@ angular.module('app')
for(var tagToRemove of toRemove) {
note.removeItemAsRelationship(tagToRemove);
tagToRemove.removeItemAsRelationship(note);
tagToRemove.setDirty(true);
}
var tags = [];
@@ -128,7 +128,7 @@ angular.module('app')
}
for(var tag of tags) {
modelManager.createRelationshipBetweenItems(note, tag);
note.addItemAsRelationship(tag);
}
note.setDirty(true);
@@ -190,7 +190,8 @@ angular.module('app')
modelManager.addItem(note);
if(!$scope.selectedTag.all && !$scope.selectedTag.archiveTag) {
modelManager.createRelationshipBetweenItems($scope.selectedTag, note);
note.addItemAsRelationship($scope.selectedTag);
note.setDirty(true);
}
}

View File

@@ -217,8 +217,9 @@ angular.module('app')
this.createNewNote = function() {
var title = "New Note" + (this.tag.notes ? (" " + (this.tag.notes.length + 1)) : "");
this.newNote = modelManager.createItem({content_type: "Note", dummy: true, text: ""});
this.newNote.title = title;
let newNote = modelManager.createItem({content_type: "Note", content: {text: "", title: title}});
newNote.dummy = true;
this.newNote = newNote;
this.selectNote(this.newNote);
this.addNew()(this.newNote);
}

View File

@@ -244,7 +244,7 @@ class AccountMenu {
$scope.importJSONData = function(data, password, callback) {
var onDataReady = function(errorCount) {
var items = modelManager.mapResponseItemsToLocalModels(data.items, ModelManager.MappingSourceFileImport);
var items = modelManager.mapResponseItemsToLocalModels(data.items, SFModelManager.MappingSourceFileImport);
items.forEach(function(item){
item.setDirty(true, true);
item.deleted = false;

View File

@@ -1,314 +0,0 @@
let AppDomain = "org.standardnotes.sn";
var dateFormatter;
class Item {
constructor(json_obj = {}) {
this.appData = {};
this.updateFromJSON(json_obj);
this.observers = [];
if(!this.uuid) {
this.uuid = SFJS.crypto.generateUUIDSync();
}
}
static sortItemsByDate(items) {
items.sort(function(a,b){
return new Date(b.created_at) - new Date(a.created_at);
});
}
get contentObject() {
if(!this.content) {
return {};
}
if(this.content !== null && typeof this.content === 'object') {
// this is the case when mapping localStorage content, in which case the content is already parsed
return this.content;
}
try {
// console.log("Parsing json", this.content);
this.content = JSON.parse(this.content);
return this.content;
} catch (e) {
console.log("Error parsing json", e, this);
return {};
}
}
updateFromJSON(json) {
_.merge(this, json);
if(this.created_at) {
this.created_at = new Date(this.created_at);
this.updated_at = new Date(this.updated_at);
} else {
this.created_at = new Date();
this.updated_at = new Date();
}
// Allows the getter to be re-invoked
this._client_updated_at = null;
if(json.content) {
this.mapContentToLocalProperties(this.contentObject);
} else if(json.deleted == true) {
this.handleDeletedContent();
}
}
mapContentToLocalProperties(contentObj) {
if(contentObj.appData) {
this.appData = contentObj.appData;
}
if(!this.appData) { this.appData = {}; }
}
createContentJSONFromProperties() {
return this.structureParams();
}
referenceParams() {
// subclasses can override
return this.contentObject.references || [];
}
structureParams() {
var params = this.contentObject;
params.appData = this.appData;
params.references = this.referenceParams();
return params;
}
refreshContentObject() {
// Before an item can be duplicated or cloned, we must update this.content (if it is an object) with the object's
// current physical properties, because updateFromJSON, which is what all new items must go through,
// will call this.mapContentToLocalProperties(this.contentObject), which may have stale values if not explicitly updated.
this.content = this.structureParams();
}
/* Allows the item to handle the case where the item is deleted and the content is null */
handleDeletedContent() {
// Subclasses can override
}
setDirty(dirty, dontUpdateClientDate) {
this.dirty = dirty;
// Allows the syncManager to check if an item has been marked dirty after a sync has been started
// This prevents it from clearing it as a dirty item after sync completion, if someone else has marked it dirty
// again after an ongoing sync.
if(!this.dirtyCount) { this.dirtyCount = 0; }
if(dirty) {
this.dirtyCount++;
} else {
this.dirtyCount = 0;
}
if(dirty && !dontUpdateClientDate) {
// Set the client modified date to now if marking the item as dirty
this.client_updated_at = new Date();
} else if(!this.hasRawClientUpdatedAtValue()) {
// copy updated_at
this.client_updated_at = new Date(this.updated_at);
}
if(dirty) {
this.notifyObserversOfChange();
}
}
addObserver(observer, callback) {
if(!_.find(this.observers, observer)) {
this.observers.push({observer: observer, callback: callback});
}
}
removeObserver(observer) {
_.remove(this.observers, {observer: observer})
}
notifyObserversOfChange() {
for(var observer of this.observers) {
observer.callback(this);
}
}
addItemAsRelationship(item) {
// must override
}
removeItemAsRelationship(item) {
// must override
}
isBeingRemovedLocally() {
}
removeAndDirtyAllRelationships() {
// must override
this.setDirty(true);
}
removeReferencesNotPresentIn(references) {
}
mergeMetadataFromItem(item) {
_.merge(this, _.omit(item, ["content"]));
}
informReferencesOfUUIDChange(oldUUID, newUUID) {
// optional override
}
potentialItemOfInterestHasChangedItsUUID(newItem, oldUUID, newUUID) {
// optional override
for(var reference of this.content.references) {
if(reference.uuid == oldUUID) {
reference.uuid = newUUID;
}
}
}
doNotEncrypt() {
return false;
}
/*
App Data
*/
setDomainDataItem(key, value, domain) {
var data = this.appData[domain];
if(!data) {
data = {}
}
data[key] = value;
this.appData[domain] = data;
}
getDomainDataItem(key, domain) {
var data = this.appData[domain];
if(data) {
return data[key];
} else {
return null;
}
}
setAppDataItem(key, value) {
this.setDomainDataItem(key, value, AppDomain);
}
getAppDataItem(key) {
return this.getDomainDataItem(key, AppDomain);
}
get pinned() {
return this.getAppDataItem("pinned");
}
get archived() {
return this.getAppDataItem("archived");
}
get locked() {
return this.getAppDataItem("locked");
}
hasRawClientUpdatedAtValue() {
return this.getAppDataItem("client_updated_at") != null;
}
get client_updated_at() {
if(!this._client_updated_at) {
var saved = this.getAppDataItem("client_updated_at");
if(saved) {
this._client_updated_at = new Date(saved);
} else {
this._client_updated_at = new Date(this.updated_at);
}
}
return this._client_updated_at;
}
set client_updated_at(date) {
this._client_updated_at = date;
this.setAppDataItem("client_updated_at", date);
}
/*
During sync conflicts, when determing whether to create a duplicate for an item, we can omit keys that have no
meaningful weight and can be ignored. For example, if one component has active = true and another component has active = false,
it would be silly to duplicate them, so instead we ignore this.
*/
keysToIgnoreWhenCheckingContentEquality() {
return [];
}
// Same as above, but keys inside appData[AppDomain]
appDataKeysToIgnoreWhenCheckingContentEquality() {
return ["client_updated_at"];
}
isItemContentEqualWith(otherItem) {
let omit = (obj, keys) => {
for(var key of keys) {
delete obj[key];
}
return obj;
}
var left = this.structureParams();
left.appData[AppDomain] = omit(left.appData[AppDomain], this.appDataKeysToIgnoreWhenCheckingContentEquality());
left = omit(left, this.keysToIgnoreWhenCheckingContentEquality());
var right = otherItem.structureParams();
right.appData[AppDomain] = omit(right.appData[AppDomain], otherItem.appDataKeysToIgnoreWhenCheckingContentEquality());
right = omit(right, otherItem.keysToIgnoreWhenCheckingContentEquality());
return JSON.stringify(left) === JSON.stringify(right)
}
/*
Dates
*/
createdAtString() {
return this.dateToLocalizedString(this.created_at);
}
updatedAtString() {
return this.dateToLocalizedString(this.client_updated_at);
}
dateToLocalizedString(date) {
if (typeof Intl !== 'undefined' && Intl.DateTimeFormat) {
if (!dateFormatter) {
var locale = (navigator.languages && navigator.languages.length) ? navigator.languages[0] : navigator.language;
dateFormatter = new Intl.DateTimeFormat(locale, {
year: 'numeric',
month: 'short',
day: '2-digit',
weekday: 'long',
hour: '2-digit',
minute: '2-digit',
});
}
return dateFormatter.format(date);
} else {
// IE < 11, Safari <= 9.0.
// In English, this generates the string most similar to
// the toLocaleDateString() result above.
return date.toDateString() + ' ' + date.toLocaleTimeString();
}
}
}

View File

@@ -1,4 +1,4 @@
class Mfa extends Item {
class Mfa extends SFItem {
constructor(json_obj) {
super(json_obj);

View File

@@ -1,4 +1,4 @@
class ServerExtension extends Item {
class ServerExtension extends SFItem {
constructor(json_obj) {
super(json_obj);

View File

@@ -1,4 +1,4 @@
class Component extends Item {
class Component extends SFItem {
constructor(json_obj) {
// If making a copy of an existing component (usually during sign in if you have a component active in the session),

View File

@@ -1,4 +1,4 @@
class Editor extends Item {
class Editor extends SFItem {
constructor(json_obj) {
super(json_obj);
@@ -68,18 +68,18 @@ class Editor extends Item {
var uuids = references.map(function(ref){return ref.uuid});
this.notes.forEach(function(note){
if(!uuids.includes(note.uuid)) {
_.pull(this.notes, note);
_.remove(this.notes, {uuid: note.uuid});
}
}.bind(this))
}
potentialItemOfInterestHasChangedItsUUID(newItem, oldUUID, newUUID) {
if(newItem.content_type === "Note" && _.find(this.notes, {uuid: oldUUID})) {
_.pull(this.notes, {uuid: oldUUID});
_.remove(this.notes, {uuid: oldUUID});
this.notes.push(newItem);
}
}
toJSON() {
return {uuid: this.uuid}
}

View File

@@ -1,4 +1,4 @@
class Note extends Item {
export class Note extends SFItem {
constructor(json_obj) {
super(json_obj);
@@ -21,14 +21,6 @@ class Note extends Item {
this.text = content.text;
}
referenceParams() {
var references = _.map(this.tags, function(tag){
return {uuid: tag.uuid, content_type: tag.content_type};
})
return references;
}
structureParams() {
var params = {
title: this.title,
@@ -44,8 +36,9 @@ class Note extends Item {
this.savedTagsString = null;
if(item.content_type == "Tag") {
if(!_.find(this.tags, item)) {
if(!_.find(this.tags, {uuid: item.uuid})) {
this.tags.push(item);
item.notes.push(this);
}
}
super.addItemAsRelationship(item);
@@ -55,38 +48,29 @@ class Note extends Item {
this.savedTagsString = null;
if(item.content_type == "Tag") {
_.pull(this.tags, item);
_.remove(this.tags, {uuid: item.uuid});
_.remove(item.notes, {uuid: this.uuid});
}
super.removeItemAsRelationship(item);
}
removeAndDirtyAllRelationships() {
updateLocalRelationships() {
this.savedTagsString = null;
this.tags.forEach(function(tag){
_.pull(tag.notes, this);
tag.setDirty(true);
}.bind(this))
this.tags = [];
}
removeReferencesNotPresentIn(references) {
this.savedTagsString = null;
super.removeReferencesNotPresentIn(references);
var references = this.content.references;
var uuids = references.map(function(ref){return ref.uuid});
this.tags.slice().forEach(function(tag){
if(!uuids.includes(tag.uuid)) {
_.pull(tag.notes, this);
_.pull(this.tags, tag);
_.remove(tag.notes, {uuid: this.uuid});
_.remove(this.tags, {uuid: tag.uuid});
}
}.bind(this))
}
isBeingRemovedLocally() {
this.tags.forEach(function(tag){
_.pull(tag.notes, this);
_.remove(tag.notes, {uuid: this.uuid});
}.bind(this))
super.isBeingRemovedLocally();
}
@@ -99,7 +83,7 @@ class Note extends Item {
informReferencesOfUUIDChange(oldUUID, newUUID) {
super.informReferencesOfUUIDChange();
for(var tag of this.tags) {
_.pull(tag.notes, {uuid: oldUUID});
_.remove(tag.notes, {uuid: oldUUID});
tag.notes.push(this);
}
}
@@ -116,10 +100,6 @@ class Note extends Item {
return {uuid: this.uuid}
}
get content_type() {
return "Note";
}
tagsString() {
this.savedTagsString = Tag.arrayToDisplayString(this.tags);
return this.savedTagsString;

View File

@@ -1,4 +1,4 @@
class Tag extends Item {
export class Tag extends SFItem {
constructor(json_obj) {
super(json_obj);
@@ -13,14 +13,6 @@ class Tag extends Item {
this.title = content.title;
}
referenceParams() {
var references = _.map(this.notes, function(note){
return {uuid: note.uuid, content_type: note.content_type};
})
return references;
}
structureParams() {
var params = {
title: this.title
@@ -31,59 +23,20 @@ class Tag extends Item {
return superParams;
}
addItemAsRelationship(item) {
if(item.content_type == "Note") {
if(!_.find(this.notes, item)) {
this.notes.unshift(item);
}
}
super.addItemAsRelationship(item);
}
removeItemAsRelationship(item) {
if(item.content_type == "Note") {
_.pull(this.notes, item);
}
super.removeItemAsRelationship(item);
}
removeAndDirtyAllRelationships() {
this.notes.forEach(function(note){
_.pull(note.tags, this);
note.setDirty(true);
}.bind(this))
this.notes = [];
}
removeReferencesNotPresentIn(references) {
var uuids = references.map(function(ref){return ref.uuid});
this.notes.slice().forEach(function(note){
if(!uuids.includes(note.uuid)) {
_.pull(note.tags, this);
_.pull(this.notes, note);
}
}.bind(this))
}
isBeingRemovedLocally() {
this.notes.forEach(function(note){
_.pull(note.tags, this);
_.remove(note.tags, {uuid: this.uuid});
}.bind(this))
super.isBeingRemovedLocally();
}
informReferencesOfUUIDChange(oldUUID, newUUID) {
for(var note of this.notes) {
_.pull(note.tags, {uuid: oldUUID});
_.remove(note.tags, {uuid: oldUUID});
note.tags.push(this);
}
}
get content_type() {
return "Tag";
}
static arrayToDisplayString(tags) {
return tags.sort((a, b) => {return a.title > b.title}).map(function(tag, i){
return "#" + tag.title;

View File

@@ -1,4 +1,4 @@
class EncryptedStorage extends Item {
class EncryptedStorage extends SFItem {
constructor(json_obj) {
super(json_obj);

View File

@@ -1,72 +0,0 @@
class ItemParams {
constructor(item, keys, version) {
this.item = item;
this.keys = keys;
this.version = version || SFJS.version();
}
async paramsForExportFile(includeDeleted) {
this.additionalFields = ["updated_at"];
this.forExportFile = true;
if(includeDeleted) {
return this.__params();
} else {
var result = await this.__params();
return _.omit(result, ["deleted"]);
}
}
async paramsForExtension() {
return this.paramsForExportFile();
}
async paramsForLocalStorage() {
this.additionalFields = ["updated_at", "dirty", "errorDecrypting"];
this.forExportFile = true;
return this.__params();
}
async paramsForSync() {
return this.__params();
}
async __params() {
console.assert(!this.item.dummy, "Item is dummy, should not have gotten here.", this.item.dummy)
var params = {uuid: this.item.uuid, content_type: this.item.content_type, deleted: this.item.deleted, created_at: this.item.created_at};
if(!this.item.errorDecrypting) {
// Items should always be encrypted for export files. Only respect item.doNotEncrypt for remote sync params.
var doNotEncrypt = this.item.doNotEncrypt() && !this.forExportFile;
if(this.keys && !doNotEncrypt) {
var encryptedParams = await SFJS.itemTransformer.encryptItem(this.item, this.keys, this.version);
_.merge(params, encryptedParams);
if(this.version !== "001") {
params.auth_hash = null;
}
}
else {
params.content = this.forExportFile ? this.item.createContentJSONFromProperties() : "000" + await SFJS.crypto.base64(JSON.stringify(this.item.createContentJSONFromProperties()));
if(!this.forExportFile) {
params.enc_item_key = null;
params.auth_hash = null;
}
}
} else {
// Error decrypting, keep "content" and related fields as is (and do not try to encrypt, otherwise that would be undefined behavior)
params.content = this.item.content;
params.enc_item_key = this.item.enc_item_key;
params.auth_hash = this.item.auth_hash;
}
if(this.additionalFields) {
_.merge(params, _.pick(this.item, this.additionalFields));
}
return params;
}
}

View File

@@ -74,7 +74,7 @@ class ActionsManager {
if(!item.errorDecrypting) {
if(merge) {
var items = this.modelManager.mapResponseItemsToLocalModels([item], ModelManager.MappingSourceRemoteActionRetrieved);
var items = this.modelManager.mapResponseItemsToLocalModels([item], SFModelManager.MappingSourceRemoteActionRetrieved);
for(var mappedItem of items) {
mappedItem.setDirty(true);
}
@@ -179,7 +179,7 @@ class ActionsManager {
if(decrypted) {
keys = null;
}
var itemParams = new ItemParams(item, keys, this.authManager.protocolVersion());
var itemParams = new SFItemParams(item, keys, this.authManager.protocolVersion());
return itemParams.paramsForExtension();
}

View File

@@ -296,7 +296,7 @@ angular.module('app')
this.userPreferencesDidChange();
}, (valueCallback) => {
// Safe to create. Create and return object.
var prefs = new Item({content_type: prefsContentType});
var prefs = new SFItem({content_type: prefsContentType});
modelManager.addItem(prefs);
prefs.setDirty(true);
$rootScope.sync("authManager singletonCreate");

View File

@@ -53,13 +53,13 @@ class ComponentManager {
/* If the source of these new or updated items is from a Component itself saving items, we don't need to notify
components again of the same item. Regarding notifying other components than the issuing component, other mapping sources
will take care of that, like ModelManager.MappingSourceRemoteSaved
will take care of that, like SFModelManager.MappingSourceRemoteSaved
Update: We will now check sourceKey to determine whether the incoming change should be sent to
a component. If sourceKey == component.uuid, it will be skipped. This way, if one component triggers a change,
it's sent to other components.
*/
// if(source == ModelManager.MappingSourceComponentRetrieved) {
// if(source == SFModelManager.MappingSourceComponentRetrieved) {
// return;
// }
@@ -70,7 +70,7 @@ class ComponentManager {
/* We only want to sync if the item source is Retrieved, not MappingSourceRemoteSaved to avoid
recursion caused by the component being modified and saved after it is updated.
*/
if(syncedComponents.length > 0 && source != ModelManager.MappingSourceRemoteSaved) {
if(syncedComponents.length > 0 && source != SFModelManager.MappingSourceRemoteSaved) {
// Ensure any component in our data is installed by the system
this.desktopManager.syncComponentsInstallation(syncedComponents);
}
@@ -195,11 +195,11 @@ class ComponentManager {
/* This means the this function is being triggered through a remote Saving response, which should not update
actual local content values. The reason is, Save responses may be delayed, and a user may have changed some values
in between the Save was initiated, and the time it completes. So we only want to update actual content values (and not just metadata)
when its another source, like ModelManager.MappingSourceRemoteRetrieved.
when its another source, like SFModelManager.MappingSourceRemoteRetrieved.
3/7/18: Add MappingSourceLocalSaved as well to handle fully offline saving. github.com/standardnotes/forum/issues/169
*/
if(source && (source == ModelManager.MappingSourceRemoteSaved || source == ModelManager.MappingSourceLocalSaved)) {
if(source && (source == SFModelManager.MappingSourceRemoteSaved || source == SFModelManager.MappingSourceLocalSaved)) {
params.isMetadataUpdate = true;
}
this.removePrivatePropertiesFromResponseItems([params], component);
@@ -468,7 +468,7 @@ class ComponentManager {
We map the items here because modelManager is what updates the UI. If you were to instead get the items directly,
this would update them server side via sync, but would never make its way back to the UI.
*/
var localItems = this.modelManager.mapResponseItemsToLocalModels(responseItems, ModelManager.MappingSourceComponentRetrieved, component.uuid);
var localItems = this.modelManager.mapResponseItemsToLocalModels(responseItems, SFModelManager.MappingSourceComponentRetrieved, component.uuid);
for(var item of localItems) {
var responseItem = _.find(responseItems, {uuid: item.uuid});

View File

@@ -37,7 +37,7 @@ class DesktopManager {
Keys are not passed into ItemParams, so the result is not encrypted
*/
async convertComponentForTransmission(component) {
return new ItemParams(component).paramsForExportFile(true);
return new SFItemParams(component).paramsForExportFile(true);
}
// All `components` should be installed
@@ -96,7 +96,7 @@ class DesktopManager {
for(var key of permissableKeys) {
component[key] = componentData.content[key];
}
this.modelManager.notifySyncObserversOfModels([component], ModelManager.MappingSourceDesktopInstalled);
this.modelManager.notifySyncObserversOfModels([component], SFModelManager.MappingSourceDesktopInstalled);
component.setAppDataItem("installError", null);
}
component.setDirty(true);

View File

@@ -36,9 +36,11 @@ class MigrationManager {
if(editor.url && !this.componentManager.componentForUrl(editor.url)) {
var component = this.modelManager.createItem({
content_type: "SN|Component",
url: editor.url,
name: editor.name,
area: "editor-editor"
content: {
url: editor.url,
name: editor.name,
area: "editor-editor"
}
})
component.setAppDataItem("data", editor.data);
component.setDirty(true);

View File

@@ -1,10 +1,25 @@
class ModelManager {
SFModelManager.ContentTypeClassMapping = {
"Note" : Note,
"Tag" : Tag,
"Extension" : Extension,
"SN|Editor" : Editor,
"SN|Theme" : Theme,
"SN|Component" : Component,
"SF|Extension" : ServerExtension,
"SF|MFA" : Mfa
};
SFItem.AppDomain = "org.standardnotes.sn";
class ModelManager extends SFModelManager {
constructor(storageManager) {
super(storageManager);
super();
this.notes = [];
this.tags = [];
this._extensions = [];
this.storageManager = storageManager;
}
resetLocalMemory() {
@@ -17,7 +32,7 @@ class ModelManager {
findOrCreateTagByTitle(title) {
var tag = _.find(this.tags, {title: title})
if(!tag) {
tag = this.createItem({content_type: "Tag", title: title});
tag = this.createItem({content_type: "Tag", content: {title: title}});
this.addItem(tag);
}
return tag;
@@ -86,6 +101,8 @@ class ModelManager {
} else if(item.content_type == "Extension") {
_.pull(this._extensions, item);
}
this.storageManager.deleteModel(item, callback);
}
/*

View File

@@ -153,7 +153,7 @@ class StorageManager {
encryptedStorage.storage = this.storageAsHash();
// Save new encrypted storage in Fixed storage
var params = new ItemParams(encryptedStorage, this.encryptedStorageKeys, this.encryptedStorageAuthParams.version);
var params = new SFItemParams(encryptedStorage, this.encryptedStorageKeys, this.encryptedStorageAuthParams.version);
params.paramsForSync().then((syncParams) => {
this.setItem("encryptedStorage", JSON.stringify(syncParams), StorageManager.Fixed);
})

View File

@@ -48,7 +48,7 @@ class SyncManager {
var keys = this.authManager.offline() ? this.passcodeManager.keys() : this.authManager.keys();
Promise.all(items.map(async (item) => {
var itemParams = new ItemParams(item, keys, version);
var itemParams = new SFItemParams(item, keys, version);
itemParams = await itemParams.paramsForLocalStorage();
if(offlineOnly) {
delete itemParams.dirty;
@@ -79,13 +79,13 @@ class SyncManager {
var processed = [];
var completion = () => {
Item.sortItemsByDate(processed);
SFItem.sortItemsByDate(processed);
callback(processed);
}
var decryptNext = async () => {
var subitems = items.slice(current, current + iteration);
var processedSubitems = await this.handleItemsResponse(subitems, null, ModelManager.MappingSourceLocalRetrieved);
var processedSubitems = await this.handleItemsResponse(subitems, null, SFModelManager.MappingSourceLocalRetrieved);
processed.push(processedSubitems);
current += subitems.length;
@@ -93,6 +93,7 @@ class SyncManager {
if(current < total) {
this.$timeout(() => { decryptNext(); });
} else {
// this.modelManager.resolveReferencesForAllItems()
completion();
}
}
@@ -341,7 +342,7 @@ class SyncManager {
params.limit = 150;
await Promise.all(subItems.map((item) => {
var itemParams = new ItemParams(item, keys, version);
var itemParams = new SFItemParams(item, keys, version);
itemParams.additionalFields = options.additionalFields;
return itemParams.paramsForSync();
})).then((itemsParams) => {
@@ -386,7 +387,7 @@ class SyncManager {
// Map retrieved items to local data
// Note that deleted items will not be returned
var retrieved = await this.handleItemsResponse(response.retrieved_items, null, ModelManager.MappingSourceRemoteRetrieved);
var retrieved = await this.handleItemsResponse(response.retrieved_items, null, SFModelManager.MappingSourceRemoteRetrieved);
// Append items to master list of retrieved items for this ongoing sync operation
this.allRetreivedItems = this.allRetreivedItems.concat(retrieved);
@@ -397,7 +398,7 @@ class SyncManager {
var omitFields = ["content", "auth_hash"];
// Map saved items to local data
var saved = await this.handleItemsResponse(response.saved_items, omitFields, ModelManager.MappingSourceRemoteSaved);
var saved = await this.handleItemsResponse(response.saved_items, omitFields, SFModelManager.MappingSourceRemoteSaved);
// Append items to master list of saved items for this ongoing sync operation
this.allSavedItems = this.allSavedItems.concat(saved);
@@ -504,7 +505,7 @@ class SyncManager {
refreshErroredItems() {
var erroredItems = this.modelManager.allItems.filter((item) => {return item.errorDecrypting == true});
if(erroredItems.length > 0) {
this.handleItemsResponse(erroredItems, null, ModelManager.MappingSourceLocalRetrieved);
this.handleItemsResponse(erroredItems, null, SFModelManager.MappingSourceLocalRetrieved);
}
}