Copy and Paste Not working

Tags: #<Tag:0x00007efc60a953b8>

I’ve implemented a custom editor using the Handsontable.editors.BaseEditor. I’m able to copy and paste to another cell which is the standard text cell but I can’t seem to copy and paste to the cell of the same custom editor. It seems that the custom editor is not registering the paste into event.

/* eslint-disable no-param-reassign /
/
eslint-disable no-underscore-dangle /
/
eslint-disable class-methods-use-this */
import Handsontable from ‘handsontable’;

import { CONST_COL, CONST_ROW } from ‘…/…/constants/config’;
import { getIndexFromUUID } from ‘…/…/utility/table_functions’;

export default class TableRelationEditor extends Handsontable.editors.BaseEditor {
inputText: any = {};

filter: any = ‘’;

tableRef: any = {};

relationList: any = [];

currRow: any = 0;

currCol: any = 0;

state: any = { filter: ‘’ };

constructor(hotInstance, row, col, prop, TD, cellProperties) {
super(hotInstance, row, col, prop, TD, cellProperties);

this.tableRef = hotInstance.rootElement;

}

init() {
// super.init()
}

// When user selects a cell that use this editor
prepare(row, col, prop, td, originalValue, cellProperties) {
super.prepare(row, col, prop, td, originalValue, cellProperties);
this.inputText = originalValue;
this.currRow = row;
this.currCol = col;
this.relationList = cellProperties.relationList;
}

// When editor should be displayed
open() {
// Create Modal
const modal = document.createElement(‘div’);
modal.setAttribute(‘class’, ‘cell-modal z-20-imp’);
modal.innerHTML = ‘’;

// Modal Content
const modalContent = document.createElement('div');
modalContent.setAttribute('class', 'cell-modal-content rounded-2xl');

// Choose options container
const filterHeader = document.createElement('div');
const header = document.createElement('h4');
header.innerHTML = this.relationList[0].name || '';

const inputFilter = document.createElement('input');
inputFilter.type = 'text';
inputFilter.setAttribute('id', 'search-filter');
inputFilter.setAttribute('class', 'my-4 p-1 w-3/12 shadow-sm focus:ring-indigo-500 border focus:border-indigo-500 block sm:text-sm border border-gray-300 rounded-md');
inputFilter.setAttribute('placeholder', 'Search...');

filterHeader.appendChild(header);
filterHeader.appendChild(inputFilter);

const chooseFieldDom = document.createElement('div');
let optionsDom1 = '';
if (this.relationList.length > 0) {
  optionsDom1 = '<div class="grid grid-cols-3 gap-2 search-list">';
  const rows = this.relationList[0].firstCols;
  const options = rows.map((row) => `<div class="col-span-1 cell-link"><input class="mr-2" type="checkbox" data-ident=${row.ident} id=${row.ident} ${this.inputText.includes(row.ident) ? 'checked' : ''} /><label for=${row.ident}>${row.value ? row.value : 'NULL'}</label></div>`);
  optionsDom1 += `${options.join('')}</div>`;
}

chooseFieldDom.innerHTML = optionsDom1;

// Submit Button
const btnSubmit = document.createElement('button');
btnSubmit.setAttribute('class', 'ml-2 btn btn-primary px-3 py-1');
btnSubmit.innerHTML = 'Submit';

// Clear Button
const btnClear = document.createElement('button');
btnClear.setAttribute('class', 'btn btn-white px-3 py-1');
btnClear.innerHTML = 'Cancel';

const modalActions = document.createElement('div');
modalActions.setAttribute('class', 'mt-4 flex justify-end');
modalActions.appendChild(btnClear);
modalActions.appendChild(btnSubmit);

// Append
modalContent.appendChild(filterHeader);
modalContent.appendChild(chooseFieldDom);
modalContent.appendChild(modalActions);
modal.appendChild(modalContent);
modal.style.display = 'block';

btnSubmit.onclick = () => {
  const inputs = [].filter.call(chooseFieldDom.getElementsByTagName('input'), (el) => el.checked).map((el) => el.dataset.ident);
  this.inputText = inputs.length > 0 ? inputs : '';
  this.hot.setDataAtCell(this.currRow, this.currCol, this.inputText);
  modal.style.display = 'none';
};
btnClear.onclick = () => {
  modal.style.display = 'none';
};

modal.onclick = (e) => { if (e.target === modal) { modal.style.display = 'none'; } };
this.tableRef.appendChild(modal);

const items = modal.querySelector('.search-list').getElementsByClassName('cell-link');
inputFilter.addEventListener('keyup', (el) => {
  const textInput = el.target as HTMLInputElement;
  const text = textInput.value;
  const pat = new RegExp(text, 'i');
  Array.from(items).forEach((item) => {
    const checkbox = item as HTMLInputElement;
    const { innerText } = checkbox;

    if (pat.test(innerText)) {
      checkbox.classList.remove('hidden');
    } else {
      checkbox.classList.add('hidden');
    }
  });
});

}

focus() {
}

close() {
}

getValue() {
return this.inputText;
}

setValue(value) {
this.inputText = value;
}
}

