]>
Commit | Line | Data |
---|---|---|
6527f429 DM |
1 | /**\r |
2 | * This {@link Ext.grid.Panel grid} plugin adds clipboard support to a grid.\r | |
3 | *\r | |
4 | * *Note that the grid must use the {@link Ext.grid.selection.SpreadsheetModel spreadsheet selection model} to utilize this plugin.*\r | |
5 | *\r | |
6 | * This class supports the following `{@link Ext.plugin.AbstractClipboard#formats formats}`\r | |
7 | * for grid data:\r | |
8 | *\r | |
9 | * * `cell` - Complete field data that can be matched to other grids using the same\r | |
10 | * {@link Ext.data.Model model} regardless of column order.\r | |
11 | * * `text` - Cell content stripped of HTML tags.\r | |
12 | * * `html` - Complete cell content, including any rendered HTML tags.\r | |
13 | * * `raw` - Underlying field values based on `dataIndex`.\r | |
14 | *\r | |
15 | * The `cell` format is not valid for the `{@link Ext.plugin.AbstractClipboard#system system}`\r | |
16 | * clipboard format.\r | |
17 | */\r | |
18 | Ext.define('Ext.grid.plugin.Clipboard', {\r | |
19 | extend: 'Ext.plugin.AbstractClipboard',\r | |
20 | \r | |
21 | alias: 'plugin.clipboard',\r | |
22 | requires: [\r | |
23 | 'Ext.util.Format',\r | |
24 | 'Ext.util.TSV'\r | |
25 | ],\r | |
26 | \r | |
27 | formats: {\r | |
28 | cell: {\r | |
29 | get: 'getCells'\r | |
30 | },\r | |
31 | html: {\r | |
32 | get: 'getCellData'\r | |
33 | },\r | |
34 | raw: {\r | |
35 | get: 'getCellData'\r | |
36 | }\r | |
37 | },\r | |
38 | \r | |
39 | getCellData: function (format, erase) {\r | |
40 | var cmp = this.getCmp(),\r | |
41 | selModel = cmp.getSelectionModel(),\r | |
42 | ret = [],\r | |
43 | isRaw = format === 'raw',\r | |
44 | isText = format === 'text',\r | |
45 | viewNode,\r | |
46 | cell, data, dataIndex, lastRecord, column, record, row, view;\r | |
47 | \r | |
48 | selModel.getSelected().eachCell(function (cellContext) {\r | |
49 | column = cellContext.column,\r | |
50 | view = cellContext.column.getView();\r | |
51 | record = cellContext.record;\r | |
52 | \r | |
53 | // Do not copy the check column or row numberer column\r | |
54 | if (column.ignoreExport) {\r | |
55 | return;\r | |
56 | }\r | |
57 | \r | |
58 | if (lastRecord !== record) {\r | |
59 | lastRecord = record;\r | |
60 | ret.push(row = []);\r | |
61 | }\r | |
62 | \r | |
63 | dataIndex = column.dataIndex;\r | |
64 | \r | |
65 | if (isRaw) {\r | |
66 | data = record.data[dataIndex];\r | |
67 | } else {\r | |
68 | // Try to access the view node.\r | |
69 | viewNode = view.all.item(cellContext.rowIdx);\r | |
70 | // If we could not, it's because it's outside of the rendered block - recreate it.\r | |
71 | if (!viewNode) {\r | |
72 | viewNode = Ext.fly(view.createRowElement(record, cellContext.rowIdx));\r | |
73 | }\r | |
74 | cell = viewNode.down(column.getCellInnerSelector());\r | |
75 | data = cell.dom.innerHTML;\r | |
76 | if (isText) {\r | |
77 | data = Ext.util.Format.stripTags(data);\r | |
78 | }\r | |
79 | }\r | |
80 | \r | |
81 | row.push(data);\r | |
82 | \r | |
83 | if (erase && dataIndex) {\r | |
84 | record.set(dataIndex, null);\r | |
85 | }\r | |
86 | });\r | |
87 | \r | |
88 | return Ext.util.TSV.encode(ret);\r | |
89 | },\r | |
90 | \r | |
91 | getCells: function (format, erase) {\r | |
92 | var cmp = this.getCmp(),\r | |
93 | selModel = cmp.getSelectionModel(),\r | |
94 | ret = [],\r | |
95 | dataIndex, lastRecord, record, row;\r | |
96 | \r | |
97 | selModel.getSelected().eachCell(function (cellContext) {\r | |
98 | record = cellContext.record;\r | |
99 | if (lastRecord !== record) {\r | |
100 | lastRecord = record;\r | |
101 | ret.push(row = {\r | |
102 | model: record.self,\r | |
103 | fields: []\r | |
104 | });\r | |
105 | }\r | |
106 | \r | |
107 | dataIndex = cellContext.column.dataIndex;\r | |
108 | \r | |
109 | row.fields.push({\r | |
110 | name: dataIndex,\r | |
111 | value: record.data[dataIndex]\r | |
112 | });\r | |
113 | \r | |
114 | if (erase && dataIndex) {\r | |
115 | record.set(dataIndex, null);\r | |
116 | }\r | |
117 | });\r | |
118 | \r | |
119 | return ret;\r | |
120 | },\r | |
121 | \r | |
122 | getTextData: function (format, erase) {\r | |
123 | return this.getCellData(format, erase);\r | |
124 | },\r | |
125 | \r | |
126 | putCellData: function (data, format) {\r | |
127 | var values = Ext.util.TSV.decode(data),\r | |
128 | row,\r | |
129 | recCount = values.length,\r | |
130 | colCount = recCount ? values[0].length : 0,\r | |
131 | sourceRowIdx, sourceColIdx,\r | |
132 | view = this.getCmp().getView(),\r | |
133 | maxRowIdx = view.dataSource.getCount() - 1,\r | |
134 | maxColIdx = view.getVisibleColumnManager().getColumns().length - 1,\r | |
135 | navModel = view.getNavigationModel(),\r | |
136 | destination = navModel.getPosition(),\r | |
137 | dataIndex, destinationStartColumn,\r | |
138 | dataObject = {};\r | |
139 | \r | |
140 | // If the view is not focused, use the first cell of the selection as the destination.\r | |
141 | if (!destination) {\r | |
142 | view.getSelectionModel().getSelected().eachCell(function(c){\r | |
143 | destination = c;\r | |
144 | return false;\r | |
145 | });\r | |
146 | }\r | |
147 | \r | |
148 | if (destination) {\r | |
149 | // Create a new Context based upon the outermost View.\r | |
150 | // NavigationModel works on local views. TODO: remove this step when NavModel is fixed to use outermost view in locked grid.\r | |
151 | // At that point, we can use navModel.getPosition()\r | |
152 | destination = new Ext.grid.CellContext(view).setPosition(destination.record, destination.column);\r | |
153 | } else {\r | |
154 | destination = new Ext.grid.CellContext(view).setPosition(0, 0);\r | |
155 | }\r | |
156 | destinationStartColumn = destination.colIdx;\r | |
157 | \r | |
158 | for (sourceRowIdx = 0; sourceRowIdx < recCount; sourceRowIdx++) {\r | |
159 | row = values[sourceRowIdx];\r | |
160 | \r | |
161 | // Collect new values in dataObject\r | |
162 | for (sourceColIdx = 0; sourceColIdx < colCount; sourceColIdx++) {\r | |
163 | dataIndex = destination.column.dataIndex;\r | |
164 | if (dataIndex) {\r | |
165 | switch (format) {\r | |
166 | // Raw field values\r | |
167 | case 'raw':\r | |
168 | dataObject[dataIndex] = row[sourceColIdx];\r | |
169 | break;\r | |
170 | \r | |
171 | // Textual data with HTML tags stripped \r | |
172 | case 'text':\r | |
173 | dataObject[dataIndex] = row[sourceColIdx];\r | |
174 | break;\r | |
175 | \r | |
176 | // innerHTML from the cell inner\r | |
177 | case 'html':\r | |
178 | break;\r | |
179 | }\r | |
180 | }\r | |
181 | // If we are at the end of the destination row, break the column loop.\r | |
182 | if (destination.colIdx === maxColIdx) {\r | |
183 | break;\r | |
184 | }\r | |
185 | destination.setColumn(destination.colIdx + 1);\r | |
186 | }\r | |
187 | \r | |
188 | // Update the record in one go.\r | |
189 | destination.record.set(dataObject);\r | |
190 | \r | |
191 | // If we are at the end of the destination store, break the row loop.\r | |
192 | if (destination.rowIdx === maxRowIdx) {\r | |
193 | break;\r | |
194 | }\r | |
195 | \r | |
196 | // Jump to next row in destination\r | |
197 | destination.setPosition(destination.rowIdx + 1, destinationStartColumn);\r | |
198 | }\r | |
199 | },\r | |
200 | \r | |
201 | putTextData: function (data, format) {\r | |
202 | this.putCellData(data, format);\r | |
203 | },\r | |
204 | \r | |
205 | getTarget: function(comp) {\r | |
206 | return comp.body;\r | |
207 | }\r | |
208 | });\r |