Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Add button to load unsaved edits from localstorage #316

Merged
merged 3 commits into from
Jan 26, 2024
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,9 @@ <h2 mat-dialog-title>{{ dialogTitle }}</h2>
<!-- apparently, this can also be achieved by using [(ngModel)]="postData.content" debounce="300" -->
<tag-editor [tagIn]="tag" (tagsUpdate)="updateTags($event)" [config]="config" [syncAtStart]="false"></tag-editor>
</mat-dialog-content>
<button (click)="loadLastUnsavedEdit()" [disabled]="noUnsavedEditTooltip()" matTooltip="{{ noUnsavedEditTooltip() }}">
Load last unsaved edit
</button>
<mat-dialog-actions align="end">
<button mat-button mat-dialog-close *ngIf="!liveFeedback">Cancel</button>
<button mat-button [mat-dialog-close]="true" (click)="addContent($event)">{{ addButtonLabel }}</button>
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -70,7 +70,7 @@ describe('AddContentComponent', () => {
{ provide: MAT_DIALOG_DATA, useValue: {} },
{ provide: MatDialogRef, useValue: {} },
{ provide: AddContentService, useClass: AddContentServiceMock },
{ provide: AppConfigService, useValue: { getConfig } }
{ provide: AppConfigService, useValue: { getConfig } },
],
declarations: [AddContentComponent]
})
Expand Down Expand Up @@ -118,14 +118,18 @@ describe('AddContentComponent', () => {
expect(component.liveFeedback).toBe(false);
expect(component.addButtonLabel).toBe("Done");
expect(component.sendMessage).toHaveBeenCalledTimes(1);
expect(component.editStorageKey).toEqual('6061d9a13587f37b851694d6LastEdit');
});

it('should get data from editor before sending', () => {
component.setupComponent();
component.editor = jasmine.createSpyObj("component.editor", ["getData"])
const localStorageSpy = spyOn(localStorage, 'removeItem');
component.editStorageKey = '123LastEdit';
component.addContent("");
expect(component.editor.getData).toHaveBeenCalled();
})
expect(localStorageSpy).toHaveBeenCalledOnceWith('123LastEdit');
});

it('should get edit data from editor before sending', () => {
component.setupComponent();
Expand All @@ -135,7 +139,8 @@ describe('AddContentComponent', () => {
component.addContent("");
expect(component.editor.getData).toHaveBeenCalled();
expect(component.notification.snippetType).toEqual('paragraph');
})
expect(component.editStorageKey).toEqual(undefined);
});

it('should prepare quote', () => {
let quoted_snippet = {
Expand Down Expand Up @@ -188,7 +193,7 @@ describe('AddContentComponent', () => {
expect(component.metadataPanelExpanded).toBe(false);
component.toggleMetadataPanel();
expect(component.metadataPanelExpanded).toBe(true);
})
});

it('should update tags', () => {
spyOn(component, 'changeChain')
Expand All @@ -197,13 +202,13 @@ describe('AddContentComponent', () => {
expect(component.contentChanged).toBe(true);
expect(component.tag).toEqual(defaultTags);
expect(component.changeChain).toHaveBeenCalledTimes(1);
})
});

it('should send message', () => {
spyOn(component['dataService'], 'changeMessage');
component.sendMessage();
expect(component['dataService'].changeMessage).toHaveBeenCalledWith(component.notification);
})
});

it('should adjust figure HTML content for ckeditor', () => {
let figureMockNoSize = '<figure class="image"><img src="source" title="d3cc95ad-45d5-48c4-ba0e-db6fcfd252ce"></figure>';
Expand All @@ -223,8 +228,7 @@ describe('AddContentComponent', () => {
component.data = figureMockSizeBefore;
component.adjustContentForEditor();
expect(component.data).toBe(figureMockSizeAfter);

})
});


it('should adjust figure HTML content with links for ckeditor ', () => {
Expand All @@ -239,8 +243,7 @@ describe('AddContentComponent', () => {
component.data = figureMockSizeBefore;
component.adjustContentForEditor();
expect(component.data).toBe(figureMockSizeAfter);

})
});

