Browse Source

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

Conflicts:
	src/bootstrap-table.js
jtrumbull 10 years ago
parent
commit
0aaf0a61d9
1 changed files with 148 additions and 62 deletions
  1. 148 62
      src/bootstrap-table.js

+ 148 - 62
src/bootstrap-table.js

@@ -211,6 +211,10 @@
         idField: undefined,
         uniqueId: undefined,
         cardView: false,
+        detailView: false,
+        detailFormatter: function (index, row) {
+            return '';
+        },
         trimOnSearch: true,
         clickToSelect: false,
         singleSelect: false,
@@ -242,6 +246,12 @@
         onAll: function (name, args) {
             return false;
         },
+        onClickCell: function (field, value, row, $element) {
+            return false;
+        },
+        onDblClickCell: function (field, value, row, $element) {
+            return false;
+        },
         onClickRow: function (item, $element) {
             return false;
         },
@@ -257,10 +267,16 @@
         onUncheck: function (row) {
             return false;
         },
-        onCheckAll: function () {
+        onCheckAll: function (rows) {
             return false;
         },
-        onUncheckAll: function () {
+        onUncheckAll: function (rows) {
+            return false;
+        },
+        onCheckSome: function(rows){
+            return false;
+        },
+        onUncheckSome: function(rows){
             return false;
         },
         onLoadSuccess: function (data) {
@@ -290,10 +306,10 @@
         onPostHeader: function () {
             return false;
         },
-        onPreRows: function () {
+        onExpandRow: function (index, row, $detail) {
             return false;
         },
-        onPostRows: function () {
+        onCollapseRow: function (index, row) {
             return false;
         }
     };
@@ -364,6 +380,8 @@
 
     BootstrapTable.EVENTS = {
         'all.bs.table': 'onAll',
+        'click-cell.bs.table': 'onClickCell',
+        'dbl-click-cell.bs.table': 'onDblClickCell',
         'click-row.bs.table': 'onClickRow',
         'dbl-click-row.bs.table': 'onDblClickRow',
         'sort.bs.table': 'onSort',
@@ -371,6 +389,8 @@
         'uncheck.bs.table': 'onUncheck',
         'check-all.bs.table': 'onCheckAll',
         'uncheck-all.bs.table': 'onUncheckAll',
+        'check-some.bs.table': 'onCheckSome',
+        'uncheck-some.bs.table': 'onUncheckSome',
         'load-success.bs.table': 'onLoadSuccess',
         'load-error.bs.table': 'onLoadError',
         'column-switch.bs.table': 'onColumnSwitch',
@@ -380,8 +400,8 @@
         'pre-body.bs.table': 'onPreBody',
         'post-body.bs.table': 'onPostBody',
         '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 () {
@@ -418,16 +438,23 @@
             '</div>'].join(''));
 
         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.$loading = this.$container.find('.fixed-table-loading');
 
         this.$el.addClass(this.options.classes);
         if (this.options.striped) {
             this.$el.addClass('table-striped');
         }
         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');
         }
     };
 
@@ -447,7 +474,7 @@
             var column = $.extend({}, {
                 title: $(this).html(),
                 'class': $(this).attr('class')
-            }, getRealDataAttr($(this).data()));
+            }, $(this).data());
 
             columns.push(column);
         });
@@ -504,6 +531,11 @@
             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) {
             var text = '',
                 halign = '', // header align style
@@ -511,12 +543,12 @@
                 style = '',
                 class_ = sprintf(' class="%s"', column['class']),
                 order = that.options.sortOrder || column.order,
-                searchable = true,
                 unitWidth = 'px',
                 width = column.width;
 
             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) {
                     that.header.fields.push(column.field);
                 }
@@ -598,12 +630,12 @@
 
         if (!this.options.showHeader || this.options.cardView) {
             this.$header.hide();
-            this.$container.find('.fixed-table-header').hide();
-            this.$loading.css('top', 0);
+            this.$tableHeader.hide();
+            this.$tableLoading.css('top', 0);
         } else {
             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
             this.getCaretHtml();
         }
@@ -617,11 +649,10 @@
     };
 
     BootstrapTable.prototype.initFooter = function () {
-        this.$footer = this.$container.find('.fixed-table-footer');
         if (!this.options.showFooter || this.options.cardView) {
-            this.$footer.hide();
+            this.$tableFooter.hide();
         } else {
-            this.$footer.show();
+            this.$tableFooter.show();
         }
     };
 
@@ -745,7 +776,7 @@
             $search,
             switchableCount = 0;
 
