浏览代码

Merge pull request #7244 from wenzhixin/fix/7232

Rebuilt and improved pipeline extension
文翼 1 年之前
父节点
当前提交
657235c6d6
共有 2 个文件被更改,包括 142 次插入208 次删除
  1. 3 1
      src/bootstrap-table.js
  2. 139 207
      src/extensions/pipeline/bootstrap-table-pipeline.js

+ 3 - 1
src/bootstrap-table.js

@@ -1236,7 +1236,9 @@ class BootstrapTable {
     }
 
     if (this.paginationParts.includes('pageInfo') || this.paginationParts.includes('pageInfoShort')) {
-      const paginationInfo = this.paginationParts.includes('pageInfoShort') ? opts.formatDetailPagination(opts.totalRows) : opts.formatShowingRows(this.pageFrom, this.pageTo, opts.totalRows, opts.totalNotFiltered)
+      const paginationInfo = this.paginationParts.includes('pageInfoShort') ?
+        opts.formatDetailPagination(opts.totalRows) :
+        opts.formatShowingRows(this.pageFrom, this.pageTo, opts.totalRows, opts.totalNotFiltered)
 
       html.push(`<span class="pagination-info">
       ${paginationInfo}

+ 139 - 207
src/extensions/pipeline/bootstrap-table-pipeline.js

@@ -67,222 +67,173 @@ Object.assign($.fn.bootstrapTable.events, {
   'cached-data-reset.bs.table': 'onCachedDataReset'
 })
 
-const BootstrapTable = $.fn.bootstrapTable.Constructor
-const _init = BootstrapTable.prototype.init
-const _onSearch = BootstrapTable.prototype.onSearch
-const _onSort = BootstrapTable.prototype.onSort
-const _onPageListChange = BootstrapTable.prototype.onPageListChange
-
-BootstrapTable.prototype.init = function (...args) {
-  // needs to be called before initServer()
-  this.initPipeline()
-  _init.apply(this, Array.prototype.slice.apply(args))
-}
-
-BootstrapTable.prototype.initPipeline = function () {
-  this.cacheRequestJSON = {}
-  this.cacheWindows = []
-  this.currWindow = 0
-  this.resetCache = true
-}
-
-BootstrapTable.prototype.onSearch = function () {
-  /* force a cache reset on search */
-  if (this.options.usePipeline) {
-    this.resetCache = true
+$.BootstrapTable = class extends $.BootstrapTable {
+  // needs to be called before initServer
+  init (...args) {
+    if (this.options.usePipeline) {
+      this.initPipeline()
+    }
+    super.init(...args)
   }
-  _onSearch.apply(this, Array.prototype.slice.apply(arguments))
-}
 
-BootstrapTable.prototype.onSort = function () {
-  /* force a cache reset on sort */
-  if (this.options.usePipeline) {
+  initPipeline () {
+    this.cacheRequestJSON = {}
+    this.cacheWindows = []
+    this.currWindow = 0
     this.resetCache = true
   }
-  _onSort.apply(this, Array.prototype.slice.apply(arguments))
-}
 
-BootstrapTable.prototype.onPageListChange = function (event) {
-  /* rebuild cache window on page size change */
-  const target = $(event.currentTarget)
-  const newPageSize = parseInt(target.text(), 10)
-
-  this.options.pipelineSize = this.calculatePipelineSize(this.options.pipelineSize, newPageSize)
-  this.resetCache = true
-  _onPageListChange.apply(this, Array.prototype.slice.apply(arguments))
-}
-
-BootstrapTable.prototype.calculatePipelineSize = (pipelineSize, pageSize) => {
-  /* calculate pipeline size by rounding up to the nearest value evenly divisible
-   * by the pageSize */
-  if (pageSize === 0) return 0
-  return Math.ceil(pipelineSize / pageSize) * pageSize
-}
+  // force a cache reset on search
+  onSearch (...args) {
+    if (this.options.usePipeline) {
+      this.resetCache = true
+    }
+    super.onSearch(...args)
+  }
 
-BootstrapTable.prototype.setCacheWindows = function () {
-  /* set cache windows based on the total number of rows returned by server side
-   * request and the pipelineSize */
-  this.cacheWindows = []
-  const numWindows = this.options.totalRows / this.options.pipelineSize
+  // force a cache reset on sort
+  onSort (...args) {
+    if (this.options.usePipeline) {
+      this.resetCache = true
+    }
+    super.onSort(...args)
+  }
 
-  for (let i = 0; i <= numWindows; i++) {
-    const b = i * this.options.pipelineSize
+  // rebuild cache window on page size change
+  onPageListChange (event) {
+    const target = $(event.currentTarget)
+    const newPageSize = parseInt(target.text(), 10)
 
-    this.cacheWindows[i] = { lower: b, upper: b + this.options.pipelineSize - 1 }
+    this.options.pipelineSize = this.calculatePipelineSize(this.options.pipelineSize, newPageSize)
+    this.resetCache = true
+    super.onPageListChange(event)
   }
-}
 
-BootstrapTable.prototype.setCurrWindow = function (offset) {
-  /* set the current cache window index, based on where the current offset falls */
-  this.currWindow = 0
-  for (let i = 0; i < this.cacheWindows.length; i++) {
-    if (this.cacheWindows[i].lower <= offset && offset <= this.cacheWindows[i].upper) {
-      this.currWindow = i
-      break
+  // calculate pipeline size by rounding up to
+  // the nearest value evenly divisible by the pageSize
+  calculatePipelineSize (pipelineSize, pageSize) {
+    if (pageSize === 0) {
+      return 0
     }
+    return Math.ceil(pipelineSize / pageSize) * pageSize
   }
-}
 
-BootstrapTable.prototype.drawFromCache = function (offset, limit) {
-  /* draw rows from the cache using offset and limit */
-  const res = Utils.extend(true, {}, this.cacheRequestJSON)
-  const drawStart = offset - this.cacheWindows[this.currWindow].lower
-  const drawEnd = drawStart + limit
+  // set cache windows based on the total number of rows returned
+  // by server side request and the pipelineSize
+  setCacheWindows () {
+    this.cacheWindows = []
 
-  res.rows = res.rows.slice(drawStart, drawEnd)
-  return res
-}
+    for (let i = 0; i <= this.options.totalRows / this.options.pipelineSize; i++) {
+      const lower = i * this.options.pipelineSize
 
-BootstrapTable.prototype.initServer = function (silent, query, url) {
-  /* determine if requested data is in cache (on paging) or if
-   * a new ajax request needs to be issued (sorting, searching, paging
-   * moving outside of cached data, page size change)
-   * initial version of this extension will entirely override base initServer
-   */
-
-  let data = {}
-  const index = this.header.fields.indexOf(this.options.sortName)
-
-  let params = {
-    searchText: this.searchText,
-    sortName: this.options.sortName,
-    sortOrder: this.options.sortOrder
+      this.cacheWindows[i] = { lower, upper: lower + this.options.pipelineSize - 1 }
+    }
   }
 
-  let request = null
+  // set the current cache window index, based on where the current offset falls
+  setCurrWindow (offset) {
+    this.currWindow = 0
 
-  if (this.header.sortNames[index]) {
-    params.sortName = this.header.sortNames[index]
+    for (let i = 0; i < this.cacheWindows.length; i++) {
+      if (this.cacheWindows[i].lower <= offset && offset <= this.cacheWindows[i].upper) {
+        this.currWindow = i
+        break
+      }
+    }
   }
 
-  if (this.options.pagination && this.options.sidePagination === 'server') {
-    params.pageSize = this.options.pageSize === this.options.formatAllRows() ?
-      this.options.totalRows : this.options.pageSize
-    params.pageNumber = this.options.pageNumber
-  }
+  // draw rows from the cache using offset and limit
+  drawFromCache (offset, limit) {
+    const res = Utils.extend(true, {}, this.cacheRequestJSON)
+    const drawStart = offset - this.cacheWindows[this.currWindow].lower
+    const drawEnd = drawStart + limit
 
-  if (!(url || this.options.url) && !this.options.ajax) {
-    return
+    res.rows = res.rows.slice(drawStart, drawEnd)
+    return res
   }
 
-  let useAjax = true
-
-  if (this.options.queryParamsType === 'limit') {
-    params = {
-      searchText: params.searchText,
-      sortName: params.sortName,
-      sortOrder: params.sortOrder
+  /*
+   * determine if requested data is in cache (on paging) or if
+   * a new ajax request needs to be issued (sorting, searching, paging
+   * moving outside of cached data, page size change)
+   * initial version of this extension will entirely override base initServer
+   */
+  initServer (silent, query, url) {
+    if (!this.options.usePipeline) {
+      return super.initServer(silent, query, url)
     }
-    if (this.options.pagination && this.options.sidePagination === 'server') {
-      params.limit = this.options.pageSize === this.options.formatAllRows() ? this.options.totalRows : this.options.pageSize
-      params.offset = (this.options.pageSize === this.options.formatAllRows() ? this.options.totalRows : this.options.pageSize) * (this.options.pageNumber - 1)
-      if (this.options.usePipeline) {
-        // if cacheWindows is empty, this is the initial request
-        if (!this.cacheWindows.length) {
+
+    let useAjax = true
+    const params = {}
+
+    if (
+      this.options.queryParamsType === 'limit' &&
+      this.options.pagination &&
+      this.options.sidePagination === 'server'
+    ) {
+      // same as parent initServer: params.offset
+      params.offset = this.options.pageSize === this.options.formatAllRows() ?
+        0 : this.options.pageSize * (this.options.pageNumber - 1)
+      params.limit = this.options.pageSize
+
+      // if cacheWindows is empty, this is the initial request
+      if (!this.cacheWindows.length) {
+        useAjax = true
+        params.drawOffset = params.offset
+        // cache exists: determine if the page request is entirely within the current cached window
+      } else {
+        const w = this.cacheWindows[this.currWindow]
+
+        // case 1: reset cache but stay within current window (e.g. column sort)
+        // case 2: move outside of the current window (e.g. search or paging)
+        //  since each cache window is aligned with the current page size
+        //  checking if params.offset is outside the current window is sufficient.
+        //  need to re-query for preceding or succeeding cache window
+        //  also handle case
+        if (this.resetCache || (params.offset < w.lower || params.offset > w.upper)) {
           useAjax = true
+          this.setCurrWindow(params.offset)
+          // store the relative offset for drawing the page data afterwards
           params.drawOffset = params.offset
-          // cache exists: determine if the page request is entirely within the current cached window
+          // now set params.offset to the lower bound of the new cache window
+          // the server will return that whole cache window
+          params.offset = this.cacheWindows[this.currWindow].lower
+          // within current cache window
         } else {
-          const w = this.cacheWindows[this.currWindow]
-
-          // case 1: reset cache but stay within current window (e.g. column sort)
-          // case 2: move outside of the current window (e.g. search or paging)
-          //  since each cache window is aligned with the current page size
-          //  checking if params.offset is outside the current window is sufficient.
-          //  need to re-query for preceding or succeeding cache window
-          //  also handle case
-          if (this.resetCache || (params.offset < w.lower || params.offset > w.upper)) {
-            useAjax = true
-            this.setCurrWindow(params.offset)
-            // store the relative offset for drawing the page data afterwards
-            params.drawOffset = params.offset
-            // now set params.offset to the lower bound of the new cache window
-            // the server will return that whole cache window
-            params.offset = this.cacheWindows[this.currWindow].lower
-            // within current cache window
-          } else {
-            useAjax = false
-          }
+          useAjax = false
         }
-      } else if (params.limit === 0) {
-        delete params.limit
       }
     }
-  }
 
-  // force an ajax call - this is on search, sort or page size change
-  if (this.resetCache) {
-    useAjax = true
-    this.resetCache = false
-  }
-
-  if (this.options.usePipeline && useAjax) {
-    /* in this scenario limit is used on the server to get the cache window
-            * and drawLimit is used to get the page data afterwards */
-    params.drawLimit = params.limit
-    params.limit = this.options.pipelineSize
-  }
-
-  // cached results can be used
-  if (!useAjax) {
-    const res = this.drawFromCache(params.offset, params.limit)
+    // force an ajax call - this is on search, sort or page size change
+    if (this.resetCache) {
+      useAjax = true
+      this.resetCache = false
+    }
 
-    this.load(res)
-    this.trigger('load-success', res)
-    this.trigger('cached-data-hit', res)
-    return
-  }
-  // cached results can't be used
-  // continue base initServer code
-  if (!$.isEmptyObject(this.filterColumnsPartial)) {
-    params.filter = JSON.stringify(this.filterColumnsPartial, null)
-  }
+    if (useAjax) {
+      // in this scenario limit is used on the server to get the cache window
+      // and drawLimit is used to get the page data afterwards
+      params.drawLimit = params.limit
+      params.limit = this.options.pipelineSize
+    }
 
-  data = Utils.calculateObjectValue(this.options, this.options.queryParams, [params], data)
+    // cached results can be used
+    if (!useAjax) {
+      const res = this.drawFromCache(params.offset, params.limit)
 
-  Utils.extend(data, query || {})
+      this.load(res)
+      this.trigger('load-success', res)
+      this.trigger('cached-data-hit', res)
+      return
+    }
 
-  // false to stop request
-  if (data === false) {
-    return
-  }
+    if (!this.pipelineResponseHandler) {
+      this.pipelineResponseHandler = this.options.responseHandler
 
-  if (!silent) {
-    this.$showLoading()
-  }
+      this.options.responseHandler = (_res, jqXHR) => {
+        let res = Utils.calculateObjectValue(this.options, this.pipelineResponseHandler, [_res, jqXHR], _res)
 
-  request = Utils.extend({}, Utils.calculateObjectValue(null, this.options.ajaxOptions), {
-    type: this.options.method,
-    url: url || this.options.url,
-    data: this.options.contentType === 'application/json' && this.options.method === 'post' ?
-      JSON.stringify(data) : data,
-    cache: this.options.cache,
-    contentType: this.options.contentType,
-    dataType: this.options.dataType,
-    success: res => {
-      res = Utils.calculateObjectValue(this.options, this.options.responseHandler, [res], res)
-      // cache results if using pipelining
-      if (this.options.usePipeline) {
         // store entire request in cache
         this.cacheRequestJSON = Utils.extend(true, {}, res)
         // this gets set in load() also but needs to be set before
@@ -292,39 +243,20 @@ BootstrapTable.prototype.initServer = function (silent, query, url) {
         // so cache windows need to be rebuilt. Otherwise it
         // will come out the same
         this.setCacheWindows()
-        this.setCurrWindow(params.drawOffset)
         // just load data for the page
         res = this.drawFromCache(params.drawOffset, params.drawLimit)
         this.trigger('cached-data-reset', res)
-      }
-      this.load(res)
-      this.trigger('load-success', res)
-      if (!silent) {
-        this.hideLoading()
-      }
-    },
-    error: res => {
-      let data = []
-
-      if (this.options.sidePagination === 'server') {
-        data = {}
-        data[this.options.totalField] = 0
-        data[this.options.dataField] = []
-      }
-      this.load(data)
-      this.trigger('load-error', res.status, res)
-      if (!silent) {
-        this.hideLoading()
+        return res
       }
     }
-  })
 
-  if (this.options.ajax) {
-    Utils.calculateObjectValue(this, this.options.ajax, [request], null)
-  } else {
-    if (this._xhr && this._xhr.readyState !== 4) {
-      this._xhr.abort()
-    }
-    this._xhr = $.ajax(request)
+    return super.initServer(silent, { ...query, ...params }, url)
+  }
+
+  destroy (...args) {
+    this.options.responseHandler = this.pipelineResponseHandler
+    this.pipelineResponseHandler = null
+
+    super.destroy(...args)
   }
 }