1 |
|
2 |
|
3 |
|
4 |
|
5 |
|
6 |
|
7 |
|
8 |
|
9 |
|
10 |
|
11 |
|
12 | import { ICodeCellModel } from './model';
|
13 | import { Cell } from './widget';
|
14 | import { h, VirtualDOM } from '@lumino/virtualdom';
|
15 | import * as nbformat from '@jupyterlab/nbformat';
|
16 |
|
17 |
|
18 |
|
19 |
|
20 |
|
21 |
|
22 |
|
23 |
|
24 | const DRAG_THRESHOLD = 5;
|
25 |
|
26 |
|
27 |
|
28 | const DRAG_IMAGE_CLASS = 'jp-dragImage';
|
29 |
|
30 |
|
31 |
|
32 |
|
33 | const SINGLE_DRAG_IMAGE_CLASS = 'jp-dragImage-singlePrompt';
|
34 |
|
35 |
|
36 |
|
37 |
|
38 | const CELL_DRAG_CONTENT_CLASS = 'jp-dragImage-content';
|
39 |
|
40 |
|
41 |
|
42 |
|
43 | const CELL_DRAG_PROMPT_CLASS = 'jp-dragImage-prompt';
|
44 |
|
45 |
|
46 |
|
47 |
|
48 | const CELL_DRAG_MULTIPLE_BACK = 'jp-dragImage-multipleBack';
|
49 |
|
50 | export namespace CellDragUtils {
|
51 | export type ICellTargetArea = 'input' | 'prompt' | 'cell' | 'unknown';
|
52 |
|
53 | |
54 |
|
55 |
|
56 |
|
57 |
|
58 |
|
59 |
|
60 |
|
61 |
|
62 |
|
63 |
|
64 |
|
65 |
|
66 | export function findCell(
|
67 | node: HTMLElement,
|
68 | cells: Iterable<Cell>,
|
69 | isCellNode: (node: HTMLElement) => boolean
|
70 | ): number {
|
71 | let cellIndex = -1;
|
72 | while (node && node.parentElement) {
|
73 | if (isCellNode(node)) {
|
74 | let index = -1;
|
75 | for (const cell of cells) {
|
76 | if (cell.node === node) {
|
77 | cellIndex = ++index;
|
78 | break;
|
79 | }
|
80 | }
|
81 | break;
|
82 | }
|
83 | node = node.parentElement;
|
84 | }
|
85 | return cellIndex;
|
86 | }
|
87 |
|
88 | |
89 |
|
90 |
|
91 |
|
92 |
|
93 |
|
94 | export function detectTargetArea(
|
95 | cell: Cell,
|
96 | target: HTMLElement
|
97 | ): ICellTargetArea {
|
98 | let targetArea: ICellTargetArea;
|
99 | if (cell) {
|
100 | if (cell.editorWidget?.node.contains(target)) {
|
101 | targetArea = 'input';
|
102 | } else if (cell.promptNode?.contains(target)) {
|
103 | targetArea = 'prompt';
|
104 | } else {
|
105 | targetArea = 'cell';
|
106 | }
|
107 | } else {
|
108 | targetArea = 'unknown';
|
109 | }
|
110 | return targetArea;
|
111 | }
|
112 |
|
113 | |
114 |
|
115 |
|
116 |
|
117 |
|
118 |
|
119 |
|
120 |
|
121 |
|
122 | export function shouldStartDrag(
|
123 | prevX: number,
|
124 | prevY: number,
|
125 | nextX: number,
|
126 | nextY: number
|
127 | ): boolean {
|
128 | const dx = Math.abs(nextX - prevX);
|
129 | const dy = Math.abs(nextY - prevY);
|
130 | return dx >= DRAG_THRESHOLD || dy >= DRAG_THRESHOLD;
|
131 | }
|
132 |
|
133 | |
134 |
|
135 |
|
136 |
|
137 |
|
138 |
|
139 | export function createCellDragImage(
|
140 | activeCell: Cell,
|
141 | selectedCells: nbformat.ICell[]
|
142 | ): HTMLElement {
|
143 | const count = selectedCells.length;
|
144 | let promptNumber: string;
|
145 | if (activeCell.model.type === 'code') {
|
146 | const executionCount = (activeCell.model as ICodeCellModel)
|
147 | .executionCount;
|
148 | promptNumber = ' ';
|
149 | if (executionCount) {
|
150 | promptNumber = executionCount.toString();
|
151 | }
|
152 | } else {
|
153 | promptNumber = '';
|
154 | }
|
155 |
|
156 | const cellContent = activeCell.model.sharedModel
|
157 | .getSource()
|
158 | .split('\n')[0]
|
159 | .slice(0, 26);
|
160 | if (count > 1) {
|
161 | if (promptNumber !== '') {
|
162 | return VirtualDOM.realize(
|
163 | h.div(
|
164 | h.div(
|
165 | { className: DRAG_IMAGE_CLASS },
|
166 | h.span(
|
167 | { className: CELL_DRAG_PROMPT_CLASS },
|
168 | '[' + promptNumber + ']:'
|
169 | ),
|
170 | h.span({ className: CELL_DRAG_CONTENT_CLASS }, cellContent)
|
171 | ),
|
172 | h.div({ className: CELL_DRAG_MULTIPLE_BACK }, '')
|
173 | )
|
174 | );
|
175 | } else {
|
176 | return VirtualDOM.realize(
|
177 | h.div(
|
178 | h.div(
|
179 | { className: DRAG_IMAGE_CLASS },
|
180 | h.span({ className: CELL_DRAG_PROMPT_CLASS }),
|
181 | h.span({ className: CELL_DRAG_CONTENT_CLASS }, cellContent)
|
182 | ),
|
183 | h.div({ className: CELL_DRAG_MULTIPLE_BACK }, '')
|
184 | )
|
185 | );
|
186 | }
|
187 | } else {
|
188 | if (promptNumber !== '') {
|
189 | return VirtualDOM.realize(
|
190 | h.div(
|
191 | h.div(
|
192 | { className: `${DRAG_IMAGE_CLASS} ${SINGLE_DRAG_IMAGE_CLASS}` },
|
193 | h.span(
|
194 | { className: CELL_DRAG_PROMPT_CLASS },
|
195 | '[' + promptNumber + ']:'
|
196 | ),
|
197 | h.span({ className: CELL_DRAG_CONTENT_CLASS }, cellContent)
|
198 | )
|
199 | )
|
200 | );
|
201 | } else {
|
202 | return VirtualDOM.realize(
|
203 | h.div(
|
204 | h.div(
|
205 | { className: `${DRAG_IMAGE_CLASS} ${SINGLE_DRAG_IMAGE_CLASS}` },
|
206 | h.span({ className: CELL_DRAG_PROMPT_CLASS }),
|
207 | h.span({ className: CELL_DRAG_CONTENT_CLASS }, cellContent)
|
208 | )
|
209 | )
|
210 | );
|
211 | }
|
212 | }
|
213 | }
|
214 | }
|