2021-01-02 21:11:42 +00:00
|
|
|
import {Component, HostListener, Input, OnDestroy, OnInit, ViewChild} from '@angular/core';
|
2020-10-13 16:57:56 +00:00
|
|
|
import {EditorNodeContract} from '../EditorNode.contract';
|
2020-10-14 03:28:38 +00:00
|
|
|
import {EditorService} from '../../../service/editor.service';
|
2021-01-02 21:11:42 +00:00
|
|
|
import {FlitterSocketConnection, FlitterSocketServerClientTransaction} from '../../../flitter-socket';
|
|
|
|
import {ApiService} from '../../../service/api.service';
|
|
|
|
import {debug} from '../../../utility';
|
2021-01-31 16:26:07 +00:00
|
|
|
import {EditingUserSelect, MutationBroadcast, WysiwygComponent} from '../../wysiwyg/wysiwyg.component';
|
2020-10-13 16:57:56 +00:00
|
|
|
|
|
|
|
@Component({
|
|
|
|
selector: 'editor-norm',
|
|
|
|
templateUrl: './norm.component.html',
|
|
|
|
styleUrls: ['./norm.component.scss'],
|
|
|
|
})
|
2021-01-02 21:11:42 +00:00
|
|
|
export class NormComponent extends EditorNodeContract implements OnInit, OnDestroy {
|
2020-10-14 01:19:38 +00:00
|
|
|
@ViewChild('editable') editable;
|
2021-01-31 16:26:07 +00:00
|
|
|
@ViewChild('wysiwygComponent') wysiwygComponent: WysiwygComponent;
|
2020-10-14 03:28:38 +00:00
|
|
|
@Input() nodeId: string;
|
2020-11-03 03:59:58 +00:00
|
|
|
@Input() editorUUID?: string;
|
2020-10-14 03:28:38 +00:00
|
|
|
|
2021-01-03 21:16:05 +00:00
|
|
|
public initialValue = 'Double-click to edit...';
|
|
|
|
protected savedValue = 'Double-click to edit...';
|
2020-10-14 01:19:38 +00:00
|
|
|
public contents = '';
|
|
|
|
private dirtyOverride = false;
|
2021-01-02 21:11:42 +00:00
|
|
|
private editorGroupSocket?: FlitterSocketConnection;
|
|
|
|
|
|
|
|
public editorGroupUsers: Array<{uuid: string, uid: string, display: string, color: string}> = [];
|
|
|
|
public editorGroupId?: string;
|
2021-01-03 21:16:05 +00:00
|
|
|
public editingUserSelections: Array<EditingUserSelect> = [];
|
2021-01-02 21:11:42 +00:00
|
|
|
|
|
|
|
public requestSelectionRefresh = () => this.refreshRemoteSelections();
|
2020-11-09 18:03:53 +00:00
|
|
|
|
2020-10-14 03:28:38 +00:00
|
|
|
constructor(
|
2020-11-03 03:59:58 +00:00
|
|
|
public editorService: EditorService,
|
2021-01-02 21:11:42 +00:00
|
|
|
public readonly api: ApiService,
|
2020-10-14 03:28:38 +00:00
|
|
|
) {
|
2020-10-14 01:19:38 +00:00
|
|
|
super();
|
|
|
|
this.contents = this.initialValue;
|
2020-10-15 14:31:54 +00:00
|
|
|
this.savedValue = this.initialValue;
|
2021-01-02 21:11:42 +00:00
|
|
|
|
|
|
|
console.log('Norm editor component', this);
|
2020-10-14 01:19:38 +00:00
|
|
|
}
|
2020-10-13 16:57:56 +00:00
|
|
|
|
2020-11-09 17:44:01 +00:00
|
|
|
public isDark() {
|
|
|
|
return document.body.classList.contains('dark');
|
|
|
|
}
|
|
|
|
|
2020-10-13 16:57:56 +00:00
|
|
|
public isDirty(): boolean | Promise<boolean> {
|
2020-10-15 14:31:54 +00:00
|
|
|
return this.dirtyOverride || this.contents !== this.savedValue;
|
2020-10-13 16:57:56 +00:00
|
|
|
}
|
|
|
|
|
2020-11-10 14:20:22 +00:00
|
|
|
public get isReadonly(): boolean {
|
|
|
|
return !this.editorService.canEdit();
|
|
|
|
}
|
|
|
|
|
2020-10-14 03:28:38 +00:00
|
|
|
public writeChangesToNode(): void | Promise<void> {
|
|
|
|
this.nodeRec.value = this.contents;
|
2020-10-15 14:31:54 +00:00
|
|
|
this.savedValue = this.contents;
|
2020-10-14 03:28:38 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
ngOnInit() {
|
2020-11-03 03:59:58 +00:00
|
|
|
this.editorService = this.editorService.getEditor(this.editorUUID);
|
2020-10-14 03:28:38 +00:00
|
|
|
this.editorService.registerNodeEditor(this.nodeId, this).then(() => {
|
2020-10-14 14:23:25 +00:00
|
|
|
if ( !this.node.Value ) {
|
|
|
|
this.node.Value = {};
|
|
|
|
}
|
|
|
|
|
|
|
|
if ( this.node.Value.Value ) {
|
|
|
|
this.initialValue = this.node.Value.Value;
|
2020-10-15 14:31:54 +00:00
|
|
|
this.savedValue = this.node.Value.Value;
|
2020-10-14 14:23:25 +00:00
|
|
|
}
|
2020-10-15 14:31:54 +00:00
|
|
|
|
2020-10-14 03:28:38 +00:00
|
|
|
this.contents = this.initialValue;
|
|
|
|
});
|
|
|
|
}
|
|
|
|
|
2021-01-02 21:11:42 +00:00
|
|
|
ngOnDestroy() {
|
|
|
|
debug('ngOnDestroy in Norm editor component');
|
|
|
|
if ( this.editorGroupSocket && this.editorGroupId ) {
|
|
|
|
debug('Closing editor socket...');
|
|
|
|
this.editorGroupSocket.socket.close();
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2020-10-14 01:19:38 +00:00
|
|
|
onContentsChanged(contents: string) {
|
2020-11-10 14:20:22 +00:00
|
|
|
if ( this.contents !== contents ) {
|
|
|
|
this.contents = contents;
|
2020-10-14 16:25:26 +00:00
|
|
|
this.editorService.triggerSave();
|
2020-10-14 01:19:38 +00:00
|
|
|
}
|
|
|
|
}
|
2021-01-02 21:11:42 +00:00
|
|
|
|
|
|
|
public needsLoad(): boolean | Promise<boolean> {
|
|
|
|
return true;
|
|
|
|
}
|
|
|
|
|
|
|
|
public async performLoad(): Promise<void> {
|
|
|
|
// This is called after the Node record has been loaded.
|
2021-01-31 16:26:07 +00:00
|
|
|
return;
|
2021-01-02 21:11:42 +00:00
|
|
|
|
|
|
|
// FIXME need to find a consistent way of doing this on prod/development
|
|
|
|
// FIXME Probably make use of the systemBase, but allow overriding it in the environment
|
|
|
|
// const url = this.api._build_url('socket/norm-editor');
|
|
|
|
const url = 'ws://localhost:8000/api/v1/socket/norm-editor';
|
|
|
|
debug(`Norm editor socket URL: ${url}`);
|
|
|
|
|
|
|
|
const socket = new FlitterSocketConnection(url);
|
|
|
|
socket.controller(this);
|
|
|
|
|
|
|
|
await socket.on_open();
|
|
|
|
debug('Connected to norm editor socket', socket);
|
|
|
|
|
|
|
|
const [transaction2, socket2, { editor_group_id }] = await socket.asyncRequest('join_editor_group', {
|
|
|
|
NodeId: this.node.UUID,
|
|
|
|
PageId: this.page.UUID,
|
|
|
|
});
|
|
|
|
|
|
|
|
this.editorGroupSocket = socket;
|
|
|
|
|
|
|
|
const [transaction3, socket3, users = []] = await socket.asyncRequest('get_editor_group_users', { editor_group_id });
|
|
|
|
if ( Array.isArray(users) ) {
|
|
|
|
this.editorGroupUsers = users;
|
|
|
|
}
|
|
|
|
|
|
|
|
this.editorGroupId = editor_group_id;
|
|
|
|
await this.refreshRemoteSelections();
|
|
|
|
}
|
|
|
|
|
|
|
|
setEditorGroupUsers(transaction: FlitterSocketServerClientTransaction, socket: any) {
|
|
|
|
if ( Array.isArray(transaction?.incoming?.users) ) {
|
|
|
|
this.editorGroupUsers = transaction.incoming.users;
|
|
|
|
debug('Refreshed norm editor group users.');
|
|
|
|
transaction.resolve();
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
setEditorGroupSelections(transaction: FlitterSocketServerClientTransaction, socket: any) {
|
|
|
|
if ( Array.isArray(transaction?.incoming?.selections) ) {
|
|
|
|
debug('Got selections', transaction.incoming.selections);
|
|
|
|
this.editingUserSelections = transaction.incoming.selections;
|
|
|
|
transaction.resolve();
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2021-01-31 16:26:07 +00:00
|
|
|
applyRemoteContentMutation(transaction: FlitterSocketServerClientTransaction, socket: any) {
|
|
|
|
if ( this.wysiwygComponent && transaction?.incoming?.mutation ) {
|
|
|
|
this.wysiwygComponent.applyRemoteContentMutation(transaction.incoming.mutation);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2021-01-02 21:11:42 +00:00
|
|
|
async onSelectionChanged(selection: { path: string, offset: number }) {
|
|
|
|
if ( this.editorGroupSocket && this.editorGroupId ) {
|
|
|
|
await this.editorGroupSocket.asyncRequest('set_member_selection', {
|
|
|
|
editor_group_id: this.editorGroupId,
|
|
|
|
selection,
|
|
|
|
});
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2021-01-31 16:26:07 +00:00
|
|
|
async onContentsMutated(data: MutationBroadcast) {
|
|
|
|
if ( this.editorGroupSocket && this.editorGroupId ) {
|
|
|
|
await this.editorGroupSocket.asyncRequest('broadcast_content_mutation', {
|
|
|
|
editor_group_id: this.editorGroupId,
|
|
|
|
data,
|
|
|
|
});
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2021-01-02 21:11:42 +00:00
|
|
|
async refreshRemoteSelections() {
|
|
|
|
if ( this.editorGroupSocket && this.editorGroupId ) {
|
|
|
|
const [
|
|
|
|
transaction, _, data
|
|
|
|
] = await this.editorGroupSocket.asyncRequest('get_selections', {
|
|
|
|
editor_group_id: this.editorGroupId,
|
|
|
|
});
|
|
|
|
|
|
|
|
if ( Array.isArray(data?.selections) ) {
|
|
|
|
this.editingUserSelections = data.selections;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
2020-10-13 16:57:56 +00:00
|
|
|
}
|