field-to-grid-dd.js 12 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338
  1. Ext.require(['*']);
  2. // A DropZone which cooperates with DragZones whose dragData contains
  3. // a "field" property representing a form Field. Fields may be dropped onto
  4. // grid data cells containing a matching data type.
  5. Ext.define('Ext.ux.CellFieldDropZone', {
  6. extend: 'Ext.dd.DropZone',
  7. constructor: function(cfg){
  8. cfg = cfg || {};
  9. if (cfg.onCellDrop) {
  10. this.onCellDrop = cfg.onCellDrop;
  11. }
  12. },
  13. // Call the DropZone constructor using the View's scrolling element
  14. // only after the grid has been rendered.
  15. init: function(grid) {
  16. var me = this;
  17. if (grid.rendered) {
  18. me.grid = grid;
  19. grid.getView().on({
  20. render: function(v) {
  21. me.view = v;
  22. Ext.ux.CellFieldDropZone.superclass.constructor.call(me, me.view.el);
  23. },
  24. single: true
  25. });
  26. } else {
  27. grid.on('render', me.init, me, {single: true});
  28. }
  29. },
  30. // Scroll the main configured Element when we drag close to the edge
  31. containerScroll: true,
  32. getTargetFromEvent: function(e) {
  33. var me = this,
  34. v = me.view;
  35. // Ascertain whether the mousemove is within a grid cell
  36. var cell = e.getTarget(v.cellSelector);
  37. if (cell) {
  38. // We *are* within a grid cell, so ask the View exactly which one,
  39. // Extract data from the Model to create a target object for
  40. // processing in subsequent onNodeXXXX methods. Note that the target does
  41. // not have to be a DOM element. It can be whatever the noNodeXXX methods are
  42. // programmed to expect.
  43. var row = v.findItemByChild(cell),
  44. columnIndex = cell.cellIndex;
  45. if (row && Ext.isDefined(columnIndex)) {
  46. return {
  47. node: cell,
  48. record: v.getRecord(row),
  49. fieldName: me.grid.columns[columnIndex].dataIndex
  50. };
  51. }
  52. }
  53. },
  54. // On Node enter, see if it is valid for us to drop the field on that type of column.
  55. onNodeEnter: function(target, dd, e, dragData) {
  56. delete this.dropOK;
  57. if (!target) {
  58. return;
  59. }
  60. // Check that a field is being dragged.
  61. var f = dragData.field;
  62. if (!f) {
  63. return;
  64. }
  65. // Check whether the data type of the column being dropped on accepts the
  66. // dragged field type. If so, set dropOK flag, and highlight the target node.
  67. var type = target.record.fields.get(target.fieldName).type,
  68. types = Ext.data.Types;
  69. switch(type){
  70. case types.FLOAT:
  71. case types.INT:
  72. if (!f.isXType('numberfield')) {
  73. return;
  74. }
  75. break;
  76. case types.DATE:
  77. if (!f.isXType('datefield')) {
  78. return;
  79. }
  80. break;
  81. case types.BOOL:
  82. if (!f.isXType('checkbox')) {
  83. return;
  84. }
  85. }
  86. this.dropOK = true;
  87. Ext.fly(target.node).addCls('x-drop-target-active');
  88. },
  89. // Return the class name to add to the drag proxy. This provides a visual indication
  90. // of drop allowed or not allowed.
  91. onNodeOver: function(target, dd, e, dragData) {
  92. return this.dropOK ? this.dropAllowed : this.dropNotAllowed;
  93. },
  94. // highlight the target node.
  95. onNodeOut: function(target, dd, e, dragData) {
  96. Ext.fly(target.node).removeCls('x-drop-target-active');
  97. },
  98. // Process the drop event if we have previously ascertained that a drop is OK.
  99. onNodeDrop: function(target, dd, e, dragData) {
  100. if (this.dropOK) {
  101. var value = dragData.field.getValue();
  102. target.record.set(target.fieldName, value);
  103. this.onCellDrop(target.fieldName, value);
  104. return true;
  105. }
  106. },
  107. onCellDrop: Ext.emptyFn
  108. });
  109. // A class which makes Fields within a Panel draggable.
  110. // the dragData delivered to a cooperating DropZone's methods contains
  111. // the dragged Field in the property "field".
  112. Ext.define('Ext.ux.PanelFieldDragZone', {
  113. extend: 'Ext.dd.DragZone',
  114. constructor: function(){},
  115. // Call the DRagZone's constructor. The Panel must have been rendered.
  116. init: function(panel) {
  117. if (panel.nodeType) {
  118. Ext.ux.PanelFieldDragZone.superclass.init.apply(this, arguments);
  119. } else {
  120. if (panel.rendered) {
  121. Ext.ux.PanelFieldDragZone.superclass.constructor.call(this, panel.getEl());
  122. var i = Ext.fly(panel.getEl()).select('input');
  123. i.unselectable();
  124. } else {
  125. panel.on('afterlayout', this.init, this, {single: true});
  126. }
  127. }
  128. },
  129. scroll: false,
  130. // On mousedown, we ascertain whether it is on one of our draggable Fields.
  131. // If so, we collect data about the draggable object, and return a drag data
  132. // object which contains our own data, plus a "ddel" property which is a DOM
  133. // node which provides a "view" of the dragged data.
  134. getDragData: function(e) {
  135. var t = e.getTarget('input');
  136. if (t) {
  137. e.stopEvent();
  138. // Ugly code to "detach" the drag gesture from the input field.
  139. // Without this, Opera never changes the mouseover target from the input field
  140. // even when dragging outside of the field - it just keeps selecting.
  141. if (Ext.isOpera) {
  142. Ext.fly(t).on('mousemove', function(e1){
  143. t.style.visibility = 'hidden';
  144. Ext.defer(function(){
  145. t.style.visibility = '';
  146. }, 1);
  147. }, null, {single:true});
  148. }
  149. // Get the data we are dragging: the Field
  150. // create a ddel for the drag proxy to display
  151. var f = Ext.ComponentQuery.query('field[inputEl]{inputEl.id=="' + t.id + '"}')[0];
  152. var d = document.createElement('div');
  153. d.className = 'x-form-text';
  154. d.appendChild(document.createTextNode(t.value));
  155. Ext.fly(d).setWidth(f.getEl().getWidth());
  156. return {
  157. field: f,
  158. ddel: d
  159. };
  160. }
  161. },
  162. // The coordinates to slide the drag proxy back to on failed drop.
  163. getRepairXY: function() {
  164. return this.dragData.field.getEl().getXY();
  165. }
  166. });
  167. Ext.onReady(function(){
  168. var myData = [
  169. ['3m Co',71.72,0.02,0.03,'9/1 12:00am'],
  170. ['Alcoa Inc',29.01,0.42,1.47,'9/1 12:00am'],
  171. ['Altria Group Inc',83.81,0.28,0.34,'9/1 12:00am'],
  172. ['American Express Company',52.55,0.01,0.02,'9/1 12:00am'],
  173. ['American International Group, Inc.',64.13,0.31,0.49,'9/1 12:00am'],
  174. ['AT&T Inc.',31.61,-0.48,-1.54,'9/1 12:00am'],
  175. ['Boeing Co.',75.43,0.53,0.71,'9/1 12:00am'],
  176. ['Caterpillar Inc.',67.27,0.92,1.39,'9/1 12:00am'],
  177. ['Citigroup, Inc.',49.37,0.02,0.04,'9/1 12:00am'],
  178. ['E.I. du Pont de Nemours and Company',40.48,0.51,1.28,'9/1 12:00am'],
  179. ['Exxon Mobil Corp',68.1,-0.43,-0.64,'9/1 12:00am'],
  180. ['General Electric Company',34.14,-0.08,-0.23,'9/1 12:00am'],
  181. ['General Motors Corporation',30.27,1.09,3.74,'9/1 12:00am'],
  182. ['Hewlett-Packard Co.',36.53,-0.03,-0.08,'9/1 12:00am'],
  183. ['Honeywell Intl Inc',38.77,0.05,0.13,'9/1 12:00am'],
  184. ['Intel Corporation',19.88,0.31,1.58,'9/1 12:00am'],
  185. ['International Business Machines',81.41,0.44,0.54,'9/1 12:00am'],
  186. ['Johnson & Johnson',64.72,0.06,0.09,'9/1 12:00am'],
  187. ['JP Morgan & Chase & Co',45.73,0.07,0.15,'9/1 12:00am'],
  188. ['McDonald\'s Corporation',36.76,0.86,2.40,'9/1 12:00am'],
  189. ['Merck & Co., Inc.',40.96,0.41,1.01,'9/1 12:00am'],
  190. ['Microsoft Corporation',25.84,0.14,0.54,'9/1 12:00am'],
  191. ['Pfizer Inc',27.96,0.4,1.45,'9/1 12:00am'],
  192. ['The Coca-Cola Company',45.07,0.26,0.58,'9/1 12:00am'],
  193. ['The Home Depot, Inc.',34.64,0.35,1.02,'9/1 12:00am'],
  194. ['The Procter & Gamble Company',61.91,0.01,0.02,'9/1 12:00am'],
  195. ['United Technologies Corporation',63.26,0.55,0.88,'9/1 12:00am'],
  196. ['Verizon Communications',35.57,0.39,1.11,'9/1 12:00am'],
  197. ['Wal-Mart Stores, Inc.',45.45,0.73,1.63,'9/1 12:00am']
  198. ];
  199. // example of custom renderer function
  200. function change(val){
  201. if(val > 0){
  202. return '<span style="color:green;">' + val + '</span>';
  203. }else if(val < 0){
  204. return '<span style="color:red;">' + val + '</span>';
  205. }
  206. return val;
  207. }
  208. // example of custom renderer function
  209. function pctChange(val){
  210. if(val > 0){
  211. return '<span style="color:green;">' + val + '%</span>';
  212. }else if(val < 0){
  213. return '<span style="color:red;">' + val + '%</span>';
  214. }
  215. return val;
  216. }
  217. // create the data store
  218. var store = Ext.create('Ext.data.ArrayStore', {
  219. fields: [
  220. {name: 'company', type: 'string'},
  221. {name: 'price', type: 'float'},
  222. {name: 'change', type: 'float'},
  223. {name: 'pctChange', type: 'float'},
  224. {name: 'lastChange', type: 'date', dateFormat: 'n/j h:ia'}
  225. ],
  226. data: myData
  227. });
  228. var helpWindow = Ext.create('Ext.Window', {
  229. title: 'Source code',
  230. width: 920,
  231. height: 500,
  232. closeAction: 'hide',
  233. layout: 'fit',
  234. items: {
  235. hideLabel: true,
  236. xtype: 'textarea',
  237. readOnly: true
  238. },
  239. listeners: {
  240. render: function(w) {
  241. Ext.Ajax.request({
  242. url: 'field-to-grid-dd.js',
  243. success: function(r) {
  244. w.items.first().setValue(r.responseText);
  245. }
  246. });
  247. }
  248. }
  249. });
  250. // create the Grid
  251. var grid = Ext.create('Ext.grid.Panel', {
  252. store: store,
  253. columns: [
  254. {id:'company',header: "Company", width: 160, sortable: true, dataIndex: 'company', flex: 1},
  255. {header: "Price", width: 75, sortable: true, renderer: 'usMoney', dataIndex: 'price'},
  256. {header: "Change", width: 75, sortable: true, renderer: change, dataIndex: 'change'},
  257. {header: "% Change", width: 75, sortable: true, renderer: pctChange, dataIndex: 'pctChange'},
  258. {header: "Last Updated", width: 85, sortable: true, renderer: Ext.util.Format.dateRenderer('m/d/Y'), dataIndex: 'lastChange'}
  259. ],
  260. plugins: Ext.create('Ext.ux.CellFieldDropZone', {
  261. onCellDrop: function(field){
  262. var sorter = store.sorters.first();
  263. if (sorter && sorter.property == field) {
  264. store.sort();
  265. }
  266. }
  267. }),
  268. stripeRows: true,
  269. height:350,
  270. width:600,
  271. title:'Array Grid',
  272. dockedItems: [{
  273. dock: 'bottom',
  274. xtype: 'toolbar',
  275. items: {
  276. text: 'View Source',
  277. handler: function() {
  278. helpWindow.show();
  279. }
  280. }
  281. }]
  282. });
  283. grid.render('grid-example');
  284. var f = Ext.create('Ext.Panel', {
  285. frame: true,
  286. width: 600,
  287. plugins: Ext.create('Ext.ux.PanelFieldDragZone'),
  288. labelWidth: 150,
  289. items: [{
  290. xtype: 'textfield',
  291. fieldLabel: 'Drag this text',
  292. value: 'test'
  293. },{
  294. xtype: 'numberfield',
  295. fieldLabel: 'Drag this number',
  296. value: '1.2'
  297. },{
  298. xtype: 'datefield',
  299. fieldLabel: 'Drag this date',
  300. value: new Date()
  301. }],
  302. renderTo: Ext.getBody()
  303. });
  304. });