浏览代码

Merge branch 'master' of https://github.com/wenzhixin/bootstrap-table into issue-894

Conflicts:
	src/bootstrap-table.js
jtrumbull 10 年之前
父节点
当前提交
b97de79383

+ 1 - 1
CHANGELOG.md

@@ -1,6 +1,6 @@
 ## ChangeLog
 ## ChangeLog
 
 
-###
+### 1.8.0
 
 
 - [bug] Fix #672: Column Fixed Width in Percentage bug.
 - [bug] Fix #672: Column Fixed Width in Percentage bug.
 - [enh] Added state saving for visible columns and the ability to use extension with multiple simultaneous tables.
 - [enh] Added state saving for visible columns and the ability to use extension with multiple simultaneous tables.

+ 30 - 0
docs/_i18n/en/documentation/events.md

@@ -94,6 +94,24 @@
         </td>
         </td>
     </tr>
     </tr>
     <tr>
     <tr>
+        <td>onCheckSome</td>
+        <td>check-some.bs.table</td>
+        <td>rows</td>
+        <td>
+        Fires when user check some rows, the parameters contains: <br>
+        rows: array of records corresponding to previously checked rows.
+        </td>
+    </tr>
+    <tr>
+        <td>onUncheckSome</td>
+        <td>uncheck-some.bs.table</td>
+        <td>rows</td>
+        <td>
+        Fires when user uncheck some rows, the parameters contains: <br>
+        rows: array of records corresponding to previously checked rows.
+        </td>
+    </tr>
+    <tr>
         <td>onLoadSuccess</td>
         <td>onLoadSuccess</td>
         <td>load-success.bs.table</td>
         <td>load-success.bs.table</td>
         <td>data</td>
         <td>data</td>
@@ -155,5 +173,17 @@
        <td>none</td>
        <td>none</td>
        <td>Fires after the table header is rendered and availble in the DOM</td>
        <td>Fires after the table header is rendered and availble in the DOM</td>
     </tr>
     </tr>
+    <tr>
+        <td>onExpandRow</td>
+        <td>expand-row.bs.table</td>
+        <td>index, row, $detail</td>
+        <td>Fires when click the detail icon to expand the detail view.</td>
+    </tr>
+    <tr>
+       <td>onCollapseRow</td>
+       <td>collapse-row.bs.table</td>
+       <td>index, row</td>
+       <td>Fires when click the detail icon to collapse the detail view.</td>
+    </tr>
     </tbody>
     </tbody>
 </table>
 </table>

+ 10 - 0
docs/_i18n/en/documentation/methods.md

@@ -129,6 +129,16 @@ The calling method syntax: `$('#table').bootstrapTable('method', parameter);`.
         </td>
         </td>
     </tr>
     </tr>
     <tr>
     <tr>
+        <td>updateCell</td>
+        <td>params</td>
+        <td>
+        Update one cell, the params contains following properties: <br>
+        rowIndex: the row index. <br>
+        fieldName: the field name.<br>
+        fieldValue: the new field value. <br>
+        </td>
+    </tr>
+    <tr>
         <td>refresh</td>
         <td>refresh</td>
         <td>params</td>
         <td>params</td>
         <td>Refresh the remote server data, you can set <code>{silent: true}</code> to refresh the data silently, and set <code>{url: newUrl}</code> to change the url. To supply query params specific to this request, set <code>{query: {foo: 'bar'}}</code></td>
         <td>Refresh the remote server data, you can set <code>{silent: true}</code> to refresh the data silently, and set <code>{url: newUrl}</code> to change the url. To supply query params specific to this request, set <code>{query: {foo: 'bar'}}</code></td>

+ 14 - 0
docs/_i18n/en/documentation/table-options.md

@@ -332,6 +332,20 @@ The table options is defined in `jQuery.fn.bootstrapTable.defaults`.
         <td>True to show card view table, for example mobile view.</td>
         <td>True to show card view table, for example mobile view.</td>
     </tr>
     </tr>
     <tr>
     <tr>
+        <td>detailView</td>
+        <td>data-detail-view</td>
+        <td>Boolean</td>
+        <td>false</td>
+        <td>True to show detail view table.</td>
+    </tr>
+    <tr>
+        <td>detailFormatter</td>
+        <td>data-detail-formatter</td>
+        <td>Function</td>
+        <td>function(index, row) {<br>return '';<br>}</td>
+        <td>Format your detail view when <code>detailView</code> is set to <code>true</code>.</td>
+    </tr>
+    <tr>
         <td>searchAlign</td>
         <td>searchAlign</td>
         <td>data-search-align</td>
         <td>data-search-align</td>
         <td>String</td>
         <td>String</td>

+ 39 - 5
docs/_i18n/es/documentation/events.md

@@ -71,20 +71,40 @@
         <td>row</td>
         <td>row</td>
         <td>
         <td>
         Se ejecuta cuando el usuario des-chequea una fila, los parámetros contienen: <br>
         Se ejecuta cuando el usuario des-chequea una fila, los parámetros contienen: <br>
-        row: el registro que corresponde a la fila des-chequeada.
+        row: el registro que corresponde a la fila deschequeada.
         </td>
         </td>
     </tr>
     </tr>
     <tr>
     <tr>
         <td>onCheckAll</td>
         <td>onCheckAll</td>
         <td>check-all.bs.table</td>
         <td>check-all.bs.table</td>