export function RelationRenderer(instance, td, row, col, prop, value, cellProperties) {
const documentFragment = document.createDocumentFragment();

const current = cellProperties.relationList[0];
if (value && !Array.isArray(value)) value = value.split(’,’);
if (Array.isArray(value)) {
value.forEach((link) => {
const block = document.createElement(‘div’);
block.setAttribute(‘class’, ‘rel-block’);
block.setAttribute(‘data-content’, link);
// const content = document.createElement(‘span’);
// content.setAttribute(‘class’, ‘dropdown-item’);
const hover = document.createElement(‘div’);
let hoverClass = 'rel-dropdown-content ';
const relCoord = cellProperties.openRelationCoord;
if (cellProperties.openRelation === link && relCoord.row === row && relCoord.col === col) {
hoverClass += ‘block’;
} else {
hoverClass += ‘hidden’;
}
hover.setAttribute(‘class’, hoverClass);

  if (!current) return;
  const linkRow = current.firstCols.filter((r) => r && Object.prototype.hasOwnProperty.call(r, 'ident') && r.ident === link)[0];

  if (!linkRow) return;
  block.innerHTML = linkRow.value || 'NULL';

  const thValues = current.headers.map((header) => `<td class="visible-show cbg-gray-200 w-32">${header.name}</td>`);

  const tdValues = current.headers.map((header) => {
    const rowId = getIndexFromUUID(CONST_ROW, linkRow.ident.split('-')[1], current.rows);
    const colId = getIndexFromUUID(CONST_COL, header._id, current.headers);
    const cellVal = current.data[rowId][colId];
    let val = '';
    if (cellVal) {
      if (Object.prototype.hasOwnProperty.call(cellVal, 'relation') && cellVal.relation.length > 0) {
        val = '';
      } else {
        val = cellVal;
      }
    }
    return `<td class="w-32">${val}</td>`;
  });

  const tableHeaders = thValues ? thValues.join('') : '';
  const tableBody = tdValues ? tdValues.join('') : '';

  const hoverContent = document.createElement('div');
  hoverContent.setAttribute('class', 'w-full overflow-x-scroll');
  hoverContent.innerHTML = `<table class="block overflow-x-auto table-fixed"><caption class="text-left mb-2 whitespace-nowrap"><b>${current.name}</b></caption><thead><tr>${tableHeaders}</tr></thead><tbody>${tableBody}</tbody></table>`;

  hover.appendChild(hoverContent);
  block.appendChild(hover);

  Handsontable.dom.empty(td);
  if (value) {
    documentFragment.appendChild(block);
  }
});

td.appendChild(documentFragment);
if (value.length === 0) {
  td.innerHTML = '';
}

} else {
td.innerHTML = ‘’;
}
}

Hi @andrew3

we provide code reviews of custom implementations based on the scope of the support plan. Please send us your license ID (or license holder email) at support@handsontable.com