From 87b8edb92d463badc9727ff9f397523e34d0d462 Mon Sep 17 00:00:00 2001 From: Karl Seamon Date: Tue, 12 May 2020 22:10:36 -0400 Subject: [PATCH] =?UTF-8?q?fix(column-resize):=20Resize=20table=20as=20wel?= =?UTF-8?q?l=20as=20columns,=20improve=20handing=20=E2=80=A6=20(#19264)?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../column-resize-flex.ts | 2 +- .../column-resize-directives/column-resize.ts | 2 +- .../default-enabled-column-resize-flex.ts | 2 +- .../default-enabled-column-resize.ts | 2 +- .../column-resize/column-resize-notifier.ts | 8 +- .../column-resize/column-resize.ts | 11 ++- .../column-resize/overlay-handle.ts | 27 ++---- .../column-resize/resizable.ts | 17 ++-- .../column-resize/resize-strategy.ts | 84 ++++++++++++++++--- ...efault-enabled-column-resize-flex-demo.css | 4 + ...fault-enabled-column-resize-flex-demo.html | 2 +- ...default-enabled-column-resize-flex-demo.ts | 4 +- .../default-enabled-column-resize-demo.css | 4 + .../default-enabled-column-resize-demo.html | 2 +- .../default-enabled-column-resize-demo.ts | 4 +- .../opt-in/opt-in-column-resize-demo.css | 4 + .../opt-in/opt-in-column-resize-demo.html | 2 +- .../opt-in/opt-in-column-resize-demo.ts | 4 +- .../column-resize-flex.ts | 2 +- .../column-resize-directives/column-resize.ts | 2 +- .../default-enabled-column-resize-flex.ts | 2 +- .../default-enabled-column-resize.ts | 2 +- .../column-resize/column-resize.spec.ts | 75 ++++++++++++----- 23 files changed, 191 insertions(+), 77 deletions(-) create mode 100644 src/components-examples/material-experimental/column-resize/default-enabled-flex/default-enabled-column-resize-flex-demo.css create mode 100644 src/components-examples/material-experimental/column-resize/default-enabled/default-enabled-column-resize-demo.css create mode 100644 src/components-examples/material-experimental/column-resize/opt-in/opt-in-column-resize-demo.css diff --git a/src/cdk-experimental/column-resize/column-resize-directives/column-resize-flex.ts b/src/cdk-experimental/column-resize/column-resize-directives/column-resize-flex.ts index 85b16e16e3bc..7013bc25312f 100644 --- a/src/cdk-experimental/column-resize/column-resize-directives/column-resize-flex.ts +++ b/src/cdk-experimental/column-resize/column-resize-directives/column-resize-flex.ts @@ -27,7 +27,7 @@ import {FLEX_PROVIDERS} from './constants'; export class CdkColumnResizeFlex extends ColumnResize { constructor( readonly columnResizeNotifier: ColumnResizeNotifier, - protected readonly elementRef: ElementRef, + readonly elementRef: ElementRef, protected readonly eventDispatcher: HeaderRowEventDispatcher, protected readonly ngZone: NgZone, protected readonly notifier: ColumnResizeNotifierSource) { diff --git a/src/cdk-experimental/column-resize/column-resize-directives/column-resize.ts b/src/cdk-experimental/column-resize/column-resize-directives/column-resize.ts index e30a49f9d473..2e487c1df88c 100644 --- a/src/cdk-experimental/column-resize/column-resize-directives/column-resize.ts +++ b/src/cdk-experimental/column-resize/column-resize-directives/column-resize.ts @@ -27,7 +27,7 @@ import {TABLE_PROVIDERS} from './constants'; export class CdkColumnResize extends ColumnResize { constructor( readonly columnResizeNotifier: ColumnResizeNotifier, - protected readonly elementRef: ElementRef, + readonly elementRef: ElementRef, protected readonly eventDispatcher: HeaderRowEventDispatcher, protected readonly ngZone: NgZone, protected readonly notifier: ColumnResizeNotifierSource) { diff --git a/src/cdk-experimental/column-resize/column-resize-directives/default-enabled-column-resize-flex.ts b/src/cdk-experimental/column-resize/column-resize-directives/default-enabled-column-resize-flex.ts index 1c6d1a891c0f..86a600ca259f 100644 --- a/src/cdk-experimental/column-resize/column-resize-directives/default-enabled-column-resize-flex.ts +++ b/src/cdk-experimental/column-resize/column-resize-directives/default-enabled-column-resize-flex.ts @@ -27,7 +27,7 @@ import {FLEX_PROVIDERS} from './constants'; export class CdkDefaultEnabledColumnResizeFlex extends ColumnResize { constructor( readonly columnResizeNotifier: ColumnResizeNotifier, - protected readonly elementRef: ElementRef, + readonly elementRef: ElementRef, protected readonly eventDispatcher: HeaderRowEventDispatcher, protected readonly ngZone: NgZone, protected readonly notifier: ColumnResizeNotifierSource) { diff --git a/src/cdk-experimental/column-resize/column-resize-directives/default-enabled-column-resize.ts b/src/cdk-experimental/column-resize/column-resize-directives/default-enabled-column-resize.ts index c42be3d80b59..264195edfa7b 100644 --- a/src/cdk-experimental/column-resize/column-resize-directives/default-enabled-column-resize.ts +++ b/src/cdk-experimental/column-resize/column-resize-directives/default-enabled-column-resize.ts @@ -27,7 +27,7 @@ import {TABLE_PROVIDERS} from './constants'; export class CdkDefaultEnabledColumnResize extends ColumnResize { constructor( readonly columnResizeNotifier: ColumnResizeNotifier, - protected readonly elementRef: ElementRef, + readonly elementRef: ElementRef, protected readonly eventDispatcher: HeaderRowEventDispatcher, protected readonly ngZone: NgZone, protected readonly notifier: ColumnResizeNotifierSource) { diff --git a/src/cdk-experimental/column-resize/column-resize-notifier.ts b/src/cdk-experimental/column-resize/column-resize-notifier.ts index 7d424c4a60c3..220df8456efa 100644 --- a/src/cdk-experimental/column-resize/column-resize-notifier.ts +++ b/src/cdk-experimental/column-resize/column-resize-notifier.ts @@ -16,6 +16,9 @@ export interface ColumnSize { /** The width in pixels of the column. */ readonly size: number; + + /** The width in pixels of the column prior to this update, if known. */ + readonly previousSize?: number; } /** Interface describing column size changes. */ @@ -28,7 +31,10 @@ export interface ColumnSizeAction extends ColumnSize { readonly completeImmediately?: boolean; } -/** Originating source of column resize events within a table. */ +/** + * Originating source of column resize events within a table. + * @docs-private + */ @Injectable() export class ColumnResizeNotifierSource { /** Emits when an in-progress resize is canceled. */ diff --git a/src/cdk-experimental/column-resize/column-resize.ts b/src/cdk-experimental/column-resize/column-resize.ts index 6a8f4321d55a..5cfb471ae3b5 100644 --- a/src/cdk-experimental/column-resize/column-resize.ts +++ b/src/cdk-experimental/column-resize/column-resize.ts @@ -32,7 +32,9 @@ export abstract class ColumnResize implements AfterViewInit, OnDestroy { /* Publicly accessible interface for triggering and being notified of resizes. */ abstract readonly columnResizeNotifier: ColumnResizeNotifier; - protected abstract readonly elementRef: ElementRef; + /* ElementRef that this directive is attached to. Exposed For use by column-level directives */ + abstract readonly elementRef: ElementRef; + protected abstract readonly eventDispatcher: HeaderRowEventDispatcher; protected abstract readonly ngZone: NgZone; protected abstract readonly notifier: ColumnResizeNotifierSource; @@ -61,6 +63,11 @@ export abstract class ColumnResize implements AfterViewInit, OnDestroy { return `cdk-column-resize-${this.selectorId}`; } + /** Called when a column in the table is resized. Applies a css class to the table element. */ + setResized() { + this.elementRef.nativeElement!.classList.add(WITH_RESIZED_COLUMN_CLASS); + } + private _listenForRowHoverEvents() { this.ngZone.runOutsideAngular(() => { const element = this.elementRef.nativeElement!; @@ -87,7 +94,7 @@ export abstract class ColumnResize implements AfterViewInit, OnDestroy { takeUntil(this.destroyed), take(1), ).subscribe(() => { - this.elementRef.nativeElement!.classList.add(WITH_RESIZED_COLUMN_CLASS); + this.setResized(); }); } diff --git a/src/cdk-experimental/column-resize/overlay-handle.ts b/src/cdk-experimental/column-resize/overlay-handle.ts index 77d3b8fa8c46..c129006cf12a 100644 --- a/src/cdk-experimental/column-resize/overlay-handle.ts +++ b/src/cdk-experimental/column-resize/overlay-handle.ts @@ -92,9 +92,8 @@ export abstract class ResizeOverlayHandle implements AfterViewInit, OnDestroy { const startX = mousedownEvent.screenX; - const initialOverlayOffset = this._getOverlayOffset(); const initialSize = this._getOriginWidth(); - let overlayOffset = initialOverlayOffset; + let overlayOffset = this._getOverlayOffset(); let originOffset = this._getOriginOffset(); let size = initialSize; let overshot = 0; @@ -143,7 +142,7 @@ export abstract class ResizeOverlayHandle implements AfterViewInit, OnDestroy { Math.max(computedNewSize, this.resizeRef.minWidthPx, 0), this.resizeRef.maxWidthPx); this.resizeNotifier.triggerResize.next( - {columnId: this.columnDef.name, size: computedNewSize}); + {columnId: this.columnDef.name, size: computedNewSize, previousSize: size}); const originNewSize = this._getOriginWidth(); const originNewOffset = this._getOriginOffset(); @@ -153,7 +152,7 @@ export abstract class ResizeOverlayHandle implements AfterViewInit, OnDestroy { originOffset = originNewOffset; overshot += deltaX + (this._isLtr() ? -originSizeDeltaX : originSizeDeltaX); - overlayOffset += originSizeDeltaX + originOffsetDeltaX; + overlayOffset += originOffsetDeltaX + (this._isLtr() ? originSizeDeltaX : 0); this._updateOverlayOffset(overlayOffset); }); @@ -169,29 +168,15 @@ export abstract class ResizeOverlayHandle implements AfterViewInit, OnDestroy { } private _getOriginOffset(): number { - const originElement = this.resizeRef.origin.nativeElement!; - const offsetLeft = originElement.offsetLeft; - - return this._isLtr() ? - offsetLeft : - originElement.offsetParent!.offsetWidth - (offsetLeft + this._getOriginWidth()); + return this.resizeRef.origin.nativeElement!.offsetLeft; } private _getOverlayOffset(): number { - const overlayElement = this.resizeRef.overlayRef.overlayElement; - return this._isLtr() ? - parseInt(overlayElement.style.left!, 10) : parseInt(overlayElement.style.right!, 10); + return parseInt(this.resizeRef.overlayRef.overlayElement.style.left!, 10); } private _updateOverlayOffset(offset: number): void { - const overlayElement = this.resizeRef.overlayRef.overlayElement; - const overlayOffsetCssValue = coerceCssPixelValue(offset); - - if (this._isLtr()) { - overlayElement.style.left = overlayOffsetCssValue; - } else { - overlayElement.style.right = overlayOffsetCssValue; - } + this.resizeRef.overlayRef.overlayElement.style.left = coerceCssPixelValue(offset); } private _isLtr(): boolean { diff --git a/src/cdk-experimental/column-resize/resizable.ts b/src/cdk-experimental/column-resize/resizable.ts index d7d98c7338b7..75a1fbbc2372 100644 --- a/src/cdk-experimental/column-resize/resizable.ts +++ b/src/cdk-experimental/column-resize/resizable.ts @@ -70,6 +70,7 @@ export abstract class Resizable this.minWidthPxInternal = value; if (this.elementRef.nativeElement) { + this.columnResize.setResized(); this._applyMinWidthPx(); } } @@ -82,6 +83,7 @@ export abstract class Resizable this.maxWidthPxInternal = value; if (this.elementRef.nativeElement) { + this.columnResize.setResized(); this._applyMaxWidthPx(); } } @@ -116,20 +118,23 @@ export abstract class Resizable // of two table cells and is also useful for displaying a resize thumb // over both cells and extending it down the table as needed. + const isRtl = this.directionality.value === 'rtl'; const positionStrategy = this.overlay.position() .flexibleConnectedTo(this.elementRef.nativeElement!) .withFlexibleDimensions(false) .withGrowAfterOpen(false) .withPush(false) + .withDefaultOffsetX(isRtl ? 1 : 0) .withPositions([{ - originX: 'end', + originX: isRtl ? 'start' : 'end', originY: 'top', overlayX: 'center', overlayY: 'top', }]); return this.overlay.create({ - direction: this.directionality, + // Always position the overlay based on left-indexed coordinates. + direction: 'ltr', disposeOnNavigation: true, positionStrategy, scrollStrategy: this.overlay.scrollStrategies.reposition(), @@ -166,9 +171,9 @@ export abstract class Resizable ).pipe( takeUntilDestroyed, filter(columnSize => columnSize.columnId === this.columnDef.name), - ).subscribe(({size, completeImmediately}) => { + ).subscribe(({size, previousSize, completeImmediately}) => { this.elementRef.nativeElement!.classList.add(OVERLAY_ACTIVE_CLASS); - this._applySize(size); + this._applySize(size, previousSize); if (completeImmediately) { this._completeResizeOperation(); @@ -223,11 +228,11 @@ export abstract class Resizable this.overlayRef!.updateSize({height: this.elementRef.nativeElement!.offsetHeight}); } - private _applySize(sizeInPixels: number): void { + private _applySize(sizeInPixels: number, previousSize?: number): void { const sizeToApply = Math.min(Math.max(sizeInPixels, this.minWidthPx, 0), this.maxWidthPx); this.resizeStrategy.applyColumnSize(this.columnDef.cssClassFriendlyName, - this.elementRef.nativeElement!, sizeToApply); + this.elementRef.nativeElement!, sizeToApply, previousSize); } private _applyMinWidthPx(): void { diff --git a/src/cdk-experimental/column-resize/resize-strategy.ts b/src/cdk-experimental/column-resize/resize-strategy.ts index 76ff0e6aa15c..d91bab5ece1e 100644 --- a/src/cdk-experimental/column-resize/resize-strategy.ts +++ b/src/cdk-experimental/column-resize/resize-strategy.ts @@ -18,20 +18,34 @@ import {ColumnResize} from './column-resize'; */ @Injectable() export abstract class ResizeStrategy { + protected abstract readonly columnResize: ColumnResize; + + /** Updates the width of the specified column. */ abstract applyColumnSize( cssFriendlyColumnName: string, columnHeader: HTMLElement, - sizeInPx: number): void; + sizeInPx: number, + previousSizeInPx?: number): void; + /** Applies a minimum width to the specified column, updating its current width as needed. */ abstract applyMinColumnSize( cssFriendlyColumnName: string, columnHeader: HTMLElement, minSizeInPx: number): void; + /** Applies a maximum width to the specified column, updating its current width as needed. */ abstract applyMaxColumnSize( cssFriendlyColumnName: string, columnHeader: HTMLElement, minSizeInPx: number): void; + + /** Adjusts the width of the table element by the specified delta. */ + protected updateTableWidth(delta: number): void { + const table = this.columnResize.elementRef.nativeElement; + const tableWidth = getElementWidth(table); + + table.style.width = coerceCssPixelValue(tableWidth + delta); + } } /** @@ -43,17 +57,31 @@ export abstract class ResizeStrategy { */ @Injectable() export class TableLayoutFixedResizeStrategy extends ResizeStrategy { - applyColumnSize(_: string, columnHeader: HTMLElement, sizeInPx: number): void { + constructor(protected readonly columnResize: ColumnResize) { + super(); + } + + applyColumnSize(_: string, columnHeader: HTMLElement, sizeInPx: number, + previousSizeInPx?: number): void { + const delta = sizeInPx - (previousSizeInPx ?? getElementWidth(columnHeader)); + columnHeader.style.width = coerceCssPixelValue(sizeInPx); + + this.updateTableWidth(delta); } applyMinColumnSize(_: string, columnHeader: HTMLElement, sizeInPx: number): void { - columnHeader.style.minWidth = coerceCssPixelValue(sizeInPx); + const currentWidth = getElementWidth(columnHeader); + const newWidth = Math.max(currentWidth, sizeInPx); + + this.applyColumnSize(_, columnHeader, newWidth, currentWidth); } - applyMaxColumnSize(): void { - // Intentionally omitted as max-width causes strange rendering issues in Chrome. - // Max size will still apply when the user is resizing this column. + applyMaxColumnSize(_: string, columnHeader: HTMLElement, sizeInPx: number): void { + const currentWidth = getElementWidth(columnHeader); + const newWidth = Math.min(currentWidth, sizeInPx); + + this.applyColumnSize(_, columnHeader, newWidth, currentWidth); } } @@ -76,16 +104,23 @@ export class CdkFlexTableResizeStrategy extends ResizeStrategy implements OnDest protected readonly defaultMaxSize = Number.MAX_SAFE_INTEGER; constructor( - private readonly _columnResize: ColumnResize, + protected readonly columnResize: ColumnResize, @Inject(DOCUMENT) document: any) { super(); this._document = document; } - applyColumnSize(cssFriendlyColumnName: string, _: HTMLElement, sizeInPx: number): void { + applyColumnSize(cssFriendlyColumnName: string, columnHeader: HTMLElement, + sizeInPx: number, previousSizeInPx?: number): void { + // Optimization: Check applied width first as we probably set it already before reading + // offsetWidth which triggers layout. + const delta = sizeInPx - (previousSizeInPx ?? + (this._getAppliedWidth(cssFriendlyColumnName) || columnHeader.offsetWidth)); + const cssSize = coerceCssPixelValue(sizeInPx); this._applyProperty(cssFriendlyColumnName, 'flex', `0 0.01 ${cssSize}`); + this.updateTableWidth(delta); } applyMinColumnSize(cssFriendlyColumnName: string, _: HTMLElement, sizeInPx: number): void { @@ -106,7 +141,7 @@ export class CdkFlexTableResizeStrategy extends ResizeStrategy implements OnDest return `cdk-column-${cssFriendlyColumnName}`; } - ngOnDestroy() { + ngOnDestroy(): void { // TODO: Use remove() once we're off IE11. if (this._styleElement && this._styleElement.parentNode) { this._styleElement.parentNode.removeChild(this._styleElement); @@ -114,6 +149,15 @@ export class CdkFlexTableResizeStrategy extends ResizeStrategy implements OnDest } } + private _getPropertyValue(cssFriendlyColumnName: string, key: string): string|undefined { + const properties = this._getColumnPropertiesMap(cssFriendlyColumnName); + return properties.get(key); + } + + private _getAppliedWidth(cssFriendslyColumnName: string): number { + return coercePixelsFromFlexValue(this._getPropertyValue(cssFriendslyColumnName, 'flex')); + } + private _applyProperty( cssFriendlyColumnName: string, key: string, @@ -166,7 +210,7 @@ export class CdkFlexTableResizeStrategy extends ResizeStrategy implements OnDest } const columnClassName = this.getColumnCssClass(cssFriendlyColumnName); - const tableClassName = this._columnResize.getUniqueCssClass(); + const tableClassName = this.columnResize.getUniqueCssClass(); const selector = `.${tableClassName} .${columnClassName}`; const body = propertyKeys.map(key => `${key}:${properties.get(key)}`).join(';'); @@ -175,6 +219,26 @@ export class CdkFlexTableResizeStrategy extends ResizeStrategy implements OnDest } } +/** Converts CSS pixel values to numbers, eg "123px" to 123. Returns NaN for non pixel values. */ +function coercePixelsFromCssValue(cssValue: string): number { + return Number(cssValue.match(/(\d+)px/)?.[1]); +} + +/** Gets the style.width pixels on the specified element if present, otherwise its offsetWidth. */ +function getElementWidth(element: HTMLElement) { + // Optimization: Check style.width first as we probably set it already before reading + // offsetWidth which triggers layout. + return coercePixelsFromCssValue(element.style.width) || element.offsetWidth; +} + +/** + * Converts CSS flex values as set in CdkFlexTableResizeStrategy to numbers, + * eg "0 0.01 123px" to 123. + */ +function coercePixelsFromFlexValue(flexValue: string|undefined): number { + return Number(flexValue?.match(/0 0\.01 (\d+)px/)?.[1]); +} + export const TABLE_LAYOUT_FIXED_RESIZE_STRATEGY_PROVIDER: Provider = { provide: ResizeStrategy, useClass: TableLayoutFixedResizeStrategy, diff --git a/src/components-examples/material-experimental/column-resize/default-enabled-flex/default-enabled-column-resize-flex-demo.css b/src/components-examples/material-experimental/column-resize/default-enabled-flex/default-enabled-column-resize-flex-demo.css new file mode 100644 index 000000000000..b2ed3b0dddd3 --- /dev/null +++ b/src/components-examples/material-experimental/column-resize/default-enabled-flex/default-enabled-column-resize-flex-demo.css @@ -0,0 +1,4 @@ +:host { + display: block; + overflow: auto; +} diff --git a/src/components-examples/material-experimental/column-resize/default-enabled-flex/default-enabled-column-resize-flex-demo.html b/src/components-examples/material-experimental/column-resize/default-enabled-flex/default-enabled-column-resize-flex-demo.html index e90565e55c8d..06a7c3966410 100644 --- a/src/components-examples/material-experimental/column-resize/default-enabled-flex/default-enabled-column-resize-flex-demo.html +++ b/src/components-examples/material-experimental/column-resize/default-enabled-flex/default-enabled-column-resize-flex-demo.html @@ -7,7 +7,7 @@ - Name + Name {{element.name}} diff --git a/src/components-examples/material-experimental/column-resize/default-enabled-flex/default-enabled-column-resize-flex-demo.ts b/src/components-examples/material-experimental/column-resize/default-enabled-flex/default-enabled-column-resize-flex-demo.ts index 85ca5d9bf1f0..1d9b17297311 100644 --- a/src/components-examples/material-experimental/column-resize/default-enabled-flex/default-enabled-column-resize-flex-demo.ts +++ b/src/components-examples/material-experimental/column-resize/default-enabled-flex/default-enabled-column-resize-flex-demo.ts @@ -6,7 +6,7 @@ * found in the LICENSE file at https://angular.io/license */ -import {Component, ViewEncapsulation} from '@angular/core'; +import {Component} from '@angular/core'; export interface PeriodicElement { name: string; @@ -44,7 +44,7 @@ const ELEMENT_DATA: PeriodicElement[] = [ @Component({ selector: 'default-enabled-column-resize-flex-demo', templateUrl: 'default-enabled-column-resize-flex-demo.html', - encapsulation: ViewEncapsulation.None, + styleUrls: ['default-enabled-column-resize-flex-demo.css'], }) export class DefaultEnabledColumnResizeFlexDemo { displayedColumns: string[] = ['position', 'name', 'weight', 'symbol']; diff --git a/src/components-examples/material-experimental/column-resize/default-enabled/default-enabled-column-resize-demo.css b/src/components-examples/material-experimental/column-resize/default-enabled/default-enabled-column-resize-demo.css new file mode 100644 index 000000000000..b2ed3b0dddd3 --- /dev/null +++ b/src/components-examples/material-experimental/column-resize/default-enabled/default-enabled-column-resize-demo.css @@ -0,0 +1,4 @@ +:host { + display: block; + overflow: auto; +} diff --git a/src/components-examples/material-experimental/column-resize/default-enabled/default-enabled-column-resize-demo.html b/src/components-examples/material-experimental/column-resize/default-enabled/default-enabled-column-resize-demo.html index e1f06a760533..0cbbc035a947 100644 --- a/src/components-examples/material-experimental/column-resize/default-enabled/default-enabled-column-resize-demo.html +++ b/src/components-examples/material-experimental/column-resize/default-enabled/default-enabled-column-resize-demo.html @@ -7,7 +7,7 @@ - Name + Name {{element.name}} diff --git a/src/components-examples/material-experimental/column-resize/default-enabled/default-enabled-column-resize-demo.ts b/src/components-examples/material-experimental/column-resize/default-enabled/default-enabled-column-resize-demo.ts index a4fddc80e039..292b940bb195 100644 --- a/src/components-examples/material-experimental/column-resize/default-enabled/default-enabled-column-resize-demo.ts +++ b/src/components-examples/material-experimental/column-resize/default-enabled/default-enabled-column-resize-demo.ts @@ -6,7 +6,7 @@ * found in the LICENSE file at https://angular.io/license */ -import {Component, ViewEncapsulation} from '@angular/core'; +import {Component} from '@angular/core'; export interface PeriodicElement { name: string; @@ -44,7 +44,7 @@ const ELEMENT_DATA: PeriodicElement[] = [ @Component({ selector: 'default-enabled-column-resize-demo', templateUrl: 'default-enabled-column-resize-demo.html', - encapsulation: ViewEncapsulation.None, + styleUrls: ['default-enabled-column-resize-demo.css'], }) export class DefaultEnabledColumnResizeDemo { displayedColumns: string[] = ['position', 'name', 'weight', 'symbol']; diff --git a/src/components-examples/material-experimental/column-resize/opt-in/opt-in-column-resize-demo.css b/src/components-examples/material-experimental/column-resize/opt-in/opt-in-column-resize-demo.css new file mode 100644 index 000000000000..b2ed3b0dddd3 --- /dev/null +++ b/src/components-examples/material-experimental/column-resize/opt-in/opt-in-column-resize-demo.css @@ -0,0 +1,4 @@ +:host { + display: block; + overflow: auto; +} diff --git a/src/components-examples/material-experimental/column-resize/opt-in/opt-in-column-resize-demo.html b/src/components-examples/material-experimental/column-resize/opt-in/opt-in-column-resize-demo.html index d6749709a59b..381dcffd68ee 100644 --- a/src/components-examples/material-experimental/column-resize/opt-in/opt-in-column-resize-demo.html +++ b/src/components-examples/material-experimental/column-resize/opt-in/opt-in-column-resize-demo.html @@ -7,7 +7,7 @@ - Name + Name {{element.name}} diff --git a/src/components-examples/material-experimental/column-resize/opt-in/opt-in-column-resize-demo.ts b/src/components-examples/material-experimental/column-resize/opt-in/opt-in-column-resize-demo.ts index f9aca644f8ea..ed8ae0566396 100644 --- a/src/components-examples/material-experimental/column-resize/opt-in/opt-in-column-resize-demo.ts +++ b/src/components-examples/material-experimental/column-resize/opt-in/opt-in-column-resize-demo.ts @@ -6,7 +6,7 @@ * found in the LICENSE file at https://angular.io/license */ -import {Component, ViewEncapsulation} from '@angular/core'; +import {Component} from '@angular/core'; export interface PeriodicElement { name: string; @@ -44,7 +44,7 @@ const ELEMENT_DATA: PeriodicElement[] = [ @Component({ selector: 'opt-in-column-resize-demo', templateUrl: 'opt-in-column-resize-demo.html', - encapsulation: ViewEncapsulation.None, + styleUrls: ['opt-in-column-resize-demo.css'], }) export class OptInColumnResizeDemo { displayedColumns: string[] = ['position', 'name', 'weight', 'symbol']; diff --git a/src/material-experimental/column-resize/column-resize-directives/column-resize-flex.ts b/src/material-experimental/column-resize/column-resize-directives/column-resize-flex.ts index 1e8c5292781a..7a6665ae56b2 100644 --- a/src/material-experimental/column-resize/column-resize-directives/column-resize-flex.ts +++ b/src/material-experimental/column-resize/column-resize-directives/column-resize-flex.ts @@ -31,7 +31,7 @@ import {AbstractMatColumnResize, FLEX_HOST_BINDINGS, FLEX_PROVIDERS} from './com export class MatColumnResizeFlex extends AbstractMatColumnResize { constructor( readonly columnResizeNotifier: ColumnResizeNotifier, - protected readonly elementRef: ElementRef, + readonly elementRef: ElementRef, protected readonly eventDispatcher: HeaderRowEventDispatcher, protected readonly ngZone: NgZone, protected readonly notifier: ColumnResizeNotifierSource) { diff --git a/src/material-experimental/column-resize/column-resize-directives/column-resize.ts b/src/material-experimental/column-resize/column-resize-directives/column-resize.ts index f7402d72139d..f6014c9334f6 100644 --- a/src/material-experimental/column-resize/column-resize-directives/column-resize.ts +++ b/src/material-experimental/column-resize/column-resize-directives/column-resize.ts @@ -31,7 +31,7 @@ import {AbstractMatColumnResize, TABLE_HOST_BINDINGS, TABLE_PROVIDERS} from './c export class MatColumnResize extends AbstractMatColumnResize { constructor( readonly columnResizeNotifier: ColumnResizeNotifier, - protected readonly elementRef: ElementRef, + readonly elementRef: ElementRef, protected readonly eventDispatcher: HeaderRowEventDispatcher, protected readonly ngZone: NgZone, protected readonly notifier: ColumnResizeNotifierSource) { diff --git a/src/material-experimental/column-resize/column-resize-directives/default-enabled-column-resize-flex.ts b/src/material-experimental/column-resize/column-resize-directives/default-enabled-column-resize-flex.ts index 08bf3375b655..7d11cb0c8afe 100644 --- a/src/material-experimental/column-resize/column-resize-directives/default-enabled-column-resize-flex.ts +++ b/src/material-experimental/column-resize/column-resize-directives/default-enabled-column-resize-flex.ts @@ -31,7 +31,7 @@ import {AbstractMatColumnResize, FLEX_HOST_BINDINGS, FLEX_PROVIDERS} from './com export class MatDefaultEnabledColumnResizeFlex extends AbstractMatColumnResize { constructor( readonly columnResizeNotifier: ColumnResizeNotifier, - protected readonly elementRef: ElementRef, + readonly elementRef: ElementRef, protected readonly eventDispatcher: HeaderRowEventDispatcher, protected readonly ngZone: NgZone, protected readonly notifier: ColumnResizeNotifierSource) { diff --git a/src/material-experimental/column-resize/column-resize-directives/default-enabled-column-resize.ts b/src/material-experimental/column-resize/column-resize-directives/default-enabled-column-resize.ts index a9804c5d40ef..aca54c3439e9 100644 --- a/src/material-experimental/column-resize/column-resize-directives/default-enabled-column-resize.ts +++ b/src/material-experimental/column-resize/column-resize-directives/default-enabled-column-resize.ts @@ -31,7 +31,7 @@ import {AbstractMatColumnResize, TABLE_HOST_BINDINGS, TABLE_PROVIDERS} from './c export class MatDefaultEnabledColumnResize extends AbstractMatColumnResize { constructor( readonly columnResizeNotifier: ColumnResizeNotifier, - protected readonly elementRef: ElementRef, + readonly elementRef: ElementRef, protected readonly eventDispatcher: HeaderRowEventDispatcher, protected readonly ngZone: NgZone, protected readonly notifier: ColumnResizeNotifierSource) { diff --git a/src/material-experimental/column-resize/column-resize.spec.ts b/src/material-experimental/column-resize/column-resize.spec.ts index bdd8badc3fc7..01a852c35414 100644 --- a/src/material-experimental/column-resize/column-resize.spec.ts +++ b/src/material-experimental/column-resize/column-resize.spec.ts @@ -44,9 +44,15 @@ function getTableTemplate(defaultEnabled: boolean) { .mat-resizable { box-sizing: border-box; } + .mat-header-cell { + border: 1px solid green; + } + table { + width: 800px; + } -
- +
@@ -58,7 +64,7 @@ function getTableTemplate(defaultEnabled: boolean) { + ${directives.columnEnabled} [matResizableMinWidthPx]="150"> Name @@ -94,9 +100,15 @@ function getFlexTemplate(defaultEnabled: boolean) { .mat-resizable { box-sizing: border-box; } + .mat-header-cell { + border: 1px solid green; + } + mat-table { + width: 800px; + } -
- +
+ Name + ${directives.columnEnabled} [matResizableMinWidthPx]="150"> Name {{element.name}} @@ -146,6 +158,10 @@ abstract class BaseTestComponent { dataSource = new ElementDataSource(); direction = 'ltr'; + getTableWidth(): number { + return this.table.nativeElement.querySelector('.mat-table').offsetWidth; + } + getColumnElement(index: number): HTMLElement { return this.table.nativeElement!.querySelectorAll('.mat-resizable')[index] as HTMLElement; } @@ -154,6 +170,10 @@ abstract class BaseTestComponent { return this.getColumnElement(index).offsetWidth; } + getColumnOriginPosition(index: number): number { + return this.getColumnElement(index).offsetLeft + this.getColumnWidth(index); + } + triggerHoverState(): void { const headerCell = this.table.nativeElement.querySelector('.mat-header-cell'); headerCell.dispatchEvent(new Event('mouseover', {bubbles: true})); @@ -209,9 +229,8 @@ abstract class BaseTestComponent { abstract class BaseTestComponentRtl extends BaseTestComponent { direction = 'rtl'; - getOverlayThumbPosition(index: number): number { - const thumbElement = this.getOverlayThumbElement(index); - return parseInt((thumbElement.parentNode as HTMLElement).style.right!, 10); + getColumnOriginPosition(index: number): number { + return this.getColumnElement(index).offsetLeft; } updateResizeWithMouseInProgress(totalDelta: number): void { @@ -366,22 +385,31 @@ describe('Material Popover Edit', () => { })); it('resizes the target column via mouse input', fakeAsync(() => { + const initialTableWidth = component.getTableWidth(); const initialColumnWidth = component.getColumnWidth(1); + const initialColumnPosition = component.getColumnOriginPosition(1); component.triggerHoverState(); fixture.detectChanges(); component.beginColumnResizeWithMouse(1); - const initialPosition = component.getOverlayThumbPosition(1); - + const initialThumbPosition = component.getOverlayThumbPosition(1); component.updateResizeWithMouseInProgress(5); - (expect(component.getOverlayThumbPosition(1)) as any).isApproximately(initialPosition + 5); + let thumbPositionDelta = component.getOverlayThumbPosition(1) - initialThumbPosition; + let columnPositionDelta = component.getColumnOriginPosition(1) - initialColumnPosition; + expect(thumbPositionDelta).toBe(columnPositionDelta); + + (expect(component.getTableWidth()) as any).isApproximately(initialTableWidth + 5); (expect(component.getColumnWidth(1)) as any).isApproximately(initialColumnWidth + 5); component.updateResizeWithMouseInProgress(1); - (expect(component.getOverlayThumbPosition(1)) as any).isApproximately(initialPosition + 1); + thumbPositionDelta = component.getOverlayThumbPosition(1) - initialThumbPosition; + columnPositionDelta = component.getColumnOriginPosition(1) - initialColumnPosition; + expect(thumbPositionDelta).toBe(columnPositionDelta); + + (expect(component.getTableWidth()) as any).isApproximately(initialTableWidth + 1); (expect(component.getColumnWidth(1)) as any).isApproximately(initialColumnWidth + 1); component.completeResizeWithMouseInProgress(1); @@ -403,27 +431,34 @@ describe('Material Popover Edit', () => { component.updateResizeWithMouseInProgress(5); - (expect(component.getOverlayThumbPosition(1)) as any).toBe(initialPosition); - (expect(component.getColumnWidth(1)) as any).toBe(initialColumnWidth); + expect(component.getOverlayThumbPosition(1)).toBe(initialPosition); + expect(component.getColumnWidth(1)).toBe(initialColumnWidth); })); it('cancels an active mouse resize with the escape key', fakeAsync(() => { + const initialTableWidth = component.getTableWidth(); const initialColumnWidth = component.getColumnWidth(1); + const initialColumnPosition = component.getColumnOriginPosition(1); component.triggerHoverState(); fixture.detectChanges(); component.beginColumnResizeWithMouse(1); - const initialPosition = component.getOverlayThumbPosition(1); + const initialThumbPosition = component.getOverlayThumbPosition(1); component.updateResizeWithMouseInProgress(5); - (expect(component.getOverlayThumbPosition(1)) as any).isApproximately(initialPosition + 5); + let thumbPositionDelta = component.getOverlayThumbPosition(1) - initialThumbPosition; + let columnPositionDelta = component.getColumnOriginPosition(1) - initialColumnPosition; + expect(thumbPositionDelta).toBe(columnPositionDelta); + (expect(component.getColumnWidth(1)) as any).isApproximately(initialColumnWidth + 5); + (expect(component.getTableWidth()) as any).isApproximately(initialTableWidth + 5); dispatchKeyboardEvent(document, 'keyup', ESCAPE); (expect(component.getColumnWidth(1)) as any).isApproximately(initialColumnWidth); + (expect(component.getTableWidth()) as any).isApproximately(initialTableWidth); component.endHoverState(); fixture.detectChanges(); @@ -472,11 +507,11 @@ describe('Material Popover Edit', () => { it('performs a column resize triggered via ColumnResizeNotifier', () => { // Pre-verify that we are not updating the size to the initial size. - (expect(component.getColumnWidth(1)) as any).not.isApproximately(123); + (expect(component.getColumnWidth(1)) as any).not.isApproximately(173); - component.columnResize.columnResizeNotifier.resize('name', 123); + component.columnResize.columnResizeNotifier.resize('name', 173); - (expect(component.getColumnWidth(1)) as any).isApproximately(123); + (expect(component.getColumnWidth(1)) as any).isApproximately(173); }); }); }
Name {{element.name}}