-        <td>none</td>
-        <td>Fires when user check all rows.</td>
+        <td>rows</td>
+        <td>Se ejecuta cuando el usuario chequea todas las filas, los parámetros contienen: <br>
+        rows: arreglo de las filas chequeadas.</td>
     </tr>
     </tr>
     <tr>
     <tr>
         <td>onUncheckAll</td>
         <td>onUncheckAll</td>
         <td>uncheck-all.bs.table</td>
         <td>uncheck-all.bs.table</td>
-        <td>none</td>
-        <td>Se ejecuta cuando el usuario des-chequea todas las filas.</td>
+        <td>rows</td>
+        <td>Se ejecuta cuando el usuario des-chequea todas las filas, los parámetros contienen: <br>
+        rows: arreglo de las filas deschequeadas.</td>
+    </tr>
+    <tr>
+        <td>onCheckSome</td>
+        <td>check-some.bs.table</td>
+        <td>rows</td>
+        <td>
+        Se ejecuta cuando el usuario chequea algunas filas, los parámetros contienen: <br>
+        rows: arreglo de las filas chequeadas.
+        </td>
+    </tr>
+    <tr>
+        <td>onUncheckSome</td>
+        <td>uncheck-some.bs.table</td>
+        <td>rows</td>
+        <td>
+        Se ejecuta cuando el usuario deschequea algunas filas, los parámetros contienen: <br>
+        rows: arreglo de las filas deschequeadas.
+        </td>
     </tr>
     </tr>
     <tr>
     <tr>
         <td>onLoadSuccess</td>
         <td>onLoadSuccess</td>
@@ -140,5 +160,19 @@
        <td>none</td>
        <td>none</td>
        <td>Se ejecuta después de que el encabezado es renderizado y disponible en el DOM.</td>
        <td>Se ejecuta después de que el encabezado es renderizado y disponible en el DOM.</td>
     </tr>
     </tr>
+    <tr>
+        <td>onExpandRow</td>
+        <td>expand-row.bs.table</td>
+        <td>index, row, $detail</td>
+        <td>Se ejecuta cuando se da click al icono de detalle para expandir la vista detalle.</td>
+    </tr>
+    <tr>
+       <td>onCollapseRow</td>
+       <td>collapse-row.bs.table</td>
+       <td>index, row</td>
+       <td>Se ejecuta cuando se da click al icono de detalle para colapsar la vista detalle.</td>
+    </tr>
+    </tbody>
+</table>
     </tbody>
     </tbody>
 </table>
 </table>

+ 10 - 0
docs/_i18n/es/documentation/methods.md

