@vaadin/vaadin-grid 5.8.2 → 5.9.1

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.
package/package.json CHANGED
@@ -15,7 +15,7 @@
15
15
  "repository": "vaadin/vaadin-grid",
16
16
  "homepage": "https://vaadin.com/components",
17
17
  "name": "@vaadin/vaadin-grid",
18
- "version": "5.8.2",
18
+ "version": "5.9.1",
19
19
  "main": "vaadin-grid.js",
20
20
  "author": "Vaadin Ltd",
21
21
  "license": "Apache-2.0",
@@ -44,7 +44,7 @@
44
44
  "@vaadin/vaadin-element-mixin": "^2.4.1"
45
45
  },
46
46
  "resolutions": {
47
- "@webcomponents/webcomponentsjs": "2.0.0",
47
+ "@webcomponents/webcomponentsjs": "2.0.0",
48
48
  "es-abstract": "1.17.6",
49
49
  "@types/doctrine": "0.0.3",
50
50
  "inherits": "2.0.3",
@@ -53,9 +53,9 @@
53
53
  "type-detect": "1.0.0"
54
54
  },
55
55
  "scripts": {
56
- "generate-typings": "gen-typescript-declarations --outDir . --verify"
57
- },
58
- "devDependencies": {
56
+ "generate-typings": "gen-typescript-declarations --outDir . --verify"
57
+ },
58
+ "devDependencies": {
59
59
  "@webcomponents/webcomponentsjs": "^2.0.0",
60
60
  "wct-browser-legacy": "^1.0.1",
61
61
  "@polymer/iron-test-helpers": "^3.0.0",
package/src/iron-list.js CHANGED
@@ -643,7 +643,7 @@ export const PolymerIronList = Class({
643
643
  // When this happens, there might be some issues as described
644
644
  // here https://github.com/vaadin/web-components/issues/2127.
645
645
  // Skipping any calculation for a hidden Grid.
646
- if (this.hidden) {
646
+ if (!this._isVisible) {
647
647
  return;
648
648
  }
649
649
 
@@ -8,6 +8,7 @@ import '@polymer/polymer/polymer-legacy.js';
8
8
  import { microTask } from '@polymer/polymer/lib/utils/async.js';
9
9
  import { FlattenedNodesObserver } from '@polymer/polymer/lib/utils/flattened-nodes-observer.js';
10
10
  import { ColumnBaseMixin } from './vaadin-grid-column.js';
11
+ import { GridHelper } from './vaadin-grid-helpers.js';
11
12
  import { PolymerElement } from '@polymer/polymer/polymer-element.js';
12
13
  /**
13
14
  * A `<vaadin-grid-column-group>` is used to make groups of columns in `<vaadin-grid>` and
@@ -153,7 +154,7 @@ class GridColumnGroupElement extends ColumnBaseMixin(PolymerElement) {
153
154
 
154
155
  // In an unlikely situation where a group has more than 9 child columns,
155
156
  // the child scope must have 1 digit less...
156
- const childCountDigits = ~~(Math.log(rootColumns.length) / Math.log(Math.LN10)) + 1;
157
+ const childCountDigits = ~~(Math.log(rootColumns.length) / Math.LN10) + 1;
157
158
 
158
159
  // Final scope for the child columns needs to mind both factors.
159
160
  const scope = Math.pow(10, trailingZeros - childCountDigits);
@@ -163,7 +164,7 @@ class GridColumnGroupElement extends ColumnBaseMixin(PolymerElement) {
163
164
  _rootColumns.sort((a, b) => a._order - b._order);
164
165
  }
165
166
 
166
- _rootColumns.forEach((column, index) => column._order = order + ((index + 1) * scope));
167
+ GridHelper._updateColumnOrders(_rootColumns, scope, order);
167
168
  }
168
169
  }
169
170
 
@@ -5,6 +5,7 @@ This program is available under Apache License Version 2.0, available at https:/
5
5
  */
6
6
  import { GestureEventListeners } from '@polymer/polymer/lib/mixins/gesture-event-listeners.js';
7
7
 
8
+ import { GridHelper } from './vaadin-grid-helpers.js';
8
9
  import { addListener } from '@polymer/polymer/lib/utils/gestures.js';
9
10
  import { dom } from '@polymer/polymer/lib/legacy/polymer.dom.js';
10
11
  import { useShadow } from '@polymer/polymer/lib/utils/settings.js';
@@ -293,7 +294,7 @@ export const ColumnReorderingMixin = superClass => class ColumnReorderingMixin e
293
294
  // Reset all column orders
294
295
  columnTree[0].forEach((column, index) => column._order = 0);
295
296
  // Set order numbers to top-level columns
296
- columnTree[0].forEach((column, index) => column._order = (index + 1) * this._orderBaseScope);
297
+ GridHelper._updateColumnOrders(columnTree[0], this._orderBaseScope, 0);
297
298
  }
298
299
 
299
300
  /**
@@ -319,7 +319,15 @@ export const ColumnBaseMixin = superClass => class ColumnBaseMixin extends super
319
319
  }
320
320
 
321
321
  cells.forEach(cell => {
322
- const model = this._grid.__getRowModel(cell.parentElement);
322
+ const parent = cell.parentElement;
323
+
324
+ // When a column is made hidden and shown again, in some instances it breaks rendering of rows for grid
325
+ // this happens when parent element of cell is null, which might not be set correctly during rendering
326
+ // the newly shown column, this check simply avoid that case
327
+ if (!parent) {
328
+ return;
329
+ }
330
+ const model = this._grid.__getRowModel(parent);
323
331
 
324
332
  if (renderer) {
325
333
  cell._renderer = renderer;
@@ -395,7 +395,7 @@ export const DataProviderMixin = superClass => class DataProviderMixin extends s
395
395
  this._debouncerApplyCachedData.flush();
396
396
  }
397
397
 
398
- this.__itemsReceived();
398
+ this.__flushPendingRecalculateColumnWidths();
399
399
  });
400
400
  }
401
401
  }
@@ -87,7 +87,7 @@ export const DragAndDropMixin = superClass => class DragAndDropMixin extends sup
87
87
 
88
88
  static get observers() {
89
89
  return [
90
- '_dragDropAccessChanged(rowsDraggable, dropMode, dragFilter, dropFilter)'
90
+ '_dragDropAccessChanged(rowsDraggable, dropMode, dragFilter, dropFilter, loading)'
91
91
  ];
92
92
  }
93
93
 
@@ -297,13 +297,17 @@ export const DragAndDropMixin = superClass => class DragAndDropMixin extends sup
297
297
 
298
298
  /** @private */
299
299
  __getViewportRows() {
300
- const headerBottom = this.$.header.getBoundingClientRect().bottom;
301
- const footerTop = this.$.footer.getBoundingClientRect().top;
302
- return Array.from(this.$.items.children)
303
- .filter(row => {
304
- const rowRect = row.getBoundingClientRect();
305
- return rowRect.bottom > headerBottom && rowRect.top < footerTop;
306
- });
300
+ // Workaround an IE11 bug where the `getBoundingClientRect` for header/footer
301
+ // might return incorrect values
302
+ this.$.header.style.outline = '0px solid transparent';
303
+ const scrollerRect = this.$.scroller.getBoundingClientRect();
304
+ const headerBottom = Math.max(this.$.header.getBoundingClientRect().bottom, scrollerRect.top);
305
+ const footerTop = Math.min(this.$.footer.getBoundingClientRect().top, scrollerRect.bottom);
306
+
307
+ return Array.from(this.$.items.children).filter((row) => {
308
+ const rowRect = row.getBoundingClientRect();
309
+ return rowRect.bottom > headerBottom && rowRect.top < footerTop;
310
+ });
307
311
  }
308
312
 
309
313
  /** @protected */
@@ -382,8 +386,9 @@ export const DragAndDropMixin = superClass => class DragAndDropMixin extends sup
382
386
  * @protected
383
387
  */
384
388
  _filterDragAndDrop(row, model) {
385
- const dragDisabled = !this.rowsDraggable || (this.dragFilter && !this.dragFilter(model));
386
- const dropDisabled = !this.dropMode || (this.dropFilter && !this.dropFilter(model));
389
+ const loading = this.loading || row.hasAttribute('loading');
390
+ const dragDisabled = !this.rowsDraggable || loading || (this.dragFilter && !this.dragFilter(model));
391
+ const dropDisabled = !this.dropMode || loading || (this.dropFilter && !this.dropFilter(model));
387
392
 
388
393
  const draggableElements = window.ShadyDOM
389
394
  ? [row]
@@ -0,0 +1,26 @@
1
+ /**
2
+ @license
3
+ Copyright (c) 2017 Vaadin Ltd.
4
+ This program is available under Apache License Version 2.0, available at https://vaadin.com/license/
5
+ */
6
+ /** @private */
7
+ export const GridHelper = class VaadinGridHelper {
8
+
9
+ /**
10
+ * @param {Array<Object>} columns array of columns to be modified
11
+ * @param {number} scope multiplier added to base order for each column
12
+ * @param {number} baseOrder base number used for order
13
+ */
14
+ static _updateColumnOrders(columns, scope, baseOrder) {
15
+ let c = 1;
16
+ columns.forEach((column) => {
17
+ // avoid multiples of 10 because they introduce and extra zero and
18
+ // causes the underlying calculations for child order goes wrong
19
+ if (c % 10 === 0) {
20
+ c++;
21
+ }
22
+ column._order = baseOrder + c * scope;
23
+ c++;
24
+ });
25
+ }
26
+ };
@@ -532,6 +532,12 @@ export const KeyboardNavigationMixin = superClass => class KeyboardNavigationMix
532
532
  }
533
533
  // Inform cell content of the focus (used in <vaadin-grid-sorter>)
534
534
  cell._content.dispatchEvent(new CustomEvent('cell-focusin', {bubbles: false}));
535
+
536
+ // Fire a public event for cell focus.
537
+ const context = this.getEventContext(e);
538
+ cell.dispatchEvent(
539
+ new CustomEvent('cell-focus', {bubbles: true, composed: true, detail: {context: context}})
540
+ );
535
541
  }
536
542
 
537
543
  this._detectFocusedItemIndex(e);
@@ -738,4 +744,12 @@ export const KeyboardNavigationMixin = superClass => class KeyboardNavigationMix
738
744
  }
739
745
  return null;
740
746
  }
