extension sync

This commit is contained in:
Mo Bitar
2017-01-05 15:42:35 -06:00
parent 117d6fca4e
commit 54ac4ffd15
10 changed files with 542 additions and 174 deletions

View File

@@ -53,6 +53,12 @@ angular.module('app.frontend')
}) })
} }
this.reloadExtensionsPressed = function() {
if(confirm("For your security, reloading extensions will disable any currently enabled repeat actions.")) {
extensionManager.refreshExtensionsFromServer();
}
}
this.changeServer = function() { this.changeServer = function() {
apiController.setServer(this.serverData.url, true); apiController.setServer(this.serverData.url, true);
} }

View File

@@ -1,14 +1,3 @@
class Extension extends Item {
constructor(json) {
super(json);
_.merge(this, json);
this.actions = this.actions.map(function(action){
return new Action(action);
})
}
}
class Action { class Action {
constructor(json) { constructor(json) {
_.merge(this, json); _.merge(this, json);
@@ -22,3 +11,44 @@ class Action {
} }
} }
} }
class Extension extends Item {
constructor(json) {
super(json);
_.merge(this, json);
this.content_type = "Extension";
}
mapContentToLocalProperties(contentObject) {
super.mapContentToLocalProperties(contentObject)
this.name = contentObject.name;
this.url = contentObject.url;
this.actions = contentObject.actions.map(function(action){
return new Action(action);
})
}
updateFromExternalResponseItem(externalResponseItem) {
_.merge(this, externalResponseItem);
this.actions = externalResponseItem.actions.map(function(action){
return new Action(action);
})
}
referenceParams() {
return null;
}
structureParams() {
var params = {
name: this.name,
url: this.url,
actions: this.actions
};
_.merge(params, super.structureParams());
return params;
}
}

View File

