Skip to content

Commit

Permalink
fix(fxHide,fxShow): fix standalone breakpoint selectors
Browse files Browse the repository at this point in the history
* Many directive selectors were missing a `,` separator between then xs and gt-xs breakpoints
* fxShow, fxHide preserve and restore the element's original display CSS style
* added more tests standalone breakpoint selectors, disabled selectors, and deactivated mediaQueries

fixes #62, closes ##59.
  • Loading branch information
ThomasBurleson committed Jan 21, 2017
1 parent 976d3c2 commit dafa6dc
Show file tree
Hide file tree
Showing 12 changed files with 263 additions and 79 deletions.
30 changes: 28 additions & 2 deletions src/lib/flexbox/api/base.ts
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,7 @@
* Use of this source code is governed by an MIT-style license that can be
* found in the LICENSE file at https://angular.io/license
*/
import {ElementRef, Renderer, OnDestroy} from '@angular/core';
import {ElementRef, Renderer, OnDestroy} from '@angular/core';
import {applyCssPrefixes} from '../../utils/auto-prefixer';

import {ResponsiveActivation, KeyOptions} from '../responsive/responsive-activation';
Expand All @@ -20,6 +20,11 @@ export type StyleDefinition = string|{[property: string]: string|number};

/** Abstract base class for the Layout API styling directives. */
export abstract class BaseFxDirective implements OnDestroy {
/**
* Original dom Elements CSS display style
*/
protected _display;

/**
* MediaQuery Activation Tracker
*/
Expand All @@ -36,6 +41,7 @@ export abstract class BaseFxDirective implements OnDestroy {
constructor(private _mediaMonitor: MediaMonitor,
protected _elementRef: ElementRef,
private _renderer: Renderer) {
this._display = this._getDisplayStyle() || "flex";
}

// *********************************************
Expand Down Expand Up @@ -65,6 +71,26 @@ export abstract class BaseFxDirective implements OnDestroy {
// Protected Methods
// *********************************************

/**
* Was the directive's default selector used ?
* If not, use the fallback value!
*/
protected _getDefaultVal(key: string, fallbackVal: any): string|boolean {
let val = this._queryInput(key);
let hasDefaultVal = (val !== undefined && val !== null);
return (hasDefaultVal && val !== '') ? val : fallbackVal;
}

/**
* Quick accessor to the current HTMLElement's `display` style
* Note: this allows use to preserve the original style
* and optional restore it when the mediaQueries deactivate
*/
protected _getDisplayStyle(): string {
let element: HTMLElement = this._elementRef.nativeElement;
return (element.style as any)['display'] || "flex";
}

/**
* Applies styles given via string pair or object map to the directive element.
*/
Expand Down Expand Up @@ -140,7 +166,7 @@ export abstract class BaseFxDirective implements OnDestroy {
var array = [];

// iterate backwards ensuring that length is an UInt32
for ( var i = obj.length; i--; ) {
for (var i = obj.length; i--;) {
array[i] = obj[i];
}
return array;
Expand Down
2 changes: 1 addition & 1 deletion src/lib/flexbox/api/flex-align.ts
Original file line number Diff line number Diff line change
Expand Up @@ -28,7 +28,7 @@ import {MediaMonitor} from '../../media-query/media-monitor';
@Directive({
selector: `
[fxFlexAlign],
[fxFlexAlign.xs]
[fxFlexAlign.xs],
[fxFlexAlign.gt-xs],
[fxFlexAlign.sm],
[fxFlexAlign.gt-sm]
Expand Down
2 changes: 1 addition & 1 deletion src/lib/flexbox/api/flex-offset.ts
Original file line number Diff line number Diff line change
Expand Up @@ -28,7 +28,7 @@ import {MediaMonitor} from '../../media-query/media-monitor';
*/
@Directive({selector: `
[fxFlexOffset],
[fxFlexOffset.xs]
[fxFlexOffset.xs],
[fxFlexOffset.gt-xs],
[fxFlexOffset.sm],
[fxFlexOffset.gt-sm]
Expand Down
2 changes: 1 addition & 1 deletion src/lib/flexbox/api/flex.ts
Original file line number Diff line number Diff line change
Expand Up @@ -41,7 +41,7 @@ export type FlexBasisAlias = 'grow' | 'initial' | 'auto' | 'none' | 'nogrow' | '
@Directive({
selector: `
[fxFlex],
[fxFlex.xs]
[fxFlex.xs],
[fxFlex.gt-xs],
[fxFlex.sm],
[fxFlex.gt-sm]
Expand Down
71 changes: 62 additions & 9 deletions src/lib/flexbox/api/hide.spec.ts
Original file line number Diff line number Diff line change
Expand Up @@ -5,20 +5,25 @@
* Use of this source code is governed by an MIT-style license that can be
* found in the LICENSE file at https://angular.io/license
*/
import {Component, OnInit, Inject} from '@angular/core';
import {
Component, OnInit, Inject
} from '@angular/core';
import {CommonModule} from '@angular/common';
import {ComponentFixture, TestBed} from '@angular/core/testing';

import {MockMatchMedia} from '../../media-query/mock/mock-match-media';
import {MatchMedia, MatchMediaObservable} from '../../media-query/match-media';
import {BreakPointsProvider} from '../../media-query/providers/break-points-provider';
import {BreakPointRegistry} from '../../media-query/breakpoints/break-point-registry';
import {FlexLayoutModule} from '../_module';

import {customMatchers} from '../../utils/testing/custom-matchers';
import {makeCreateTestComponent, expectNativeEl} from '../../utils/testing/helpers';
import {
makeCreateTestComponent, expectNativeEl,
} from '../../utils/testing/helpers';
import {HideDirective} from './hide';
import {MediaQueriesModule} from '../../media-query/_module';

describe('show directive', () => {
describe('hide directive', () => {
let fixture: ComponentFixture<any>;
let createTestComponent = makeCreateTestComponent(() => TestHideComponent);
let activateMediaQuery = (alias) => {
Expand All @@ -29,10 +34,11 @@ describe('show directive', () => {
beforeEach(() => {
jasmine.addMatchers(customMatchers);


// Configure testbed to prepare services
TestBed.configureTestingModule({
imports: [CommonModule, FlexLayoutModule.forRoot()],
declarations: [TestHideComponent],
imports: [CommonModule, MediaQueriesModule.forRoot()],
declarations: [TestHideComponent, HideDirective],
providers: [
BreakPointRegistry, BreakPointsProvider,
{provide: MatchMedia, useClass: MockMatchMedia}
Expand Down Expand Up @@ -77,7 +83,7 @@ describe('show directive', () => {

it('should update styles with binding changes', () => {
fixture = createTestComponent(`
<div [fxHide]="menuHidden" >
<div [fxHide]="menuHidden">
...content
</div>
`);
Expand All @@ -92,7 +98,7 @@ describe('show directive', () => {

describe('with responsive features', () => {

it('should show on `xs` viewports only', () => {
it('should show on `xs` viewports only when the default is included', () => {
fixture = createTestComponent(`
<div fxHide="" fxHide.xs="false" >
...content
Expand All @@ -108,6 +114,52 @@ describe('show directive', () => {

});

it('should preserve display and update only on activated mediaQuery', () => {
fixture = createTestComponent(`
<div [fxHide.xs]="isHidden" style="display:inline-block"></div>
`);
expectNativeEl(fixture).toHaveCssStyle({'display': 'inline-block'});

// should hide with this activation
activateMediaQuery('xs');
expectNativeEl(fixture).toHaveCssStyle({'display': 'none'});

// should reset to original display style
activateMediaQuery('md');
expectNativeEl(fixture).toHaveCssStyle({'display': 'inline-block'});
});

it('should restore original display when disabled', () => {
fixture = createTestComponent(`
<div [fxHide.xs]="isHidden" style="display:inline-block"></div>
`);
expectNativeEl(fixture).toHaveCssStyle({'display': 'inline-block'});

// should hide with this activation
activateMediaQuery('xs');
expectNativeEl(fixture).toHaveCssStyle({'display': 'none'});

// should reset to original display style
fixture.componentInstance.isHidden = false;
expectNativeEl(fixture).toHaveCssStyle({'display': 'inline-block'});
});

it('should restore original display when the mediaQuery deactivates', () => {
let originalDisplay = {'display': 'table'};
fixture = createTestComponent(`
<div [fxHide.xs]="isHidden" style="display:table"></div>
`);
expectNativeEl(fixture).toHaveCssStyle(originalDisplay);

// should hide with this activation
activateMediaQuery('xs');
expectNativeEl(fixture).toHaveCssStyle({'display': 'none'});

// should reset to original display style
activateMediaQuery('md');
expectNativeEl(fixture).toHaveCssStyle(originalDisplay);
});

it('should support use of the `media` observable in templates ', () => {
fixture = createTestComponent(`
<div [fxHide]="media.isActive('xs')" >
Expand Down Expand Up @@ -150,7 +202,8 @@ describe('show directive', () => {
})
export class TestHideComponent implements OnInit {
isVisible = 0;
menuHidden: boolean = true;
isHidden = true;
menuHidden = true;

constructor(@Inject(MatchMediaObservable) private media) {
}
Expand Down
83 changes: 55 additions & 28 deletions src/lib/flexbox/api/hide.ts
Original file line number Diff line number Diff line change
Expand Up @@ -30,9 +30,10 @@ import {LayoutDirective} from './layout';
* 'show' Layout API directive
*
*/
@Directive({selector: `
@Directive({
selector: `
[fxHide],
[fxHide.xs]
[fxHide.xs],
[fxHide.gt-xs],
[fxHide.sm],
[fxHide.gt-sm]
Expand All @@ -41,38 +42,63 @@ import {LayoutDirective} from './layout';
[fxHide.lg],
[fxHide.gt-lg],
[fxHide.xl]
`})
`
})
export class HideDirective extends BaseFxDirective implements OnInit, OnChanges, OnDestroy {
/**
* Original dom Elements CSS display style
*/
private _display = 'flex';

/**
* Subscription to the parent flex container's layout changes.
* Stored so we can unsubscribe when this directive is destroyed.
*/
* Subscription to the parent flex container's layout changes.
* Stored so we can unsubscribe when this directive is destroyed.
*/
private _layoutWatcher: Subscription;

@Input('fxHide') set hide(val) { this._cacheInput("hide", val); }
@Input('fxHide.xs') set hideXs(val) { this._cacheInput('hideXs', val); }
@Input('fxHide.gt-xs') set hideGtXs(val) { this._cacheInput('hideGtXs', val); };
@Input('fxHide.sm') set hideSm(val) { this._cacheInput('hideSm', val); };
@Input('fxHide.gt-sm') set hideGtSm(val) { this._cacheInput('hideGtSm', val); };
@Input('fxHide.md') set hideMd(val) { this._cacheInput('hideMd', val); };
@Input('fxHide.gt-md') set hideGtMd(val) { this._cacheInput('hideGtMd', val); };
@Input('fxHide.lg') set hideLg(val) { this._cacheInput('hideLg', val); };
@Input('fxHide.gt-lg') set hideGtLg(val) { this._cacheInput('hideGtLg', val); };
@Input('fxHide.xl') set hideXl(val) { this._cacheInput('hideXl', val); };
@Input('fxHide') set hide(val) {
this._cacheInput("hide", val);
}

@Input('fxHide.xs') set hideXs(val) {
this._cacheInput('hideXs', val);
}

@Input('fxHide.gt-xs') set hideGtXs(val) {
this._cacheInput('hideGtXs', val);
};

@Input('fxHide.sm') set hideSm(val) {
this._cacheInput('hideSm', val);
};

@Input('fxHide.gt-sm') set hideGtSm(val) {
this._cacheInput('hideGtSm', val);
};

@Input('fxHide.md') set hideMd(val) {
this._cacheInput('hideMd', val);
};

@Input('fxHide.gt-md') set hideGtMd(val) {
this._cacheInput('hideGtMd', val);
};

@Input('fxHide.lg') set hideLg(val) {
this._cacheInput('hideLg', val);
};

@Input('fxHide.gt-lg') set hideGtLg(val) {
this._cacheInput('hideGtLg', val);
};

@Input('fxHide.xl') set hideXl(val) {
this._cacheInput('hideXl', val);
};

/**
*
*/
constructor(
monitor: MediaMonitor,
@Optional() @Self() private _layout: LayoutDirective,
protected elRef: ElementRef,
protected renderer: Renderer) {
constructor(monitor: MediaMonitor,
@Optional() @Self() private _layout: LayoutDirective,
protected elRef: ElementRef,
protected renderer: Renderer) {
super(monitor, elRef, renderer);

if (_layout) {
Expand Down Expand Up @@ -105,7 +131,8 @@ export class HideDirective extends BaseFxDirective implements OnInit, OnChanges,
* mql change events to onMediaQueryChange handlers
*/
ngOnInit() {
this._listenForMediaQueryChanges('hide', true, (changes: MediaChange) => {
let value = this._getDefaultVal("hide", false);
this._listenForMediaQueryChanges('hide', value, (changes: MediaChange) => {
this._updateWithValue(changes.value);
});
this._updateWithValue();
Expand All @@ -127,7 +154,7 @@ export class HideDirective extends BaseFxDirective implements OnInit, OnChanges,
* Validate the visibility value and then update the host's inline display style
*/
private _updateWithValue(value?: string|number|boolean) {
value = value || this._queryInput("hide") || true;
value = value || this._getDefaultVal("hide", false);
if (this._mqActivation) {
value = this._mqActivation.activatedInput;
}
Expand All @@ -141,7 +168,7 @@ export class HideDirective extends BaseFxDirective implements OnInit, OnChanges,
* Build the CSS that should be assigned to the element instance
*/
private _buildCSS(value) {
return {'display': value ? 'none' : this._display };
return {'display': value ? 'none' : this._display};
}

/**
Expand Down
2 changes: 1 addition & 1 deletion src/lib/flexbox/api/layout-align.ts
Original file line number Diff line number Diff line change
Expand Up @@ -37,7 +37,7 @@ import {LAYOUT_VALUES, LayoutDirective} from './layout';
*/
@Directive({selector: `
[fxLayoutAlign],
[fxLayoutAlign.xs]
[fxLayoutAlign.xs],
[fxLayoutAlign.gt-xs],
[fxLayoutAlign.sm],
[fxLayoutAlign.gt-sm]
Expand Down
2 changes: 1 addition & 1 deletion src/lib/flexbox/api/layout-gap.ts
Original file line number Diff line number Diff line change
Expand Up @@ -30,7 +30,7 @@ import {LayoutDirective, LAYOUT_VALUES} from './layout';
*/
@Directive({selector: `
[fxLayoutGap],
[fxLayoutGap.xs]
[fxLayoutGap.xs],
[fxLayoutGap.gt-xs],
[fxLayoutGap.sm],
[fxLayoutGap.gt-sm]
Expand Down
2 changes: 1 addition & 1 deletion src/lib/flexbox/api/layout-wrap.ts
Original file line number Diff line number Diff line change
Expand Up @@ -31,7 +31,7 @@ import {LayoutDirective, LAYOUT_VALUES} from './layout';
*/
@Directive({selector: `
[fxLayoutWrap],
[fxLayoutWrap.xs]
[fxLayoutWrap.xs],
[fxLayoutWrap.gt-xs],
[fxLayoutWrap.sm],
[fxLayoutWrap.gt-sm]
Expand Down
2 changes: 1 addition & 1 deletion src/lib/flexbox/api/layout.ts
Original file line number Diff line number Diff line change
Expand Up @@ -33,7 +33,7 @@ export const LAYOUT_VALUES = ['row', 'column', 'row-reverse', 'column-reverse'];
*/
@Directive({selector: `
[fxLayout],
[fxLayout.xs]
[fxLayout.xs],
[fxLayout.gt-xs],
[fxLayout.sm],
[fxLayout.gt-sm]
Expand Down
Loading

0 comments on commit dafa6dc

Please sign in to comment.