Skip to content
This repository was archived by the owner on Jan 6, 2025. It is now read-only.
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Original file line number Diff line number Diff line change
@@ -1,25 +1,25 @@
import {ChangeDetectionStrategy, Component} from '@angular/core';
import {Component} from '@angular/core';
import {MediaChange, MediaObserver} from '@angular/flex-layout';
import {Observable} from 'rxjs';

@Component({
selector: 'media-query-status',
template: `
<div class="mqInfo" *ngIf="media$ | async as event">
<span title="Active MediaQuery">{{ extractQuery(event) }}</span>
<div class="mqInfo">
Active MediaQuery(s):
<ul>
<li *ngFor="let change of (media$ | async) as changes">
{{change.mqAlias}} = {{change.mediaQuery}}
</li>
</ul>
</div>
`,
styleUrls: ['./media-query-status.component.scss'],
changeDetection : ChangeDetectionStrategy.OnPush
})
export class MediaQueryStatusComponent {
media$: Observable<MediaChange>;
media$: Observable<MediaChange[]>;

constructor(mediaObserver: MediaObserver) {
this.media$ = mediaObserver.media$;
}

extractQuery(change: MediaChange): string {
return change ? `'${change.mqAlias}' = (${change.mediaQuery})` : '';
constructor(media: MediaObserver) {
this.media$ = media.asObservable();
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -17,13 +17,13 @@ export class ResponsiveRowColumnComponent implements OnDestroy {
};
isVisible = true;

private activeMQC: MediaChange;
private activeMQC: MediaChange[];
private subscription: Subscription;

constructor(mediaObserver: MediaObserver) {
this.subscription = mediaObserver.media$
.subscribe((e: MediaChange) => {
this.activeMQC = e;
constructor(mediaService: MediaObserver) {
this.subscription = mediaService.asObservable()
.subscribe((events: MediaChange[]) => {
this.activeMQC = events;
});
}

Expand All @@ -32,16 +32,18 @@ export class ResponsiveRowColumnComponent implements OnDestroy {
}

toggleLayoutFor(col: number) {
switch (col) {
case 1:
const set1 = `firstCol${this.activeMQC ? this.activeMQC.suffix : ''}`;
this.cols[set1] = (this.cols[set1] === 'column') ? 'row' : 'column';
break;
this.activeMQC.forEach((change: MediaChange) => {
switch (col) {
case 1:
const set1 = `firstCol${change ? change.suffix : ''}`;
this.cols[set1] = (this.cols[set1] === 'column') ? 'row' : 'column';
break;

case 2:
const set2 = 'secondCol';
this.cols[set2] = (this.cols[set2] === 'row') ? 'column' : 'row';
break;
}
case 2:
const set2 = 'secondCol';
this.cols[set2] = (this.cols[set2] === 'row') ? 'column' : 'row';
break;
}
});
}
}
13 changes: 8 additions & 5 deletions src/lib/core/add-alias.ts
Original file line number Diff line number Diff line change
Expand Up @@ -7,15 +7,18 @@
*/
import {MediaChange} from './media-change';
import {BreakPoint} from './breakpoints/break-point';
import {extendObject} from '../utils/object-extend';

/**
* For the specified MediaChange, make sure it contains the breakpoint alias
* and suffix (if available).
*/
export function mergeAlias(dest: MediaChange, source: BreakPoint | null): MediaChange {
return extendObject(dest || {}, source ? {
mqAlias: source.alias,
suffix: source.suffix
} : {});
dest = dest ? dest.clone() : new MediaChange();
if (source) {
dest.mqAlias = source.alias;
dest.mediaQuery = source.mediaQuery;
dest.suffix = source.suffix as string;
dest.priority = source.priority as number;
}
return dest;
}
71 changes: 38 additions & 33 deletions src/lib/core/match-media/match-media.spec.ts
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,8 @@
* found in the LICENSE file at https://angular.io/license
*/
import {TestBed, inject} from '@angular/core/testing';
import {BreakPoint} from '@angular/flex-layout/core';
import {Subscription} from 'rxjs';

import {MediaChange} from '../media-change';
import {MockMatchMedia, MockMatchMediaProvider} from './mock/mock-match-media';
Expand All @@ -16,7 +18,6 @@ import {MediaObserver} from '../media-observer/media-observer';
describe('match-media', () => {
let breakPoints: BreakPointRegistry;
let mediaController: MockMatchMedia;
let mediaObserver: MediaObserver;

beforeEach(() => {
// Configure testbed to prepare services
Expand All @@ -31,11 +32,11 @@ describe('match-media', () => {
_breakPoints: BreakPointRegistry) => {
breakPoints = _breakPoints;
mediaController = _matchMedia; // inject only to manually activate mediaQuery ranges
mediaObserver = _mediaObserver;
}));

afterEach(() => {
mediaController.clearAll();
mediaController.clearAll();
mediaController.useOverlaps = false;
});

it('can observe the initial, default activation for mediaQuery == "all". ', () => {
Expand Down Expand Up @@ -101,38 +102,41 @@ describe('match-media', () => {
});

describe('match-media-observable', () => {
const watchMedia = (alias: string, observer: (value: MediaChange) => void): Subscription => {
return mediaController
.observe(alias ? [alias] : [])
.subscribe(observer);
};

it('can observe an existing activation', () => {
let current: MediaChange = new MediaChange();
let bp = breakPoints.findByAlias('md')!;
mediaController.activate(bp.mediaQuery);
let subscription = mediaObserver.media$.subscribe((change: MediaChange) => {
current = change;
});
const onChange = (change: MediaChange) => current = change;
const subscription = watchMedia('md', onChange);

mediaController.activate(bp.mediaQuery);
expect(current.mediaQuery).toEqual(bp.mediaQuery);
subscription.unsubscribe();
});

it('can observe the initial, default activation for mediaQuery == "all". ', () => {
let current: MediaChange = new MediaChange();
let subscription = mediaObserver.media$.subscribe((change: MediaChange) => {
current = change;
});
const onChange = (change: MediaChange) => current = change;
const subscription = watchMedia('', onChange);

expect(current.mediaQuery).toEqual('all');
subscription.unsubscribe();
});

it('can observe custom mediaQuery ranges', () => {
let current: MediaChange = new MediaChange();
let customQuery = 'screen and (min-width: 610px) and (max-width: 620px)';
let subscription = mediaObserver.media$.subscribe((change: MediaChange) => {
current = change;
});
const customQuery = 'screen and (min-width: 610px) and (max-width: 620px)';
const onChange = (change: MediaChange) => current = change;
const subscription = watchMedia(customQuery, onChange);

mediaController.useOverlaps = true;
let activated = mediaController.activate(customQuery);
const activated = mediaController.activate(customQuery);

expect(activated).toEqual(true);
expect(current.mediaQuery).toEqual(customQuery);

Expand All @@ -141,46 +145,47 @@ describe('match-media', () => {

it('can observe registered breakpoint activations', () => {
let current: MediaChange = new MediaChange();
let bp = breakPoints.findByAlias('md') !;
let subscription = mediaObserver.media$.subscribe((change: MediaChange) => {
current = change;
});
const onChange = (change: MediaChange) => current = change;
const subscription = watchMedia('md', onChange);

let bp = breakPoints.findByAlias('md') !;
let activated = mediaController.activate(bp.mediaQuery);
expect(activated).toEqual(true);

expect(activated).toEqual(true);
expect(current.mediaQuery).toEqual(bp.mediaQuery);

subscription.unsubscribe();
});

/**
* Only the MediaObserver ignores de-activations;
* MediaMonitor and MatchMedia report both activations and de-activations!
* Only the MediaObserver ignores de-activations;
*/
it('ignores mediaQuery de-activations', () => {
let activationCount = 0;
let deactivationCount = 0;

mediaObserver.filterOverlaps = false;
let subscription = mediaObserver.media$.subscribe((change: MediaChange) => {
it('reports mediaQuery de-activations', () => {
const lookupMediaQuery = (alias: string) => {
const bp: BreakPoint = breakPoints.findByAlias(alias) as BreakPoint;
return bp.mediaQuery;
};
let activationCount = 0, deactivationCount = 0;
let subscription = watchMedia('', (change: MediaChange) => {
if (change.matches) {
++activationCount;
activationCount += 1;
} else {
++deactivationCount;
deactivationCount += 1;
}
});

mediaController.activate(breakPoints.findByAlias('md')!.mediaQuery);
mediaController.activate(breakPoints.findByAlias('gt-md')!.mediaQuery);
mediaController.activate(breakPoints.findByAlias('lg')!.mediaQuery);
mediaController.activate(lookupMediaQuery('md'));
mediaController.activate(lookupMediaQuery('gt-md'));
mediaController.activate(lookupMediaQuery('lg'));

// 'all' mediaQuery is already active; total count should be (3)
expect(activationCount).toEqual(4);
expect(deactivationCount).toEqual(0);
expect(deactivationCount).toEqual(2);

subscription.unsubscribe();
});

});
});

15 changes: 14 additions & 1 deletion src/lib/core/match-media/match-media.ts
Original file line number Diff line number Diff line change
Expand Up @@ -32,6 +32,19 @@ export class MatchMedia {
@Inject(DOCUMENT) protected _document: any) {
}

/**
* Publish list of all current activations
*/
get activations(): string[] {
const results: string[] = [];
this._registry.forEach((mql: MediaQueryList, key: string) => {
if (mql.matches) {
results.push(key);
}
});
return results;
}

/**
* For the specified mediaQuery?
*/
Expand Down Expand Up @@ -60,7 +73,7 @@ export class MatchMedia {
* subscribers of notifications.
*/
observe(mqList?: string[], filterOthers = false): Observable<MediaChange> {
if (mqList) {
if (mqList && mqList.length) {
const matchMedia$: Observable<MediaChange> = this._observable$.pipe(
filter((change: MediaChange) => {
return !filterOthers ? true : (mqList.indexOf(change.mediaQuery) > -1);
Expand Down
3 changes: 2 additions & 1 deletion src/lib/core/media-change.ts
Original file line number Diff line number Diff line change
Expand Up @@ -23,7 +23,8 @@ export class MediaChange {
constructor(public matches = false,
public mediaQuery = 'all',
public mqAlias = '',
public suffix = '') {
public suffix = '',
public priority = 0) {
}

/** Create an exact copy of the MediaChange */
Expand Down
Loading