2 * Clipboard handler module: exports methods for handling all clipboard-related events in the
4 * @module xterm/handlers/Clipboard
8 import { ITerminal } from '../Interfaces';
10 interface IWindow extends Window {
12 getData(format: string): string;
13 setData(format: string, data: string);
17 declare var window: IWindow;
20 * Prepares text copied from terminal selection, to be saved in the clipboard by:
21 * 1. stripping all trailing white spaces
22 * 2. converting all non-breaking spaces to regular spaces
23 * @param {string} text The copied text that needs processing for storing in clipboard
26 export function prepareTextForClipboard(text: string): string {
27 let space = String.fromCharCode(32),
28 nonBreakingSpace = String.fromCharCode(160),
29 allNonBreakingSpaces = new RegExp(nonBreakingSpace, 'g'),
30 processedText = text.split('\n').map(function (line) {
31 // Strip all trailing white spaces and convert all non-breaking spaces
33 let processedLine = line.replace(/\s+$/g, '').replace(allNonBreakingSpaces, space);
42 * Prepares text to be pasted into the terminal by normalizing the line endings
43 * @param text The pasted text that needs processing before inserting into the terminal
45 export function prepareTextForTerminal(text: string, isMSWindows: boolean): string {
47 return text.replace(/\r?\n/g, '\n');
53 * Binds copy functionality to the given terminal.
54 * @param {ClipboardEvent} ev The original copy event to be handled
56 export function copyHandler(ev: ClipboardEvent, term: ITerminal) {
57 // We cast `window` to `any` type, because TypeScript has not declared the `clipboardData`
58 // property that we use below for Internet Explorer.
59 let copiedText = window.getSelection().toString(),
60 text = prepareTextForClipboard(copiedText);
62 if (term.browser.isMSIE) {
63 window.clipboardData.setData('Text', text);
65 ev.clipboardData.setData('text/plain', text);
68 ev.preventDefault(); // Prevent or the original text will be copied.
72 * Redirect the clipboard's data to the terminal's input handler.
73 * @param {ClipboardEvent} ev The original paste event to be handled
74 * @param {Terminal} term The terminal on which to apply the handled paste event
76 export function pasteHandler(ev: ClipboardEvent, term: ITerminal) {
81 let dispatchPaste = function(text) {
82 text = prepareTextForTerminal(text, term.browser.isMSWindows);
84 term.textarea.value = '';
85 return term.cancel(ev);
88 if (term.browser.isMSIE) {
89 if (window.clipboardData) {
90 text = window.clipboardData.getData('Text');
94 if (ev.clipboardData) {
95 text = ev.clipboardData.getData('text/plain');
102 * Bind to right-click event and allow right-click copy and paste.
105 * If text is selected and right-click happens on selected text, then
106 * do nothing to allow seamless copying.
107 * If no text is selected or right-click is outside of the selection
108 * area, then bring the terminal's input below the cursor, in order to
109 * trigger the event on the textarea and allow-right click paste, without
110 * caring about disappearing selection.
111 * @param {MouseEvent} ev The original right click event to be handled
112 * @param {Terminal} term The terminal on which to apply the handled paste event
114 export function rightClickHandler(ev: MouseEvent, term: ITerminal) {
115 let s = document.getSelection(),
116 selectedText = prepareTextForClipboard(s.toString()),
117 clickIsOnSelection = false,
122 let r = s.getRangeAt(0),
123 cr = r.getClientRects();
125 for (let i = 0; i < cr.length; i++) {
128 clickIsOnSelection = (
129 (x > rect.left) && (x < rect.right) &&
130 (y > rect.top) && (y < rect.bottom)
133 if (clickIsOnSelection) {
137 // If we clicked on selection and selection is not a single space,
138 // then mark the right click as copy-only. We check for the single
139 // space selection, as this can happen when clicking on an
140 // and there is not much pointing in copying a single space.
141 if (selectedText.match(/^\s$/) || !selectedText.length) {
142 clickIsOnSelection = false;
146 // Bring textarea at the cursor position
147 if (!clickIsOnSelection) {
148 term.textarea.style.position = 'fixed';
149 term.textarea.style.width = '20px';
150 term.textarea.style.height = '20px';
151 term.textarea.style.left = (x - 10) + 'px';
152 term.textarea.style.top = (y - 10) + 'px';
153 term.textarea.style.zIndex = '1000';
154 term.textarea.focus();
156 // Reset the terminal textarea's styling
157 setTimeout(function () {
158 term.textarea.style.position = null;
159 term.textarea.style.width = null;
160 term.textarea.style.height = null;
161 term.textarea.style.left = null;
162 term.textarea.style.top = null;
163 term.textarea.style.zIndex = null;