Editor updates

This commit is contained in:
Mo Bitar
2018-01-12 14:36:17 -06:00
parent 5db97b0a4c
commit c7ce308a19
22 changed files with 6662 additions and 794 deletions

View File

@@ -115,19 +115,21 @@ angular.module('app.frontend')
// if plain editor or other editor
this.showEditorMenu = false;
var editor = component;
if(this.selectedEditor && editor !== this.selectedEditor) {
this.disassociateComponentWithCurrentNote(this.selectedEditor);
}
if(editor) {
this.note.setAppDataItem("prefersPlainEditor", false);
this.note.setDirty(true);
componentManager.associateComponentWithItem(editor, this.note);
if(this.note.getAppDataItem("prefersPlainEditor") == true) {
this.note.setAppDataItem("prefersPlainEditor", false);
this.note.setDirty(true);
}
this.associateComponentWithCurrentNote(editor);
} else {
// Note prefers plain editor
if(this.selectedEditor) {
this.disableComponentForCurrentItem(this.selectedEditor);
if(!this.note.getAppDataItem("prefersPlainEditor")) {
this.note.setAppDataItem("prefersPlainEditor", true);
this.note.setDirty(true);
}
this.note.setAppDataItem("prefersPlainEditor", true);
this.note.setDirty(true);
syncManager.sync();
$timeout(() => {
this.reloadFont();
})
@@ -139,6 +141,8 @@ angular.module('app.frontend')
this.toggleStackComponentForCurrentItem(component);
}
// Lots of dirtying can happen above, so we'll sync
syncManager.sync();
}.bind(this)
this.hasAvailableExtensions = function() {
@@ -502,31 +506,34 @@ angular.module('app.frontend')
this.toggleStackComponentForCurrentItem = function(component) {
if(component.isActiveForItem(this.note)) {
this.disableComponentForCurrentItem(component);
componentManager.deactivateComponent(component);
this.disassociateComponentWithCurrentNote(component);
} else {
this.enableComponentForCurrentItem(component);
componentManager.activateComponent(component);
componentManager.contextItemDidChangeInArea("editor-stack");
this.associateComponentWithCurrentNote(component);
}
}
this.disableComponentForCurrentItem = function(component) {
componentManager.deactivateComponent(component);
_.pull(component.associatedItemIds, this.note.uuid);
if(component.disassociatedItemIds.indexOf(this.note.uuid) !== -1) {
return;
this.disassociateComponentWithCurrentNote = function(component) {
component.associatedItemIds = component.associatedItemIds.filter((id) => {return id !== this.note.uuid});
// Only disassociative components should modify the disassociatedItemIds
if(!component.isAssociative() && !component.disassociatedItemIds.includes(this.note.uuid)) {
component.disassociatedItemIds.push(this.note.uuid);
}
component.disassociatedItemIds.push(this.note.uuid);
component.setDirty(true);
syncManager.sync();
}
this.enableComponentForCurrentItem = function(component) {
componentManager.activateComponent(component);
componentManager.contextItemDidChangeInArea("editor-stack");
this.associateComponentWithCurrentNote = function(component) {
component.disassociatedItemIds = component.disassociatedItemIds.filter((id) => {return id !== this.note.uuid});
if(component.isAssociative() && !component.associatedItemIds.includes(this.note.uuid)) {
component.associatedItemIds.push(this.note.uuid);
}
_.pull(component.disassociatedItemIds, this.note.uuid);
component.setDirty(true);
syncManager.sync();
}

View File

@@ -166,6 +166,11 @@ angular.module('app.frontend')
// Safe to create. Create and return object.
let url = window._prolink_package_url;
console.log("Installing ProLink from URL", url);
if(!url) {
console.error("window._prolink_package_url must be set.");
return;
}
packageManager.installPackage(url, (component) => {
valueCallback(component);
})

View File

@@ -23,9 +23,10 @@ class Component extends Item {
/* New */
this.local_url = content.local_url;
this.hosted_url = content.hosted_url;
this.offlineOnly = content.offlineOnly;
this.name = content.name;
this.autoupdate = content.autoupdate;
this.autoupdateDisabled = content.autoupdateDisabled;
this.package_info = content.package_info;
@@ -50,12 +51,13 @@ class Component extends Item {
url: this.url,
hosted_url: this.hosted_url,
local_url: this.local_url,
offlineOnly: this.offlineOnly,
name: this.name,
area: this.area,
package_info: this.package_info,
permissions: this.permissions,
active: this.active,
autoupdate: this.autoupdate,
autoupdateDisabled: this.autoupdateDisabled,
componentData: this.componentData,
disassociatedItemIds: this.disassociatedItemIds,
associatedItemIds: this.associatedItemIds,
@@ -73,14 +75,6 @@ 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";
}

View File

@@ -6,10 +6,14 @@ class ItemParams {
this.version = version || "002";
}
paramsForExportFile() {
paramsForExportFile(includeDeleted) {
this.additionalFields = ["updated_at"];
this.forExportFile = true;
return _.omit(this.__params(), ["deleted"]);
if(includeDeleted) {
return this.__params();
} else {
return _.omit(this.__params(), ["deleted"]);
}
}
paramsForExtension() {

View File

@@ -127,7 +127,7 @@ class ComponentManager {
postThemeToComponent(component) {
var activeTheme = this.getActiveTheme();
var data = {
themes: [activeTheme ? activeTheme.computedUrl() : null]
themes: [activeTheme ? this.urlForComponent(activeTheme) : null]
}
this.sendMessageToComponent(component, {action: "themes", data: data})
@@ -196,6 +196,14 @@ class ComponentManager {
})
}
urlForComponent(component) {
if(component.offlineOnly || (isDesktopApplication() && component.local_url)) {
return component.local_url.replace("sn://", this.desktopManager.getApplicationDataPath() + "/");
} else {
return component.url || component.hosted_url;
}
}
componentForUrl(url) {
return this.components.filter(function(component){
return component.url === url || component.hosted_url === url;
@@ -246,8 +254,6 @@ class ComponentManager {
this.handleCreateItemMessage(component, message);
} else if(message.action === "save-items") {
this.handleSaveItemsMessage(component, message);
} else if(message.action === "install-local-component") {
this.handleInstallLocalComponentMessage(component, message);
} else if(message.action === "toggle-activate-component") {
let componentToToggle = this.modelManager.findItem(message.data.uuid);
this.handleToggleComponentMessage(component, componentToToggle, message);
@@ -265,7 +271,7 @@ class ComponentManager {
removePrivatePropertiesFromResponseItems(responseItems, includeUrls) {
// Don't allow component to overwrite these properties.
var privateProperties = ["appData", "autoupdate", "permissions", "active", "encrypted"];
var privateProperties = ["appData", "autoupdateDisabled", "permissions", "active", "encrypted"];
if(includeUrls) {
privateProperties = privateProperties.concat(["url", "hosted_url", "local_url"]);
}
@@ -329,17 +335,21 @@ class ComponentManager {
// push immediately now
for(let handler of this.handlersForArea(component.area)) {
var itemInContext = handler.contextRequestHandler(component);
this.sendContextItemInReply(component, itemInContext, message);
if(handler.contextRequestHandler) {
var itemInContext = handler.contextRequestHandler(component);
this.sendContextItemInReply(component, itemInContext, message);
}
}
}.bind(this))
}
isItemWithinComponentContextJurisdiction(item, component) {
for(let handler of this.handlersForArea(component.area)) {
var itemInContext = handler.contextRequestHandler(component);
if(itemInContext.uuid == item.uuid) {
return true;
if(handler.contextRequestHandler) {
var itemInContext = handler.contextRequestHandler(component);
if(itemInContext.uuid == item.uuid) {
return true;
}
}
}
return false;
@@ -388,6 +398,7 @@ class ComponentManager {
}
item.setDirty(true);
}
this.syncManager.sync((response) => {
// Allow handlers to be notified when a save begins and ends, to update the UI
var saveMessage = Object.assign({}, message);
@@ -443,24 +454,6 @@ class ComponentManager {
});
}
handleInstallLocalComponentMessage(component, message) {
var requiredPermissions = [
{
name: "stream-items",
content_types: [message.data.content_type]
}
];
this.runWithPermissions(component, requiredPermissions, () => {
this.desktopManager.installOfflineComponentFromData(message.data, (response) => {
var component = this.modelManager.mapResponseItemsToLocalModels([response], ModelManager.MappingSourceComponentRetrieved)[0];
// Save updated URL
component.setDirty(true);
this.syncManager.sync();
})
});
}
handleSetComponentDataMessage(component, message) {
// A component setting its own data does not require special permissions
this.runWithPermissions(component, [], () => {
@@ -719,19 +712,6 @@ class ComponentManager {
return component.active;
}
associateComponentWithItem(component, item) {
_.pull(component.disassociatedItemIds, item.uuid);
if(component.associatedItemIds.includes(item.uuid)) {
return;
}
component.associatedItemIds.push(item.uuid);
component.setDirty(true);
this.syncManager.sync();
}
iframeForComponent(component) {
for(var frame of document.getElementsByTagName("iframe")) {
var componentId = frame.dataset.componentId;

View File

@@ -25,14 +25,6 @@ class DesktopManager {
})
}
/* Can handle components and themes */
installOfflineComponentFromData(componentData, callback) {
this.componentInstallationHandler(componentData, (installedComponent) => {
componentData.content.local_url = installedComponent.content.local_url;
callback(componentData);
});
}
getApplicationDataPath() {
console.assert(this.applicationDataPath, "applicationDataPath is null");
return this.applicationDataPath;
@@ -40,24 +32,31 @@ class DesktopManager {
/* Sending a component in its raw state is really slow for the desktop app */
convertComponentForTransmission(component) {
return new ItemParams(component).paramsForExportFile();
return new ItemParams(component).paramsForExportFile(true);
}
// All `components` should be installed
syncComponentsInstallation(components) {
// console.log("Web Syncing Components", components);
if(!this.isDesktop) return;
/* Allows us to look up component on desktop_updateComponentComplete */
this.syncingComponents = components;
var data = components.map((component) => {
console.log("Web Sycying Component", this.convertComponentForTransmission(component));
return this.convertComponentForTransmission(component);
})
this.installationSyncHandler(data);
}
desktop_onComponentInstallationComplete(componentData) {
console.log("Web|Component Installation Complete", componentData);
var component = this.modelManager.mapResponseItemsToLocalModels([componentData], ModelManager.MappingSourceDesktopInstalled)[0];
component.setDirty(true);
this.syncManager.sync();
}
desktop_updateComponentComplete(componentData) {
var component = this.syncingComponents.filter((c) => {return c.uuid == componentData.uuid})[0];
console.log("Web|Component Update Complete", componentData);
var component = this.modelManager.mapResponseItemsToLocalModels([componentData], ModelManager.MappingSourceDesktopInstalled)[0];
component.setDirty(true);
this.syncManager.sync();
}

View File

@@ -35,7 +35,6 @@ class ComponentView {
}.bind(this)});
$scope.$watch('component', function(component, prevComponent){
// console.log("Component View Setting Component", component);
ctrl.componentValueChanging(component, prevComponent);
});
}
@@ -43,22 +42,26 @@ 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
console.log("DEACTIVATING OLD COMPONENT", prevComponent);
componentManager.deactivateComponent(prevComponent);
}
if(component) {
componentManager.activateComponent(component);
component.runningLocally = $scope.getUrl
console.log("Loading", $scope.component.name, $scope.getUrl());
}
}
$scope.getUrl = function() {
var url = componentManager.urlForComponent($scope.component);
$scope.component.runningLocally = url !== ($scope.component.url || $scope.component.hosted_url);
return url;
}
$scope.$on("$destroy", function() {
console.log("DESTROY COMPONENT VIEW");
componentManager.deregisterHandler($scope.identifier);
if($scope.component) {
componentManager.deactivateComponent($scope.component);

View File

@@ -39,6 +39,10 @@ class EditorMenu {
}
}
$scope.offlineAvailableForComponent = function(component) {
return component.local_url && isDesktopApplication();
}
$scope.makeEditorDefault = function(component) {
var currentDefault = componentManager.componentsForArea("editor-editor").filter((e) => {return e.isDefaultEditor()})[0];
if(currentDefault) {

View File

@@ -6,6 +6,7 @@ class ModelManager {
ModelManager.MappingSourceLocalSaved = "MappingSourceLocalSaved";
ModelManager.MappingSourceLocalRetrieved = "MappingSourceLocalRetrieved";
ModelManager.MappingSourceComponentRetrieved = "MappingSourceComponentRetrieved";
ModelManager.MappingSourceDesktopInstalled = "MappingSourceDesktopInstalled"; // When a component is installed by the desktop and some of its values change
ModelManager.MappingSourceRemoteActionRetrieved = "MappingSourceRemoteActionRetrieved"; /* aciton-based Extensions like note history */
ModelManager.MappingSourceFileImport = "MappingSourceFileImport";
@@ -147,7 +148,7 @@ class ModelManager {
}
if(!item) {
item = this.createItem(json_obj);
item = this.createItem(json_obj, true);
}
this.addItem(item);
@@ -200,7 +201,7 @@ class ModelManager {
}
}
createItem(json_obj) {
createItem(json_obj, dontNotifyObservers) {
var item;
if(json_obj.content_type == "Note") {
item = new Note(json_obj);
@@ -224,6 +225,15 @@ class ModelManager {
item = new Item(json_obj);
}
// Some observers would be interested to know when an an item is locally created
// If we don't send this out, these observers would have to wait until MappingSourceRemoteSaved
// to hear about it, but sometimes, RemoveSaved is explicitly ignored by the observer to avoid
// recursive callbacks. See componentManager's syncObserver callback.
// dontNotifyObservers is currently only set true by modelManagers mapResponseItemsToLocalModels
if(!dontNotifyObservers) {
this.notifySyncObserversOfModels([item], ModelManager.MappingSourceLocalSaved);
}
item.addObserver(this, function(changedItem){
this.notifyItemChangeObserversOfModels([changedItem]);
}.bind(this));

View File

@@ -18,10 +18,11 @@ class PackageManager {
// Remove private properties
this.componentManager.removePrivatePropertiesFromResponseItems([aPackage]);
var assembled = this.modelManager.createItem(aPackage);
aPackage.package_info = Object.assign({}, aPackage);
assembled.package_info = aPackage;
var assembled = this.modelManager.createItem(aPackage);;
this.modelManager.addItem(assembled);
assembled.setDirty(true);
this.syncManager.sync();

View File

@@ -27,7 +27,6 @@ class SingletonManager {
setTimeout(function () {
var userPrefs = modelManager.itemsForContentType("SN|UserPreferences");
console.assert(userPrefs.length == 1);
console.log("All extant prefs", userPrefs);
}, 1000);
}

View File

@@ -5,6 +5,7 @@ class ThemeManager {
this.modelManager = modelManager;
this.$rootScope = $rootScope;
this.storageManager = storageManager;
this.componentManager = componentManager;
componentManager.registerHandler({identifier: "themeManager", areas: ["themes"], activationHandler: (component) => {
if(component.active) {
@@ -55,8 +56,7 @@ class ThemeManager {
this.deactivateTheme(this.activeTheme);
}
var url = theme.computedUrl();
var url = this.componentManager.urlForComponent(theme);
var link = document.createElement("link");
link.href = url;