Skip to content

Commit

Permalink
Merge branch 'master' into sboykova/editable-date-picker
Browse files Browse the repository at this point in the history
  • Loading branch information
sboykova committed Jan 4, 2019
2 parents a856cfc + d87c61e commit 7e5d086
Show file tree
Hide file tree
Showing 16 changed files with 1,484 additions and 651 deletions.
5 changes: 4 additions & 1 deletion CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -22,8 +22,11 @@ All notable changes for each version of this project will be documented in this
- `focusedValuePipe` input property is provided that allows developers to additionally transform the value on focus;
- `IgxTreeGrid`:
- Batch editing - an injectable transaction provider accumulates pending changes, which are not directly applied to the grid's data source. Those can later be inspected, manipulated and submitted at once. Changes are collected for individual cells or rows, depending on editing mode, and accumulated per data row/record.
- You can now export the tree grid both to CSV and Excel. The hierarchy and the records' expanded states would be reflected in the exported Excel worksheet.
- You can now export the tree grid both to CSV and Excel.
- The hierarchy and the records' expanded states would be reflected in the exported Excel worksheet.
- Summaries feature is now supported in the tree grid. Summary results are calculated and displayed for the root level and each child level by default.
- `IgxOverlayService`:
- `ElasticPositioningStrategy` added. This strategy positions the element as in **Connected** positioning strategy and resize the element to fit in the view port in case the element is partially getting out of view.

## 7.0.4
### Bug fixes
Expand Down
8 changes: 8 additions & 0 deletions projects/igniteui-angular/src/lib/core/utils.spec.ts
Original file line number Diff line number Diff line change
Expand Up @@ -161,6 +161,14 @@ describe('Utils', () => {
expect(clone.Null).toBeNull();
expect(clone.undefined).toBeUndefined();
});

it('Should correctly handle null and undefined values', () => {
const nullClone = cloneValue(null);
expect(nullClone).toBeNull();

const undefinedClone = cloneValue(undefined);
expect(undefinedClone).toBeUndefined();
});
});

