Skip to content
This repository has been archived by the owner on Jan 6, 2025. It is now read-only.

Commit

Permalink
fix(fxFlex): improve support of flex-basis variations
Browse files Browse the repository at this point in the history
* improve support for fxFlex options and parsing
* add calc() auto-corrections for bad whitespacing
* add basis-validator tools
  • Loading branch information
ThomasBurleson committed Mar 8, 2017
1 parent cc2fd11 commit b82839e
Show file tree
Hide file tree
Showing 4 changed files with 127 additions and 36 deletions.
6 changes: 4 additions & 2 deletions src/lib/flexbox/api/flex.spec.ts
Original file line number Diff line number Diff line change
Expand Up @@ -119,9 +119,11 @@ describe('flex directive', () => {
});

it('should work with calc without internal whitespaces', async(() => {
let fRef = componentWithTemplate('<div fxFlex="calc(75%-10px)"></div>');
fRef.detectChanges();
// @see http://caniuse.com/#feat=calc for IE issues with calc()
if (!isIE) {
let fRef = componentWithTemplate('<div fxFlex="calc(75%-10px)"></div>');
fRef.detectChanges();

setTimeout(() => {
expectNativeEl(fRef).toHaveCssStyle({
'box-sizing': 'border-box',
Expand Down
38 changes: 4 additions & 34 deletions src/lib/flexbox/api/flex.ts
Original file line number Diff line number Diff line change
Expand Up @@ -26,6 +26,7 @@ import {MediaMonitor} from '../../media-query/media-monitor';

import {LayoutDirective} from './layout';
import {LayoutWrapDirective} from './layout-wrap';
import {validateBasis} from '../../utils/basis-validator';


/** Built-in aliases for different flex-basis values. */
Expand Down Expand Up @@ -178,40 +179,9 @@ export class FlexDirective extends BaseFxDirective implements OnInit, OnChanges,
flexBasis = this._mqActivation.activatedInput;
}

this._applyStyleToElement(this._validateValue.apply(this,
this._parseFlexParts(String(flexBasis))));
}

/**
* If the used the short-form `fxFlex="1 0 37%"`, then parse the parts
*/
protected _parseFlexParts(basis: string) {
basis = basis.replace(";", "");

let hasCalc = basis && basis.indexOf("calc") > -1;
let matches = !hasCalc ? basis.split(" ") : this._getPartsWithCalc(basis.trim());
return (matches.length === 3) ? matches : [this._queryInput("grow"),
this._queryInput("shrink"), basis];
}

/**
* Extract more complicated short-hand versions.
* e.g.
* fxFlex="3 3 calc(15em + 20px)"
*/
protected _getPartsWithCalc(value: string) {
let parts = [this._queryInput("grow"), this._queryInput("shrink"), value];
let j = value.indexOf('calc');

if (j > 0) {
parts[2] = value.substring(j);
let matches = value.substr(0, j).trim().split(" ");
if (matches.length == 2) {
parts[0] = matches[0];
parts[1] = matches[1];
}
}
return parts;
let basis = String(flexBasis).replace(";", "");
let parts = validateBasis(basis, this._queryInput("grow"), this._queryInput("shrink"));
this._applyStyleToElement(this._validateValue.apply(this, parts));
}

/**
Expand Down
67 changes: 67 additions & 0 deletions src/lib/utils/basis-validator.spec.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,67 @@
/**
* @license
* Copyright Google Inc. All Rights Reserved.
*
* 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 {validateBasis} from './basis-validator';


describe('validateBasis', () => {

it('should validate single-value basis with default grow/shrink', () => {
let result = validateBasis('37px').join(" ");
expect( result ).toEqual('1 1 37px');
});

it('should validate single-value basis with custom grow and shrink', () => {
let result = validateBasis('37px', "2", "13").join(" ");
expect( result ).toEqual('2 13 37px');
});

it('should validate full `flex` value `2 1 37%`', () => {
let result = validateBasis('2 1 37%').join(" ");
expect( result ).toEqual('2 1 37%');
});

it('should validate with complex value that includes calc()', () => {
let result = validateBasis('3 3 calc(15em + 20px)').join(" ");
expect( result ).toEqual('3 3 calc(15em + 20px)');
});

it('should validate with complex value that includes a bad calc() expression', () => {
let result = validateBasis('3 3 calc(15em +20px)').join(" ");
expect( result ).toEqual('3 3 calc(15em + 20px)');
});

it('should validate with complex value that includes ONLY calc()', () => {
let result = validateBasis('calc(15em + 20px)').join(" ");
expect( result ).toEqual('1 1 calc(15em + 20px)');
});

it('should validate with good calc(x + x) expression()', () => {
let result = validateBasis('calc(15em + 20px)').join(" ");
expect( result ).toEqual('1 1 calc(15em + 20px)');
});

it('should validate with bad calc(x+x) expression()', () => {
let result = validateBasis('calc(15em+20px)').join(" ");
expect( result ).toEqual('1 1 calc(15em + 20px)');
});

it('should validate with bad calc(x-x) expression()', () => {
let result = validateBasis('calc(15em-20px)').join(" ");
expect( result ).toEqual('1 1 calc(15em - 20px)');
});

it('should validate with bad calc(x*x) expression()', () => {
let result = validateBasis('calc(15em*20px)').join(" ");
expect( result ).toEqual('1 1 calc(15em * 20px)');
});

it('should validate with bad calc(x/x) expression()', () => {
let result = validateBasis('calc(15em/20px)').join(" ");
expect( result ).toEqual('1 1 calc(15em / 20px)');
});
});
52 changes: 52 additions & 0 deletions src/lib/utils/basis-validator.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,52 @@
/**
* The flex API permits 3 or 1 parts of the value:
* - `flex-grow flex-shrink flex-basis`, or
* - `flex-basis`
* Flex-Basis values can be complicated short-hand versions such as:
* - "3 3 calc(15em + 20px)"
* - "calc(15em + 20px)"
* - "calc(15em+20px)"
* - "37px"
* = "43%"
*/
export function validateBasis(basis: string, grow = "1", shrink = "1"): string[] {
let parts = [grow, shrink, basis];

let j = basis.indexOf('calc');
if (j > 0) {
parts[2] = _validateCalcValue(basis.substring(j).trim());
let matches = basis.substr(0, j).trim().split(" ");
if (matches.length == 2) {
parts[0] = matches[0];
parts[1] = matches[1];
}
} else if (j == 0) {
parts[2] = _validateCalcValue(basis.trim());
} else {
let matches = basis.split(" ");
parts = (matches.length === 3) ? matches : [
grow, shrink, basis
];
}

return parts;
}


/**
* Calc expressions require whitespace before & after the operator
* This is a simple, crude whitespace padding solution.
*/
function _validateCalcValue(calc: string): string {
let operators = ["+", "-", "*", "/"];
let findOperator = () => operators.reduce((index, operator) => {
return index || (calc.indexOf(operator) + 1);
}, 0);

if (findOperator() > 0) {
calc = calc.replace(/[\s]/g, "");
let offset = findOperator() - 1;
calc = calc.substr(0, offset) + " " + calc.charAt(offset) + " " + calc.substr(offset + 1);
}
return calc;
}

0 comments on commit b82839e

Please sign in to comment.