This commit is contained in:
Mo Bitar
2018-01-07 23:29:37 -06:00
parent 3cf5a9ad45
commit 4bda20a8d9
22 changed files with 335 additions and 213 deletions

View File

@@ -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);

View File

@@ -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

View File

@@ -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,

View File

@@ -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());

View File

@@ -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( "<permissions-modal component='component' permissions='permissions' callback='callback' class='permissions-modal'></permissions-modal>" )(scope);
var el = this.$compile( "<permissions-modal component='component' permissions='permissions' callback='callback' class='modal'></permissions-modal>" )(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( "<component-modal component='component' class='component-modal'></component-modal>" )(scope);
var el = this.$compile( "<component-modal component='component' class='modal'></component-modal>" )(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;
}
}

View File

@@ -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);
});
}

View File

@@ -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);
}

View File

@@ -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);

View File

@@ -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) {

View File

@@ -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];
}
})
}

View File

@@ -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);

View File

@@ -33,6 +33,9 @@
#account-panel {
width: 400px;
}
.panel {
cursor: default;
}

View File

@@ -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%;
}
}

View File

@@ -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;"}

View File

@@ -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}}"}

View File

@@ -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

View File

@@ -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()"}

View File

@@ -1,4 +1,4 @@
.panel.panel-default.account-panel.panel-right#global-ext-menu
.panel#global-ext-menu
.panel-body
.container
.float-group.h20

View File

@@ -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 <i>Trusted</i> 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

View File

@@ -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.

View File

@@ -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

View File

@@ -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 */