soccerloway / quill-better-table

Module for better table in Quill, more useful features are supported.
MIT License
307 stars 113 forks source link

Is there any way to display operationMenu buttons in quill's toolbar instead of the right click pop up ? #103

Open Denis-Dev-2020 opened 3 weeks ago

Denis-Dev-2020 commented 3 weeks ago

this is my best failed try :

import { Component, ViewChild, Output, EventEmitter, AfterViewInit, Inject, PLATFORM_ID, ElementRef } from '@angular/core';
import { FormControl, FormGroup, Validators, ReactiveFormsModule, NgForm, FormsModule } from '@angular/forms';
import { CommonModule, isPlatformBrowser } from '@angular/common';
import { combineLatest } from 'rxjs';
import { first } from 'rxjs/operators';
import Quill from 'quill';
import QuillBetterTable from 'quill-better-table'
import { Post } from '../../models/Post';
import { AuthService } from "../../services/auth.service";
import { PostService } from "../../services/post.service";
import { DatamediatorpostsService } from '../../services/datamediator/datamediatorposts.service';
import DOMPurify from 'dompurify';

@Component({
  selector: 'app-createpost',
  standalone: true,
  imports: [CommonModule, ReactiveFormsModule, FormsModule],
  templateUrl: './createpost.component.html',
  styleUrls: ['./createpost.component.css']
})
export class CreatepostComponent implements AfterViewInit {
  @ViewChild("editor", { static: false }) editorElementRef!: ElementRef;
  @Output() create: EventEmitter<any> = new EventEmitter();
  selectedTopic!: number;
  selectedSubtopic!: number;

  form: FormGroup;
  quillEditor: any;

  constructor(
    @Inject(PLATFORM_ID) private platformId: object,
    private authService: AuthService,
    private postService: PostService,
    private datamediatorpostsService: DatamediatorpostsService
  ) {
    this.form = this.createFormGroup();

    this.datamediatorpostsService.getSelectedTopic$().subscribe(topic => {
      if (topic != null) {
        this.selectedTopic = topic;
      }
    });

    this.datamediatorpostsService.getSelectedSubTopic$().subscribe(subtopic => {
      if (subtopic != null) {
        this.selectedSubtopic = subtopic;
      }
    });
  }

  ngAfterViewInit(): void {
    if (isPlatformBrowser(this.platformId) && this.editorElementRef) {
      this.initializeQuillEditor();
    }
  }

async initializeQuillEditor(): Promise<void> {
  const { default: Quill } = await import('quill');
  const { default: QuillBetterTable } = await import('quill-better-table');

  Quill.register('modules/better-table', QuillBetterTable, true);

  this.quillEditor = new Quill(this.editorElementRef.nativeElement, {
    theme: 'snow',
    modules: {
      table: false,
      'better-table': {
        operationMenu: {
          items: {
            insertColumnRight: false,
            insertColumnLeft: {
              text: 'Insert Column',
            },
            insertRowUp: {
              text: 'Insert Row Up',
            },
            insertRowDown: {
              text: 'Insert Row Down',
            },
            mergeCells: false,
            unmergeCells: false,
            deleteColumn: {
              text: 'Delete Selected Column',
            },
            deleteRow: {
              text: 'Delete Selected Row',
            },
            deleteTable: {
              text: 'Delete Table',
            }
          }
        }
      },
      toolbar: {
        container: [
          ['bold', 'italic', 'underline', 'strike'],
          ['blockquote', 'code-block'],
          [{ 'header': 1 }, { 'header': 2 }],
          [{ 'list': 'ordered' }, { 'list': 'bullet' }],
          [{ 'script': 'sub' }, { 'script': 'super' }],
          [{ 'indent': '-1' }, { 'indent': '+1' }],
          [{ 'direction': 'rtl' }],
          [{ 'size': ['small', false, 'large', 'huge'] }],
          [{ 'header': [1, 2, 3, 4, 5, 6, false] }],
          [{ 'color': [] }, { 'background': [] }],
          [{ 'font': [] }],
          [{ 'align': [] }],
          ['clean'],
          [{ 'better-table': true }],
          ['insertColumnLeft', 'insertRowUp', 'deleteTable']
        ],
        handlers: {
          'better-table': () => {
            const tableModule: any = this.quillEditor.getModule('better-table');
            if (tableModule && tableModule.options) {
              tableModule.options.show();
            } else {
              console.error('Better Table Module or operationMenu is not defined');
            }
          },
          'insertColumnLeft': () => {
            const tableModule: any = this.quillEditor.getModule('better-table');
            if (tableModule && tableModule.options) {
              tableModule.options.insertColumnLeft();
            } else {
              console.error('Better Table Module or operationMenu is not defined');
            }
          },
          'insertRowUp': () => {
            const tableModule: any = this.quillEditor.getModule('better-table');
            if (tableModule && tableModule.options) {
              tableModule.options.insertRowUp();
            } else {
              console.error('Better Table Module or operationMenu is not defined');
            }
          },
          'deleteTable': () => {
            const tableModule: any = this.quillEditor.getModule('better-table');
            if (tableModule && tableModule.options) {
              tableModule.operationMenu.deleteTable();
            } else {
              console.error('Better Table Module or operationMenu is not defined');
            }
          }
        }
      }
    }
  });

  console.log('Quill editor initialized with full better-table configuration:', this.quillEditor);

  this.quillEditor.on('text-change', () => {
    const formBodyControl = this.form.get('body');
    if (formBodyControl) {
      formBodyControl.setValue(this.quillEditor.root.innerHTML);
    } else {
      console.error('Form control "body" is not defined');
    }
  });

  this.editorElementRef.nativeElement.addEventListener('contextmenu', (event: MouseEvent) => {
    event.preventDefault();
    const tableModule: any = this.quillEditor.getModule('better-table');
    if (tableModule && tableModule.operationMenu) {
      tableModule.operationMenu.show(event.clientX, event.clientY);
    } else {
      console.error('Better Table Module or operationMenu is not defined');
    }
  });
}

  onInsertTable() {
    const tableModule = this.quillEditor.getModule('better-table');
    if (tableModule) {
      tableModule.insertTable(5, 5);
    } else {
      console.error('Better Table Module is not defined');
    }
  }

  createFormGroup(): FormGroup {
    const formGroup = new FormGroup({
      title: new FormControl('', [
        Validators.required,
        Validators.minLength(5)
      ]),
      body: new FormControl('', [
        Validators.required,
        Validators.minLength(10)
      ])
    });
    return formGroup;
  }

  onSubmit(formData: Pick<Post, "title" | "body">): void {
    const userId = this.authService.userId;
    if (userId) {
      formData.body = DOMPurify.sanitize(formData.body);
      this.postService.createPost(this.selectedTopic, this.selectedSubtopic, formData, userId).subscribe(() => {
        this.create.emit(null);
        this.form.reset();
      });
    } else {
      console.error('Authorization error');
    }
  }
}

it seems the i cannot access (or don't know how to access) operationMenu functionality so i could handle the methods in my handler