describe('Utils - mergeObjects() unit tests', () => {
Expand Down
6 changes: 5 additions & 1 deletion projects/igniteui-angular/src/lib/grids/grid.common.ts
Original file line number Diff line number Diff line change
Expand Up @@ -611,7 +611,11 @@ export class ContainerPositioningStrategy extends ConnectedPositioningStrategy {
this.settings.verticalStartPoint = this.isTop ? VerticalAlignment.Top : VerticalAlignment.Bottom;
this.settings.openAnimation = this.isTop ? scaleInVerBottom : scaleInVerTop;
const startPoint = getPointFromPositionsSettings(this.settings, contentElement.parentElement);
contentElement.style.top = startPoint.y + (this.isTop ? VerticalAlignment.Top : VerticalAlignment.Bottom) * size.height + 'px';

// TODO: extract transform setting in util function
const translateY = startPoint.y + (this.isTop ? VerticalAlignment.Top : VerticalAlignment.Bottom) * size.height;
const translateYString = `translateY(${translateY}px)`;
contentElement.style.transform = contentElement.style.transform.replace(/translateY\([.-\d]+px\)/g, translateYString);
contentElement.style.width = target.clientWidth + 'px';
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -1293,7 +1293,7 @@ describe('IgxGrid - Filtering actions', () => {
tick();
fix.detectChanges();

const firstMonth = calendar.queryAll(By.css('.igx-calendar__month'))[0];
const firstMonth = calendar.queryAll(By.css(`[class*='igx-calendar__month']`))[0];
firstMonth.nativeElement.click();
tick();
fix.detectChanges();
Expand Down
1,728 changes: 1,216 additions & 512 deletions projects/igniteui-angular/src/lib/services/overlay/overlay.spec.ts

Large diffs are not rendered by default.

24 changes: 16 additions & 8 deletions projects/igniteui-angular/src/lib/services/overlay/overlay.ts
Original file line number Diff line number Diff line change
Expand Up @@ -166,7 +166,13 @@ export class IgxOverlayService implements OnDestroy {
this.updateSize(info);
this._overlayInfos.push(info);

settings.positionStrategy.position(info.elementRef.nativeElement.parentElement, info.initialSize, document, true);
info.originalElementStyle = info.elementRef.nativeElement.style;
settings.positionStrategy.position(
info.elementRef.nativeElement.parentElement,
{ width: info.initialSize.width, height: info.initialSize.height },
document,
true,
settings.positionStrategy.settings.minSize);
settings.scrollStrategy.initialize(this._document, this, id);
settings.scrollStrategy.attach();
}
Expand Down Expand Up @@ -246,16 +252,18 @@ export class IgxOverlayService implements OnDestroy {
* ```
*/
reposition(id: string) {
const overlay = this.getOverlayById(id);
if (!overlay) {
const overlayInfo = this.getOverlayById(id);
if (!overlayInfo) {
console.error('Wrong id provided in overlay.reposition method. Id: ' + id);
return;
}

overlay.settings.positionStrategy.position(
overlay.elementRef.nativeElement.parentElement,
overlay.initialSize,
this._document);
overlayInfo.settings.positionStrategy.position(
overlayInfo.elementRef.nativeElement.parentElement,
{ width: overlayInfo.initialSize.width, height: overlayInfo.initialSize.height },
this._document,
false,
overlayInfo.settings.positionStrategy.settings.minSize);
}

private getOverlayInfo(component: any): OverlayInfo {
Expand Down Expand Up @@ -395,7 +403,7 @@ export class IgxOverlayService implements OnDestroy {
this._overlayElement.parentElement.removeChild(this._overlayElement);
this._overlayElement = null;
}

info.elementRef.nativeElement.style = info.originalElementStyle;
this.onClosed.emit({ id: info.id, componentRef: info.componentRef });
}

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -16,9 +16,10 @@ export interface IPositionStrategy {
* @param size Size of the element
* @param document reference to the Document object
* @param initialCall should be true if this is the initial call to the method
* @param minSize the size up to which element could be reduced
* ```typescript
* settings.positionStrategy.position(content, size, document, true);
* ```
*/
position(contentElement: HTMLElement, size?: Size, document?: Document, initialCall?: boolean): void;
position(contentElement: HTMLElement, size?: Size, document?: Document, initialCall?: boolean, minSize?: Size): void;
}
Original file line number Diff line number Diff line change
Expand Up @@ -14,12 +14,18 @@ Position strategies determine where to display the component in the provided Igx
|:----------------|:--------------------------|:-------------------------|:-------------------------|:-------------------------|
| new Point(0, 0) | HorizontalAlignment.Right | VerticalAlignment.Bottom | HorizontalAlignment.Left | VerticalAlignment.Bottom |

3) **Auto** - Positions the element as in **Connected** positioning strategy and re-positions the element in the view port (calculating a different start point) in case the element is partially getting out of view, adding an offsetPadding. Defaults to:
3) **Auto** - Positions the element as in **Connected** positioning strategy and re-positions the element in the view port (calculating a different start point) in case the element is partially getting out of view. Defaults to:

| target | horizontalDirection | verticalDirection | horizontalStartPoint | verticalStartPoint |
|:----------------|:--------------------------|:-------------------------|:-------------------------|:-------------------------|
| new Point(0, 0) | HorizontalAlignment.Right | VerticalAlignment.Bottom | HorizontalAlignment.Left | VerticalAlignment.Bottom |

4) **Elastic** - Positions the element as in **Connected** positioning strategy and resize the element to fit in the view port in case the element is partially getting out of view. Defaults to:

| target | horizontalDirection | verticalDirection | horizontalStartPoint | verticalStartPoint | minSize |
|:----------------|:--------------------------|:-------------------------|:-------------------------|:-------------------------|-------------------------|
| new Point(0, 0) | HorizontalAlignment.Right | VerticalAlignment.Bottom | HorizontalAlignment.Left | VerticalAlignment.Bottom | { width: 0, height: 0 } |

## Usage
Position an element based on an existing button as a target, so it's start point is the button's Bottom/Left corner.
```typescript
Expand All @@ -28,7 +34,8 @@ const positionSettings: PositionSettings = {
horizontalDirection: HorizontalAlignment.Right,
verticalDirection: VerticalAlignment.Bottom,
horizontalStartPoint: HorizontalAlignment.Left,
verticalStartPoint: VerticalAlignment.Bottom
verticalStartPoint: VerticalAlignment.Bottom,
minSize: { width: 100, height: 300 }
};

const strategy = new ConnectedPositioningStrategy(positionSettings);
Expand All @@ -48,11 +55,12 @@ import {AutoPositionStrategy, GlobalPositionStrategy, ConnectedPositioningStrate
## API

##### Methods
| Position Strategy | Name | Description |
|:------------------|:---------------------------------------------|:------------------------------------------------|
| Global | `position(contentElement)` | Positions the element, based on the horizontal and vertical directions. |
| Connected | `position(contentElement, size{})` | Positions the element, based on the position strategy used and the size passed in.|
| Auto | `position(contentElement, size{}, document?)`| Positions the element, based on the position strategy used and the size passed in.|
| Position Strategy | Name | Description |
|:------------------|:-------------------------------------------------------|:----------------------------------------------------------------------------------|
| Global | `position(contentElement)` | Positions the element, based on the horizontal and vertical directions. |
| Connected | `position(contentElement, size{})` | Positions the element, based on the position strategy used and the size passed in.|
| Auto | `position(contentElement, size{}, document?)` | Positions the element, based on the position strategy used and the size passed in.|
| Elastic | `position(contentElement, size{}, document?, minSize?)`| Positions the element, based on the position strategy used and the size passed in.|

###### PositionSettings
| Name | Type | Description |
Expand All @@ -64,3 +72,4 @@ import {AutoPositionStrategy, GlobalPositionStrategy, ConnectedPositioningStrate
|verticalStartPoint | VerticalAlignment | Target's starting point |
|openAnimation | AnimationReferenceMetadata | Animation applied while overlay opens |
|closeAnimation | AnimationReferenceMetadata | Animation applied while overlay closes |
|minSize | Size | The size up to which element could be reduced |
Original file line number Diff line number Diff line change
@@ -1,88 +1,35 @@
import { PositionSettings, VerticalAlignment, HorizontalAlignment, Size } from './../utilities';
import { VerticalAlignment, HorizontalAlignment, PositionSettings, Size } from './../utilities';
import { IPositionStrategy } from './IPositionStrategy';
import { ConnectedPositioningStrategy } from './connected-positioning-strategy';
import { BaseFitPositionStrategy } from './base-fit-position-strategy';

enum Axis {
X = 1,
Y = 0
}
export class AutoPositionStrategy extends ConnectedPositioningStrategy implements IPositionStrategy {
public offsetPadding = 16;
private _initialSettings;

getViewPort(document) { // Material Design implementation
const clientRect = document.documentElement.getBoundingClientRect();
const scrollPosition = {
top: -clientRect.top,
left: -clientRect.left
};
const width = window.innerWidth;
const height = window.innerHeight;

return {
top: scrollPosition.top,
left: scrollPosition.left,
bottom: scrollPosition.top + height,
right: scrollPosition.left + width,
height,
width
};
export class AutoPositionStrategy extends BaseFitPositionStrategy implements IPositionStrategy {
fitHorizontal(element: HTMLElement, settings: PositionSettings, innerRect: ClientRect, outerRect: ClientRect, minSize: Size) {
switch (settings.horizontalDirection) {
case HorizontalAlignment.Left:
settings.horizontalDirection = HorizontalAlignment.Right;
settings.horizontalStartPoint = HorizontalAlignment.Right;
break;
case HorizontalAlignment.Right:
settings.horizontalDirection = HorizontalAlignment.Left;
settings.horizontalStartPoint = HorizontalAlignment.Left;
break;
}

super.position(element, this._initialSize);
}

// The position method should return a <div> container that will host the component
/** @inheritdoc */
position(contentElement: HTMLElement, size?: Size, document?: Document, initialCall?: boolean): void {
if (!initialCall) {
super.position(contentElement, size);
return;
fitVertical(element: HTMLElement, settings: PositionSettings, innerRect: ClientRect, outerRect: ClientRect, minSize: Size) {
switch (settings.verticalDirection) {
case VerticalAlignment.Top:
settings.verticalDirection = VerticalAlignment.Bottom;
settings.verticalStartPoint = VerticalAlignment.Bottom;
break;
case VerticalAlignment.Bottom:
settings.verticalDirection = VerticalAlignment.Top;
settings.verticalStartPoint = VerticalAlignment.Top;
break;
}
this._initialSettings = this._initialSettings || Object.assign({}, this._initialSettings, this.settings);
this.settings = this._initialSettings ? Object.assign({}, this.settings, this._initialSettings) : this.settings;
const viewPort = this.getViewPort(document);
super.position(contentElement, size);
const checkIfMoveHorizontal = (elem: HTMLElement) => {
const leftBound = elem.offsetLeft;
const rightBound = elem.offsetLeft + elem.lastElementChild.clientWidth;
switch (this.settings.horizontalDirection) {
case HorizontalAlignment.Left:
if (leftBound < viewPort.left) {
this.settings.horizontalDirection = HorizontalAlignment.Right;
this.settings.horizontalStartPoint = HorizontalAlignment.Right;
}
break;
case HorizontalAlignment.Right:
if (rightBound > viewPort.right) {
this.settings.horizontalDirection = HorizontalAlignment.Left;
this.settings.horizontalStartPoint = HorizontalAlignment.Left;
}
break;
default:
return;
}
};
const checkIfMoveVertical = (elem: HTMLElement) => {
const topBound = elem.offsetTop;
const bottomBound = elem.offsetTop + elem.lastElementChild.clientHeight;
switch (this.settings.verticalDirection) {
case VerticalAlignment.Top:
if (topBound < viewPort.top) {
this.settings.verticalDirection = VerticalAlignment.Bottom;
this.settings.verticalStartPoint = VerticalAlignment.Bottom;
}
break;
case VerticalAlignment.Bottom:
if (bottomBound > viewPort.bottom) {
this.settings.verticalDirection = VerticalAlignment.Top;
this.settings.verticalStartPoint = VerticalAlignment.Top;
}
break;
default:
return;
}
};
checkIfMoveVertical(contentElement);
checkIfMoveHorizontal(contentElement);
super.position(contentElement, size);

super.position(element, this._initialSize);
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,71 @@
import { ConnectedPositioningStrategy } from './connected-positioning-strategy';
import { IPositionStrategy } from './IPositionStrategy';
import { HorizontalAlignment, VerticalAlignment, PositionSettings, Size } from '../utilities';

export abstract class BaseFitPositionStrategy extends ConnectedPositioningStrategy implements IPositionStrategy {
protected _initialSettings: PositionSettings;
protected _initialSize: Size;

position(contentElement: HTMLElement, size: Size, document?: Document, initialCall?: boolean, minSize?: Size): void {
this._initialSize = size;
super.position(contentElement, size);
if (!initialCall) {
return;
}
this._initialSettings = this._initialSettings || Object.assign({}, this._initialSettings, this.settings);
this.settings = this._initialSettings ? Object.assign({}, this.settings, this._initialSettings) : this.settings;
const elementRect: ClientRect = contentElement.getBoundingClientRect();
const viewPort: ClientRect = {
left: 0,
top: 0,
right: window.innerWidth,
bottom: window.innerHeight,
width: window.innerWidth,
height: window.innerHeight,
};
if (this.shouldFitHorizontal(this.settings, elementRect, viewPort)) {
this.fitHorizontal(contentElement, this.settings, elementRect, viewPort, minSize);
}

if (this.shouldFitVertical(this.settings, elementRect, viewPort)) {
this.fitVertical(contentElement, this.settings, elementRect, viewPort, minSize);
}
}

protected shouldFitHorizontal(settings: PositionSettings, innerRect: ClientRect, outerRect: ClientRect): boolean {
switch (settings.horizontalDirection) {
case HorizontalAlignment.Left:
if (innerRect.left < outerRect.left) {
return true;
}
break;
case HorizontalAlignment.Right:
if (innerRect.right > outerRect.right) {
return true;
}
break;
}

return false;
}

protected shouldFitVertical(settings: PositionSettings, innerRect: ClientRect, outerRect: ClientRect): boolean {
switch (settings.verticalDirection) {
case VerticalAlignment.Top:
if (innerRect.top < outerRect.top) {
return true;
}
break;
case VerticalAlignment.Bottom:
if (innerRect.bottom > outerRect.bottom) {
return true;
}
break;
}

return false;
}

abstract fitHorizontal(element: HTMLElement, settings: PositionSettings, innerRect: ClientRect, outerRect: ClientRect, minSize: Size);
abstract fitVertical(element: HTMLElement, settings: PositionSettings, innerRect: ClientRect, outerRect: ClientRect, minSize: Size);
}
Loading

0 comments on commit 7e5d086

Please sign in to comment.