Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Create custom clipboardData property for ClipboardEvent

In my Karma-Jasmine tests I have to test my onPaste method.

onPaste method:

onPaste(event: any): void {
  const pastedText = event.clipboardData.getData('text/plain');
  // some stuff
}

My unit test:

it('should do something', () => {
  const queryField = fixture.debugElement.query(By.css('input[type="search"]')).nativeElement;
  queryField.dispatchEvent(new ClipboardEvent('paste', {
    dataType: 'text/plain',
    data: '325435956\r325435956',
  }));
  // some stuff
})

And I use Chrome to run the tests but new ClipboardEvent() in Chrome creates ClipboardEvent object where clipboardData is null and event.clipboardData.getData('text/plain') throws an error:

Uncaught TypeError: Cannot read property 'getData' of null

It doesn't happen in Firefox, so if I use karma-firefox-launcher it works fine, but I have to use Chrome. So, I had some ideas how to solve it.

The first idea was to create ClipboardEvent object and override clipboardData property:

const pasteEvent = new ClipboardEvent('paste', {
  dataType: 'text/plain',
  data: '325435956\r325435956',
});

pasteEvent.clipboardData = {
  getData() {
    return this.data;
  }
};

But I can't do it because clipboardData is a read-only property.

The second idea was to create fake ClipboardEvent object:

function FakePasteEvent(options) {
  this.clipboardData = {
    dataType: options.dataType,
    data: options.data,
    getData() {
      return this.data;
    }
  };
}
const pasteEvent = new FakePasteEvent({
  dataType: 'text/plain',
  data: '325435956\r325435956',
});

console.log(pasteEvent.clipboardData.getData()) // returns what I need

But I can't pass it to dispatchEvent because the type of pasteEvent is not Event. Then I thought I can specify prototype object for my FakePasteEvent:

Object.setPrototypeOf(pasteEvent, ClipboardEvent);

But anyway I've got an error:

TypeError: Failed to execute 'dispatchEvent' on 'EventTarget': parameter 1 is not of type 'Event'

Can you help me to solve this problem? ;)

Code example here http://jsbin.com/puqilivalo/1/edit?html,js,console,output

like image 572
artiebits Avatar asked Dec 11 '17 11:12

artiebits


People also ask

What is window clipboardData?

clipboardData property holds a DataTransfer object, which can be used: to specify what data should be put into the clipboard from the cut and copy event handlers, typically with a setData(format, data) call; to obtain the data to be pasted from the paste event handler, typically with a getData(format) call.

What is ClipboardEvent?

The ClipboardEvent interface represents events providing information related to modification of the clipboard, that is cut , copy , and paste events.

How do you put data in the clipboard?

In Internet Explorer, use the getData method to retrieve and the clearData method to clear the contents of the clipboard. In Firefox, Opera, Google Chrome and Safari, use the execCommand method with the 'Paste' command to retrieve and with the 'Copy' command to set the text content of the clipboard.

Which of the following methods can be used for retrieving the specified formatted data from the clipboard?

Browser support: Retrieves the specified formatted data from the clipboard. In Internet Explorer, use the setData method to set and the clearData method to clear the contents of the clipboard.


1 Answers

Quite interestingly, I am currently struggling on who is right between chrome and Firefox on this, I still can't figure out what the specs tell when they say

dictionary ClipboardEventInit : EventInit {
 DataTransfer? clipboardData = null;
};

and

[Constructor (DOMString type, optional ClipboardEventInit eventInitDict), Exposed=Window]
 interface ClipboardEvent : Event {
 readonly attribute DataTransfer? clipboardData;
};

I would tend to say that Chrome is right when it returns null for the clipboardData property, but then the very next example makes FF behavior correct:

Example 3
var pasteEvent = new ClipboardEvent('paste');
pasteEvent.clipboardData.items.add('My string', 'text/plain'); document.dispatchEvent(pasteEvent);



But anyway, Chrome does support (partially) the DataTransfer contructor, whereas FF still doesn't. And you can then construct your event with this DataTransfer object in chrome too:

var dT = null;
try{ dT = new DataTransfer();} catch(e){}
var evt = new ClipboardEvent('paste', {clipboardData: dT});
console.log('clipboardData available: ', !!evt.clipboardData);
evt.clipboardData.setData('text/plain', 'Hello world');

document.onpaste = function(e){
  console.log('onpaste: ', e.clipboardData.getData('text/plain'));
};
document.dispatchEvent(evt);
like image 169
Kaiido Avatar answered Oct 24 '22 09:10

Kaiido