Browse Source

Added themes support.

zhixin 6 years ago
parent
commit
51f6259e34
5 changed files with 481 additions and 456 deletions
  1. 2 0
      .gitignore
  2. 185 163
      src/bootstrap-table.js
  3. 2 293
      src/bootstrap-table.scss
  4. 289 0
      src/themes/bootstrap-table.scss
  5. 3 0
      src/themes/bootstrap/variables.scss

+ 2 - 0
.gitignore

@@ -7,6 +7,8 @@ _gh_pages
 # use scss instead
 src/bootstrap-table.css
 src/bootstrap-table.css.map
+src/themes/*.css
+src/themes/*.css.map
 .sass-cache
 
 # old docs

+ 185 - 163
src/bootstrap-table.js

@@ -8,7 +8,7 @@
   // TOOLS DEFINITION
   // ======================
 
-  let bootstrapVersion = 3
+  let bootstrapVersion = 4
   try {
     const rawVersion = $.fn.dropdown.Constructor.VERSION
 
@@ -21,8 +21,9 @@
     // ignore
   }
 
-  const bootstrap = {
+  const constants = {
     3: {
+      theme: 'bootstrap3',
       iconsPrefix: 'glyphicon',
       icons: {
         paginationSwitchDown: 'glyphicon-collapse-down icon-chevron-down',
@@ -36,17 +37,26 @@
         fullscreen: 'glyphicon-fullscreen'
       },
       classes: {
+        buttonsPrefix: 'btn',
         buttons: 'default',
-        pull: 'pull'
+        buttonsGroup: 'btn-group',
+        buttonsDropdown: 'btn-group',
+        pull: 'pull',
+        input: '',
+        paginationDropdown: 'btn-group'
       },
       html: {
         toobarDropdow: ['<ul class="dropdown-menu" role="menu">', '</ul>'],
         toobarDropdowItem: '<li role="menuitem"><label>%s</label></li>',
         pageDropdown: ['<ul class="dropdown-menu" role="menu">', '</ul>'],
-        pageDropdownItem: '<li role="menuitem" class="%s"><a href="#">%s</a></li>'
+        pageDropdownItem: '<li role="menuitem" class="%s"><a href="#">%s</a></li>',
+        dropdownCaret: '<span class="caret"></span>',
+        pagination: ['<ul class="pagination%s">', '</ul>'],
+        paginationItem: '<li class="page-item%s"><a class="page-link" href="#">%s</a></li>'
       }
     },
     4: {
+      theme: 'bootstrap4',
       iconsPrefix: 'fa',
       icons: {
         paginationSwitchDown: 'fa-caret-square-down',
@@ -60,14 +70,22 @@
         fullscreen: 'fa-arrows-alt'
       },
       classes: {
+        buttonsPrefix: 'btn',
         buttons: 'secondary',
-        pull: 'float'
+        buttonsGroup: 'btn-group',
+        buttonsDropdown: 'btn-group',
+        pull: 'float',
+        input: '',
+        paginationDropdown: 'btn-group'
       },
       html: {
         toobarDropdow: ['<div class="dropdown-menu dropdown-menu-right">', '</div>'],
         toobarDropdowItem: '<label class="dropdown-item">%s</label>',
         pageDropdown: ['<div class="dropdown-menu">', '</div>'],
-        pageDropdownItem: '<a class="dropdown-item %s" href="#">%s</a>'
+        pageDropdownItem: '<a class="dropdown-item %s" href="#">%s</a>',
+        dropdownCaret: '<span class="caret"></span>',
+        pagination: ['<ul class="pagination%s">', '</ul>'],
+        paginationItem: '<li class="page-item%s"><a class="page-link" href="#">%s</a></li>'
       }
     }
   }[bootstrapVersion]
@@ -370,10 +388,11 @@
     toolbarAlign: 'left',
     buttonsToolbar: undefined,
     buttonsAlign: 'right',
-    buttonsClass: bootstrap.classes.buttons,
-    icons: bootstrap.icons,
+    buttonsPrefix: constants.classes.buttonsPrefix,
+    buttonsClass: constants.classes.buttons,
+    icons: constants.icons,
     iconSize: undefined,
-    iconsPrefix: bootstrap.iconsPrefix, // glyphicon or fa(font-awesome)
+    iconsPrefix: constants.iconsPrefix, // glyphicon or fa(font-awesome)
     onAll (name, args) {
       return false
     },
@@ -572,6 +591,7 @@
     }
 
     init () {
+      this.initConstants()
       this.initLocale()
       this.initContainer()
       this.initTable()
@@ -586,6 +606,18 @@
       this.initServer()
     }
 
+    initConstants () {
+      const o = this.options
+      this.constants = constants
+
+      const buttonsPrefix = o.buttonsPrefix ? o.buttonsPrefix + '-' : ''
+      this.constants.buttonsClass = [
+        o.buttonsPrefix,
+        buttonsPrefix + o.buttonsClass,
+        Utils.sprintf(`${buttonsPrefix}%s`, o.iconSize)
+      ].join(' ').trim()
+    }
+
     initLocale () {
       if (this.options.locale) {
         const locales = $.fn.bootstrapTable.locales
@@ -1088,6 +1120,7 @@
     }
 
     initToolbar () {
+      const o = this.options
       let html = []
       let timeoutId = 0
       let $keepOpen
@@ -1095,80 +1128,84 @@
       let switchableCount = 0
 
       if (this.$toolbar.find('.bs-bars').children().length) {
-        $('body').append($(this.options.toolbar))
+        $('body').append($(o.toolbar))
       }
       this.$toolbar.html('')
 
-      if (typeof this.options.toolbar === 'string' || typeof this.options.toolbar === 'object') {
-        $(Utils.sprintf('<div class="bs-bars %s-%s"></div>', bootstrap.classes.pull, this.options.toolbarAlign))
+      if (typeof o.toolbar === 'string' || typeof o.toolbar === 'object') {
+        $(Utils.sprintf('<div class="bs-bars %s-%s"></div>', this.constants.classes.pull, o.toolbarAlign))
           .appendTo(this.$toolbar)
-          .append($(this.options.toolbar))
+          .append($(o.toolbar))
       }
 
       // showColumns, showToggle, showRefresh
-      html = [Utils.sprintf('<div class="columns columns-%s btn-group %s-%s">',
-        this.options.buttonsAlign, bootstrap.classes.pull, this.options.buttonsAlign)]
+      html = [`<div class="${[
+        'columns',
+        `columns-${o.buttonsAlign}`,
+        this.constants.classes.buttonsGroup,
+        `${this.constants.classes.pull}-${o.buttonsAlign}`
+      ].join(' ')}">`]
 
-      if (typeof this.options.icons === 'string') {
-        this.options.icons = Utils.calculateObjectValue(null, this.options.icons)
+      if (typeof o.icons === 'string') {
+        o.icons = Utils.calculateObjectValue(null, o.icons)
       }
 
-      if (this.options.showPaginationSwitch) {
-        html.push(Utils.sprintf(`<button class="btn${Utils.sprintf(' btn-%s', this.options.buttonsClass)}${Utils.sprintf(' btn-%s', this.options.iconSize)}" type="button" name="paginationSwitch" aria-label="pagination Switch" title="%s">`,
-          this.options.formatPaginationSwitch()),
-        Utils.sprintf('<i class="%s %s"></i>', this.options.iconsPrefix, this.options.icons.paginationSwitchDown),
-        '</button>')
+      if (o.showPaginationSwitch) {
+        html.push(`<button class="${this.constants.buttonsClass}" type="button" name="paginationSwitch"
+          aria-label="Pagination Switch" title="${o.formatPaginationSwitch()}">
+          <i class="${o.iconsPrefix} ${o.icons.paginationSwitchDown}"></i>
+          </button>`)
       }
 
-      if (this.options.showRefresh) {
-        html.push(Utils.sprintf(`<button class="btn${Utils.sprintf(' btn-%s', this.options.buttonsClass)}${Utils.sprintf(' btn-%s', this.options.iconSize)}" type="button" name="refresh" aria-label="refresh" title="%s">`,
-          this.options.formatRefresh()),
-        Utils.sprintf('<i class="%s %s"></i>', this.options.iconsPrefix, this.options.icons.refresh),
-        '</button>')
+      if (o.showRefresh) {
+        html.push(`<button class="${this.constants.buttonsClass}" type="button" name="refresh"
+          aria-label="Refresh" title="${o.formatRefresh()}">
+          <i class="${o.iconsPrefix} ${o.icons.refresh}"></i>
+          </button>`)
       }
 
-      if (this.options.showToggle) {
-        html.push(Utils.sprintf(`<button class="btn${Utils.sprintf(' btn-%s', this.options.buttonsClass)}${Utils.sprintf(' btn-%s', this.options.iconSize)}" type="button" name="toggle" aria-label="toggle" title="%s">`,
-          this.options.formatToggle()),
-        Utils.sprintf('<i class="%s %s"></i>', this.options.iconsPrefix, this.options.icons.toggleOff),
-        '</button>')
+      if (o.showToggle) {
+        html.push(`<button class="${this.constants.buttonsClass}" type="button" name="toggle"
+          aria-label="Toggle" title="${o.formatToggle()}">
+          <i class="${o.iconsPrefix} ${o.icons.toggleOff}"></i>
+          </button>`)
       }
 
-      if (this.options.showFullscreen) {
-        html.push(Utils.sprintf(`<button class="btn${Utils.sprintf(' btn-%s', this.options.buttonsClass)}${Utils.sprintf(' btn-%s', this.options.iconSize)}" type="button" name="fullscreen" aria-label="fullscreen" title="%s">`,
-          this.options.formatFullscreen()),
-        Utils.sprintf('<i class="%s %s"></i>', this.options.iconsPrefix, this.options.icons.fullscreen),
-        '</button>')
+      if (o.showFullscreen) {
+        html.push(`<button class="${this.constants.buttonsClass}" type="button" name="fullscreen"
+          aria-label="Fullscreen" title="${o.formatFullscreen()}">
+          <i class="${o.iconsPrefix} ${o.icons.fullscreen}"></i>
+          </button>`)
       }
 
-      if (this.options.showColumns) {
-        html.push(Utils.sprintf('<div class="keep-open btn-group" title="%s">',
-          this.options.formatColumns()),
-        `<button type="button" aria-label="columns" class="btn${Utils.sprintf(' btn-%s', this.options.buttonsClass)}${Utils.sprintf(' btn-%s', this.options.iconSize)} dropdown-toggle" data-toggle="dropdown">`,
-        Utils.sprintf('<i class="%s %s"></i>', this.options.iconsPrefix, this.options.icons.columns),
-        ' <span class="caret"></span>',
-        '</button>',
-        bootstrap.html.toobarDropdow[0])
+      if (o.showColumns) {
+        html.push(`<div class="keep-open ${this.constants.classes.buttonsDropdown}" title="${o.formatColumns()}">
+          <button class="${this.constants.buttonsClass} dropdown-toggle" type="button" data-toggle="dropdown"
+          aria-label="Columns" title="${o.formatFullscreen()}">
+          <i class="${o.iconsPrefix} ${o.icons.columns}"></i>
+          ${this.constants.html.dropdownCaret}
+          </button>
+          ${this.constants.html.toobarDropdow[0]}`)
 
         this.columns.forEach((column, i) => {
           if (column.radio || column.checkbox) {
             return
           }
 
-          if (this.options.cardView && !column.cardVisible) {
+          if (o.cardView && !column.cardVisible) {
             return
           }
 
           const checked = column.visible ? ' checked="checked"' : ''
 
           if (column.switchable) {
-            html.push(Utils.sprintf(bootstrap.html.toobarDropdowItem,
+            html.push(Utils.sprintf(this.constants.html.toobarDropdowItem,
               Utils.sprintf('<input type="checkbox" data-field="%s" value="%s"%s> %s',
                 column.field, i, checked, column.title)))
             switchableCount++
           }
         })
-        html.push(bootstrap.html.toobarDropdow[1], '</div>')
+        html.push(this.constants.html.toobarDropdow[1], '</div>')
       }
 
       html.push('</div>')
@@ -1178,32 +1215,32 @@
         this.$toolbar.append(html.join(''))
       }
 
-      if (this.options.showPaginationSwitch) {
+      if (o.showPaginationSwitch) {
         this.$toolbar.find('button[name="paginationSwitch"]')
           .off('click').on('click', $.proxy(this.togglePagination, this))
       }
 
-      if (this.options.showFullscreen) {
+      if (o.showFullscreen) {
         this.$toolbar.find('button[name="fullscreen"]')
           .off('click').on('click', $.proxy(this.toggleFullscreen, this))
       }
 
-      if (this.options.showRefresh) {
+      if (o.showRefresh) {
         this.$toolbar.find('button[name="refresh"]')
           .off('click').on('click', $.proxy(this.refresh, this))
       }
 
-      if (this.options.showToggle) {
+      if (o.showToggle) {
         this.$toolbar.find('button[name="toggle"]')
           .off('click').on('click', () => {
             this.toggleView()
           })
       }
 
-      if (this.options.showColumns) {
+      if (o.showColumns) {
         $keepOpen = this.$toolbar.find('.keep-open')
 
-        if (switchableCount <= this.options.minimumCountColumns) {
+        if (switchableCount <= o.minimumCountColumns) {
           $keepOpen.find('input').prop('disabled', true)
         }
 
@@ -1218,18 +1255,17 @@
         })
       }
 
-      if (this.options.search) {
+      if (o.search) {
         html = []
-        html.push(
-          Utils.sprintf('<div class="%s-%s search">', bootstrap.classes.pull, this.options.searchAlign),
-          Utils.sprintf(`<input class="form-control${Utils.sprintf(' input-%s', this.options.iconSize)}" type="text" placeholder="%s">`,
-            this.options.formatSearch()),
-          '</div>')
+        html.push(`<div class="${this.constants.classes.pull}-${o.searchAlign} search ${this.constants.classes.input}">
+          <input class="form-control${Utils.sprintf(' input-%s', o.iconSize)}"
+          type="text" placeholder="${o.formatSearch()}">
+          </div>`)
 
         this.$toolbar.append(html.join(''))
         $search = this.$toolbar.find('.search input')
         $search.off('keyup drop blur').on('keyup drop blur', event => {
-          if (this.options.searchOnEnterKey && event.keyCode !== 13) {
+          if (o.searchOnEnterKey && event.keyCode !== 13) {
             return
           }
 
@@ -1240,7 +1276,7 @@
           clearTimeout(timeoutId) // doesn't matter if it's 0
           timeoutId = setTimeout(() => {
             this.onSearch(event)
-          }, this.options.searchTimeOut)
+          }, o.searchTimeOut)
         })
 
         if (Utils.isIEBrowser()) {
@@ -1248,7 +1284,7 @@
             clearTimeout(timeoutId) // doesn't matter if it's 0
             timeoutId = setTimeout(() => {
               this.onSearch(event)
-            }, this.options.searchTimeOut)
+            }, o.searchTimeOut)
           })
         }
       }
@@ -1355,7 +1391,8 @@
     }
 
     initPagination () {
-      if (!this.options.pagination) {
+      const o = this.options
+      if (!o.pagination) {
         this.$pagination.hide()
         return
       }
@@ -1371,118 +1408,115 @@
       let $next
       let $number
       const data = this.getData()
-      let pageList = this.options.pageList
+      let pageList = o.pageList
 
-      if (this.options.sidePagination !== 'server') {
-        this.options.totalRows = data.length
+      if (o.sidePagination !== 'server') {
+        o.totalRows = data.length
       }
 
       this.totalPages = 0
-      if (this.options.totalRows) {
-        if (this.options.pageSize === this.options.formatAllRows()) {
-          this.options.pageSize = this.options.totalRows
+      if (o.totalRows) {
+        if (o.pageSize === o.formatAllRows()) {
+          o.pageSize = o.totalRows
           $allSelected = true
-        } else if (this.options.pageSize === this.options.totalRows) {
+        } else if (o.pageSize === o.totalRows) {
           // Fix #667 Table with pagination,
           // multiple pages and a search this matches to one page throws exception
-          const pageLst = typeof this.options.pageList === 'string'
-            ? this.options.pageList.replace('[', '').replace(']', '')
-              .replace(/ /g, '').toLowerCase().split(',') : this.options.pageList
-          if (pageLst.includes(this.options.formatAllRows().toLowerCase())) {
+          const pageLst = typeof o.pageList === 'string'
+            ? o.pageList.replace('[', '').replace(']', '')
+              .replace(/ /g, '').toLowerCase().split(',') : o.pageList
+          if (pageLst.includes(o.formatAllRows().toLowerCase())) {
             $allSelected = true
           }
         }
 
-        this.totalPages = ~~((this.options.totalRows - 1) / this.options.pageSize) + 1
+        this.totalPages = ~~((o.totalRows - 1) / o.pageSize) + 1
 
-        this.options.totalPages = this.totalPages
+        o.totalPages = this.totalPages
       }
-      if (this.totalPages > 0 && this.options.pageNumber > this.totalPages) {
-        this.options.pageNumber = this.totalPages
+      if (this.totalPages > 0 && o.pageNumber > this.totalPages) {
+        o.pageNumber = this.totalPages
       }
 
-      this.pageFrom = (this.options.pageNumber - 1) * this.options.pageSize + 1
-      this.pageTo = this.options.pageNumber * this.options.pageSize
-      if (this.pageTo > this.options.totalRows) {
-        this.pageTo = this.options.totalRows
+      this.pageFrom = (o.pageNumber - 1) * o.pageSize + 1
+      this.pageTo = o.pageNumber * o.pageSize
+      if (this.pageTo > o.totalRows) {
+        this.pageTo = o.totalRows
       }
 
-      html.push(
-        Utils.sprintf('<div class="%s-%s pagination-detail">', bootstrap.classes.pull, this.options.paginationDetailHAlign),
-        '<span class="pagination-info">',
-        this.options.onlyInfoPagination ? this.options.formatDetailPagination(this.options.totalRows)
-          : this.options.formatShowingRows(this.pageFrom, this.pageTo, this.options.totalRows),
-        '</span>')
+      const paginationInfo = o.onlyInfoPagination ?
+        o.formatDetailPagination(o.totalRows) :
+        o.formatShowingRows(this.pageFrom, this.pageTo, o.totalRows)
 
-      if (!this.options.onlyInfoPagination) {
+      html.push(`<div class="${this.constants.classes.pull}-${o.paginationDetailHAlign} pagination-detail">
+        <span class="pagination-info">
+        ${paginationInfo}
+        </span>`)
+
+      if (!o.onlyInfoPagination) {
         html.push('<span class="page-list">')
 
         const pageNumber = [
-          Utils.sprintf('<span class="btn-group %s">',
-            this.options.paginationVAlign === 'top' || this.options.paginationVAlign === 'both'
-              ? 'dropdown' : 'dropup'),
-          `<button type="button" class="btn${Utils.sprintf(' btn-%s', this.options.buttonsClass)}${Utils.sprintf(' btn-%s', this.options.iconSize)} dropdown-toggle" data-toggle="dropdown">`,
-          '<span class="page-size">',
-          $allSelected ? this.options.formatAllRows() : this.options.pageSize,
-          '</span>',
-          ' <span class="caret"></span>',
-          '</button>',
-          bootstrap.html.pageDropdown[0]
-        ]
-
-        if (typeof this.options.pageList === 'string') {
-          const list = this.options.pageList.replace('[', '').replace(']', '')
+          `<span class="${this.constants.classes.paginationDropdown} ['top', 'both'].includes(o.paginationVAlign) ? 'dropdown' : 'dropup')">
+          <button class="${this.constants.buttonsClass} dropdown-toggle" type="button" data-toggle="dropdown">
+          <span class="page-size">
+          ${$allSelected ? o.formatAllRows() : o.pageSize}
+          </span>
+          ${this.constants.html.dropdownCaret}
+          </button>
+          ${this.constants.html.pageDropdown[0]}`]
+
+        if (typeof o.pageList === 'string') {
+          const list = o.pageList.replace('[', '').replace(']', '')
             .replace(/ /g, '').split(',')
 
           pageList = []
           for (const value of list) {
             pageList.push(
-              (value.toUpperCase() === this.options.formatAllRows().toUpperCase() ||
+              (value.toUpperCase() === o.formatAllRows().toUpperCase() ||
               value.toUpperCase() === 'UNLIMITED')
-                ? this.options.formatAllRows() : +value)
+                ? o.formatAllRows() : +value)
           }
         }
 
         pageList.forEach((page, i) => {
-          if (!this.options.smartDisplay || i === 0 || pageList[i - 1] < this.options.totalRows) {
+          if (!o.smartDisplay || i === 0 || pageList[i - 1] < o.totalRows) {
             let active
             if ($allSelected) {
-              active = page === this.options.formatAllRows() ? 'active' : ''
+              active = page === o.formatAllRows() ? 'active' : ''
             } else {
-              active = page === this.options.pageSize ? 'active' : ''
+              active = page === o.pageSize ? 'active' : ''
             }
-            pageNumber.push(Utils.sprintf(bootstrap.html.pageDropdownItem, active, page))
+            pageNumber.push(Utils.sprintf(this.constants.html.pageDropdownItem, active, page))
           }
         })
-        pageNumber.push(`${bootstrap.html.pageDropdown[1]}</span>`)
+        pageNumber.push(`${this.constants.html.pageDropdown[1]}</span>`)
 
-        html.push(this.options.formatRecordsPerPage(pageNumber.join('')))
-        html.push('</span>')
+        html.push(o.formatRecordsPerPage(pageNumber.join('')))
+        html.push('</span></div>')
 
-        html.push('</div>',
-          Utils.sprintf('<div class="%s-%s pagination">', bootstrap.classes.pull, this.options.paginationHAlign),
-          `<ul class="pagination${Utils.sprintf(' pagination-%s', this.options.iconSize)}">`,
-          Utils.sprintf('<li class="page-item page-pre"><a class="page-link" href="#">%s</a></li>',
-            this.options.paginationPreText))
+        html.push(`<div class="${this.constants.classes.pull}-${o.paginationHAlign} pagination">`,
+          Utils.sprintf(this.constants.html.pagination[0], Utils.sprintf(' pagination-%s', o.iconSize)),
+          Utils.sprintf(this.constants.html.paginationItem, ' page-pre', o.paginationPreText))
 
-        if (this.totalPages < this.options.paginationSuccessivelySize) {
+        if (this.totalPages < o.paginationSuccessivelySize) {
           from = 1
           to = this.totalPages
         } else {
-          from = this.options.pageNumber - this.options.paginationPagesBySide
-          to = from + (this.options.paginationPagesBySide * 2)
+          from = o.pageNumber - o.paginationPagesBySide
+          to = from + (o.paginationPagesBySide * 2)
         }
 
-        if (this.options.pageNumber < (this.options.paginationSuccessivelySize - 1)) {
-          to = this.options.paginationSuccessivelySize
+        if (o.pageNumber < (o.paginationSuccessivelySize - 1)) {
+          to = o.paginationSuccessivelySize
         }
 
         if (to > this.totalPages) {
           to = this.totalPages
         }
 
-        if (this.options.paginationSuccessivelySize > this.totalPages - from) {
-          from = from - (this.options.paginationSuccessivelySize - (this.totalPages - from)) + 1
+        if (o.paginationSuccessivelySize > this.totalPages - from) {
+          from = from - (o.paginationSuccessivelySize - (this.totalPages - from)) + 1
         }
 
         if (from < 1) {
@@ -1493,15 +1527,14 @@
           to = this.totalPages
         }
 
-        const middleSize = Math.round(this.options.paginationPagesBySide / 2)
-        const pageItem = (i, classes = '') => `
-          <li class="page-item${classes}${i === this.options.pageNumber ? ' active' : ''}">
-            <a class="page-link" href="#">${i}</a>
-          </li>
-        `
+        const middleSize = Math.round(o.paginationPagesBySide / 2)
+        const pageItem = (i, classes = '') => {
+          return Utils.sprintf(this.constants.html.paginationItem,
+            classes + (i === o.pageNumber ? ' active' : ''), i)
+        }
 
         if (from > 1) {
-          let max = this.options.paginationPagesBySide
+          let max = o.paginationPagesBySide
           if (max >= from) max = from - 1
           for (i = 1; i <= max; i++) {
             html.push(pageItem(i))
@@ -1512,17 +1545,14 @@
           } else {
             if ((from - 1) > max) {
               if (
-                (from - this.options.paginationPagesBySide * 2) > this.options.paginationPagesBySide &&
-                this.options.paginationUseIntermediate
+                (from - o.paginationPagesBySide * 2) > o.paginationPagesBySide &&
+                o.paginationUseIntermediate
               ) {
                 i = Math.round(((from - middleSize) / 2) + middleSize)
                 html.push(pageItem(i, ' page-intermediate'))
               } else {
-                html.push(`
-                  <li class="page-item page-first-separator disabled">
-                    <a class="page-link" href="#">...</a>
-                  </li>`
-                )
+                html.push(Utils.sprintf(this.constants.html.paginationItem,
+                  ' page-first-separator disabled', '...'))
               }
             }
           }
@@ -1533,7 +1563,7 @@
         }
 
         if (this.totalPages > to) {
-          let min = this.totalPages - (this.options.paginationPagesBySide - 1)
+          let min = this.totalPages - (o.paginationPagesBySide - 1)
           if (to >= min) min = to + 1
           if ((to + 1) === min - 1) {
             i = to + 1
@@ -1541,17 +1571,14 @@
           } else {
             if (min > (to + 1)) {
               if (
-                (this.totalPages - to) > this.options.paginationPagesBySide * 2 &&
-                this.options.paginationUseIntermediate
+                (this.totalPages - to) > o.paginationPagesBySide * 2 &&
+                o.paginationUseIntermediate
               ) {
                 i = Math.round(((this.totalPages - middleSize - to) / 2) + to)
                 html.push(pageItem(i, ' page-intermediate'))
               } else {
-                html.push(`
-                  <li class="page-item page-last-separator disabled">
-                    <a class="page-link" href="#">...</a>
-                  </li>`
-                )
+                html.push(Utils.sprintf(this.constants.html.paginationItem,
+                  ' page-last-separator disabled', '...'))
               }
             }
           }
@@ -1561,27 +1588,22 @@
           }
         }
 
-        html.push(`
-          <li class="page-item page-next">
-          <a class="page-link" href="#">${this.options.paginationNextText}</a>
-          </li>
-          </ul>
-          </div>
-        `)
+        html.push(Utils.sprintf(this.constants.html.paginationItem, ' page-next', o.paginationNextText))
+        html.push(this.constants.html.pagination[1], '</div>')
       }
       this.$pagination.html(html.join(''))
 
-      if (!this.options.onlyInfoPagination) {
+      if (!o.onlyInfoPagination) {
         $pageList = this.$pagination.find('.page-list a')
         $pre = this.$pagination.find('.page-pre')
         $next = this.$pagination.find('.page-next')
         $number = this.$pagination.find('.page-item').not('.page-next, .page-pre')
 
-        if (this.options.smartDisplay) {
+        if (o.smartDisplay) {
           if (this.totalPages <= 1) {
             this.$pagination.find('div.pagination').hide()
           }
-          if (pageList.length < 2 || this.options.totalRows <= pageList[0]) {
+          if (pageList.length < 2 || o.totalRows <= pageList[0]) {
             this.$pagination.find('span.page-list').hide()
           }
 
@@ -1589,17 +1611,17 @@
           this.$pagination[this.getData().length ? 'show' : 'hide']()
         }
 
-        if (!this.options.paginationLoop) {
-          if (this.options.pageNumber === 1) {
+        if (!o.paginationLoop) {
+          if (o.pageNumber === 1) {
             $pre.addClass('disabled')
           }
-          if (this.options.pageNumber === this.totalPages) {
+          if (o.pageNumber === this.totalPages) {
             $next.addClass('disabled')
           }
         }
 
         if ($allSelected) {
-          this.options.pageSize = this.options.formatAllRows()
+          o.pageSize = o.formatAllRows()
         }
         // removed the events for last and first, onPageNumber executeds the same logic
         $pageList.off('click').on('click', $.proxy(this.onPageListChange, this))
@@ -2460,7 +2482,7 @@
       if (this.options.showHeader && this.options.height) {
         this.$tableHeader.show()
         this.resetHeader()
-        padding += this.$header.outerHeight()
+        padding += this.$header.outerHeight(true)
       } else {
         this.$tableHeader.hide()
         this.trigger('post-header')
@@ -2469,7 +2491,7 @@
       if (this.options.showFooter) {
         this.resetFooter()
         if (this.options.height) {
-          padding += this.$tableFooter.outerHeight()
+          padding += this.$tableFooter.outerHeight(true)
         }
       }
 

+ 2 - 293
src/bootstrap-table.scss

@@ -4,296 +4,5 @@
  * https://github.com/wenzhixin/bootstrap-table/
  */
 