@@ -125,6 +125,16 @@ Sintaxis para llamar a un método: `$('#table').bootstrapTable('method', paramet
         </td>
         </td>
     </tr>
     </tr>
     <tr>
     <tr>
+        <td>updateCell</td>
+        <td>params</td>
+        <td>
+        Actualiza una celda, los parámetros contienen: <br>
+        rowIndex: índice de la fila. <br>
+        fieldName: el nombre del campo.<br>
+        fieldValue: el nuevo valor de la celda. <br>
+        </td>
+    </tr>
+    <tr>
         <td>refresh</td>
         <td>refresh</td>
         <td>params</td>
         <td>params</td>
         <td>Refresca los datos remotos del servidor, se puede setear <code>{silent: true}</code> para refrescar los datos silenciosamente, y setear <code>{url: newUrl}</code> para cambiar el URL. Para suministrar query params especificos para este request, setear <code>{query: {foo: 'bar'}}</code></td>
         <td>Refresca los datos remotos del servidor, se puede setear <code>{silent: true}</code> para refrescar los datos silenciosamente, y setear <code>{url: newUrl}</code> para cambiar el URL. Para suministrar query params especificos para este request, setear <code>{query: {foo: 'bar'}}</code></td>

+ 14 - 0
docs/_i18n/es/documentation/table-options.md

@@ -315,6 +315,20 @@ Las opciones de la tabla están definidas en `jQuery.fn.bootstrapTable.defaults`
         <td>True para mostrar la vista de tarjeta, por ejemplo en móviles.</td>
         <td>True para mostrar la vista de tarjeta, por ejemplo en móviles.</td>
     </tr>
     </tr>
     <tr>
     <tr>
+        <td>detailView</td>
+        <td>data-detail-view</td>
+        <td>Boolean</td>
+        <td>false</td>
+        <td>True para mostrar la vista detalle en la tabla.</td>
+    </tr>
+    <tr>
+        <td>detailFormatter</td>
+        <td>data-detail-formatter</td>
+        <td>Function</td>
+        <td>function(index, row) {<br>return '';<br>}</td>
+        <td>Formatee su vista detalle cuando <code>detailView</code> está seteada en <code>true</code>.</td>
+    </tr>
+    <tr>
         <td>searchAlign</td>
         <td>searchAlign</td>
         <td>data-search-align</td>
         <td>data-search-align</td>
         <td>String</td>
         <td>String</td>

+ 32 - 0
docs/_i18n/zh-cn/documentation/events.md

@@ -94,6 +94,24 @@
         </td>
         </td>
     </tr>
     </tr>
     <tr>
     <tr>
+        <td>onCheckSome</td>
+        <td>check-some.bs.table</td>
+        <td>rows</td>
+        <td>
+        Fires when user check some rows, the parameters contains: <br>
+        rows: array of records corresponding to previously checked rows.
+        </td>
+    </tr>
+    <tr>
+        <td>onUncheckSome</td>
+        <td>uncheck-some.bs.table</td>
+        <td>rows</td>
+        <td>
+        Fires when user uncheck some rows, the parameters contains: <br>
+        rows: array of records corresponding to previously checked rows.
+        </td>
+    </tr>
+    <tr>
         <td>onLoadSuccess</td>
         <td>onLoadSuccess</td>
         <td>load-success.bs.table</td>
         <td>load-success.bs.table</td>
         <td>data</td>
         <td>data</td>
@@ -155,5 +173,19 @@
        <td>none</td>
        <td>none</td>
        <td>Fires after the table header is rendered and availble in the DOM</td>
        <td>Fires after the table header is rendered and availble in the DOM</td>
     </tr>
     </tr>
+    <tr>
+        <td>onExpandRow</td>
+        <td>expand-row.bs.table</td>
+        <td>index, row, $detail</td>
+        <td>当点击详细图标展开详细页面的时候触发。</td>
+    </tr>
+    <tr>
+       <td>onCollapseRow</td>
+       <td>collapse-row.bs.table</td>
+       <td>index, row</td>
+       <td>当点击详细图片收起详细页面的时候触发。</td>
+    </tr>
+    </tbody>
+</table>
     </tbody>
     </tbody>
 </table>
 </table>

+ 10 - 0
docs/_i18n/zh-cn/documentation/methods.md

@@ -108,6 +108,16 @@ The calling method syntax: `$('#table').bootstrapTable('method', parameter);`.
         </td>
         </td>
     </tr>
     </tr>
     <tr>
     <tr>
+        <td>updateCell</td>
+        <td>params</td>
+        <td>
+        Update one cell, the params contains following properties: <br>
+        rowIndex: the row index. <br>
+        fieldName: the field name.<br>
+        fieldValue: the new field value. <br>
+        </td>
+    </tr>
+    <tr>
         <td>refresh</td>
         <td>refresh</td>
         <td>params</td>
         <td>params</td>
         <td>Refresh the remote server data, you can set <code>{silent: true}</code> to refresh the data silently, and set <code>{url: newUrl}</code> to change the url. To supply query params specific to this request, set <code>{query: {foo: 'bar'}}</code></td>
         <td>Refresh the remote server data, you can set <code>{silent: true}</code> to refresh the data silently, and set <code>{url: newUrl}</code> to change the url. To supply query params specific to this request, set <code>{query: {foo: 'bar'}}</code></td>

+ 14 - 0
docs/_i18n/zh-cn/documentation/table-options.md

@@ -332,6 +332,20 @@ The table options is defined in `jQuery.fn.bootstrapTable.defaults`.
         <td>True to show card view table, for example mobile view.</td>
         <td>True to show card view table, for example mobile view.</td>
     </tr>
     </tr>
     <tr>
     <tr>
+        <td>detailView</td>
+        <td>data-detail-view</td>
+        <td>Boolean</td>
+        <td>false</td>
+        <td>设置为 True 可以显示详细页面模式。</td>
+    </tr>
+    <tr>
+        <td>detailFormatter</td>
+        <td>data-detail-formatter</td>
+        <td>Function</td>
+        <td>function(index, row) {<br>return '';<br>}</td>
+        <td>格式化详细页面模式的视图。</td>
+    </tr>
+    <tr>
         <td>searchAlign</td>
         <td>searchAlign</td>
         <td>data-search-align</td>
         <td>data-search-align</td>
         <td>String</td>
         <td>String</td>

+ 3 - 1
docs/extensions.md

@@ -25,4 +25,6 @@ lead: pages.extensions.lead
 
 
 {% tf extensions/filtercontrol.md %}
 {% tf extensions/filtercontrol.md %}
 
 
-{% tf extensions/naturalsorting.md %}
+{% tf extensions/naturalsorting.md %}
+
+{% tf extensions/toolbar.md %}

+ 4 - 0
src/bootstrap-table.css

@@ -96,6 +96,10 @@
     padding-right: 30px;
     padding-right: 30px;
 }
 }
 
 
+.fixed-table-container th.detail {
+    width: 30px;
+}
+
 .fixed-table-container tbody td {
 .fixed-table-container tbody td {
     border-left: 1px solid #dddddd;
     border-left: 1px solid #dddddd;
 }
 }

+ 121 - 58
src/bootstrap-table.js

@@ -211,6 +211,10 @@
         idField: undefined,
         idField: undefined,
         uniqueId: undefined,
         uniqueId: undefined,
         cardView: false,
         cardView: false,
+        detailView: false,
+        detailFormatter: function (index, row) {
+            return '';
+        },
         trimOnSearch: true,
         trimOnSearch: true,
         clickToSelect: false,
         clickToSelect: false,
         singleSelect: false,
         singleSelect: false,
@@ -263,10 +267,16 @@
         onUncheck: function (row) {
         onUncheck: function (row) {
             return false;
             return false;
         },
         },
-        onCheckAll: function () {
+        onCheckAll: function (rows) {
+            return false;
+        },
+        onUncheckAll: function (rows) {
+            return false;
+        },
+        onCheckSome: function(rows){
             return false;
             return false;
         },
         },
-        onUncheckAll: function () {
+        onUncheckSome: function(rows){
             return false;
             return false;
         },
         },
         onLoadSuccess: function (data) {
         onLoadSuccess: function (data) {
@@ -296,10 +306,10 @@
         onPostHeader: function () {
         onPostHeader: function () {
             return false;
             return false;
         },
         },
-        onPreRows: function () {
+        onExpandRow: function (index, row, $detail) {
             return false;
             return false;
         },
         },
-        onPostRows: function () {
+        onCollapseRow: function (index, row) {
             return false;
             return false;
         }
         }
     };
     };
@@ -379,6 +389,8 @@
         'uncheck.bs.table': 'onUncheck',
         'uncheck.bs.table': 'onUncheck',
         'check-all.bs.table': 'onCheckAll',
         'check-all.bs.table': 'onCheckAll',
         'uncheck-all.bs.table': 'onUncheckAll',
         'uncheck-all.bs.table': 'onUncheckAll',
+        'check-some.bs.table': 'onCheckSome',
+        'uncheck-some.bs.table': 'onUncheckSome',
         'load-success.bs.table': 'onLoadSuccess',
         'load-success.bs.table': 'onLoadSuccess',
         'load-error.bs.table': 'onLoadError',
         'load-error.bs.table': 'onLoadError',
         'column-switch.bs.table': 'onColumnSwitch',
         'column-switch.bs.table': 'onColumnSwitch',
@@ -388,8 +400,8 @@
         'pre-body.bs.table': 'onPreBody',
         'pre-body.bs.table': 'onPreBody',
         'post-body.bs.table': 'onPostBody',
         'post-body.bs.table': 'onPostBody',
         'post-header.bs.table': 'onPostHeader',
         'post-header.bs.table': 'onPostHeader',
-        'pre-rows.bs.table': 'onPreRows',
-        'post-rows.bs.table': 'onPostRows'
+        'expand-row.bs.table': 'onExpandRow',
+        'collapse-row.bs.table': 'onCollapseRow'
     };
     };
 
 
     BootstrapTable.prototype.init = function () {
     BootstrapTable.prototype.init = function () {
@@ -426,16 +438,23 @@
             '</div>'].join(''));
             '</div>'].join(''));
 
 
         this.$container.insertAfter(this.$el);
         this.$container.insertAfter(this.$el);
-        this.$container.find('.fixed-table-body').append(this.$el);
+        this.$tableContainer = this.$container.find('.fixed-table-container');
+        this.$tableHeader = this.$container.find('.fixed-table-header');
+        this.$tableBody = this.$container.find('.fixed-table-body');
+        this.$tableLoading = this.$container.find('.fixed-table-loading');
+        this.$tableFooter = this.$container.find('.fixed-table-footer');
+        this.$toolbar = this.$container.find('.fixed-table-toolbar');
+        this.$pagination = this.$container.find('.fixed-table-pagination');
+
+        this.$tableBody.append(this.$el);
         this.$container.after('<div class="clearfix"></div>');
         this.$container.after('<div class="clearfix"></div>');
-        this.$loading = this.$container.find('.fixed-table-loading');
 
 
         this.$el.addClass(this.options.classes);
         this.$el.addClass(this.options.classes);
         if (this.options.striped) {
         if (this.options.striped) {
             this.$el.addClass('table-striped');
             this.$el.addClass('table-striped');
         }
         }
         if ($.inArray('table-no-bordered', this.options.classes.split(' ')) !== -1) {
         if ($.inArray('table-no-bordered', this.options.classes.split(' ')) !== -1) {
-            this.$container.find('.fixed-table-container').addClass('table-no-bordered');
+            this.$tableContainer.addClass('table-no-bordered');
         }
         }
     };
     };
 
 
@@ -455,7 +474,7 @@
             var column = $.extend({}, {
             var column = $.extend({}, {
                 title: $(this).html(),
                 title: $(this).html(),
                 'class': $(this).attr('class')
                 'class': $(this).attr('class')
-            }, getRealDataAttr($(this).data()));
+            }, $(this).data());
 
 
             columns.push(column);
             columns.push(column);
         });
         });
@@ -512,6 +531,11 @@
             searchables: []
             searchables: []
         };
         };
 
 
+        if (!this.options.cardView && this.options.detailView) {
+            html.push('<th class="detail"><div class="fht-cell"></div></th>');
+            visibleColumns.push({});
+        }
+
         $.each(this.options.columns, function (i, column) {
         $.each(this.options.columns, function (i, column) {
             var text = '',
             var text = '',
                 halign = '', // header align style
                 halign = '', // header align style
@@ -519,12 +543,12 @@
                 style = '',
                 style = '',
                 class_ = sprintf(' class="%s"', column['class']),
                 class_ = sprintf(' class="%s"', column['class']),
                 order = that.options.sortOrder || column.order,
                 order = that.options.sortOrder || column.order,
-                searchable = true,
                 unitWidth = 'px',
                 unitWidth = 'px',
                 width = column.width;
                 width = column.width;
 
 
             if (!column.visible) {
             if (!column.visible) {
-                // Fix #229. Default Sort order is wrong if data-visible="false" is set on the field referenced by data-sort-name.
+                // Fix #229. Default Sort order is wrong
+                // if data-visible="false" is set on the field referenced by data-sort-name.
                 if (column.field === that.options.sortName) {
                 if (column.field === that.options.sortName) {
                     that.header.fields.push(column.field);
                     that.header.fields.push(column.field);
                 }
                 }
@@ -606,12 +630,12 @@
 
 
         if (!this.options.showHeader || this.options.cardView) {
         if (!this.options.showHeader || this.options.cardView) {
             this.$header.hide();
             this.$header.hide();
-            this.$container.find('.fixed-table-header').hide();
-            this.$loading.css('top', 0);
+            this.$tableHeader.hide();
+            this.$tableLoading.css('top', 0);
         } else {
         } else {
             this.$header.show();
             this.$header.show();
-            this.$container.find('.fixed-table-header').show();
-            this.$loading.css('top', cellHeight + 'px');
+            this.$tableHeader.show();
+            this.$tableLoading.css('top', cellHeight + 'px');
             // Assign the correct sortable arrow
             // Assign the correct sortable arrow
             this.getCaretHtml();
             this.getCaretHtml();
         }
         }
@@ -625,11 +649,10 @@
     };
     };
 
 
     BootstrapTable.prototype.initFooter = function () {
     BootstrapTable.prototype.initFooter = function () {
-        this.$footer = this.$container.find('.fixed-table-footer');
         if (!this.options.showFooter || this.options.cardView) {
         if (!this.options.showFooter || this.options.cardView) {
-            this.$footer.hide();
+            this.$tableFooter.hide();
         } else {
         } else {
-            this.$footer.show();
+            this.$tableFooter.show();
         }
         }
     };
     };
 
 
@@ -753,7 +776,7 @@
             $search,
             $search,
             switchableCount = 0;
             switchableCount = 0;
 
 
-        this.$toolbar = this.$container.find('.fixed-table-toolbar').html('');
+        this.$toolbar.html('');
 
 
         if (typeof this.options.toolbar === 'string') {
         if (typeof this.options.toolbar === 'string') {
             $(sprintf('<div class="bars pull-%s"></div>', this.options.toolbarAlign))
             $(sprintf('<div class="bars pull-%s"></div>', this.options.toolbarAlign))
@@ -950,8 +973,6 @@
     };
     };
 
 
     BootstrapTable.prototype.initPagination = function () {
     BootstrapTable.prototype.initPagination = function () {
-        this.$pagination = this.$container.find('.fixed-table-pagination');
-
         if (!this.options.pagination) {
         if (!this.options.pagination) {
             this.$pagination.hide();
             this.$pagination.hide();
             return;
             return;
@@ -1248,6 +1269,14 @@
                 html.push(sprintf('<td colspan="%s">', this.header.fields.length));
                 html.push(sprintf('<td colspan="%s">', this.header.fields.length));
             }
             }
 
 
+            if (!this.options.cardView && this.options.detailView) {
+                html.push('<td>',
+                    '<a class="detail-icon" href="javascript:">',
+                    '<i class="glyphicon glyphicon-plus icon-plus"></i>',
+                    '</a>',
+                    '</td>');
+            }
+
             $.each(this.header.fields, function (j, field) {
             $.each(this.header.fields, function (j, field) {
                 var text = '',
                 var text = '',
                     value = item[field],
                     value = item[field],
@@ -1349,14 +1378,12 @@
         // show no records
         // show no records
         if (!html.length) {
         if (!html.length) {
             html.push('<tr class="no-records-found">',
             html.push('<tr class="no-records-found">',
-                sprintf('<td colspan="%s">%s</td>', this.header.fields.length, this.options.formatNoMatches()),
+                sprintf('<td colspan="%s">%s</td>',
+                    this.$header.find('th').length, this.options.formatNoMatches()),
                 '</tr>');
                 '</tr>');
         }
         }
 
 
-        this.trigger('pre-rows');
         this.$body.html(html.join(''));
         this.$body.html(html.join(''));
-        this.trigger('post-rows');
-
 
 
         if (!fixedScroll) {
         if (!fixedScroll) {
             this.scrollTo(0);
             this.scrollTo(0);
@@ -1393,6 +1420,27 @@
             that.trigger('dbl-click-row', item, $tr);
             that.trigger('dbl-click-row', item, $tr);
         });
         });
 
 
+        this.$body.find('> tr > td > .detail-icon').off('click').on('click', function () {
+            var $this = $(this),
+                $tr = $this.parent().parent(),
+                index = $tr.data('index'),
+                row = that.options.data[index];
+
+            // remove and update
+            if ($tr.next().is('tr.detail-view')) {
+                $this.find('i').attr('class', 'glyphicon glyphicon-plus icon-plus');
+                $tr.next().remove();
+                that.trigger('collapse-row', index, row);
+            } else {
+                $this.find('i').attr('class', 'glyphicon glyphicon-minus icon-minus');
+                $tr.after(sprintf('<tr class="detail-view"><td colspan="%s">%s</td></tr>',
+                    $tr.find('td').length, calculateObjectValue(that.options,
+                        that.options.detailFormatter, [index, row], '')));
+                that.trigger('expand-row', index, row, $tr.next().find('td'));
+            }
+            that.resetView();
+        });
+
         this.$selectItem = this.$body.find(sprintf('[name="%s"]', this.options.selectItemName));
         this.$selectItem = this.$body.find(sprintf('[name="%s"]', this.options.selectItemName));
         this.$selectItem.off('click').on('click', function (event) {
         this.$selectItem.off('click').on('click', function (event) {
             event.stopImmediatePropagation();
             event.stopImmediatePropagation();
@@ -1421,6 +1469,9 @@
             if (typeof events === 'string') {
             if (typeof events === 'string') {
                 events = calculateObjectValue(null, events);
                 events = calculateObjectValue(null, events);
             }
             }
+            if (!that.options.cardView && that.options.detailView) {
+                i += 1;
+            }
             for (var key in events) {
             for (var key in events) {
                 that.$body.find('tr').each(function () {
                 that.$body.find('tr').each(function () {
                     var $tr = $(this),
                     var $tr = $(this),
@@ -1492,7 +1543,7 @@
         }
         }
 
 
         if (!silent) {
         if (!silent) {
-            this.$loading.show();
+            this.$tableLoading.show();
         }
         }
         request = $.extend({}, calculateObjectValue(null, this.options.ajaxOptions), {
         request = $.extend({}, calculateObjectValue(null, this.options.ajaxOptions), {
             type: this.options.method,
             type: this.options.method,
@@ -1513,7 +1564,7 @@
             },
             },
             complete: function () {
             complete: function () {
                 if (!silent) {
                 if (!silent) {
-                    that.$loading.hide();
+                    that.$tableLoading.hide();
                 }
                 }
             }
             }
         });
         });
@@ -1586,8 +1637,6 @@
 
 
     BootstrapTable.prototype.fitHeader = function () {
     BootstrapTable.prototype.fitHeader = function () {
         var that = this,
         var that = this,
-            $fixedHeader,
-            $fixedBody,
             fixedBody,
             fixedBody,
             scrollWidth;
             scrollWidth;
 
 
@@ -1595,9 +1644,7 @@
             that.timeoutFooter_ = setTimeout($.proxy(that.fitHeader, that), 100);
             that.timeoutFooter_ = setTimeout($.proxy(that.fitHeader, that), 100);
             return;
             return;
         }
         }
-        $fixedHeader = this.$container.find('.fixed-table-header');
-        $fixedBody = this.$container.find('.fixed-table-body');
-        fixedBody = $fixedBody.get(0);
+        fixedBody = this.$tableBody.get(0);
 
 
         scrollWidth = fixedBody.scrollWidth > fixedBody.clientWidth &&
         scrollWidth = fixedBody.scrollWidth > fixedBody.clientWidth &&
             fixedBody.scrollHeight > fixedBody.clientHeight + this.$header.height() ?
             fixedBody.scrollHeight > fixedBody.clientHeight + this.$header.height() ?
@@ -1606,7 +1653,7 @@
         this.$el.css('margin-top', -this.$header.height());
         this.$el.css('margin-top', -this.$header.height());
         this.$header_ = this.$header.clone(true, true);
         this.$header_ = this.$header.clone(true, true);
         this.$selectAll_ = this.$header_.find('[name="btSelectAll"]');
         this.$selectAll_ = this.$header_.find('[name="btSelectAll"]');
-        $fixedHeader.css({
+        this.$tableHeader.css({
             'margin-right': scrollWidth
             'margin-right': scrollWidth
         }).find('table').css('width', this.$el.css('width'))
         }).find('table').css('width', this.$el.css('width'))
             .html('').attr('class', this.$el.attr('class'))
             .html('').attr('class', this.$el.attr('class'))
@@ -1622,8 +1669,8 @@
         });
         });
         // horizontal scroll event
         // horizontal scroll event
         // TODO: it's probably better improving the layout than binding to scroll event
         // TODO: it's probably better improving the layout than binding to scroll event
-        $fixedBody.off('scroll').on('scroll', function () {
-            $fixedHeader.scrollLeft($(this).scrollLeft());
+        this.$tableBody.off('scroll').on('scroll', function () {
+            that.$tableHeader.scrollLeft($(this).scrollLeft());
         });
         });
         that.trigger('post-header');
         that.trigger('post-header');
     };
     };
@@ -1637,6 +1684,10 @@
             return;
             return;
         }
         }
 
 
+        if (!this.options.cardView && this.options.detailView) {
+            html.push('<td></td>');
+        }
+
         $.each(this.options.columns, function (i, column) {
         $.each(this.options.columns, function (i, column) {
             var falign = '', // footer align style
             var falign = '', // footer align style
                 style = '',
                 style = '',
@@ -1655,12 +1706,11 @@
 
 
             html.push('<td', class_, sprintf(' style="%s"', falign + style), '>');
             html.push('<td', class_, sprintf(' style="%s"', falign + style), '>');
 
 
-
             html.push(calculateObjectValue(column, column.footerFormatter, [data], '&nbsp;') || '&nbsp;');
             html.push(calculateObjectValue(column, column.footerFormatter, [data], '&nbsp;') || '&nbsp;');
             html.push('</td>');
             html.push('</td>');
         });
         });
 
 
-        this.$footer.find('tr').html(html.join(''));
+        this.$tableFooter.find('tr').html(html.join(''));
         clearTimeout(this.timeoutFooter_);
         clearTimeout(this.timeoutFooter_);
         this.timeoutFooter_ = setTimeout($.proxy(this.fitFooter, this),
         this.timeoutFooter_ = setTimeout($.proxy(this.fitFooter, this),
             this.$el.is(':hidden') ? 100 : 0);
             this.$el.is(':hidden') ? 100 : 0);
@@ -1668,7 +1718,6 @@
 
 
     BootstrapTable.prototype.fitFooter = function () {
     BootstrapTable.prototype.fitFooter = function () {
         var that = this,
         var that = this,
-            $fixedBody,
             $footerTd,
             $footerTd,
             elWidth,
             elWidth,
             scrollWidth;
             scrollWidth;
@@ -1679,18 +1728,17 @@
             return;
             return;
         }
         }
 
 
-        $fixedBody = this.$container.find('.fixed-table-body');
         elWidth = this.$el.css('width');
         elWidth = this.$el.css('width');
-        scrollWidth = elWidth > $fixedBody.width() ? getScrollBarWidth() : 0;
+        scrollWidth = elWidth > this.$tableBody.width() ? getScrollBarWidth() : 0;
 
 
-        this.$footer.css({
+        this.$tableFooter.css({
             'margin-right': scrollWidth
             'margin-right': scrollWidth
         }).find('table').css('width', elWidth)
         }).find('table').css('width', elWidth)
             .attr('class', this.$el.attr('class'));
             .attr('class', this.$el.attr('class'));
 
 
-        $footerTd = this.$footer.find('td');
+        $footerTd = this.$tableFooter.find('td');
 
 
-        $fixedBody.find('tbody tr:first-child:not(.no-records-found) > td').each(function (i) {
+        this.$tableBody.find('tbody tr:first-child:not(.no-records-found) > td').each(function (i) {
             $footerTd.eq(i).outerWidth($(this).outerWidth());
             $footerTd.eq(i).outerWidth($(this).outerWidth());
         });
         });
     };
     };
@@ -1732,8 +1780,7 @@
 
 
     BootstrapTable.prototype.resetView = function (params) {
     BootstrapTable.prototype.resetView = function (params) {
         var that = this,
         var that = this,
-            padding = 0,
-            $tableContainer = that.$container.find('.fixed-table-container');
+            padding = 0;
 
 
         if (params && params.height) {
         if (params && params.height) {
             this.options.height = params.height;
             this.options.height = params.height;
@@ -1747,7 +1794,7 @@
                 paginationHeight = getRealHeight(this.$pagination),
                 paginationHeight = getRealHeight(this.$pagination),
                 height = this.options.height - toolbarHeight - paginationHeight;
                 height = this.options.height - toolbarHeight - paginationHeight;
 
 
-            $tableContainer.css('height', height + 'px');
+            this.$tableContainer.css('height', height + 'px');
         }
         }
 
 
         if (this.options.cardView) {
         if (this.options.cardView) {
@@ -1758,11 +1805,11 @@
         }
         }
 
 
         if (this.options.showHeader && this.options.height) {
         if (this.options.showHeader && this.options.height) {
-            this.$container.find('.fixed-table-header').show();
+            this.$tableHeader.show();
             this.resetHeader();
             this.resetHeader();
             padding += cellHeight;
             padding += cellHeight;
         } else {
         } else {
-            this.$container.find('.fixed-table-header').hide();
+            this.$tableHeader.hide();
             this.trigger('post-header');
             this.trigger('post-header');
         }
         }
 
 
@@ -1775,7 +1822,7 @@
 
 
         // Assign the correct sortable arrow
         // Assign the correct sortable arrow
         this.getCaretHtml();
         this.getCaretHtml();
-        $tableContainer.css('padding-bottom', padding + 'px');
+        this.$tableContainer.css('padding-bottom', padding + 'px');
     };
     };
 
 
     BootstrapTable.prototype.getData = function (useCurrentPage) {
     BootstrapTable.prototype.getData = function (useCurrentPage) {
@@ -1950,6 +1997,11 @@
             $tr = this.$body.find('tr'),
             $tr = this.$body.find('tr'),
             $td = $tr.eq(row).find('td').eq(col);
             $td = $tr.eq(row).find('td').eq(col);
 
 
+        if (!this.options.cardView && this.options.detailView) {
+            col += 1;
+        }
+        $td = $tr.eq(row).find('td').eq(col);
+
         if (row < 0 || col < 0 || row >= this.data.length) {
         if (row < 0 || col < 0 || row >= this.data.length) {
             return;
             return;
         }
         }
@@ -1963,6 +2015,15 @@
         $td.attr('rowspan', rowspan).attr('colspan', colspan).show();
         $td.attr('rowspan', rowspan).attr('colspan', colspan).show();
     };
     };
 
 
+    BootstrapTable.prototype.updateCell = function (params) {
+        if (!params.hasOwnProperty('rowIndex') || !params.hasOwnProperty('fieldName') || !params.hasOwnProperty('fieldValue')) {
+            return;
+        }
+        this.data[params.rowIndex][params.fieldName] = params.fieldValue;
+        this.initSort();
+        this.initBody(true);
+    };
+
     BootstrapTable.prototype.getOptions = function () {
     BootstrapTable.prototype.getOptions = function () {
         return this.options;
         return this.options;
     };
     };
@@ -2033,7 +2094,8 @@
             return;
             return;
         }
         }
 
 
-        var that = this;
+        var that = this,
+            rows = [];
         $.each(this.options.data, function (index, row) {
         $.each(this.options.data, function (index, row) {
             if (!row.hasOwnProperty(obj.field)) {
             if (!row.hasOwnProperty(obj.field)) {
                 return false;
                 return false;
@@ -2041,10 +2103,12 @@
             if ($.inArray(row[obj.field], obj.values) !== -1) {
             if ($.inArray(row[obj.field], obj.values) !== -1) {
                 that.$selectItem.filter(sprintf('[data-index="%s"]', index)).prop('checked', checked);
                 that.$selectItem.filter(sprintf('[data-index="%s"]', index)).prop('checked', checked);
                 row[that.header.stateField] = checked;
                 row[that.header.stateField] = checked;
+                rows.push(row);
                 that.trigger(checked ? 'check' : 'uncheck', row);
                 that.trigger(checked ? 'check' : 'uncheck', row);
             }
             }
         });
         });
         this.updateSelected();
         this.updateSelected();
+        this.trigger(checked ? 'check-some' : 'uncheck-some', rows);
     };
     };
 
 
     BootstrapTable.prototype.destroy = function () {
     BootstrapTable.prototype.destroy = function () {
@@ -2058,11 +2122,11 @@
     };
     };
 
 
     BootstrapTable.prototype.showLoading = function () {
     BootstrapTable.prototype.showLoading = function () {
-        this.$loading.show();
+        this.$tableLoading.show();
     };
     };
 
 
     BootstrapTable.prototype.hideLoading = function () {
     BootstrapTable.prototype.hideLoading = function () {
-        this.$loading.hide();
+        this.$tableLoading.hide();
     };
     };
 
 
     BootstrapTable.prototype.togglePagination = function () {
     BootstrapTable.prototype.togglePagination = function () {
@@ -2109,15 +2173,14 @@
     };
     };
 
 
     BootstrapTable.prototype.scrollTo = function (value) {
     BootstrapTable.prototype.scrollTo = function (value) {
-        var $tbody = this.$container.find('.fixed-table-body');
         if (typeof value === 'string') {
         if (typeof value === 'string') {
-            value = value === 'bottom' ? $tbody[0].scrollHeight : 0;
+            value = value === 'bottom' ? this.$tableBody[0].scrollHeight : 0;
         }
         }
         if (typeof value === 'number') {
         if (typeof value === 'number') {
-            $tbody.scrollTop(value);
+            this.$tableBody.scrollTop(value);
         }
         }
         if (typeof value === 'undefined') {
         if (typeof value === 'undefined') {
-            return $tbody.scrollTop();
+            return this.$tableBody.scrollTop();
         }
         }
     };
     };
 
 
@@ -2162,7 +2225,7 @@
         'getOptions',
         'getOptions',
         'getSelections', 'getAllSelections', 'getData',
         'getSelections', 'getAllSelections', 'getData',
         'load', 'append', 'prepend', 'remove', 'removeAll',
         'load', 'append', 'prepend', 'remove', 'removeAll',
-        'insertRow', 'updateRow', 'removeByUniqueId',
+        'insertRow', 'updateRow', 'updateCell', 'removeByUniqueId',
         'showRow', 'hideRow', 'getRowsHidden',
         'showRow', 'hideRow', 'getRowsHidden',
         'mergeCells',
         'mergeCells',
         'checkAll', 'uncheckAll',
         'checkAll', 'uncheckAll',

+ 24 - 0
src/extensions/cookie/bootstrap-table-cookie.js

@@ -107,6 +107,10 @@
         _onSort = BootstrapTable.prototype.onSort,
         _onSort = BootstrapTable.prototype.onSort,
         _onPageNumber = BootstrapTable.prototype.onPageNumber,
         _onPageNumber = BootstrapTable.prototype.onPageNumber,
         _onPageListChange = BootstrapTable.prototype.onPageListChange,
         _onPageListChange = BootstrapTable.prototype.onPageListChange,
+        _onPageFirst = BootstrapTable.prototype.onPageFirst,
+        _onPagePre = BootstrapTable.prototype.onPagePre,
+        _onPageNext = BootstrapTable.prototype.onPageNext,
+        _onPageLast = BootstrapTable.prototype.onPageLast,
         _toggleColumn = BootstrapTable.prototype.toggleColumn,
         _toggleColumn = BootstrapTable.prototype.toggleColumn,
         _onSearch = BootstrapTable.prototype.onSearch;
         _onSearch = BootstrapTable.prototype.onSearch;
 
 
@@ -180,6 +184,26 @@
         setCookie(this, idsStateSaveList.pageList, this.options.pageSize);
         setCookie(this, idsStateSaveList.pageList, this.options.pageSize);
     };
     };
 
 
+    BootstrapTable.prototype.onPageFirst = function () {
+        _onPageFirst.apply(this, Array.prototype.slice.apply(arguments));
+        setCookie(this, idsStateSaveList.pageNumber, this.options.pageNumber);
+    };
+
+    BootstrapTable.prototype.onPagePre = function () {
+        _onPagePre.apply(this, Array.prototype.slice.apply(arguments));
+        setCookie(this, idsStateSaveList.pageNumber, this.options.pageNumber);
+    };
+
+    BootstrapTable.prototype.onPageNext = function () {
+        _onPageNext.apply(this, Array.prototype.slice.apply(arguments));
+        setCookie(this, idsStateSaveList.pageNumber, this.options.pageNumber);
+    };
+
+    BootstrapTable.prototype.onPageLast = function () {
+        _onPageLast.apply(this, Array.prototype.slice.apply(arguments));
+        setCookie(this, idsStateSaveList.pageNumber, this.options.pageNumber);
+    };
+
     BootstrapTable.prototype.toggleColumn = function () {
     BootstrapTable.prototype.toggleColumn = function () {
         _toggleColumn.apply(this, Array.prototype.slice.apply(arguments));
         _toggleColumn.apply(this, Array.prototype.slice.apply(arguments));