-        this.$toolbar = this.$container.find('.fixed-table-toolbar').html('');
+        this.$toolbar.html('');
 
         if (typeof this.options.toolbar === 'string') {
             $(sprintf('<div class="bars pull-%s"></div>', this.options.toolbarAlign))
@@ -942,8 +973,6 @@
     };
 
     BootstrapTable.prototype.initPagination = function () {
-        this.$pagination = this.$container.find('.fixed-table-pagination');
-
         if (!this.options.pagination) {
             this.$pagination.hide();
             return;
@@ -1240,6 +1269,14 @@
                 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) {
                 var text = '',
                     value = item[field],
@@ -1341,14 +1378,12 @@
         // show no records
         if (!html.length) {
             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>');
         }
 
-        this.trigger('pre-rows');
         this.$body.html(html.join(''));
-        this.trigger('post-rows');
-
 
         if (!fixedScroll) {
             this.scrollTo(0);
@@ -1356,8 +1391,15 @@
 
         // click to select by column
         this.$body.find('> tr > td').off('click').on('click', function () {
-            var $tr = $(this).parent();
-            that.trigger('click-row', that.data[$tr.data('index')], $tr);
+            var $td = $(this),
+                $tr = $td.parent(),
+                item = that.data[$tr.data('index')],
+                cellIndex = $td[0].cellIndex,
+                $headerCell = that.$header.find('th:eq(' + cellIndex + ')'),
+                field = $headerCell.data('field'),
+                value = item[field];
+            that.trigger('click-cell', field, value, item, $td);
+            that.trigger('click-row', item, $tr);
             // if click to select - then trigger the checkbox/radio click
             if (that.options.clickToSelect) {
                 if (that.header.clickToSelects[$tr.children().index($(this))]) {
@@ -1366,8 +1408,37 @@
                 }
             }
         });
-        this.$body.find('tr').off('dblclick').on('dblclick', function () {
-            that.trigger('dbl-click-row', that.data[$(this).data('index')], $(this));
+        this.$body.find('> tr > td').off('dblclick').on('dblclick', function () {
+            var $td = $(this),
+                $tr = $td.parent(),
+                item = that.data[$tr.data('index')],
+                cellIndex = $td[0].cellIndex,
+                $headerCell = that.$header.find('th:eq(' + cellIndex + ')'),
+                field = $headerCell.data('field'),
+                value = item[field];
+            that.trigger('dbl-click-cell', field, value, item, $td);
+            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));
@@ -1398,6 +1469,9 @@
             if (typeof events === 'string') {
                 events = calculateObjectValue(null, events);
             }
+            if (!that.options.cardView && that.options.detailView) {
+                i += 1;
+            }
             for (var key in events) {
                 that.$body.find('tr').each(function () {
                     var $tr = $(this),
@@ -1469,7 +1543,7 @@
         }
 
         if (!silent) {
-            this.$loading.show();
+            this.$tableLoading.show();
         }
         request = $.extend({}, calculateObjectValue(null, this.options.ajaxOptions), {
             type: this.options.method,
@@ -1490,7 +1564,7 @@
             },
             complete: function () {
                 if (!silent) {
-                    that.$loading.hide();
+                    that.$tableLoading.hide();
                 }
             }
         });
@@ -1563,8 +1637,6 @@
 
     BootstrapTable.prototype.fitHeader = function () {
         var that = this,
-            $fixedHeader,
-            $fixedBody,
             fixedBody,
             scrollWidth;
 
@@ -1572,9 +1644,7 @@
             that.timeoutFooter_ = setTimeout($.proxy(that.fitHeader, that), 100);
             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 &&
             fixedBody.scrollHeight > fixedBody.clientHeight + this.$header.height() ?
@@ -1583,7 +1653,7 @@
         this.$el.css('margin-top', -this.$header.height());
         this.$header_ = this.$header.clone(true, true);
         this.$selectAll_ = this.$header_.find('[name="btSelectAll"]');
-        $fixedHeader.css({
+        this.$tableHeader.css({
             'margin-right': scrollWidth
         }).find('table').css('width', this.$el.css('width'))
             .html('').attr('class', this.$el.attr('class'))
@@ -1599,8 +1669,8 @@
         });
         // horizontal 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');
     };
@@ -1614,6 +1684,10 @@
             return;
         }
 
+        if (!this.options.cardView && this.options.detailView) {
+            html.push('<td></td>');
+        }
+
         $.each(this.options.columns, function (i, column) {
             var falign = '', // footer align style
                 style = '',
@@ -1632,12 +1706,11 @@
 
             html.push('<td', class_, sprintf(' style="%s"', falign + style), '>');
 
-
             html.push(calculateObjectValue(column, column.footerFormatter, [data], '&nbsp;') || '&nbsp;');
             html.push('</td>');
         });
 
-        this.$footer.find('tr').html(html.join(''));
+        this.$tableFooter.find('tr').html(html.join(''));
         clearTimeout(this.timeoutFooter_);
         this.timeoutFooter_ = setTimeout($.proxy(this.fitFooter, this),
             this.$el.is(':hidden') ? 100 : 0);
@@ -1645,7 +1718,6 @@
 
     BootstrapTable.prototype.fitFooter = function () {
         var that = this,
-            $fixedBody,
             $footerTd,
             elWidth,
             scrollWidth;
@@ -1656,18 +1728,17 @@
             return;
         }
 
-        $fixedBody = this.$container.find('.fixed-table-body');
         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
         }).find('table').css('width', elWidth)
             .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());
         });
     };