747
+
748
+ /**
749
+ * Fired when a cell is focused with click or keyboard navigation.
750
+ *
751
+ * Use context property of @see {@link GridCellFocusEvent} to get detail information about the event.
752
+ *
753
+ * @event cell-focus
754
+ */
741
755
  };
@@ -79,7 +79,13 @@ class GridScrollerElement extends PolymerIronList {
79
79
  this._scrollingToIndex = true;
80
80
  index = Math.min(Math.max(index, 0), this._effectiveSize - 1);
81
81
  this.$.table.scrollTop = index / this._effectiveSize * (this.$.table.scrollHeight - this.$.table.offsetHeight);
82
+
83
+ // We need to run the iron-list scroll handler here in order to recalculate the scaling from effective size to
84
+ // virtual size after changing the scroll position. However we don't want to trigger updates to the items / rows
85
+ // in this step, which could result in data provider requests for the previous viewport
86
+ this._preventItemUpdates = true;
82
87
  this._scrollHandler();
88
+ this._preventItemUpdates = false;
83
89
 
84
90
  if (this._accessIronListAPI(() => this._maxScrollTop) && this._virtualCount < this._effectiveSize) {
85
91
  this._adjustVirtualIndexOffset(1000000);
@@ -209,6 +215,7 @@ class GridScrollerElement extends PolymerIronList {
209
215
  // Ensure the rows are in order after increasing pool
210
216
  this.__reorderChildNodes();
211
217
  }
218
+ this.__flushPendingRecalculateColumnWidths();
212
219
  });