-$border-color: #dee2e6;
-$hover-bg: rgba(0,0,0,.075);
-$dark-border-color: #32383e;
-
-.bootstrap-table {
-  .fixed-table-toolbar {
-    &:after {
-      content: "";
-      display: block;
-      clear: both;
-    }
-
-    .bs-bars,
-    .search,
-    .columns {
-      position: relative;
-      margin-top: 10px;
-      margin-bottom: 10px;
-    }
-
-    .columns {
-      .btn-group > .btn-group {
-        display: inline-block;
-        margin-left: -1px !important;
-
-        &:first-child > .btn {
-          border-top-left-radius: 4px;
-          border-bottom-left-radius: 4px;
-        }
-
-        &:last-child > .btn {
-          border-top-right-radius: 4px;
-          border-bottom-right-radius: 4px;
-        }
-
-        > .btn {
-          border-radius: 0;
-        }
-      }
-
-      .dropdown-menu {
-        text-align: left;
-        max-height: 300px;
-        overflow: auto;
-      }
-
-      label {
-        display: block;
-        padding: 3px 20px;
-        clear: both;
-        font-weight: normal;
-        line-height: 1.428571429;
-      }
-    }
-
-    .columns-left {
-      margin-right: 5px;
-    }
-    .columns-right {
-      margin-left: 5px;
-    }
-
-    .pull-right .dropdown-menu {
-      right: 0;
-      left: auto;
-    }
-  }
-
-  .fixed-table-container {
-    position: relative;
-    clear: both;
-
-    &.fixed-height {
-      &:not(.has-footer) {
-        border-bottom: 1px solid $border-color;
-      }
-
-      .fixed-table-border {
-        border-left: 1px solid $border-color;
-        border-right: 1px solid $border-color;
-      }
-
-      .table {
-        thead th {
-          border-bottom: 1px solid $border-color;
-        }
-      }
-
-      .table-dark {
-        thead th {
-          border-bottom: 1px solid $dark-border-color;
-        }
-      }
-    }
-
-    .fixed-table-header {
-      overflow: hidden;
-    }
-
-    .fixed-table-body {
-      overflow-x: auto;
-      overflow-y: auto;
-      height: 100%;
-
-      .fixed-table-loading {
-        display: none;
-        position: absolute;
-        top: 42px;
-        right: 0;
-        bottom: 0;
-        left: 0;
-        z-index: 99;
-        background-color: #fff;
-        text-align: center;
-      }
-    }
-
-    .table {
-      width: 100%;
-      margin-bottom: 0 !important;
-
-      th,
-      td {
-        vertical-align: middle;
-        box-sizing: border-box;
-      }
-
-      thead th {
-        vertical-align: bottom;
-        padding: 0;
-        margin: 0;
-
-        &:focus {
-          outline: 0 solid transparent;
-        }
-
-        &.detail {
-          width: 30px;
-        }
-
-        .th-inner {
-          padding: .75rem;
-          vertical-align: bottom;
-          overflow: hidden;
-          text-overflow: ellipsis;
-          white-space: nowrap;
-        }
-
-        .sortable {
-          cursor: pointer;
-          background-position: right;
-          background-repeat: no-repeat;
-          padding-right: 30px;
-        }
-
-        .both {
-          background-image: url('data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAABMAAAATCAQAAADYWf5HAAAAkElEQVQoz7X QMQ5AQBCF4dWQSJxC5wwax1Cq1e7BAdxD5SL+Tq/QCM1oNiJidwox0355mXnG/DrEtIQ6azioNZQxI0ykPhTQIwhCR+BmBYtlK7kLJYwWCcJA9M4qdrZrd8pPjZWPtOqdRQy320YSV17OatFC4euts6z39GYMKRPCTKY9UnPQ6P+GtMRfGtPnBCiqhAeJPmkqAAAAAElFTkSuQmCC');
-        }
-
-        .asc {
-          background-image: url('data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAABMAAAATCAYAAAByUDbMAAAAZ0lEQVQ4y2NgGLKgquEuFxBPAGI2ahhWCsS/gDibUoO0gPgxEP8H4ttArEyuQYxAPBdqEAxPBImTY5gjEL9DM+wTENuQahAvEO9DMwiGdwAxOymGJQLxTyD+jgWDxCMZRsEoGAVoAADeemwtPcZI2wAAAABJRU5ErkJggg==');
-        }
-
-        .desc {
-          background-image: url('data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAABMAAAATCAYAAAByUDbMAAAAZUlEQVQ4y2NgGAWjYBSggaqGu5FA/BOIv2PBIPFEUgxjB+IdQPwfC94HxLykus4GiD+hGfQOiB3J8SojEE9EM2wuSJzcsFMG4ttQgx4DsRalkZENxL+AuJQaMcsGxBOAmGvopk8AVz1sLZgg0bsAAAAASUVORK5CYII= ');
-        }
-      }
-
-      tbody tr {
-        &.selected td {
-          background-color: $hover-bg;
-        }
-
-        &.no-records-found {
-          text-align: center;
-        }
-
-        .card-view .title {
-          font-weight: bold;
-          display: inline-block;
-          min-width: 30%;
-          text-align: left !important;
-        }
-      }
-
-      .bs-checkbox {
-        text-align: center;
-      }
-
-      input[type="radio"],
-      input[type="checkbox"] {
-        margin: 0 auto !important;
-      }
-
-      &.table-sm .th-inner {
-        padding: .3rem;
-      }
-    }
-
-    .fixed-table-footer {
-      overflow: hidden;
-    }
-  }
-
-  .fixed-table-pagination {
-    &:after {
-      content: "";
-      display: block;
-      clear: both;
-    }
-
-    > .pagination-detail,
-    > .pagination {
-      margin-top: 10px;
-      margin-bottom: 10px;
-    }
-
-    > .pagination-detail {
-      .pagination-info {
-        line-height: 34px;
-        margin-right: 5px;
-      }
-
-      .page-list {
-        display: inline-block;
-
-        .btn-group {
-          position: relative;
-          display: inline-block;
-          vertical-align: middle;
-
-          .dropdown-menu {
-            margin-bottom: 0;
-          }
-        }
-      }
-    }
-
-    > .pagination {
-      ul.pagination {
-        margin: 0;
-
-        a {
-          padding: 6px 12px;
-          line-height: 1.428571429;
-        }
-
-        li.page-intermediate {
-          a {
-            &:before {
-              content: '\2B05';
-            }
-
-            &:after {
-              content: '\27A1';
-            }
-
-            color:#c8c8c8;
-          }
-        }
-
-        li.disabled a {
-          pointer-events: none;
-          cursor: default;
-        }
-      }
-    }
-  }
-
-  &.fullscreen {
-    position: fixed;
-    top: 0;
-    left: 0;
-    z-index: 1050;
-    width: 100%!important;
-    background: #FFF;
-  }
-}
-
-/* calculate scrollbar width */
-div.fixed-table-scroll-inner {
-  width: 100%;
-  height: 200px;
-}
-
-div.fixed-table-scroll-outer {
-  top: 0;
-  left: 0;
-  visibility: hidden;
-  width: 200px;
-  height: 150px;
-  overflow: hidden;
-}
+@import './themes/bootstrap/variables.scss';
+@import './themes/bootstrap-table.scss';

