Component management improvements, removal of dependence on noteReady flag
This commit is contained in:
@@ -1,5 +1,5 @@
|
|||||||
import { WebApplication } from '@/ui_models/application';
|
import { WebApplication } from '@/ui_models/application';
|
||||||
import { SNComponent } from 'snjs';
|
import { SNComponent, ComponentAction, LiveItem } from 'snjs';
|
||||||
import { WebDirective } from './../../types';
|
import { WebDirective } from './../../types';
|
||||||
import template from '%/directives/component-view.pug';
|
import template from '%/directives/component-view.pug';
|
||||||
import { isDesktopApplication } from '../../utils';
|
import { isDesktopApplication } from '../../utils';
|
||||||
@@ -7,38 +7,37 @@ import { isDesktopApplication } from '../../utils';
|
|||||||
* The maximum amount of time we'll wait for a component
|
* The maximum amount of time we'll wait for a component
|
||||||
* to load before displaying error
|
* to load before displaying error
|
||||||
*/
|
*/
|
||||||
const MAX_LOAD_THRESHOLD = 4000;
|
const MaxLoadThreshold = 4000;
|
||||||
|
const VisibilityChangeKey = 'visibilitychange';
|
||||||
const VISIBILITY_CHANGE_LISTENER_KEY = 'visibilitychange';
|
|
||||||
|
|
||||||
interface ComponentViewScope {
|
interface ComponentViewScope {
|
||||||
component: SNComponent
|
componentUuid: string
|
||||||
onLoad?: (component: SNComponent) => void
|
onLoad?: (component: SNComponent) => void
|
||||||
manualDealloc: boolean
|
|
||||||
application: WebApplication
|
application: WebApplication
|
||||||
}
|
}
|
||||||
|
|
||||||
class ComponentViewCtrl implements ComponentViewScope {
|
class ComponentViewCtrl implements ComponentViewScope {
|
||||||
|
|
||||||
$rootScope: ng.IRootScopeService
|
/** @scope */
|
||||||
$timeout: ng.ITimeoutService
|
|
||||||
componentValid = true
|
|
||||||
cleanUpOn: () => void
|
|
||||||
unregisterComponentHandler!: () => void
|
|
||||||
component!: SNComponent
|
|
||||||
onLoad?: (component: SNComponent) => void
|
onLoad?: (component: SNComponent) => void
|
||||||
manualDealloc = false
|
componentUuid!: string
|
||||||
application!: WebApplication
|
application!: WebApplication
|
||||||
unregisterDesktopObserver!: () => void
|
liveComponent!: LiveItem<SNComponent>
|
||||||
didRegisterObservers = false
|
|
||||||
lastComponentValue?: SNComponent
|
private $rootScope: ng.IRootScopeService
|
||||||
issueLoading = false
|
private $timeout: ng.ITimeoutService
|
||||||
reloading = false
|
private componentValid = true
|
||||||
expired = false
|
private cleanUpOn: () => void
|
||||||
loading = false
|
private unregisterComponentHandler!: () => void
|
||||||
didAttemptReload = false
|
private unregisterDesktopObserver!: () => void
|
||||||
error: 'offline-restricted' | 'url-missing' | undefined
|
private didRegisterObservers = false
|
||||||
loadTimeout: any
|
private issueLoading = false
|
||||||
|
public reloading = false
|
||||||
|
private expired = false
|
||||||
|
private loading = false
|
||||||
|
private didAttemptReload = false
|
||||||
|
public error: 'offline-restricted' | 'url-missing' | undefined
|
||||||
|
private loadTimeout: any
|
||||||
|
|
||||||
/* @ngInject */
|
/* @ngInject */
|
||||||
constructor(
|
constructor(
|
||||||
@@ -51,7 +50,6 @@ class ComponentViewCtrl implements ComponentViewScope {
|
|||||||
this.cleanUpOn = $scope.$on('ext-reload-complete', () => {
|
this.cleanUpOn = $scope.$on('ext-reload-complete', () => {
|
||||||
this.reloadStatus(false);
|
this.reloadStatus(false);
|
||||||
});
|
});
|
||||||
|
|
||||||
/** To allow for registering events */
|
/** To allow for registering events */
|
||||||
this.onVisibilityChange = this.onVisibilityChange.bind(this);
|
this.onVisibilityChange = this.onVisibilityChange.bind(this);
|
||||||
}
|
}
|
||||||
@@ -61,49 +59,56 @@ class ComponentViewCtrl implements ComponentViewScope {
|
|||||||
(this.cleanUpOn as any) = undefined;
|
(this.cleanUpOn as any) = undefined;
|
||||||
this.unregisterComponentHandler();
|
this.unregisterComponentHandler();
|
||||||
(this.unregisterComponentHandler as any) = undefined;
|
(this.unregisterComponentHandler as any) = undefined;
|
||||||
if (this.component && !this.manualDealloc) {
|
|
||||||
/* application and componentManager may be destroyed if this onDestroy is part of
|
|
||||||
the entire application being destroyed rather than part of just a single component
|
|
||||||
view being removed */
|
|
||||||
if (this.application && this.application.componentManager) {
|
|
||||||
this.application.componentManager.deregisterComponent(this.component);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
this.unregisterDesktopObserver();
|
this.unregisterDesktopObserver();
|
||||||
(this.unregisterDesktopObserver as any) = undefined;
|
(this.unregisterDesktopObserver as any) = undefined;
|
||||||
document.removeEventListener(
|
this.liveComponent.deinit();
|
||||||
VISIBILITY_CHANGE_LISTENER_KEY,
|
(this.liveComponent as any) = undefined;
|
||||||
this.onVisibilityChange
|
|
||||||
);
|
|
||||||
(this.component as any) = undefined;
|
|
||||||
this.onLoad = undefined;
|
|
||||||
(this.application as any) = undefined;
|
(this.application as any) = undefined;
|
||||||
(this.onVisibilityChange as any) = undefined;
|
(this.onVisibilityChange as any) = undefined;
|
||||||
|
this.onLoad = undefined;
|
||||||
|
document.removeEventListener(
|
||||||
|
VisibilityChangeKey,
|
||||||
|
this.onVisibilityChange
|
||||||
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
$onChanges() {
|
$onInit() {
|
||||||
if (!this.didRegisterObservers) {
|
this.liveComponent = new LiveItem(this.componentUuid, this.application);
|
||||||
this.didRegisterObservers = true;
|
this.loadComponent();
|
||||||
this.registerComponentHandlers();
|
this.registerComponentHandlers();
|
||||||
this.registerPackageUpdateObserver();
|
this.registerPackageUpdateObserver();
|
||||||
}
|
|
||||||
const newComponent = this.component;
|
|
||||||
const oldComponent = this.lastComponentValue;
|
|
||||||
this.lastComponentValue = newComponent;
|
|
||||||
if (oldComponent && oldComponent !== newComponent) {
|
|
||||||
this.application.componentManager!.deregisterComponent(
|
|
||||||
oldComponent
|
|
||||||
);
|
|
||||||
}
|
|
||||||
if (newComponent && newComponent !== oldComponent) {
|
|
||||||
this.application.componentManager!.registerComponent(
|
|
||||||
newComponent
|
|
||||||
)
|
|
||||||
this.reloadStatus();
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
registerPackageUpdateObserver() {
|
get component() {
|
||||||
|
return this.liveComponent?.item;
|
||||||
|
}
|
||||||
|
|
||||||
|
private loadComponent() {
|
||||||
|
if (!this.component) {
|
||||||
|
throw 'Component view is missing component';
|
||||||
|
}
|
||||||
|
if (!this.component.active) {
|
||||||
|
throw 'Component view component must be active';
|
||||||
|
}
|
||||||
|
const iframe = this.application.componentManager!.iframeForComponent(
|
||||||
|
this.component
|
||||||
|
);
|
||||||
|
if (!iframe) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
this.loading = true;
|
||||||
|
if (this.loadTimeout) {
|
||||||
|
this.$timeout.cancel(this.loadTimeout);
|
||||||
|
}
|
||||||
|
this.loadTimeout = this.$timeout(() => {
|
||||||
|
this.handleIframeLoadTimeout();
|
||||||
|
}, MaxLoadThreshold);
|
||||||
|
iframe.onload = (event) => {
|
||||||
|
this.handleIframeLoad(iframe);
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
private registerPackageUpdateObserver() {
|
||||||
this.unregisterDesktopObserver = this.application.getDesktopService()
|
this.unregisterDesktopObserver = this.application.getDesktopService()
|
||||||
.registerUpdateObserver((component: SNComponent) => {
|
.registerUpdateObserver((component: SNComponent) => {
|
||||||
if (component === this.component && component.active) {
|
if (component === this.component && component.active) {
|
||||||
@@ -112,27 +117,19 @@ class ComponentViewCtrl implements ComponentViewScope {
|
|||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
registerComponentHandlers() {
|
private registerComponentHandlers() {
|
||||||
this.unregisterComponentHandler = this.application.componentManager!.registerHandler({
|
this.unregisterComponentHandler = this.application.componentManager!.registerHandler({
|
||||||
identifier: 'component-view-' + Math.random(),
|
identifier: 'component-view-' + Math.random(),
|
||||||
areas: [this.component.area],
|
areas: [this.component.area],
|
||||||
activationHandler: (component) => {
|
|
||||||
if (component !== this.component) {
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
this.$timeout(() => {
|
|
||||||
this.handleActivation();
|
|
||||||
});
|
|
||||||
},
|
|
||||||
actionHandler: (component, action, data) => {
|
actionHandler: (component, action, data) => {
|
||||||
if (action === 'set-size') {
|
if (action === ComponentAction.SetSize) {
|
||||||
this.application.componentManager!.handleSetSizeEvent(component, data);
|
this.application.componentManager!.handleSetSizeEvent(component, data);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
onVisibilityChange() {
|
private onVisibilityChange() {
|
||||||
if (document.visibilityState === 'hidden') {
|
if (document.visibilityState === 'hidden') {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
@@ -141,13 +138,13 @@ class ComponentViewCtrl implements ComponentViewScope {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
async reloadComponent() {
|
public async reloadComponent() {
|
||||||
this.componentValid = false;
|
this.componentValid = false;
|
||||||
await this.application.componentManager!.reloadComponent(this.component);
|
await this.application.componentManager!.reloadComponent(this.component);
|
||||||
this.reloadStatus();
|
this.reloadStatus();
|
||||||
}
|
}
|
||||||
|
|
||||||
reloadStatus(doManualReload = true) {
|
public reloadStatus(doManualReload = true) {
|
||||||
this.reloading = true;
|
this.reloading = true;
|
||||||
const component = this.component;
|
const component = this.component;
|
||||||
const previouslyValid = this.componentValid;
|
const previouslyValid = this.componentValid;
|
||||||
@@ -183,36 +180,12 @@ class ComponentViewCtrl implements ComponentViewScope {
|
|||||||
if (this.expired && doManualReload) {
|
if (this.expired && doManualReload) {
|
||||||
this.$rootScope.$broadcast('reload-ext-dat');
|
this.$rootScope.$broadcast('reload-ext-dat');
|
||||||
}
|
}
|
||||||
|
|
||||||
this.$timeout(() => {
|
this.$timeout(() => {
|
||||||
this.reloading = false;
|
this.reloading = false;
|
||||||
}, 500);
|
}, 500);
|
||||||
}
|
}
|
||||||
|
|
||||||
handleActivation() {
|
private async handleIframeLoadTimeout() {
|
||||||
if (!this.component || !this.component.active) {
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
const iframe = this.application.componentManager!.iframeForComponent(
|
|
||||||
this.component
|
|
||||||
);
|
|
||||||
if (!iframe) {
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
this.loading = true;
|
|
||||||
if (this.loadTimeout) {
|
|
||||||
this.$timeout.cancel(this.loadTimeout);
|
|
||||||
}
|
|
||||||
this.loadTimeout = this.$timeout(() => {
|
|
||||||
this.handleIframeLoadTimeout();
|
|
||||||
}, MAX_LOAD_THRESHOLD);
|
|
||||||
|
|
||||||
iframe.onload = (event) => {
|
|
||||||
this.handleIframeLoad(iframe);
|
|
||||||
};
|
|
||||||
}
|
|
||||||
|
|
||||||
async handleIframeLoadTimeout() {
|
|
||||||
if (this.loading) {
|
if (this.loading) {
|
||||||
this.loading = false;
|
this.loading = false;
|
||||||
this.issueLoading = true;
|
this.issueLoading = true;
|
||||||
@@ -221,14 +194,14 @@ class ComponentViewCtrl implements ComponentViewScope {
|
|||||||
this.reloadComponent();
|
this.reloadComponent();
|
||||||
} else {
|
} else {
|
||||||
document.addEventListener(
|
document.addEventListener(
|
||||||
VISIBILITY_CHANGE_LISTENER_KEY,
|
VisibilityChangeKey,
|
||||||
this.onVisibilityChange
|
this.onVisibilityChange
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
async handleIframeLoad(iframe: HTMLIFrameElement) {
|
private async handleIframeLoad(iframe: HTMLIFrameElement) {
|
||||||
let desktopError = false;
|
let desktopError = false;
|
||||||
if (isDesktopApplication()) {
|
if (isDesktopApplication()) {
|
||||||
try {
|
try {
|
||||||
@@ -252,11 +225,7 @@ class ComponentViewCtrl implements ComponentViewScope {
|
|||||||
}, avoidFlickerTimeout);
|
}, avoidFlickerTimeout);
|
||||||
}
|
}
|
||||||
|
|
||||||
disableActiveTheme() {
|
public getUrl() {
|
||||||
this.application.getThemeService().deactivateAllThemes();
|
|
||||||
}
|
|
||||||
|
|
||||||
getUrl() {
|
|
||||||
const url = this.application.componentManager!.urlForComponent(this.component);
|
const url = this.application.componentManager!.urlForComponent(this.component);
|
||||||
return url;
|
return url;
|
||||||
}
|
}
|
||||||
@@ -268,9 +237,8 @@ export class ComponentView extends WebDirective {
|
|||||||
this.restrict = 'E';
|
this.restrict = 'E';
|
||||||
this.template = template;
|
this.template = template;
|
||||||
this.scope = {
|
this.scope = {
|
||||||
component: '=',
|
componentUuid: '=',
|
||||||
onLoad: '=?',
|
onLoad: '=?',
|
||||||
manualDealloc: '=?',
|
|
||||||
application: '='
|
application: '='
|
||||||
};
|
};
|
||||||
this.controller = ComponentViewCtrl;
|
this.controller = ComponentViewCtrl;
|
||||||
|
|||||||
@@ -15,7 +15,7 @@ interface EditorMenuScope {
|
|||||||
|
|
||||||
class EditorMenuCtrl extends PureViewCtrl implements EditorMenuScope {
|
class EditorMenuCtrl extends PureViewCtrl implements EditorMenuScope {
|
||||||
|
|
||||||
callback!: (component: SNComponent) => void
|
callback!: () => (component: SNComponent) => void
|
||||||
selectedEditor!: SNComponent
|
selectedEditor!: SNComponent
|
||||||
currentItem!: SNItem
|
currentItem!: SNItem
|
||||||
application!: WebApplication
|
application!: WebApplication
|
||||||
@@ -52,7 +52,7 @@ class EditorMenuCtrl extends PureViewCtrl implements EditorMenuScope {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
this.$timeout(() => {
|
this.$timeout(() => {
|
||||||
this.callback(component);
|
this.callback()(component);
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -1,3 +1,4 @@
|
|||||||
|
import { ComponentGroup } from './component_group';
|
||||||
import { EditorGroup } from '@/ui_models/editor_group';
|
import { EditorGroup } from '@/ui_models/editor_group';
|
||||||
import { InputModalScope } from '@/directives/views/inputModal';
|
import { InputModalScope } from '@/directives/views/inputModal';
|
||||||
import { PasswordWizardType, PasswordWizardScope } from '@/types';
|
import { PasswordWizardType, PasswordWizardScope } from '@/types';
|
||||||
@@ -13,7 +14,7 @@ import {
|
|||||||
import angular from 'angular';
|
import angular from 'angular';
|
||||||
import { getPlatformString } from '@/utils';
|
import { getPlatformString } from '@/utils';
|
||||||
import { AlertService } from '@/services/alertService';
|
import { AlertService } from '@/services/alertService';
|
||||||
import { WebDeviceInterface } from '@/web_device_interface';
|
import { WebDeviceInterface } from '@/interface';
|
||||||
import {
|
import {
|
||||||
AppState,
|
AppState,
|
||||||
DesktopManager,
|
DesktopManager,
|
||||||
@@ -46,6 +47,7 @@ export class WebApplication extends SNApplication {
|
|||||||
private webServices!: WebServices
|
private webServices!: WebServices
|
||||||
private currentAuthenticationElement?: JQLite
|
private currentAuthenticationElement?: JQLite
|
||||||
public editorGroup: EditorGroup
|
public editorGroup: EditorGroup
|
||||||
|
public componentGroup: ComponentGroup
|
||||||
|
|
||||||
/* @ngInject */
|
/* @ngInject */
|
||||||
constructor(
|
constructor(
|
||||||
@@ -74,6 +76,7 @@ export class WebApplication extends SNApplication {
|
|||||||
this.onDeinit = onDeinit;
|
this.onDeinit = onDeinit;
|
||||||
deviceInterface.setApplication(this);
|
deviceInterface.setApplication(this);
|
||||||
this.editorGroup = new EditorGroup(this);
|
this.editorGroup = new EditorGroup(this);
|
||||||
|
this.componentGroup = new ComponentGroup(this);
|
||||||
}
|
}
|
||||||
|
|
||||||
/** @override */
|
/** @override */
|
||||||
@@ -90,6 +93,7 @@ export class WebApplication extends SNApplication {
|
|||||||
this.onDeinit = undefined;
|
this.onDeinit = undefined;
|
||||||
this.$compile = undefined;
|
this.$compile = undefined;
|
||||||
this.editorGroup.deinit();
|
this.editorGroup.deinit();
|
||||||
|
this.componentGroup.deinit();
|
||||||
(this.scope! as any).application = undefined;
|
(this.scope! as any).application = undefined;
|
||||||
this.scope!.$destroy();
|
this.scope!.$destroy();
|
||||||
this.scope = undefined;
|
this.scope = undefined;
|
||||||
|
|||||||
100
app/assets/javascripts/ui_models/component_group.ts
Normal file
100
app/assets/javascripts/ui_models/component_group.ts
Normal file
@@ -0,0 +1,100 @@
|
|||||||
|
import { dictToArray } from '../utils';
|
||||||
|
import { SNComponent, ComponentArea, removeFromArray } from 'snjs';
|
||||||
|
import { WebApplication } from './application';
|
||||||
|
|
||||||
|
/** Areas that only allow a single component to be active */
|
||||||
|
const SingleComponentAreas = [
|
||||||
|
ComponentArea.Editor,
|
||||||
|
ComponentArea.NoteTags,
|
||||||
|
ComponentArea.TagsList
|
||||||
|
]
|
||||||
|
|
||||||
|
export class ComponentGroup {
|
||||||
|
|
||||||
|
private application: WebApplication
|
||||||
|
changeObservers: any[] = []
|
||||||
|
activeComponents: Partial<Record<string, SNComponent>> = {}
|
||||||
|
|
||||||
|
|
||||||
|
constructor(application: WebApplication) {
|
||||||
|
this.application = application;
|
||||||
|
}
|
||||||
|
|
||||||
|
get componentManager() {
|
||||||
|
return this.application.componentManager!;
|
||||||
|
}
|
||||||
|
|
||||||
|
public deinit() {
|
||||||
|
(this.application as any) = undefined;
|
||||||
|
for (const component of this.allActiveComponents()) {
|
||||||
|
this.componentManager.deregisterComponent(component);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
async activateComponent(component: SNComponent) {
|
||||||
|
if (this.activeComponents[component.uuid]) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
if (SingleComponentAreas.includes(component.area)) {
|
||||||
|
const currentActive = this.activeComponentForArea(component.area);
|
||||||
|
if (currentActive) {
|
||||||
|
await this.deactivateComponent(currentActive, false);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
this.activeComponents[component.uuid] = component;
|
||||||
|
await this.componentManager.activateComponent(component);
|
||||||
|
this.notifyObservers();
|
||||||
|
}
|
||||||
|
|
||||||
|
async deactivateComponent(component: SNComponent, notify = true) {
|
||||||
|
if (!this.activeComponents[component.uuid]) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
delete this.activeComponents[component.uuid];
|
||||||
|
await this.componentManager.deactivateComponent(component);
|
||||||
|
if(notify) {
|
||||||
|
this.notifyObservers();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
async deactivateComponentForArea(area: ComponentArea) {
|
||||||
|
const component = this.activeComponentForArea(area);
|
||||||
|
if (component) {
|
||||||
|
return this.deactivateComponent(component);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
activeComponentForArea(area: ComponentArea) {
|
||||||
|
return this.activeComponentsForArea(area)[0];
|
||||||
|
}
|
||||||
|
|
||||||
|
activeComponentsForArea(area: ComponentArea) {
|
||||||
|
const all = dictToArray(this.activeComponents);
|
||||||
|
return all.filter((c) => c.area === area);
|
||||||
|
}
|
||||||
|
|
||||||
|
allComponentsForArea(area: ComponentArea) {
|
||||||
|
return this.componentManager.componentsForArea(area);
|
||||||
|
}
|
||||||
|
|
||||||
|
private allActiveComponents() {
|
||||||
|
return dictToArray(this.activeComponents);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Notifies observer when the active editor has changed.
|
||||||
|
*/
|
||||||
|
public addChangeObserver(callback: () => void) {
|
||||||
|
this.changeObservers.push(callback);
|
||||||
|
return () => {
|
||||||
|
removeFromArray(this.changeObservers, callback);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private notifyObservers() {
|
||||||
|
for (const observer of this.changeObservers) {
|
||||||
|
observer();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -11,8 +11,8 @@ export function isNullOrUndefined(value: any) {
|
|||||||
return value === null || value === undefined;
|
return value === null || value === undefined;
|
||||||
}
|
}
|
||||||
|
|
||||||
export function dictToArray(dict: any) {
|
export function dictToArray<T>(dict: Record<any, T>) {
|
||||||
return Object.keys(dict).map((key) => dict[key]);
|
return Object.keys(dict).map((key) => dict[key]!);
|
||||||
}
|
}
|
||||||
|
|
||||||
export function getPlatformString() {
|
export function getPlatformString() {
|
||||||
|
|||||||
@@ -31,9 +31,9 @@
|
|||||||
) {{self.state.noteStatus.message}}
|
) {{self.state.noteStatus.message}}
|
||||||
.desc(ng-show='self.state.noteStatus.desc') {{self.state.noteStatus.desc}}
|
.desc(ng-show='self.state.noteStatus.desc') {{self.state.noteStatus.desc}}
|
||||||
.editor-tags
|
.editor-tags
|
||||||
#note-tags-component-container(ng-if='self.state.tagsComponent')
|
#note-tags-component-container(ng-if='self.activeTagsComponent')
|
||||||
component-view.component-view(
|
component-view.component-view(
|
||||||
component='self.state.tagsComponent',
|
component-uuid='self.activeTagsComponent.uuid',
|
||||||
ng-class="{'locked' : self.noteLocked}",
|
ng-class="{'locked' : self.noteLocked}",
|
||||||
ng-style="self.noteLocked && {'pointer-events' : 'none'}",
|
ng-style="self.noteLocked && {'pointer-events' : 'none'}",
|
||||||
application='self.application'
|
application='self.application'
|
||||||
@@ -41,7 +41,7 @@
|
|||||||
input.tags-input(
|
input.tags-input(
|
||||||
ng-blur='self.onTagsInputBlur()',
|
ng-blur='self.onTagsInputBlur()',
|
||||||
ng-disabled='self.noteLocked',
|
ng-disabled='self.noteLocked',
|
||||||
ng-if='!(self.state.tagsComponent && self.state.tagsComponent.active)',
|
ng-if='!self.activeTagsComponent',
|
||||||
ng-keyup='$event.keyCode == 13 && $event.target.blur();',
|
ng-keyup='$event.keyCode == 13 && $event.target.blur();',
|
||||||
ng-model='self.editorValues.tagsInputValue',
|
ng-model='self.editorValues.tagsInputValue',
|
||||||
placeholder='#tags',
|
placeholder='#tags',
|
||||||
@@ -133,18 +133,18 @@
|
|||||||
action="self.selectedMenuItem(true); self.toggleWebPrefKey(self.prefKeyMonospace)",
|
action="self.selectedMenuItem(true); self.toggleWebPrefKey(self.prefKeyMonospace)",
|
||||||
circle="self.state.monospaceEnabled ? 'success' : 'neutral'",
|
circle="self.state.monospaceEnabled ? 'success' : 'neutral'",
|
||||||
desc="'Toggles the font style for the default editor'",
|
desc="'Toggles the font style for the default editor'",
|
||||||
disabled='self.state.selectedEditor',
|
disabled='self.activeEditorComponent',
|
||||||
label="'Monospace Font'",
|
label="'Monospace Font'",
|
||||||
subtitle="self.state.selectedEditor ? 'Not available with editor extensions' : null"
|
subtitle="self.activeEditorComponent ? 'Not available with editor extensions' : null"
|
||||||
)
|
)
|
||||||
menu-row(
|
menu-row(
|
||||||
action="self.selectedMenuItem(true); self.toggleWebPrefKey(self.prefKeySpellcheck)",
|
action="self.selectedMenuItem(true); self.toggleWebPrefKey(self.prefKeySpellcheck)",
|
||||||
circle="self.state.spellcheck ? 'success' : 'neutral'",
|
circle="self.state.spellcheck ? 'success' : 'neutral'",
|
||||||
desc="'Toggles spellcheck for the default editor'",
|
desc="'Toggles spellcheck for the default editor'",
|
||||||
disabled='self.state.selectedEditor',
|
disabled='self.activeEditorComponent',
|
||||||
label="'Spellcheck'",
|
label="'Spellcheck'",
|
||||||
subtitle=`
|
subtitle=`
|
||||||
self.state.selectedEditor
|
self.activeEditorComponent
|
||||||
? 'Not available with editor extensions'
|
? 'Not available with editor extensions'
|
||||||
: (self.state.isDesktop ? 'May degrade editor performance' : null)
|
: (self.state.isDesktop ? 'May degrade editor performance' : null)
|
||||||
`)
|
`)
|
||||||
@@ -163,10 +163,10 @@
|
|||||||
)
|
)
|
||||||
.sk-label Editor
|
.sk-label Editor
|
||||||
editor-menu(
|
editor-menu(
|
||||||
callback='self.editorMenuOnSelect()',
|
callback='self.editorMenuOnSelect',
|
||||||
current-item='self.note',
|
current-item='self.note',
|
||||||
ng-if='self.state.showEditorMenu',
|
ng-if='self.state.showEditorMenu',
|
||||||
selected-editor='self.state.selectedEditor',
|
selected-editor='self.activeEditorComponent',
|
||||||
application='self.application'
|
application='self.application'
|
||||||
)
|
)
|
||||||
.sk-app-bar-item(
|
.sk-app-bar-item(
|
||||||
@@ -205,8 +205,8 @@
|
|||||||
property="'left'"
|
property="'left'"
|
||||||
)
|
)
|
||||||
component-view.component-view(
|
component-view.component-view(
|
||||||
component='self.state.selectedEditor',
|
component-uuid='self.activeEditorComponent.uuid',
|
||||||
ng-if='self.state.selectedEditor',
|
ng-if='self.activeEditorComponent',
|
||||||
on-load='self.onEditorLoad',
|
on-load='self.onEditorLoad',
|
||||||
application='self.application'
|
application='self.application'
|
||||||
)
|
)
|
||||||
@@ -216,7 +216,7 @@
|
|||||||
ng-change='self.contentChanged()',
|
ng-change='self.contentChanged()',
|
||||||
ng-click='self.clickedTextArea()',
|
ng-click='self.clickedTextArea()',
|
||||||
ng-focus='self.onContentFocus()',
|
ng-focus='self.onContentFocus()',
|
||||||
ng-if='!self.state.selectedEditor',
|
ng-if='!self.activeEditorComponent',
|
||||||
ng-model='self.editorValues.text',
|
ng-model='self.editorValues.text',
|
||||||
ng-model-options='{ debounce: self.state.editorDebounce}',
|
ng-model-options='{ debounce: self.state.editorDebounce}',
|
||||||
ng-readonly='self.noteLocked',
|
ng-readonly='self.noteLocked',
|
||||||
@@ -236,11 +236,11 @@
|
|||||||
| There was an error decrypting this item. Ensure you are running the
|
| 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.
|
| latest version of this app, then sign out and sign back in to try again.
|
||||||
#editor-pane-component-stack(ng-show='self.note')
|
#editor-pane-component-stack(ng-show='self.note')
|
||||||
#component-stack-menu-bar.sk-app-bar.no-edges(ng-if='self.state.componentStack.length')
|
#component-stack-menu-bar.sk-app-bar.no-edges(ng-if='self.state.allStackComponents.length')
|
||||||
.left
|
.left
|
||||||
.sk-app-bar-item(
|
.sk-app-bar-item(
|
||||||
|
ng-repeat='component in self.state.allStackComponents track by component.uuid'
|
||||||
ng-click='self.toggleStackComponentForCurrentItem(component)',
|
ng-click='self.toggleStackComponentForCurrentItem(component)',
|
||||||
ng-repeat='component in self.state.componentStack track by component.uuid'
|
|
||||||
)
|
)
|
||||||
.sk-app-bar-item-column
|
.sk-app-bar-item-column
|
||||||
.sk-circle.small(
|
.sk-circle.small(
|
||||||
@@ -250,10 +250,9 @@
|
|||||||
.sk-label {{component.name}}
|
.sk-label {{component.name}}
|
||||||
.sn-component
|
.sn-component
|
||||||
component-view.component-view.component-stack-item(
|
component-view.component-view.component-stack-item(
|
||||||
component='component',
|
ng-repeat='component in self.activeStackComponents track by component.uuid',
|
||||||
|
component-uuid='component.uuid',
|
||||||
manual-dealloc='true',
|
manual-dealloc='true',
|
||||||
ng-if='component.active',
|
|
||||||
ng-repeat='component in self.state.componentStack track by component.uuid',
|
|
||||||
ng-show='!component.hidden',
|
ng-show='!component.hidden',
|
||||||
application='self.application'
|
application='self.application'
|
||||||
)
|
)
|
||||||
|
|||||||
@@ -58,15 +58,16 @@ type NoteStatus = {
|
|||||||
}
|
}
|
||||||
|
|
||||||
type EditorState = {
|
type EditorState = {
|
||||||
|
allStackComponents: SNComponent[]
|
||||||
|
activeEditorComponent?: SNComponent
|
||||||
|
activeTagsComponent?: SNComponent
|
||||||
|
activeStackComponents: SNComponent[]
|
||||||
saveError?: any
|
saveError?: any
|
||||||
editorComponent?: SNComponent
|
|
||||||
noteStatus?: NoteStatus
|
noteStatus?: NoteStatus
|
||||||
tagsAsStrings?: string
|
tagsAsStrings?: string
|
||||||
marginResizersEnabled?: boolean
|
marginResizersEnabled?: boolean
|
||||||
monospaceEnabled?: boolean
|
monospaceEnabled?: boolean
|
||||||
isDesktop?: boolean
|
isDesktop?: boolean
|
||||||
tagsComponent?: SNComponent
|
|
||||||
componentStack?: SNComponent[]
|
|
||||||
syncTakingTooLong: boolean
|
syncTakingTooLong: boolean
|
||||||
showExtensions: boolean
|
showExtensions: boolean
|
||||||
noteReady: boolean
|
noteReady: boolean
|
||||||
@@ -106,6 +107,7 @@ class EditorViewCtrl extends PureViewCtrl implements EditorViewScope {
|
|||||||
private removeTrashKeyObserver?: any
|
private removeTrashKeyObserver?: any
|
||||||
private removeDeleteKeyObserver?: any
|
private removeDeleteKeyObserver?: any
|
||||||
private removeTabObserver?: any
|
private removeTabObserver?: any
|
||||||
|
private removeComponentObserver: any
|
||||||
|
|
||||||
prefKeyMonospace: string
|
prefKeyMonospace: string
|
||||||
prefKeySpellcheck: string
|
prefKeySpellcheck: string
|
||||||
@@ -133,6 +135,8 @@ class EditorViewCtrl extends PureViewCtrl implements EditorViewScope {
|
|||||||
}
|
}
|
||||||
|
|
||||||
deinit() {
|
deinit() {
|
||||||
|
this.removeComponentObserver();
|
||||||
|
this.removeComponentObserver = undefined;
|
||||||
this.removeAltKeyObserver();
|
this.removeAltKeyObserver();
|
||||||
this.removeAltKeyObserver = undefined;
|
this.removeAltKeyObserver = undefined;
|
||||||
this.removeTrashKeyObserver();
|
this.removeTrashKeyObserver();
|
||||||
@@ -173,20 +177,29 @@ class EditorViewCtrl extends PureViewCtrl implements EditorViewScope {
|
|||||||
this.editorValues.text = note.text;
|
this.editorValues.text = note.text;
|
||||||
this.reloadTagsString();
|
this.reloadTagsString();
|
||||||
}
|
}
|
||||||
|
});
|
||||||
|
this.removeComponentObserver = this.componentGroup.addChangeObserver(() => {
|
||||||
|
this.setEditorState({
|
||||||
|
activeEditorComponent: this.componentGroup.activeComponentForArea(ComponentArea.Editor),
|
||||||
|
activeTagsComponent: this.componentGroup.activeComponentForArea(ComponentArea.NoteTags),
|
||||||
|
activeStackComponents: this.componentGroup.activeComponentsForArea(ComponentArea.EditorStack)
|
||||||
|
})
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
/** @override */
|
/** @override */
|
||||||
getInitialState() {
|
getInitialState() {
|
||||||
return {
|
return {
|
||||||
componentStack: [],
|
allStackComponents: [],
|
||||||
|
activeStackComponents: [],
|
||||||
editorDebounce: EDITOR_DEBOUNCE,
|
editorDebounce: EDITOR_DEBOUNCE,
|
||||||
isDesktop: isDesktopApplication(),
|
isDesktop: isDesktopApplication(),
|
||||||
spellcheck: true,
|
spellcheck: true,
|
||||||
|
noteReady: true,
|
||||||
mutable: {
|
mutable: {
|
||||||
tagsString: ''
|
tagsString: ''
|
||||||
}
|
}
|
||||||
};
|
} as Partial<EditorState>;
|
||||||
}
|
}
|
||||||
|
|
||||||
async setEditorState(state: Partial<EditorState>) {
|
async setEditorState(state: Partial<EditorState>) {
|
||||||
@@ -238,6 +251,22 @@ class EditorViewCtrl extends PureViewCtrl implements EditorViewScope {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
get activeEditorComponent() {
|
||||||
|
return this.getState().activeEditorComponent;
|
||||||
|
}
|
||||||
|
|
||||||
|
get activeTagsComponent() {
|
||||||
|
return this.getState().activeTagsComponent;
|
||||||
|
}
|
||||||
|
|
||||||
|
get activeStackComponents() {
|
||||||
|
return this.getState().activeStackComponents;
|
||||||
|
}
|
||||||
|
|
||||||
|
get componentGroup() {
|
||||||
|
return this.application.componentGroup;
|
||||||
|
}
|
||||||
|
|
||||||
async handleEditorNoteChange() {
|
async handleEditorNoteChange() {
|
||||||
const note = this.editor.note;
|
const note = this.editor.note;
|
||||||
await this.setEditorState({
|
await this.setEditorState({
|
||||||
@@ -248,31 +277,7 @@ class EditorViewCtrl extends PureViewCtrl implements EditorViewScope {
|
|||||||
});
|
});
|
||||||
this.editorValues.title = note.title;
|
this.editorValues.title = note.title;
|
||||||
this.editorValues.text = note.text;
|
this.editorValues.text = note.text;
|
||||||
if (!note) {
|
await this.reloadComponentEditorState();
|
||||||
this.setEditorState({
|
|
||||||
noteReady: false
|
|
||||||
});
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
const associatedEditor = this.editorForNote(note);
|
|
||||||
if (associatedEditor && associatedEditor !== this.getState().editorComponent) {
|
|
||||||
/**
|
|
||||||
* 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.setEditorState({
|
|
||||||
noteReady: false,
|
|
||||||
editorComponent: associatedEditor
|
|
||||||
});
|
|
||||||
} else if (!associatedEditor) {
|
|
||||||
/** No editor */
|
|
||||||
this.setEditorState({
|
|
||||||
editorComponent: undefined
|
|
||||||
});
|
|
||||||
}
|
|
||||||
await this.setEditorState({
|
|
||||||
noteReady: true,
|
|
||||||
});
|
|
||||||
this.reloadTagsString();
|
this.reloadTagsString();
|
||||||
this.reloadPreferences();
|
this.reloadPreferences();
|
||||||
if (note.safeText().length === 0) {
|
if (note.safeText().length === 0) {
|
||||||
@@ -281,6 +286,19 @@ class EditorViewCtrl extends PureViewCtrl implements EditorViewScope {
|
|||||||
this.reloadComponentContext();
|
this.reloadComponentContext();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
async reloadComponentEditorState() {
|
||||||
|
const associatedEditor = this.application.componentManager!.editorForNote(this.note)
|
||||||
|
if (associatedEditor && associatedEditor !== this.activeEditorComponent) {
|
||||||
|
/** 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 */
|
||||||
|
await this.componentGroup.activateComponent(associatedEditor);
|
||||||
|
} else if (!associatedEditor) {
|
||||||
|
/** No editor */
|
||||||
|
await this.componentGroup.deactivateComponentForArea(ComponentArea.Editor);
|
||||||
|
}
|
||||||
|
return associatedEditor;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Because note.locked accesses note.content.appData,
|
* Because note.locked accesses note.content.appData,
|
||||||
@@ -334,10 +352,7 @@ class EditorViewCtrl extends PureViewCtrl implements EditorViewScope {
|
|||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
/** Find the most recent editor for note */
|
/** Find the most recent editor for note */
|
||||||
const editor = this.editorForNote(this.note);
|
const editor = this.reloadComponentEditorState();
|
||||||
this.setEditorState({
|
|
||||||
editorComponent: editor
|
|
||||||
});
|
|
||||||
if (!editor) {
|
if (!editor) {
|
||||||
this.reloadFont();
|
this.reloadFont();
|
||||||
}
|
}
|
||||||
@@ -345,10 +360,6 @@ class EditorViewCtrl extends PureViewCtrl implements EditorViewScope {
|
|||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
editorForNote(note: SNNote) {
|
|
||||||
return this.application.componentManager!.editorForNote(note);
|
|
||||||
}
|
|
||||||
|
|
||||||
setMenuState(menu: string, state: boolean) {
|
setMenuState(menu: string, state: boolean) {
|
||||||
this.setEditorState({
|
this.setEditorState({
|
||||||
[menu]: state
|
[menu]: state
|
||||||
@@ -376,42 +387,39 @@ class EditorViewCtrl extends PureViewCtrl implements EditorViewScope {
|
|||||||
this.setEditorState(menuState);
|
this.setEditorState(menuState);
|
||||||
}
|
}
|
||||||
|
|
||||||
editorMenuOnSelect(component: SNComponent) {
|
async editorMenuOnSelect(component?: SNComponent) {
|
||||||
if (!component || component.area === 'editor-editor') {
|
this.setMenuState('showEditorMenu', false);
|
||||||
/** If plain editor or other editor */
|
if (!component) {
|
||||||
this.setMenuState('showEditorMenu', false);
|
if (!this.note.prefersPlainEditor) {
|
||||||
const editor = component;
|
await this.application.changeItem(this.note.uuid, (mutator) => {
|
||||||
if (this.getState().editorComponent && editor !== this.getState().editorComponent) {
|
const noteMutator = mutator as NoteMutator;
|
||||||
this.disassociateComponentWithCurrentNote(this.getState().editorComponent!);
|
noteMutator.prefersPlainEditor = true;
|
||||||
|
})
|
||||||
}
|
}
|
||||||
const note = this.note;
|
if(this.activeEditorComponent?.isExplicitlyEnabledForItem(this.note)) {
|
||||||
if (editor) {
|
await this.disassociateComponentWithCurrentNote(this.activeEditorComponent);
|
||||||
const prefersPlain = note.prefersPlainEditor;
|
|
||||||
if (prefersPlain) {
|
|
||||||
this.application.changeItem(note.uuid, (mutator) => {
|
|
||||||
const noteMutator = mutator as NoteMutator;
|
|
||||||
noteMutator.prefersPlainEditor = false;
|
|
||||||
})
|
|
||||||
}
|
|
||||||
this.associateComponentWithCurrentNote(editor);
|
|
||||||
} else {
|
|
||||||
/** Note prefers plain editor */
|
|
||||||
if (!note.prefersPlainEditor) {
|
|
||||||
this.application.changeItem(note.uuid, (mutator) => {
|
|
||||||
const noteMutator = mutator as NoteMutator;
|
|
||||||
noteMutator.prefersPlainEditor = true;
|
|
||||||
})
|
|
||||||
}
|
|
||||||
this.reloadFont();
|
|
||||||
}
|
}
|
||||||
|
await this.componentGroup.deactivateComponentForArea(ComponentArea.Editor);
|
||||||
this.setEditorState({
|
this.reloadFont();
|
||||||
editorComponent: editor
|
}
|
||||||
});
|
else if (component.area === ComponentArea.Editor) {
|
||||||
} else if (component.area === 'editor-stack') {
|
const currentEditor = this.activeEditorComponent;
|
||||||
this.toggleStackComponentForCurrentItem(component);
|
if (currentEditor && component !== currentEditor) {
|
||||||
|
await this.disassociateComponentWithCurrentNote(currentEditor);
|
||||||
|
}
|
||||||
|
const prefersPlain = this.note.prefersPlainEditor;
|
||||||
|
if (prefersPlain) {
|
||||||
|
await this.application.changeItem(this.note.uuid, (mutator) => {
|
||||||
|
const noteMutator = mutator as NoteMutator;
|
||||||
|
noteMutator.prefersPlainEditor = false;
|
||||||
|
})
|
||||||
|
}
|
||||||
|
await this.associateComponentWithCurrentNote(component);
|
||||||
|
await this.componentGroup.activateComponent(component);
|
||||||
|
}
|
||||||
|
else if (component.area === ComponentArea.EditorStack) {
|
||||||
|
await this.toggleStackComponentForCurrentItem(component);
|
||||||
}
|
}
|
||||||
|
|
||||||
/** Dirtying can happen above */
|
/** Dirtying can happen above */
|
||||||
this.application.sync();
|
this.application.sync();
|
||||||
}
|
}
|
||||||
@@ -980,55 +988,16 @@ class EditorViewCtrl extends PureViewCtrl implements EditorViewScope {
|
|||||||
ComponentArea.Editor
|
ComponentArea.Editor
|
||||||
],
|
],
|
||||||
activationHandler: (component) => {
|
activationHandler: (component) => {
|
||||||
if (component.area === 'note-tags') {
|
if (component.area === ComponentArea.EditorStack) {
|
||||||
this.setEditorState({
|
|
||||||
tagsComponent: component.active ? component : undefined
|
|
||||||
});
|
|
||||||
} else if (component.area === 'editor-editor') {
|
|
||||||
if (
|
|
||||||
component === this.getState().editorComponent &&
|
|
||||||
!component.active
|
|
||||||
) {
|
|
||||||
this.setEditorState({ editorComponent: undefined });
|
|
||||||
}
|
|
||||||
else if (this.getState().editorComponent) {
|
|
||||||
if (this.getState().editorComponent!.active && this.note) {
|
|
||||||
if (
|
|
||||||
component.isExplicitlyEnabledForItem(this.note)
|
|
||||||
&& !this.getState().editorComponent!.isExplicitlyEnabledForItem(this.note)
|
|
||||||
) {
|
|
||||||
this.setEditorState({ editorComponent: component });
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
else if (this.note) {
|
|
||||||
const enableable = (
|
|
||||||
component.isExplicitlyEnabledForItem(this.note)
|
|
||||||
|| component.isDefaultEditor()
|
|
||||||
);
|
|
||||||
if (
|
|
||||||
component.active
|
|
||||||
&& enableable
|
|
||||||
) {
|
|
||||||
this.setEditorState({ editorComponent: component });
|
|
||||||
} else {
|
|
||||||
/**
|
|
||||||
* Not a candidate, and no qualified editor.
|
|
||||||
* Disable the current editor.
|
|
||||||
*/
|
|
||||||
this.setEditorState({ editorComponent: undefined });
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
} else if (component.area === 'editor-stack') {
|
|
||||||
this.reloadComponentContext();
|
this.reloadComponentContext();
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
contextRequestHandler: (component) => {
|
contextRequestHandler: (component) => {
|
||||||
|
const currentEditor = this.activeEditorComponent;
|
||||||
if (
|
if (
|
||||||
component === this.getState().editorComponent ||
|
component === currentEditor ||
|
||||||
component === this.getState().tagsComponent ||
|
component === this.activeTagsComponent ||
|
||||||
this.getState().componentStack!.includes(component)
|
this.activeStackComponents.includes(component)
|
||||||
) {
|
) {
|
||||||
return this.note;
|
return this.note;
|
||||||
}
|
}
|
||||||
@@ -1040,7 +1009,10 @@ class EditorViewCtrl extends PureViewCtrl implements EditorViewScope {
|
|||||||
},
|
},
|
||||||
actionHandler: (component, action, data) => {
|
actionHandler: (component, action, data) => {
|
||||||
if (action === ComponentAction.SetSize) {
|
if (action === ComponentAction.SetSize) {
|
||||||
const setSize = function (element: HTMLElement, size: { width: number, height: number }) {
|
const setSize = (
|
||||||
|
element: HTMLElement,
|
||||||
|
size: { width: number, height: number }
|
||||||
|
) => {
|
||||||
const widthString = typeof size.width === 'string'
|
const widthString = typeof size.width === 'string'
|
||||||
? size.width
|
? size.width
|
||||||
: `${data.width}px`;
|
: `${data.width}px`;
|
||||||
@@ -1089,16 +1061,15 @@ class EditorViewCtrl extends PureViewCtrl implements EditorViewScope {
|
|||||||
.sort((a, b) => {
|
.sort((a, b) => {
|
||||||
return a.name.toLowerCase() < b.name.toLowerCase() ? -1 : 1;
|
return a.name.toLowerCase() < b.name.toLowerCase() ? -1 : 1;
|
||||||
});
|
});
|
||||||
|
|
||||||
this.setEditorState({
|
this.setEditorState({
|
||||||
componentStack: components
|
allStackComponents: components
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
reloadComponentContext() {
|
reloadComponentContext() {
|
||||||
this.reloadComponentStackArray();
|
this.reloadComponentStackArray();
|
||||||
if (this.note) {
|
if (this.note) {
|
||||||
for (const component of this.getState().componentStack!) {
|
for (const component of this.getState().allStackComponents!) {
|
||||||
if (component.active) {
|
if (component.active) {
|
||||||
this.application.componentManager!.setComponentHidden(
|
this.application.componentManager!.setComponentHidden(
|
||||||
component,
|
component,
|
||||||
@@ -1113,33 +1084,34 @@ class EditorViewCtrl extends PureViewCtrl implements EditorViewScope {
|
|||||||
this.application.componentManager!.contextItemDidChangeInArea(ComponentArea.Editor);
|
this.application.componentManager!.contextItemDidChangeInArea(ComponentArea.Editor);
|
||||||
}
|
}
|
||||||
|
|
||||||
toggleStackComponentForCurrentItem(component: SNComponent) {
|
async toggleStackComponentForCurrentItem(component: SNComponent) {
|
||||||
const hidden = this.application.componentManager!.isComponentHidden(component);
|
const hidden = this.application.componentManager!.isComponentHidden(component);
|
||||||
if (hidden || !component.active) {
|
if (hidden || !component.active) {
|
||||||
this.application.componentManager!.setComponentHidden(component, false);
|
this.application.componentManager!.setComponentHidden(component, false);
|
||||||
this.associateComponentWithCurrentNote(component);
|
await this.associateComponentWithCurrentNote(component);
|
||||||
if (!component.active) {
|
if (!component.active) {
|
||||||
this.application.componentManager!.activateComponent(component);
|
this.application.componentManager!.activateComponent(component);
|
||||||
}
|
}
|
||||||
this.application.componentManager!.contextItemDidChangeInArea(ComponentArea.EditorStack);
|
this.application.componentManager!.contextItemDidChangeInArea(ComponentArea.EditorStack);
|
||||||
} else {
|
} else {
|
||||||
this.application.componentManager!.setComponentHidden(component, true);
|
this.application.componentManager!.setComponentHidden(component, true);
|
||||||
this.disassociateComponentWithCurrentNote(component);
|
await this.disassociateComponentWithCurrentNote(component);
|
||||||
}
|
}
|
||||||
|
this.application.sync();
|
||||||
}
|
}
|
||||||
|
|
||||||
disassociateComponentWithCurrentNote(component: SNComponent) {
|
async disassociateComponentWithCurrentNote(component: SNComponent) {
|
||||||
const note = this.note;
|
const note = this.note;
|
||||||
this.application.changeAndSaveItem(component.uuid, (m) => {
|
return this.application.changeItem(component.uuid, (m) => {
|
||||||
const mutator = m as ComponentMutator;
|
const mutator = m as ComponentMutator;
|
||||||
mutator.removeAssociatedItemId(note.uuid);
|
mutator.removeAssociatedItemId(note.uuid);
|
||||||
mutator.disassociateWithItem(note);
|
mutator.disassociateWithItem(note);
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
associateComponentWithCurrentNote(component: SNComponent) {
|
async associateComponentWithCurrentNote(component: SNComponent) {
|
||||||
const note = this.note;
|
const note = this.note;
|
||||||
this.application.changeAndSaveItem(component.uuid, (m) => {
|
return this.application.changeItem(component.uuid, (m) => {
|
||||||
const mutator = m as ComponentMutator;
|
const mutator = m as ComponentMutator;
|
||||||
mutator.removeDisassociatedItemId(note.uuid);
|
mutator.removeDisassociatedItemId(note.uuid);
|
||||||
mutator.associateWithItem(note);
|
mutator.associateWithItem(note);
|
||||||
|
|||||||
@@ -1,7 +1,7 @@
|
|||||||
#tags-column.sn-component.section.tags(aria-label='Tags')
|
#tags-column.sn-component.section.tags(aria-label='Tags')
|
||||||
.component-view-container(ng-if='self.component.active')
|
.component-view-container(ng-if='self.component.active')
|
||||||
component-view.component-view(
|
component-view.component-view(
|
||||||
component='self.component',
|
component-uuid='self.component.uuid',
|
||||||
application='self.application'
|
application='self.application'
|
||||||
)
|
)
|
||||||
#tags-content.content(ng-if='!(self.component && self.component.active)')
|
#tags-content.content(ng-if='!(self.component && self.component.active)')
|
||||||
|
|||||||
@@ -11,6 +11,6 @@
|
|||||||
| {{ctrl.component.name}}
|
| {{ctrl.component.name}}
|
||||||
a.sk-a.info.close-button(ng-click="ctrl.dismiss()") Close
|
a.sk-a.info.close-button(ng-click="ctrl.dismiss()") Close
|
||||||
component-view.component-view(
|
component-view.component-view(
|
||||||
component="ctrl.component",
|
component-uuid="ctrl.component.uuid",
|
||||||
application='ctrl.application'
|
application='ctrl.application'
|
||||||
)
|
)
|
||||||
|
|||||||
@@ -22,7 +22,7 @@
|
|||||||
style="white-space: pre-wrap; font-size: 16px;"
|
style="white-space: pre-wrap; font-size: 16px;"
|
||||||
) {{ctrl.content.text}}
|
) {{ctrl.content.text}}
|
||||||
component-view.component-view(
|
component-view.component-view(
|
||||||
component="ctrl.editor"
|
component-uuid="ctrl.editor.uuid"
|
||||||
ng-if="ctrl.editor",
|
ng-if="ctrl.editor",
|
||||||
application='ctrl.application'
|
application='ctrl.application'
|
||||||
)
|
)
|
||||||
|
|||||||
29
dist/@types/app/assets/javascripts/interface.d.ts
vendored
Normal file
29
dist/@types/app/assets/javascripts/interface.d.ts
vendored
Normal file
@@ -0,0 +1,29 @@
|
|||||||
|
import { DeviceInterface, SNApplication } from 'snjs';
|
||||||
|
export declare class WebDeviceInterface extends DeviceInterface {
|
||||||
|
private database;
|
||||||
|
constructor(namespace: string, timeout: any);
|
||||||
|
setApplication(application: SNApplication): void;
|
||||||
|
deinit(): void;
|
||||||
|
getRawStorageValue(key: string): Promise<string | null>;
|
||||||
|
getAllRawStorageKeyValues(): Promise<{
|
||||||
|
key: string;
|
||||||
|
value: any;
|
||||||
|
}[]>;
|
||||||
|
setRawStorageValue(key: string, value: any): Promise<void>;
|
||||||
|
removeRawStorageValue(key: string): Promise<void>;
|
||||||
|
removeAllRawStorageValues(): Promise<void>;
|
||||||
|
openDatabase(): Promise<{
|
||||||
|
isNewDatabase?: boolean | undefined;
|
||||||
|
} | undefined>;
|
||||||
|
private getDatabaseKeyPrefix;
|
||||||
|
private keyForPayloadId;
|
||||||
|
getAllRawDatabasePayloads(): Promise<any[]>;
|
||||||
|
saveRawDatabasePayload(payload: any): Promise<void>;
|
||||||
|
saveRawDatabasePayloads(payloads: any[]): Promise<void>;
|
||||||
|
removeRawDatabasePayloadWithId(id: string): Promise<void>;
|
||||||
|
removeAllRawDatabasePayloads(): Promise<void>;
|
||||||
|
getKeychainValue(): Promise<any>;
|
||||||
|
setKeychainValue(value: any): Promise<void>;
|
||||||
|
clearKeychainValue(): Promise<void>;
|
||||||
|
openUrl(url: string): void;
|
||||||
|
}
|
||||||
@@ -1,4 +1,5 @@
|
|||||||
/// <reference types="angular" />
|
/// <reference types="angular" />
|
||||||
|
import { ComponentGroup } from './component_group';
|
||||||
import { EditorGroup } from '@/ui_models/editor_group';
|
import { EditorGroup } from '@/ui_models/editor_group';
|
||||||
import { PasswordWizardType } from '@/types';
|
import { PasswordWizardType } from '@/types';
|
||||||
import { SNApplication, Challenge, ChallengeOrchestrator, ProtectedAction } from 'snjs';
|
import { SNApplication, Challenge, ChallengeOrchestrator, ProtectedAction } from 'snjs';
|
||||||
@@ -21,27 +22,19 @@ export declare class WebApplication extends SNApplication {
|
|||||||
private webServices;
|
private webServices;
|
||||||
private currentAuthenticationElement?;
|
private currentAuthenticationElement?;
|
||||||
editorGroup: EditorGroup;
|
editorGroup: EditorGroup;
|
||||||
|
componentGroup: ComponentGroup;
|
||||||
constructor($compile: ng.ICompileService, $timeout: ng.ITimeoutService, scope: ng.IScope, onDeinit: (app: WebApplication) => void);
|
constructor($compile: ng.ICompileService, $timeout: ng.ITimeoutService, scope: ng.IScope, onDeinit: (app: WebApplication) => void);
|
||||||
/** @override */
|
/** @override */
|
||||||
deinit(): void;
|
deinit(): void;
|
||||||
setWebServices(services: WebServices): void;
|
setWebServices(services: WebServices): void;
|
||||||
/** @access public */
|
|
||||||
getAppState(): AppState;
|
getAppState(): AppState;
|
||||||
/** @access public */
|
|
||||||
getDesktopService(): DesktopManager;
|
getDesktopService(): DesktopManager;
|
||||||
/** @access public */
|
|
||||||
getLockService(): LockManager;
|
getLockService(): LockManager;
|
||||||
/** @access public */
|
|
||||||
getArchiveService(): ArchiveManager;
|
getArchiveService(): ArchiveManager;
|
||||||
/** @access public */
|
|
||||||
getNativeExtService(): NativeExtManager;
|
getNativeExtService(): NativeExtManager;
|
||||||
/** @access public */
|
|
||||||
getStatusService(): StatusManager;
|
getStatusService(): StatusManager;
|
||||||
/** @access public */
|
|
||||||
getThemeService(): ThemeManager;
|
getThemeService(): ThemeManager;
|
||||||
/** @access public */
|
|
||||||
getPrefsService(): PreferencesManager;
|
getPrefsService(): PreferencesManager;
|
||||||
/** @access public */
|
|
||||||
getKeyboardService(): KeyboardManager;
|
getKeyboardService(): KeyboardManager;
|
||||||
checkForSecurityUpdate(): Promise<boolean>;
|
checkForSecurityUpdate(): Promise<boolean>;
|
||||||
presentPasswordWizard(type: PasswordWizardType): void;
|
presentPasswordWizard(type: PasswordWizardType): void;
|
||||||
|
|||||||
23
dist/@types/app/assets/javascripts/ui_models/component_group.d.ts
vendored
Normal file
23
dist/@types/app/assets/javascripts/ui_models/component_group.d.ts
vendored
Normal file
@@ -0,0 +1,23 @@
|
|||||||
|
import { SNComponent, ComponentArea } from 'snjs';
|
||||||
|
import { WebApplication } from './application';
|
||||||
|
export declare class ComponentGroup {
|
||||||
|
private application;
|
||||||
|
changeObservers: any[];
|
||||||
|
activeComponents: Partial<Record<string, SNComponent>>;
|
||||||
|
constructor(application: WebApplication);
|
||||||
|
get componentManager(): import("../../../../../snjs/dist/@types").SNComponentManager;
|
||||||
|
deinit(): void;
|
||||||
|
registerComponentHandler(): void;
|
||||||
|
activateComponent(component: SNComponent): Promise<void>;
|
||||||
|
deactivateComponent(component: SNComponent): Promise<void>;
|
||||||
|
deactivateComponentForArea(area: ComponentArea): Promise<void>;
|
||||||
|
activeComponentForArea(area: ComponentArea): SNComponent;
|
||||||
|
activeComponentsForArea(area: ComponentArea): SNComponent[];
|
||||||
|
allComponentsForArea(area: ComponentArea): SNComponent[];
|
||||||
|
private allActiveComponents;
|
||||||
|
/**
|
||||||
|
* Notifies observer when the active editor has changed.
|
||||||
|
*/
|
||||||
|
addChangeObserver(callback: any): void;
|
||||||
|
private notifyObservers;
|
||||||
|
}
|
||||||
@@ -1,6 +1,6 @@
|
|||||||
export declare function getParameterByName(name: string, url: string): string | null;
|
export declare function getParameterByName(name: string, url: string): string | null;
|
||||||
export declare function isNullOrUndefined(value: any): boolean;
|
export declare function isNullOrUndefined(value: any): boolean;
|
||||||
export declare function dictToArray(dict: any): any[];
|
export declare function dictToArray<T>(dict: Record<any, T>): NonNullable<T>[];
|
||||||
export declare function getPlatformString(): string;
|
export declare function getPlatformString(): string;
|
||||||
export declare function dateToLocalizedString(date: Date): string;
|
export declare function dateToLocalizedString(date: Date): string;
|
||||||
/** Via https://davidwalsh.name/javascript-debounce-function */
|
/** Via https://davidwalsh.name/javascript-debounce-function */
|
||||||
|
|||||||
2113
dist/javascripts/app.js
vendored
2113
dist/javascripts/app.js
vendored
File diff suppressed because one or more lines are too long
2
dist/javascripts/app.js.map
vendored
2
dist/javascripts/app.js.map
vendored
File diff suppressed because one or more lines are too long
Reference in New Issue
Block a user