1 | (function ($) {
|
2 |
|
3 | $.extend(true, window, {
|
4 | "Slick": {
|
5 | "CellExternalCopyManager": CellExternalCopyManager
|
6 | }
|
7 | });
|
8 |
|
9 |
|
10 | function CellExternalCopyManager(options) {
|
11 | |
12 |
|
13 |
|
14 |
|
15 |
|
16 |
|
17 |
|
18 |
|
19 |
|
20 |
|
21 |
|
22 |
|
23 |
|
24 |
|
25 |
|
26 |
|
27 |
|
28 |
|
29 |
|
30 |
|
31 |
|
32 |
|
33 | var _grid;
|
34 | var _self = this;
|
35 | var _copiedRanges;
|
36 | var _options = options || {};
|
37 | var _copiedCellStyleLayerKey = _options.copiedCellStyleLayerKey || "copy-manager";
|
38 | var _copiedCellStyle = _options.copiedCellStyle || "copied";
|
39 | var _clearCopyTI = 0;
|
40 | var _bodyElement = _options.bodyElement || document.body;
|
41 | var _onCopyInit = _options.onCopyInit || null;
|
42 | var _onCopySuccess = _options.onCopySuccess || null;
|
43 |
|
44 | var keyCodes = {
|
45 | 'C': 67,
|
46 | 'V': 86,
|
47 | 'ESC': 27,
|
48 | 'INSERT': 45
|
49 | };
|
50 |
|
51 | function init(grid) {
|
52 | _grid = grid;
|
53 | _grid.onKeyDown.subscribe(handleKeyDown);
|
54 |
|
55 |
|
56 | var cellSelectionModel = grid.getSelectionModel();
|
57 | if (!cellSelectionModel){
|
58 | throw new Error("Selection model is mandatory for this plugin. Please set a selection model on the grid before adding this plugin: grid.setSelectionModel(new Slick.CellSelectionModel())");
|
59 | }
|
60 |
|
61 |
|
62 | cellSelectionModel.onSelectedRangesChanged.subscribe(function(e, args){
|
63 | _grid.focus();
|
64 | });
|
65 | }
|
66 |
|
67 | function destroy() {
|
68 | _grid.onKeyDown.unsubscribe(handleKeyDown);
|
69 | }
|
70 |
|
71 | function getHeaderValueForColumn(columnDef) {
|
72 | if (_options.headerColumnValueExtractor) {
|
73 | var val = _options.headerColumnValueExtractor(columnDef);
|
74 |
|
75 | if (val) { return val; }
|
76 | }
|
77 |
|
78 | return columnDef.name;
|
79 | }
|
80 |
|
81 | function getDataItemValueForColumn(item, columnDef, e) {
|
82 | if (_options.dataItemColumnValueExtractor) {
|
83 | var val = _options.dataItemColumnValueExtractor(item, columnDef);
|
84 |
|
85 | if (val) { return val; }
|
86 | }
|
87 |
|
88 | var retVal = '';
|
89 |
|
90 |
|
91 | if (columnDef.editor){
|
92 | var editorArgs = {
|
93 | 'container':$("<p>"),
|
94 | 'column':columnDef,
|
95 | 'position':{'top':0, 'left':0},
|
96 | 'grid':_grid,
|
97 | 'event':e
|
98 | };
|
99 | var editor = new columnDef.editor(editorArgs);
|
100 | editor.loadValue(item);
|
101 | retVal = editor.serializeValue();
|
102 | editor.destroy();
|
103 | } else {
|
104 | retVal = item[columnDef.field];
|
105 | }
|
106 |
|
107 | return retVal;
|
108 | }
|
109 |
|
110 | function setDataItemValueForColumn(item, columnDef, value) {
|
111 | if (columnDef.denyPaste) { return null; }
|
112 |
|
113 | if (_options.dataItemColumnValueSetter) {
|
114 | return _options.dataItemColumnValueSetter(item, columnDef, value);
|
115 | }
|
116 |
|
117 |
|
118 | if (columnDef.editor){
|
119 | var editorArgs = {
|
120 | 'container':$("body"),
|
121 | 'column':columnDef,
|
122 | 'position':{'top':0, 'left':0},
|
123 | 'grid':_grid
|
124 | };
|
125 | var editor = new columnDef.editor(editorArgs);
|
126 | editor.loadValue(item);
|
127 | editor.applyValue(item, value);
|
128 | editor.destroy();
|
129 | } else {
|
130 | item[columnDef.field] = value;
|
131 | }
|
132 | }
|
133 |
|
134 |
|
135 | function _createTextBox(innerText){
|
136 | var ta = document.createElement('textarea');
|
137 | ta.style.position = 'absolute';
|
138 | ta.style.left = '-1000px';
|
139 | ta.style.top = document.body.scrollTop + 'px';
|
140 | ta.value = innerText;
|
141 | _bodyElement.appendChild(ta);
|
142 | ta.select();
|
143 |
|
144 | return ta;
|
145 | }
|
146 |
|
147 | function _decodeTabularData(_grid, ta){
|
148 | var columns = _grid.getColumns();
|
149 | var clipText = ta.value;
|
150 | var clipRows = clipText.split(/[\n\f\r]/);
|
151 |
|
152 | if (clipRows[clipRows.length - 1]==="") { clipRows.pop(); }
|
153 |
|
154 | var clippedRange = [];
|
155 | var j = 0;
|
156 |
|
157 | _bodyElement.removeChild(ta);
|
158 | for (var i=0; i<clipRows.length; i++) {
|
159 | if (clipRows[i]!=="")
|
160 | clippedRange[j++] = clipRows[i].split("\t");
|
161 | else
|
162 | clippedRange[j++] = [""];
|
163 | }
|
164 | var selectedCell = _grid.getActiveCell();
|
165 | var ranges = _grid.getSelectionModel().getSelectedRanges();
|
166 | var selectedRange = ranges && ranges.length ? ranges[0] : null;
|
167 | var activeRow = null;
|
168 | var activeCell = null;
|
169 |
|
170 | if (selectedRange){
|
171 | activeRow = selectedRange.fromRow;
|
172 | activeCell = selectedRange.fromCell;
|
173 | } else if (selectedCell){
|
174 | activeRow = selectedCell.row;
|
175 | activeCell = selectedCell.cell;
|
176 | } else {
|
177 |
|
178 | return;
|
179 | }
|
180 |
|
181 | var oneCellToMultiple = false;
|
182 | var destH = clippedRange.length;
|
183 | var destW = clippedRange.length ? clippedRange[0].length : 0;
|
184 | if (clippedRange.length == 1 && clippedRange[0].length == 1 && selectedRange){
|
185 | oneCellToMultiple = true;
|
186 | destH = selectedRange.toRow - selectedRange.fromRow +1;
|
187 | destW = selectedRange.toCell - selectedRange.fromCell +1;
|
188 | }
|
189 | var availableRows = _grid.getData().length - activeRow;
|
190 | var addRows = 0;
|
191 |
|
192 |
|
193 | if(availableRows < destH && _options.newRowCreator)
|
194 | {
|
195 | var d = _grid.getData();
|
196 | for(addRows = 1; addRows <= destH - availableRows; addRows++)
|
197 | d.push({});
|
198 | _grid.setData(d);
|
199 | _grid.render();
|
200 | }
|
201 |
|
202 | var overflowsBottomOfGrid = activeRow + destH > _grid.getDataLength();
|
203 |
|
204 | if (_options.newRowCreator && overflowsBottomOfGrid) {
|
205 |
|
206 | var newRowsNeeded = activeRow + destH - _grid.getDataLength();
|
207 |
|
208 | _options.newRowCreator(newRowsNeeded);
|
209 |
|
210 | }
|
211 |
|
212 | var clipCommand = {
|
213 |
|
214 | isClipboardCommand: true,
|
215 | clippedRange: clippedRange,
|
216 | oldValues: [],
|
217 | cellExternalCopyManager: _self,
|
218 | _options: _options,
|
219 | setDataItemValueForColumn: setDataItemValueForColumn,
|
220 | markCopySelection: markCopySelection,
|
221 | oneCellToMultiple: oneCellToMultiple,
|
222 | activeRow: activeRow,
|
223 | activeCell: activeCell,
|
224 | destH: destH,
|
225 | destW: destW,
|
226 | maxDestY: _grid.getDataLength(),
|
227 | maxDestX: _grid.getColumns().length,
|
228 | h: 0,
|
229 | w: 0,
|
230 |
|
231 | execute: function() {
|
232 | this.h=0;
|
233 | for (var y = 0; y < this.destH; y++){
|
234 | this.oldValues[y] = [];
|
235 | this.w=0;
|
236 | this.h++;
|
237 | for (var x = 0; x < this.destW; x++){
|
238 | this.w++;
|
239 | var desty = activeRow + y;
|
240 | var destx = activeCell + x;
|
241 |
|
242 | if (desty < this.maxDestY && destx < this.maxDestX ) {
|
243 | var nd = _grid.getCellNode(desty, destx);
|
244 | var dt = _grid.getDataItem(desty);
|
245 | this.oldValues[y][x] = dt[columns[destx]['field']];
|
246 | if (oneCellToMultiple)
|
247 | this.setDataItemValueForColumn(dt, columns[destx], clippedRange[0][0]);
|
248 | else
|
249 | this.setDataItemValueForColumn(dt, columns[destx], clippedRange[y] ? clippedRange[y][x] : '');
|
250 | _grid.updateCell(desty, destx);
|
251 | _grid.onCellChange.notify({
|
252 | row: desty,
|
253 | cell: destx,
|
254 | item: dt,
|
255 | grid: _grid
|
256 | });
|
257 |
|
258 | }
|
259 | }
|
260 | }
|
261 |
|
262 | var bRange = {
|
263 | 'fromCell': activeCell,
|
264 | 'fromRow': activeRow,
|
265 | 'toCell': activeCell+this.w-1,
|
266 | 'toRow': activeRow+this.h-1
|
267 | };
|
268 |
|
269 | this.markCopySelection([bRange]);
|
270 | _grid.getSelectionModel().setSelectedRanges([bRange]);
|
271 | this.cellExternalCopyManager.onPasteCells.notify({ranges: [bRange]});
|
272 | },
|
273 |
|
274 | undo: function() {
|
275 | for (var y = 0; y < this.destH; y++){
|
276 | for (var x = 0; x < this.destW; x++){
|
277 | var desty = activeRow + y;
|
278 | var destx = activeCell + x;
|
279 |
|
280 | if (desty < this.maxDestY && destx < this.maxDestX ) {
|
281 | var nd = _grid.getCellNode(desty, destx);
|
282 | var dt = _grid.getDataItem(desty);
|
283 | if (oneCellToMultiple)
|
284 | this.setDataItemValueForColumn(dt, columns[destx], this.oldValues[0][0]);
|
285 | else
|
286 | this.setDataItemValueForColumn(dt, columns[destx], this.oldValues[y][x]);
|
287 | _grid.updateCell(desty, destx);
|
288 | _grid.onCellChange.notify({
|
289 | row: desty,
|
290 | cell: destx,
|
291 | item: dt,
|
292 | grid: _grid
|
293 | });
|
294 | }
|
295 | }
|
296 | }
|
297 |
|
298 | var bRange = {
|
299 | 'fromCell': activeCell,
|
300 | 'fromRow': activeRow,
|
301 | 'toCell': activeCell+this.w-1,
|
302 | 'toRow': activeRow+this.h-1
|
303 | };
|
304 |
|
305 | this.markCopySelection([bRange]);
|
306 | _grid.getSelectionModel().setSelectedRanges([bRange]);
|
307 | this.cellExternalCopyManager.onPasteCells.notify({ranges: [bRange]});
|
308 |
|
309 | if(addRows > 1){
|
310 | var d = _grid.getData();
|
311 | for(; addRows > 1; addRows--)
|
312 | d.splice(d.length - 1, 1);
|
313 | _grid.setData(d);
|
314 | _grid.render();
|
315 | }
|
316 | }
|
317 | };
|
318 |
|
319 | if(_options.clipboardCommandHandler) {
|
320 | _options.clipboardCommandHandler(clipCommand);
|
321 | }
|
322 | else {
|
323 | clipCommand.execute();
|
324 | }
|
325 | }
|
326 |
|
327 |
|
328 | function handleKeyDown(e, args) {
|
329 | var ranges;
|
330 | if (!_grid.getEditorLock().isActive() || _grid.getOptions().autoEdit) {
|
331 | if (e.which == keyCodes.ESC) {
|
332 | if (_copiedRanges) {
|
333 | e.preventDefault();
|
334 | clearCopySelection();
|
335 | _self.onCopyCancelled.notify({ranges: _copiedRanges});
|
336 | _copiedRanges = null;
|
337 | }
|
338 | }
|
339 |
|
340 | if ((e.which === keyCodes.C || e.which === keyCodes.INSERT) && (e.ctrlKey || e.metaKey) && !e.shiftKey) {
|
341 | if (_onCopyInit) {
|
342 | _onCopyInit.call();
|
343 | }
|
344 | ranges = _grid.getSelectionModel().getSelectedRanges();
|
345 | if (ranges.length !== 0) {
|
346 | _copiedRanges = ranges;
|
347 | markCopySelection(ranges);
|
348 | _self.onCopyCells.notify({ranges: ranges});
|
349 |
|
350 | var columns = _grid.getColumns();
|
351 | var clipText = "";
|
352 |
|
353 | for (var rg = 0; rg < ranges.length; rg++){
|
354 | var range = ranges[rg];
|
355 | var clipTextRows = [];
|
356 | for (var i=range.fromRow; i< range.toRow+1 ; i++){
|
357 | var clipTextCells = [];
|
358 | var dt = _grid.getDataItem(i);
|
359 |
|
360 | if (clipTextRows.length === 0 && _options.includeHeaderWhenCopying) {
|
361 | var clipTextHeaders = [];
|
362 | for (var j = range.fromCell; j < range.toCell + 1 ; j++) {
|
363 | if (columns[j].name.length > 0)
|
364 | clipTextHeaders.push(getHeaderValueForColumn(columns[j]));
|
365 | }
|
366 | clipTextRows.push(clipTextHeaders.join("\t"));
|
367 | }
|
368 |
|
369 | for (var j=range.fromCell; j< range.toCell+1 ; j++){
|
370 | clipTextCells.push(getDataItemValueForColumn(dt, columns[j], e));
|
371 | }
|
372 | clipTextRows.push(clipTextCells.join("\t"));
|
373 | }
|
374 | clipText += clipTextRows.join("\r\n") + "\r\n";
|
375 | }
|
376 |
|
377 | if(window.clipboardData) {
|
378 | window.clipboardData.setData("Text", clipText);
|
379 | return true;
|
380 | }
|
381 | else {
|
382 | var focusEl = document.activeElement;
|
383 |
|
384 | var ta = _createTextBox(clipText);
|
385 |
|
386 | ta.focus();
|
387 |
|
388 | setTimeout(function(){
|
389 | _bodyElement.removeChild(ta);
|
390 |
|
391 | if (focusEl)
|
392 | focusEl.focus();
|
393 | else
|
394 | console.log("Not element to restore focus to after copy?");
|
395 |
|
396 | }, 100);
|
397 |
|
398 | if (_onCopySuccess) {
|
399 | var rowCount = 0;
|
400 |
|
401 | if (ranges.length === 1) {
|
402 | rowCount = (ranges[0].toRow + 1) - ranges[0].fromRow;
|
403 | }
|
404 | else {
|
405 | rowCount = ranges.length;
|
406 | }
|
407 | _onCopySuccess.call(this, rowCount);
|
408 | }
|
409 |
|
410 | return false;
|
411 | }
|
412 | }
|
413 | }
|
414 |
|
415 | if (!_options.readOnlyMode && (
|
416 | (e.which === keyCodes.V && (e.ctrlKey || e.metaKey) && !e.shiftKey)
|
417 | || (e.which === keyCodes.INSERT && e.shiftKey && !e.ctrlKey)
|
418 | )) {
|
419 | var ta = _createTextBox('');
|
420 |
|
421 | setTimeout(function(){
|
422 | _decodeTabularData(_grid, ta);
|
423 | }, 100);
|
424 |
|
425 | return false;
|
426 | }
|
427 | }
|
428 | }
|
429 |
|
430 | function markCopySelection(ranges) {
|
431 | clearCopySelection();
|
432 |
|
433 | var columns = _grid.getColumns();
|
434 | var hash = {};
|
435 | for (var i = 0; i < ranges.length; i++) {
|
436 | for (var j = ranges[i].fromRow; j <= ranges[i].toRow; j++) {
|
437 | hash[j] = {};
|
438 | for (var k = ranges[i].fromCell; k <= ranges[i].toCell && k<columns.length; k++) {
|
439 | hash[j][columns[k].id] = _copiedCellStyle;
|
440 | }
|
441 | }
|
442 | }
|
443 | _grid.setCellCssStyles(_copiedCellStyleLayerKey, hash);
|
444 | clearTimeout(_clearCopyTI);
|
445 | _clearCopyTI = setTimeout(function(){
|
446 | _self.clearCopySelection();
|
447 | }, 2000);
|
448 | }
|
449 |
|
450 | function clearCopySelection() {
|
451 | _grid.removeCellCssStyles(_copiedCellStyleLayerKey);
|
452 | }
|
453 |
|
454 | function setIncludeHeaderWhenCopying(includeHeaderWhenCopying) {
|
455 | _options.includeHeaderWhenCopying = includeHeaderWhenCopying;
|
456 | }
|
457 |
|
458 | $.extend(this, {
|
459 | "init": init,
|
460 | "destroy": destroy,
|
461 | "pluginName": "CellExternalCopyManager",
|
462 |
|
463 | "clearCopySelection": clearCopySelection,
|
464 | "handleKeyDown":handleKeyDown,
|
465 |
|
466 | "onCopyCells": new Slick.Event(),
|
467 | "onCopyCancelled": new Slick.Event(),
|
468 | "onPasteCells": new Slick.Event(),
|
469 | "setIncludeHeaderWhenCopying" : setIncludeHeaderWhenCopying
|
470 | });
|
471 | }
|
472 | })(jQuery); |
\ | No newline at end of file |