This commit is contained in:
Mo Bitar
2017-12-23 11:25:08 -06:00
parent 2bc52578e0
commit 0c31668625
14 changed files with 186 additions and 32 deletions

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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