11import { Signal } from '@lumino/signaling' ;
22import { IDisposable } from '@lumino/disposable' ;
3- import { Cell , ICellModel } from '@jupyterlab/cells' ;
3+ import { CommandRegistry } from '@lumino/commands' ;
4+ import { Cell , CodeCell , ICellModel } from '@jupyterlab/cells' ;
45import { Notebook , NotebookPanel } from '@jupyterlab/notebook' ;
5- import { postNotebookClick , postCellClick } from '../api' ;
6+ import {
7+ postNotebookClick ,
8+ postCellClick ,
9+ postCellCopy ,
10+ postCellPaste ,
11+ postClipboardCopy ,
12+ postClipboardPaste
13+ } from '../api' ;
614import { Selectors } from '../utils/constants' ;
715import { CompatibilityManager } from '../utils/compatibility' ;
816
917type ClickType = 'OFF' | 'ON' ;
18+ interface CellCopyData {
19+ lastCopyCellId : string ;
20+ lastCopyNotebookId : string ;
21+ lastCopyTime : string ;
22+ lastCopyContent : string ;
23+ }
24+
25+ const CELL_COPY_ID : string = 'notebook:copy-cell' ;
26+ const CELL_PASTE_ID : string = 'notebook:paste-cell-below' ;
1027
1128export class FocusDisposable implements IDisposable {
12- constructor ( panel : NotebookPanel , notebookId : string ) {
29+ constructor (
30+ commands : CommandRegistry ,
31+ panel : NotebookPanel ,
32+ notebookId : string
33+ ) {
1334 this . _panel = panel ;
1435
1536 this . _notebookId = notebookId ;
@@ -22,6 +43,13 @@ export class FocusDisposable implements IDisposable {
2243 // connect to active cell changes
2344 panel . content . activeCellChanged . connect ( this . _onCellChanged , this ) ;
2445
46+ // connect to commands executed
47+ commands . commandExecuted . connect ( this . _onCommandExecuted , this ) ;
48+
49+ // Add listener to copy and paste (to clipbaord)
50+ document . addEventListener ( 'copy' , this . _onClipboardCopy ) ;
51+ document . addEventListener ( 'paste' , this . _onClipboardPaste ) ;
52+
2553 // panel.content is disposed before panel itself, so release the associated connection before
2654 panel . content . disposed . connect ( this . _onContentDisposed , this ) ;
2755 }
@@ -44,10 +72,56 @@ export class FocusDisposable implements IDisposable {
4472 this . _sendCellClick ( 'ON' ) ;
4573 } ;
4674
75+ private _onCommandExecuted = (
76+ commandR : CommandRegistry ,
77+ args : CommandRegistry . ICommandExecutedArgs
78+ ) => {
79+ if ( args . id === CELL_COPY_ID ) {
80+ this . _onCopyCommandExecuted ( ) ;
81+ } else if ( args . id === CELL_PASTE_ID ) {
82+ this . _onPasteCommandExecuted ( ) ;
83+ }
84+ } ;
85+
86+ private _onCopyCommandExecuted = ( ) => {
87+ console . log ( 'A cell was copied!' ) ;
88+ if ( this . _lastActiveCellId && this . _lastActiveCellContent ) {
89+ this . _cellCopyData = {
90+ lastCopyNotebookId : this . _notebookId ,
91+ lastCopyCellId : this . _lastActiveCellId ,
92+ lastCopyTime : new Date ( ) . toISOString ( ) ,
93+ lastCopyContent : this . _lastActiveCellContent
94+ } ;
95+ this . _sendCellCopy ( ) ;
96+ }
97+ } ;
98+
99+ private _onPasteCommandExecuted = ( ) => {
100+ console . log ( 'A cell was pasted!' ) ;
101+ this . _sendCellPaste ( ) ;
102+ } ;
103+
104+ private _onClipboardCopy = ( event : ClipboardEvent ) => {
105+ const content = event . clipboardData ?. getData ( 'text' ) ;
106+ console . log ( 'Clipboard copied ' , content ) ;
107+ if ( content ) {
108+ this . _sendClipboardCopy ( content ) ;
109+ }
110+ } ;
111+
112+ private _onClipboardPaste = ( event : ClipboardEvent ) => {
113+ const content = event . clipboardData ?. getData ( 'text' ) ;
114+ console . log ( 'Clipboard pasted ' , content ) ;
115+ if ( content ) {
116+ this . _sendClipboardPaste ( content ) ;
117+ }
118+ } ;
119+
47120 private _setActiveCellAndOrigCellId = (
48121 activeCell : Cell < ICellModel > | null
49122 ) => {
50123 this . _lastActiveCellId = activeCell ?. model . sharedModel . getId ( ) ;
124+ this . _lastActiveCellContent = activeCell ?. model . toJSON ( ) . source . toString ( ) ;
51125 if ( this . _lastActiveCellId ) {
52126 this . _lastOrigCellId = CompatibilityManager . getMetadataComp (
53127 this . _panel ?. model ,
@@ -83,6 +157,53 @@ export class FocusDisposable implements IDisposable {
83157 }
84158 } ;
85159
160+ private _sendCellCopy = ( ) => {
161+ if ( this . _cellCopyData ) {
162+ postCellCopy ( {
163+ notebook_id : this . _cellCopyData . lastCopyNotebookId ,
164+ cell_id : this . _cellCopyData . lastCopyCellId ,
165+ time : this . _cellCopyData . lastCopyTime ,
166+ content : this . _cellCopyData . lastCopyContent
167+ } ) ;
168+ }
169+ } ;
170+
171+ private _sendCellPaste = ( ) => {
172+ if ( this . _cellCopyData && this . _lastActiveCellId ) {
173+ postCellPaste ( {
174+ notebook_id : this . _notebookId ,
175+ copied_notebook_id : this . _cellCopyData . lastCopyNotebookId ,
176+ copied_cell_id : this . _cellCopyData . lastCopyCellId ,
177+ copied_time : this . _cellCopyData . lastCopyTime ,
178+ cell_id : this . _lastActiveCellId ,
179+ time : new Date ( ) . toISOString ( ) ,
180+ content : this . _cellCopyData . lastCopyContent
181+ } ) ;
182+ }
183+ } ;
184+
185+ private _sendClipboardCopy = ( content : string ) => {
186+ if ( this . _lastActiveCellId ) {
187+ postClipboardCopy ( {
188+ notebook_id : this . _notebookId ,
189+ cell_id : this . _lastActiveCellId ,
190+ time : new Date ( ) . toISOString ( ) ,
191+ content : content
192+ } ) ;
193+ }
194+ } ;
195+
196+ private _sendClipboardPaste = ( content : string ) => {
197+ if ( this . _lastActiveCellId ) {
198+ postClipboardPaste ( {
199+ notebook_id : this . _notebookId ,
200+ cell_id : this . _lastActiveCellId ,
201+ time : new Date ( ) . toISOString ( ) ,
202+ content : content
203+ } ) ;
204+ }
205+ } ;
206+
86207 private _sendNotebookClick = ( clickType : ClickType ) => {
87208 let notebookDurationSec : number | null = null ;
88209 if ( clickType === 'ON' ) {
@@ -116,15 +237,20 @@ export class FocusDisposable implements IDisposable {
116237
117238 this . _isDisposed = true ;
118239 this . _lastActiveCellId = null ;
240+ this . _cellCopyData = null ;
119241
242+ document . removeEventListener ( 'copy' , this . _onClipboardCopy ) ;
243+ document . removeEventListener ( 'paste' , this . _onClipboardPaste ) ;
120244 Signal . clearData ( this ) ;
121245 }
122246
123247 private _isDisposed = false ;
124248 private _panel : NotebookPanel ;
125249 private _notebookId : string ;
126250 private _lastActiveCellId : string | null | undefined = null ;
251+ private _lastActiveCellContent : string | null | undefined = null ;
127252 private _lastOrigCellId : string | null | undefined = null ;
253+ private _cellCopyData : CellCopyData | null | undefined = null ;
128254
129255 private _notebookStart : Date = new Date ( ) ;
130256 private _cellStart : Date = new Date ( ) ;
0 commit comments