no extensions box

This commit is contained in:
Mo Bitar
2017-05-16 11:55:52 -05:00
parent b65ed8c90c
commit 5ec4797d85
13 changed files with 315 additions and 156 deletions

View File

@@ -8,4 +8,14 @@ class BaseCtrl {
}
}
function getParameterByName(name, url) {
name = name.replace(/[\[\]]/g, "\\$&");
var regex = new RegExp("[?&]" + name + "(=([^&#]*)|&|#|$)"),
results = regex.exec(url);
if (!results) return null;
if (!results[2]) return '';
return decodeURIComponent(results[2].replace(/\+/g, " "));
}
angular.module('app.frontend').controller('BaseCtrl', BaseCtrl);

View File

@@ -55,6 +55,11 @@ angular.module('app.frontend')
this.showExtensionsMenu = !this.showExtensionsMenu;
}
$timeout(function(){
// testing
this.toggleExtensions();
}.bind(this))
this.toggleIO = function() {
this.showIOMenu = !this.showIOMenu;
this.showExtensionsMenu = false;

View File

@@ -26,7 +26,7 @@ class ContextualExtensionsMenu {
})
}
$scope.executeAction = function(action, extension) {
$scope.executeAction = function(action, extension, parentAction) {
if(!$scope.isActionEnabled(action, extension)) {
alert("This action requires " + action.access_type + " access to this note. You can change this setting in the Extensions menu on the bottom of the app.");
return;
@@ -41,7 +41,13 @@ class ContextualExtensionsMenu {
$scope.handleActionResponse(action, response);
// reload extension actions
extensionManager.loadExtensionInContextOfItem(extension, $scope.item, null);
extensionManager.loadExtensionInContextOfItem(extension, $scope.item, function(ext){
// keep nested state
if(parentAction) {
var matchingAction = _.find(ext.actions, {label: parentAction.label});
matchingAction.showNestedActions = true;
}
});
})
}

View File

@@ -20,25 +20,6 @@ class EditorMenu {
$scope.callback()(editor);
}
$scope.deleteEditor = function(editor) {
if(confirm("Are you sure you want to delete this editor?")) {
editorManager.deleteEditor(editor);
}
}
$scope.setDefaultEditor = function(editor) {
editorManager.setDefaultEditor(editor);
}
$scope.removeDefaultEditor = function(editor) {
editorManager.removeDefaultEditor(editor);
}
$scope.submitNewEditorRequest = function() {
editorManager.addNewEditorFromURL($scope.formData.url);
$scope.formData = {};
}
}
}

View File

