From 4bda20a8d9d6d3d1eacea0792f5b20030d5516f0 Mon Sep 17 00:00:00 2001 From: Mo Bitar Date: Sun, 7 Jan 2018 23:29:37 -0600 Subject: [PATCH] Wip --- .../app/frontend/controllers/editor.js | 47 ++----- .../app/frontend/controllers/footer.js | 21 +-- .../app/frontend/models/app/component.js | 9 +- .../app/frontend/models/app/theme.js | 4 +- .../app/services/componentManager.js | 39 +++--- .../app/services/desktopManager.js | 3 +- .../directives/views/componentModal.js | 10 +- .../directives/views/componentView.js | 71 ++++++++++ .../services/directives/views/editorMenu.js | 10 +- .../directives/views/permissionsModal.js | 7 +- .../app/services/packageManager.js | 8 +- app/assets/stylesheets/app/_footer.scss | 3 + app/assets/stylesheets/app/_modals.scss | 98 +++++--------- .../directives/account-menu.html.haml | 4 +- .../directives/component-modal.html.haml | 12 +- .../directives/component-view.html.haml | 6 + .../frontend/directives/editor-menu.html.haml | 6 +- .../global-extensions-menu.html.haml | 2 +- .../directives/permissions-modal.html.haml | 43 +++--- .../templates/frontend/editor.html.haml | 9 +- .../templates/frontend/footer.html.haml | 9 +- vendor/assets/stylesheets/stylekit.css | 127 +++++++++++++++--- 22 files changed, 335 insertions(+), 213 deletions(-) create mode 100644 app/assets/javascripts/app/services/directives/views/componentView.js create mode 100644 app/assets/templates/frontend/directives/component-view.html.haml diff --git a/app/assets/javascripts/app/frontend/controllers/editor.js b/app/assets/javascripts/app/frontend/controllers/editor.js index 047264ffa..326674086 100644 --- a/app/assets/javascripts/app/frontend/controllers/editor.js +++ b/app/assets/javascripts/app/frontend/controllers/editor.js @@ -66,21 +66,15 @@ angular.module('app.frontend') onReady(); } - if(this.editorComponent && this.editorComponent != associatedEditor) { - // Deactivate old editor - componentManager.deactivateComponent(this.editorComponent); - this.editorComponent = null; - } - // Activate new editor if it's different from the one currently activated - if(associatedEditor && associatedEditor != this.editorComponent) { + if(associatedEditor) { // switch after timeout, so that note data isnt posted to current editor $timeout(() => { - this.enableComponent(associatedEditor); - this.editorComponent = associatedEditor; + this.selectedEditor = associatedEditor; onReady(); }) } else { + this.selectedEditor = null; onReady(); } @@ -111,23 +105,19 @@ angular.module('app.frontend') } } - this.selectedEditor = function(editorComponent) { + this.selectEditor = function(editor) { + console.log("selectEditor", editor); this.showEditorMenu = false; - if(this.editorComponent && this.editorComponent !== editorComponent) { - // This disassociates the editor from the note, but the component itself still needs to be deactivated - this.disableComponentForCurrentItem(this.editorComponent); - // Now deactivate the component - componentManager.deactivateComponent(this.editorComponent); - } - - if(editorComponent) { + if(editor) { this.note.setAppDataItem("prefersPlainEditor", false); this.note.setDirty(true); - this.enableComponent(editorComponent); - this.associateComponentWithCurrentItem(editorComponent); + componentManager.associateComponentWithItem(editor, this.note); } else { // Note prefers plain editor + if(this.selectedEditor) { + componentManager.disassociateComponentWithItem(this.selectedEditor, this.note); + } this.note.setAppDataItem("prefersPlainEditor", true); this.note.setDirty(true); syncManager.sync(); @@ -137,7 +127,7 @@ angular.module('app.frontend') }) } - this.editorComponent = editorComponent; + this.selectedEditor = editor; }.bind(this) this.hasAvailableExtensions = function() { @@ -423,10 +413,10 @@ angular.module('app.frontend') } } else { // Editor - if(component.active && this.note && component.isActiveForItem(this.note)) { - this.editorComponent = component; + if(component.active && this.note && (component.isActiveForItem(this.note) || component.isDefaultEditor())) { + this.selectedEditor = component; } else { - this.editorComponent = null; + this.selectedEditor = null; } } @@ -512,15 +502,6 @@ angular.module('app.frontend') componentManager.contextItemDidChangeInArea("editor-editor"); } - this.enableComponent = function(component) { - componentManager.activateComponent(component); - componentManager.setEventFlowForComponent(component, 1); - } - - this.associateComponentWithCurrentItem = function(component) { - componentManager.associateComponentWithItem(component, this.note); - } - let alertKey = "displayed-component-disable-alert"; this.disableComponentForCurrentItem = function(component, showAlert) { componentManager.disassociateComponentWithItem(component, this.note); diff --git a/app/assets/javascripts/app/frontend/controllers/footer.js b/app/assets/javascripts/app/frontend/controllers/footer.js index 6028de680..07001176c 100644 --- a/app/assets/javascripts/app/frontend/controllers/footer.js +++ b/app/assets/javascripts/app/frontend/controllers/footer.js @@ -23,7 +23,7 @@ angular.module('app.frontend') } }) .controller('FooterCtrl', function ($rootScope, authManager, modelManager, $timeout, dbManager, - syncManager, storageManager, passcodeManager, componentManager, singletonManager) { + syncManager, storageManager, passcodeManager, componentManager, singletonManager, packageManager) { this.user = authManager.user; @@ -143,16 +143,17 @@ angular.module('app.frontend') this.selectRoom = function(room) { room.show = !room.show; - if(room.show) { - this.componentManager.activateComponent(room); - } else { - this.hideRoom(room); - } - } - this.hideRoom = function(room) { - room.show = false; - this.componentManager.deactivateComponent(room); + // Allows us to send messages to component modal directive + if(!room.directiveController) { + room.directiveController = {}; + } + + if(!room.show) { + room.directiveController.dismiss(); + } + + console.log("Show", room.show); } // Handle singleton ProLink instance diff --git a/app/assets/javascripts/app/frontend/models/app/component.js b/app/assets/javascripts/app/frontend/models/app/component.js index eb515ce32..5287f412e 100644 --- a/app/assets/javascripts/app/frontend/models/app/component.js +++ b/app/assets/javascripts/app/frontend/models/app/component.js @@ -18,7 +18,12 @@ class Component extends Item { mapContentToLocalProperties(content) { super.mapContentToLocalProperties(content) + /* Legacy */ this.url = content.url; + /* New */ + this.local_url = content.local_url; + this.hosted_url = content.hosted_url; + this.name = content.name; this.autoupdate = content.autoupdate; @@ -29,7 +34,6 @@ class Component extends Item { this.permissions = content.permissions; this.active = content.active; - this.local = content.local; // custom data that a component can store in itself this.componentData = content.componentData || {}; @@ -44,12 +48,13 @@ class Component extends Item { structureParams() { var params = { url: this.url, + hosted_url: this.hosted_url, + local_url: this.local_url, name: this.name, area: this.area, package_info: this.package_info, permissions: this.permissions, active: this.active, - local: this.local, autoupdate: this.autoupdate, componentData: this.componentData, disassociatedItemIds: this.disassociatedItemIds, diff --git a/app/assets/javascripts/app/frontend/models/app/theme.js b/app/assets/javascripts/app/frontend/models/app/theme.js index d69eaad76..38ced50ce 100644 --- a/app/assets/javascripts/app/frontend/models/app/theme.js +++ b/app/assets/javascripts/app/frontend/models/app/theme.js @@ -8,14 +8,12 @@ class Theme extends Item { super.mapContentToLocalProperties(content) this.url = content.url; this.name = content.name; - this.local = content.local; } structureParams() { var params = { url: this.url, - name: this.name, - local: this.local + name: this.name }; _.merge(params, super.structureParams()); diff --git a/app/assets/javascripts/app/services/componentManager.js b/app/assets/javascripts/app/services/componentManager.js index c0dbc2df0..2b73b1580 100644 --- a/app/assets/javascripts/app/services/componentManager.js +++ b/app/assets/javascripts/app/services/componentManager.js @@ -143,7 +143,8 @@ class ComponentManager { 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}; params.content = item.createContentJSONFromProperties(); - params.clientData = item.getDomainDataItem(component.url, ClientDataDomain) || {}; + /* Legacy is using component.url key, so if it's present, use it, otherwise use uuid */ + params.clientData = item.getDomainDataItem(component.url || component.uuid, ClientDataDomain) || {}; /* 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 @@ -186,7 +187,7 @@ class ComponentManager { componentForUrl(url) { return this.components.filter(function(component){ - return component.url === url; + return component.url === url || component.hosted_url === url; })[0]; } @@ -251,9 +252,12 @@ class ComponentManager { } } - removePrivatePropertiesFromResponseItems(responseItems) { + removePrivatePropertiesFromResponseItems(responseItems, includeUrls) { // Don't allow component to overwrite these properties. - let privateProperties = ["appData"]; + var privateProperties = ["appData", "autoupdate", "permissions", "active"]; + if(includeUrls) { + privateProperties = privateProperties.concat(["url", "hosted_url", "local_url"]); + } for(var responseItem of responseItems) { // Do not pass in actual items here, otherwise that would be destructive. @@ -275,10 +279,10 @@ class ComponentManager { ]; this.runWithPermissions(component, requiredPermissions, message.permissions, function(){ - if(!_.find(this.streamObservers, {identifier: component.url})) { + if(!_.find(this.streamObservers, {identifier: component.uuid})) { // for pushing laster as changes come in this.streamObservers.push({ - identifier: component.url, + identifier: component.uuid, component: component, originalMessage: message, contentTypes: message.data.content_types @@ -304,10 +308,10 @@ class ComponentManager { ]; this.runWithPermissions(component, requiredPermissions, message.permissions, function(){ - if(!_.find(this.contextStreamObservers, {identifier: component.url})) { + if(!_.find(this.contextStreamObservers, {identifier: component.uuid})) { // for pushing laster as changes come in this.contextStreamObservers.push({ - identifier: component.url, + identifier: component.uuid, component: component, originalMessage: message }) @@ -336,7 +340,7 @@ class ComponentManager { this.runWithPermissions(component, requiredPermissions, message.permissions, () => { var responseItems = message.data.items; - this.removePrivatePropertiesFromResponseItems(responseItems); + this.removePrivatePropertiesFromResponseItems(responseItems, {includeUrls: true}); /* We map the items here because modelManager is what updates the UI. If you were to instead get the items directly, @@ -348,7 +352,7 @@ class ComponentManager { var responseItem = _.find(responseItems, {uuid: item.uuid}); _.merge(item.content, responseItem.content); if(responseItem.clientData) { - item.setDomainDataItem(component.url, responseItem.clientData, ClientDataDomain); + item.setDomainDataItem(component.url || component.uuid, responseItem.clientData, ClientDataDomain); } item.setDirty(true); } @@ -374,7 +378,7 @@ class ComponentManager { this.removePrivatePropertiesFromResponseItems([responseItem]); var item = this.modelManager.createItem(responseItem); if(responseItem.clientData) { - item.setDomainDataItem(component.url, responseItem.clientData, ClientDataDomain); + item.setDomainDataItem(component.url || component.uuid, responseItem.clientData, ClientDataDomain); } this.modelManager.addItem(item); this.modelManager.resolveReferencesForItem(item); @@ -457,7 +461,7 @@ class ComponentManager { } return p.name == required.name && matchesContentTypes; })[0]; - console.log("required", required, "requested", requestedPermissions, "matching", matching); + if(!matching) { /* Required permissions can be 1 content type, and requestedPermisisons may send an array of content types. In the case of an array, we can just check to make sure that requiredPermissions content type is found in the array @@ -503,7 +507,6 @@ class ComponentManager { // since these calls are asyncronous, multiple dialogs may be requested at the same time. We only want to present one and trigger all callbacks based on one modal result var existingDialog = _.find(this.permissionDialogs, {component: component}); - component.trusted = component.url.startsWith("https://standardnotes.org") || component.url.startsWith("https://extensions.standardnotes.org"); var scope = this.$rootScope.$new(true); scope.component = component; scope.permissions = requestedPermissions; @@ -531,7 +534,7 @@ class ComponentManager { this.permissionDialogs.push(scope); if(!existingDialog) { - var el = this.$compile( "" )(scope); + var el = this.$compile( "" )(scope); angular.element(document.body).append(el); } else { console.log("Existing dialog, not presenting."); @@ -541,7 +544,7 @@ class ComponentManager { openModalComponent(component) { var scope = this.$rootScope.$new(true); scope.component = component; - var el = this.$compile( "" )(scope); + var el = this.$compile( "" )(scope); angular.element(document.body).append(el); } @@ -711,10 +714,10 @@ class ComponentManager { } urlForComponent(component) { - if(isDesktopApplication() && component.local && component.url.startsWith("sn://")) { - return component.url.replace("sn://", this.desktopManager.getApplicationDataPath() + "/"); + if(isDesktopApplication() && component.local_url) { + return component.local_url.replace("sn://", this.desktopManager.getApplicationDataPath() + "/"); } else { - return component.url; + return component.url || component.hosted_url; } } diff --git a/app/assets/javascripts/app/services/desktopManager.js b/app/assets/javascripts/app/services/desktopManager.js index 3bdfdfae2..a89dd1514 100644 --- a/app/assets/javascripts/app/services/desktopManager.js +++ b/app/assets/javascripts/app/services/desktopManager.js @@ -28,8 +28,7 @@ class DesktopManager { /* Can handle components and themes */ installOfflineComponentFromData(componentData, callback) { this.componentInstallationHandler(componentData, (installedComponent) => { - componentData.content.url = installedComponent.content.url; - componentData.content.local = true; + componentData.content.local_url = installedComponent.content.local_url; callback(componentData); }); } diff --git a/app/assets/javascripts/app/services/directives/views/componentModal.js b/app/assets/javascripts/app/services/directives/views/componentModal.js index ee20de0d2..72502e854 100644 --- a/app/assets/javascripts/app/services/directives/views/componentModal.js +++ b/app/assets/javascripts/app/services/directives/views/componentModal.js @@ -6,6 +6,7 @@ class ComponentModal { this.scope = { show: "=", component: "=", + controller: "=", callback: "=" }; } @@ -19,12 +20,17 @@ class ComponentModal { let identifier = "modal-" + $scope.component.uuid; - $scope.dismiss = function() { - componentManager.deregisterHandler(identifier); + $scope.component.directiveController.dismiss = function() { + $scope.component.show = false; componentManager.deactivateComponent($scope.component); + componentManager.deregisterHandler(identifier); $scope.el.remove(); } + $scope.dismiss = function() { + $scope.component.directiveController.dismiss(); + } + $scope.url = function() { return componentManager.urlForComponent($scope.component); } diff --git a/app/assets/javascripts/app/services/directives/views/componentView.js b/app/assets/javascripts/app/services/directives/views/componentView.js new file mode 100644 index 000000000..d3f75fa5e --- /dev/null +++ b/app/assets/javascripts/app/services/directives/views/componentView.js @@ -0,0 +1,71 @@ +class ComponentView { + + constructor() { + this.restrict = "E"; + this.templateUrl = "frontend/directives/component-view.html"; + this.scope = { + component: "=" + }; + } + + link($scope, el, attrs, ctrl) { + $scope.el = el; + + $scope.$watch('component', function(component, prevComponent){ + console.log("Component View Setting Component", component); + ctrl.componentValueChanging(component, prevComponent); + }); + } + + controller($scope, $timeout, componentManager, desktopManager) { + 'ngInject'; + + this.componentValueChanging = (component, prevComponent) => { + if(prevComponent && component !== prevComponent) { + // Deactive old component + console.log("DEACTIVATING OLD COMPONENT", prevComponent); + componentManager.deactivateComponent(prevComponent); + } + + if(component) { + componentManager.activateComponent(component); + componentManager.setEventFlowForComponent(component, 1); + } + } + + let identifier = "component-view-" + Math.random(); + + $scope.url = function() { + if($scope.component.offlineOnly) { + return $scope.component.local_url; + } + + if(desktopManager.isDesktop && $scope.component.local_url) { + return $scope.component.local_url; + } + + return $scope.component.hosted_url || $scope.component.url; + } + + componentManager.registerHandler({identifier: identifier, areas: ["*"], activationHandler: (component) => { + if(component.active) { + $timeout(function(){ + var iframe = componentManager.iframeForComponent(component); + if(iframe) { + iframe.onload = function() { + componentManager.registerComponentWindow(component, iframe.contentWindow); + }.bind(this); + } + }.bind(this)); + } + }, + actionHandler: function(component, action, data) { + if(action == "set-size") { + componentManager.handleSetSizeEvent(component, data); + } + }.bind(this)}); + } + +} + +angular.module('app.frontend').directive('componentView', () => new ComponentView); diff --git a/app/assets/javascripts/app/services/directives/views/editorMenu.js b/app/assets/javascripts/app/services/directives/views/editorMenu.js index 292e090a4..78e4005ab 100644 --- a/app/assets/javascripts/app/services/directives/views/editorMenu.js +++ b/app/assets/javascripts/app/services/directives/views/editorMenu.js @@ -9,7 +9,7 @@ class EditorMenu { }; } - controller($scope, componentManager, syncManager) { + controller($scope, componentManager, syncManager, $timeout) { 'ngInject'; $scope.formData = {}; @@ -23,12 +23,10 @@ class EditorMenu { $scope.selectEditor = function($event, editor) { if(editor) { editor.conflict_of = null; // clear conflict if applicable - if(editor.local && !isDesktopApplication()) { - alert("This editor is installed locally and is available only through Standard Notes for Desktop.") - return; - } } - $scope.callback()(editor); + $timeout(() => { + $scope.callback()(editor); + }) } $scope.toggleDefaultForEditor = function(editor) { diff --git a/app/assets/javascripts/app/services/directives/views/permissionsModal.js b/app/assets/javascripts/app/services/directives/views/permissionsModal.js index 51604dcb1..d08de104e 100644 --- a/app/assets/javascripts/app/services/directives/views/permissionsModal.js +++ b/app/assets/javascripts/app/services/directives/views/permissionsModal.js @@ -29,10 +29,11 @@ class PermissionsModal { } controller($scope, modelManager) { + console.log("permissions", $scope.permissions); + $scope.formattedPermissions = $scope.permissions.map(function(permission){ if(permission.name === "stream-items") { - var title = "Access to "; var types = permission.content_types.map(function(type){ var desc = modelManager.humanReadableDisplayForContentType(type); if(desc) { @@ -61,14 +62,14 @@ class PermissionsModal { } } - return title + typesString; + return typesString; } else if(permission.name === "stream-context-item") { var mapping = { "editor-stack" : "working note", "note-tags" : "working note", "editor-editor": "working note" } - return "Access to " + mapping[$scope.component.area]; + return mapping[$scope.component.area]; } }) } diff --git a/app/assets/javascripts/app/services/packageManager.js b/app/assets/javascripts/app/services/packageManager.js index 048d5b2ae..103ab5096 100644 --- a/app/assets/javascripts/app/services/packageManager.js +++ b/app/assets/javascripts/app/services/packageManager.js @@ -1,12 +1,12 @@ class PackageManager { - constructor(httpManager, modelManager, syncManager) { + constructor(httpManager, modelManager, syncManager, componentManager) { this.httpManager = httpManager; this.modelManager = modelManager; this.syncManager = syncManager; + this.componentManager = componentManager; } - installPackage(url, callback) { this.httpManager.getAbsolute(url, {}, function(aPackage){ console.log("Got package data", aPackage); @@ -15,7 +15,11 @@ class PackageManager { return; } + // Remove private properties + this.componentManager.removePrivatePropertiesFromResponseItems([aPackage]); + var assembled = this.modelManager.createItem(aPackage); + assembled.package_info = aPackage; this.modelManager.addItem(assembled); assembled.setDirty(true); diff --git a/app/assets/stylesheets/app/_footer.scss b/app/assets/stylesheets/app/_footer.scss index c9110a733..0694c4e2e 100644 --- a/app/assets/stylesheets/app/_footer.scss +++ b/app/assets/stylesheets/app/_footer.scss @@ -33,6 +33,9 @@ #account-panel { width: 400px; +} + +.panel { cursor: default; } diff --git a/app/assets/stylesheets/app/_modals.scss b/app/assets/stylesheets/app/_modals.scss index d22afe91e..e4dfa9c71 100644 --- a/app/assets/stylesheets/app/_modals.scss +++ b/app/assets/stylesheets/app/_modals.scss @@ -1,4 +1,18 @@ -.permissions-modal, .component-modal { +#permissions-modal { + width: 350px; + .panel { + border-radius: 0; + background-color: white; + } + .content { + padding-top: 1.1rem; + } + .footer { + padding-bottom: 1.4rem; + } +} + +.modal { position: fixed; margin-left: auto; margin-right: auto; @@ -11,9 +25,9 @@ height: 100vh; background-color: rgba(gray, 0.3); color: black; - font-size: 16px; display: flex; align-items: center; + justify-content: center; .background { position: absolute; @@ -22,70 +36,8 @@ height: 100%; } - .content { - box-shadow: 0 6px 12px rgba(0, 0, 0, 0.175); - background-color: white; - width: 700px; - // height: 500px; - margin: auto; - padding: 10px 30px; - padding-bottom: 30px; - // position: absolute; - // top: 0; left: 0; bottom: 0; right: 0; + > .content { overflow-y: scroll; - - p { - margin-bottom: 8px; - margin-top: 0; - } - - h3 { - margin-bottom: 0; - } - - h4 { - margin-bottom: 6px; - } - } - - .learn-more { - margin-top: 20px; - line-height: 1.3; - } - - .status { - color: orange; - } - - .buttons { - margin-top: 35px; - } - - button.standard { - border-radius: 1px; - font-weight: bold; - padding: 6px 20px; - display: inline-block; - - &:hover { - text-decoration: underline; - } - - &.tinted { - background-color: $blue-color; - color: white; - } - - &.white { - color: black; - background-color: white; - border: 1px solid gray; - } - } -} - -.component-modal { - .content { width: auto; padding: 0; padding-bottom: 0; @@ -93,10 +45,20 @@ } .modal-iframe-container { + flex-grow: 1; + display: flex; - .modal-iframe { + iframe { + flex-grow: 1; + width: 100%; + } +} + +.component-view { + flex-grow: 1; + display: flex; + iframe { + flex: 1; width: 100%; - height: 100%; } - } diff --git a/app/assets/templates/frontend/directives/account-menu.html.haml b/app/assets/templates/frontend/directives/account-menu.html.haml index 3c674d434..38db58dec 100644 --- a/app/assets/templates/frontend/directives/account-menu.html.haml +++ b/app/assets/templates/frontend/directives/account-menu.html.haml @@ -1,5 +1,5 @@ .sn-component - .panel.panel-right#account-panel + .panel#account-panel .header %h1.title Account %a.close-button Close @@ -169,8 +169,6 @@ %input.form-control.mt-5{:type => 'password', "ng-model" => "importData.password", "autofocus" => "true"} %button.standard.ui-button.block.tinted.mt-5{"type" => "submit"} Decrypt & Import - %p.mt-5{"ng-if" => "user"} Notes are downloaded in the Standard File format, which allows you to re-import back into this app easily. To download as plain text files, choose "Decrypted". - .spinner.mt-10{"ng-if" => "importData.loading"} .footer %a.right{"ng-if" => "formData.showLogin || formData.showRegister", "ng-click" => "formData.showLogin = false; formData.showRegister = false;"} diff --git a/app/assets/templates/frontend/directives/component-modal.html.haml b/app/assets/templates/frontend/directives/component-modal.html.haml index 4ce5aaf62..2d02ce18a 100644 --- a/app/assets/templates/frontend/directives/component-modal.html.haml +++ b/app/assets/templates/frontend/directives/component-modal.html.haml @@ -1,5 +1,7 @@ -.background{"ng-click" => "dismiss()"} - -.content - .modal-iframe-container{"ng-attr-id" => "component-{{component.uuid}}"} - %iframe.modal-iframe{"ng-src" => "{{url() | trusted}}", "frameBorder" => "0", "sandbox" => "allow-scripts allow-top-navigation-by-user-activation allow-popups allow-popups-to-escape-sandbox allow-modals", "data-component-id" => "{{component.uuid}}"} +.sn-component + .panel{"ng-attr-id" => "component-{{component.uuid}}"} + .header + %h1.title {{component.name}} + %a.close-button.info{"ng-click" => "dismiss()"} Close + .modal-iframe-container{"ng-attr-id" => "component-{{component.uuid}}"} + %iframe{"ng-src" => "{{url() | trusted}}", "frameBorder" => "0", "sandbox" => "allow-scripts allow-top-navigation-by-user-activation allow-popups allow-popups-to-escape-sandbox allow-modals", "data-component-id" => "{{component.uuid}}"} diff --git a/app/assets/templates/frontend/directives/component-view.html.haml b/app/assets/templates/frontend/directives/component-view.html.haml new file mode 100644 index 000000000..60ffbab5d --- /dev/null +++ b/app/assets/templates/frontend/directives/component-view.html.haml @@ -0,0 +1,6 @@ +%iframe{"ng-if" => "component", +"ng-attr-id" => "component-{{component.uuid}}", +"ng-src" => "{{url() | trusted}}", "frameBorder" => "0", +"sandbox" => "allow-scripts allow-top-navigation-by-user-activation allow-popups allow-popups-to-escape-sandbox allow-modals", +"data-component-id" => "{{component.uuid}}"} + Loading diff --git a/app/assets/templates/frontend/directives/editor-menu.html.haml b/app/assets/templates/frontend/directives/editor-menu.html.haml index 9209a4b0b..6324f53f4 100644 --- a/app/assets/templates/frontend/directives/editor-menu.html.haml +++ b/app/assets/templates/frontend/directives/editor-menu.html.haml @@ -12,10 +12,8 @@ .row .column %strong.red.medium{"ng-if" => "editor.conflict_of"} Conflicted copy - .sublabel{"ng-if" => "editor.local"} - Locally Installed - - .sublabel.faded{"ng-if" => "editor.local && !isDesktop"} Unavailable in Web Browser + .sublabel{"ng-if" => "editor.local_url"} + Available Offline %a.no-decoration{"ng-if" => "editors.length == 0", "href" => "https://standardnotes.org/extensions", "target" => "blank"} %menu-row{"title" => "'Download More Editors'", "ng-click" => "moreEditors()"} diff --git a/app/assets/templates/frontend/directives/global-extensions-menu.html.haml b/app/assets/templates/frontend/directives/global-extensions-menu.html.haml index fe8965304..276a370c5 100644 --- a/app/assets/templates/frontend/directives/global-extensions-menu.html.haml +++ b/app/assets/templates/frontend/directives/global-extensions-menu.html.haml @@ -1,4 +1,4 @@ -.panel.panel-default.account-panel.panel-right#global-ext-menu +.panel#global-ext-menu .panel-body .container .float-group.h20 diff --git a/app/assets/templates/frontend/directives/permissions-modal.html.haml b/app/assets/templates/frontend/directives/permissions-modal.html.haml index e17fb7f75..cfd7d8661 100644 --- a/app/assets/templates/frontend/directives/permissions-modal.html.haml +++ b/app/assets/templates/frontend/directives/permissions-modal.html.haml @@ -1,25 +1,24 @@ .background{"ng-click" => "deny()"} -.content - %h3 The following extension has requested these permissions: +.content#permissions-modal + .sn-component + .panel + .header + %h1.title Activate Extension + %a.close-button.info Cancel + .content + .panel-section + .panel-row + %h3 + %strong {{component.name}} + would like to interact with your + %span{"ng-repeat" => "permission in formattedPermissions"} + {{permission}}. + -# %p.wrap URL: {{component.runningUrl}} - %h4 Extension - %p Name: {{component.name}} - %p.wrap URL: {{component.url}} - - %h4 Permissions - .permission{"ng-repeat" => "permission in formattedPermissions"} - %p {{permission}} - - %h4 Status - %p.status{"ng-class" => "{'trusted tinted' : component.trusted}"} {{component.trusted ? 'Trusted' : 'Untrusted'}} - - .learn-more - %h4 Details - %p - Extensions use an offline messaging system to communicate. With Trusted extensions, data is never sent remotely without your consent. Learn more about extension permissions at - %a{"href" => "https://standardnotes.org/permissions", "target" => "_blank"} https://standardnotes.org/permissions. - - .buttons - %button.standard.white{"ng-click" => "deny()"} Deny - %button.standard.tinted{"ng-click" => "accept()"} Accept + .panel-row + %p + Extensions use an offline messaging system to communicate. Learn more at + %a{"href" => "https://standardnotes.org/permissions", "target" => "_blank"} https://standardnotes.org/permissions. + .footer + .button.info.big.block.bold{"ng-click" => "accept()"} Continue diff --git a/app/assets/templates/frontend/editor.html.haml b/app/assets/templates/frontend/editor.html.haml index 574fe2f88..9541746bf 100644 --- a/app/assets/templates/frontend/editor.html.haml +++ b/app/assets/templates/frontend/editor.html.haml @@ -34,7 +34,7 @@ .item{"ng-click" => "ctrl.showEditorMenu = !ctrl.showEditorMenu; ctrl.showMenu = false; ctrl.showExtensions = false;", "ng-class" => "{'selected' : ctrl.showEditorMenu}", "click-outside" => "ctrl.showEditorMenu = false;", "is-open" => "ctrl.showEditorMenu"} .label Editor - %editor-menu{"ng-if" => "ctrl.showEditorMenu", "callback" => "ctrl.selectedEditor", "selected-editor" => "ctrl.editorComponent"} + %editor-menu{"ng-if" => "ctrl.showEditorMenu", "callback" => "ctrl.selectEditor", "selected-editor" => "ctrl.selectedEditor"} .item{"ng-click" => "ctrl.showExtensions = !ctrl.showExtensions; ctrl.showMenu = false; ctrl.showEditorMenu = false;", "ng-class" => "{'selected' : ctrl.showExtensions}", "ng-if" => "ctrl.hasAvailableExtensions()", "click-outside" => "ctrl.showExtensions = false;", "is-open" => "ctrl.showExtensions"} .label Actions @@ -42,14 +42,13 @@ .editor-content#editor-content{"ng-if" => "ctrl.noteReady && !ctrl.note.errorDecrypting"} %panel-resizer.left{"panel-id" => "'editor-content'", "on-resize-finish" => "ctrl.onPanelResizeFinish","control" => "ctrl.resizeControl", "min-width" => 300, "property" => "'left'", "hoverable" => "true"} - %iframe#editor-iframe{"ng-if" => "ctrl.editorComponent && ctrl.editorComponent.active", "ng-src" => "{{ctrl.componentManager.urlForComponent(ctrl.editorComponent) | trusted}}", "data-component-id" => "{{ctrl.editorComponent.uuid}}", "frameBorder" => "0", "style" => "width: 100%;"} - Loading - %textarea.editable#note-text-editor{"ng-if" => "!ctrl.editorComponent", "ng-model" => "ctrl.note.text", + -# ng-show is required here (as opposed to ng-if) in order for the component-view to receive events such as nulling ctrl.selectorEditor + %component-view{"ng-show" => "ctrl.selectedEditor", "component" => "ctrl.selectedEditor", "class" => "component-view"} + %textarea.editable#note-text-editor{"ng-if" => "!ctrl.selectedEditor", "ng-model" => "ctrl.note.text", "ng-change" => "ctrl.contentChanged()", "ng-click" => "ctrl.clickedTextArea()", "ng-focus" => "ctrl.onContentFocus()", "dir" => "auto"} {{ctrl.onSystemEditorLoad()}} %panel-resizer{"panel-id" => "'editor-content'", "on-resize-finish" => "ctrl.onPanelResizeFinish","control" => "ctrl.resizeControl", "min-width" => 300, "hoverable" => "true"} - %section.section{"ng-if" => "ctrl.note.errorDecrypting"} %p.medium-padding{"style" => "padding-top: 0 !important;"} There was an error decrypting this item. Ensure you are running the latest version of this app, then sign out and sign back in to try again. diff --git a/app/assets/templates/frontend/footer.html.haml b/app/assets/templates/frontend/footer.html.haml index 54634cdec..dc8b87d7f 100644 --- a/app/assets/templates/frontend/footer.html.haml +++ b/app/assets/templates/frontend/footer.html.haml @@ -19,11 +19,10 @@ .item.border - .item{"ng-repeat" => "room in ctrl.rooms", "ng-click" => "ctrl.selectRoom(room)", "click-outside" => "ctrl.hideRoom(room)", "is-open" => "room.show && room.active"} - .label {{room.name}} - .sn-component - .panel-right.panel{"ng-if" => "room.show && room.active", "ng-attr-id" => "component-{{room.uuid}}"} - %iframe.room-iframe{"ng-src" => "{{ctrl.componentManager.urlForComponent(room) | trusted}}", "frameBorder" => "0", "sandbox" => "allow-scripts allow-top-navigation-by-user-activation allow-popups allow-popups-to-escape-sandbox allow-modals", "data-component-id" => "{{room.uuid}}"} + .item{"ng-repeat" => "room in ctrl.rooms"} + .column{"ng-click" => "ctrl.selectRoom(room)"} + .label {{room.name}} + %component-modal{"ng-if" => "room.show", "component" => "room"} .right diff --git a/vendor/assets/stylesheets/stylekit.css b/vendor/assets/stylesheets/stylekit.css index 07729e74c..906073401 100644 --- a/vendor/assets/stylesheets/stylekit.css +++ b/vendor/assets/stylesheets/stylekit.css @@ -7,8 +7,17 @@ box-shadow: 0px 2px 13px #C8C8C8; border-radius: 0.7rem; overflow: scroll; + display: flex; + flex-direction: column; +} +.sn-component .panel.static { + box-shadow: none; + border: none; + border-radius: 0; } .sn-component .panel .header { + flex-shrink: 0; + /* Don't allow to condense in height */ display: flex; justify-content: space-between; padding: 1.1rem 2rem; @@ -32,8 +41,9 @@ display: block; } .sn-component .panel .content { - padding: 1.9rem 2rem; + padding: 1.6rem 2rem; padding-bottom: 0; + flex-grow: 1; } .sn-component .panel .content p { color: #454545; @@ -45,6 +55,29 @@ .sn-component .panel .content .panel-section { padding-bottom: 1.6rem; } +.sn-component .panel .content .panel-section .panel-row { + display: flex; + justify-content: space-between; + align-items: center; + padding-top: 0.4rem; +} +.sn-component .panel .content .panel-section .panel-row.centered { + justify-content: center; +} +.sn-component .panel .content .panel-section .panel-row .panel-column { + width: 100%; +} +.sn-component .panel .content .panel-section .panel-row:not(:last-child) { + padding-bottom: 0.4rem; +} +.sn-component .panel .content .panel-section .panel-row:not(:last-child).condensed { + padding-top: 0.2rem; + padding-bottom: 0.2rem; +} +.sn-component .panel .content .panel-section .panel-row p { + margin: 0; + padding: 0; +} .sn-component .panel .content .panel-section.hero { text-align: center; } @@ -65,29 +98,12 @@ margin-bottom: 15px; } .sn-component .panel .content .panel-section .subtitle { - margin-top: -4px; + margin-top: -0.5rem; } .sn-component .panel .content .panel-section .subtitle.subtle { font-weight: normal; opacity: 0.6; } -.sn-component .panel .content .panel-section .panel-row { - display: flex; - justify-content: space-between; - align-items: center; - padding-top: 0.4rem; -} -.sn-component .panel .content .panel-section .panel-row:not(:last-child) { - padding-bottom: 0.4rem; -} -.sn-component .panel .content .panel-section .panel-row:not(:last-child).condensed { - padding-top: 0.2rem; - padding-bottom: 0.2rem; -} -.sn-component .panel .content .panel-section .panel-row p { - margin: 0; - padding: 0; -} .sn-component .panel .content .panel-form { width: 100%; } @@ -169,17 +185,21 @@ .sn-component h1 { font-weight: 500; font-size: 1.3rem; + line-height: 1.9rem; } .sn-component h2 { font-size: 1.2rem; + line-height: 1.8rem; } .sn-component h3 { font-weight: normal; font-size: 1.2rem; + line-height: 1.7rem; } .sn-component h4 { font-weight: bold; font-size: 0.95rem; + line-height: 1.4rem; } .sn-component h5 { font-weight: bold; @@ -203,6 +223,14 @@ .sn-component *.success { color: #2B9612; } +.sn-component *.clear { + background-color: transparent; + border: none; +} +.sn-component .center-text { + text-align: center; + justify-content: center; +} .sn-component p { margin: 0.5rem 0; } @@ -215,10 +243,15 @@ font-size: 1.1rem; width: 100%; outline: 0; + resize: none; } .sn-component input.info { border-color: #086DD6; background-color: transparent; + color: #086DD6; +} +.sn-component input.info::-webkit-input-placeholder { + color: rgba(8, 109, 214, 0.5); } .sn-component label { margin: 0.7rem 0; @@ -277,6 +310,9 @@ .sn-component .box-group .box:not(:last-child) { margin-right: 5px; } +.sn-component a.button, .sn-component a.box, .sn-component a.circle { + text-decoration: none; +} .sn-component .button, .sn-component .box, .sn-component .circle { display: table; border-radius: 3px; @@ -291,6 +327,10 @@ display: block; text-align: center; } +.sn-component .button.big, .sn-component .big.box, .sn-component .big.circle { + font-size: 1.1rem; + padding: 0.7rem 2.5rem; +} .sn-component .box { padding: 2.5rem 1.5rem; } @@ -461,9 +501,15 @@ border-radius: 0.2rem; cursor: default; } +.sn-component .notification.one-line { + padding: 0rem 0.4rem; +} .sn-component .notification.stretch { width: 100%; } +.sn-component .notification.dashed { + border-style: dashed; +} .sn-component .notification .text { line-height: 1.5rem; font-size: 1.05rem; @@ -573,5 +619,48 @@ font-weight: normal; opacity: 0.6; } +.sn-component .panel-table { + display: flex; + flex-wrap: wrap; + padding-left: 1px; + padding-top: 1px; +} +.sn-component .panel-table .table-item { + flex: 45%; + flex-flow: wrap; + border: 1px solid #DDDDDD; + padding: 1rem; + margin-left: -1px; + margin-top: -1px; + display: flex; + flex-direction: column; + justify-content: space-between; +} +.sn-component .panel-table .table-item img { + max-width: 100%; + margin-bottom: 1rem; +} +.sn-component .panel-table .table-item .item-content { + display: flex; + flex-direction: row; +} +.sn-component .panel-table .table-item .item-column { + align-items: center; +} +.sn-component .panel-table .table-item .item-column:not(:first-child) { + padding-left: 0.75rem; +} +.sn-component .panel-table .table-item .item-column.quarter { + flex-basis: 25%; +} +.sn-component .panel-table .table-item .item-column.three-quarters { + flex-basis: 75%; +} +.sn-component .panel-table .table-item .item-footer { + margin-top: 1.25rem; +} +.sn-component .panel-table .table-item.no-border { + border: none; +} /*# sourceMappingURL=stylekit.css.map */