213
220
  }
214
221
  }
@@ -255,6 +262,10 @@ class GridScrollerElement extends PolymerIronList {
255
262
  * @protected
256
263
  */
257
264
  _assignModels(itemSet) {
265
+ // Skip here if internal flag for preventing item updates is set
266
+ if (this._preventItemUpdates) {
267
+ return;
268
+ }
258
269
  this._iterateItems((pidx, vidx) => {
259
270
  const el = this._physicalItems[pidx];
260
271
  this._toggleAttribute('hidden', vidx >= this._effectiveSize, el);
@@ -430,6 +441,19 @@ class GridScrollerElement extends PolymerIronList {
430
441
  super._resizeHandler();
431
442
  flush();
432
443
  }
444
+
445
+ __isCreatingRows() {
446
+ // iron-list's _increasePoolIfNeeded function may have scheduled a debouncer
447
+ // that will re-invoke _increasePoolIfNeeded (in vaadin-grid-scroller)
448
+ const schedulingDebounceIncreasePool = this._debouncers
449
+ && this._debouncers._increasePoolIfNeeded
450
+ && this._debouncers._increasePoolIfNeeded.isActive();
451
+ // vaadin-grid-scroller's overridden _increasePoolIfNeeded may have scheduled a _debounceIncreasePool debouncer
452
+ const debouncingIncreasePoolActive = this._debounceIncreasePool && this._debounceIncreasePool.isActive();
453
+
454
+ // If either of the conditions are true, we consider the grid is still in the process of creating new rows
455
+ return schedulingDebounceIncreasePool || debouncingIncreasePoolActive;
456
+ }
433
457
  }
434
458
 
435
459
  customElements.define(GridScrollerElement.is, GridScrollerElement);
@@ -197,7 +197,7 @@ class GridTreeToggleElement extends ThemableMixin(DirMixin(PolymerElement)) {
197
197
  /** @private */
198
198
  _levelChanged(level) {
199
199
  const value = Number(level).toString();
200
- this.style['---level'] = value;
200
+ this.updateStyles({'---level': value});
201
201
  // Async is to make DOM updates applied before evaluating the style
202
202
  // update, required for polyfilled RTL support in MSIE and Edge.
203
203
  this._debouncerUpdateLevel = Debouncer.debounce(
@@ -313,7 +313,7 @@ declare class GridElement extends
313
313
  allRowsVisible: boolean;
314
314
  connectedCallback(): void;
315
315
  attributeChangedCallback(name: string, oldValue: string|null, newValue: string|null): void;
316
- __itemsReceived(): void;
316
+ __flushPendingRecalculateColumnWidths(): void;
317
317
 
318
318
  /**
319
319
  * Updates the `width` of all columns which have `autoWidth` set to `true`.
@@ -322,7 +322,7 @@ class GridElement extends
322
322
  }
323
323
 
324
324
  static get version() {
325
- return '5.8.2';
325
+ return '5.9.1';
326
326
  }
327
327
 
328
328
  static get observers() {
@@ -451,46 +451,80 @@ class GridElement extends
451
451
  }
452
452
 
453
453
  /** @protected */
454
- __itemsReceived() {
454
+ __flushPendingRecalculateColumnWidths() {
455
455
  if (this._recalculateColumnWidthOnceLoadingFinished
456
- && !this._cache.isLoading()
457
- && this.__hasRowsWithClientHeight()) {
456
+ && !this._cache.isLoading()
457
+ && this.__hasRowsWithClientHeight()
458
+ && !this.__isCreatingRows()) {
458
459
  this._recalculateColumnWidthOnceLoadingFinished = false;
459
460
  this.recalculateColumnWidths();
460
461
  }
461
462
  }
462
463
 
464
+ /** @private */
465
+ __getIntrinsicWidth(col) {
466
+ const initialWidth = col.width;
467
+ const initialFlexGrow = col.flexGrow;
468
+
469
+ col.width = 'auto';
470
+ col.flexGrow = 0;
471
+
472
+ // Note: _allCells only contains cells which are currently rendered in DOM
473
+ const width = col._allCells
474
+ .reduce((width, cell) => {
475
+ // Add 1px buffer to the offset width to avoid too narrow columns (sub-pixel rendering)
476
+ return Math.max(width, cell.offsetWidth + 1);
477
+ }, 0);
478
+
479
+ col.flexGrow = initialFlexGrow;
480
+ col.width = initialWidth;
481
+
482
+ return width;
483
+ }
484
+
485
+ /** @private */
486
+ __getDistributedWidth(col, innerColumn) {
487
+ if (col == null || col === this) {
488
+ return 0;
489
+ }
490
+
491
+ const columnWidth = Math.max(this.__getIntrinsicWidth(col), this.__getDistributedWidth(col.parentElement, col));
492
+
493
+ // we're processing a regular grid-column and not a grid-column-group
494
+ if (!innerColumn) {
495
+ return columnWidth;
496
+ }
497
+
498
+ // At the end, the width of each vaadin-grid-column-group is determined by the sum of the width of its children.
499
+ // Here we determine how much space the vaadin-grid-column-group actually needs to render properly and then we distribute that space
500
+ // to its children, so when we actually do the summation it will be rendered properly.
501
+ // Check out vaadin-grid-column-group:_updateFlexAndWidth
502
+ const columnGroup = col;
503
+ const columnGroupWidth = columnWidth;
504
+ const sumOfWidthOfAllChildColumns = columnGroup._visibleChildColumns
505
+ .map((col) => this.__getIntrinsicWidth(col))
506
+ .reduce((sum, curr) => sum + curr, 0);
507
+
508
+ const extraNecessarySpaceForGridColumnGroup = Math.max(0, columnGroupWidth - sumOfWidthOfAllChildColumns);
509
+
510
+ // The distribution of the extra necessary space is done according to the intrinsic width of each child column.
511
+ // Lets say we need 100 pixels of extra space for the grid-column-group to render properly
512
+ // it has two grid-column children, |100px|300px| in total 400px
513
+ // the first column gets 25px of the additional space (100/400)*100 = 25
514
+ // the second column gets the 75px of the additional space (300/400)*100 = 75
515
+ const proportionOfExtraSpace = this.__getIntrinsicWidth(innerColumn) / sumOfWidthOfAllChildColumns;
516
+ const shareOfInnerColumnFromNecessaryExtraSpace = proportionOfExtraSpace * extraNecessarySpaceForGridColumnGroup;
517
+
518
+ return this.__getIntrinsicWidth(innerColumn) + shareOfInnerColumnFromNecessaryExtraSpace;
519
+ }
520
+
463
521
  /**
464
522
  * @param {!Array<!GridColumnElement>} cols the columns to auto size based on their content width
465
523
  * @private
466
524
  */
467
525
  _recalculateColumnWidths(cols) {
468
- // Note: The `cols.forEach()` loops below could be implemented as a single loop but this has been
469
- // split for performance reasons to batch these similar actions [write/read] together to avoid
470
- // unnecessary layout trashing.
471
-
472
- // [write] Set automatic width for all cells (breaks column alignment)
473
- cols.forEach(col => {
474
- col.width = 'auto';
475
- col._origFlexGrow = col.flexGrow;
476
- col.flexGrow = 0;
477
- });
478
- // [read] Measure max cell width in each column
479
- cols.forEach(col => {
480
- col._currentWidth = 0;
481
- // Note: _allCells only contains cells which are currently rendered in DOM
482
- col._allCells.forEach(c => {
483
- // Add 1px buffer to the offset width to avoid too narrow columns (sub-pixel rendering)
484
- const cellWidth = c.offsetWidth + 1;
485
- col._currentWidth = Math.max(col._currentWidth, cellWidth);
486
- });
487
- });
488
- // [write] Set column widths to fit widest measured content
489
- cols.forEach(col => {
490
- col.width = `${col._currentWidth}px`;
491
- col.flexGrow = col._origFlexGrow;
492
- col._currentWidth = undefined;
493
- col._origFlexGrow = undefined;
526
+ cols.forEach((col) => {
527
+ col.width = `${this.__getDistributedWidth(col)}px`;
494
528
  });
495
529
  }
496
530
 
@@ -501,7 +535,7 @@ class GridElement extends
501
535
  if (!this._columnTree) {
502
536
  return; // No columns
503
537
  }
504
- if (this._cache.isLoading()) {
538
+ if (this._cache.isLoading() || this.__isCreatingRows()) {
505
539
  this._recalculateColumnWidthOnceLoadingFinished = true;
506
540
  } else {
507
541
  const cols = this._getColumns().filter(col => !col.hidden && col.autoWidth);
@@ -862,7 +896,7 @@ class GridElement extends
862
896
  this._render();
863
897
  e.stopPropagation();
864
898
  this.notifyResize();
865
- this.__itemsReceived();
899
+ this.__flushPendingRecalculateColumnWidths();
866
900
 
867
901
  requestAnimationFrame(() => {
868
902
  this.__scrollToPendingIndex();