it('should extract notification with new files', () => {
let figureMock = '<figure class="image image_resized" style="width:79%;"><img src="data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAEjgAAA2oCAIAAACtz6bAAAAACXBIWXMAAHsIAAB7CAF"></figure>"';
Expand All @@ -254,8 +257,7 @@ describe('AddContentComponent', () => {
expect(message.files[0].fileHash).toBeTruthy();
combineHtmlFigureHash(figureMockNoSrc, message.files[0].fileHash)
expect(message.textcontent).toEqual(combineHtmlFigureHash(figureMockNoSrc, message.files[0].fileHash));

})
});

it('should extract notification without files', () => {
let figureMock = '<figure class="image image_resized" style="width:79%;"><img src="data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAEjgAAA2oCAIAAACtz6bAAAAACXBIWXMAAHsIAAB7CAF"></figure>"'
Expand All @@ -268,18 +270,16 @@ describe('AddContentComponent', () => {
expect(message.files[0].fileHash).toBeTruthy();
combineHtmlFigureHash(figureMockNoSrc, message.files[0].fileHash)
expect(message.textcontent).toEqual(combineHtmlFigureHash(figureMockNoSrc, message.files[0].fileHash));

})
});

it('should extract links', () => {
let linkMock = '<p><a class="fileLink" href="file:myHash">myFile.pdf</a></p>'
let linkStorageMock = [{ fileHash: "myHash" }];
let message = extractNotificationMessage(linkMock, linkStorageMock);
expect(message.files[0].fileHash).toEqual("myHash")
})
});

it('should prepare subsnippets container for quotes', () => {

component.notification = notificationMock;
component.prepareSubsnippetsQuoteContainer();
expect(component.notification.subsnippets[0].id).toBeFalsy();
Expand All @@ -291,48 +291,86 @@ describe('AddContentComponent', () => {
expect(component.notification.subsnippets[0].defaultOrder).toBeFalsy();
expect(component.notification.subsnippets[0].subsnippets).toBeFalsy();
expect(component.notification.subsnippets[0].linkType).toBe(LinkType.QUOTE);

})
});

it('should send a message if notification is edit', () => {
spyOn(component, 'sendMessage');
component.notification.snippetType = 'edit';
component.changeChain(notificationMock);
expect(component.sendMessage).toHaveBeenCalledTimes(1);
})
});

it('should not send messages if notification is not edit', () => {
spyOn(component, 'sendMessage');
component.changeChain(notificationMock);
expect(component.sendMessage).toHaveBeenCalledTimes(0);
})
});

it('should mark for deletion and send message', () => {
spyOn(component, 'sendMessage');
component.dialogTitle = 'Modify data snippet';
component['sendEditDelitionMessage']();
expect(component.sendMessage).toHaveBeenCalledTimes(1);
expect(component.notification.toDelete).toEqual(true);
})
});

it('should not mark for deletion and send message', () => {
spyOn(component, 'sendMessage');
component.sendEditDelitionMessage();
expect(component.sendMessage).toHaveBeenCalledTimes(0);
})
});


it('should unset the logbook on unload', () => {
spyOn(component, 'sendEditDelitionMessage');
const unloadEvent = new Event('unload');
window.dispatchEvent(unloadEvent);
expect(component.sendEditDelitionMessage).toHaveBeenCalledTimes(1);
})
});

it('should unset the logbook on destroy', () => {
spyOn(component, 'sendEditDelitionMessage');
component.ngOnDestroy();
expect(component.sendEditDelitionMessage).toHaveBeenCalledTimes(1);
})
});

[
{input: undefined, output: 'No unsaved edit in current session'},
{input: 'sameData', output: 'No unsaved edit in current session'},
{input: 'edit', output: undefined},
].forEach((t, i) => {
it(`should test noUnsavedEditTooltip ${i}`, () => {
component.lastEdit = t.input;
if (t.input === 'sameData') component.data = t.input;
expect(component.noUnsavedEditTooltip()).toEqual(t.output);
});
});