+ 289 - 0
src/themes/bootstrap-table.scss

@@ -0,0 +1,289 @@
+.bootstrap-table {
+  .fixed-table-toolbar {
+    &:after {
+      content: "";
+      display: block;
+      clear: both;
+    }
+
+    .bs-bars,
+    .search,
+    .columns {
+      position: relative;
+      margin-top: 10px;
+      margin-bottom: 10px;
+    }
+
+    .columns {
+      .btn-group > .btn-group {
+        display: inline-block;
+        margin-left: -1px !important;
+
+        &:first-child > .btn {
+          border-top-left-radius: 4px;
+          border-bottom-left-radius: 4px;
+        }
+
+        &:last-child > .btn {
+          border-top-right-radius: 4px;
+          border-bottom-right-radius: 4px;
+        }
+
+        > .btn {
+          border-radius: 0;
+        }
+      }
+
+      .dropdown-menu {
+        text-align: left;
+        max-height: 300px;
+        overflow: auto;
+      }
+
+      label {
+        display: block;
+        padding: 3px 20px;
+        clear: both;
+        font-weight: normal;
+        line-height: 1.428571429;
+      }
+    }
+
+    .columns-left {
+      margin-right: 5px;
+    }
+    .columns-right {
+      margin-left: 5px;
+    }
+
+    .pull-right .dropdown-menu {
+      right: 0;
+      left: auto;
+    }
+  }
+
+  .fixed-table-container {
+    position: relative;
+    clear: both;
+
+    &.fixed-height {
+      &:not(.has-footer) {
+        border-bottom: 1px solid $border-color;
+      }
+
+      .fixed-table-border {
+        border-left: 1px solid $border-color;
+        border-right: 1px solid $border-color;
+      }
+
+      .table {
+        thead th {
+          border-bottom: 1px solid $border-color;
+        }
+      }
+
+      .table-dark {
+        thead th {
+          border-bottom: 1px solid $dark-border-color;
+        }
+      }
+    }
+
+    .fixed-table-header {
+      overflow: hidden;
+    }
+
+    .fixed-table-body {
+      overflow-x: auto;
+      overflow-y: auto;
+      height: 100%;
+
+      .fixed-table-loading {
+        display: none;
+        position: absolute;
+        top: 42px;
+        right: 0;
+        bottom: 0;
+        left: 0;
+        z-index: 99;
+        background-color: #fff;
+        text-align: center;
+      }
+    }
+
+    .table {
+      width: 100%;
+      margin-bottom: 0 !important;
+
+      th,
+      td {
+        vertical-align: middle;
+        box-sizing: border-box;
+      }
+
+      thead th {
+        vertical-align: bottom;
+        padding: 0;
+        margin: 0;
+
+        &:focus {
+          outline: 0 solid transparent;
+        }
+
+        &.detail {
+          width: 30px;
+        }
+
+        .th-inner {
+          padding: .75rem;
+          vertical-align: bottom;
+          overflow: hidden;
+          text-overflow: ellipsis;
+          white-space: nowrap;
+        }
+
+        .sortable {
+          cursor: pointer;
+          background-position: right;
+          background-repeat: no-repeat;
+          padding-right: 30px;
+        }
+
+        .both {
+          background-image: url('data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAABMAAAATCAQAAADYWf5HAAAAkElEQVQoz7X QMQ5AQBCF4dWQSJxC5wwax1Cq1e7BAdxD5SL+Tq/QCM1oNiJidwox0355mXnG/DrEtIQ6azioNZQxI0ykPhTQIwhCR+BmBYtlK7kLJYwWCcJA9M4qdrZrd8pPjZWPtOqdRQy320YSV17OatFC4euts6z39GYMKRPCTKY9UnPQ6P+GtMRfGtPnBCiqhAeJPmkqAAAAAElFTkSuQmCC');
+        }
+
+        .asc {
+          background-image: url('data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAABMAAAATCAYAAAByUDbMAAAAZ0lEQVQ4y2NgGLKgquEuFxBPAGI2ahhWCsS/gDibUoO0gPgxEP8H4ttArEyuQYxAPBdqEAxPBImTY5gjEL9DM+wTENuQahAvEO9DMwiGdwAxOymGJQLxTyD+jgWDxCMZRsEoGAVoAADeemwtPcZI2wAAAABJRU5ErkJggg==');
+        }
+
+        .desc {
+          background-image: url('data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAABMAAAATCAYAAAByUDbMAAAAZUlEQVQ4y2NgGAWjYBSggaqGu5FA/BOIv2PBIPFEUgxjB+IdQPwfC94HxLykus4GiD+hGfQOiB3J8SojEE9EM2wuSJzcsFMG4ttQgx4DsRalkZENxL+AuJQaMcsGxBOAmGvopk8AVz1sLZgg0bsAAAAASUVORK5CYII= ');
+        }
+      }
+
+      tbody tr {
+        &.selected td {
+          background-color: $hover-bg;
+        }
+
+        &.no-records-found {
+          text-align: center;
+        }
+
+        .card-view .title {
+          font-weight: bold;
+          display: inline-block;
+          min-width: 30%;
+          text-align: left !important;
+        }
+      }
+
+      .bs-checkbox {
+        text-align: center;
+      }
+
+      input[type="radio"],
+      input[type="checkbox"] {
+        margin: 0 auto !important;
+      }
+
+      &.table-sm .th-inner {
+        padding: .3rem;
+      }
+    }
+
+    .fixed-table-footer {
+      overflow: hidden;
+    }
+  }
+
+  .fixed-table-pagination {
+    &:after {
+      content: "";
+      display: block;
+      clear: both;
+    }
+
+    > .pagination-detail,
+    > .pagination {
+      margin-top: 10px;
+      margin-bottom: 10px;
+    }
+
+    > .pagination-detail {
+      .pagination-info {
+        line-height: 34px;
+        margin-right: 5px;
+      }
+
+      .page-list {
+        display: inline-block;
+
+        .btn-group {
+          position: relative;
+          display: inline-block;
+          vertical-align: middle;
+
+          .dropdown-menu {
+            margin-bottom: 0;
+          }
+        }
+      }
+    }
+
+    > .pagination {
+      ul.pagination {
+        margin: 0;
+
+        a {
+          padding: 6px 12px;
+          line-height: 1.428571429;
+        }
+
+        li.page-intermediate {
+          a {
+            &:before {
+              content: '\2B05';
+            }
+
+            &:after {
+              content: '\27A1';
+            }
+
+            color:#c8c8c8;
+          }
+        }
+
+        li.disabled a {
+          pointer-events: none;
+          cursor: default;
+        }
+      }
+    }
+  }
+
+  &.fullscreen {
+    position: fixed;
+    top: 0;
+    left: 0;
+    z-index: 1050;
+    width: 100%!important;
+    background: #FFF;
+  }
+}
+
+/* calculate scrollbar width */
+div.fixed-table-scroll-inner {
+  width: 100%;
+  height: 200px;
+}
+
+div.fixed-table-scroll-outer {
+  top: 0;
+  left: 0;
+  visibility: hidden;
+  width: 200px;
+  height: 150px;
+  overflow: hidden;
+}

+ 3 - 0
src/themes/bootstrap/variables.scss

@@ -0,0 +1,3 @@
+$border-color: #dee2e6;
+$hover-bg: rgba(0,0,0,.075);
+$dark-border-color: #32383e;