ModelManager mapping sources
This commit is contained in:
@@ -31,7 +31,15 @@ class ComponentManager {
|
|||||||
this.handleMessage(this.componentForSessionKey(event.data.sessionKey), event.data);
|
this.handleMessage(this.componentForSessionKey(event.data.sessionKey), event.data);
|
||||||
}.bind(this), false);
|
}.bind(this), false);
|
||||||
|
|
||||||
this.modelManager.addItemSyncObserver("component-manager", "*", function(allItems, validItems, deletedItems) {
|
this.modelManager.addItemSyncObserver("component-manager", "*", function(allItems, validItems, deletedItems, source) {
|
||||||
|
|
||||||
|
/* 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
|
||||||
|
*/
|
||||||
|
if(source == ModelManager.MappingSourceComponentRetrieved) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
var syncedComponents = allItems.filter(function(item){return item.content_type === "SN|Component" });
|
var syncedComponents = allItems.filter(function(item){return item.content_type === "SN|Component" });
|
||||||
for(var component of syncedComponents) {
|
for(var component of syncedComponents) {
|
||||||
@@ -76,7 +84,7 @@ class ComponentManager {
|
|||||||
if(itemInContext) {
|
if(itemInContext) {
|
||||||
var matchingItem = _.find(allItems, {uuid: itemInContext.uuid});
|
var matchingItem = _.find(allItems, {uuid: itemInContext.uuid});
|
||||||
if(matchingItem) {
|
if(matchingItem) {
|
||||||
this.sendContextItemInReply(observer.component, matchingItem, observer.originalMessage);
|
this.sendContextItemInReply(observer.component, matchingItem, observer.originalMessage, source);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -118,29 +126,37 @@ class ComponentManager {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
jsonForItem(item, component) {
|
jsonForItem(item, component, source) {
|
||||||
var params = {uuid: item.uuid, content_type: item.content_type, created_at: item.created_at, updated_at: item.updated_at, deleted: item.deleted};
|
var params = {uuid: item.uuid, content_type: item.content_type, created_at: item.created_at, updated_at: item.updated_at, deleted: item.deleted};
|
||||||
params.content = item.createContentJSONFromProperties();
|
params.content = item.createContentJSONFromProperties();
|
||||||
params.clientData = item.getDomainDataItem(component.url, ClientDataDomain) || {};
|
params.clientData = item.getDomainDataItem(component.url, ClientDataDomain) || {};
|
||||||
params.isMetadataUpdate = item.lastTouchSaved;
|
|
||||||
|
/* 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.
|
||||||
|
*/
|
||||||
|
if(source && source == ModelManager.MappingSourceRemoteSaved) {
|
||||||
|
params.isMetadataUpdate = true;
|
||||||
|
}
|
||||||
this.removePrivatePropertiesFromResponseItems([params]);
|
this.removePrivatePropertiesFromResponseItems([params]);
|
||||||
return params;
|
return params;
|
||||||
}
|
}
|
||||||
|
|
||||||
sendItemsInReply(component, items, message) {
|
sendItemsInReply(component, items, message, source) {
|
||||||
if(this.loggingEnabled) {console.log("Web|componentManager|sendItemsInReply", component, items, message)};
|
if(this.loggingEnabled) {console.log("Web|componentManager|sendItemsInReply", component, items, message)};
|
||||||
var response = {items: {}};
|
var response = {items: {}};
|
||||||
var mapped = items.map(function(item) {
|
var mapped = items.map(function(item) {
|
||||||
return this.jsonForItem(item, component);
|
return this.jsonForItem(item, component, source);
|
||||||
}.bind(this));
|
}.bind(this));
|
||||||
|
|
||||||
response.items = mapped;
|
response.items = mapped;
|
||||||
this.replyToMessage(component, message, response);
|
this.replyToMessage(component, message, response);
|
||||||
}
|
}
|
||||||
|
|
||||||
sendContextItemInReply(component, item, originalMessage) {
|
sendContextItemInReply(component, item, originalMessage, source) {
|
||||||
if(this.loggingEnabled) {console.log("Web|componentManager|sendContextItemInReply", component, item, originalMessage)};
|
if(this.loggingEnabled) {console.log("Web|componentManager|sendContextItemInReply", component, item, originalMessage)};
|
||||||
var response = {item: this.jsonForItem(item, component)};
|
var response = {item: this.jsonForItem(item, component, source)};
|
||||||
this.replyToMessage(component, originalMessage, response);
|
this.replyToMessage(component, originalMessage, response);
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -240,7 +256,7 @@ class ComponentManager {
|
|||||||
We map the items here because modelManager is what updates the UI. If you were to instead get the items directly,
|
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.
|
this would update them server side via sync, but would never make its way back to the UI.
|
||||||
*/
|
*/
|
||||||
var localItems = this.modelManager.mapResponseItemsToLocalModels(responseItems, {dontNotifyObservers: true});
|
var localItems = this.modelManager.mapResponseItemsToLocalModels(responseItems, ModelManager.MappingSourceComponentRetrieved);
|
||||||
|
|
||||||
for(var item of localItems) {
|
for(var item of localItems) {
|
||||||
var responseItem = _.find(responseItems, {uuid: item.uuid});
|
var responseItem = _.find(responseItems, {uuid: item.uuid});
|
||||||
|
|||||||
@@ -242,7 +242,7 @@ class AccountMenu {
|
|||||||
|
|
||||||
$scope.importJSONData = function(data, password, callback) {
|
$scope.importJSONData = function(data, password, callback) {
|
||||||
var onDataReady = function(errorCount) {
|
var onDataReady = function(errorCount) {
|
||||||
var items = modelManager.mapResponseItemsToLocalModels(data.items);
|
var items = modelManager.mapResponseItemsToLocalModels(data.items, ModelManager.MappingSourceFileImport);
|
||||||
items.forEach(function(item){
|
items.forEach(function(item){
|
||||||
item.setDirty(true);
|
item.setDirty(true);
|
||||||
item.deleted = false;
|
item.deleted = false;
|
||||||
|
|||||||
@@ -161,7 +161,7 @@ class ExtensionManager {
|
|||||||
action.error = false;
|
action.error = false;
|
||||||
var items = response.items || [response.item];
|
var items = response.items || [response.item];
|
||||||
EncryptionHelper.decryptMultipleItems(items, this.authManager.keys());
|
EncryptionHelper.decryptMultipleItems(items, this.authManager.keys());
|
||||||
items = this.modelManager.mapResponseItemsToLocalModels(items);
|
items = this.modelManager.mapResponseItemsToLocalModels(items, ModelManager.MappingSourceRemoteActionRetrieved);
|
||||||
for(var item of items) {
|
for(var item of items) {
|
||||||
item.setDirty(true);
|
item.setDirty(true);
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,6 +1,13 @@
|
|||||||
class ModelManager {
|
class ModelManager {
|
||||||
|
|
||||||
constructor(storageManager) {
|
constructor(storageManager) {
|
||||||
|
ModelManager.MappingSourceRemoteRetrieved = "MappingSourceRemoteRetrieved";
|
||||||
|
ModelManager.MappingSourceRemoteSaved = "MappingSourceRemoteSaved";
|
||||||
|
ModelManager.MappingSourceLocalRetrieved = "MappingSourceLocalRetrieved";
|
||||||
|
ModelManager.MappingSourceComponentRetrieved = "MappingSourceComponentRetrieved";
|
||||||
|
ModelManager.MappingSourceRemoteActionRetrieved = "MappingSourceRemoteActionRetrieved"; /* aciton-based Extensions like note history */
|
||||||
|
ModelManager.MappingSourceFileImport = "MappingSourceFileImport";
|
||||||
|
|
||||||
this.storageManager = storageManager;
|
this.storageManager = storageManager;
|
||||||
this.notes = [];
|
this.notes = [];
|
||||||
this.tags = [];
|
this.tags = [];
|
||||||
@@ -96,11 +103,11 @@ class ModelManager {
|
|||||||
return tag;
|
return tag;
|
||||||
}
|
}
|
||||||
|
|
||||||
mapResponseItemsToLocalModels(items, options) {
|
mapResponseItemsToLocalModels(items, source) {
|
||||||
return this.mapResponseItemsToLocalModelsOmittingFields(items, null, options);
|
return this.mapResponseItemsToLocalModelsOmittingFields(items, null, source);
|
||||||
}
|
}
|
||||||
|
|
||||||
mapResponseItemsToLocalModelsOmittingFields(items, omitFields, options) {
|
mapResponseItemsToLocalModelsOmittingFields(items, omitFields, source) {
|
||||||
var models = [], processedObjects = [], modelsToNotifyObserversOf = [];
|
var models = [], processedObjects = [], modelsToNotifyObserversOf = [];
|
||||||
|
|
||||||
// first loop should add and process items
|
// first loop should add and process items
|
||||||
@@ -136,14 +143,6 @@ class ModelManager {
|
|||||||
item = this.createItem(json_obj);
|
item = this.createItem(json_obj);
|
||||||
}
|
}
|
||||||
|
|
||||||
/* If content is being omitted from the json_obj, this means this is a metadata save only.
|
|
||||||
This happens by the sync manager on sync completion when processing saved items to update
|
|
||||||
their meta fields, like updated_at that comes from the server. We omit content in such a case
|
|
||||||
because content may be outdated from the time a sync begins to when it completes (user performed action in between).
|
|
||||||
So we will only ever update content from a remote source when it is retrieved by the server (serverResponse.retrieved_items)
|
|
||||||
*/
|
|
||||||
item.lastTouchSaved = omitFields && omitFields.includes("content");
|
|
||||||
|
|
||||||
this.addItem(item);
|
this.addItem(item);
|
||||||
|
|
||||||
modelsToNotifyObserversOf.push(item);
|
modelsToNotifyObserversOf.push(item);
|
||||||
@@ -159,18 +158,12 @@ class ModelManager {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/* Sometimes, a controller will want to map incoming state to the UI, but without yet notifiny all observers of an item change
|
this.notifySyncObserversOfModels(modelsToNotifyObserversOf, source);
|
||||||
Particulary, the componentManager sets dontNotifyObservers to true when it receives an update from a component and wnats
|
|
||||||
to update the remaining UI, but without receiving a (useless) syncObserverCallback immediately.
|
|
||||||
*/
|
|
||||||
if(!(options && options.dontNotifyObservers)) {
|
|
||||||
this.notifySyncObserversOfModels(modelsToNotifyObserversOf);
|
|
||||||
}
|
|
||||||
|
|
||||||
return models;
|
return models;
|
||||||
}
|
}
|
||||||
|
|
||||||
notifySyncObserversOfModels(models) {
|
notifySyncObserversOfModels(models, source) {
|
||||||
for(var observer of this.itemSyncObservers) {
|
for(var observer of this.itemSyncObservers) {
|
||||||
var allRelevantItems = models.filter(function(item){return item.content_type == observer.type || observer.type == "*"});
|
var allRelevantItems = models.filter(function(item){return item.content_type == observer.type || observer.type == "*"});
|
||||||
var validItems = [], deletedItems = [];
|
var validItems = [], deletedItems = [];
|
||||||
@@ -183,7 +176,7 @@ class ModelManager {
|
|||||||
}
|
}
|
||||||
|
|
||||||
if(allRelevantItems.length > 0) {
|
if(allRelevantItems.length > 0) {
|
||||||
observer.callback(allRelevantItems, validItems, deletedItems);
|
observer.callback(allRelevantItems, validItems, deletedItems, source);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -47,7 +47,7 @@ class SyncManager {
|
|||||||
|
|
||||||
loadLocalItems(callback) {
|
loadLocalItems(callback) {
|
||||||
var params = this.storageManager.getAllModels(function(items){
|
var params = this.storageManager.getAllModels(function(items){
|
||||||
var items = this.handleItemsResponse(items, null);
|
var items = this.handleItemsResponse(items, null, ModelManager.MappingSourceLocalRetrieved);
|
||||||
Item.sortItemsByDate(items);
|
Item.sortItemsByDate(items);
|
||||||
callback(items);
|
callback(items);
|
||||||
}.bind(this))
|
}.bind(this))
|
||||||
@@ -267,7 +267,7 @@ class SyncManager {
|
|||||||
|
|
||||||
// Map retrieved items to local data
|
// Map retrieved items to local data
|
||||||
var retrieved
|
var retrieved
|
||||||
= this.handleItemsResponse(response.retrieved_items, null);
|
= this.handleItemsResponse(response.retrieved_items, null, ModelManager.MappingSourceRemoteRetrieved);
|
||||||
|
|
||||||
// Append items to master list of retrieved items for this ongoing sync operation
|
// Append items to master list of retrieved items for this ongoing sync operation
|
||||||
this.allRetreivedItems = this.allRetreivedItems.concat(retrieved);
|
this.allRetreivedItems = this.allRetreivedItems.concat(retrieved);
|
||||||
@@ -279,7 +279,7 @@ class SyncManager {
|
|||||||
|
|
||||||
// Map saved items to local data
|
// Map saved items to local data
|
||||||
var saved =
|
var saved =
|
||||||
this.handleItemsResponse(response.saved_items, omitFields);
|
this.handleItemsResponse(response.saved_items, omitFields, ModelManager.MappingSourceRemoteSaved);
|
||||||
|
|
||||||
// Create copies of items or alternate their uuids if neccessary
|
// Create copies of items or alternate their uuids if neccessary
|
||||||
var unsaved = response.unsaved;
|
var unsaved = response.unsaved;
|
||||||
@@ -355,10 +355,10 @@ class SyncManager {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
handleItemsResponse(responseItems, omitFields) {
|
handleItemsResponse(responseItems, omitFields, source) {
|
||||||
var keys = this.authManager.keys() || this.passcodeManager.keys();
|
var keys = this.authManager.keys() || this.passcodeManager.keys();
|
||||||
EncryptionHelper.decryptMultipleItems(responseItems, keys);
|
EncryptionHelper.decryptMultipleItems(responseItems, keys);
|
||||||
var items = this.modelManager.mapResponseItemsToLocalModelsOmittingFields(responseItems, omitFields);
|
var items = this.modelManager.mapResponseItemsToLocalModelsOmittingFields(responseItems, omitFields, source);
|
||||||
return items;
|
return items;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
Reference in New Issue
Block a user