|
1 |
| -import {Component} from '@angular/core'; |
| 1 | +import { |
| 2 | + Component, |
| 3 | + ViewEncapsulation, |
| 4 | + AfterContentChecked, |
| 5 | + OnInit, |
| 6 | + Input, |
| 7 | + ContentChildren, |
| 8 | + QueryList, |
| 9 | + Renderer, |
| 10 | + ElementRef |
| 11 | +} from '@angular/core'; |
| 12 | +import {MdGridTile} from './grid-tile'; |
| 13 | +import {TileCoordinator} from './tile-coordinator'; |
| 14 | +import { |
| 15 | + TileStyler, |
| 16 | + FitTileStyler, |
| 17 | + RatioTileStyler, |
| 18 | + FixedTileStyler |
| 19 | +} from './tile-styler'; |
| 20 | +import {MdGridListColsError} from './grid-list-errors'; |
| 21 | +import {Dir} from '../../core/rtl/dir'; |
| 22 | + |
| 23 | +// TODO(kara): Conditional (responsive) column count / row size. |
| 24 | +// TODO(kara): Re-layout on window resize / media change (debounced). |
| 25 | +// TODO(kara): gridTileHeader and gridTileFooter. |
| 26 | + |
| 27 | +const MD_FIT_MODE = 'fit'; |
2 | 28 |
|
3 | 29 | @Component({
|
4 | 30 | selector: 'md-grid-list',
|
| 31 | + host: { 'role': 'list' }, |
5 | 32 | templateUrl: './components/grid-list/grid-list.html',
|
6 | 33 | styleUrls: ['./components/grid-list/grid-list.css'],
|
| 34 | + encapsulation: ViewEncapsulation.None, |
7 | 35 | })
|
8 |
| -export class MdGridList {} |
| 36 | +export class MdGridList implements OnInit, AfterContentChecked { |
| 37 | + /** Number of columns being rendered. */ |
| 38 | + _cols: number; |
| 39 | + |
| 40 | + /** Row height value passed in by user. This can be one of three types: |
| 41 | + * - Number value (ex: "100px"): sets a fixed row height to that value |
| 42 | + * - Ratio value (ex: "4:3"): sets the row height based on width:height ratio |
| 43 | + * - "Fit" mode (ex: "fit"): sets the row height to total height divided by number of rows |
| 44 | + * */ |
| 45 | + _rowHeight: string; |
| 46 | + |
| 47 | + /** The amount of space between tiles. This will be something like '5px' or '2em'. */ |
| 48 | + _gutter: string = '1px'; |
| 49 | + |
| 50 | + /** Sets position and size styles for a tile */ |
| 51 | + _tileStyler: TileStyler; |
| 52 | + |
| 53 | + /** Query list of tiles that are being rendered. */ |
| 54 | + @ContentChildren(MdGridTile) _tiles: QueryList<MdGridTile>; |
| 55 | + |
| 56 | + constructor(private _renderer: Renderer, private _element: ElementRef, |
| 57 | + private _dir: Dir) {} |
| 58 | + |
| 59 | + @Input() |
| 60 | + get cols() { |
| 61 | + return this._cols; |
| 62 | + } |
| 63 | + |
| 64 | + set cols(value: any) { |
| 65 | + this._cols = coerceToNumber(value); |
| 66 | + } |
| 67 | + |
| 68 | + @Input('gutterSize') |
| 69 | + get gutterSize() { |
| 70 | + return this._gutter; |
| 71 | + } |
| 72 | + |
| 73 | + set gutterSize(value: any) { |
| 74 | + this._gutter = coerceToString(value); |
| 75 | + } |
| 76 | + |
| 77 | + /** Set internal representation of row height from the user-provided value. */ |
| 78 | + @Input() |
| 79 | + set rowHeight(value: string | number) { |
| 80 | + this._rowHeight = coerceToString(value); |
| 81 | + this._setTileStyler(); |
| 82 | + } |
| 83 | + |
| 84 | + ngOnInit() { |
| 85 | + this._checkCols(); |
| 86 | + this._checkRowHeight(); |
| 87 | + } |
| 88 | + |
| 89 | + /** The layout calculation is fairly cheap if nothing changes, so there's little cost |
| 90 | + * to run it frequently. */ |
| 91 | + ngAfterContentChecked() { |
| 92 | + this._layoutTiles(); |
| 93 | + } |
| 94 | + |
| 95 | + /** Throw a friendly error if cols property is missing */ |
| 96 | + private _checkCols() { |
| 97 | + if (!this.cols) { |
| 98 | + throw new MdGridListColsError(); |
| 99 | + } |
| 100 | + } |
| 101 | + |
| 102 | + /** Default to equal width:height if rowHeight property is missing */ |
| 103 | + private _checkRowHeight(): void { |
| 104 | + if (!this._rowHeight) { |
| 105 | + this._tileStyler = new RatioTileStyler('1:1'); |
| 106 | + } |
| 107 | + } |
| 108 | + |
| 109 | + /** Creates correct Tile Styler subtype based on rowHeight passed in by user */ |
| 110 | + private _setTileStyler(): void { |
| 111 | + if (this._rowHeight === MD_FIT_MODE) { |
| 112 | + this._tileStyler = new FitTileStyler(); |
| 113 | + } else if (this._rowHeight && this._rowHeight.match(/:/g)) { |
| 114 | + this._tileStyler = new RatioTileStyler(this._rowHeight); |
| 115 | + } else { |
| 116 | + this._tileStyler = new FixedTileStyler(this._rowHeight); |
| 117 | + } |
| 118 | + } |
| 119 | + |
| 120 | + /** Computes and applies the size and position for all children grid tiles. */ |
| 121 | + private _layoutTiles(): void { |
| 122 | + let tiles = this._tiles.toArray(); |
| 123 | + let tracker = new TileCoordinator(this.cols, tiles); |
| 124 | + this._tileStyler.init(this.gutterSize, tracker, this.cols, this._dir); |
| 125 | + |
| 126 | + for (let i = 0; i < tiles.length; i++) { |
| 127 | + let pos = tracker.positions[i]; |
| 128 | + let tile = tiles[i]; |
| 129 | + this._tileStyler.setStyle(tile, pos.row, pos.col); |
| 130 | + } |
| 131 | + this.setListStyle(this._tileStyler.getComputedHeight()); |
| 132 | + } |
| 133 | + |
| 134 | + /** Sets style on the main grid-list element, given the style name and value. |
| 135 | + * @internal |
| 136 | + */ |
| 137 | + setListStyle(style: [string, string]): void { |
| 138 | + if (style) { |
| 139 | + this._renderer.setElementStyle(this._element.nativeElement, style[0], style[1]); |
| 140 | + } |
| 141 | + } |
| 142 | +} |
| 143 | + |
| 144 | +/** Converts values into strings. Falsy values become empty strings. |
| 145 | + * @internal |
| 146 | + */ |
| 147 | +export function coerceToString(value: string | number): string { |
| 148 | + return `${value || ''}`; |
| 149 | +} |
| 150 | + |
| 151 | +/** Converts a value that might be a string into a number. |
| 152 | + * @internal |
| 153 | + */ |
| 154 | +export function coerceToNumber(value: string | number): number { |
| 155 | + return typeof value === 'string' ? parseInt(value, 10) : value; |
| 156 | +} |
| 157 | + |
| 158 | +export const MD_GRID_LIST_DIRECTIVES: any[] = [MdGridList, MdGridTile]; |
0 commit comments