You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
frontend/src/app/components/nodes/norm/norm.component.ts

164 lines
5.6 KiB

import {Component, HostListener, Input, OnDestroy, OnInit, ViewChild} from '@angular/core';
import {EditorNodeContract} from '../EditorNode.contract';
import {EditorService} from '../../../service/editor.service';
import {FlitterSocketConnection, FlitterSocketServerClientTransaction} from '../../../flitter-socket';
import {ApiService} from '../../../service/api.service';
import {debug} from '../../../utility';
import { EditingUserSelect } from '../../wysiwyg/wysiwyg.component';
@Component({
selector: 'editor-norm',
templateUrl: './norm.component.html',
styleUrls: ['./norm.component.scss'],
})
export class NormComponent extends EditorNodeContract implements OnInit, OnDestroy {
@ViewChild('editable') editable;
@Input() nodeId: string;
@Input() editorUUID?: string;
public initialValue = 'Double-click to edit...';
protected savedValue = 'Double-click to edit...';
public contents = '';
private dirtyOverride = false;
private editorGroupSocket?: FlitterSocketConnection;
public editorGroupUsers: Array<{uuid: string, uid: string, display: string, color: string}> = [];
public editorGroupId?: string;
public editingUserSelections: Array<EditingUserSelect> = [];
public requestSelectionRefresh = () => this.refreshRemoteSelections();
constructor(
public editorService: EditorService,
public readonly api: ApiService,
) {
super();
this.contents = this.initialValue;
this.savedValue = this.initialValue;
console.log('Norm editor component', this);
}
public isDark() {
return document.body.classList.contains('dark');
}
public isDirty(): boolean | Promise<boolean> {
return this.dirtyOverride || this.contents !== this.savedValue;
}
public get isReadonly(): boolean {
return !this.editorService.canEdit();
}
public writeChangesToNode(): void | Promise<void> {
this.nodeRec.value = this.contents;
this.savedValue = this.contents;
}
ngOnInit() {
this.editorService = this.editorService.getEditor(this.editorUUID);
this.editorService.registerNodeEditor(this.nodeId, this).then(() => {
if ( !this.node.Value ) {
this.node.Value = {};
}
if ( this.node.Value.Value ) {
this.initialValue = this.node.Value.Value;
this.savedValue = this.node.Value.Value;
}
this.contents = this.initialValue;
});
}
ngOnDestroy() {
debug('ngOnDestroy in Norm editor component');
if ( this.editorGroupSocket && this.editorGroupId ) {
debug('Closing editor socket...');
this.editorGroupSocket.socket.close();
}
}
onContentsChanged(contents: string) {
if ( this.contents !== contents ) {
this.contents = contents;
this.editorService.triggerSave();
}
}
public needsLoad(): boolean | Promise<boolean> {
return true;
}
public async performLoad(): Promise<void> {
// This is called after the Node record has been loaded.
// 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();
}
}
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,
});
}
}
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;
}
}
}
}