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