Add auto-save support and saving indicator
This commit is contained in:
parent
9a53faf338
commit
9f80842b9f
@ -199,12 +199,15 @@ export class CodeComponent extends EditorNodeContract implements OnInit {
|
|||||||
public onEditorModelChange($event) {
|
public onEditorModelChange($event) {
|
||||||
if ( this.editorValue !== this.dbRecord.code ) {
|
if ( this.editorValue !== this.dbRecord.code ) {
|
||||||
this.dirty = true;
|
this.dirty = true;
|
||||||
|
this.editorService.triggerSave();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
public onSelectChange(updateDbRecord = true) {
|
public onSelectChange(updateDbRecord = true) {
|
||||||
if ( updateDbRecord ) {
|
if ( updateDbRecord ) {
|
||||||
this.dbRecord.Language = this.editorOptions.language;
|
this.dbRecord.Language = this.editorOptions.language;
|
||||||
|
this.editorService.triggerSave();
|
||||||
|
this.dirty = true;
|
||||||
}
|
}
|
||||||
|
|
||||||
this.editorOptions = {...this.editorOptions};
|
this.editorOptions = {...this.editorOptions};
|
||||||
|
@ -71,6 +71,7 @@ export class DatabaseComponent extends EditorNodeContract implements OnInit {
|
|||||||
|
|
||||||
onCellValueChanged() {
|
onCellValueChanged() {
|
||||||
this.dirty = true;
|
this.dirty = true;
|
||||||
|
this.editorService.triggerSave();
|
||||||
}
|
}
|
||||||
|
|
||||||
async onManageColumns() {
|
async onManageColumns() {
|
||||||
@ -98,6 +99,7 @@ export class DatabaseComponent extends EditorNodeContract implements OnInit {
|
|||||||
this.rowData.push({});
|
this.rowData.push({});
|
||||||
this.agGridElement.api.setRowData(this.rowData);
|
this.agGridElement.api.setRowData(this.rowData);
|
||||||
this.dirty = true;
|
this.dirty = true;
|
||||||
|
this.editorService.triggerSave();
|
||||||
}
|
}
|
||||||
|
|
||||||
async onRemoveRow() {
|
async onRemoveRow() {
|
||||||
@ -122,6 +124,7 @@ export class DatabaseComponent extends EditorNodeContract implements OnInit {
|
|||||||
this.agGridElement.api.setRowData(this.rowData);
|
this.agGridElement.api.setRowData(this.rowData);
|
||||||
this.lastClickRow = -1;
|
this.lastClickRow = -1;
|
||||||
this.dirty = true;
|
this.dirty = true;
|
||||||
|
this.editorService.triggerSave();
|
||||||
},
|
},
|
||||||
}
|
}
|
||||||
],
|
],
|
||||||
@ -168,6 +171,7 @@ export class DatabaseComponent extends EditorNodeContract implements OnInit {
|
|||||||
|
|
||||||
this.agGridElement.api.setColumnDefs(this.columnDefs);
|
this.agGridElement.api.setColumnDefs(this.columnDefs);
|
||||||
this.dirty = true;
|
this.dirty = true;
|
||||||
|
this.editorService.triggerSave();
|
||||||
}
|
}
|
||||||
|
|
||||||
public async performLoad(): Promise<void> {
|
public async performLoad(): Promise<void> {
|
||||||
|
@ -62,6 +62,7 @@ export class NormComponent extends EditorNodeContract implements OnInit {
|
|||||||
const innerHTML = this.editable.nativeElement.innerHTML;
|
const innerHTML = this.editable.nativeElement.innerHTML;
|
||||||
if ( this.contents !== innerHTML ) {
|
if ( this.contents !== innerHTML ) {
|
||||||
this.contents = innerHTML;
|
this.contents = innerHTML;
|
||||||
|
this.editorService.triggerSave();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -11,6 +11,12 @@
|
|||||||
class="title-input"
|
class="title-input"
|
||||||
></ion-input>
|
></ion-input>
|
||||||
</ion-title>
|
</ion-title>
|
||||||
|
<ion-buttons slot="end">
|
||||||
|
<button class="save-button" (click)="editorService.triggerSave()" title="Manually save this note">
|
||||||
|
<i *ngIf="!(editorService.isSaving || editorService.willSave)" class="fa fa-check-circle"></i>
|
||||||
|
{{ (editorService.isSaving || editorService.willSave) ? 'Saving...' : 'Saved!' }}
|
||||||
|
</button>
|
||||||
|
</ion-buttons>
|
||||||
</ion-toolbar>
|
</ion-toolbar>
|
||||||
</ion-header>
|
</ion-header>
|
||||||
|
|
||||||
|
@ -48,3 +48,11 @@ ion-icon.invisible {
|
|||||||
color: #4d4d4d;
|
color: #4d4d4d;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
.save-button {
|
||||||
|
color: #777;
|
||||||
|
|
||||||
|
i {
|
||||||
|
margin-right: 5px;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
@ -11,6 +11,17 @@ export class NoPageLoadedError extends Error {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
export function debounce(func: (...args: any[]) => any, timeout?: number) {
|
||||||
|
let timer: number | undefined;
|
||||||
|
return (...args: any[]) => {
|
||||||
|
const next = () => func(...args);
|
||||||
|
if (timer) {
|
||||||
|
clearTimeout(timer);
|
||||||
|
}
|
||||||
|
timer = setTimeout(next, timeout > 0 ? timeout : 300);
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
@Injectable({
|
@Injectable({
|
||||||
providedIn: 'root'
|
providedIn: 'root'
|
||||||
})
|
})
|
||||||
@ -21,6 +32,30 @@ export class EditorService {
|
|||||||
protected dirtyOverride = false;
|
protected dirtyOverride = false;
|
||||||
protected ready$: BehaviorSubject<boolean> = new BehaviorSubject<boolean>(false);
|
protected ready$: BehaviorSubject<boolean> = new BehaviorSubject<boolean>(false);
|
||||||
protected subs: Subscription[] = [];
|
protected subs: Subscription[] = [];
|
||||||
|
protected saving = false;
|
||||||
|
protected saveTriggered = false;
|
||||||
|
protected privTriggerSave = debounce(() => {
|
||||||
|
if ( this.saving ) {
|
||||||
|
this.triggerSave();
|
||||||
|
} else {
|
||||||
|
this.save();
|
||||||
|
}
|
||||||
|
|
||||||
|
this.saveTriggered = false;
|
||||||
|
}, 3000);
|
||||||
|
|
||||||
|
public triggerSave() {
|
||||||
|
this.saveTriggered = true;
|
||||||
|
this.privTriggerSave();
|
||||||
|
}
|
||||||
|
|
||||||
|
public get isSaving() {
|
||||||
|
return this.saving;
|
||||||
|
}
|
||||||
|
|
||||||
|
public get willSave() {
|
||||||
|
return this.saveTriggered;
|
||||||
|
}
|
||||||
|
|
||||||
public get immutableNodes(): HostRecord[] {
|
public get immutableNodes(): HostRecord[] {
|
||||||
return [...this.currentNodes];
|
return [...this.currentNodes];
|
||||||
@ -46,9 +81,7 @@ export class EditorService {
|
|||||||
|
|
||||||
constructor(
|
constructor(
|
||||||
protected api: ApiService,
|
protected api: ApiService,
|
||||||
) {
|
) { }
|
||||||
console.log('editor service', this);
|
|
||||||
}
|
|
||||||
|
|
||||||
async startEditing(pageId: string) {
|
async startEditing(pageId: string) {
|
||||||
if ( this.currentPage ) {
|
if ( this.currentPage ) {
|
||||||
@ -58,8 +91,6 @@ export class EditorService {
|
|||||||
this.currentPage = await this.loadPage(pageId);
|
this.currentPage = await this.loadPage(pageId);
|
||||||
this.currentNodes = await this.loadNodes(pageId);
|
this.currentNodes = await this.loadNodes(pageId);
|
||||||
await this.ready$.next(true);
|
await this.ready$.next(true);
|
||||||
console.log('editing', this.currentPage);
|
|
||||||
console.log('nodes', this.currentNodes);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
async stopEditing() {
|
async stopEditing() {
|
||||||
@ -72,10 +103,11 @@ export class EditorService {
|
|||||||
}
|
}
|
||||||
|
|
||||||
async save() {
|
async save() {
|
||||||
if ( !(await this.needsSave()) ) {
|
if ( !(await this.needsSave()) || this.saving ) {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
this.saving = true;
|
||||||
const editors = Object.values(this.nodeIdToEditorContract);
|
const editors = Object.values(this.nodeIdToEditorContract);
|
||||||
|
|
||||||
// Save all editors that handle their data independently first
|
// Save all editors that handle their data independently first
|
||||||
@ -92,6 +124,7 @@ export class EditorService {
|
|||||||
|
|
||||||
await this.saveNodesAsPage(this.currentPage, this.currentNodes);
|
await this.saveNodesAsPage(this.currentPage, this.currentNodes);
|
||||||
this.dirtyOverride = false;
|
this.dirtyOverride = false;
|
||||||
|
this.saving = false;
|
||||||
}
|
}
|
||||||
|
|
||||||
async moveNode(node: HostRecord, direction: 'up' | 'down') {
|
async moveNode(node: HostRecord, direction: 'up' | 'down') {
|
||||||
@ -117,6 +150,7 @@ export class EditorService {
|
|||||||
}
|
}
|
||||||
|
|
||||||
this.dirtyOverride = true;
|
this.dirtyOverride = true;
|
||||||
|
this.triggerSave();
|
||||||
}
|
}
|
||||||
|
|
||||||
async saveNodesAsPage(page: PageRecord, nodes: HostRecord[]): Promise<HostRecord[]> {
|
async saveNodesAsPage(page: PageRecord, nodes: HostRecord[]): Promise<HostRecord[]> {
|
||||||
@ -184,6 +218,7 @@ export class EditorService {
|
|||||||
|
|
||||||
this.currentNodes = this.currentNodes.filter(x => x.UUID !== nodeId);
|
this.currentNodes = this.currentNodes.filter(x => x.UUID !== nodeId);
|
||||||
this.dirtyOverride = true;
|
this.dirtyOverride = true;
|
||||||
|
this.triggerSave();
|
||||||
}
|
}
|
||||||
|
|
||||||
async addNode(type: 'paragraph' | 'code_ref' | 'database_ref' | 'file_ref', position?: 'before' | 'after', positionNodeId?: string) {
|
async addNode(type: 'paragraph' | 'code_ref' | 'database_ref' | 'file_ref', position?: 'before' | 'after', positionNodeId?: string) {
|
||||||
@ -217,6 +252,7 @@ export class EditorService {
|
|||||||
}
|
}
|
||||||
|
|
||||||
this.dirtyOverride = true;
|
this.dirtyOverride = true;
|
||||||
|
this.triggerSave();
|
||||||
return host;
|
return host;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
Loading…
Reference in New Issue
Block a user