jquery.dgtable 0.6.1 → 0.6.2

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
@@ -1,5 +1,5 @@
1
1
  /*!
2
- * jquery.dgtable 0.6.1
2
+ * jquery.dgtable 0.6.2
3
3
  * git://github.com/danielgindi/jquery.dgtable.git
4
4
  */
5
5
  import jQuery from 'jquery';
@@ -1784,6 +1784,45 @@ class SelectionHelper {
1784
1784
 
1785
1785
  const hasOwnProperty$1 = Object.prototype.hasOwnProperty;
1786
1786
 
1787
+ const hasInsertAdjacentElement = Element.prototype.insertAdjacentElement !== undefined;
1788
+
1789
+ function insertBefore(el, before, parent) {
1790
+ if (!before)
1791
+ parent.appendChild(el);else
1792
+ if (hasInsertAdjacentElement === true)
1793
+ before.insertAdjacentElement('beforebegin', el);else
1794
+ parent.insertBefore(el, before);
1795
+ }
1796
+
1797
+ /**
1798
+ *
1799
+ * @param {Element} itemEl
1800
+ * @param {DocumentFragment|null} fragment
1801
+ * @param {Node|undefined} before
1802
+ * @param {Element} itemParent
1803
+ * @returns {DocumentFragment|null}
1804
+ */
1805
+ function insertBeforeWithFragment(itemEl, fragment, before, itemParent) {
1806
+ if (itemEl.parentNode !== itemParent) {
1807
+ if (!fragment)
1808
+ fragment = document.createDocumentFragment();
1809
+ fragment.appendChild(itemEl);
1810
+ } else {
1811
+ // insert fragment
1812
+ if (fragment && fragment.childNodes.length > 0) {
1813
+ insertBefore(fragment, before, itemParent);
1814
+ fragment = null;
1815
+ }
1816
+
1817
+ // insert element
1818
+ if (itemEl.nextSibling !== before) {
1819
+ insertBefore(itemEl, before, itemParent);
1820
+ }
1821
+ }
1822
+
1823
+ return fragment;
1824
+ }
1825
+
1787
1826
  class VirtualListHelper {
1788
1827
  /**
1789
1828
  * @param {VirtualListHelper~Options} opts
@@ -2162,6 +2201,7 @@ class VirtualListHelper {
2162
2201
  const list = p.list;
2163
2202
  const virtual = p.virtual;
2164
2203
  let virtualWrapper = p.virtualWrapper;
2204
+ let itemParent = p.currentItemsParent;
2165
2205
  let scrollTop = list.scrollTop;
2166
2206
  let visibleHeight = list.clientHeight;
2167
2207
  let visibleBottom = scrollTop + visibleHeight;
@@ -2182,6 +2222,7 @@ class VirtualListHelper {
2182
2222
  }
2183
2223
 
2184
2224
  this._resetCurrentItemsParent();
2225
+ itemParent = p.currentItemsParent;
2185
2226
 
2186
2227
  if (p.autoVirtualWrapperWidth) {
2187
2228
  virtualWrapper.style.width = '100%';
@@ -2211,12 +2252,18 @@ class VirtualListHelper {
2211
2252
  let renderPos = this._calculateItemPosition(index);
2212
2253
  let bufferEnd = buffer;
2213
2254
 
2214
- /** @type Node|undefined */
2215
- let lastEl = undefined;
2255
+ // we want to render until viewport's bottom + buffer items
2256
+ let maxIndexToRender = Math.max(index, binarySearchPosition(p.cachedItemPositions, visibleBottom - 1) + 1 + buffer);
2257
+
2258
+ let insertedItems = [];
2216
2259
 
2217
- // If rendering position has not reached the viewport bottom
2218
- // AND we have not rendered all the buffer items yet
2219
- while ((renderPos < visibleBottom || bufferEnd-- > 0) && index < count) {
2260
+ /** @type DocumentFragment|null */
2261
+ let fragment = null;
2262
+
2263
+ // Find the element to insert before
2264
+ let before = virtualWrapper.childNodes[0];
2265
+
2266
+ const findElementToReuse = function (index) {
2220
2267
  // Find existing element to reuse
2221
2268
  /** @type Element|undefined */
2222
2269
  let existingEl = undefined;
@@ -2238,20 +2285,53 @@ class VirtualListHelper {
2238
2285
  delete existingEl[ReuseElSymbol];
2239
2286
  }
2240
2287
 
2241
- // Find the element to insert before
2242
- let insertBefore = lastEl ? lastEl.nextSibling : virtualWrapper.childNodes[0];
2243
- if (insertBefore && insertBefore === existingEl)
2244
- insertBefore = insertBefore.nextSibling;
2288
+ return existingEl;
2289
+ };
2290
+
2291
+ // First we iterate and try to add all at once in a fragment, as much as we can.
2292
+ // And then reflow the at once.
2293
+ for (; index < count && index < maxIndexToRender; index++) {
2294
+ let existingEl = findElementToReuse(index);
2295
+
2296
+ if (before && before === existingEl)
2297
+ before = before.nextSibling;
2245
2298
 
2246
2299
  // Dequeue the element by reusing or creating a new one
2247
- lastEl = this._dequeueElementForIndex(existingEl, index, insertBefore);
2300
+ const itemEl = this._dequeueElementForIndex(existingEl, index, before, true);
2301
+ insertedItems.push([itemEl, index]);
2302
+
2303
+ fragment = insertBeforeWithFragment(itemEl, fragment, before, itemParent);
2304
+ }
2305
+
2306
+ // Insert any remaining fragment
2307
+ if (fragment && fragment.childNodes.length > 0) {
2308
+ insertBefore(fragment, before, itemParent);
2309
+ }
2248
2310
 
2249
- // Increment pointers
2311
+ // Iterate on inserted items and reflow them
2312
+ for (let item of insertedItems) {
2313
+ const index = item[1];
2314
+ this._insertItemAndFlow(item[0], index, false /* inserted already */);
2250
2315
  renderPos = p.cachedItemPositions[index] + p.cachedItemHeights[index];
2251
- index++;
2252
2316
  }
2253
2317
 
2254
- // Calculate up to date scroll height
2318
+ // See if we still need to insert more items
2319
+ if (renderPos < visibleBottom) {
2320
+ for (; (renderPos < visibleBottom || bufferEnd-- > 0) && index < count; index++) {
2321
+ let existingEl = findElementToReuse(index);
2322
+
2323
+ if (before && before === existingEl)
2324
+ before = before.nextSibling;
2325
+
2326
+ // Dequeue the element by reusing or creating a new one
2327
+ this._dequeueElementForIndex(existingEl, index, before, false);
2328
+
2329
+ // Increment pointers
2330
+ renderPos = p.cachedItemPositions[index] + p.cachedItemHeights[index];
2331
+ }
2332
+ }
2333
+
2334
+ // Calculate up-to-date scroll height
2255
2335
  let scrollHeight = this.estimateFullHeight();
2256
2336
  p.virtualWrapper.style.height = scrollHeight + 'px';
2257
2337
 
@@ -2263,8 +2343,12 @@ class VirtualListHelper {
2263
2343
  existingEls[i][ReuseElSymbol] = true;
2264
2344
  }
2265
2345
 
2266
- /** @type Node|undefined */
2267
- let lastEl = undefined;
2346
+ // Find the element to insert before
2347
+ let before = list.childNodes[0];
2348
+
2349
+ /** @type DocumentFragment|null */
2350
+ let fragment = null;
2351
+
2268
2352
  for (let index = 0; index < count; index++) {
2269
2353
  // Find existing element to reuse
2270
2354
  let existingEl = existingEls.find((x) => x[ItemIndexSymbol] === index && x[ReuseElSymbol] === true);
@@ -2273,13 +2357,18 @@ class VirtualListHelper {
2273
2357
  delete existingEl[ReuseElSymbol];
2274
2358
  }
2275
2359
 
2276
- // Find the element to insert before
2277
- let insertBefore = lastEl ? lastEl.nextSibling : list.childNodes[0];
2278
- if (insertBefore && insertBefore === existingEl)
2279
- insertBefore = insertBefore.nextSibling;
2360
+ if (before && before === existingEl)
2361
+ before = before.nextSibling;
2280
2362
 
2281
2363
  // Dequeue the element by reusing or creating a new one
2282
- lastEl = this._dequeueElementForIndex(existingEl, index, insertBefore);
2364
+ const itemEl = this._dequeueElementForIndex(existingEl, index, before, true);
2365
+
2366
+ fragment = insertBeforeWithFragment(itemEl, fragment, before, itemParent);
2367
+ }
2368
+
2369
+ // Insert any remaining fragment
2370
+ if (fragment && fragment.childNodes.length > 0) {
2371
+ insertBefore(fragment, before, itemParent);
2283
2372
  }
2284
2373
  }
2285
2374
  }
@@ -2335,16 +2424,28 @@ class VirtualListHelper {
2335
2424
  if (existingRange.firstValidArrayIndex === -1)
2336
2425
  return this;
2337
2426
 
2427
+ const itemParent = p.currentItemsParent;
2428
+
2338
2429
  let startIndex = existingRange.firstValidArrayIndex + atIndex - existingRange.firstIndex;
2339
2430
 
2340
2431
  this._pushItemIndexesAt(atIndex, count);
2341
2432
 
2342
2433
  /** @type Node|undefined */
2343
- let lastEl = existingEls[startIndex - 1];
2434
+ let before = existingEls[startIndex - 1] ?
2435
+ existingEls[startIndex - 1].nextSibling :
2436
+ existingEls[0];
2437
+
2438
+ /** @type DocumentFragment|null */
2439
+ let fragment = null;
2344
2440
 
2345
2441
  for (let index = atIndex, end = atIndex + count; index < end; index++) {
2346
- let insertBefore = lastEl ? lastEl.nextSibling : existingEls[0];
2347
- lastEl = this._dequeueElementForIndex(undefined, index, insertBefore);
2442
+ const itemEl = this._dequeueElementForIndex(undefined, index, before, true);
2443
+ fragment = insertBeforeWithFragment(itemEl, fragment, before, itemParent);
2444
+ }
2445
+
2446
+ // Insert any remaining fragment
2447
+ if (fragment && fragment.childNodes.length > 0) {
2448
+ insertBefore(fragment, before, itemParent);
2348
2449
  }
2349
2450
  }
2350
2451
 
@@ -2427,7 +2528,7 @@ class VirtualListHelper {
2427
2528
  if (index >= existingRange.firstIndex && index <= existingRange.lastIndex) {
2428
2529
  let itemEl = existingEls[existingRange.firstValidArrayIndex + index - existingRange.firstIndex];
2429
2530
  delete itemEl[ItemIndexSymbol];
2430
- this._dequeueElementForIndex(itemEl, index, itemEl.nextSibling);
2531
+ this._dequeueElementForIndex(itemEl, index, itemEl.nextSibling, false);
2431
2532
  }
2432
2533
  }
2433
2534
 
@@ -2570,7 +2671,7 @@ class VirtualListHelper {
2570
2671
  createGhostItemElement(ghostIndex, append, ghostTester) {
2571
2672
  const p = this._p;
2572
2673
 
2573
- let itemEl = this._dequeueElementForIndex(null, ghostIndex, false);
2674
+ let itemEl = this._dequeueElementForIndex(null, ghostIndex, false, true);
2574
2675
  try {
2575
2676
  if (append) {
2576
2677
  p.currentItemsParent.appendChild(itemEl);
@@ -2821,13 +2922,14 @@ class VirtualListHelper {
2821
2922
  * @param {Element|undefined} itemEl
2822
2923
  * @param {number} index
2823
2924
  * @param {Node|boolean|undefined} insertBefore
2925
+ * @param {boolean|undefined} avoidDomReflow
2824
2926
  * @returns {Element}
2825
2927
  * @private
2826
2928
  */
2827
- _dequeueElementForIndex(itemEl, index, insertBefore) {
2929
+ _dequeueElementForIndex(itemEl, index, insertBefore, avoidDomReflow) {
2828
2930
  const p = this._p;
2829
2931
  const virtualWrapper = p.virtualWrapper;
2830
- const itemParent = p.currentItemsParent;
2932
+ p.currentItemsParent;
2831
2933
  const existingEls = p.existingEls;
2832
2934
  const onItemRender = p.onItemRender;
2833
2935
  const onItemUnrender = p.onItemUnrender;
@@ -2862,12 +2964,6 @@ class VirtualListHelper {
2862
2964
  if (!(insertBefore instanceof Node))
2863
2965
  insertBefore = null;
2864
2966
 
2865
- // Insert into DOM
2866
- if (itemEl.parentNode !== itemParent ||
2867
- itemEl.nextSibling !== insertBefore) {
2868
- itemParent.insertBefore(itemEl, insertBefore);
2869
- }
2870
-
2871
2967
  // Remove from existing list
2872
2968
  if (!isNew) {
2873
2969
  let i = existingEls.indexOf(itemEl);
@@ -2883,37 +2979,65 @@ class VirtualListHelper {
2883
2979
  existingEls.splice(beforeIndex, 0, itemEl);
2884
2980
  }
2885
2981
 
2886
- if (virtualWrapper) {
2887
- // Calculate height
2888
- let itemHeight = itemEl.getBoundingClientRect().height;
2982
+ if (!avoidDomReflow) {
2983
+ this._insertItemAndFlow(itemEl, index, insertBefore);
2984
+ }
2985
+ }
2889
2986
 
2890
- // Put calculated height into cache, and invalidate positions if it's different
2891
- let cachedItemHeight = p.cachedItemHeights[index];
2892
- if (cachedItemHeight !== itemHeight) {
2893
- p.cachedItemHeights[index] = itemHeight;
2894
- }
2987
+ // Add index metadata to item
2988
+ itemEl[ItemIndexSymbol] = index;
2895
2989
 
2896
- if (cachedItemHeight !== undefined && itemHeight !== cachedItemHeight ||
2897
- cachedItemHeight === undefined && itemHeight !== p.cachedItemEstimatedHeights[index]) {
2898
- this._setItemPositionsNeedsUpdate(index + 1);
2899
- }
2990
+ return itemEl;
2991
+ }
2900
2992
 
2901
- // Set item top position
2902
- let pos = this._calculateItemPosition(index);
2903
- const supportedTransform = getSupportedTransform();
2993
+ /**
2994
+ * Insert item element into the DOM, set it's flow in the DOM, and update the item's position. <br />
2995
+ * @param {Element|undefined} itemEl
2996
+ * @param {number} index
2997
+ * @param {Node|boolean|undefined} before
2998
+ * @private
2999
+ */
3000
+ _insertItemAndFlow(itemEl, index, before) {
3001
+ const p = this._p;
3002
+ const virtualWrapper = p.virtualWrapper;
3003
+ const itemParent = p.currentItemsParent;
2904
3004
 
2905
- if (supportedTransform === false) {
2906
- /**@type ElementCSSInlineStyle*/itemEl.style.top = `${pos}px`;
2907
- } else {
2908
- /**@type ElementCSSInlineStyle*/itemEl.style[supportedTransform] = `translateY(${pos}px)`;
2909
- }
3005
+ if (before !== false) {
3006
+ if (!(before instanceof Node))
3007
+ before = null;
3008
+
3009
+ // Insert into DOM
3010
+ if (itemEl.parentNode !== itemParent ||
3011
+ itemEl.nextSibling !== before) {
3012
+ insertBefore(itemEl, before, itemParent);
2910
3013
  }
2911
3014
  }
2912
3015
 
2913
- // Add index metadata to item
2914
- itemEl[ItemIndexSymbol] = index;
3016
+ if (virtualWrapper) {
3017
+ // Calculate height
3018
+ let itemHeight = itemEl.getBoundingClientRect().height;
2915
3019
 
2916
- return itemEl;
3020
+ // Put calculated height into cache, and invalidate positions if it's different
3021
+ let cachedItemHeight = p.cachedItemHeights[index];
3022
+ if (cachedItemHeight !== itemHeight) {
3023
+ p.cachedItemHeights[index] = itemHeight;
3024
+ }
3025
+
3026
+ if (cachedItemHeight !== undefined && itemHeight !== cachedItemHeight ||
3027
+ cachedItemHeight === undefined && itemHeight !== p.cachedItemEstimatedHeights[index]) {
3028
+ this._setItemPositionsNeedsUpdate(index + 1);
3029
+ }
3030
+
3031
+ // Set item top position
3032
+ let pos = this._calculateItemPosition(index);
3033
+ const supportedTransform = getSupportedTransform();
3034
+
3035
+ if (supportedTransform === false) {
3036
+ /**@type ElementCSSInlineStyle*/itemEl.style.top = `${pos}px`;
3037
+ } else {
3038
+ /**@type ElementCSSInlineStyle*/itemEl.style[supportedTransform] = `translateY(${pos}px)`;
3039
+ }
3040
+ }
2917
3041
  }
2918
3042
 
2919
3043
  /**