@@ -234,7 +234,7 @@ angular.module('app.frontend')
return this.createRequestParamsForItem(item, options.additionalFields); return this.createRequestParamsForItem(item, options.additionalFields);
}.bind(this)); }.bind(this));
console.log("syncing items", request.items); // console.log("syncing items", request.items);
if(this.syncToken) { if(this.syncToken) {
request.sync_token = this.syncToken; request.sync_token = this.syncToken;

View File

@@ -1,28 +1,78 @@
class ExtensionManager { class ExtensionManager {
constructor(Restangular, modelManager) { constructor(Restangular, modelManager, apiController) {
this.Restangular = Restangular; this.Restangular = Restangular;
this.modelManager = modelManager; this.modelManager = modelManager;
this.extensions = []; this.apiController = apiController;
this.enabledRepeatActions = []; this.enabledRepeatActionUrls = JSON.parse(localStorage.getItem("enabledRepeatActionUrls")) || [];
this.enabledRepeatActionUrls = localStorage.getItem("enabled_ext_urls") || [];
modelManager.addItemSyncObserver("extensionManager", "Extension", function(items){
for (var ext of items) {
for (var action of ext.actions) {
if(this.enabledRepeatActionUrls.includes(action.url)) {
this.enableRepeatAction(action, ext);
}
}
}
}.bind(this))
}
get extensions() {
return this.modelManager.extensions;
}
actionWithURL(url) {
for (var extension of this.extensions) {
return _.find(extension.actions, {url: url})
}
} }
addExtension(url) { addExtension(url) {
this.retrieveExtensionFromServer(url, null);
}
retrieveExtensionFromServer(url, callback) {
console.log("Registering URL", url); console.log("Registering URL", url);
this.Restangular.oneUrl(url, url).get().then(function(response){ this.Restangular.oneUrl(url, url).get().then(function(response){
console.log("get response", response.plain()); console.log("get response", response.plain());
var extension = new Extension(response.plain()); var ext = this.handleExtensionLoadExternalResponseItem(url, response.plain());
this.registerExtension(extension); if(callback) {
callback(ext);
}
}.bind(this)) }.bind(this))
.catch(function(response){ .catch(function(response){
console.log("Error registering extension", response); console.log("Error registering extension", response);
}) })
} }
registerExtension(extension) { handleExtensionLoadExternalResponseItem(url, externalResponseItem) {
this.extensions.push(extension); var extension = _.find(this.extensions, {url: url});
console.log("registered extensions", this.extensions); if(extension) {
extension.updateFromExternalResponseItem(externalResponseItem);
console.log("updated existing ext", extension);
} else {
console.log("creating new ext", externalResponseItem);
extension = new Extension(externalResponseItem);
extension.url = url;
extension.dirty = true;
this.modelManager.addItem(extension);
this.apiController.sync(null);
}
return extension;
}
refreshExtensionsFromServer() {
for (var url of this.enabledRepeatActionUrls) {
var action = this.actionWithURL(url);
this.disableRepeatAction(action);
}
for(var ext of this.extensions) {
this.retrieveExtensionFromServer(ext.url, function(extension){
extension.dirty = true;
});
}
} }
executeAction(action, extension, callback) { executeAction(action, extension, callback) {
@@ -43,46 +93,71 @@ class ExtensionManager {
disableRepeatAction(action, extension) { disableRepeatAction(action, extension) {
console.log("Disabling action", action); console.log("Disabling action", action);
_.pull(this.enabledRepeatActionUrls, action.url); _.pull(this.enabledRepeatActionUrls, action.url);
_.pull(this.enabledRepeatActions, action); this.modelManager.removeItemSyncObserver(action.url);
this.modelManager.removeItemObserver(action.url);
console.assert(this.isRepeatActionEnabled(action) == false); console.assert(this.isRepeatActionEnabled(action) == false);
} }
enableRepeatAction(action, extension) { enableRepeatAction(action, extension) {
console.log("Enabling repeat action", action); console.log("Enabling repeat action", action);
this.enabledRepeatActionUrls.push(action.url); if(!_.find(this.enabledRepeatActionUrls, action.url)) {
this.enabledRepeatActions.push(action); this.enabledRepeatActionUrls.push(action.url);
localStorage.setItem("enabledRepeatActionUrls", JSON.stringify(this.enabledRepeatActionUrls));
}
if(action.repeatType == "watch") { if(action.repeatType == "watch") {
for(var structure of action.structures) { for(var structure of action.structures) {
this.modelManager.addItemObserver(action.url, structure.type, function(changedItems){ this.modelManager.addItemSyncObserver(action.url, structure.type, function(changedItems){
this.triggerWatchAction(action, changedItems); this.triggerWatchAction(action, changedItems);
}.bind(this)) }.bind(this))
} }
} }
} }
queueAction(action, delay, changedItems) {
this.actionQueue = this.actionQueue || [];
if(_.find(this.actionQueue, action)) {
// console.log("Action already queued, skipping.")
return;
}
// console.log("Adding action to queue", action);
this.actionQueue.push(action);
setTimeout(function () {
console.log("Performing queued action", action);
this.triggerWatchAction(action, changedItems);
_.pull(this.actionQueue, action);
}.bind(this), delay * 1000);
}
triggerWatchAction(action, changedItems) { triggerWatchAction(action, changedItems) {
console.log("Watch action triggered", action, changedItems); // console.log("Watch action triggered", action, changedItems);
if(action.repeatFrequency > 0) { if(action.repeatFrequency > 0) {
var lastExecuted = action.lastExecuted; var lastExecuted = action.lastExecuted;
var diffInSeconds = (new Date() - lastExecuted)/1000; var diffInSeconds = (new Date() - lastExecuted)/1000;
console.log("last executed", action.lastExecuted, "diff", diffInSeconds, "repeatFreq", action.repeatFrequency);
if(diffInSeconds < action.repeatFrequency) { if(diffInSeconds < action.repeatFrequency) {
console.log("too frequent, returning"); var delay = action.repeatFrequency - diffInSeconds;
console.log("delaying action by", delay);
this.queueAction(action, delay, changedItems);
return; return;
} }
} }
console.log("Performing action immediately", action);
action.lastExecuted = new Date();
// console.log("setting last exectured", action.lastExecuted)
if(action.repeatVerb == "post") { if(action.repeatVerb == "post") {
var request = this.Restangular.oneUrl(action.url, action.url); var request = this.Restangular.oneUrl(action.url, action.url);
request.items = changedItems.map(function(item){ request.items = changedItems.map(function(item){
var params = {uuid: item.uuid, content_type: item.content_type, content: item.content}; var params = {uuid: item.uuid, content_type: item.content_type, content: item.createContentJSONFromProperties()};
return params; return params;
}) })
request.post().then(function(response){ request.post().then(function(response){
console.log("watch action response", response); // console.log("watch action response", response);
action.lastExecuted = new Date();
}) })
} }
} }

View File

@@ -3,8 +3,9 @@ class ModelManager {
constructor() { constructor() {
this.notes = []; this.notes = [];
this.tags = []; this.tags = [];
this.changeObservers = []; this.itemSyncObservers = [];
this.items = []; this.items = [];
this.extensions = [];
} }
findItem(itemId) { findItem(itemId) {
@@ -44,6 +45,13 @@ class ModelManager {
models.push(item) models.push(item)
} }
for(var observer of this.itemSyncObservers) {
var relevantItems = models.filter(function(item){return item.content_type == observer.type});
if(relevantItems.length > 0) {
observer.callback(relevantItems);
}
}
this.sortItems(); this.sortItems();
return models; return models;
} }
@@ -53,6 +61,8 @@ class ModelManager {
return new Note(json_obj); return new Note(json_obj);
} else if(json_obj.content_type == "Tag") { } else if(json_obj.content_type == "Tag") {
return new Tag(json_obj); return new Tag(json_obj);
} else if(json_obj.content_type == "Extension") {
return new Extension(json_obj);
} else { } else {
return new Item(json_obj); return new Item(json_obj);
} }
@@ -70,6 +80,10 @@ class ModelManager {
if(!_.find(this.notes, {uuid: item.uuid})) { if(!_.find(this.notes, {uuid: item.uuid})) {
this.notes.unshift(item); this.notes.unshift(item);
} }
} else if(item.content_type == "Extension") {
if(!_.find(this.extensions, {uuid: item.uuid})) {
this.extensions.unshift(item);
}
} }
}.bind(this)) }.bind(this))
} }
@@ -85,7 +99,6 @@ class ModelManager {
} }
resolveReferencesForItem(item) { resolveReferencesForItem(item) {
var contentObject = item.contentObject; var contentObject = item.contentObject;
if(!contentObject.references) { if(!contentObject.references) {
return; return;
@@ -100,7 +113,6 @@ class ModelManager {
console.log("Unable to find item:", reference.uuid); console.log("Unable to find item:", reference.uuid);
} }
} }
} }
sortItems() { sortItems() {
@@ -111,33 +123,23 @@ class ModelManager {
}) })
} }
addItemObserver(id, type, callback) { addItemSyncObserver(id, type, callback) {
this.changeObservers.push({id: id, type: type, callback: callback}); this.itemSyncObservers.push({id: id, type: type, callback: callback});
} }
removeItemObserver(id) { removeItemSyncObserver(id) {
_.remove(this.changeObservers, _.find(this.changeObservers, {id: id})); _.remove(this.itemSyncObservers, _.find(this.itemSyncObservers, {id: id}));
} }
get filteredNotes() { get filteredNotes() {
return Note.filterDummyNotes(this.notes); return Note.filterDummyNotes(this.notes);
} }
notifyObserversOfSyncCompletion() {
for(var observer of this.changeObservers) {
var changedItems = this.dirtyItems.filter(function(item){return item.content_type == observer.type});
console.log("observer:", observer, "items", changedItems);
observer.callback(changedItems);
}
}
getDirtyItems() { getDirtyItems() {
return this.items.filter(function(item){return item.dirty == true && !item.dummy}) return this.items.filter(function(item){return item.dirty == true && !item.dummy})
} }
clearDirtyItems() { clearDirtyItems() {
this.notifyObserversOfSyncCompletion();
this.getDirtyItems().forEach(function(item){ this.getDirtyItems().forEach(function(item){
item.dirty = false; item.dirty = false;
}) })
@@ -156,6 +158,8 @@ class ModelManager {
_.pull(this.tags, item); _.pull(this.tags, item);
} else if(item.content_type == "Note") { } else if(item.content_type == "Note") {
_.pull(this.notes, item); _.pull(this.notes, item);
} else if(item.content_type == "Extension") {
_.pull(this.extensions, item);
} }
} }

