The State of Copy-Pasting in JavaScript

Written by knyzorg | Published 2022/01/20
Tech Story Tags: programming | javascript | software-development | copy-pasting-in-javascript | javascript-development | javascript-tutorial | javascript-fundamentals | learn-javascript

TLDRClipboards across different operating systems work essentially the same. Clipboards hold all the ways target software can represent the data. Microsoft Word displays rich content exactly as Firefox does. Firefox provides multiple representations of the rendered content to the clipboard. We can look inside some of the clipboard types using Powershell, mainly `HTML Format` and `Text with the following commands: Get Text[System.Windows.Forms]::GetText[SystemWindows]::Text]::WriteLine($fmt)via the TL;DR App

I recently did some work on a VS Code extension whose purpose is to handle rich pastes. It prompted me to survey different copy-pasting libraries and the state of the NPM ecosystem as a whole.

How do Clipboards Work?

Clipboards across different operating systems work essentially the same. For this reason, we will stick to looking at a single one -- Windows.

A common misconception about how clipboards work is that they contain a single piece of data, such as text or an image. In reality, clipboards hold all the ways target software can represent the data.

Consider if I copy the following webpage:

HTML headings as rendered by Firefox

When pasting it into Microsoft Word, it appears formatted as rich content:

Microsoft Word displays rich content exactly as Firefox does

When pasting it into Notepad++, it appears as plain text:

Notepad++ does not handle rich content

Pasting different content types depending on the software is possible because Firefox provides multiple representations of the rendered content to the clipboard.

Let's see what types the clipboard is holding using Powershell:

$dataObj = [System.Windows.Forms.Clipboard]::GetDataObject()
foreach ($fmt in $dataObj.GetFormats()) {
    [Console]::WriteLine($fmt)
}
## Output: ##
HTML Format
System.String
UnicodeText
Text
Chromium Web Custom MIME Data Format
Locale
OEMText

We can look inside some of the clipboard types using Powershell, mainly HTML Format and Text with the following commands:

# Get Text
[System.Windows.Forms.Clipboard]::GetText([System.Windows.Forms.TextDataFormat]::Text)
## Output: ##
This is heading 1
This is heading 2
This is heading 3
This is heading 4
This is heading 5
This is heading 6
# Get HTML Format
[System.Windows.Forms.Clipboard]::GetText([System.Windows.Forms.TextDataFormat]::Text)
## Output: ##
Version:0.9
StartHTML:00000174
EndHTML:00000410
StartFragment:00000208
EndFragment:00000374
SourceURL:https://www.w3schools.com/tags/tryit.asp?filename=tryhtml_headers
<html><body>
<!--StartFragment--><h1>This is heading 1</h1>
<h2>This is heading 2</h2>
<h3>This is heading 3</h3>
<h4>This is heading 4</h4>
<h5>This is heading 5</h5>
<h6>This is heading 6</h6><!--EndFragment-->
</body>
</html>

The way to approach clipboards as a consumer is to consume the clipboard formats you know how to, prioritizing some over others. For example, Microsoft Word will prioritize pasting HTML Format formats over Text formats by default.

While Powershell has some built-in parsers, implementing the format specification for every type of content is a lot of work. Are there libraries that can help us with this?

Copy-Pasting in the NPM Ecosystem

The simplest clipboard library would let us query the clipboard directly for binary data. This approach would require us to a parser per format per operating system. While such libraries deserve a place in this world, they are not helpful for most applications. Most applications want to handle copying and pasting only for text, rich text, images, and sometimes files. Let's go through the different clipboard management libraries and see how they fare.

We are looking for a library that has the following features:

  • Pure JS, with native bindings
  • Cross-Platform Support
    • Windows
    • Linux
    • MacOS
  • Copy to clipboard
    • Plain Text
    • Rich Text
    • Images
    • Files
  • Paste from clipboard
    • Plain Text
    • Rich Text
    • Images
    • Files

Here is a table I made from the collected NPM packages, featuring the most popular clipboard-related libraries on NPM:

Note: This table does not include browser-based copy-paste.

Honorable mention: save-clipboard-image, uses AppleScript to save an image from clipboard to a file.

Summary

Before writing this post, I was unaware that the result would be this. It appears that all of NPM's clipboard libraries work the same way: they call built-in executables on their host operating system and return the data. Interestingly, none of them handle images, rich text, or files despite no reason they couldn't deal with them the same way.

The only exceptions to this pattern are Electron and node-clipboard-wd. The former is a framework unsuitable for usage as a library. The latter was written by myself last week as an experiment.

Where do We Go From Here?

Software developers have crossed the clipboard bridge in other environments before. In fact, NodeJS developers have already crossed it in Electron, which uses native bindings under the hood. There is no reason we couldn't do the same using a more lightweight C++ library.

I find clip particularly promising in this regard, and I've been looking into writing a NodeJS wrapper around it. For posterity, here is a table of possible native libraries that I have found so far:


Also Published Here


Written by knyzorg | Sometimes I have good ideas. Writing about Building Better Software Slower at https://bbss.dev
Published by HackerNoon on 2022/01/20