Skip to content
This repository has been archived by the owner on Sep 5, 2024. It is now read-only.

Commit

Permalink
fix(layout, flexbox): longhand workarounds, flex-order, interpolated …
Browse files Browse the repository at this point in the history
…values

* apply flexbox workarounds per [Flexbox Workarounds](https:/philipwalton/flexbugs#3-min-height-on-a-flex-container-wont-apply-to-its-flex-items): use flex longhand notations with workarounds
  *  add support for flex="1", flex="auto", and flex
  *  add references to online specs/resources
  *  fix flex-33 and flex-67 max-width and max-heights
  *  fix layout-align to use max-width
* layout-fill should use height:100%
* allow flex-order to be negative
* add support to observe interpolated layout values.
*  restore max-width for layouts
  *  restore `layout > flex` specifiers of max-width or max-height.
  * publish `$$mdLayout` service to allow Attribute selectors to be removed when the translation inject to Class selector finishes.

According to CSS Flexible Box Layout Module Level 1 and CSS Values and Units Module Level 3, the order property can be negative, -9 to -1, as well as positive, 1 to 9, and zero.

Fixes #4729. Fixes #4616. Fixes #4520. Fixes #4482. Close #3376. Closes #4592.

> Thx @flowersinthesand for original PR
  • Loading branch information
ThomasBurleson committed Sep 22, 2015
1 parent bf77109 commit 7264cab
Show file tree
Hide file tree
Showing 3 changed files with 149 additions and 79 deletions.
143 changes: 80 additions & 63 deletions src/core/services/layout/layout.js
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
(function () {
'use strict';

var _$$mdLayout, _$parse;
var $$mdLayout, $parse, $interpolate;

/**
*
Expand Down Expand Up @@ -69,20 +69,16 @@
.directive('layout' , attributeWithObserve('layout' , true) )
.directive('layoutSm' , attributeWithObserve('layout-sm' , true) )
.directive('layoutGtSm' , attributeWithObserve('layout-gt-sm', true) )
.directive('layoutLtMd' , warnAttrNotSupported('layout-lt-md',true) )
.directive('layoutMd' , attributeWithObserve('layout-md' , true) )
.directive('layoutGtMd' , attributeWithObserve('layout-gt-md', true) )
.directive('layoutLtLg' , warnAttrNotSupported('layout-lt-lg',true) )
.directive('layoutLg' , attributeWithObserve('layout-lg' , true) )
.directive('layoutGtLg' , attributeWithObserve('layout-gt-lg', true) )

.directive('flex' , attributeWithObserve('flex' , true) )
.directive('flexSm' , attributeWithObserve('flex-sm' , true) )
.directive('flexGtSm' , attributeWithObserve('flex-gt-sm' , true) )
.directive('flexLtMd' , warnAttrNotSupported('flex-lt-md' ,true) )
.directive('flexMd' , attributeWithObserve('flex-md' , true) )
.directive('flexGtMd' , attributeWithObserve('flex-gt-md' , true) )
.directive('flexLtLg' , warnAttrNotSupported('flex-lt-lg' ,true) )
.directive('flexLg' , attributeWithObserve('flex-lg' , true) )
.directive('flexGtLg' , attributeWithObserve('flex-gt-lg' , true) )

Expand All @@ -91,30 +87,24 @@
.directive('layoutAlign' , attributeWithObserve('layout-align') )
.directive('layoutAlignSm' , attributeWithObserve('layout-align-sm') )
.directive('layoutAlignGtSm' , attributeWithObserve('layout-align-gt-sm') )
.directive('layoutAlignLtMd' , warnAttrNotSupported('layout-align-lt-md') )
.directive('layoutAlignMd' , attributeWithObserve('layout-align-md') )
.directive('layoutAlignGtMd' , attributeWithObserve('layout-align-gt-md') )
.directive('layoutAlignLtLg' , warnAttrNotSupported('layout-align-lt-lg') )
.directive('layoutAlignLg' , attributeWithObserve('layout-align-lg') )
.directive('layoutAlignGtLg' , attributeWithObserve('layout-align-gt-lg') )

.directive('flexOrder' , attributeWithObserve('flex-order') )
.directive('flexOrderSm' , attributeWithObserve('flex-order-sm') )
.directive('flexOrderGtSm' , attributeWithObserve('flex-order-gt-sm') )
.directive('flexOrderLtMd' , warnAttrNotSupported('flex-order-lt-md') )
.directive('flexOrderMd' , attributeWithObserve('flex-order-md') )
.directive('flexOrderGtMd' , attributeWithObserve('flex-order-gt-md') )
.directive('flexOrderLtLg' , warnAttrNotSupported('flex-order-lt-lg') )
.directive('flexOrderLg' , attributeWithObserve('flex-order-lg') )
.directive('flexOrderGtLg' , attributeWithObserve('flex-order-gt-lg') )

.directive('offset' , attributeWithObserve('offset') )
.directive('offsetSm' , attributeWithObserve('offset-sm') )
.directive('offsetGtSm' , attributeWithObserve('offset-gt-sm') )
.directive('offsetLtMd' , warnAttrNotSupported('offset-lt-md') )
.directive('offsetMd' , attributeWithObserve('offset-md') )
.directive('offsetGtMd' , attributeWithObserve('offset-gt-md') )
.directive('offsetLtLg' , warnAttrNotSupported('offset-lt-lg') )
.directive('offsetLg' , attributeWithObserve('offset-lg') )
.directive('offsetGtLg' , attributeWithObserve('offset-gt-lg') )

Expand All @@ -128,21 +118,36 @@
.directive('hide' , attributeWithoutValue('hide') )
.directive('hideSm' , attributeWithoutValue('hide-sm') )
.directive('hideGtSm' , attributeWithoutValue('hide-gt-sm') )
.directive('hideLtMd' , warnAttrNotSupported ('hide-lt-md') )
.directive('hideMd' , attributeWithoutValue('hide-md') )
.directive('hideGtMd' , attributeWithoutValue('hide-gt-md') )
.directive('hideLtLg' , warnAttrNotSupported ('hide-lt-lg') )
.directive('hideLg' , attributeWithoutValue('hide-lg') )
.directive('hideGtLg' , attributeWithoutValue('hide-gt-lg') )
.directive('show' , attributeWithoutValue('show') )
.directive('showSm' , attributeWithoutValue('show-sm') )
.directive('showGtSm' , attributeWithoutValue('show-gt-sm') )
.directive('showLtMd' , warnAttrNotSupported ('show-lt-md') )
.directive('showMd' , attributeWithoutValue('show-md') )
.directive('showGtMd' , attributeWithoutValue('show-gt-md') )
.directive('showLtLg' , warnAttrNotSupported ('show-lt-lg') )
.directive('showLg' , attributeWithoutValue('show-lg') )
.directive('showGtLg' , attributeWithoutValue('show-gt-lg') );
.directive('showGtLg' , attributeWithoutValue('show-gt-lg') )

// !! Deprecated attributes: use the `-lt` (aka less-than) notations

.directive('layoutLtMd' , warnAttrNotSupported('layout-lt-md',true) )
.directive('layoutLtLg' , warnAttrNotSupported('layout-lt-lg',true) )
.directive('flexLtMd' , warnAttrNotSupported('flex-lt-md' ,true) )
.directive('flexLtLg' , warnAttrNotSupported('flex-lt-lg' ,true) )

.directive('layoutAlignLtMd' , warnAttrNotSupported('layout-align-lt-md') )
.directive('layoutAlignLtLg' , warnAttrNotSupported('layout-align-lt-lg') )
.directive('flexOrderLtMd' , warnAttrNotSupported('flex-order-lt-md') )
.directive('flexOrderLtLg' , warnAttrNotSupported('flex-order-lt-lg') )
.directive('offsetLtMd' , warnAttrNotSupported('offset-lt-md') )
.directive('offsetLtLg' , warnAttrNotSupported('offset-lt-lg') )

.directive('hideLtMd' , warnAttrNotSupported ('hide-lt-md') )
.directive('hideLtLg' , warnAttrNotSupported ('hide-lt-lg') )
.directive('showLtMd' , warnAttrNotSupported ('show-lt-md') )
.directive('showLtLg' , warnAttrNotSupported ('show-lt-lg') );

/**
* These functions create registration functions for ngMaterial Layout attribute directives
Expand All @@ -158,9 +163,11 @@
* @param {boolean=} addDirectiveAsClass
*/
function attributeWithObserve(className, addDirectiveAsClass) {
return ['$$mdLayout', '$document', '$parse', function($$mdLayout, $document, $parse) {
_$$mdLayout = $$mdLayout;
_$parse = $parse;

return ['$$mdLayout', '$document', '$parse', '$interpolate', function(_$$mdLayout_, $document, _$parse_, _$interpolate_) {
$$mdLayout = _$$mdLayout_;
$parse = _$parse_;
$interpolate = _$interpolate_;

return {
restrict : 'A',
Expand All @@ -176,69 +183,76 @@
}];



/**
* Add as transformed class selector(s), then
* remove the deprecated attribute selector
*/
function attributeValueToClass(scope, element, attr) {
var directive = attr.$normalize(className);
var attrExpression = _$parse( directive[directive] );
function attributeValueToClass(scope, element, attrs) {
var updateClassFn = updateClassWithValue(element,className, attrs);
var normalizedAttr = attrs.$normalize(className);
var attrValue = attrs[normalizedAttr] ? attrs[normalizedAttr].replace(/\s+/g, "-") : null;
var addImmediate = attrValue ? !needsInterpolation(attrValue) : false;
var watchValue = needsInterpolation(attrValue);

// Add transformed class selector(s)
if (addDirectiveAsClass) {
element.addClass(className);
}

if ( attr[directive] ) {
element.addClass(className + "-" + attr[directive].replace(/\s+/g, "-"));

if ( _$$mdLayout.removeAttributes ) {
element.removeAttr(directive);
}
}
if (addDirectiveAsClass) element.addClass(className);

if ( scope ) {
/**
* After link-phase, do NOT remove deprecated layout attribute selector.
* Instead watch the attribute so interpolated data-bindings to layout
* selectors will continue to be supported.
*
* $observe() the className and update with new class (after removing the last one)
*
* e.g. `layout="{{layoutDemo.direction}}"` will update...
*/
var lastClass;

attr.$observe(function() {

return attrExpression(scope);
if ( addImmediate ) element.addClass(className + "-" + attrValue);
if ( watchValue ) attrs.$observe( normalizedAttr, updateClassFn );
if ( $$mdLayout.removeAttributes ) element.removeAttr(className);
}

}, function(newVal) {
}

element.removeClass(lastClass);
/**
* See if the original value has interpolation symbols:
* e.g. flex-gt-md="{{triggerPoint}}"
*/
function needsInterpolation(value) {
return (value ||"").indexOf($interpolate.startSymbol()) > -1;
}

lastClass = className + "-" + String(newVal).replace(/\s+/g, "-");
/**
* After link-phase, do NOT remove deprecated layout attribute selector.
* Instead watch the attribute so interpolated data-bindings to layout
* selectors will continue to be supported.
*
* $observe() the className and update with new class (after removing the last one)
*
* e.g. `layout="{{layoutDemo.direction}}"` will update...
*
* NOTE: The value must match one of the specified styles in the CSS.
* For example `flex-gt-md="{{size}}` where `scope.size == 47` will NOT work since
* only breakpoints for 0, 5, 10, 15... 100, 33, 34, 66, 67 are defined.
*
*/
function updateClassWithValue(element, className, attr) {
var lastClass;

element.addClass(lastClass);
return function updateClassWithValue(newValue) {
var value = String(newValue || "").replace(/\s+/g, "-");

});
element.removeClass(lastClass);
lastClass = !value ? className : className + "-" + value;
element.addClass(lastClass);

}
// Conditionally remove the attribute selector in case the browser attempts to
// read it and suffers a performance downgrade (IE).

}
if ( $$mdLayout.removeAttributes ) element.removeAttr(className);
};
}

/**
* Creates a registration function with for ngMaterial Layout attribute directive.
* This is a `simple` transpose of attribute usage to class usage
*/
function attributeWithoutValue(className) {
return ['$$mdLayout', '$document', function($$mdLayout, $document) {
_$$mdLayout = $$mdLayout;
return ['$$mdLayout', '$document', function(_$$mdLayout_, $document) {
$$mdLayout = _$$mdLayout_;
return {
restrict : 'A',
compile: function(element, attr) {
compile: function(element, attrs) {
if ( postLinkIsDisabled($document[0]) ) return angular.noop;

attributeToClass(null, element);
Expand All @@ -256,7 +270,7 @@
function attributeToClass(scope, element) {
element.addClass(className);

if ( scope && _$$mdLayout.removeAttributes ) {
if ( $$mdLayout.removeAttributes ) {
// After link-phase, remove deprecated layout attribute selector
element.removeAttr(className);
}
Expand Down Expand Up @@ -289,10 +303,13 @@
* }
*
* Note: this means that 'md-css-only' will not work for IE (due to performance issues)
* In these cases, the Layout translators (directives) should be enabled.
* In these cases, the Layout translators (directives) should be enabled and the
* `angular-material.[min.]js` must be loaded.
*/
function postLinkIsDisabled(document) {
var disablePostLinks = _$$mdLayout.disablePostLinks;
var disablePostLinks = $$mdLayout.disablePostLinks;

// Perform a read-once (1x) check for the `md-css-only` class on the BODY

if ( angular.isUndefined(disablePostLinks) ) {
var body = document.querySelectorAll("body")[0];
Expand All @@ -301,7 +318,7 @@
disablePostLinks = styles ? (styles.indexOf('md-css-only') > -1) : false;
}

return _$$mdLayout.disablePostLinks = disablePostLinks;
return $$mdLayout.disablePostLinks = disablePostLinks;
}

})();
53 changes: 39 additions & 14 deletions src/core/services/layout/layout.scss
Original file line number Diff line number Diff line change
@@ -1,4 +1,10 @@
// Responsive attributes
//
// References:
// 1) https://scotch.io/tutorials/a-visual-guide-to-css3-flexbox-properties#flex
// 2) https://css-tricks.com/almanac/properties/f/flex/
// 3) https:/philipwalton/flexbugs#3-min-height-on-a-flex-container-wont-apply-to-its-flex-items
//
// ------------------------------

// hide means hide everywhere
Expand Down Expand Up @@ -94,8 +100,9 @@

.layout-fill, .md-css-only [layout-fill] {
margin: 0;
min-height: 100%;
width: 100%;
min-height: 100%;
height: 100%;
}
@-moz-document url-prefix() {
.layout-fill, .md-css-only [layout-fill] {
Expand All @@ -111,16 +118,12 @@
@if $suffix != null {
$selector: 'flex-order-#{$suffix}';
}
.md-css-only [#{$selector}="0"] { order: 0; }
.md-css-only [#{$selector}="1"] { order: 1; }
.md-css-only [#{$selector}="2"] { order: 2; }
.md-css-only [#{$selector}="3"] { order: 3; }
.md-css-only [#{$selector}="4"] { order: 4; }
.md-css-only [#{$selector}="5"] { order: 5; }
.md-css-only [#{$selector}="6"] { order: 6; }
.md-css-only [#{$selector}="7"] { order: 7; }
.md-css-only [#{$selector}="8"] { order: 8; }
.md-css-only [#{$selector}="9"] { order: 9; }

@for $i from -9 through 9 {
.#{$selector}-#{$i}, .md-css-only .#{$selector}-#{$i} {
order: #{$i};
}
}
}

@mixin layout-for-name($name) {
Expand Down Expand Up @@ -178,10 +181,28 @@
box-sizing: border-box;
flex: 1;
}

@if ( $name == 'flex' ) {
.flex, .md-css-only [flex=""],
.flex-initial, .md-css-only [flex="initial"] {
box-sizing: border-box;
flex: 0 1 auto;
}


// (0-20) * 5 = 0-100%
@for $i from 0 through 20 {
.flex-1, .md-css-only [flex="1"] {
box-sizing: border-box;
flex: 1 1 0%;
}

.flex-auto, .md-css-only [flex="auto"] {
box-sizing: border-box;
flex: 1 1 auto;
}
}

// (1-20) * 5 = 0-100%
@for $i from 1 through 20 {
.#{$flexName}-#{$i * 5},
.md-css-only [#{$flexName}="#{$i * 5}"]
{
Expand All @@ -203,11 +224,13 @@
.#{$flexName}-33, .#{$flexName}-34
{
flex: 0 0 33%;
max-width: 33%;
}

.#{$flexName}-66, .#{$flexName}-67
{
flex: 0 0 67%;
max-width: 67%;

}

Expand All @@ -217,7 +240,7 @@
}
.layout-column, .md-css-only [layout="column"] {
> .#{$flexName}-33, > .#{$flexName}-34 { max-height: 33%; }
> .#{$flexName}-66, > .#{$flexName}-67 { max-height: 33%; }
> .#{$flexName}-66, > .#{$flexName}-67 { max-height: 67%; }
}
}

Expand Down Expand Up @@ -319,6 +342,8 @@
.md-css-only [#{$name}="space-around center"]
{
align-items: center;
max-width: 100%;

}

// Cross Axis End
Expand Down
Loading

0 comments on commit 7264cab

Please sign in to comment.