Component management improvements, removal of dependence on noteReady flag
This commit is contained in:
@@ -31,9 +31,9 @@
|
||||
) {{self.state.noteStatus.message}}
|
||||
.desc(ng-show='self.state.noteStatus.desc') {{self.state.noteStatus.desc}}
|
||||
.editor-tags
|
||||
#note-tags-component-container(ng-if='self.state.tagsComponent')
|
||||
#note-tags-component-container(ng-if='self.activeTagsComponent')
|
||||
component-view.component-view(
|
||||
component='self.state.tagsComponent',
|
||||
component-uuid='self.activeTagsComponent.uuid',
|
||||
ng-class="{'locked' : self.noteLocked}",
|
||||
ng-style="self.noteLocked && {'pointer-events' : 'none'}",
|
||||
application='self.application'
|
||||
@@ -41,7 +41,7 @@
|
||||
input.tags-input(
|
||||
ng-blur='self.onTagsInputBlur()',
|
||||
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-model='self.editorValues.tagsInputValue',
|
||||
placeholder='#tags',
|
||||
@@ -133,18 +133,18 @@
|
||||
action="self.selectedMenuItem(true); self.toggleWebPrefKey(self.prefKeyMonospace)",
|
||||
circle="self.state.monospaceEnabled ? 'success' : 'neutral'",
|
||||
desc="'Toggles the font style for the default editor'",
|
||||
disabled='self.state.selectedEditor',
|
||||
disabled='self.activeEditorComponent',
|
||||
label="'Monospace Font'",
|
||||
subtitle="self.state.selectedEditor ? 'Not available with editor extensions' : null"
|
||||
subtitle="self.activeEditorComponent ? 'Not available with editor extensions' : null"
|
||||
)
|
||||
menu-row(
|
||||
action="self.selectedMenuItem(true); self.toggleWebPrefKey(self.prefKeySpellcheck)",
|
||||
circle="self.state.spellcheck ? 'success' : 'neutral'",
|
||||
desc="'Toggles spellcheck for the default editor'",
|
||||
disabled='self.state.selectedEditor',
|
||||
disabled='self.activeEditorComponent',
|
||||
label="'Spellcheck'",
|
||||
subtitle=`
|
||||
self.state.selectedEditor
|
||||
self.activeEditorComponent
|
||||
? 'Not available with editor extensions'
|
||||
: (self.state.isDesktop ? 'May degrade editor performance' : null)
|
||||
`)
|
||||
@@ -163,10 +163,10 @@
|
||||
)
|
||||
.sk-label Editor
|
||||
editor-menu(
|
||||
callback='self.editorMenuOnSelect()',
|
||||
callback='self.editorMenuOnSelect',
|
||||
current-item='self.note',
|
||||
ng-if='self.state.showEditorMenu',
|
||||
selected-editor='self.state.selectedEditor',
|
||||
selected-editor='self.activeEditorComponent',
|
||||
application='self.application'
|
||||
)
|
||||
.sk-app-bar-item(
|
||||
@@ -205,8 +205,8 @@
|
||||
property="'left'"
|
||||
)
|
||||
component-view.component-view(
|
||||
component='self.state.selectedEditor',
|
||||
ng-if='self.state.selectedEditor',
|
||||
component-uuid='self.activeEditorComponent.uuid',
|
||||
ng-if='self.activeEditorComponent',
|
||||
on-load='self.onEditorLoad',
|
||||
application='self.application'
|
||||
)
|
||||
@@ -216,7 +216,7 @@
|
||||
ng-change='self.contentChanged()',
|
||||
ng-click='self.clickedTextArea()',
|
||||
ng-focus='self.onContentFocus()',
|
||||
ng-if='!self.state.selectedEditor',
|
||||
ng-if='!self.activeEditorComponent',
|
||||
ng-model='self.editorValues.text',
|
||||
ng-model-options='{ debounce: self.state.editorDebounce}',
|
||||
ng-readonly='self.noteLocked',
|
||||
@@ -236,11 +236,11 @@
|
||||
| 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.
|
||||
#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
|
||||
.sk-app-bar-item(
|
||||
ng-repeat='component in self.state.allStackComponents track by component.uuid'
|
||||
ng-click='self.toggleStackComponentForCurrentItem(component)',
|
||||
ng-repeat='component in self.state.componentStack track by component.uuid'
|
||||
)
|
||||
.sk-app-bar-item-column
|
||||
.sk-circle.small(
|
||||
@@ -250,10 +250,9 @@
|
||||
.sk-label {{component.name}}
|
||||
.sn-component
|
||||
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',
|
||||
ng-if='component.active',
|
||||
ng-repeat='component in self.state.componentStack track by component.uuid',
|
||||
ng-show='!component.hidden',
|
||||
application='self.application'
|
||||
)
|
||||
|
||||
@@ -58,15 +58,16 @@ type NoteStatus = {
|
||||
}
|
||||
|
||||
type EditorState = {
|
||||
allStackComponents: SNComponent[]
|
||||
activeEditorComponent?: SNComponent
|
||||
activeTagsComponent?: SNComponent
|
||||
activeStackComponents: SNComponent[]
|
||||
saveError?: any
|
||||
editorComponent?: SNComponent
|
||||
noteStatus?: NoteStatus
|
||||
tagsAsStrings?: string
|
||||
marginResizersEnabled?: boolean
|
||||
monospaceEnabled?: boolean
|
||||
isDesktop?: boolean
|
||||
tagsComponent?: SNComponent
|
||||
componentStack?: SNComponent[]
|
||||
syncTakingTooLong: boolean
|
||||
showExtensions: boolean
|
||||
noteReady: boolean
|
||||
@@ -106,6 +107,7 @@ class EditorViewCtrl extends PureViewCtrl implements EditorViewScope {
|
||||
private removeTrashKeyObserver?: any
|
||||
private removeDeleteKeyObserver?: any
|
||||
private removeTabObserver?: any
|
||||
private removeComponentObserver: any
|
||||
|
||||
prefKeyMonospace: string
|
||||
prefKeySpellcheck: string
|
||||
@@ -133,6 +135,8 @@ class EditorViewCtrl extends PureViewCtrl implements EditorViewScope {
|
||||
}
|
||||
|
||||
deinit() {
|
||||
this.removeComponentObserver();
|
||||
this.removeComponentObserver = undefined;
|
||||
this.removeAltKeyObserver();
|
||||
this.removeAltKeyObserver = undefined;
|
||||
this.removeTrashKeyObserver();
|
||||
@@ -173,20 +177,29 @@ class EditorViewCtrl extends PureViewCtrl implements EditorViewScope {
|
||||
this.editorValues.text = note.text;
|
||||
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 */
|
||||
getInitialState() {
|
||||
return {
|
||||
componentStack: [],
|
||||
allStackComponents: [],
|
||||
activeStackComponents: [],
|
||||
editorDebounce: EDITOR_DEBOUNCE,
|
||||
isDesktop: isDesktopApplication(),
|
||||
spellcheck: true,
|
||||
noteReady: true,
|
||||
mutable: {
|
||||
tagsString: ''
|
||||
}
|
||||
};
|
||||
} as 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() {
|
||||
const note = this.editor.note;
|
||||
await this.setEditorState({
|
||||
@@ -248,31 +277,7 @@ class EditorViewCtrl extends PureViewCtrl implements EditorViewScope {
|
||||
});
|
||||
this.editorValues.title = note.title;
|
||||
this.editorValues.text = note.text;
|
||||
if (!note) {
|
||||
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,
|
||||
});
|
||||
await this.reloadComponentEditorState();
|
||||
this.reloadTagsString();
|
||||
this.reloadPreferences();
|
||||
if (note.safeText().length === 0) {
|
||||
@@ -281,6 +286,19 @@ class EditorViewCtrl extends PureViewCtrl implements EditorViewScope {
|
||||
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,
|
||||
@@ -334,10 +352,7 @@ class EditorViewCtrl extends PureViewCtrl implements EditorViewScope {
|
||||
return;
|
||||
}
|
||||
/** Find the most recent editor for note */
|
||||
const editor = this.editorForNote(this.note);
|
||||
this.setEditorState({
|
||||
editorComponent: editor
|
||||
});
|
||||
const editor = this.reloadComponentEditorState();
|
||||
if (!editor) {
|
||||
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) {
|
||||
this.setEditorState({
|
||||
[menu]: state
|
||||
@@ -376,42 +387,39 @@ class EditorViewCtrl extends PureViewCtrl implements EditorViewScope {
|
||||
this.setEditorState(menuState);
|
||||
}
|
||||
|
||||
editorMenuOnSelect(component: SNComponent) {
|
||||
if (!component || component.area === 'editor-editor') {
|
||||
/** If plain editor or other editor */
|
||||
this.setMenuState('showEditorMenu', false);
|
||||
const editor = component;
|
||||
if (this.getState().editorComponent && editor !== this.getState().editorComponent) {
|
||||
this.disassociateComponentWithCurrentNote(this.getState().editorComponent!);
|
||||
async editorMenuOnSelect(component?: SNComponent) {
|
||||
this.setMenuState('showEditorMenu', false);
|
||||
if (!component) {
|
||||
if (!this.note.prefersPlainEditor) {
|
||||
await this.application.changeItem(this.note.uuid, (mutator) => {
|
||||
const noteMutator = mutator as NoteMutator;
|
||||
noteMutator.prefersPlainEditor = true;
|
||||
})
|
||||
}
|
||||
const note = this.note;
|
||||
if (editor) {
|
||||
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();
|
||||
if(this.activeEditorComponent?.isExplicitlyEnabledForItem(this.note)) {
|
||||
await this.disassociateComponentWithCurrentNote(this.activeEditorComponent);
|
||||
}
|
||||
|
||||
this.setEditorState({
|
||||
editorComponent: editor
|
||||
});
|
||||
} else if (component.area === 'editor-stack') {
|
||||
this.toggleStackComponentForCurrentItem(component);
|
||||
await this.componentGroup.deactivateComponentForArea(ComponentArea.Editor);
|
||||
this.reloadFont();
|
||||
}
|
||||
else if (component.area === ComponentArea.Editor) {
|
||||
const currentEditor = this.activeEditorComponent;
|
||||
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 */
|
||||
this.application.sync();
|
||||
}
|
||||
@@ -980,55 +988,16 @@ class EditorViewCtrl extends PureViewCtrl implements EditorViewScope {
|
||||
ComponentArea.Editor
|
||||
],
|
||||
activationHandler: (component) => {
|
||||
if (component.area === 'note-tags') {
|
||||
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') {
|
||||
if (component.area === ComponentArea.EditorStack) {
|
||||
this.reloadComponentContext();
|
||||
}
|
||||
},
|
||||
contextRequestHandler: (component) => {
|
||||
const currentEditor = this.activeEditorComponent;
|
||||
if (
|
||||
component === this.getState().editorComponent ||
|
||||
component === this.getState().tagsComponent ||
|
||||
this.getState().componentStack!.includes(component)
|
||||
component === currentEditor ||
|
||||
component === this.activeTagsComponent ||
|
||||
this.activeStackComponents.includes(component)
|
||||
) {
|
||||
return this.note;
|
||||
}
|
||||
@@ -1040,7 +1009,10 @@ class EditorViewCtrl extends PureViewCtrl implements EditorViewScope {
|
||||
},
|
||||
actionHandler: (component, action, data) => {
|
||||
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'
|
||||
? size.width
|
||||
: `${data.width}px`;
|
||||
@@ -1089,16 +1061,15 @@ class EditorViewCtrl extends PureViewCtrl implements EditorViewScope {
|
||||
.sort((a, b) => {
|
||||
return a.name.toLowerCase() < b.name.toLowerCase() ? -1 : 1;
|
||||
});
|
||||
|
||||
this.setEditorState({
|
||||
componentStack: components
|
||||
allStackComponents: components
|
||||
});
|
||||
}
|
||||
|
||||
reloadComponentContext() {
|
||||
this.reloadComponentStackArray();
|
||||
if (this.note) {
|
||||
for (const component of this.getState().componentStack!) {
|
||||
for (const component of this.getState().allStackComponents!) {
|
||||
if (component.active) {
|
||||
this.application.componentManager!.setComponentHidden(
|
||||
component,
|
||||
@@ -1113,33 +1084,34 @@ class EditorViewCtrl extends PureViewCtrl implements EditorViewScope {
|
||||
this.application.componentManager!.contextItemDidChangeInArea(ComponentArea.Editor);
|
||||
}
|
||||
|
||||
toggleStackComponentForCurrentItem(component: SNComponent) {
|
||||
async toggleStackComponentForCurrentItem(component: SNComponent) {
|
||||
const hidden = this.application.componentManager!.isComponentHidden(component);
|
||||
if (hidden || !component.active) {
|
||||
this.application.componentManager!.setComponentHidden(component, false);
|
||||
this.associateComponentWithCurrentNote(component);
|
||||
await this.associateComponentWithCurrentNote(component);
|
||||
if (!component.active) {
|
||||
this.application.componentManager!.activateComponent(component);
|
||||
}
|
||||
this.application.componentManager!.contextItemDidChangeInArea(ComponentArea.EditorStack);
|
||||
} else {
|
||||
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;
|
||||
this.application.changeAndSaveItem(component.uuid, (m) => {
|
||||
return this.application.changeItem(component.uuid, (m) => {
|
||||
const mutator = m as ComponentMutator;
|
||||
mutator.removeAssociatedItemId(note.uuid);
|
||||
mutator.disassociateWithItem(note);
|
||||
})
|
||||
}
|
||||
|
||||
associateComponentWithCurrentNote(component: SNComponent) {
|
||||
async associateComponentWithCurrentNote(component: SNComponent) {
|
||||
const note = this.note;
|
||||
this.application.changeAndSaveItem(component.uuid, (m) => {
|
||||
return this.application.changeItem(component.uuid, (m) => {
|
||||
const mutator = m as ComponentMutator;
|
||||
mutator.removeDisassociatedItemId(note.uuid);
|
||||
mutator.associateWithItem(note);
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
#tags-column.sn-component.section.tags(aria-label='Tags')
|
||||
.component-view-container(ng-if='self.component.active')
|
||||
component-view.component-view(
|
||||
component='self.component',
|
||||
component-uuid='self.component.uuid',
|
||||
application='self.application'
|
||||
)
|
||||
#tags-content.content(ng-if='!(self.component && self.component.active)')
|
||||
|
||||
Reference in New Issue
Block a user