contextual extension menu

This commit is contained in:
Mo Bitar
2017-01-06 13:44:25 -06:00
parent 1a2bcb39ca
commit 71b6e666b4
15 changed files with 258 additions and 52 deletions

View File

@@ -18,7 +18,6 @@ class Item {
}
get contentObject() {
// console.log("getting content object from content", this.content);
if(!this.content) {
return {};
}

View File

@@ -56,6 +56,12 @@ class Extension extends Item {
})
}
actionsWithContextForItem(item) {
return this.actions.filter(function(action){
return action.context == item.content_type || action.context == "Item";
})
}
mapContentToLocalProperties(contentObject) {
super.mapContentToLocalProperties(contentObject)
this.name = contentObject.name;

View File

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

View File

@@ -0,0 +1,30 @@
class ContextualExtensionsMenu {
constructor() {
this.restrict = "E";
this.templateUrl = "frontend/directives/contextual-menu.html";
this.scope = {
item: "="
};
}
controller($scope, modelManager, extensionManager) {
$scope.extensions = extensionManager.extensionsInContextOfItem($scope.item);
$scope.executeAction = function(action, extension) {
action.running = true;
extensionManager.executeAction(action, extension, $scope.item, function(response){
action.running = false;
})
}
$scope.accessTypeForExtension = function(extension) {
return extensionManager.extensionUsesEncryptedData(extension) ? "encrypted" : "decrypted";
}
}
}
angular.module('app.frontend').directive('contextualExtensionsMenu', () => new ContextualExtensionsMenu);

View File

@@ -25,6 +25,12 @@ class ExtensionManager {
return this.modelManager.extensions;
}
extensionsInContextOfItem(item) {
return this.extensions.filter(function(ext){
return ext.actionsWithContextForItem(item).length > 0;
})
}
actionWithURL(url) {
for (var extension of this.extensions) {
return _.find(extension.actions, {url: url})
@@ -115,14 +121,20 @@ class ExtensionManager {
}
case "post": {
var items;
var params = {};
if(action.all) {
items = this.modelManager.allItemsMatchingTypes(action.content_types);
var items = this.modelManager.allItemsMatchingTypes(action.content_types);
params.items = items.map(function(item){
var params = this.outgoingParamsForItem(item, extension);
return params;
}.bind(this))
} else {
items = [item];
params.item = this.outgoingParamsForItem(item, extension);
}
this.performPost(action, extension, items, function(items){
this.performPost(action, extension, params, function(items){
callback(items);
});
}
@@ -149,7 +161,7 @@ class ExtensionManager {
}
enableRepeatAction(action, extension) {
console.log("Enabling repeat action", action);
// console.log("Enabling repeat action", action);
if(!_.find(this.enabledRepeatActionUrls, action.url)) {
this.enabledRepeatActionUrls.push(action.url);
@@ -205,7 +217,12 @@ class ExtensionManager {
action.lastExecuted = new Date();
if(action.verb == "post") {
this.performPost(action, extension, changedItems, null);
var params = {};
params.items = changedItems.map(function(item){
var params = this.outgoingParamsForItem(item, extension);
return params;
}.bind(this))
this.performPost(action, extension, params, null);
} else {
// todo
}
@@ -215,12 +232,9 @@ class ExtensionManager {
return this.apiController.paramsForExtension(item, this.extensionUsesEncryptedData(extension));
}
performPost(action, extension, items, callback) {
performPost(action, extension, params, callback) {
var request = this.Restangular.oneUrl(action.url, action.url);
request.items = items.map(function(item){
var params = this.outgoingParamsForItem(item, extension);
return params;
}.bind(this))
_.merge(request, params);
request.post().then(function(response){
// console.log("watch action response", response);

View File

@@ -140,7 +140,7 @@ class ModelManager {
item.addItemAsRelationship(referencedItem);
referencedItem.addItemAsRelationship(item);
} else {
console.log("Unable to find item:", reference.uuid);
// console.log("Unable to find item:", reference.uuid);
}
}
}
@@ -185,7 +185,9 @@ class ModelManager {
setItemToBeDeleted(item) {
item.deleted = true;
item.setDirty(true);
if(!item.dummy) {
item.setDirty(true);
}
item.removeAllRelationships();
}

View File

@@ -30,7 +30,7 @@
}
.nt-dropdown-menu.dark {
background-color: $selection-color;
background-color: white;
color: $selected-text-color;
li {
@@ -85,18 +85,27 @@
bottom: 0px;
background-color: #f1f1f1;
color: $selected-text-color;
// padding-top: 5px;
height: 28px;
cursor: default;
ol, ul {
margin-top: 7px;
margin-top: 5px;
margin-bottom: 10px;
&.dropdown-menu {
margin-top: 10px;
}
}
ul {
li {
text-align: left;
&.sep {
margin: 6px;
display: block;
}
a {
font-size: 13px;
font-weight: bold;

View File

@@ -0,0 +1,64 @@
.dropdown-menu.contextual-menu {
.extension {
&:not(:first-child) {
margin-top: 18px;
}
.ext-header {
background-color: #ededed;
border-bottom: 1px solid #d3d3d3;
padding-top: 12px;
padding-left: 10px;
padding-bottom: 10px;
> .name {
font-size: 14px;
}
> .access {
font-size: 12px;
opacity: 0.5;
font-weight: normal;
margin-top: 2px;
}
}
ul {
margin-top: 0px;
margin-bottom: 0px;
list-style:none;
padding-left:0;
li {
cursor: pointer;
height: auto;
&.action {
padding: 10px;
border-bottom: 1px solid rgba(black, 0.1);
background-color: rgba(white, 0.9);
&:hover {
background-color: rgba(gray, 0.05);
}
> .name {
font-weight: bold;
font-size: 14px;
}
> .desc {
font-weight: normal;
opacity: 0.5;
margin-top: 1px;
font-size: 12px;
}
}
}
}
}
}

View File

@@ -7,6 +7,7 @@ $dark-gray: #2e2e2e;
@import "app/tags";
@import "app/notes";
@import "app/editor";
@import "app/directives";
@font-face {
font-family: 'icomoon';

View File

@@ -0,0 +1,13 @@
%ul.dropdown-menu.dropdown-menu-left.nt-dropdown-menu.dark.contextual-menu
.extension{"ng-repeat" => "extension in extensions"}
.ext-header
.name {{extension.name}}
.access
Can access your data
%strong {{accessTypeForExtension(extension)}}
%ul
%li.action{"ng-repeat" => "action in extension.actionsWithContextForItem(item)", "ng-click" => "executeAction(action, extension)"}
.name {{action.label}}
.desc {{action.desc}}
%span{"ng-if" => "action.running"}
.spinner{"style" => "margin-top: 3px;"}

View File

@@ -9,7 +9,7 @@
.section-menu
%ul.nav.nav-pills
%li.dropdown
%a.dropdown-toggle{"ng-click" => "ctrl.clickedMenu()"}
%a.dropdown-toggle{"ng-click" => "ctrl.clickedMenu(); ctrl.showExtensions = false"}
File
%span.caret{"ng-if" => "!ctrl.note.locked"}
%span{"ng-if" => " ctrl.note.locked"}
@@ -17,20 +17,28 @@
%span.sr-only
%ul.dropdown-menu.dropdown-menu-left.nt-dropdown-menu.dark{"ng-if" => "ctrl.showMenu && !ctrl.note.locked"}
%li
%a.text{"ng-click" => "ctrl.selectedMenuItem(); ctrl.toggleFullScreen()"} Toggle Fullscreen
%li{"ng-click" => "ctrl.selectedMenuItem(); ctrl.toggleFullScreen()"}
.text Toggle Fullscreen
.shortcut Cmd + O
%li
%a.text{"ng-click" => "ctrl.selectedMenuItem(); ctrl.toggleMarkdown()"} Toggle Markdown Preview
%li{"ng-click" => "ctrl.selectedMenuItem(); ctrl.toggleMarkdown()"}
.text Toggle Markdown Preview
.shortcut Cmd + M
%li{"ng-if" => "!ctrl.note.isSharedIndividually()"}
%a.text{"ng-click" => "ctrl.selectedMenuItem(); ctrl.shareNote()"} Share
%li{"ng-if" => "ctrl.note.isSharedIndividually()"}
%a.text{"ng-click" => "ctrl.selectedMenuItem(); ctrl.editUrlPressed()"} Edit URL
%li{"ng-if" => "ctrl.note.isSharedIndividually()"}
%a.text{"ng-click" => "ctrl.selectedMenuItem(); ctrl.unshareNote()"} Unshare
%li
%a.text{"ng-click" => "ctrl.deleteNote()"} Delete
%li{"ng-if" => "!ctrl.note.isSharedIndividually()", "ng-click" => "ctrl.selectedMenuItem(); ctrl.shareNote()"}
.text Share
%li{"ng-if" => "ctrl.note.isSharedIndividually()", "ng-click" => "ctrl.selectedMenuItem(); ctrl.editUrlPressed()"}
.text Edit URL
%li{"ng-if" => "ctrl.note.isSharedIndividually()", "ng-click" => "ctrl.selectedMenuItem(); ctrl.unshareNote()"}
.text Unshare
%li{"ng-click" => "ctrl.deleteNote()"}
.text Delete
%li.sep
%li.dropdown
%a.dropdown-toggle{"ng-click" => "ctrl.showExtensions = !ctrl.showExtensions; ctrl.showMenu = false"}
Extensions
%span.caret
%span.sr-only
%contextual-extensions-menu{"ng-if" => "ctrl.showExtensions", "item" => "ctrl.note"}
.markdown.icon{"ng-if" => "ctrl.editorMode == 'preview'", "ng-click" => "ctrl.showMarkdown = !ctrl.showMarkdown"}
.icon-markdown
.panel.panel-default.info-panel{"ng-if" => "ctrl.showMarkdown"}

View File

@@ -114,11 +114,11 @@
.encryption-type
%span {{action.encryptionModeString}}
.execute
%a{"ng-click" => "ctrl.selectedAction(action, extension)"}
%span{"ng-if" => "action.repeat_mode"}
%span{"ng-if" => "ctrl.extensionManager.isRepeatActionEnabled(action)", "ng-click" => "ctrl.extensionManager.disableRepeatAction(action, extension)"} Disable
%span{"ng-if" => "!ctrl.extensionManager.isRepeatActionEnabled(action)", "ng-click" => "ctrl.extensionManager.enableRepeatAction(action, extension)"} Enable
%span{"ng-if" => "!action.repeat_mode && !action.running"}
%a{"ng-if" => "action.repeat_mode"}
%span{"ng-if" => "ctrl.extensionManager.isRepeatActionEnabled(action)", "ng-click" => "ctrl.extensionManager.disableRepeatAction(action, extension)"} Disable
%span{"ng-if" => "!ctrl.extensionManager.isRepeatActionEnabled(action)", "ng-click" => "ctrl.extensionManager.enableRepeatAction(action, extension)"} Enable
%a{"ng-if" => "!action.repeat_mode", "ng-click" => "ctrl.selectedAction(action, extension)"}
%span{"ng-if" => "!action.running"}
Run
%span{"ng-if" => "action.running"}
.spinner{"style" => "margin-top: 3px;"}

View File

@@ -13,6 +13,7 @@
File
%span.caret
%span.sr-only
%ul.dropdown-menu.dropdown-menu-left.nt-dropdown-menu.dark{"ng-if" => "ctrl.showMenu"}
%li{"ng-if" => "!ctrl.tag.isPublic()"}
%a.text{"ng-click" => "ctrl.selectedMenuItem(); ctrl.selectedTagShare($event)"} Share Tag
@@ -20,6 +21,7 @@
%a.text{"ng-click" => "ctrl.selectedMenuItem(); ctrl.selectedTagUnshare()"} Unshare Tag
%li{"ng-if" => "!ctrl.tag.all"}
%a.text{"ng-click" => "ctrl.selectedMenuItem(); ctrl.selectedTagDelete()"} Delete Tag
.menu-right-container
.public-link{"ng-if" => "ctrl.tag.isPublic()"}
%a.url{"ng-if" => "!ctrl.editingUrl", "href" => "{{ctrl.tag.presentationURL()}}", "target" => "_blank"}

View File

@@ -1466,7 +1466,6 @@ var Item = function () {
}, {
key: 'contentObject',
get: function get() {
// console.log("getting content object from content", this.content);
if (!this.content) {
return {};
}
@@ -1584,6 +1583,13 @@ var Extension = function (_Item) {
return action.context == "global";
});
}
}, {
key: 'actionsWithContextForItem',
value: function actionsWithContextForItem(item) {
return this.actions.filter(function (action) {
return action.context == item.content_type || action.context == "Item";
});
}
}, {
key: 'mapContentToLocalProperties',
value: function mapContentToLocalProperties(contentObject) {
@@ -2091,7 +2097,7 @@ var User = function User(json_obj) {
return this.createRequestParamsForItem(item, options.additionalFields);
}.bind(this));
console.log("syncing items", request.items);
// console.log("syncing items", request.items);
if (this.syncToken) {
request.sync_token = this.syncToken;
@@ -2447,6 +2453,42 @@ var User = function User(json_obj) {
}
};
}]);
;
var ContextualExtensionsMenu = function () {
function ContextualExtensionsMenu() {
_classCallCheck(this, ContextualExtensionsMenu);
this.restrict = "E";
this.templateUrl = "frontend/directives/contextual-menu.html";
this.scope = {
item: "="
};
}
_createClass(ContextualExtensionsMenu, [{
key: 'controller',
value: function controller($scope, modelManager, extensionManager) {
$scope.extensions = extensionManager.extensionsInContextOfItem($scope.item);
$scope.executeAction = function (action, extension) {
action.running = true;
extensionManager.executeAction(action, extension, $scope.item, function (response) {
action.running = false;
});
};
$scope.accessTypeForExtension = function (extension) {
return extensionManager.extensionUsesEncryptedData(extension) ? "encrypted" : "decrypted";
};
}
}]);
return ContextualExtensionsMenu;
}();
angular.module('app.frontend').directive('contextualExtensionsMenu', function () {
return new ContextualExtensionsMenu();
});
;angular.module('app.frontend').directive('draggable', function () {
return {
scope: {
@@ -2841,6 +2883,13 @@ var ExtensionManager = function () {
}
_createClass(ExtensionManager, [{
key: 'extensionsInContextOfItem',
value: function extensionsInContextOfItem(item) {
return this.extensions.filter(function (ext) {
return ext.actionsWithContextForItem(item).length > 0;
});
}
}, {
key: 'actionWithURL',
value: function actionWithURL(url) {
var _iteratorNormalCompletion7 = true;
@@ -3004,14 +3053,19 @@ var ExtensionManager = function () {
case "post":
{
var items;
var params = {};
if (action.all) {
items = this.modelManager.allItemsMatchingTypes(action.content_types);
var items = this.modelManager.allItemsMatchingTypes(action.content_types);
params.items = items.map(function (item) {
var params = this.outgoingParamsForItem(item, extension);
return params;
}.bind(this));
} else {
items = [item];
params.item = this.outgoingParamsForItem(item, extension);
}
this.performPost(action, extension, items, function (items) {
this.performPost(action, extension, params, function (items) {
callback(items);
});
}
@@ -3040,7 +3094,7 @@ var ExtensionManager = function () {
}, {
key: 'enableRepeatAction',
value: function enableRepeatAction(action, extension) {
console.log("Enabling repeat action", action);
// console.log("Enabling repeat action", action);
if (!_.find(this.enabledRepeatActionUrls, action.url)) {
this.enabledRepeatActionUrls.push(action.url);
@@ -3097,7 +3151,12 @@ var ExtensionManager = function () {
action.lastExecuted = new Date();
if (action.verb == "post") {
this.performPost(action, extension, changedItems, null);
var params = {};
params.items = changedItems.map(function (item) {
var params = this.outgoingParamsForItem(item, extension);
return params;
}.bind(this));
this.performPost(action, extension, params, null);
} else {
// todo
}
@@ -3109,12 +3168,9 @@ var ExtensionManager = function () {
}
}, {
key: 'performPost',
value: function performPost(action, extension, items, callback) {
value: function performPost(action, extension, params, callback) {
var request = this.Restangular.oneUrl(action.url, action.url);
request.items = items.map(function (item) {
var params = this.outgoingParamsForItem(item, extension);
return params;
}.bind(this));
_.merge(request, params);
request.post().then(function (response) {
// console.log("watch action response", response);
@@ -3389,7 +3445,7 @@ var ModelManager = function () {
item.addItemAsRelationship(referencedItem);
referencedItem.addItemAsRelationship(item);
} else {
console.log("Unable to find item:", reference.uuid);
// console.log("Unable to find item:", reference.uuid);
}
}
} catch (err) {
@@ -3454,7 +3510,9 @@ var ModelManager = function () {
key: 'setItemToBeDeleted',
value: function setItemToBeDeleted(item) {
item.deleted = true;
item.setDirty(true);
if (!item.dummy) {
item.setDirty(true);
}
item.removeAllRelationships();
}
}, {

File diff suppressed because one or more lines are too long