Updates
This commit is contained in:
@@ -58,22 +58,20 @@ angular.module('app.frontend')
|
||||
}
|
||||
|
||||
let associatedEditor = this.editorForNote(note);
|
||||
if(associatedEditor) {
|
||||
if(associatedEditor && associatedEditor != this.selectedEditor) {
|
||||
// setting note to not ready will remove the editor from view in a flash,
|
||||
// so we only want to do this if switching between external editors
|
||||
this.noteReady = false;
|
||||
} else {
|
||||
onReady();
|
||||
}
|
||||
|
||||
// Activate new editor if it's different from the one currently activated
|
||||
if(associatedEditor) {
|
||||
// switch after timeout, so that note data isnt posted to current editor
|
||||
// switch after timeout, so that note data isnt posted to current editor
|
||||
$timeout(() => {
|
||||
this.selectedEditor = associatedEditor;
|
||||
onReady();
|
||||
})
|
||||
} else if(associatedEditor) {
|
||||
// Same editor as currently active
|
||||
onReady();
|
||||
} else {
|
||||
// No editor
|
||||
this.selectedEditor = null;
|
||||
onReady();
|
||||
}
|
||||
@@ -106,7 +104,6 @@ angular.module('app.frontend')
|
||||
}
|
||||
|
||||
this.selectEditor = function(editor) {
|
||||
console.log("selectEditor", editor);
|
||||
this.showEditorMenu = false;
|
||||
|
||||
if(editor) {
|
||||
@@ -419,18 +416,6 @@ angular.module('app.frontend')
|
||||
this.selectedEditor = null;
|
||||
}
|
||||
}
|
||||
|
||||
if(component.active) {
|
||||
$timeout(function(){
|
||||
var iframe = componentManager.iframeForComponent(component);
|
||||
if(iframe) {
|
||||
iframe.onload = function() {
|
||||
componentManager.registerComponentWindow(component, iframe.contentWindow);
|
||||
}.bind(this);
|
||||
}
|
||||
}.bind(this));
|
||||
}
|
||||
|
||||
}.bind(this), contextRequestHandler: function(component){
|
||||
return this.note;
|
||||
}.bind(this), actionHandler: function(component, action, data){
|
||||
@@ -441,21 +426,10 @@ angular.module('app.frontend')
|
||||
element.setAttribute("style", `width:${widthString}; height:${heightString}; `);
|
||||
}
|
||||
|
||||
if(data.type === "content") {
|
||||
var iframe = componentManager.iframeForComponent(component);
|
||||
var width = data.width;
|
||||
var height = data.height;
|
||||
iframe.width = width;
|
||||
iframe.height = height;
|
||||
|
||||
setSize(iframe, data);
|
||||
} else {
|
||||
if(data.type == "container") {
|
||||
if(component.area == "note-tags") {
|
||||
var container = document.getElementById("note-tags-component-container");
|
||||
setSize(container, data);
|
||||
} else {
|
||||
var container = document.getElementById("component-" + component.uuid);
|
||||
setSize(container, data);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -121,46 +121,49 @@ angular.module('app.frontend')
|
||||
|
||||
componentManager.registerHandler({identifier: "roomBar", areas: ["rooms"], activationHandler: (component) => {
|
||||
if(component.active) {
|
||||
// Show room, if it was not activated manually (in the event of event from componentManager)
|
||||
if(!component.showRoom) {
|
||||
this.selectRoom(component);
|
||||
}
|
||||
$timeout(() => {
|
||||
var iframe = componentManager.iframeForComponent(component);
|
||||
if(iframe) {
|
||||
var lastSize = component.getRoomLastSize();
|
||||
if(lastSize) {
|
||||
componentManager.handleSetSizeEvent(component, lastSize);
|
||||
}
|
||||
iframe.onload = function() {
|
||||
componentManager.registerComponentWindow(component, iframe.contentWindow);
|
||||
}.bind(this);
|
||||
var lastSize = component.getRoomLastSize();
|
||||
if(lastSize) {
|
||||
componentManager.handleSetSizeEvent(component, lastSize);
|
||||
}
|
||||
});
|
||||
}
|
||||
}, actionHandler: (component, action, data) => {
|
||||
if(action == "set-size") {
|
||||
componentManager.handleSetSizeEvent(component, data);
|
||||
component.setRoomLastSize(data);
|
||||
}
|
||||
}});
|
||||
|
||||
this.selectRoom = function(room) {
|
||||
room.show = !room.show;
|
||||
|
||||
// Allows us to send messages to component modal directive
|
||||
if(!room.directiveController) {
|
||||
room.directiveController = {};
|
||||
room.directiveController = {onDismiss: () => {
|
||||
room.showRoom = false;
|
||||
}};
|
||||
}
|
||||
|
||||
if(!room.show) {
|
||||
room.directiveController.dismiss();
|
||||
}
|
||||
// Make sure to call dismiss() before setting new showRoom value
|
||||
// This way the directive stays alive long enough to deactivate the associated component
|
||||
// (The directive's life is at the mercy of "ng-if" => "room.showRoom")
|
||||
if(room.showRoom) {
|
||||
room.directiveController.dismiss(() => {
|
||||
|
||||
console.log("Show", room.show);
|
||||
});
|
||||
} else {
|
||||
room.showRoom = true;
|
||||
}
|
||||
}
|
||||
|
||||
// Handle singleton ProLink instance
|
||||
singletonManager.registerSingleton({content_type: "SN|Component", package_info: {identifier: "org.standardnotes.prolink"}}, (resolvedSingleton) => {
|
||||
console.log("Roombar received resolved ProLink", resolvedSingleton);
|
||||
|
||||
}, (valueCallback) => {
|
||||
console.log("Creating prolink");
|
||||
|
||||
// Safe to create. Create and return object.
|
||||
let url = window._prolink_package_url;
|
||||
packageManager.installPackage(url, (component) => {
|
||||
|
||||
@@ -63,19 +63,9 @@ angular.module('app.frontend')
|
||||
componentManager.registerHandler({identifier: "tags", areas: ["tags-list"], activationHandler: function(component){
|
||||
this.component = component;
|
||||
|
||||
if(component.active) {
|
||||
$timeout(function(){
|
||||
var iframe = document.getElementById("tags-list-iframe");
|
||||
iframe.onload = function() {
|
||||
componentManager.registerComponentWindow(this.component, iframe.contentWindow);
|
||||
}.bind(this);
|
||||
}.bind(this));
|
||||
}
|
||||
|
||||
}.bind(this), contextRequestHandler: function(component){
|
||||
return null;
|
||||
}.bind(this), actionHandler: function(component, action, data){
|
||||
|
||||
if(action === "select-item") {
|
||||
var tag = modelManager.findItem(data.item.uuid);
|
||||
if(tag) {
|
||||
@@ -86,7 +76,6 @@ angular.module('app.frontend')
|
||||
else if(action === "clear-selection") {
|
||||
this.selectTag(this.allTag);
|
||||
}
|
||||
|
||||
}.bind(this)});
|
||||
|
||||
this.setAllTag = function(allTag) {
|
||||
|
||||
@@ -73,6 +73,14 @@ class Component extends Item {
|
||||
return "SN|Component";
|
||||
}
|
||||
|
||||
computedUrl() {
|
||||
if(this.offlineOnly || (isDesktopApplication() && this.local_url)) {
|
||||
return this.local_url.replace("sn://", this.desktopManager.getApplicationDataPath() + "/");
|
||||
} else {
|
||||
return this.url || this.hosted_url;
|
||||
}
|
||||
}
|
||||
|
||||
isEditor() {
|
||||
return this.area == "editor-editor";
|
||||
}
|
||||
|
||||
@@ -1,27 +1,9 @@
|
||||
class Theme extends Item {
|
||||
class Theme extends Component {
|
||||
|
||||
constructor(json_obj) {
|
||||
super(json_obj);
|
||||
}
|
||||
|
||||
mapContentToLocalProperties(content) {
|
||||
super.mapContentToLocalProperties(content)
|
||||
this.url = content.url;
|
||||
this.name = content.name;
|
||||
}
|
||||
|
||||
structureParams() {
|
||||
var params = {
|
||||
url: this.url,
|
||||
name: this.name
|
||||
};
|
||||
|
||||
_.merge(params, super.structureParams());
|
||||
return params;
|
||||
}
|
||||
|
||||
toJSON() {
|
||||
return {uuid: this.uuid}
|
||||
this.area = "themes";
|
||||
}
|
||||
|
||||
get content_type() {
|
||||
|
||||
@@ -296,7 +296,6 @@ angular.module('app.frontend')
|
||||
let prefsContentType = "SN|UserPreferences";
|
||||
|
||||
singletonManager.registerSingleton({content_type: prefsContentType}, (resolvedSingleton) => {
|
||||
console.log("AuthManager received resolved UserPreferences", resolvedSingleton);
|
||||
this.userPreferences = resolvedSingleton;
|
||||
this.userPreferencesDidChange();
|
||||
}, (valueCallback) => {
|
||||
@@ -304,7 +303,6 @@ angular.module('app.frontend')
|
||||
var prefs = new Item({content_type: prefsContentType});
|
||||
modelManager.addItem(prefs);
|
||||
prefs.setDirty(true);
|
||||
console.log("Created new prefs", prefs);
|
||||
$rootScope.sync();
|
||||
valueCallback(prefs);
|
||||
});
|
||||
|
||||
@@ -3,12 +3,11 @@ let ClientDataDomain = "org.standardnotes.sn.components";
|
||||
|
||||
class ComponentManager {
|
||||
|
||||
constructor($rootScope, modelManager, syncManager, desktopManager, themeManager, $timeout, $compile) {
|
||||
constructor($rootScope, modelManager, syncManager, desktopManager, $timeout, $compile) {
|
||||
this.$compile = $compile;
|
||||
this.$rootScope = $rootScope;
|
||||
this.modelManager = modelManager;
|
||||
this.syncManager = syncManager;
|
||||
this.themeManager = themeManager;
|
||||
this.desktopManager = desktopManager;
|
||||
this.timeout = $timeout;
|
||||
this.streamObservers = [];
|
||||
@@ -21,9 +20,9 @@ class ComponentManager {
|
||||
|
||||
this.handlers = [];
|
||||
|
||||
$rootScope.$on("theme-changed", function(){
|
||||
this.postThemeToComponents();
|
||||
}.bind(this))
|
||||
// $rootScope.$on("theme-changed", function(){
|
||||
// this.postThemeToAllComponents();
|
||||
// }.bind(this))
|
||||
|
||||
window.addEventListener("message", function(event){
|
||||
if(this.loggingEnabled) {
|
||||
@@ -32,7 +31,7 @@ class ComponentManager {
|
||||
this.handleMessage(this.componentForSessionKey(event.data.sessionKey), event.data);
|
||||
}.bind(this), false);
|
||||
|
||||
this.modelManager.addItemSyncObserver("component-manager", "*", function(allItems, validItems, deletedItems, source) {
|
||||
this.modelManager.addItemSyncObserver("component-manager", "*", (allItems, validItems, deletedItems, source) => {
|
||||
|
||||
/* If the source of these new or updated items is from a Component itself saving items, we don't need to notify
|
||||
components again of the same item. Regarding notifying other components than the issuing component, other mapping sources
|
||||
@@ -42,7 +41,9 @@ class ComponentManager {
|
||||
return;
|
||||
}
|
||||
|
||||
var syncedComponents = allItems.filter(function(item){return item.content_type === "SN|Component" });
|
||||
var syncedComponents = allItems.filter(function(item) {
|
||||
return item.content_type === "SN|Component" || item.content_type == "SN|Theme"
|
||||
});
|
||||
|
||||
/* We only want to sync if the item source is Retrieved, not MappingSourceRemoteSaved to avoid
|
||||
recursion caused by the component being modified and saved after it is updated.
|
||||
@@ -77,9 +78,10 @@ class ComponentManager {
|
||||
}
|
||||
];
|
||||
|
||||
this.runWithPermissions(observer.component, requiredPermissions, observer.originalMessage.permissions, function(){
|
||||
this.runWithPermissions(observer.component, requiredPermissions, () => {
|
||||
console.log("Stream observer, sending items", relevantItems);
|
||||
this.sendItemsInReply(observer.component, relevantItems, observer.originalMessage);
|
||||
}.bind(this))
|
||||
})
|
||||
}
|
||||
|
||||
var requiredContextPermissions = [
|
||||
@@ -89,36 +91,43 @@ class ComponentManager {
|
||||
];
|
||||
|
||||
for(let observer of this.contextStreamObservers) {
|
||||
this.runWithPermissions(observer.component, requiredContextPermissions, observer.originalMessage.permissions, function(){
|
||||
for(let handler of this.handlers) {
|
||||
if(!handler.areas.includes(observer.component.area)) {
|
||||
continue;
|
||||
}
|
||||
for(let handler of this.handlers) {
|
||||
if(!handler.areas.includes(observer.component.area) && !handler.areas.includes("*")) {
|
||||
continue;
|
||||
}
|
||||
if(handler.contextRequestHandler) {
|
||||
var itemInContext = handler.contextRequestHandler(observer.component);
|
||||
if(itemInContext) {
|
||||
var matchingItem = _.find(allItems, {uuid: itemInContext.uuid});
|
||||
if(matchingItem) {
|
||||
this.sendContextItemInReply(observer.component, matchingItem, observer.originalMessage, source);
|
||||
this.runWithPermissions(observer.component, requiredContextPermissions, () => {
|
||||
this.sendContextItemInReply(observer.component, matchingItem, observer.originalMessage, source);
|
||||
})
|
||||
}
|
||||
}
|
||||
}
|
||||
}.bind(this))
|
||||
}
|
||||
}
|
||||
}.bind(this))
|
||||
});
|
||||
}
|
||||
|
||||
postThemeToComponents() {
|
||||
postThemeToAllComponents() {
|
||||
for(var component of this.components) {
|
||||
if(!component.active || !component.window) {
|
||||
if(component.area == "themes" || !component.active || !component.window) {
|
||||
continue;
|
||||
}
|
||||
this.postThemeToComponent(component);
|
||||
}
|
||||
}
|
||||
|
||||
getActiveTheme() {
|
||||
return this.componentsForArea("themes").find((theme) => {return theme.active});
|
||||
}
|
||||
|
||||
postThemeToComponent(component) {
|
||||
var activeTheme = this.getActiveTheme();
|
||||
var data = {
|
||||
themes: [this.themeManager.currentTheme ? this.themeManager.currentTheme.url : null]
|
||||
themes: [activeTheme ? activeTheme.computedUrl() : null]
|
||||
}
|
||||
|
||||
this.sendMessageToComponent(component, {action: "themes", data: data})
|
||||
@@ -126,7 +135,7 @@ class ComponentManager {
|
||||
|
||||
contextItemDidChangeInArea(area) {
|
||||
for(let handler of this.handlers) {
|
||||
if(handler.areas.includes(area) === false) {
|
||||
if(handler.areas.includes(area) === false && !handler.areas.includes("*")) {
|
||||
continue;
|
||||
}
|
||||
var observers = this.contextStreamObservers.filter(function(observer){
|
||||
@@ -134,8 +143,10 @@ class ComponentManager {
|
||||
})
|
||||
|
||||
for(let observer of observers) {
|
||||
var itemInContext = handler.contextRequestHandler(observer.component);
|
||||
this.sendContextItemInReply(observer.component, itemInContext, observer.originalMessage);
|
||||
if(handler.contextRequestHandler) {
|
||||
var itemInContext = handler.contextRequestHandler(observer.component);
|
||||
this.sendContextItemInReply(observer.component, itemInContext, observer.originalMessage);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -176,7 +187,7 @@ class ComponentManager {
|
||||
}
|
||||
|
||||
get components() {
|
||||
return this.modelManager.itemsForContentType("SN|Component");
|
||||
return this.modelManager.allItemsMatchingTypes(["SN|Component", "SN|Theme"]);
|
||||
}
|
||||
|
||||
componentsForArea(area) {
|
||||
@@ -220,7 +231,7 @@ class ComponentManager {
|
||||
save-context-client-data
|
||||
get-context-client-data
|
||||
install-local-component
|
||||
open-component
|
||||
toggle-activate-component
|
||||
*/
|
||||
|
||||
if(message.action === "stream-items") {
|
||||
@@ -237,14 +248,14 @@ class ComponentManager {
|
||||
this.handleSaveItemsMessage(component, message);
|
||||
} else if(message.action === "install-local-component") {
|
||||
this.handleInstallLocalComponentMessage(component, message);
|
||||
} else if(message.action === "open-component") {
|
||||
let openComponent = this.modelManager.findItem(message.data.uuid);
|
||||
this.openModalComponent(openComponent);
|
||||
} else if(message.action === "toggle-activate-component") {
|
||||
let componentToToggle = this.modelManager.findItem(message.data.uuid);
|
||||
this.handleToggleComponentMessage(component, componentToToggle, message);
|
||||
}
|
||||
|
||||
// Notify observers
|
||||
for(let handler of this.handlers) {
|
||||
if(handler.areas.includes(component.area)) {
|
||||
if(handler.areas.includes(component.area) || handler.areas.includes("*")) {
|
||||
this.timeout(function(){
|
||||
handler.actionHandler(component, message.action, message.data);
|
||||
})
|
||||
@@ -254,7 +265,7 @@ class ComponentManager {
|
||||
|
||||
removePrivatePropertiesFromResponseItems(responseItems, includeUrls) {
|
||||
// Don't allow component to overwrite these properties.
|
||||
var privateProperties = ["appData", "autoupdate", "permissions", "active"];
|
||||
var privateProperties = ["appData", "autoupdate", "permissions", "active", "encrypted"];
|
||||
if(includeUrls) {
|
||||
privateProperties = privateProperties.concat(["url", "hosted_url", "local_url"]);
|
||||
}
|
||||
@@ -278,7 +289,7 @@ class ComponentManager {
|
||||
}
|
||||
];
|
||||
|
||||
this.runWithPermissions(component, requiredPermissions, message.permissions, function(){
|
||||
this.runWithPermissions(component, requiredPermissions, () => {
|
||||
if(!_.find(this.streamObservers, {identifier: component.uuid})) {
|
||||
// for pushing laster as changes come in
|
||||
this.streamObservers.push({
|
||||
@@ -289,14 +300,13 @@ class ComponentManager {
|
||||
})
|
||||
}
|
||||
|
||||
|
||||
// push immediately now
|
||||
var items = [];
|
||||
for(var contentType of message.data.content_types) {
|
||||
items = items.concat(this.modelManager.itemsForContentType(contentType));
|
||||
}
|
||||
this.sendItemsInReply(component, items, message);
|
||||
}.bind(this));
|
||||
});
|
||||
}
|
||||
|
||||
handleStreamContextItemMessage(component, message) {
|
||||
@@ -307,7 +317,7 @@ class ComponentManager {
|
||||
}
|
||||
];
|
||||
|
||||
this.runWithPermissions(component, requiredPermissions, message.permissions, function(){
|
||||
this.runWithPermissions(component, requiredPermissions, function(){
|
||||
if(!_.find(this.contextStreamObservers, {identifier: component.uuid})) {
|
||||
// for pushing laster as changes come in
|
||||
this.contextStreamObservers.push({
|
||||
@@ -318,27 +328,49 @@ class ComponentManager {
|
||||
}
|
||||
|
||||
// push immediately now
|
||||
for(let handler of this.handlers) {
|
||||
if(handler.areas.includes(component.area) === false) {
|
||||
continue;
|
||||
}
|
||||
for(let handler of this.handlersForArea(component.area)) {
|
||||
var itemInContext = handler.contextRequestHandler(component);
|
||||
this.sendContextItemInReply(component, itemInContext, message);
|
||||
}
|
||||
}.bind(this))
|
||||
}
|
||||
|
||||
handleSaveItemsMessage(component, message) {
|
||||
var requiredContentTypes = _.uniq(message.data.items.map((i) => {return i.content_type})).sort();
|
||||
var requiredPermissions = [
|
||||
{
|
||||
name: "stream-items",
|
||||
content_types: requiredContentTypes
|
||||
isItemWithinComponentContextJurisdiction(item, component) {
|
||||
for(let handler of this.handlersForArea(component.area)) {
|
||||
var itemInContext = handler.contextRequestHandler(component);
|
||||
if(itemInContext.uuid == item.uuid) {
|
||||
return true;
|
||||
}
|
||||
];
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
this.runWithPermissions(component, requiredPermissions, message.permissions, () => {
|
||||
var responseItems = message.data.items;
|
||||
handlersForArea(area) {
|
||||
return this.handlers.filter((candidate) => {return candidate.areas.includes(area)});
|
||||
}
|
||||
|
||||
handleSaveItemsMessage(component, message) {
|
||||
var responseItems = message.data.items;
|
||||
var requiredPermissions;
|
||||
|
||||
// Check if you're just trying to save the context item, which requires only stream-context-item permissions
|
||||
if(responseItems.length == 1 && this.isItemWithinComponentContextJurisdiction(responseItems[0], component)) {
|
||||
requiredPermissions = [
|
||||
{
|
||||
name: "stream-context-item"
|
||||
}
|
||||
];
|
||||
} else {
|
||||
var requiredContentTypes = _.uniq(responseItems.map((i) => {return i.content_type})).sort();
|
||||
requiredPermissions = [
|
||||
{
|
||||
name: "stream-items",
|
||||
content_types: requiredContentTypes
|
||||
}
|
||||
];
|
||||
}
|
||||
|
||||
this.runWithPermissions(component, requiredPermissions, () => {
|
||||
|
||||
this.removePrivatePropertiesFromResponseItems(responseItems, {includeUrls: true});
|
||||
|
||||
@@ -373,7 +405,7 @@ class ComponentManager {
|
||||
}
|
||||
];
|
||||
|
||||
this.runWithPermissions(component, requiredPermissions, message.permissions, () => {
|
||||
this.runWithPermissions(component, requiredPermissions, () => {
|
||||
var responseItem = message.data.item;
|
||||
this.removePrivatePropertiesFromResponseItems([responseItem]);
|
||||
var item = this.modelManager.createItem(responseItem);
|
||||
@@ -397,7 +429,7 @@ class ComponentManager {
|
||||
}
|
||||
];
|
||||
|
||||
this.runWithPermissions(component, requiredPermissions, message.permissions, () => {
|
||||
this.runWithPermissions(component, requiredPermissions, () => {
|
||||
var items = message.data.items;
|
||||
var noun = items.length == 1 ? "item" : "items";
|
||||
if(confirm(`Are you sure you want to delete ${items.length} ${noun}?`)) {
|
||||
@@ -419,10 +451,8 @@ class ComponentManager {
|
||||
}
|
||||
];
|
||||
|
||||
this.runWithPermissions(component, requiredPermissions, message.permissions, () => {
|
||||
console.log("Received install-local-component event");
|
||||
this.runWithPermissions(component, requiredPermissions, () => {
|
||||
this.desktopManager.installOfflineComponentFromData(message.data, (response) => {
|
||||
console.log("componentManager: installed component:", response);
|
||||
var component = this.modelManager.mapResponseItemsToLocalModels([response], ModelManager.MappingSourceComponentRetrieved)[0];
|
||||
// Save updated URL
|
||||
component.setDirty(true);
|
||||
@@ -432,68 +462,73 @@ class ComponentManager {
|
||||
}
|
||||
|
||||
handleSetComponentDataMessage(component, message) {
|
||||
var requiredPermissions = [
|
||||
{
|
||||
name: "stream-items",
|
||||
content_types: [component.content_type]
|
||||
}
|
||||
];
|
||||
|
||||
this.runWithPermissions(component, requiredPermissions, message.permissions, () => {
|
||||
// A component setting its own data does not require special permissions
|
||||
this.runWithPermissions(component, [], () => {
|
||||
component.componentData = message.data.componentData;
|
||||
component.setDirty(true);
|
||||
this.syncManager.sync();
|
||||
});
|
||||
}
|
||||
|
||||
runWithPermissions(component, requiredPermissions, requestedPermissions, runFunction) {
|
||||
|
||||
var acquiredPermissions = component.permissions;
|
||||
|
||||
var requestedMatchesRequired = true;
|
||||
|
||||
for(var required of requiredPermissions) {
|
||||
var matching = _.find(requestedPermissions, required);
|
||||
var matching = requestedPermissions.filter((p) => {
|
||||
var matchesContentTypes = true;
|
||||
if(p.content_types) {
|
||||
matchesContentTypes = JSON.stringify(p.content_types.sort()) == JSON.stringify(required.content_types.sort());
|
||||
}
|
||||
return p.name == required.name && matchesContentTypes;
|
||||
})[0];
|
||||
|
||||
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
|
||||
*/
|
||||
matching = requestedPermissions.filter((requested) => {
|
||||
return Array.isArray(requested.content_types) && requested.content_types.containsSubset(required.content_types);
|
||||
});
|
||||
|
||||
console.log("Matching 2nd chance", matching);
|
||||
|
||||
if(!matching) {
|
||||
requestedMatchesRequired = false;
|
||||
break;
|
||||
handleToggleComponentMessage(sourceComponent, targetComponent, message) {
|
||||
if(targetComponent.area == "modal") {
|
||||
this.openModalComponent(targetComponent);
|
||||
} else {
|
||||
if(targetComponent.active) {
|
||||
this.deactivateComponent(targetComponent);
|
||||
} else {
|
||||
if(targetComponent.content_type == "SN|Theme") {
|
||||
// Deactive currently active theme
|
||||
var activeTheme = this.getActiveTheme();
|
||||
if(activeTheme) {
|
||||
this.deactivateComponent(activeTheme);
|
||||
}
|
||||
}
|
||||
this.activateComponent(targetComponent);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if(!requestedMatchesRequired) {
|
||||
// Error with Component permissions request
|
||||
console.error("You are requesting permissions", requestedPermissions, "when you need to be requesting", requiredPermissions, ". Component:", component);
|
||||
return false;
|
||||
}
|
||||
|
||||
runWithPermissions(component, requiredPermissions, runFunction) {
|
||||
|
||||
if(!component.permissions) {
|
||||
component.permissions = [];
|
||||
}
|
||||
|
||||
var acquiredMatchesRequested = angular.toJson(component.permissions.sort()) === angular.toJson(requestedPermissions.sort());
|
||||
var acquiredPermissions = component.permissions;
|
||||
var acquiredMatchesRequired = true;
|
||||
|
||||
if(!acquiredMatchesRequested) {
|
||||
this.promptForPermissions(component, requestedPermissions, function(approved){
|
||||
for(var required of requiredPermissions) {
|
||||
var matching = acquiredPermissions.find((candidate) => {
|
||||
var matchesContentTypes = true;
|
||||
if(candidate.content_types && required.content_types) {
|
||||
matchesContentTypes = JSON.stringify(candidate.content_types.sort()) == JSON.stringify(required.content_types.sort());
|
||||
}
|
||||
return candidate.name == required.name && matchesContentTypes;
|
||||
});
|
||||
|
||||
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
|
||||
*/
|
||||
matching = acquiredPermissions.find((candidate) => {
|
||||
return Array.isArray(candidate.content_types)
|
||||
&& Array.isArray(required.content_types)
|
||||
&& candidate.content_types.containsSubset(required.content_types);
|
||||
});
|
||||
|
||||
if(!matching) {
|
||||
acquiredMatchesRequired = false;
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// var acquiredMatchesRequested = angular.toJson(component.permissions.sort()) === angular.toJson(requestedPermissions.sort());
|
||||
|
||||
if(!acquiredMatchesRequired) {
|
||||
this.promptForPermissions(component, requiredPermissions, function(approved){
|
||||
if(approved) {
|
||||
runFunction();
|
||||
}
|
||||
@@ -503,18 +538,22 @@ class ComponentManager {
|
||||
}
|
||||
}
|
||||
|
||||
promptForPermissions(component, requestedPermissions, callback) {
|
||||
promptForPermissions(component, permissions, callback) {
|
||||
// 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});
|
||||
|
||||
var scope = this.$rootScope.$new(true);
|
||||
scope.component = component;
|
||||
scope.permissions = requestedPermissions;
|
||||
scope.permissions = permissions;
|
||||
scope.actionBlock = callback;
|
||||
|
||||
scope.callback = function(approved) {
|
||||
if(approved) {
|
||||
component.permissions = requestedPermissions;
|
||||
for(var permission of permissions) {
|
||||
if(!component.permissions.includes(permission)) {
|
||||
component.permissions.push(permission);
|
||||
}
|
||||
}
|
||||
component.setDirty(true);
|
||||
this.syncManager.sync();
|
||||
}
|
||||
@@ -544,6 +583,9 @@ class ComponentManager {
|
||||
openModalComponent(component) {
|
||||
var scope = this.$rootScope.$new(true);
|
||||
scope.component = component;
|
||||
scope.onDismiss = () => {
|
||||
|
||||
}
|
||||
var el = this.$compile( "<component-modal component='component' class='modal'></component-modal>" )(scope);
|
||||
angular.element(document.body).append(el);
|
||||
}
|
||||
@@ -591,7 +633,7 @@ class ComponentManager {
|
||||
|
||||
component.active = true;
|
||||
for(var handler of this.handlers) {
|
||||
if(handler.areas.includes(component.area)) {
|
||||
if(handler.areas.includes(component.area) || handler.areas.includes("*")) {
|
||||
handler.activationHandler(component);
|
||||
}
|
||||
}
|
||||
@@ -604,6 +646,10 @@ class ComponentManager {
|
||||
if(!this.activeComponents.includes(component)) {
|
||||
this.activeComponents.push(component);
|
||||
}
|
||||
|
||||
if(component.area == "themes") {
|
||||
this.postThemeToAllComponents();
|
||||
}
|
||||
}
|
||||
|
||||
registerHandler(handler) {
|
||||
@@ -640,12 +686,13 @@ class ComponentManager {
|
||||
}
|
||||
|
||||
deactivateComponent(component) {
|
||||
console.log("Deactivating component", component);
|
||||
var didChange = component.active != false;
|
||||
component.active = false;
|
||||
component.sessionKey = null;
|
||||
|
||||
for(var handler of this.handlers) {
|
||||
if(handler.areas.includes(component.area)) {
|
||||
if(handler.areas.includes(component.area) || handler.areas.includes("*")) {
|
||||
handler.activationHandler(component);
|
||||
}
|
||||
}
|
||||
@@ -664,6 +711,10 @@ class ComponentManager {
|
||||
this.contextStreamObservers = this.contextStreamObservers.filter(function(o){
|
||||
return o.component !== component;
|
||||
})
|
||||
|
||||
if(component.area == "themes") {
|
||||
this.postThemeToAllComponents();
|
||||
}
|
||||
}
|
||||
|
||||
deleteComponent(component) {
|
||||
@@ -713,14 +764,6 @@ class ComponentManager {
|
||||
component.ignoreEvents = !on;
|
||||
}
|
||||
|
||||
urlForComponent(component) {
|
||||
if(isDesktopApplication() && component.local_url) {
|
||||
return component.local_url.replace("sn://", this.desktopManager.getApplicationDataPath() + "/");
|
||||
} else {
|
||||
return component.url || component.hosted_url;
|
||||
}
|
||||
}
|
||||
|
||||
iframeForComponent(component) {
|
||||
for(var frame of document.getElementsByTagName("iframe")) {
|
||||
var componentId = frame.dataset.componentId;
|
||||
|
||||
@@ -6,8 +6,8 @@ class ComponentModal {
|
||||
this.scope = {
|
||||
show: "=",
|
||||
component: "=",
|
||||
controller: "=",
|
||||
callback: "="
|
||||
callback: "=",
|
||||
onDismiss: "&"
|
||||
};
|
||||
}
|
||||
|
||||
@@ -18,42 +18,23 @@ class ComponentModal {
|
||||
controller($scope, $timeout, componentManager) {
|
||||
'ngInject';
|
||||
|
||||
let identifier = "modal-" + $scope.component.uuid;
|
||||
|
||||
$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);
|
||||
}
|
||||
|
||||
componentManager.registerHandler({identifier: identifier, areas: ["modal"], 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));
|
||||
if($scope.component.directiveController) {
|
||||
$scope.component.directiveController.dismiss = function(callback) {
|
||||
$scope.dismiss(callback);
|
||||
}
|
||||
},
|
||||
actionHandler: function(component, action, data) {
|
||||
if(action == "set-size") {
|
||||
componentManager.handleSetSizeEvent(component, data);
|
||||
}
|
||||
}.bind(this)});
|
||||
}
|
||||
|
||||
$scope.dismiss = function(callback) {
|
||||
var onDismiss = $scope.component.directiveController && $scope.component.directiveController.onDismiss();
|
||||
// Setting will null out compinent-view's component, which will handle deactivation
|
||||
$scope.component = null;
|
||||
$timeout(() => {
|
||||
$scope.el.remove();
|
||||
onDismiss && onDismiss();
|
||||
callback && callback();
|
||||
})
|
||||
}
|
||||
|
||||
componentManager.activateComponent($scope.component);
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
@@ -1,18 +1,41 @@
|
||||
class ComponentView {
|
||||
|
||||
constructor() {
|
||||
constructor(componentManager, $timeout) {
|
||||
this.restrict = "E";
|
||||
this.templateUrl = "frontend/directives/component-view.html";
|
||||
this.scope = {
|
||||
component: "="
|
||||
};
|
||||
|
||||
this.componentManager = componentManager;
|
||||
this.timeout = $timeout;
|
||||
}
|
||||
|
||||
link($scope, el, attrs, ctrl) {
|
||||
$scope.el = el;
|
||||
|
||||
let identifier = "component-view-" + Math.random();
|
||||
|
||||
this.componentManager.registerHandler({identifier: identifier, areas: ["*"], activationHandler: (component) => {
|
||||
if(component.active) {
|
||||
this.timeout(function(){
|
||||
var iframe = this.componentManager.iframeForComponent(component);
|
||||
if(iframe) {
|
||||
iframe.onload = function() {
|
||||
this.componentManager.registerComponentWindow(component, iframe.contentWindow);
|
||||
}.bind(this);
|
||||
}
|
||||
}.bind(this));
|
||||
}
|
||||
},
|
||||
actionHandler: function(component, action, data) {
|
||||
if(action == "set-size") {
|
||||
this.componentManager.handleSetSizeEvent(component, data);
|
||||
}
|
||||
}.bind(this)});
|
||||
|
||||
$scope.$watch('component', function(component, prevComponent){
|
||||
console.log("Component View Setting Component", component);
|
||||
// console.log("Component View Setting Component", component);
|
||||
ctrl.componentValueChanging(component, prevComponent);
|
||||
});
|
||||
}
|
||||
@@ -20,6 +43,8 @@ class ComponentView {
|
||||
controller($scope, $timeout, componentManager, desktopManager) {
|
||||
'ngInject';
|
||||
|
||||
console.log("Creating New Component View");
|
||||
|
||||
this.componentValueChanging = (component, prevComponent) => {
|
||||
if(prevComponent && component !== prevComponent) {
|
||||
// Deactive old component
|
||||
@@ -33,39 +58,15 @@ class ComponentView {
|
||||
}
|
||||
}
|
||||
|
||||
let identifier = "component-view-" + Math.random();
|
||||
|
||||
$scope.url = function() {
|
||||
if($scope.component.offlineOnly) {
|
||||
return $scope.component.local_url;
|
||||
$scope.$on("$destroy", function() {
|
||||
console.log("DESTROY COMPONENT VIEW");
|
||||
componentManager.deregisterHandler($scope.identifier);
|
||||
if($scope.component) {
|
||||
componentManager.deactivateComponent($scope.component);
|
||||
}
|
||||
|
||||
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);
|
||||
angular.module('app.frontend').directive('componentView', (componentManager, $timeout) => new ComponentView(componentManager, $timeout));
|
||||
|
||||
@@ -30,7 +30,6 @@ class EditorMenu {
|
||||
}
|
||||
|
||||
$scope.toggleDefaultForEditor = function(editor) {
|
||||
console.log("Toggling editor", editor);
|
||||
if($scope.defaultEditor == editor) {
|
||||
$scope.removeEditorDefault(editor);
|
||||
} else {
|
||||
|
||||
@@ -30,8 +30,6 @@ class PermissionsModal {
|
||||
|
||||
controller($scope, modelManager) {
|
||||
|
||||
console.log("permissions", $scope.permissions);
|
||||
|
||||
$scope.formattedPermissions = $scope.permissions.map(function(permission){
|
||||
if(permission.name === "stream-items") {
|
||||
var types = permission.content_types.map(function(type){
|
||||
|
||||
@@ -1,54 +1,65 @@
|
||||
class ThemeManager {
|
||||
|
||||
constructor(modelManager, syncManager, $rootScope, storageManager) {
|
||||
constructor(modelManager, syncManager, $rootScope, storageManager, componentManager) {
|
||||
this.syncManager = syncManager;
|
||||
this.modelManager = modelManager;
|
||||
this.$rootScope = $rootScope;
|
||||
this.storageManager = storageManager;
|
||||
|
||||
componentManager.registerHandler({identifier: "themeManager", areas: ["themes"], activationHandler: (component) => {
|
||||
if(component.active) {
|
||||
this.activateTheme(component);
|
||||
} else {
|
||||
this.deactivateTheme(component);
|
||||
}
|
||||
}});
|
||||
}
|
||||
|
||||
get themes() {
|
||||
return this.modelManager.itemsForContentType("SN|Theme");
|
||||
}
|
||||
|
||||
|
||||
/*
|
||||
activeTheme: computed property that returns saved theme
|
||||
currentTheme: stored variable that allows other classes to watch changes
|
||||
*/
|
||||
|
||||
get activeTheme() {
|
||||
var activeThemeId = this.storageManager.getItem("activeTheme");
|
||||
if(!activeThemeId) {
|
||||
return null;
|
||||
}
|
||||
|
||||
var theme = _.find(this.themes, {uuid: activeThemeId});
|
||||
return theme;
|
||||
}
|
||||
// get activeTheme() {
|
||||
// var activeThemeId = this.storageManager.getItem("activeTheme");
|
||||
// if(!activeThemeId) {
|
||||
// return null;
|
||||
// }
|
||||
//
|
||||
// var theme = _.find(this.themes, {uuid: activeThemeId});
|
||||
// return theme;
|
||||
// }
|
||||
|
||||
activateInitialTheme() {
|
||||
var theme = this.activeTheme;
|
||||
if(theme) {
|
||||
this.activateTheme(theme);
|
||||
}
|
||||
// var theme = this.activeTheme;
|
||||
// if(theme) {
|
||||
// this.activateTheme(theme);
|
||||
// }
|
||||
}
|
||||
|
||||
submitTheme(url) {
|
||||
var name = this.displayNameForThemeFile(this.fileNameFromPath(url));
|
||||
var theme = this.modelManager.createItem({content_type: "SN|Theme", url: url, name: name});
|
||||
this.modelManager.addItem(theme);
|
||||
theme.setDirty(true);
|
||||
this.syncManager.sync();
|
||||
}
|
||||
// submitTheme(url) {
|
||||
// var name = this.displayNameForThemeFile(this.fileNameFromPath(url));
|
||||
// var theme = this.modelManager.createItem({content_type: "SN|Theme", url: url, name: name});
|
||||
// this.modelManager.addItem(theme);
|
||||
// theme.setDirty(true);
|
||||
// this.syncManager.sync();
|
||||
// }
|
||||
|
||||
activateTheme(theme) {
|
||||
var activeTheme = this.activeTheme;
|
||||
if(activeTheme) {
|
||||
this.deactivateTheme(activeTheme);
|
||||
if(this.activeTheme && this.activeTheme !== theme) {
|
||||
this.deactivateTheme(this.activeTheme);
|
||||
}
|
||||
|
||||
|
||||
var url = theme.computedUrl();
|
||||
|
||||
var link = document.createElement("link");
|
||||
link.href = theme.url;
|
||||
link.href = url;
|
||||
link.type = "text/css";
|
||||
link.rel = "stylesheet";
|
||||
link.media = "screen,print";
|
||||
@@ -72,10 +83,6 @@ class ThemeManager {
|
||||
this.$rootScope.$broadcast("theme-changed");
|
||||
}
|
||||
|
||||
isThemeActive(theme) {
|
||||
return this.storageManager.getItem("activeTheme") === theme.uuid;
|
||||
}
|
||||
|
||||
fileNameFromPath(filePath) {
|
||||
return filePath.replace(/^.*[\\\/]/, '');
|
||||
}
|
||||
|
||||
@@ -68,7 +68,7 @@ $heading-height: 75px;
|
||||
|
||||
#note-tags-component-container {
|
||||
height: 50px;
|
||||
#note-tags-iframe {
|
||||
iframe {
|
||||
height: 50px;
|
||||
width: 100%;
|
||||
position: absolute;
|
||||
@@ -116,8 +116,8 @@ $heading-height: 75px;
|
||||
#editor-pane-component-stack {
|
||||
width: 100%;
|
||||
|
||||
.component {
|
||||
height: 50px;
|
||||
.component-stack-item {
|
||||
// height: 50px;
|
||||
width: 100%;
|
||||
position: relative;
|
||||
&:not(:last-child) {
|
||||
@@ -128,28 +128,6 @@ $heading-height: 75px;
|
||||
border-top: 1px solid $bg-color;
|
||||
}
|
||||
|
||||
.exit-button {
|
||||
width: 15px;
|
||||
height: 100%;
|
||||
position: absolute;
|
||||
right: 0;
|
||||
background-color: transparent;
|
||||
cursor: pointer;
|
||||
display: flex;
|
||||
align-items: center;
|
||||
color: rgba(black, 0.7);
|
||||
text-align: center;
|
||||
padding-left: 2px;
|
||||
|
||||
.content {
|
||||
|
||||
}
|
||||
|
||||
&:hover {
|
||||
background-color: rgba(gray, 0.3);
|
||||
}
|
||||
}
|
||||
|
||||
iframe {
|
||||
width: 100%;
|
||||
}
|
||||
|
||||
@@ -12,6 +12,10 @@
|
||||
}
|
||||
}
|
||||
|
||||
.panel {
|
||||
background-color: white;
|
||||
}
|
||||
|
||||
.modal {
|
||||
position: fixed;
|
||||
margin-left: auto;
|
||||
@@ -44,14 +48,12 @@
|
||||
}
|
||||
}
|
||||
|
||||
.modal-iframe-container {
|
||||
// Optionally use if .component-view container is not flex-based
|
||||
.component-view-container {
|
||||
flex-grow: 1;
|
||||
display: flex;
|
||||
|
||||
iframe {
|
||||
flex-grow: 1;
|
||||
width: 100%;
|
||||
}
|
||||
height: 100%;
|
||||
width: 100%;
|
||||
}
|
||||
|
||||
.component-view {
|
||||
|
||||
7
app/assets/stylesheets/app/_stylekit-sub.scss
Normal file
7
app/assets/stylesheets/app/_stylekit-sub.scss
Normal file
@@ -0,0 +1,7 @@
|
||||
.panel {
|
||||
color: black;
|
||||
|
||||
a {
|
||||
color: $blue-color;
|
||||
}
|
||||
}
|
||||
@@ -11,5 +11,6 @@ $dark-gray: #2e2e2e;
|
||||
@import "app/menus";
|
||||
@import "app/modals";
|
||||
@import "app/lock-screen";
|
||||
@import "app/stylekit-sub";
|
||||
|
||||
@import "ionicons";
|
||||
|
||||
@@ -1,7 +1,9 @@
|
||||
.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}}"}
|
||||
.background{"ng-click" => "dismiss()"}
|
||||
|
||||
.content
|
||||
.sn-component
|
||||
.panel{"ng-attr-id" => "component-{{component.uuid}}"}
|
||||
.header
|
||||
%h1.title {{component.name}}
|
||||
%a.close-button.info{"ng-click" => "dismiss()"} Close
|
||||
%component-view.component-view{"component" => "component"}
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
%iframe{"ng-if" => "component",
|
||||
"ng-attr-id" => "component-{{component.uuid}}",
|
||||
"ng-src" => "{{url() | trusted}}", "frameBorder" => "0",
|
||||
"ng-src" => "{{component.computedUrl() | 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
|
||||
|
||||
@@ -24,8 +24,8 @@
|
||||
%h3
|
||||
%input.bold{"ng-if" => "theme.rename", "ng-model" => "theme.tempName", "ng-keyup" => "$event.keyCode == 13 && submitExtensionRename(theme);", "mb-autofocus" => "true", "should-focus" => "true"}
|
||||
%span{"ng-if" => "!theme.rename"} {{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
|
||||
-# %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
|
||||
.mt-3{"ng-if" => "theme.showDetails"}
|
||||
.link-group
|
||||
%a{"ng-click" => "renameExtension(theme); $event.stopPropagation();"} Rename
|
||||
|
||||
@@ -5,7 +5,7 @@
|
||||
.panel
|
||||
.header
|
||||
%h1.title Activate Extension
|
||||
%a.close-button.info Cancel
|
||||
%a.close-button.info{"ng-click" => "deny()"} Cancel
|
||||
.content
|
||||
.panel-section
|
||||
.panel-row
|
||||
@@ -14,7 +14,6 @@
|
||||
would like to interact with your
|
||||
%span{"ng-repeat" => "permission in formattedPermissions"}
|
||||
{{permission}}.
|
||||
-# %p.wrap URL: {{component.runningUrl}}
|
||||
|
||||
.panel-row
|
||||
%p
|
||||
|
||||
@@ -8,8 +8,8 @@
|
||||
#save-status{"ng-class" => "{'red bold': ctrl.saveError, 'orange bold': ctrl.syncTakingTooLong}", "ng-bind-html" => "ctrl.noteStatus"}
|
||||
|
||||
.editor-tags
|
||||
#note-tags-component-container{"ng-if" => "ctrl.tagsComponent && ctrl.tagsComponent.active"}
|
||||
%iframe#note-tags-iframe{"ng-src" => "{{ctrl.componentManager.urlForComponent(ctrl.tagsComponent) | trusted}}", "frameBorder" => "0", "sandbox" => "allow-scripts", "data-component-id" => "{{ctrl.tagsComponent.uuid}}"}
|
||||
#note-tags-component-container{"ng-if" => "ctrl.tagsComponent"}
|
||||
%component-view.component-view{ "component" => "ctrl.tagsComponent"}
|
||||
%input.tags-input{"ng-if" => "!(ctrl.tagsComponent && ctrl.tagsComponent.active)", "type" => "text", "ng-keyup" => "$event.keyCode == 13 && $event.target.blur();",
|
||||
"ng-model" => "ctrl.tagsString", "placeholder" => "#tags", "ng-blur" => "ctrl.updateTagsFromTagsString($event, ctrl.tagsString)"}
|
||||
|
||||
@@ -42,8 +42,7 @@
|
||||
|
||||
.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"}
|
||||
-# 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"}
|
||||
%component-view.component-view{"ng-if" => "ctrl.selectedEditor", "component" => "ctrl.selectedEditor"}
|
||||
%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()}}
|
||||
@@ -53,6 +52,4 @@
|
||||
%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.
|
||||
|
||||
#editor-pane-component-stack
|
||||
.component.component-stack-border{"ng-repeat" => "component in ctrl.componentStack", "ng-if" => "component.active", "ng-show" => "!component.ignoreEvents", "id" => "{{'component-' + component.uuid}}", "ng-mouseover" => "component.showExit = true", "ng-mouseleave" => "component.showExit = false"}
|
||||
.exit-button.body-text-color{"ng-if" => "component.showExit", "ng-click" => "ctrl.disableComponentForCurrentItem(component, true)"} ×
|
||||
%iframe{"ng-src" => "{{ctrl.componentManager.urlForComponent(component) | 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}}"}
|
||||
%component-view.component-view.component-stack-item{"ng-repeat" => "component in ctrl.componentStack", "ng-if" => "component.active", "component" => "component"}
|
||||
|
||||
@@ -22,7 +22,7 @@
|
||||
.item{"ng-repeat" => "room in ctrl.rooms"}
|
||||
.column{"ng-click" => "ctrl.selectRoom(room)"}
|
||||
.label {{room.name}}
|
||||
%component-modal{"ng-if" => "room.show", "component" => "room"}
|
||||
%component-modal{"ng-if" => "room.showRoom", "component" => "room", "controller" => "room.directiveController"}
|
||||
|
||||
|
||||
.right
|
||||
|
||||
@@ -1,5 +1,6 @@
|
||||
.section.tags#tags-column
|
||||
%iframe#tags-list-iframe{"ng-if" => "ctrl.component && ctrl.component.active", "ng-src" => "{{ctrl.componentManager.urlForComponent(ctrl.component) | trusted}}", "frameBorder" => "0", "style" => "width: 100%; height: 100%;", "sandbox" => "allow-scripts"}
|
||||
.component-view-container{"ng-if" => "ctrl.component"}
|
||||
%component-view.component-view{"component" => "ctrl.component"}
|
||||
#tags-content.content{"ng-if" => "!(ctrl.component && ctrl.component.active)"}
|
||||
#tags-title-bar.section-title-bar
|
||||
.section-title-bar-header
|
||||
|
||||
106
vendor/assets/stylesheets/stylekit.css
vendored
106
vendor/assets/stylesheets/stylekit.css
vendored
@@ -6,9 +6,12 @@
|
||||
.sn-component .panel {
|
||||
box-shadow: 0px 2px 13px #C8C8C8;
|
||||
border-radius: 0.7rem;
|
||||
overflow: scroll;
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
overflow: hidden;
|
||||
}
|
||||
.sn-component .panel a:hover {
|
||||
text-decoration: underline;
|
||||
}
|
||||
.sn-component .panel.static {
|
||||
box-shadow: none;
|
||||
@@ -28,15 +31,16 @@
|
||||
.sn-component .panel .header .close-button {
|
||||
font-weight: bold;
|
||||
}
|
||||
.sn-component .panel .footer {
|
||||
.sn-component .panel .footer, .sn-component .panel .panel-footer {
|
||||
padding: 1rem 2rem;
|
||||
border-top: 1px solid #F1F1F1;
|
||||
border-top: 1px solid #E1E1E1;
|
||||
box-sizing: border-box;
|
||||
}
|
||||
.sn-component .panel .footer .left {
|
||||
.sn-component .panel .footer .left, .sn-component .panel .panel-footer .left {
|
||||
text-align: right;
|
||||
display: block;
|
||||
}
|
||||
.sn-component .panel .footer .right {
|
||||
.sn-component .panel .footer .right, .sn-component .panel .panel-footer .right {
|
||||
text-align: right;
|
||||
display: block;
|
||||
}
|
||||
@@ -44,75 +48,88 @@
|
||||
padding: 1.6rem 2rem;
|
||||
padding-bottom: 0;
|
||||
flex-grow: 1;
|
||||
overflow: scroll;
|
||||
}
|
||||
.sn-component .panel .content p {
|
||||
color: #454545;
|
||||
line-height: 1.3;
|
||||
}
|
||||
.sn-component .panel .content .label, .sn-component .panel .content .panel-section .subtitle {
|
||||
.sn-component .panel .content .label, .sn-component .panel .content .panel-section .subtitle, .sn-component .panel-section .panel .content .subtitle {
|
||||
font-weight: bold;
|
||||
}
|
||||
.sn-component .panel .content .panel-section {
|
||||
.sn-component .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;
|
||||
flex-direction: column;
|
||||
}
|
||||
.sn-component .panel .content .panel-section .panel-row.centered {
|
||||
justify-content: center;
|
||||
.sn-component .panel-section.no-bottom-pad {
|
||||
padding-bottom: 0;
|
||||
}
|
||||
.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 {
|
||||
.sn-component .panel-section.hero {
|
||||
text-align: center;
|
||||
}
|
||||
.sn-component .panel .content .panel-section p:last-child {
|
||||
.sn-component .panel-section p:last-child {
|
||||
margin-bottom: 0;
|
||||
}
|
||||
.sn-component .panel .content .panel-section:not(:last-child) {
|
||||
.sn-component .panel-section:not(:last-child) {
|
||||
margin-bottom: 1.5rem;
|
||||
border-bottom: 1px solid #DDDDDD;
|
||||
}
|
||||
.sn-component .panel .content .panel-section:last-child {
|
||||
.sn-component .panel-section:not(:last-child).no-border {
|
||||
border-bottom: none;
|
||||
}
|
||||
.sn-component .panel-section:last-child {
|
||||
margin-bottom: 0.5rem;
|
||||
}
|
||||
.sn-component .panel .content .panel-section .outer-title {
|
||||
.sn-component .panel-section .outer-title {
|
||||
border-bottom: 1px solid #DDDDDD;
|
||||
padding-bottom: 0.9rem;
|
||||
margin-top: 2.1rem;
|
||||
margin-bottom: 15px;
|
||||
}
|
||||
.sn-component .panel .content .panel-section .subtitle {
|
||||
.sn-component .panel-section .subtitle {
|
||||
margin-top: -0.5rem;
|
||||
}
|
||||
.sn-component .panel .content .panel-section .subtitle.subtle {
|
||||
.sn-component .panel-section .subtitle.subtle {
|
||||
font-weight: normal;
|
||||
opacity: 0.6;
|
||||
}
|
||||
.sn-component .panel .content .panel-form {
|
||||
.sn-component .panel-row {
|
||||
display: flex;
|
||||
justify-content: space-between;
|
||||
align-items: center;
|
||||
padding-top: 0.4rem;
|
||||
}
|
||||
.sn-component .panel-row.centered {
|
||||
justify-content: center;
|
||||
}
|
||||
.sn-component .panel-row .panel-column {
|
||||
width: 100%;
|
||||
}
|
||||
.sn-component .panel .content .panel-form.half {
|
||||
.sn-component .panel-row.default-padding, .sn-component .panel-row:not(:last-child) {
|
||||
padding-bottom: 0.4rem;
|
||||
}
|
||||
.sn-component .panel-row.default-padding.condensed, .sn-component .panel-row:not(:last-child).condensed {
|
||||
padding-top: 0.2rem;
|
||||
padding-bottom: 0.2rem;
|
||||
}
|
||||
.sn-component .panel-row p {
|
||||
margin: 0;
|
||||
padding: 0;
|
||||
}
|
||||
.sn-component .panel-form {
|
||||
width: 100%;
|
||||
}
|
||||
.sn-component .panel-form.half {
|
||||
width: 50%;
|
||||
}
|
||||
.sn-component .panel .content .panel-form .form-submit {
|
||||
.sn-component .panel-form .form-submit {
|
||||
margin-top: 0.15rem;
|
||||
}
|
||||
.sn-component .right-aligned {
|
||||
justify-content: flex-end;
|
||||
text-align: right;
|
||||
}
|
||||
.sn-component .menu-panel {
|
||||
box-shadow: 0px 4px 4px #C8C8C8;
|
||||
border-radius: 0.6rem;
|
||||
@@ -156,14 +173,14 @@
|
||||
.sn-component .menu-panel .row .column .left {
|
||||
display: flex;
|
||||
}
|
||||
.sn-component .menu-panel .row .button .label, .sn-component .menu-panel .row .box .label, .sn-component .menu-panel .row .circle .label, .sn-component .menu-panel .row .button .panel .content .panel-section .subtitle, .sn-component .panel .content .panel-section .menu-panel .row .button .subtitle, .sn-component .menu-panel .row .box .panel .content .panel-section .subtitle, .sn-component .panel .content .panel-section .menu-panel .row .box .subtitle, .sn-component .menu-panel .row .circle .panel .content .panel-section .subtitle, .sn-component .panel .content .panel-section .menu-panel .row .circle .subtitle {
|
||||
.sn-component .menu-panel .row .button .label, .sn-component .menu-panel .row .box .label, .sn-component .menu-panel .row .circle .label, .sn-component .menu-panel .row .button .panel-section .subtitle, .sn-component .panel-section .menu-panel .row .button .subtitle, .sn-component .menu-panel .row .box .panel-section .subtitle, .sn-component .panel-section .menu-panel .row .box .subtitle, .sn-component .menu-panel .row .circle .panel-section .subtitle, .sn-component .panel-section .menu-panel .row .circle .subtitle {
|
||||
font-size: 0.8rem;
|
||||
font-weight: normal;
|
||||
}
|
||||
.sn-component .menu-panel .row:hover {
|
||||
background-color: #efefef;
|
||||
}
|
||||
.sn-component .menu-panel .row .label, .sn-component .menu-panel .row .panel .content .panel-section .subtitle, .sn-component .panel .content .panel-section .menu-panel .row .subtitle {
|
||||
.sn-component .menu-panel .row .label, .sn-component .menu-panel .row .panel-section .subtitle, .sn-component .panel-section .menu-panel .row .subtitle {
|
||||
font-size: 1rem;
|
||||
font-weight: bold;
|
||||
}
|
||||
@@ -270,6 +287,9 @@
|
||||
.sn-component .horizontal-group > *:not(:first-child), .sn-component .input-group > *:not(:first-child) {
|
||||
margin-left: 0.9rem;
|
||||
}
|
||||
.sn-component .border-bottom {
|
||||
border-bottom: 1px solid #DDDDDD;
|
||||
}
|
||||
.sn-component .checkbox-group {
|
||||
padding-top: 0.5rem;
|
||||
padding-bottom: 0.3rem;
|
||||
@@ -322,7 +342,7 @@
|
||||
text-align: center;
|
||||
border: 1px solid;
|
||||
}
|
||||
.sn-component .button .label, .sn-component .box .label, .sn-component .circle .label, .sn-component .button .panel .content .panel-section .subtitle, .sn-component .panel .content .panel-section .button .subtitle, .sn-component .box .panel .content .panel-section .subtitle, .sn-component .panel .content .panel-section .box .subtitle, .sn-component .circle .panel .content .panel-section .subtitle, .sn-component .panel .content .panel-section .circle .subtitle {
|
||||
.sn-component .button .label, .sn-component .box .label, .sn-component .circle .label, .sn-component .button .panel-section .subtitle, .sn-component .panel-section .button .subtitle, .sn-component .box .panel-section .subtitle, .sn-component .panel-section .box .subtitle, .sn-component .circle .panel-section .subtitle, .sn-component .panel-section .circle .subtitle {
|
||||
font-weight: bold;
|
||||
display: block;
|
||||
text-align: center;
|
||||
@@ -602,10 +622,10 @@
|
||||
.sn-component .app-bar .item.no-pointer {
|
||||
cursor: default;
|
||||
}
|
||||
.sn-component .app-bar .item:hover > .label:not(.subtle), .sn-component .app-bar .panel .content .panel-section .item:hover > .subtitle:not(.subtle), .sn-component .panel .content .panel-section .app-bar .item:hover > .subtitle:not(.subtle), .sn-component .app-bar .item:hover > .sublabel:not(.subtle), .sn-component .app-bar .item:hover > .column > .label:not(.subtle), .sn-component .app-bar .panel .content .panel-section .item:hover > .column > .subtitle:not(.subtle), .sn-component .panel .content .panel-section .app-bar .item:hover > .column > .subtitle:not(.subtle), .sn-component .app-bar .item:hover > .column > .sublabel:not(.subtle) {
|
||||
.sn-component .app-bar .item:hover > .label:not(.subtle), .sn-component .app-bar .panel-section .item:hover > .subtitle:not(.subtle), .sn-component .panel-section .app-bar .item:hover > .subtitle:not(.subtle), .sn-component .app-bar .item:hover > .sublabel:not(.subtle), .sn-component .app-bar .item:hover > .column > .label:not(.subtle), .sn-component .app-bar .panel-section .item:hover > .column > .subtitle:not(.subtle), .sn-component .panel-section .app-bar .item:hover > .column > .subtitle:not(.subtle), .sn-component .app-bar .item:hover > .column > .sublabel:not(.subtle) {
|
||||
color: #086DD6;
|
||||
}
|
||||
.sn-component .app-bar .item > .label, .sn-component .app-bar .panel .content .panel-section .item > .subtitle, .sn-component .panel .content .panel-section .app-bar .item > .subtitle, .sn-component .app-bar .item > .column > .label, .sn-component .app-bar .panel .content .panel-section .item > .column > .subtitle, .sn-component .panel .content .panel-section .app-bar .item > .column > .subtitle {
|
||||
.sn-component .app-bar .item > .label, .sn-component .app-bar .panel-section .item > .subtitle, .sn-component .panel-section .app-bar .item > .subtitle, .sn-component .app-bar .item > .column > .label, .sn-component .app-bar .panel-section .item > .column > .subtitle, .sn-component .panel-section .app-bar .item > .column > .subtitle {
|
||||
font-weight: bold;
|
||||
font-size: 0.9rem;
|
||||
white-space: nowrap;
|
||||
|
||||
Reference in New Issue
Block a user