Component management improvements, removal of dependence on noteReady flag

This commit is contained in:
Mo Bitar
2020-04-15 10:26:55 -05:00
parent a2303aa7af
commit 0d44a2ff64
17 changed files with 1618 additions and 1119 deletions

View File

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

View File

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

View File

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