1 // ========================================================================== 2 // Project: The M-Project - Mobile HTML5 Application Framework 3 // Copyright: (c) 2011 panacoda GmbH. All rights reserved. 4 // Creator: dominik 5 // Date: 05.12.11 6 // License: Dual licensed under the MIT or GPL Version 2 licenses. 7 // http://github.com/mwaylabs/The-M-Project/blob/master/MIT-LICENSE 8 // http://github.com/mwaylabs/The-M-Project/blob/master/GPL-LICENSE 9 // ========================================================================== 10 11 /** 12 * @class 13 * 14 * The M.TableView renders a default HTML table, that can be dynamically filled via 15 * content binding. Depending on the table's configuration, there will be a static 16 * table header, that is visible even if there is no content. It is also possible 17 * to always update the header, when applying content binding, too. 18 * 19 * @extends M.View 20 */ 21 M.TableView = M.View.extend( 22 /** @scope M.TableView.prototype */ { 23 24 /** 25 * The type of this object. 26 * 27 * @type String 28 */ 29 type: 'M.TableView', 30 31 /** 32 * Determines whether to remove all content rows if the table is updated or not. 33 * 34 * @type Boolean 35 */ 36 removeContentRowsOnUpdate: YES, 37 38 /** 39 * Determines whether to remove the header rows if the table is updated or not. 40 * 41 * @type Boolean 42 */ 43 removeHeaderRowOnUpdate: NO, 44 45 /** 46 * Determines whether the table was initialized. If this flag is set to YES, 47 * the table's header and colgroup was rendered. Depending on the table's 48 * configuration (e.g. the removeHeaderRowOnUpdate property), this flag might 49 * change dynamically at runtime. 50 * 51 * @private 52 * @type Boolean 53 */ 54 isInitialized: NO, 55 56 /** 57 * This property can be used to specify the table's header and cols, independent 58 * from dynamically loaded table content. It can be provided with the table's 59 * definition within a page component. The table's content, in contrast, can only 60 * be applied via content binding. 61 * 62 * Note: If the removeHeaderRowOnUpdate property is set to YES, the header will 63 * be removed whenever a content binding is applied. So if the header shall be 64 * statically specified by the view component, do not set that property to YES! 65 * 66 * This property should look something like the following: 67 * 68 * { 69 * data: ['col1', 'col2', 'col3'], 70 * cols: ['20%', '10%', '70%'] 71 * } 72 * 73 * Note: the cols property of this object is optional. You can also let CSS take 74 * care of the columns arrangement or simply let the browser do all the work 75 * automatically. 76 * 77 * @type Object 78 */ 79 header: null, 80 81 /** 82 * Renders a table view as a table element within a div box. 83 * 84 * @private 85 * @returns {String} The table view's html representation. 86 */ 87 render: function() { 88 this.html += '<div id="' + this.id + '_container"><table id="' + this.id +'"' + this.style() + '><thead></thead><tbody></tbody></table></div>'; 89 90 return this.html; 91 }, 92 93 /** 94 * Applies some style-attributes to the table. 95 * 96 * @private 97 * @returns {String} The table's styling as html representation. 98 */ 99 style: function() { 100 var html = ' class="tmp-table'; 101 if(this.cssClass) { 102 html += ' ' + this.cssClass; 103 } 104 html += '"' 105 return html; 106 }, 107 108 /** 109 * This method is called once the initial rendering was applied to the 110 * DOM. So this is where we will add the table's header (if there is 111 * one specified) 112 */ 113 theme: function() { 114 if(this.header) { 115 this.renderHeader(); 116 } 117 }, 118 119 /** 120 * This method renders the table's header. Based on the table's configuration, 121 * this can either happen right at the first rendering or on every content 122 * binding update. 123 * 124 * @private 125 */ 126 renderHeader: function() { 127 /* render the table header (if there is one) and define the cols */ 128 if(this.header && this.header.data) { 129 130 /* render the colgroup element (define the columns) */ 131 if(this.header.cols && this.header.cols.length > 0) { 132 html = '<colgroup>'; 133 _.each(this.header.cols, function(col) { 134 html += '<col width="' + col + '">'; 135 }); 136 html += '</colgroup>'; 137 $('#' + this.id).prepend(html); 138 } 139 140 /* render the table header */ 141 html = '<tr>'; 142 _.each(this.header.data, function(col) { 143 html += '<th class="tmp-table-th">' + (col && col.toString() ? col.toString() : '') + '</th> '; 144 }); 145 html += '</tr>'; 146 this.addRow(html, YES); 147 } 148 }, 149 150 /** 151 * Updates the table based on its content binding. This should look like the following: 152 * 153 * { 154 * header: { 155 * data: ['col1', 'col2', 'col3'], 156 * cols: ['20%', '10%', '70%'] 157 * }, 158 * content: [ 159 * [25, 'Y, 'Lorem Ipsum'], 160 * [25, 46, 'Dolor Sit'], 161 * [25, 46, 'Amet'] 162 * ] 163 * } 164 * 165 * Note: If the content binding specifies a header object, any previously rendered 166 * header (and the col definition) will be overwritten! 167 * 168 * @private 169 */ 170 renderUpdate: function() { 171 var html; 172 var content = this.value; 173 174 /* clear the table before filling it up again */ 175 if(this.removeHeaderRowOnUpdate && this.removeContentRowsOnUpdate) { 176 this.removeAllRows(); 177 } else if(this.removeContentRowsOnUpdate) { 178 this.removeContentRows(); 179 } 180 181 if(content && content.content && content.content.length > 0) { 182 183 /* render the table header (if there is one) */ 184 if(content.header && content.header.data) { 185 this.header = content.header; 186 this.renderHeader(); 187 } 188 189 /* render the table's content (row by row) */ 190 if(content.content && content.content.length > 0) { 191 var that = this; 192 var zebraFlag = 0; 193 _.each(content.content, function(row) { 194 zebraFlag = (zebraFlag === 0 ? 1 : 0); 195 html = '<tr class="tmp-table-tr-' + (zebraFlag === 1 ? 'a' : 'b') + '">'; 196 _.each(row, function(col) { 197 html += '<td class="tmp-table-td">' + (col && col.toString() ? col.toString() : '') + '</td> '; 198 }); 199 html += '</tr>'; 200 that.addRow(html); 201 }); 202 } 203 204 } 205 else { 206 M.Logger.log('The specified content binding for the table view (' + this.id + ') is invalid!', M.WARN); 207 } 208 }, 209 210 /** 211 * This method adds a new row to the table view by simply appending its html representation 212 * to the table view inside the DOM. This method is based on jQuery's append(). 213 * 214 * @param {String} row The html representation of a table row to be added. 215 * @param {Boolean} addToTableHeader Determines whether or not to add the row to the table's header. 216 */ 217 addRow: function(row, addToTableHeader) { 218 if(addToTableHeader) { 219 $('#' + this.id + ' thead').append(row); 220 } else { 221 $('#' + this.id + ' tbody').append(row); 222 } 223 }, 224 225 /** 226 * This method removes all of the table view's rows by removing all of its content in the DOM. This 227 * method is based on jQuery's empty(). 228 */ 229 removeAllRows: function() { 230 $('#' + this.id).empty(); 231 }, 232 233 /** 234 * This method removes all content rows of the table view by removing the corresponding 235 * html in the DOM. This method is based on jQuery's remove(). 236 */ 237 removeContentRows: function() { 238 $('#' + 'm_3' + ' tr td').parent().remove(); 239 } 240 241 });