├── Ext.ux.TouchGridPanel.css ├── Ext.ux.TouchGridPanel.js ├── LICENSE ├── README ├── index.html ├── main.js ├── sort_asc.gif └── sort_desc.gif /Ext.ux.TouchGridPanel.css: -------------------------------------------------------------------------------- 1 | .x-grid-header { 2 | width: 100%; 3 | 4 | margin-right: 4px; 5 | 6 | background-image: -webkit-gradient(linear, 0% 0%, 0% 100%, color-stop(0%, #9aa7b2), color-stop(2%, #647482), color-stop(100%, #434d57)); 7 | } 8 | .x-grid-row { 9 | border-top: 1px solid #000; 10 | border-bottom: 1px solid #000; 11 | } 12 | .x-grid-row:nth-child(even) { 13 | background-color: #ffffff; 14 | } 15 | .x-grid-row:nth-child(odd) { 16 | background-color: #f0f0f0; 17 | } 18 | .x-grid-hd-cell { 19 | text-align: center; 20 | color: #FFF; 21 | text-shadow: rgba(0, 0, 0, 0.5) 0 -0.08em 0; 22 | } 23 | .x-grid-hd-cell[sort$=ASC] { 24 | background: url('sort_asc.gif') no-repeat right center; 25 | } 26 | .x-grid-hd-cell[sort$=DESC] { 27 | background: url('sort_desc.gif') no-repeat right center; 28 | } 29 | .x-grid-cell { 30 | line-height:15px; 31 | vertical-align:middle; 32 | line-height: 2em; 33 | font-size: 1em; 34 | font-weight: bold; 35 | border-left: 1px solid #000; 36 | border-right: 1px solid #000; 37 | } 38 | .x-grid-cell-no-of { 39 | overflow:hidden; 40 | text-overflow: ellipsis; 41 | white-space: nowrap; 42 | } 43 | .x-grid-cell-del-btn { 44 | padding-top: 1px; 45 | padding-left: 0.5em; 46 | } 47 | 48 | .x-grid-col-hidden { 49 | display: none; 50 | } 51 | 52 | .x-item-selected { 53 | -webkit-transform: translate3d(0, 0, 0); 54 | background-image: -webkit-gradient(linear, 0% 0%, 0% 100%, color-stop(0%, #7fb6e7), color-stop(2%, #2986d6), color-stop(100%, #1d5e96)); 55 | background-image: linear-gradient(top, #7fb6e7 0%, #2986d6 2%, #1d5e96 100%); 56 | color: #fff; 57 | border-color: #103656; 58 | text-shadow: 0 1px 0 rgba(0, 0, 0, 0.5); 59 | } 60 | -------------------------------------------------------------------------------- /Ext.ux.TouchGridPanel.js: -------------------------------------------------------------------------------- 1 | /* 2 | * Because of limitation of the current WebKit implementation of CSS3 column layout, 3 | * I have decided to revert back to using table. 4 | */ 5 | 6 | Ext.ns("Ext.ux"); 7 | 8 | Ext.ux.TouchGridPanel = Ext.extend(Ext.Panel, { 9 | layout : "fit", 10 | 11 | multiSelect : false, 12 | scroll : "vertical", 13 | 14 | initComponent : function() { 15 | var me = this; 16 | 17 | me.items = me.dataview = me.buildDataView(); 18 | 19 | if (!Ext.isArray(me.dockedItems)) { 20 | me.dockedItems = []; 21 | } 22 | 23 | me.header = new Ext.Component(me.buildHeader()); 24 | me.dockedItems.push(me.header); 25 | 26 | Ext.ux.TouchGridPanel.superclass.initComponent.call(me); 27 | 28 | var store = me.store; 29 | 30 | store.on("update", me.dispatchDataChanged, me); 31 | }, 32 | 33 | dispatchDataChanged: function(store, rec, operation) { 34 | var me = this; 35 | 36 | me.fireEvent("storeupdate", store, rec, operation); 37 | }, 38 | 39 | buildHeader : function() { 40 | var me = this, 41 | colModel = me.colModel, 42 | colNum = me.getColNum(false), 43 | cellWidth = 100/colNum, 44 | colTpl = ''; 45 | 46 | colTpl += ' '; 47 | for (var i = 0; i < colModel.length; i++) { 48 | var col = colModel[i], 49 | flex = col.flex || 1, 50 | cls = ""; 51 | 52 | var width = flex * cellWidth; 53 | 54 | if (col.hidden) { 55 | cls += "x-grid-col-hidden"; 56 | } 57 | 58 | colTpl += ''; 59 | } 60 | colTpl += ' '; 61 | colTpl += '
' + col.header + '
'; 62 | 63 | return { 64 | dock : "top", 65 | html : colTpl, 66 | listeners : { 67 | scope : me, 68 | afterrender : me.initHeaderEvents 69 | } 70 | }; 71 | }, 72 | 73 | initHeaderEvents: function(cmp) { 74 | var me = this, 75 | el = cmp.getEl(); 76 | 77 | el.on("click", me.handleHeaderClick, me); 78 | }, 79 | 80 | handleHeaderClick: function(e, t) { 81 | e.stopEvent(); 82 | 83 | var me = this, 84 | el = Ext.get(t), 85 | mapping = el.getAttribute("mapping"); 86 | 87 | if (typeof mapping === "string") { 88 | me.store.sort(mapping); 89 | el.set({ 90 | sort : me.store.sortToggle[mapping] 91 | }); 92 | } 93 | }, 94 | 95 | buildDataView : function() { 96 | var me = this, 97 | colModel = me.colModel, 98 | colNum = me.getColNum(false), 99 | colTpl = '', 100 | cellWidth = 100/colNum; 101 | 102 | for (var i = 0; i < colModel.length; i++) { 103 | var col = colModel[i], 104 | flex = col.flex || 1, 105 | width = flex * cellWidth, 106 | style = (i === colModel.length - 1) ? "padding-right: 10px;" : "", 107 | cls = col.cls || ""; 108 | 109 | style += col.style || ""; 110 | 111 | if (col.hidden) { 112 | cls += "x-grid-col-hidden"; 113 | } 114 | 115 | colTpl += '{' + col.mapping + '}'; 116 | } 117 | colTpl += ''; 118 | 119 | return new Ext.DataView({ 120 | store : me.store, 121 | itemSelector : "tr.x-grid-row", 122 | simpleSelect : me.multiSelect, 123 | scroll : me.scroll, 124 | tpl : new Ext.XTemplate( 125 | '', 126 | '', 127 | colTpl, 128 | '', 129 | '
', 130 | { 131 | isRowDirty: function(dirty, data) { 132 | return dirty ? "x-grid-row-dirty" : ""; 133 | }, 134 | isCellDirty: function(dirty, data) { 135 | return dirty ? "x-grid-cell-dirty" : ""; 136 | } 137 | } 138 | ), 139 | prepareData : function(data, index, record) { 140 | var column, 141 | i = 0, 142 | ln = colModel.length; 143 | var prepare_data = {}; 144 | prepare_data.dirtyFields = {}; 145 | for (; i < ln; i++) { 146 | 147 | column = colModel[i]; 148 | if (typeof column.renderer === "function") { 149 | prepare_data[column.mapping] = column.renderer.apply(me, [data[column.mapping],column, record, index]); 150 | } else { 151 | prepare_data[column.mapping] = data[column.mapping]; 152 | } 153 | } 154 | 155 | prepare_data.isDirty = record.dirty; 156 | 157 | prepare_data.rowIndex = index; 158 | return prepare_data; 159 | }, 160 | bubbleEvents : [ 161 | "beforeselect", 162 | "containertap", 163 | "itemdoubletap", 164 | "itemswipe", 165 | "itemtap", 166 | "selectionchange" 167 | ] 168 | }); 169 | }, 170 | 171 | // hidden = true to count all columns 172 | getColNum : function(hidden) { 173 | var me = this, 174 | colModel = me.colModel, 175 | colNum = 0; 176 | 177 | for (var i = 0; i < colModel.length; i++) { 178 | var col = colModel[i]; 179 | if (!hidden && typeof col.header !== "string") { continue; } 180 | if (!col.hidden) { 181 | colNum += col.flex || 1; 182 | } 183 | } 184 | 185 | return colNum; 186 | }, 187 | 188 | getMappings: function() { 189 | var me = this, 190 | mappings = {}, 191 | colModel = me.colModel; 192 | 193 | for (var i = 0; i < colModel.length; i++) { 194 | mappings[colModel[i].mapping] = i 195 | } 196 | 197 | return mappings; 198 | }, 199 | 200 | toggleColumn: function(index) { 201 | var me = this; 202 | 203 | if (typeof index === "string") { 204 | var mappings = me.getMappings(); 205 | index = mappings[index]; 206 | } 207 | var el = me.getEl(), 208 | mapping = me.colModel[index].mapping, 209 | cells = el.query("td.x-grid-col-"+mapping); 210 | 211 | for (var c = 0; c < cells.length; c++) { 212 | var cellEl = Ext.get(cells[c]); 213 | if (cellEl.hasCls("x-grid-col-hidden")) { 214 | cellEl.removeCls("x-grid-col-hidden"); 215 | this.colModel[index].hidden = false; 216 | } else { 217 | cellEl.addCls("x-grid-col-hidden"); 218 | this.colModel[index].hidden = true; 219 | } 220 | } 221 | 222 | me.updateWidths(); 223 | }, 224 | 225 | updateWidths: function() { 226 | var me = this, 227 | el = me.getEl(), 228 | headerWidth = me.header.getEl().getWidth(), 229 | colModel = me.colModel, 230 | cells = el.query("td.x-grid-cell"), 231 | colNum = me.getColNum(false), 232 | cellWidth = 100 / colNum, 233 | mappings = me.getMappings(); 234 | 235 | for (var c = 0; c < cells.length; c++) { 236 | var cellEl = Ext.get(cells[c]), 237 | mapping = cellEl.getAttribute("mapping"), 238 | col = colModel[mappings[mapping]], 239 | flex = col.flex || 1, 240 | width = flex * cellWidth / 100 * headerWidth; 241 | 242 | cellEl.setWidth(width); 243 | } 244 | }, 245 | 246 | scrollToRow: function(index) { 247 | var me = this, 248 | el = me.getEl(), 249 | rows = el.query("tr.x-grid-row"), 250 | rowEl = Ext.get(rows[index]), 251 | scroller = me.dataview.scroller; 252 | 253 | var pos = { 254 | x: 0, 255 | y: rowEl.dom.offsetTop 256 | }; 257 | 258 | scroller.scrollTo(pos, true); 259 | }, 260 | 261 | getView: function() { 262 | var me = this; 263 | 264 | return me.dataview; 265 | }, 266 | 267 | bindStore: function(store) { 268 | var me = this, 269 | view = me.getView(); 270 | 271 | view.bindStore(store); 272 | }, 273 | 274 | getStore: function() { 275 | var me = this, 276 | view = me.getView(); 277 | 278 | return view.getStore(); 279 | }, 280 | 281 | getRow: function(index) { 282 | var me = this; 283 | if (typeof index === "object") { 284 | var store = me.getStore(), 285 | index = store.indexOf(index); 286 | } 287 | 288 | var el = me.getEl(), 289 | rows = el.query("tr"); 290 | 291 | return rows[index+1]; 292 | } 293 | }); 294 | 295 | Ext.reg("touchgridpanel", Ext.ux.TouchGridPanel); -------------------------------------------------------------------------------- /LICENSE: -------------------------------------------------------------------------------- 1 | /* 2 | Author : Mitchell Simoens 3 | Site : http://simoens.org/Sencha-Projects/demos/ 4 | Contact Info : mitchellsimoens@gmail.com 5 | Purpose : Creation of a grid for Sencha Touch 6 | 7 | License : MIT (http://www.opensource.org/licenses/mit-license.php) 8 | Warranty : none 9 | Price : free 10 | Version : 2.0b2 11 | Date : 3/22/2011 12 | */ -------------------------------------------------------------------------------- /README: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/mitchellsimoens/Ext.ux.TouchGridPanel/be986e5384157d833ce94f6ce6e1bed731f5b20d/README -------------------------------------------------------------------------------- /index.html: -------------------------------------------------------------------------------- 1 | 3 | 4 | 5 | 6 | Sencha Touch GridPanel 7 | 8 | 9 | 10 | 11 | 12 | 13 | 14 | 15 | 16 | 17 | 18 | 19 | 20 | 21 | -------------------------------------------------------------------------------- /main.js: -------------------------------------------------------------------------------- 1 | Ext.setup({ 2 | tabletStartupScreen : "/images/tablet_startup.png", 3 | phoneStartupScreen : "phone_startup.png", 4 | icon : "icon.png", 5 | glossOnIcon : true, 6 | onReady : function() { 7 | var deleteConfirm; 8 | Ext.regModel("TestModel", { 9 | fields : [ 10 | "company", 11 | "price", 12 | "change", 13 | "pct", 14 | "updated" 15 | ] 16 | }); 17 | var store = new Ext.data.Store({ 18 | model : "TestModel", 19 | data : [ 20 | { company : "3m Co", price : 71.72, change : 0.02, pct : 0.03, updated : "9/1/2010" }, 21 | { company : "Alcoa Inc", price : 29.01, change : 0.42, pct : 1.47, updated : "9/1/2010" }, 22 | { company : "Altria Group Inc", price : 83.81, change : 0.28, pct : 0.34, updated : "9/1/2010" }, 23 | { company : "American Express Company", price : 52.55, change : 0.01, pct : 0.02, updated : "9/1/2010" }, 24 | { company : "American International Group, Inc.", price : 64.13, change : 0.31, pct : 0.49, updated : "9/1/2010" }, 25 | { company : "AT&T Inc.", price : 31.61, change : -0.48, pct : -1.54, updated : "9/1/2010" }, 26 | { company : "Boeing Co.", price : 75.43, change : 0.53, pct : 0.71, updated : "9/1/2010" }, 27 | { company : "Caterpillar Inc.", price : 67.27, change : 0.92, pct : 1.39, updated : "9/1/2010" }, 28 | { company : "Citigroup, Inc.", price : 49.37, change : 0.02, pct : 0.04, updated : "9/1/2010" }, 29 | { company : "E.I. du Pont de Nemours and Company", price : 40.48, change : 0.51, pct : 1.28, updated : "9/1/2010" }, 30 | { company : "Exxon Mobil Corp", price : 68.1, change : -0.43, pct : -0.64, updated : "9/1/2010" }, 31 | { company : "General Electric Company", price : 34.14, change : -0.08, pct : -0.23, updated : "9/1/2010" }, 32 | { company : "General Motors Corporation", price : 30.27, change : 1.09, pct : 3.74, updated : "9/1/2010" }, 33 | { company : "Hewlett-Packard Co.", price : 36.53, change : -0.03, pct : -0.08, updated : "9/1/2010" }, 34 | { company : "Honeywell Intl Inc", price : 38.77, change : 0.05, pct : 0.13, updated : "9/1/2010" }, 35 | { company : "Intel Corporation", price : 19.88, change : 0.31, pct : 1.58, updated : "9/1/2010" }, 36 | { company : "International Business Machines", price : 81.41, change : 0.44, pct : 0.54, updated : "9/1/2010" }, 37 | { company : "Johnson & Johnson", price : 64.72, change : 0.06, pct : 0.09, updated : "9/1/2010" }, 38 | { company : "JP Morgan & Chase & Co", price : 45.73, change : 0.07, pct : 0.15, updated : "9/1/2010" }, 39 | { company : "McDonald's Corporation", price : 36.76, change : 0.86, pct : 2.40, updated : "9/1/2010" }, 40 | { company : "Merck & Co., Inc.", price : 40.96, change : 0.41, pct : 1.01, updated : "9/1/2010" }, 41 | { company : "Microsoft Corporation", price : 25.84, change : 0.14, pct : 0.54, updated : "9/1/2010" }, 42 | { company : "Pfizer Inc", price : 27.96, change : 0.4, pct : 1.45, updated : "9/1/2010" }, 43 | { company : "The Coca-Cola Company", price : 45.07, change : 0.26, pct : 0.58, updated : "9/1/2010" }, 44 | { company : "The Home Depot, Inc.", price : 34.64, change : 0.35, pct : 1.02, updated : "9/1/2010" }, 45 | { company : "The Procter & Gamble Company", price : 61.91, change : 0.01, pct : 0.02, updated : "9/1/2010" }, 46 | { company : "United Technologies Corporation", price : 63.26, change : 0.55, pct : 0.88, updated : "9/1/2010" }, 47 | { company : "Verizon Communications", price : 35.57, change : 0.39, pct : 1.11, updated : "9/1/2010" }, 48 | { company : "Wal-Mart Stores, Inc.", price : 45.45, change : 0.73, pct : 1.63, updated : "9/1/2010" } 49 | ] 50 | }); 51 | 52 | var grid = new Ext.ux.TouchGridPanel({ 53 | fullscreen : true, 54 | store : store, 55 | multiSelect : false, 56 | dockedItems : [{ 57 | xtype : "toolbar", 58 | dock : "top", 59 | title : "Ext.ux.TouchGridPanel by Mitchell Simoens" 60 | }], 61 | colModel : [{ 62 | header : "Company", 63 | mapping : "company", 64 | flex : 2 65 | },{ 66 | header : "Price", 67 | mapping : "price", 68 | style : "text-align: center;" 69 | },{ 70 | header : "Change", 71 | mapping : "change", 72 | cls : "centered-cell", 73 | renderer : function(val) { 74 | var color = (val > 0) ? "00FF00" : "FF0000"; 75 | return "" + val + ""; 76 | } 77 | /*},{ 78 | header : "% Change", 79 | mapping : "pct", 80 | cls : "centered-cell"*/ 81 | },{ 82 | header : "Last Updated", 83 | mapping : "updated", 84 | hidden : true, 85 | style : "text-align: right;" 86 | }], 87 | listeners: { 88 | beforeselect: function(dataview, nodes, selections) { 89 | console.log(selections); 90 | }, 91 | containertap: function(dataview, e) { 92 | console.log(dataview); 93 | }, 94 | itemdoubletap: function(dataview, index, el, e) { 95 | console.log(index); 96 | }, 97 | itemswipe: function(dataview, index, el, e) { 98 | console.log(index); 99 | }, 100 | itemtap: function(dataview, index, el, e) { 101 | console.log(index); 102 | }, 103 | selectionchange: function(selectionModel, selections) { 104 | console.log(selections); 105 | } 106 | } 107 | }); 108 | } 109 | }); -------------------------------------------------------------------------------- /sort_asc.gif: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/mitchellsimoens/Ext.ux.TouchGridPanel/be986e5384157d833ce94f6ce6e1bed731f5b20d/sort_asc.gif -------------------------------------------------------------------------------- /sort_desc.gif: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/mitchellsimoens/Ext.ux.TouchGridPanel/be986e5384157d833ce94f6ce6e1bed731f5b20d/sort_desc.gif --------------------------------------------------------------------------------