it('should test setLocalStorage', () => {
component.message = {id: 123};
const localStorageSpy = spyOn(localStorage, 'getItem');
component['setLocalStorage']();
expect(localStorageSpy).toHaveBeenCalledOnceWith('123LastEdit');
});

[undefined, 'edit'].forEach((t, i) => {
it(`should test loadLastUnsavedEdit ${i}`, () => {
component.lastEdit = t;
component.editor = jasmine.createSpyObj("component.editor", ["setData"]);
component.loadLastUnsavedEdit();
expect(component.editor.setData).toHaveBeenCalledTimes(t? 1: 0);
if (t)
expect(component.editor.setData).toHaveBeenCalledOnceWith(t);
});
});

it('should test onChange', () => {
component.editStorageKey = '123LastEdit';
const editor = {getData: () => 'edit'};
const localStorageSpy = spyOn(localStorage, 'setItem');
component.onChange({editor: editor});
expect(localStorageSpy).toHaveBeenCalledOnceWith('123LastEdit', 'edit');
});

function combineHtmlFigureHash(figureMock: string[], hash: string) {
return (figureMock[0] + ' title="' + hash + '"' + figureMock[1]);
Expand Down
22 changes: 21 additions & 1 deletion scilog/src/app/logbook/core/add-content/add-content.component.ts
Original file line number Diff line number Diff line change
Expand Up @@ -48,6 +48,8 @@ export class AddContentComponent implements OnInit {
prel_fileStorage: any[] = [];
config: any = [];
editor: any;
editStorageKey: string;
lastEdit: string;

constructor(
private dataService: AddContentService,
Expand Down Expand Up @@ -102,6 +104,7 @@ export class AddContentComponent implements OnInit {

if (this.message.id) {
this.notification = this.message;
this.setLocalStorage();
this.notification.snippetType = 'edit';
this.notification.toDelete = false;
this.liveFeedback = false;
Expand Down Expand Up @@ -130,6 +133,11 @@ export class AddContentComponent implements OnInit {
return;
}

private setLocalStorage() {
this.editStorageKey = `${this.message.id}LastEdit`;
this.lastEdit = localStorage.getItem(this.editStorageKey);
}

onEditorReady(editor: any) {
console.log(Array.from(editor.ui.componentFactory.names()));
editor.ui.getEditableElement().parentElement.insertBefore(
Expand All @@ -154,11 +162,13 @@ export class AddContentComponent implements OnInit {
}
if (this.notification.snippetType === 'edit' && this.contentChanged)
this.notification.snippetType = 'paragraph';
localStorage.removeItem(this.editStorageKey);
this.prepareMessage(this.data);
this.sendMessage();
};

onChange({ editor }: ChangeEvent) {
localStorage.setItem(this.editStorageKey, editor.getData());
// this.editorChange(editor);
this.contentChanged = true;
}
Expand All @@ -168,7 +178,6 @@ export class AddContentComponent implements OnInit {
if (typeof editor != "undefined") {
const data = editor.getData();
this.prel_fileStorage = editor['prel_fileStorage'];
this.contentChanged = false;
this.changeChain(data);
}
}
Expand Down Expand Up @@ -240,6 +249,11 @@ export class AddContentComponent implements OnInit {

}

loadLastUnsavedEdit() {
if (this.lastEdit)
this.editor.setData(this.lastEdit);
}

updateTags(tags: string[]) {
this.tag = tags;
this.contentChanged = true;
Expand All @@ -250,6 +264,11 @@ export class AddContentComponent implements OnInit {
this.metadataPanelExpanded = !this.metadataPanelExpanded;
}

noUnsavedEditTooltip() {
if (!this.lastEdit || this.lastEdit === this.data)
return 'No unsaved edit in current session';
}

ngOnDestroy(): void {
this.sendEditDelitionMessage();
console.log("deleting add-content subscriptions")
Expand All @@ -265,6 +284,7 @@ export class AddContentComponent implements OnInit {
}
}

@HostListener('window:beforeunload')
@HostListener('window:unload')
onUnload() {
this.sendEditDelitionMessage();
Expand Down
Loading