@@ -7,37 +7,14 @@ class GlobalExtensionsMenu {
};
}
controller($scope, extensionManager, syncManager, modelManager, themeManager) {
controller($scope, extensionManager, syncManager, modelManager, themeManager, editorManager) {
'ngInject';
$scope.formData = {};
$scope.extensionManager = extensionManager;
$scope.themeManager = themeManager;
$scope.state = {showDataExts: true, showThemes: true};
$scope.toggleExtensionForm = function() {
$scope.newExtensionData = {};
$scope.showNewExtensionForm = !$scope.showNewExtensionForm;
}
$scope.submitNewExtensionForm = function() {
if($scope.newExtensionData.url) {
extensionManager.addExtension($scope.newExtensionData.url, function(response){
if(!response) {
if($scope.newExtensionData.url.indexOf("type=sf") != -1) {
alert("Unable to register this extension. You are attempting to register a Standard File extension in Standard Notes. You should instead open your Standard File Dashboard and register this extension there.");
} else if($scope.newExtensionData.url.indexOf("name=") != -1) {
// user is mistakenly trying to register editor extension, most likely
alert("Unable to register this extension. It looks like you may be trying to install an editor extension. To do that, click 'Editor' under the current note's title.");
} else {
alert("Unable to register this extension. Make sure the link is valid and try again.");
}
} else {
$scope.newExtensionData.url = "";
$scope.showNewExtensionForm = false;
}
})
}
}
$scope.editorManager = editorManager;
$scope.selectedAction = function(action, extension) {
extensionManager.executeAction(action, extension, null, function(response){
@@ -55,7 +32,7 @@ class GlobalExtensionsMenu {
extensionManager.changeExtensionEncryptionFormat(encrypted, extension);
}
$scope.deleteExtension = function(extension) {
$scope.deleteActionExtension = function(extension) {
if(confirm("Are you sure you want to delete this extension?")) {
extensionManager.deleteExtension(extension);
}
@@ -67,11 +44,6 @@ class GlobalExtensionsMenu {
}
}
$scope.submitTheme = function() {
themeManager.submitTheme($scope.state.themeUrl);
$scope.state.themeUrl = "";
}
$scope.deleteTheme = function(theme) {
if(confirm("Are you sure you want to delete this theme?")) {
themeManager.deactivateTheme(theme);
@@ -80,6 +52,75 @@ class GlobalExtensionsMenu {
}
}
// Editors
$scope.deleteEditor = function(editor) {
if(confirm("Are you sure you want to delete this editor?")) {
editorManager.deleteEditor(editor);
}
}
$scope.setDefaultEditor = function(editor) {
editorManager.setDefaultEditor(editor);
}
$scope.removeDefaultEditor = function(editor) {
editorManager.removeDefaultEditor(editor);
}
// Installation
$scope.submitInstallLink = function() {
var link = $scope.formData.installLink;
if(!link) {
return;
}
var completion = function() {
$scope.formData.installLink = "";
}
var type = getParameterByName("type", link);
if(type == "sf" || type == "sync") {
$scope.handleSyncAdapterLink(link, completion);
} else if(type == "editor") {
$scope.handleEditorLink(link, completion);
} else if(link.indexOf(".css") != -1 || type == "theme") {
$scope.handleThemeLink(link, completion);
} else {
$scope.handleActionLink(link, completion);
}
}
$scope.handleSyncAdapterLink = function(link, completion) {
completion();
}
$scope.handleThemeLink = function(link, completion) {
themeManager.submitTheme(link);
completion();
}
$scope.handleActionLink = function(link, completion) {
if(link) {
extensionManager.addExtension(link, function(response){
if(!response) {
alert("Unable to register this extension. Make sure the link is valid and try again.");
} else {
completion();
}
})
}
}
$scope.handleEditorLink = function(link, completion) {
editorManager.addNewEditorFromURL(link);
completion();
}
}
}

View File

@@ -1,6 +1,5 @@
class EditorManager {
constructor($rootScope, modelManager, syncManager) {
this.syncManager = syncManager;
this.modelManager = modelManager;
@@ -79,7 +78,7 @@ class EditorManager {
}
addNewEditorFromURL(url) {
var name = this.getParameterByName("name", url);
var name = getParameterByName("name", url);
var editor = this.modelManager.createItem({
content_type: this.editorType,
url: url,
@@ -96,15 +95,6 @@ class EditorManager {
this.syncManager.sync();
}
getParameterByName(name, url) {
name = name.replace(/[\[\]]/g, "\\$&");
var regex = new RegExp("[?&]" + name + "(=([^&#]*)|&|#|$)"),
results = regex.exec(url);
if (!results) return null;
if (!results[2]) return '';
return decodeURIComponent(results[2].replace(/\+/g, " "));
}
}
angular.module('app.frontend').service('editorManager', EditorManager);

View File

@@ -84,6 +84,10 @@ class ThemeManager {
}
displayNameForThemeFile(fileName) {
let fromParam = getParameterByName("name", fileName);
if(fromParam) {
return fromParam;
}
let name = fileName.split(".")[0];
let cleaned = name.split("-").join(" ");
return this.capitalizeString(cleaned);

View File

@@ -10,6 +10,7 @@
width: 100vw;
height: 100vh;
background-color: rgba(gray, 0.3);
color: black;
.content {
box-shadow: 0 6px 12px rgba(0, 0, 0, 0.175);
@@ -23,3 +24,90 @@
overflow-y: scroll;
}
}
#global-ext-menu {
color: black;
.panel-body {
padding: 0;
}
.container {
padding: 13px 18px;
&.no-bottom {
padding-bottom: 0;
}
}
p {
font-size: 14px;
&.small {
font-size: 12px;
}
}
.link-group {
a {
margin-right: 2px;
}
}
.blue-box {
background-color: $blue-color;
color: white;
border-radius: 4px;
padding: 16px 20px;
button {
background-color: white;
color: $blue-color;
border-radius: 3px;
font-weight: bold;
padding: 6px 20px;
width: 100%;
&:hover {
text-decoration: underline;
}
}
}
.dashboard-link {
padding-top: 12px;
font-weight: normal;
}
.section-margin {
margin-top: 20px;
}
input {
border: 1px solid $blue-color;
border-radius: 2px;
}
ul {
border-top: 1px solid $light-bg-color;
border-bottom: 1px solid $light-bg-color;
margin: 0;
padding: 0;
margin-top: 12px;
li {
cursor: pointer;
background-color: rgba($light-bg-color, 0.2);
&:hover {
background-color: rgba($light-bg-color, 0.4);
}
&:not(:last-child) {
border-bottom: 1px solid $light-bg-color;
}
}
}
}
ul {
margin: 0;
padding: 0;
}

View File

@@ -142,9 +142,20 @@ ul.section-menu-bar {
&:hover {
background-color: $blue-color;
.blue {
color: white;
}
&.nested-hover {
color: black;
background-color: $light-bg-color;
}
}
&.nested-hover {
color: black;
background-color: white;
}
.menu-item-title {

View File

@@ -1,3 +1,11 @@
.selectable {
user-select: all;
}
.clear {
clear: both;
}
.pull-left {
float: left !important;
}
@@ -166,7 +174,7 @@
}
.small {
font-size: 10px !important;
font-size: 10px;
}
.medium {

View File

@@ -18,7 +18,7 @@
%div{"ng-if" => "action.showNestedActions"}
%ul.mt-10
%li.menu-item.white-bg{"ng-repeat" => "subaction in action.subactions", "ng-click" => "executeAction(subaction, extension);", "style" => "margin-top: -1px;"}
%li.menu-item.white-bg.nested-hover{"ng-repeat" => "subaction in action.subactions", "ng-click" => "executeAction(subaction, extension, action); $event.stopPropagation();", "style" => "margin-top: -1px;"}
.menu-item-title {{subaction.label}}
.menu-item-subtitle {{subaction.desc}}
%span{"ng-if" => "subaction.running"}

View File

@@ -12,18 +12,7 @@
.subtitle Can access your current note decrypted.
%ul
%li.menu-item{"ng-repeat" => "editor in editorManager.externalEditors", "ng-click" => "selectEditor($event, editor)"}
.left-side
%strong.red.medium{"ng-if" => "editor.conflict_of"} Conflicted copy
.menu-item-title {{editor.name}}
%a.faded{"ng-if" => "!editor.default", "ng-click" => "setDefaultEditor(editor); $event.stopPropagation();"} Set Default
%a.blue{"ng-if" => "editor.default", "ng-click" => "removeDefaultEditor(editor); $event.stopPropagation();"} Remove Default
%a.faded{"ng-click" => "editor.showUrl = !editor.showUrl; $event.stopPropagation();"} Show URL
.menu-item-subtitle.wrap.mt-5{"ng-if" => "editor.showUrl"} {{editor.url}}
%span.inline.ml-10{"ng-if" => "selectedEditor === editor"} ✓
.right-side
%button.white.medium{"style" => "width: 50px; height: 40px;", "ng-click" => "deleteEditor(editor); $event.stopPropagation();"} ☓
.footer.mt-10
%input.form-control{"ng-model" => "formData.url", "placeholder" => "Add new editor via URL", "ng-keyup" => "$event.keyCode == 13 && submitNewEditorRequest()"}
%a.block.blue{"href" => "https://standardnotes.org/extensions", "target" => "_blank"} Available Editors
%strong.red.medium{"ng-if" => "editor.conflict_of"} Conflicted copy
.menu-item-title
{{editor.name}}
%span.inline.blue{"style" => "margin-left: 8px;", "ng-if" => "selectedEditor === editor"} ✓

View File

@@ -1,82 +1,108 @@
.panel.panel-default.account-panel.panel-right
.panel.panel-default.account-panel.panel-right#global-ext-menu
.panel-body
.white-bg.medium-padding.ext-section{"ng-class" => "{'opened': state.showDataExts}"}
%h1
%a{"ng-click" => "state.showDataExts = !state.showDataExts"} Action Extensions
%p{"style" => "margin-top: 3px;"} These extensions perform actions on a specific note. Choose "Actions" in the note editor to use installed actions.
.container
.float-group.h20
%h1.blue.pull-left Extensions
%a.block.pull-right.dashboard-link{"href" => "https://dashboard.standardnotes.org", "target" => "_blank"} Open Dashboard
%div.clear{"ng-if" => "!extensionManager.extensions.length && !themeManager.themes.length && !editorManager.externalEditors.length"}
%p Customize your experience with editors, themes, and actions.
.blue-box.mt-10
%h3 Available as part of the Extended subscription.
%p.mt-5 Note history
%p.mt-5 Automated backups
%p.mt-5 All editors, themes, and actions
%a{"href" => "https://standardnotes.org/extensions", "target" => "_blank"}
%button.mt-10
%h3 Learn More
%div.mt-10{"ng-if" => "state.showDataExts"}
%div{"style" => "font-size: 15px;", "ng-if" => "!extensionManager.extensions.length"} No extensions installed
%div{"ng-if" => "extensionManager.extensions.length"}
%section.gray-bg.inline-h.mb-10.medium-padding{"ng-repeat" => "extension in extensionManager.extensions | orderBy: 'name'", "ng-init" => "extension.formData = {}"}
%div{"ng-if" => "themeManager.themes.length > 0"}
.container.no-bottom.section-margin
%h2 Themes
%ul
%li{"ng-repeat" => "theme in themeManager.themes", "ng-click" => "theme.showDetails = !theme.showDetails"}
.container
%h3 {{theme.name}}
%a{"ng-if" => "!themeManager.isThemeActive(theme)", "ng-click" => "themeManager.activateTheme(theme); $event.stopPropagation();"} Activate
%a{"ng-if" => "themeManager.isThemeActive(theme)", "ng-click" => "themeManager.deactivateTheme(theme); $event.stopPropagation();"} Deactivate
%div{"ng-if" => "theme.showDetails"}
.link-group
%a.red{"ng-click" => "deleteTheme(theme); $event.stopPropagation();"} Delete
%a{"ng-click" => "theme.showLink = !theme.showLink; $event.stopPropagation();"} Show Link
%p.small.selectable.wrap{"ng-if" => "theme.showLink"}
{{theme.url}}
%div{"ng-if" => "editorManager.externalEditors.length > 0"}
.container.no-bottom.section-margin
%h2 Editors
%p{"style" => "margin-top: 3px;"} Choose "Editor" in the note menu to use an editor for a specific note.
%ul
%li{"ng-repeat" => "editor in editorManager.externalEditors", "ng-click" => "editor.showDetails = !editor.showDetails"}
.container
%strong.red.medium{"ng-if" => "editor.conflict_of"} Conflicted copy
%h3 {{editor.name}}
%div.mt-5{"ng-if" => "editor.showDetails"}
.link-group
%a{"ng-if" => "!editor.default", "ng-click" => "setDefaultEditor(editor); $event.stopPropagation();"} Make Default
%a.blue{"ng-if" => "editor.default", "ng-click" => "removeDefaultEditor(editor); $event.stopPropagation();"} Remove as Default
%a{"ng-click" => "editor.showUrl = !editor.showUrl; $event.stopPropagation();"} Show Link
%a.red{ "ng-click" => "deleteEditor(editor); $event.stopPropagation();"} Delete
.wrap.mt-5.selectable{"ng-if" => "editor.showUrl"} {{editor.url}}
%div{"ng-if" => "extensionManager.extensions.length"}
.container.no-bottom.section-margin
%h2 Actions
%p{"style" => "margin-top: 3px;"} Choose "Actions" in the note editor to use installed actions.
%ul
%li{"ng-repeat" => "extension in extensionManager.extensions | orderBy: 'name'", "ng-init" => "extension.formData = {}", "ng-click" => "extension.showDetails = !extension.showDetails"}
.container
%h3 {{extension.name}}
%p{"ng-if" => "extension.description"} {{extension.description}}
.mt-10
%label.block Access Type
%label.normal.block
%input{"type" => "radio", "ng-model" => "extension.encrypted", "ng-value" => "true", "ng-change" => "changeExtensionEncryptionFormat(true, extension)"}
Encrypted
%label.normal.block
%input{"type" => "radio", "ng-model" => "extension.encrypted", "ng-value" => "false", "ng-change" => "changeExtensionEncryptionFormat(false, extension)"}
Decrypted
%p.small{"ng-if" => "extension.description"} {{extension.description}}
%div{"ng-if" => "extension.showDetails"}
.mt-10
%label.block Access Type
%label.normal.block
%input{"type" => "radio", "ng-model" => "extension.encrypted", "ng-value" => "true", "ng-change" => "changeExtensionEncryptionFormat(true, extension)"}
Encrypted
%label.normal.block
%input{"type" => "radio", "ng-model" => "extension.encrypted", "ng-value" => "false", "ng-change" => "changeExtensionEncryptionFormat(false, extension)"}
Decrypted
.small-v-space
.small-v-space
%section.inline-h.white-bg.medium-padding.mb-10.pb-4{"ng-repeat" => "action in extension.actionsInGlobalContext()"}
%label.block {{action.label}}
%em{"style" => "font-style: italic;"} {{action.desc}}
%em{"ng-if" => "action.repeat_mode == 'watch'"}
Repeats when a change is made to your items.
%em{"ng-if" => "action.repeat_mode == 'loop'"}
Repeats at most once every {{action.repeat_timeout}} seconds
%div
%a{"ng-click" => "action.showPermissions = !action.showPermissions"} {{action.showPermissions ? "Hide permissions" : "Show permissions"}}
%div{"ng-if" => "action.showPermissions"}
{{action.permissionsString()}}
%label.block.normal {{action.encryptionModeString()}}
%ul{"ng-repeat" => "action in extension.actionsInGlobalContext()"}
%li
%label.block {{action.label}}
%em{"style" => "font-style: italic;"} {{action.desc}}
%em{"ng-if" => "action.repeat_mode == 'watch'"}
Repeats when a change is made to your items.
%em{"ng-if" => "action.repeat_mode == 'loop'"}
Repeats at most once every {{action.repeat_timeout}} seconds
%div
%a{"ng-click" => "action.showPermissions = !action.showPermissions"} {{action.showPermissions ? "Hide permissions" : "Show permissions"}}
%div{"ng-if" => "action.showPermissions"}
{{action.permissionsString()}}
%label.block.normal {{action.encryptionModeString()}}
%div
.mt-5{"ng-if" => "action.repeat_mode"}
%button.light{"ng-if" => "extensionManager.isRepeatActionEnabled(action)", "ng-click" => "extensionManager.disableRepeatAction(action, extension)"} Disable
%button.light{"ng-if" => "!extensionManager.isRepeatActionEnabled(action)", "ng-click" => "extensionManager.enableRepeatAction(action, extension)"} Enable
%button.light.mt-10{"ng-if" => "!action.running && !action.repeat_mode", "ng-click" => "selectedAction(action, extension)"}
Perform Action
.spinner.mb-5.block{"ng-if" => "action.running"}
%p.mb-5.mt-5.small{"ng-if" => "!action.error && action.lastExecuted && !action.running"}
Last run {{action.lastExecuted | appDateTime}}
%label.red{"ng-if" => "action.error"}
Error performing action.
%div
.mt-5{"ng-if" => "action.repeat_mode"}
%button.light{"ng-if" => "extensionManager.isRepeatActionEnabled(action)", "ng-click" => "extensionManager.disableRepeatAction(action, extension); $event.stopPropagation();"} Disable
%button.light{"ng-if" => "!extensionManager.isRepeatActionEnabled(action)", "ng-click" => "extensionManager.enableRepeatAction(action, extension); $event.stopPropagation();"} Enable
%button.light.mt-10{"ng-if" => "!action.running && !action.repeat_mode", "ng-click" => "selectedAction(action, extension); $event.stopPropagation();"}
Perform Action
.spinner.mb-5.block{"ng-if" => "action.running"}
%p.mb-5.mt-5.small{"ng-if" => "!action.error && action.lastExecuted && !action.running"}
Last run {{action.lastExecuted | appDateTime}}
%label.red{"ng-if" => "action.error"}
Error performing action.
%a.block.mt-5{"ng-click" => "extension.showURL = !extension.showURL"} Show URL
%p.wrap{"ng-if" => "extension.showURL"} {{extension.url}}
%a.block.mt-5{"ng-click" => "deleteExtension(extension)"} Remove extension
%a.block.mt-5{"ng-click" => "extension.showURL = !extension.showURL; $event.stopPropagation();"} Show Link
%p.wrap.selectable.small{"ng-if" => "extension.showURL"} {{extension.url}}
%a.block.mt-5{"ng-click" => "deleteActionExtension(extension); $event.stopPropagation();"} Remove extension
.large-v-space
%a.block{"ng-click" => "toggleExtensionForm()"} Add New Extension
%form.mt-10.mb-10{"ng-if" => "showNewExtensionForm"}
%input.form-control{:autofocus => 'autofocus', :name => 'url', :placeholder => 'Extension URL', :required => true, :type => 'url', 'ng-model' => 'newExtensionData.url'}
%button.ui-button.block{"ng-click" => "submitNewExtensionForm()", :type => 'submit', "data-style" => "expand-right", "data-size" => "s", "state" => "buttonState"}
Add Extension
%a.block.mt-5{"ng-click" => "reloadExtensionsPressed()", "ng-if" => "extensionManager.extensions.length > 0"} Reload all extensions
%a.block.mt-5{"href" => "https://standardnotes.org/extensions", "target" => "_blank"} Available Extensions
.white-bg.medium-padding.mt-10.ext-section{"ng-class" => "{'opened': state.showThemes}"}
%h1
%a{"ng-click" => "state.showThemes = !state.showThemes"} Themes
%div{"ng-if" => "state.showThemes"}
%section{"ng-repeat" => "theme in themeManager.themes"}
%label {{theme.name}}
%p {{theme.url}}
%a{"ng-if" => "!themeManager.isThemeActive(theme)", "ng-click" => "themeManager.activateTheme(theme)"} Activate
%a{"ng-if" => "themeManager.isThemeActive(theme)", "ng-click" => "themeManager.deactivateTheme(theme)"} Deactivate
%a.red.ml-2{"ng-click" => "deleteTheme(theme)"} Delete
%section
%p.bold.mb-5 Install New Theme
%input.form-control{:autofocus => 'autofocus', :name => 'url', :placeholder => 'New Theme URL', :required => true,
:type => 'url', 'ng-model' => 'state.themeUrl', "ng-keyup" => "$event.keyCode == 13 && submitTheme();"}
%a.block.mt-5{"href" => "https://standardnotes.org/extensions/themes", "target" => "_blank"} Available Themes
.container.section-margin
%h2.blue Install
%p.faded Enter an install link
%form.mt-10.mb-10
%input.form-control{:autofocus => 'autofocus', :name => 'url', :required => true,
:type => 'url', 'ng-model' => 'formData.installLink', "ng-keyup" => "$event.keyCode == 13 && submitInstallLink();"}