ngm-masonry
Version:
Angular Module for displaying a feed of items in a masonry layout using https://github.com/glebmlk/ngx-masonry
287 lines (279 loc) • 9 kB
JavaScript
import { isPlatformBrowser } from '@angular/common';
import { ChangeDetectionStrategy, ChangeDetectorRef, Component, ElementRef, EventEmitter, Inject, Input, NgZone, Output, PLATFORM_ID, Directive, forwardRef, NgModule } from '@angular/core';
/**
* @fileoverview added by tsickle
* @suppress {checkTypes,extraRequire,missingReturn,unusedPrivateMembers,uselessCode} checked by tsc
*/
/** @type {?} */
let imagesLoaded;
/** @type {?} */
let masonryConstructor;
class NgmMasonryComponent {
/**
* @param {?} platformId
* @param {?} element
* @param {?} ngZone
* @param {?} changeDetectorRef
*/
constructor(platformId, element, ngZone, changeDetectorRef) {
this.platformId = platformId;
this.element = element;
this.ngZone = ngZone;
this.changeDetectorRef = changeDetectorRef;
// Inputs
this.options = {};
this.useImagesLoaded = false;
this.updateLayout = false;
// Outputs
this.layoutComplete = new EventEmitter();
this.removeComplete = new EventEmitter();
}
/**
* @return {?}
*/
ngOnInit() {
this.ngZone.runOutsideAngular(() => {
if (this.useImagesLoaded && imagesLoaded === undefined) {
imagesLoaded = require('imagesloaded');
}
if (isPlatformBrowser(this.platformId) && masonryConstructor === undefined) {
masonryConstructor = require('masonry-layout');
}
// Create masonry options object
if (!this.options) {
this.options = {};
}
// Set default itemSelector
if (!this.options.itemSelector) {
this.options.itemSelector = '[ngmMasonryItem], ngmMasonryItem';
}
if (isPlatformBrowser(this.platformId)) {
// Initialize Masonry
this._msnry = new masonryConstructor(this.element.nativeElement, this.options);
// Bind to events
this._msnry.on('layoutComplete', (items) => {
this.layoutComplete.emit(items);
this.changeDetectorRef.markForCheck();
});
this._msnry.on('removeComplete', (items) => {
this.removeComplete.emit(items);
this.changeDetectorRef.markForCheck();
});
}
});
}
/**
* @param {?} changes
* @return {?}
*/
ngOnChanges(changes) {
// only update layout if it's not the first change
if (changes.updateLayout) {
if (!changes.updateLayout.firstChange) {
this.layout();
}
}
}
/**
* @return {?}
*/
ngOnDestroy() {
if (this._msnry) {
this._msnry.destroy();
}
}
/**
* @return {?}
*/
layout() {
requestAnimationFrame(() => {
this._msnry.layout();
this.changeDetectorRef.markForCheck();
});
}
/**
* @return {?}
*/
reloadItems() {
requestAnimationFrame(() => {
this._msnry.reloadItems();
this.changeDetectorRef.markForCheck();
});
}
// public add(element: HTMLElement, prepend: boolean = false) {
/**
* @param {?} element
* @return {?}
*/
add(element) {
this.ngZone.runOutsideAngular(() => {
/** @type {?} */
let isFirstItem = false;
// Check if first item
if (this._msnry.items.length === 0) {
isFirstItem = true;
}
if (this.useImagesLoaded) {
imagesLoaded(element, (instance) => {
this.element.nativeElement.appendChild(element);
// Tell Masonry that a child element has been added
setTimeout(() => {
this._msnry.appended(element);
this.changeDetectorRef.markForCheck();
});
// layout if first item
if (isFirstItem) {
this.layout();
}
});
this.element.nativeElement.removeChild(element);
}
else {
// Tell Masonry that a child element has been added
setTimeout(() => {
this._msnry.appended(element);
this.changeDetectorRef.markForCheck();
});
// layout if first item
if (isFirstItem) {
this.layout();
}
}
});
}
/**
* @param {?} element
* @return {?}
*/
remove(element) {
// Tell Masonry that a child element has been removed
this._msnry.remove(element);
// Layout items
this.layout();
}
}
NgmMasonryComponent.decorators = [
{ type: Component, args: [{
selector: '[ngm-masonry], ngm-masonry',
template: '<ng-content></ng-content>',
changeDetection: ChangeDetectionStrategy.OnPush,
styles: [`
:host {
display: block;
}
`]
}] }
];
/** @nocollapse */
NgmMasonryComponent.ctorParameters = () => [
{ type: undefined, decorators: [{ type: Inject, args: [PLATFORM_ID,] }] },
{ type: ElementRef },
{ type: NgZone },
{ type: ChangeDetectorRef }
];
NgmMasonryComponent.propDecorators = {
options: [{ type: Input }],
useImagesLoaded: [{ type: Input }],
updateLayout: [{ type: Input }],
layoutComplete: [{ type: Output }],
removeComplete: [{ type: Output }]
};
/**
* @fileoverview added by tsickle
* @suppress {checkTypes,extraRequire,missingReturn,unusedPrivateMembers,uselessCode} checked by tsc
*/
class NgmMasonryDirective {
/**
* @param {?} _element
* @param {?} _parent
* @param {?} platformId
*/
constructor(_element, _parent, platformId) {
this._element = _element;
this._parent = _parent;
this.platformId = platformId;
}
/**
* @return {?}
*/
ngAfterViewInit() {
if (isPlatformBrowser(this.platformId)) {
this._parent.add(this._element.nativeElement);
this.watchForHtmlChanges();
}
}
/**
* @return {?}
*/
ngOnDestroy() {
if (isPlatformBrowser(this.platformId)) {
this._parent.remove(this._element.nativeElement);
if (!!this._observer) {
this._observer.disconnect();
}
}
}
/**
* When HTML in brick changes dynamically, observe that and change layout
* @private
* @return {?}
*/
watchForHtmlChanges() {
MutationObserver = window.MutationObserver || window.WebKitMutationObserver;
if (MutationObserver) {
this._observer = new MutationObserver(() => {
requestAnimationFrame(() => {
this._parent.layout();
});
});
}
if (!!this._observer) {
// define what element should be observed by the observer
// and what types of mutations trigger the callback
this._observer.observe(this._element.nativeElement, {
subtree: true,
childList: true,
attributes: true,
attributeFilter: ['src'],
});
}
}
}
NgmMasonryDirective.decorators = [
{ type: Directive, args: [{
selector: '[ngmMasonryItem], ngmMasonryItem',
},] }
];
/** @nocollapse */
NgmMasonryDirective.ctorParameters = () => [
{ type: ElementRef },
{ type: NgmMasonryComponent, decorators: [{ type: Inject, args: [forwardRef(() => NgmMasonryComponent),] }] },
{ type: undefined, decorators: [{ type: Inject, args: [PLATFORM_ID,] }] }
];
/**
* @fileoverview added by tsickle
* @suppress {checkTypes,extraRequire,missingReturn,unusedPrivateMembers,uselessCode} checked by tsc
*/
/**
* @fileoverview added by tsickle
* @suppress {checkTypes,extraRequire,missingReturn,unusedPrivateMembers,uselessCode} checked by tsc
*/
class NgmMasonryModule {
}
NgmMasonryModule.decorators = [
{ type: NgModule, args: [{
imports: [],
declarations: [NgmMasonryComponent, NgmMasonryDirective],
exports: [NgmMasonryComponent, NgmMasonryDirective],
},] }
];
/**
* @fileoverview added by tsickle
* @suppress {checkTypes,extraRequire,missingReturn,unusedPrivateMembers,uselessCode} checked by tsc
*/
/**
* @fileoverview added by tsickle
* @suppress {checkTypes,extraRequire,missingReturn,unusedPrivateMembers,uselessCode} checked by tsc
*/
export { NgmMasonryComponent, NgmMasonryDirective, NgmMasonryModule };
//# sourceMappingURL=ngm-masonry.js.map