Wip
This commit is contained in:
@@ -38,6 +38,8 @@ angular.module('app.frontend')
|
||||
|
||||
var initialLoad = true;
|
||||
|
||||
this.componentManager = componentManager;
|
||||
|
||||
componentManager.registerHandler({identifier: "tags", areas: ["tags-list"], activationHandler: function(component){
|
||||
this.component = component;
|
||||
|
||||
|
||||
@@ -21,11 +21,14 @@ class Component extends Item {
|
||||
this.url = content.url;
|
||||
this.name = content.name;
|
||||
|
||||
this.package_info = content.package_info;
|
||||
|
||||
// the location in the view this component is located in. Valid values are currently tags-list, note-tags, and editor-stack`
|
||||
this.area = content.area;
|
||||
|
||||
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 || {};
|
||||
@@ -42,8 +45,10 @@ class Component extends Item {
|
||||
url: this.url,
|
||||
name: this.name,
|
||||
area: this.area,
|
||||
package_info: this.package_info,
|
||||
permissions: this.permissions,
|
||||
active: this.active,
|
||||
local: this.local,
|
||||
componentData: this.componentData,
|
||||
disassociatedItemIds: this.disassociatedItemIds,
|
||||
associatedItemIds: this.associatedItemIds,
|
||||
|
||||
@@ -8,12 +8,14 @@ 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
|
||||
};
|
||||
|
||||
_.merge(params, super.structureParams());
|
||||
|
||||
@@ -3,12 +3,13 @@ let ClientDataDomain = "org.standardnotes.sn.components";
|
||||
|
||||
class ComponentManager {
|
||||
|
||||
constructor($rootScope, modelManager, syncManager, themeManager, $timeout, $compile) {
|
||||
constructor($rootScope, modelManager, syncManager, desktopManager, themeManager, $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 = [];
|
||||
this.contextStreamObservers = [];
|
||||
@@ -42,6 +43,10 @@ class ComponentManager {
|
||||
}
|
||||
|
||||
var syncedComponents = allItems.filter(function(item){return item.content_type === "SN|Component" });
|
||||
|
||||
// Ensure any component in our data is installed by the system
|
||||
this.desktopManager.syncComponentsInstallation(syncedComponents);
|
||||
|
||||
for(var component of syncedComponents) {
|
||||
var activeComponent = _.find(this.activeComponents, {uuid: component.uuid});
|
||||
if(component.active && !component.deleted && !activeComponent) {
|
||||
@@ -191,19 +196,20 @@ class ComponentManager {
|
||||
|
||||
/**
|
||||
Possible Messages:
|
||||
set-size
|
||||
stream-items
|
||||
stream-context-item
|
||||
save-items
|
||||
select-item
|
||||
associate-item
|
||||
deassociate-item
|
||||
clear-selection
|
||||
create-item
|
||||
delete-items
|
||||
set-component-data
|
||||
save-context-client-data
|
||||
get-context-client-data
|
||||
set-size
|
||||
stream-items
|
||||
stream-context-item
|
||||
save-items
|
||||
select-item
|
||||
associate-item
|
||||
deassociate-item
|
||||
clear-selection
|
||||
create-item
|
||||
delete-items
|
||||
set-component-data
|
||||
save-context-client-data
|
||||
get-context-client-data
|
||||
install-local-component
|
||||
*/
|
||||
|
||||
if(message.action === "stream-items") {
|
||||
@@ -274,6 +280,17 @@ class ComponentManager {
|
||||
});
|
||||
}
|
||||
|
||||
else if(message.action === "install-local-component") {
|
||||
console.log("Received install-local-component event");
|
||||
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);
|
||||
this.syncManager.sync();
|
||||
})
|
||||
}
|
||||
|
||||
for(let handler of this.handlers) {
|
||||
if(handler.areas.includes(component.area)) {
|
||||
this.timeout(function(){
|
||||
@@ -585,6 +602,14 @@ class ComponentManager {
|
||||
component.ignoreEvents = !on;
|
||||
}
|
||||
|
||||
urlForComponent(component) {
|
||||
if(isDesktopApplication() && component.local && component.url.startsWith("sn://")) {
|
||||
return component.url.replace("sn://", this.desktopManager.getApplicationDataPath() + "/");
|
||||
} else {
|
||||
return component.url;
|
||||
}
|
||||
}
|
||||
|
||||
iframeForComponent(component) {
|
||||
for(var frame of document.getElementsByTagName("iframe")) {
|
||||
var componentId = frame.dataset.componentId;
|
||||
|
||||
@@ -8,6 +8,8 @@ class DesktopManager {
|
||||
this.authManager = authManager;
|
||||
this.$rootScope = $rootScope;
|
||||
|
||||
this.isDesktop = isDesktopApplication();
|
||||
|
||||
$rootScope.$on("initial-data-loaded", () => {
|
||||
this.dataLoaded = true;
|
||||
if(this.dataLoadHandler) {
|
||||
@@ -22,6 +24,47 @@ class DesktopManager {
|
||||
})
|
||||
}
|
||||
|
||||
/* Can handle components and themes */
|
||||
installOfflineComponentFromData(componentData, callback) {
|
||||
this.componentInstallationHandler(componentData, (installedComponent) => {
|
||||
componentData.content.url = installedComponent.content.url;
|
||||
componentData.content.local = true;
|
||||
callback(componentData);
|
||||
});
|
||||
}
|
||||
|
||||
getApplicationDataPath() {
|
||||
console.assert(this.applicationDataPath, "applicationDataPath is null");
|
||||
return this.applicationDataPath;
|
||||
}
|
||||
|
||||
/* Sending a component in its raw state is really slow for the desktop app */
|
||||
convertComponentForTransmission(component) {
|
||||
return new ItemParams(component).paramsForExportFile();
|
||||
}
|
||||
|
||||
// All `components` should be installed
|
||||
syncComponentsInstallation(components) {
|
||||
if(!this.isDesktop) return;
|
||||
var data = components.map((component) => {
|
||||
return this.convertComponentForTransmission(component);
|
||||
})
|
||||
this.installationSyncHandler(data);
|
||||
}
|
||||
|
||||
/* Used to resolve "sn://" */
|
||||
desktop_setApplicationDataPath(path) {
|
||||
this.applicationDataPath = path;
|
||||
}
|
||||
|
||||
desktop_setComponentInstallationSyncHandler(handler) {
|
||||
this.installationSyncHandler = handler;
|
||||
}
|
||||
|
||||
desktop_setOfflineComponentInstallationHandler(handler) {
|
||||
this.componentInstallationHandler = handler;
|
||||
}
|
||||
|
||||
desktop_setInitialDataLoadHandler(handler) {
|
||||
this.dataLoadHandler = handler;
|
||||
if(this.dataLoaded) {
|
||||
|
||||
@@ -16,10 +16,16 @@ class EditorMenu {
|
||||
|
||||
$scope.editors = componentManager.componentsForArea("editor-editor");
|
||||
|
||||
$scope.isDesktop = isDesktopApplication();
|
||||
|
||||
$scope.selectEditor = function($event, editor) {
|
||||
if(editor) {
|
||||
editor.conflict_of = null; // clear conflict if applicable
|
||||
}
|
||||
if(editor.local && !isDesktopApplication()) {
|
||||
alert("This editor is installed ")
|
||||
return;
|
||||
}
|
||||
$scope.callback()(editor);
|
||||
}
|
||||
|
||||
|
||||
@@ -7,10 +7,9 @@ class RoomBar {
|
||||
};
|
||||
}
|
||||
|
||||
controller($rootScope, $scope, extensionManager, syncManager, modelManager, componentManager, $timeout) {
|
||||
controller($rootScope, $scope, desktopManager, syncManager, modelManager, componentManager, $timeout) {
|
||||
'ngInject';
|
||||
|
||||
$scope.extensionManager = extensionManager;
|
||||
$scope.componentManager = componentManager;
|
||||
|
||||
$rootScope.$on("initial-data-loaded", () => {
|
||||
@@ -20,8 +19,48 @@ class RoomBar {
|
||||
})
|
||||
});
|
||||
|
||||
componentManager.registerHandler({identifier: "roomBar", areas: ["rooms"], activationHandler: function(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));
|
||||
}
|
||||
}.bind(this), actionHandler: function(component, action, data){
|
||||
if(action === "set-size") {
|
||||
console.log("Set size event", data);
|
||||
var setSize = function(element, size) {
|
||||
var widthString = typeof size.width === 'string' ? size.width : `${data.width}px`;
|
||||
var heightString = typeof size.height === 'string' ? size.height : `${data.height}px`;
|
||||
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 {
|
||||
var container = document.getElementById("room-" + component.uuid);
|
||||
setSize(container, data);
|
||||
}
|
||||
}
|
||||
}.bind(this)});
|
||||
|
||||
$scope.selectRoom = function(room) {
|
||||
|
||||
room.show = !room.show;
|
||||
if(room.show) {
|
||||
this.componentManager.activateComponent(room);
|
||||
} else {
|
||||
this.componentManager.deactivateComponent(room);
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
@@ -90,9 +90,32 @@ h2 {
|
||||
padding-left: 10px;
|
||||
padding-right: 10px;
|
||||
margin-left: 5px;
|
||||
position: relative;
|
||||
|
||||
.room-item {
|
||||
display: inline-block;
|
||||
position: relative;
|
||||
|
||||
.room-container {
|
||||
max-height: 85vh;
|
||||
position: absolute;
|
||||
right: 0px;
|
||||
bottom: 20px;
|
||||
min-width: 300px;
|
||||
z-index: 1000;
|
||||
margin-top: 15px;
|
||||
|
||||
box-shadow: 0px 0px 15px rgba(black, 0.2);
|
||||
border: none;
|
||||
cursor: default;
|
||||
overflow: auto;
|
||||
background-color: white;
|
||||
}
|
||||
|
||||
.room-iframe {
|
||||
width: 100%;
|
||||
height: 100%;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -112,7 +112,6 @@ ul.section-menu-bar {
|
||||
cursor: pointer;
|
||||
}
|
||||
|
||||
|
||||
.shortcut {
|
||||
float: right;
|
||||
font-size: 12px;
|
||||
@@ -122,6 +121,12 @@ ul.section-menu-bar {
|
||||
padding-right: 10px;
|
||||
}
|
||||
}
|
||||
|
||||
.sublabel {
|
||||
font-size: 12px;
|
||||
font-weight: normal;
|
||||
margin-top: 5px;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
|
||||
@@ -101,14 +101,14 @@ button:focus {outline:0;}
|
||||
}
|
||||
|
||||
.panel {
|
||||
position: absolute;
|
||||
right: 0px;
|
||||
min-width: 300px;
|
||||
z-index: 1000;
|
||||
margin-top: 10px;
|
||||
box-shadow: 0px 0px 15px rgba(0, 0, 0, 0.2);
|
||||
border: none;
|
||||
background-color: white;
|
||||
position: absolute;
|
||||
right: 0px;
|
||||
min-width: 300px;
|
||||
z-index: 1000;
|
||||
margin-top: 10px;
|
||||
box-shadow: 0px 0px 15px rgba(0, 0, 0, 0.2);
|
||||
border: none;
|
||||
background-color: white;
|
||||
}
|
||||
|
||||
.panel-right {
|
||||
|
||||
@@ -9,10 +9,12 @@
|
||||
%div{"ng-if" => "editors.length > 0"}
|
||||
.header
|
||||
.title External Editors
|
||||
.subtitle Can access your current note decrypted.
|
||||
%ul
|
||||
%li.menu-item{"ng-repeat" => "editor in editors", "ng-click" => "selectEditor($event, editor)"}
|
||||
%strong.red.medium{"ng-if" => "editor.conflict_of"} Conflicted copy
|
||||
%label.menu-item-title
|
||||
%span.inline.tinted.mr-10{"ng-if" => "selectedEditor === editor"} ✓
|
||||
{{editor.name}}
|
||||
.sublabel{"ng-if" => "editor.local"}
|
||||
Locally Installed
|
||||
.sublabel.faded{"ng-if" => "editor.local && !isDesktop"} Unavailable in Web Browser
|
||||
|
||||
@@ -1,2 +1,4 @@
|
||||
.room-item{"ng-repeat" => "room in rooms", "ng-click" => "selectRoom(room)"}
|
||||
{{room.name}}
|
||||
%span {{room.name}}
|
||||
.room-container.panel-right{"ng-if" => "room.show && room.active", "ng-attr-id" => "room-{{room.uuid}}"}
|
||||
%iframe.room-iframe{"ng-src" => "{{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}}"}
|
||||
|
||||
@@ -9,7 +9,7 @@
|
||||
|
||||
.editor-tags
|
||||
#note-tags-component-container{"ng-if" => "ctrl.tagsComponent && ctrl.tagsComponent.active"}
|
||||
%iframe#note-tags-iframe{"ng-src" => "{{ctrl.tagsComponent.url | trusted}}", "frameBorder" => "0", "sandbox" => "allow-scripts", "data-component-id" => "{{ctrl.tagsComponent.uuid}}"}
|
||||
%iframe#note-tags-iframe{"ng-src" => "{{ctrl.componentManager.urlForComponent(ctrl.tagsComponent) | trusted}}", "frameBorder" => "0", "sandbox" => "allow-scripts", "data-component-id" => "{{ctrl.tagsComponent.uuid}}"}
|
||||
%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)"}
|
||||
%ul.section-menu-bar{"ng-if" => "ctrl.note"}
|
||||
@@ -46,7 +46,7 @@
|
||||
%contextual-extensions-menu{"ng-if" => "ctrl.showExtensions", "item" => "ctrl.note"}
|
||||
|
||||
.editor-content{"ng-if" => "ctrl.noteReady && !ctrl.note.errorDecrypting", "ng-class" => "{'fullscreen' : ctrl.fullscreen }"}
|
||||
%iframe#editor-iframe{"ng-if" => "ctrl.editorComponent && ctrl.editorComponent.active", "ng-src" => "{{ctrl.editorComponent.url | trusted}}", "data-component-id" => "{{ctrl.editorComponent.uuid}}", "frameBorder" => "0", "style" => "width: 100%;"}
|
||||
%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-class" => "{'fullscreen' : ctrl.fullscreen }", "ng-model" => "ctrl.note.text",
|
||||
"ng-change" => "ctrl.contentChanged()", "ng-click" => "ctrl.clickedTextArea()", "ng-focus" => "ctrl.onContentFocus()", "dir" => "auto"}
|
||||
@@ -59,4 +59,4 @@
|
||||
#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#note-tags-iframe{"ng-src" => "{{component.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}}"}
|
||||
%iframe#note-tags-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}}"}
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
.section.tags#tags-column
|
||||
%iframe#tags-list-iframe{"ng-if" => "ctrl.component && ctrl.component.active", "ng-src" => "{{ctrl.component.url | trusted}}", "frameBorder" => "0", "style" => "width: 100%; height: 100%;", "sandbox" => "allow-scripts"}
|
||||
%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"}
|
||||
#tags-content.content{"ng-if" => "!(ctrl.component && ctrl.component.active)"}
|
||||
#tags-title-bar.section-title-bar
|
||||
.title Tags
|
||||
|
||||
Reference in New Issue
Block a user