View File

@@ -267,6 +267,14 @@ Extensions
.extensions-panel { .extensions-panel {
font-size: 14px; font-size: 14px;
.extension-link {
margin-top: 6px;
a {
font-weight: bold;
}
}
} }
.extension-form { .extension-form {
@@ -282,6 +290,12 @@ Extensions
padding: 10px; padding: 10px;
color: black; color: black;
a {
color: $blue-color !important;
font-size: 12px !important;
font-weight: bold !important;
}
> .name { > .name {
font-weight: bold; font-weight: bold;
font-size: 16px; font-size: 16px;
@@ -295,7 +309,7 @@ Extensions
> .actions { > .actions {
margin-top: 15px; margin-top: 15px;
font-size: 14px; font-size: 12px;
.action { .action {
margin-bottom: 10px; margin-bottom: 10px;
@@ -305,9 +319,6 @@ Extensions
} }
> .execute { > .execute {
a {
color: $blue-color;
}
font-weight: bold; font-weight: bold;
margin-bottom: 3px; margin-bottom: 3px;
font-size: 12px; font-size: 12px;
@@ -315,6 +326,7 @@ Extensions
> .execute-type { > .execute-type {
font-size: 12px; font-size: 12px;
margin-bottom: 1px;
} }
> .last-run { > .last-run {

View File

@@ -95,6 +95,17 @@
.actions .actions
.action{"ng-repeat" => "action in extension.actions"} .action{"ng-repeat" => "action in extension.actions"}
.name {{action.label}} .name {{action.label}}
.desc{"style" => "font-style: italic;"} {{action.desc}}
.execute-type{"ng-if" => "action.repeatable"}
Repeats at most once every {{action.repeatFrequency}} seconds
.last-run{"ng-if" => "action.lastExecuted"}
Last executed {{action.lastExecuted | appDate}}
.permissions
%a{"ng-click" => "action.showPermissions = !action.showPermissions"} {{action.showPermissions ? "Hide permissions" : "Show permissions"}}
.permission-model{"ng-if" => "action.showPermissions", "ng-repeat" => "structure in action.structures"}
%span{"style" => "font-weight: bold;"} {{structure.type}}s:
%span{"ng-repeat" => "field in structure.fields"}
{{field.name}} ({{field.modifies ? "readwrite" : "read"}})
.execute .execute
%a{"ng-click" => "ctrl.selectedAction(action, extension)"} %a{"ng-click" => "ctrl.selectedAction(action, extension)"}
%span{"ng-if" => "action.repeatable"} %span{"ng-if" => "action.repeatable"}
@@ -102,18 +113,19 @@
%span{"ng-if" => "!ctrl.extensionManager.isRepeatActionEnabled(action)", "ng-click" => "ctrl.extensionManager.enableRepeatAction(action, extension)"} Enable %span{"ng-if" => "!ctrl.extensionManager.isRepeatActionEnabled(action)", "ng-click" => "ctrl.extensionManager.enableRepeatAction(action, extension)"} Enable
%span{"ng-if" => "!action.repeatable"} %span{"ng-if" => "!action.repeatable"}
Perform Action Perform Action
.execute-type{"ng-if" => "action.repeatable"}
This is a repeat action.
.last-run{"ng-if" => "action.lastExecuted"}
Last executed {{action.lastExecuted | appDate}}
%a{"ng-click" => "ctrl.toggleExtensionForm()"} Add new extension .extension-link
%a{"ng-click" => "ctrl.toggleExtensionForm()"} Add new extension
%form.extension-form{"ng-if" => "ctrl.showNewExtensionForm"} %form.extension-form{"ng-if" => "ctrl.showNewExtensionForm"}
.form-tag.has-feedback .form-tag.has-feedback
%input.form-control{:autofocus => 'autofocus', :name => 'url', :placeholder => 'Extension URL', :required => true, :type => 'text', 'ng-model' => 'ctrl.newExtensionData.url'} %input.form-control{:autofocus => 'autofocus', :name => 'url', :placeholder => 'Extension URL', :required => true, :type => 'text', 'ng-model' => 'ctrl.newExtensionData.url'}
%button.btn.dark-button.btn-block{:type => 'submit', "data-style" => "expand-right", "data-size" => "s", "state" => "buttonState"} %button.btn.dark-button.btn-block{:type => 'submit', "data-style" => "expand-right", "data-size" => "s", "state" => "buttonState"}
%span.ladda-label{"ng-click" => "ctrl.submitNewExtensionForm()"} Add Extension %span.ladda-label{"ng-click" => "ctrl.submitNewExtensionForm()"} Add Extension
.extension-link
%a{"ng-click" => "ctrl.reloadExtensionsPressed()", "ng-if" => "ctrl.extensionManager.extensions.length > 0"} Reload all extensions
.item .item
%a{"href" => "https://standardnotes.org", "target" => "_blank"} %a{"href" => "https://standardnotes.org", "target" => "_blank"}
Help Help

View File

@@ -765,6 +765,12 @@ angular.module('app.frontend').controller('BaseCtrl', BaseCtrl);
}); });
}; };
this.reloadExtensionsPressed = function () {
if (confirm("For your security, reloading extensions will disable any currently enabled repeat actions.")) {
extensionManager.refreshExtensionsFromServer();
}
};
this.changeServer = function () { this.changeServer = function () {
apiController.setServer(this.serverData.url, true); apiController.setServer(this.serverData.url, true);
}; };
@@ -1432,25 +1438,6 @@ var Item = function () {
}(); }();
; ;
var Extension = function (_Item) {
_inherits(Extension, _Item);
function Extension(json) {
_classCallCheck(this, Extension);
var _this3 = _possibleConstructorReturn(this, (Extension.__proto__ || Object.getPrototypeOf(Extension)).call(this, json));
_.merge(_this3, json);
_this3.actions = _this3.actions.map(function (action) {
return new Action(action);
});
return _this3;
}
return Extension;
}(Item);
var Action = function Action(json) { var Action = function Action(json) {
_classCallCheck(this, Action); _classCallCheck(this, Action);
@@ -1465,6 +1452,60 @@ var Action = function Action(json) {
} }
}; };
var Extension = function (_Item) {
_inherits(Extension, _Item);
function Extension(json) {
_classCallCheck(this, Extension);
var _this3 = _possibleConstructorReturn(this, (Extension.__proto__ || Object.getPrototypeOf(Extension)).call(this, json));
_.merge(_this3, json);
_this3.content_type = "Extension";
return _this3;
}
_createClass(Extension, [{
key: 'mapContentToLocalProperties',
value: function mapContentToLocalProperties(contentObject) {
_get(Extension.prototype.__proto__ || Object.getPrototypeOf(Extension.prototype), 'mapContentToLocalProperties', this).call(this, contentObject);
this.name = contentObject.name;
this.url = contentObject.url;
this.actions = contentObject.actions.map(function (action) {
return new Action(action);
});
}
}, {
key: 'updateFromExternalResponseItem',
value: function updateFromExternalResponseItem(externalResponseItem) {
_.merge(this, externalResponseItem);
this.actions = externalResponseItem.actions.map(function (action) {
return new Action(action);
});
}
}, {
key: 'referenceParams',
value: function referenceParams() {
return null;
}
}, {
key: 'structureParams',
value: function structureParams() {
var params = {
name: this.name,
url: this.url,
actions: this.actions
};
_.merge(params, _get(Extension.prototype.__proto__ || Object.getPrototypeOf(Extension.prototype), 'structureParams', this).call(this));
return params;
}
}]);
return Extension;
}(Item);
; ;
var Note = function (_Item2) { var Note = function (_Item2) {
_inherits(Note, _Item2); _inherits(Note, _Item2);
@@ -1932,7 +1973,7 @@ var User = function User(json_obj) {
return this.createRequestParamsForItem(item, options.additionalFields); return this.createRequestParamsForItem(item, options.additionalFields);
}.bind(this)); }.bind(this));
console.log("syncing items", request.items); // console.log("syncing items", request.items);
if (this.syncToken) { if (this.syncToken) {
request.sync_token = this.syncToken; request.sync_token = this.syncToken;
@@ -2607,33 +2648,186 @@ angular.module('app.frontend').directive('typewrite', ['$timeout', function ($ti
}]); }]);
; ;
var ExtensionManager = function () { var ExtensionManager = function () {
function ExtensionManager(Restangular, modelManager) { function ExtensionManager(Restangular, modelManager, apiController) {
_classCallCheck(this, ExtensionManager); _classCallCheck(this, ExtensionManager);
this.Restangular = Restangular; this.Restangular = Restangular;
this.modelManager = modelManager; this.modelManager = modelManager;
this.extensions = []; this.apiController = apiController;
this.enabledRepeatActions = []; this.enabledRepeatActionUrls = JSON.parse(localStorage.getItem("enabledRepeatActionUrls")) || [];
this.enabledRepeatActionUrls = localStorage.getItem("enabled_ext_urls") || [];
modelManager.addItemSyncObserver("extensionManager", "Extension", function (items) {
var _iteratorNormalCompletion3 = true;
var _didIteratorError3 = false;
var _iteratorError3 = undefined;
try {
for (var _iterator3 = items[Symbol.iterator](), _step3; !(_iteratorNormalCompletion3 = (_step3 = _iterator3.next()).done); _iteratorNormalCompletion3 = true) {
var ext = _step3.value;
var _iteratorNormalCompletion4 = true;
var _didIteratorError4 = false;
var _iteratorError4 = undefined;
try {
for (var _iterator4 = ext.actions[Symbol.iterator](), _step4; !(_iteratorNormalCompletion4 = (_step4 = _iterator4.next()).done); _iteratorNormalCompletion4 = true) {
var action = _step4.value;
if (this.enabledRepeatActionUrls.includes(action.url)) {
this.enableRepeatAction(action, ext);
}
}
} catch (err) {
_didIteratorError4 = true;
_iteratorError4 = err;
} finally {
try {
if (!_iteratorNormalCompletion4 && _iterator4.return) {
_iterator4.return();
}
} finally {
if (_didIteratorError4) {
throw _iteratorError4;
}
}
}
}
} catch (err) {
_didIteratorError3 = true;
_iteratorError3 = err;
} finally {
try {
if (!_iteratorNormalCompletion3 && _iterator3.return) {
_iterator3.return();
}
} finally {
if (_didIteratorError3) {
throw _iteratorError3;
}
}
}
}.bind(this));
} }
_createClass(ExtensionManager, [{ _createClass(ExtensionManager, [{
key: 'actionWithURL',
value: function actionWithURL(url) {
var _iteratorNormalCompletion5 = true;
var _didIteratorError5 = false;
var _iteratorError5 = undefined;
try {
for (var _iterator5 = this.extensions[Symbol.iterator](), _step5; !(_iteratorNormalCompletion5 = (_step5 = _iterator5.next()).done); _iteratorNormalCompletion5 = true) {
var extension = _step5.value;
return _.find(extension.actions, { url: url });
}
} catch (err) {
_didIteratorError5 = true;
_iteratorError5 = err;
} finally {
try {
if (!_iteratorNormalCompletion5 && _iterator5.return) {
_iterator5.return();
}
} finally {
if (_didIteratorError5) {
throw _iteratorError5;
}
}
}
}
}, {
key: 'addExtension', key: 'addExtension',
value: function addExtension(url) { value: function addExtension(url) {
this.retrieveExtensionFromServer(url, null);
}
}, {
key: 'retrieveExtensionFromServer',
value: function retrieveExtensionFromServer(url, callback) {
console.log("Registering URL", url); console.log("Registering URL", url);
this.Restangular.oneUrl(url, url).get().then(function (response) { this.Restangular.oneUrl(url, url).get().then(function (response) {
console.log("get response", response.plain()); console.log("get response", response.plain());
var extension = new Extension(response.plain()); var ext = this.handleExtensionLoadExternalResponseItem(url, response.plain());
this.registerExtension(extension); if (callback) {
callback(ext);
}
}.bind(this)).catch(function (response) { }.bind(this)).catch(function (response) {
console.log("Error registering extension", response); console.log("Error registering extension", response);
}); });
} }
}, { }, {
key: 'registerExtension', key: 'handleExtensionLoadExternalResponseItem',
value: function registerExtension(extension) { value: function handleExtensionLoadExternalResponseItem(url, externalResponseItem) {
this.extensions.push(extension); var extension = _.find(this.extensions, { url: url });
console.log("registered extensions", this.extensions); if (extension) {
extension.updateFromExternalResponseItem(externalResponseItem);
console.log("updated existing ext", extension);
} else {
console.log("creating new ext", externalResponseItem);
extension = new Extension(externalResponseItem);
extension.url = url;
extension.dirty = true;
this.modelManager.addItem(extension);
this.apiController.sync(null);
}
return extension;
}
}, {
key: 'refreshExtensionsFromServer',
value: function refreshExtensionsFromServer() {
var _iteratorNormalCompletion6 = true;
var _didIteratorError6 = false;
var _iteratorError6 = undefined;
try {
for (var _iterator6 = this.enabledRepeatActionUrls[Symbol.iterator](), _step6; !(_iteratorNormalCompletion6 = (_step6 = _iterator6.next()).done); _iteratorNormalCompletion6 = true) {
var url = _step6.value;
var action = this.actionWithURL(url);
this.disableRepeatAction(action);
}
} catch (err) {
_didIteratorError6 = true;
_iteratorError6 = err;
} finally {
try {
if (!_iteratorNormalCompletion6 && _iterator6.return) {
_iterator6.return();
}
} finally {
if (_didIteratorError6) {
throw _iteratorError6;
}
}
}
var _iteratorNormalCompletion7 = true;
var _didIteratorError7 = false;
var _iteratorError7 = undefined;
try {
for (var _iterator7 = this.extensions[Symbol.iterator](), _step7; !(_iteratorNormalCompletion7 = (_step7 = _iterator7.next()).done); _iteratorNormalCompletion7 = true) {
var ext = _step7.value;
this.retrieveExtensionFromServer(ext.url, function (extension) {
extension.dirty = true;
});
}
} catch (err) {
_didIteratorError7 = true;
_iteratorError7 = err;
} finally {
try {
if (!_iteratorNormalCompletion7 && _iterator7.return) {
_iterator7.return();
}
} finally {
if (_didIteratorError7) {
throw _iteratorError7;
}
}
}
} }
}, { }, {
key: 'executeAction', key: 'executeAction',
@@ -2657,8 +2851,7 @@ var ExtensionManager = function () {
value: function disableRepeatAction(action, extension) { value: function disableRepeatAction(action, extension) {
console.log("Disabling action", action); console.log("Disabling action", action);
_.pull(this.enabledRepeatActionUrls, action.url); _.pull(this.enabledRepeatActionUrls, action.url);
_.pull(this.enabledRepeatActions, action); this.modelManager.removeItemSyncObserver(action.url);
this.modelManager.removeItemObserver(action.url);
console.assert(this.isRepeatActionEnabled(action) == false); console.assert(this.isRepeatActionEnabled(action) == false);
} }
}, { }, {
@@ -2666,63 +2859,95 @@ var ExtensionManager = function () {
value: function enableRepeatAction(action, extension) { value: function enableRepeatAction(action, extension) {
console.log("Enabling repeat action", action); console.log("Enabling repeat action", action);
this.enabledRepeatActionUrls.push(action.url); if (!_.find(this.enabledRepeatActionUrls, action.url)) {
this.enabledRepeatActions.push(action); this.enabledRepeatActionUrls.push(action.url);
localStorage.setItem("enabledRepeatActionUrls", JSON.stringify(this.enabledRepeatActionUrls));
}
if (action.repeatType == "watch") { if (action.repeatType == "watch") {
var _iteratorNormalCompletion3 = true; var _iteratorNormalCompletion8 = true;
var _didIteratorError3 = false; var _didIteratorError8 = false;
var _iteratorError3 = undefined; var _iteratorError8 = undefined;
try { try {
for (var _iterator3 = action.structures[Symbol.iterator](), _step3; !(_iteratorNormalCompletion3 = (_step3 = _iterator3.next()).done); _iteratorNormalCompletion3 = true) { for (var _iterator8 = action.structures[Symbol.iterator](), _step8; !(_iteratorNormalCompletion8 = (_step8 = _iterator8.next()).done); _iteratorNormalCompletion8 = true) {
var structure = _step3.value; var structure = _step8.value;
this.modelManager.addItemObserver(action.url, structure.type, function (changedItems) { this.modelManager.addItemSyncObserver(action.url, structure.type, function (changedItems) {
this.triggerWatchAction(action, changedItems); this.triggerWatchAction(action, changedItems);
}.bind(this)); }.bind(this));
} }
} catch (err) { } catch (err) {
_didIteratorError3 = true; _didIteratorError8 = true;
_iteratorError3 = err; _iteratorError8 = err;
} finally { } finally {
try { try {
if (!_iteratorNormalCompletion3 && _iterator3.return) { if (!_iteratorNormalCompletion8 && _iterator8.return) {
_iterator3.return(); _iterator8.return();
} }
} finally { } finally {
if (_didIteratorError3) { if (_didIteratorError8) {
throw _iteratorError3; throw _iteratorError8;
} }
} }
} }
} }
} }
}, {
key: 'queueAction',
value: function queueAction(action, delay, changedItems) {
this.actionQueue = this.actionQueue || [];
if (_.find(this.actionQueue, action)) {
// console.log("Action already queued, skipping.")
return;
}
// console.log("Adding action to queue", action);
this.actionQueue.push(action);
setTimeout(function () {
console.log("Performing queued action", action);
this.triggerWatchAction(action, changedItems);
_.pull(this.actionQueue, action);
}.bind(this), delay * 1000);
}
}, { }, {
key: 'triggerWatchAction', key: 'triggerWatchAction',
value: function triggerWatchAction(action, changedItems) { value: function triggerWatchAction(action, changedItems) {
console.log("Watch action triggered", action, changedItems); // console.log("Watch action triggered", action, changedItems);
if (action.repeatFrequency > 0) { if (action.repeatFrequency > 0) {
var lastExecuted = action.lastExecuted; var lastExecuted = action.lastExecuted;
var diffInSeconds = (new Date() - lastExecuted) / 1000; var diffInSeconds = (new Date() - lastExecuted) / 1000;
console.log("last executed", action.lastExecuted, "diff", diffInSeconds, "repeatFreq", action.repeatFrequency);
if (diffInSeconds < action.repeatFrequency) { if (diffInSeconds < action.repeatFrequency) {
console.log("too frequent, returning"); var delay = action.repeatFrequency - diffInSeconds;
console.log("delaying action by", delay);
this.queueAction(action, delay, changedItems);
return; return;
} }
} }
console.log("Performing action immediately", action);
action.lastExecuted = new Date();
// console.log("setting last exectured", action.lastExecuted)
if (action.repeatVerb == "post") { if (action.repeatVerb == "post") {
var request = this.Restangular.oneUrl(action.url, action.url); var request = this.Restangular.oneUrl(action.url, action.url);
request.items = changedItems.map(function (item) { request.items = changedItems.map(function (item) {
var params = { uuid: item.uuid, content_type: item.content_type, content: item.content }; var params = { uuid: item.uuid, content_type: item.content_type, content: item.createContentJSONFromProperties() };
return params; return params;
}); });
request.post().then(function (response) { request.post().then(function (response) {
console.log("watch action response", response); // console.log("watch action response", response);
action.lastExecuted = new Date();
}); });
} }
} }
}, {
key: 'extensions',
get: function get() {
return this.modelManager.extensions;
}
}]); }]);
return ExtensionManager; return ExtensionManager;
@@ -2738,7 +2963,7 @@ angular.module('app.frontend').service('extensionManager', ExtensionManager);
return input ? $filter('date')(new Date(input), 'MM/dd/yyyy h:mm a') : ''; return input ? $filter('date')(new Date(input), 'MM/dd/yyyy h:mm a') : '';
}; };
}); });
;;angular.module('app.frontend').service('markdownRenderer', function ($sce) { ;angular.module('app.frontend').service('markdownRenderer', function ($sce) {
marked.setOptions({ marked.setOptions({
breaks: true, breaks: true,
@@ -2763,8 +2988,9 @@ var ModelManager = function () {
this.notes = []; this.notes = [];
this.tags = []; this.tags = [];
this.changeObservers = []; this.itemSyncObservers = [];
this.items = []; this.items = [];
this.extensions = [];
} }
_createClass(ModelManager, [{ _createClass(ModelManager, [{
@@ -2781,13 +3007,13 @@ var ModelManager = function () {
key: 'mapResponseItemsToLocalModelsOmittingFields', key: 'mapResponseItemsToLocalModelsOmittingFields',
value: function mapResponseItemsToLocalModelsOmittingFields(items, omitFields) { value: function mapResponseItemsToLocalModelsOmittingFields(items, omitFields) {
var models = []; var models = [];
var _iteratorNormalCompletion4 = true; var _iteratorNormalCompletion9 = true;
var _didIteratorError4 = false; var _didIteratorError9 = false;
var _iteratorError4 = undefined; var _iteratorError9 = undefined;
try { try {
for (var _iterator4 = items[Symbol.iterator](), _step4; !(_iteratorNormalCompletion4 = (_step4 = _iterator4.next()).done); _iteratorNormalCompletion4 = true) { for (var _iterator9 = items[Symbol.iterator](), _step9; !(_iteratorNormalCompletion9 = (_step9 = _iterator9.next()).done); _iteratorNormalCompletion9 = true) {
var json_obj = _step4.value; var json_obj = _step9.value;
json_obj = _.omit(json_obj, omitFields || []); json_obj = _.omit(json_obj, omitFields || []);
var item = this.findItem(json_obj["uuid"]); var item = this.findItem(json_obj["uuid"]);
@@ -2815,16 +3041,46 @@ var ModelManager = function () {
models.push(item); models.push(item);
} }
} catch (err) { } catch (err) {
_didIteratorError4 = true; _didIteratorError9 = true;
_iteratorError4 = err; _iteratorError9 = err;
} finally { } finally {
try { try {
if (!_iteratorNormalCompletion4 && _iterator4.return) { if (!_iteratorNormalCompletion9 && _iterator9.return) {
_iterator4.return(); _iterator9.return();
} }
} finally { } finally {
if (_didIteratorError4) { if (_didIteratorError9) {
throw _iteratorError4; throw _iteratorError9;
}
}
}
var _iteratorNormalCompletion10 = true;
var _didIteratorError10 = false;
var _iteratorError10 = undefined;
try {
for (var _iterator10 = this.itemSyncObservers[Symbol.iterator](), _step10; !(_iteratorNormalCompletion10 = (_step10 = _iterator10.next()).done); _iteratorNormalCompletion10 = true) {
var observer = _step10.value;
var relevantItems = models.filter(function (item) {
return item.content_type == observer.type;
});
if (relevantItems.length > 0) {
observer.callback(relevantItems);
}
}
} catch (err) {
_didIteratorError10 = true;
_iteratorError10 = err;
} finally {
try {
if (!_iteratorNormalCompletion10 && _iterator10.return) {
_iterator10.return();
}
} finally {
if (_didIteratorError10) {
throw _iteratorError10;
} }
} }
} }
@@ -2839,6 +3095,8 @@ var ModelManager = function () {
return new Note(json_obj); return new Note(json_obj);
} else if (json_obj.content_type == "Tag") { } else if (json_obj.content_type == "Tag") {
return new Tag(json_obj); return new Tag(json_obj);
} else if (json_obj.content_type == "Extension") {
return new Extension(json_obj);
} else { } else {
return new Item(json_obj); return new Item(json_obj);
} }
@@ -2857,6 +3115,10 @@ var ModelManager = function () {
if (!_.find(this.notes, { uuid: item.uuid })) { if (!_.find(this.notes, { uuid: item.uuid })) {
this.notes.unshift(item); this.notes.unshift(item);
} }
} else if (item.content_type == "Extension") {
if (!_.find(this.extensions, { uuid: item.uuid })) {
this.extensions.unshift(item);
}
} }
}.bind(this)); }.bind(this));
} }
@@ -2875,19 +3137,18 @@ var ModelManager = function () {
}, { }, {
key: 'resolveReferencesForItem', key: 'resolveReferencesForItem',
value: function resolveReferencesForItem(item) { value: function resolveReferencesForItem(item) {
var contentObject = item.contentObject; var contentObject = item.contentObject;
if (!contentObject.references) { if (!contentObject.references) {
return; return;
} }
var _iteratorNormalCompletion5 = true; var _iteratorNormalCompletion11 = true;
var _didIteratorError5 = false; var _didIteratorError11 = false;
var _iteratorError5 = undefined; var _iteratorError11 = undefined;
try { try {
for (var _iterator5 = contentObject.references[Symbol.iterator](), _step5; !(_iteratorNormalCompletion5 = (_step5 = _iterator5.next()).done); _iteratorNormalCompletion5 = true) { for (var _iterator11 = contentObject.references[Symbol.iterator](), _step11; !(_iteratorNormalCompletion11 = (_step11 = _iterator11.next()).done); _iteratorNormalCompletion11 = true) {
var reference = _step5.value; var reference = _step11.value;
var referencedItem = this.findItem(reference.uuid); var referencedItem = this.findItem(reference.uuid);
if (referencedItem) { if (referencedItem) {
@@ -2898,16 +3159,16 @@ var ModelManager = function () {
} }
} }
} catch (err) { } catch (err) {
_didIteratorError5 = true; _didIteratorError11 = true;
_iteratorError5 = err; _iteratorError11 = err;
} finally { } finally {
try { try {
if (!_iteratorNormalCompletion5 && _iterator5.return) { if (!_iteratorNormalCompletion11 && _iterator11.return) {
_iterator5.return(); _iterator11.return();
} }
} finally { } finally {
if (_didIteratorError5) { if (_didIteratorError11) {
throw _iteratorError5; throw _iteratorError11;
} }
} }
} }
@@ -2922,46 +3183,14 @@ var ModelManager = function () {
}); });
} }
}, { }, {
key: 'addItemObserver', key: 'addItemSyncObserver',
value: function addItemObserver(id, type, callback) { value: function addItemSyncObserver(id, type, callback) {
this.changeObservers.push({ id: id, type: type, callback: callback }); this.itemSyncObservers.push({ id: id, type: type, callback: callback });
} }
}, { }, {
key: 'removeItemObserver', key: 'removeItemSyncObserver',
value: function removeItemObserver(id) { value: function removeItemSyncObserver(id) {
_.remove(this.changeObservers, _.find(this.changeObservers, { id: id })); _.remove(this.itemSyncObservers, _.find(this.itemSyncObservers, { id: id }));
}
}, {
key: 'notifyObserversOfSyncCompletion',
value: function notifyObserversOfSyncCompletion() {
var _iteratorNormalCompletion6 = true;
var _didIteratorError6 = false;
var _iteratorError6 = undefined;
try {
for (var _iterator6 = this.changeObservers[Symbol.iterator](), _step6; !(_iteratorNormalCompletion6 = (_step6 = _iterator6.next()).done); _iteratorNormalCompletion6 = true) {
var observer = _step6.value;
var changedItems = this.dirtyItems.filter(function (item) {
return item.content_type == observer.type;
});
console.log("observer:", observer, "items", changedItems);
observer.callback(changedItems);
}
} catch (err) {
_didIteratorError6 = true;
_iteratorError6 = err;
} finally {
try {
if (!_iteratorNormalCompletion6 && _iterator6.return) {
_iterator6.return();
}
} finally {
if (_didIteratorError6) {
throw _iteratorError6;
}
}
}
} }
}, { }, {
key: 'getDirtyItems', key: 'getDirtyItems',
@@ -2973,8 +3202,6 @@ var ModelManager = function () {
}, { }, {
key: 'clearDirtyItems', key: 'clearDirtyItems',
value: function clearDirtyItems() { value: function clearDirtyItems() {
this.notifyObserversOfSyncCompletion();
this.getDirtyItems().forEach(function (item) { this.getDirtyItems().forEach(function (item) {
item.dirty = false; item.dirty = false;
}); });
@@ -2995,6 +3222,8 @@ var ModelManager = function () {
_.pull(this.tags, item); _.pull(this.tags, item);
} else if (item.content_type == "Note") { } else if (item.content_type == "Note") {
_.pull(this.notes, item); _.pull(this.notes, item);
} else if (item.content_type == "Extension") {
_.pull(this.extensions, item);
} }
} }

File diff suppressed because one or more lines are too long