@@ -1709,8 +1780,7 @@
 
     BootstrapTable.prototype.resetView = function (params) {
         var that = this,
-            padding = 0,
-            $tableContainer = that.$container.find('.fixed-table-container');
+            padding = 0;
 
         if (params && params.height) {
             this.options.height = params.height;
@@ -1724,7 +1794,7 @@
                 paginationHeight = getRealHeight(this.$pagination),
                 height = this.options.height - toolbarHeight - paginationHeight;
 
-            $tableContainer.css('height', height + 'px');
+            this.$tableContainer.css('height', height + 'px');
         }
 
         if (this.options.cardView) {
@@ -1735,11 +1805,11 @@
         }
 
         if (this.options.showHeader && this.options.height) {
-            this.$container.find('.fixed-table-header').show();
+            this.$tableHeader.show();
             this.resetHeader();
             padding += cellHeight;
         } else {
-            this.$container.find('.fixed-table-header').hide();
+            this.$tableHeader.hide();
             this.trigger('post-header');
         }
 
@@ -1752,7 +1822,7 @@
 
         // Assign the correct sortable arrow
         this.getCaretHtml();
-        $tableContainer.css('padding-bottom', padding + 'px');
+        this.$tableContainer.css('padding-bottom', padding + 'px');
     };
 
     BootstrapTable.prototype.getData = function (useCurrentPage) {
@@ -1927,6 +1997,11 @@
             $tr = this.$body.find('tr'),
             $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) {
             return;
         }
@@ -1940,6 +2015,15 @@
         $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 () {
         return this.options;
     };
@@ -2010,7 +2094,8 @@
             return;
         }
 
-        var that = this;
+        var that = this,
+            rows = [];
         $.each(this.options.data, function (index, row) {
             if (!row.hasOwnProperty(obj.field)) {
                 return false;
@@ -2018,10 +2103,12 @@
             if ($.inArray(row[obj.field], obj.values) !== -1) {
                 that.$selectItem.filter(sprintf('[data-index="%s"]', index)).prop('checked', checked);
                 row[that.header.stateField] = checked;
+                rows.push(row);
                 that.trigger(checked ? 'check' : 'uncheck', row);
             }
         });
         this.updateSelected();
+        this.trigger(checked ? 'check-some' : 'uncheck-some', rows);
     };
 
     BootstrapTable.prototype.destroy = function () {
@@ -2035,11 +2122,11 @@
     };
 
     BootstrapTable.prototype.showLoading = function () {
-        this.$loading.show();
+        this.$tableLoading.show();
     };
 
     BootstrapTable.prototype.hideLoading = function () {
-        this.$loading.hide();
+        this.$tableLoading.hide();
     };
 
     BootstrapTable.prototype.togglePagination = function () {
@@ -2086,15 +2173,14 @@
     };
 
     BootstrapTable.prototype.scrollTo = function (value) {
-        var $tbody = this.$container.find('.fixed-table-body');
         if (typeof value === 'string') {
-            value = value === 'bottom' ? $tbody[0].scrollHeight : 0;
+            value = value === 'bottom' ? this.$tableBody[0].scrollHeight : 0;
         }
         if (typeof value === 'number') {
-            $tbody.scrollTop(value);
+            this.$tableBody.scrollTop(value);
         }
         if (typeof value === 'undefined') {
-            return $tbody.scrollTop();
+            return this.$tableBody.scrollTop();
         }
     };
 
@@ -2139,7 +2225,7 @@
         'getOptions',
         'getSelections', 'getAllSelections', 'getData',
         'load', 'append', 'prepend', 'remove', 'removeAll',
-        'insertRow', 'updateRow', 'removeByUniqueId',
+        'insertRow', 'updateRow', 'updateCell', 'removeByUniqueId',
         'showRow', 'hideRow', 'getRowsHidden',
         'mergeCells',
         'checkAll', 'uncheckAll',