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

Commit

Permalink
Merge pull request #18 from jbroquist/master
Browse files Browse the repository at this point in the history
Added min/max-size options
  • Loading branch information
douglasduteil committed Jul 7, 2014
2 parents 32f95da + 1742f9f commit c281bde
Show file tree
Hide file tree
Showing 4 changed files with 315 additions and 12 deletions.
43 changes: 40 additions & 3 deletions README.md
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
# UI.Layout directive [![Build Status](https://travis-ci.org/angular-ui/ui-layout.png)](https://travis-ci.org/angular-ui/ui-layout)

This directive allows you to split stuff !
This directive allows you to split stuff !
[Holy grail demo](http://plnkr.co/k74rGs)

## Requirements
Expand Down Expand Up @@ -48,12 +48,49 @@ or

### flow

Type: `String`
Default: `'row'`
Type: `String`
Default: `'row'`
`flow: row | column`

A fake [flex-direction property](http://www.w3.org/TR/css3-flexbox/#flex-direction). It specifies how the child elements are placed in the layout container, by setting the direction of the flex container's main axis. This determines the direction that child elements are laid out in.

## Child Attributes

### minSize

Type: `String`
Default: `'8px'`

Specifices the minimum size the child element can be set to. Defaults to the width of the `splitbar` if no value is provided.

```pixels
<div ui-layout>
<div min-size="100px"></div>
</div>
percentage
<div ui-layout>
<div min-size="10%"></div>
</div>
```

### maxSize

Type: `String`

Specifices the maxium size the child element can be set to.

```pixels
<div ui-layout>
<div max-size="100px"></div>
</div>
percentage
<div ui-layout>
<div max-size="10%"></div>
</div>
```

## Testing

We use Karma and jshint to ensure the quality of the code. The easiest way to run these checks is to use grunt:
Expand Down
45 changes: 45 additions & 0 deletions demo/minmax.html
Original file line number Diff line number Diff line change
@@ -0,0 +1,45 @@
<!DOCTYPE html>
<html ng-app="x">
<head>
<meta charset="utf-8" />
<meta name="viewport" content="width=device-width">


<base href="../"/>
<title>UI.Layout : Min/Max Demo</title>

<!-- Le css -->
<link href="//netdna.bootstrapcdn.com/bootstrap/3.1.1/css/bootstrap.min.css" rel="stylesheet" type="text/css" />
<link rel="stylesheet" type="text/css" href="src/ui-layout.css"/>

<style type="text/css">
.testColumn:first-child {
background: green;
}
.testColumn:last-child {
background-color: red;
}
</style>
</head>
<body style="height: 50vh;">


<div ui-layout="{ flow:'column' }">
<div class="testColumn" min-size="5%" max-size="10%"></div>
<div class="testColumn"></div>
<div class="testColumn" min-size="10%" max-size="50%"></div>
<div class="testColumn"></div>
</div>

<!-- Le javascript -->
<script type="application/javascript" src="../bower_components/angular/angular.min.js"></script>
<script type="application/javascript" src="src/ui-layout.js"></script>
<script type="application/javascript">

angular.module('x', ['ui.layout']);

</script>


</body>
</html>
144 changes: 135 additions & 9 deletions src/ui-layout.js
Original file line number Diff line number Diff line change
Expand Up @@ -17,12 +17,37 @@ angular.module('ui.layout', [])

var splitBarElem_htmlTemplate = '<div class="stretch ui-splitbar"></div>';

function convertNumericDataTypesToPencents(numberVairousTypeArray, parentSize){
function convertNumericDataTypesToPencents(numberVairousTypeArray, minSizes, maxSizes, parentSize){
var _i, _n;
var _res = []; _res.length = numberVairousTypeArray.length;
var _commonSizeIndex = [];
var _minSizes = [];
var _maxSizes = [];
var _remainingSpace = 100;

for (_i = 0, _n = numberVairousTypeArray.length; _i < _n; ++_i) {
var minSize = parseInt(minSizes[_i], 10);
if(minSize) {
var minType = minSizes[_i].match(/\d+\s*(px|%)\s*$/i);
if(!isNaN(minSize) && minType) {
if(minType.length > 1 && 'px' === minType[1]) {
minSize = + (minSize / parentSize * 100).toFixed(5);
}
}
}
_minSizes.push(minSize);

var maxSize = parseInt(maxSizes[_i], 10);
if(maxSize) {
var maxType = maxSizes[_i].match(/\d+\s*(px|%)\s*$/i);
if(!isNaN(maxSize) && maxType) {
if(maxType.length > 1 && 'px' === maxType[1]) {
maxSize = + (maxSize / parentSize * 100).toFixed(5);
}
}
}
_maxSizes.push(maxSize);

var rawSize = numberVairousTypeArray[_i];
var value = parseInt(rawSize, 10);
// should only support pixels and pencent data type
Expand All @@ -31,9 +56,13 @@ angular.module('ui.layout', [])
if (type.length > 1 && 'px' === type[1]){
value = + (value / parentSize * 100).toFixed(5);
}

if(minSize) value = Math.max(value, minSize);
if(maxSize) value = Math.min(value, maxSize);

_res[_i] = value;
_remainingSpace -= value;
} else{
} else {
rawSize = 'auto';
}

Expand All @@ -42,12 +71,30 @@ angular.module('ui.layout', [])
}
}


if (_commonSizeIndex.length > 0){
var _commonSize = _remainingSpace / _commonSizeIndex.length ;
var _commonSize = _remainingSpace / _commonSizeIndex.length;
var _modifiedSizeIndex = [];
// Check to make sure the common size isn't outside the bounds of min/max-size
for (_i = 0, _n = _commonSizeIndex.length; _i < _n; ++_i) {
var cid = _commonSizeIndex[_i];
_res[cid] = _commonSize;
var _cid = _commonSizeIndex[_i];
var _minSize = _minSizes[_cid];
var _maxSize = _maxSizes[_cid];
if(_commonSize <= _minSize) {
_remainingSpace -= _minSize;
_res[_cid] = _minSize;
} else if(_commonSize >= _maxSize) {
_remainingSpace -= _maxSize;
_res[_cid] = _maxSize;
} else {
_modifiedSizeIndex.push(_cid);
}
}
_commonSize = _remainingSpace / _modifiedSizeIndex.length;
for (_i = 0, _n = _modifiedSizeIndex.length; _i < _n; ++_i) {
var cid = _modifiedSizeIndex[_i];
if(cid !== null) {
_res[cid] = _commonSize;
}
}
}

Expand Down Expand Up @@ -76,6 +123,10 @@ angular.module('ui.layout', [])

// Initial global size definition
opts.sizes = opts.sizes || [];
opts.maxSizes = opts.maxSizes || [];
opts.minSizes = opts.minSizes || [];
opts.dividerSize = opts.dividerSize || '10px';

// Preallocate the array size
opts.sizes.length = _child_len;

Expand All @@ -87,16 +138,18 @@ angular.module('ui.layout', [])
// - the global size on the layout option
// - 'auto' Fair separation of the remaining space
opts.sizes[_i] = angular.element(_childens[_i]).attr('size') || opts.sizes[_i] || 'auto';
opts.maxSizes[_i] = angular.element(_childens[_i]).attr('max-size') || opts.maxSizes[_i] || null;
opts.minSizes[_i] = angular.element(_childens[_i]).attr('min-size') || opts.minSizes[_i] || null;
}

// get the final percent sizes
_sizes = convertNumericDataTypesToPencents(opts.sizes, tElement[0]['offset' + (isUsingColumnFlow ? 'Width' : 'Height')]);
_sizes = convertNumericDataTypesToPencents(opts.sizes, opts.minSizes, opts.maxSizes, tElement[0]['offset' + (isUsingColumnFlow ? 'Width' : 'Height')]);

if (_child_len > 1) {
// Initialise the layout with equal sizes.

var flowProperty = ( isUsingColumnFlow ? 'left' : 'top');
var oppositeFlowProperty = ( isUsingColumnFlow ? 'right' : 'bottom');
var sizeProperty = ( isUsingColumnFlow ? 'width' : 'height');
_position = 0;
for (_i = 0; _i < _child_len; ++_i) {
var area = angular.element(_childens[_i])
Expand All @@ -108,6 +161,7 @@ angular.module('ui.layout', [])
if (_i < _child_len - 1) {
// Add a split bar
var bar = angular.element(splitBarElem_htmlTemplate).css(flowProperty, _position + '%');
bar.css(sizeProperty, opts.dividerSize);
area.after(bar);
}
}
Expand Down Expand Up @@ -143,7 +197,8 @@ angular.module('ui.layout', [])

// Use bounding box properties
var barElm = iElement[0];

var previousElement = barElm.previousElementSibling;
var nextElement = barElm.nextElementSibling;

// Stores the layout values for some seconds to not recalculate it during the animation
function _cached_layout_values() {
Expand All @@ -157,6 +212,65 @@ angular.module('ui.layout', [])
_cache.barSize = bar_bb[sizeProperty];
_cache.layoutSize = layout_bb[sizeProperty];
_cache.layoutOrigine = layout_bb[flowProperty];
_cache.previousElement = previousElement.getBoundingClientRect();
_cache.previousElement.min = parseInt(previousElement.getAttribute('min-size'),10);
_cache.previousElement.max = parseInt(previousElement.getAttribute('max-size'),10);
_cache.nextElement = nextElement.getBoundingClientRect();
_cache.nextElement.min = parseInt(nextElement.getAttribute('min-size'),10);
_cache.nextElement.max = parseInt(nextElement.getAttribute('max-size'),10);

var dividerSize = isNaN(bar_bb[sizeProperty]) ? bar_bb[sizeProperty] : bar_bb[sizeProperty] + 'px';
var _dividerSize = parseInt(dividerSize, 10);
var _dividerType = dividerSize.match(/\d+\s*(px|%)\s*$/i);
if(!isNaN(_dividerSize) && _dividerType) {
if(_dividerType.length > 1 && 'px' === _dividerType[1]) {
_dividerSize = + (_dividerSize / _cache.layoutSize * 100).toFixed(5);
}
}

if(_cache.previousElement.min) {
var minType = previousElement.getAttribute('min-size').match(/\d+\s*(px|%)\s*$/i);
if(!isNaN(_cache.previousElement.min) && minType) {
if(minType.length > 1 && 'px' === minType[1]) {
_cache.previousElement.min = + (_cache.previousElement.min / _cache.layoutSize * 100).toFixed(5);
}
}
// ensure the min size isn't smaller than the divider size
if(_dividerSize && _cache.previousElement.min < _dividerSize) _cache.previousElement.min = _dividerSize;
} else {
_cache.previousElement.min = _dividerSize;
}

if( _cache.previousElement.max) {
var maxType = previousElement.getAttribute('max-size').match(/\d+\s*(px|%)\s*$/i);
if(!isNaN( _cache.previousElement.max) && maxType) {
if(maxType.length > 1 && 'px' === maxType[1]) {
_cache.previousElement.max = + ( _cache.previousElement.max / _cache.layoutSize * 100).toFixed(5);
}
}
}

if(_cache.nextElement.min) {
var _minType = nextElement.getAttribute('min-size').match(/\d+\s*(px|%)\s*$/i);
if(!isNaN(_cache.nextElement.min) && _minType) {
if(_minType.length > 1 && 'px' === _minType[1]) {
_cache.nextElement.min = + (_cache.nextElement.min / _cache.layoutSize * 100).toFixed(5);
}
}
// ensure the min size isn't smaller than the divider size
if(_dividerSize && _cache.nextElement.min < _dividerSize) _cache.nextElement.min = _dividerSize;
} else {
_cache.nextElement.min = _dividerSize;
}

if(_cache.nextElement.max) {
var _maxType = nextElement.getAttribute('max-size').match(/\d+\s*(px|%)\s*$/i);
if(!isNaN(_cache.nextElement.max) && _maxType) {
if(_maxType.length > 1 && 'px' === _maxType[1]) {
_cache.nextElement.max = + (_cache.nextElement.max / _cache.layoutSize * 100).toFixed(5);
}
}
}
}

function _draw() {
Expand All @@ -165,6 +279,18 @@ angular.module('ui.layout', [])
// Keep the bar in the window (no left/top 100%)
the_pos = Math.min(the_pos, 100 - _cache.barSize / _cache.layoutSize * 100);

// Keep the bar from going past the previous elements max/min sizes
var previousElementValue = _cache.previousElement[flowProperty] / _cache.layoutSize * 100;
if(!isNaN(_cache.previousElement.min) && the_pos < (previousElementValue + _cache.previousElement.min)) the_pos = (previousElementValue + _cache.previousElement.min);
if(!isNaN(_cache.previousElement.max) && the_pos > (previousElementValue + _cache.previousElement.max)) the_pos = (previousElementValue + _cache.previousElement.max);

// Keep the bar from going past the next elements max/min sizes
var nextElementValue = (_cache.nextElement[flowProperty] + _cache.nextElement[sizeProperty]) / _cache.layoutSize * 100;
var nextElementMinValue = nextElementValue - _cache.nextElement.min;
var nextElementMaxValue = nextElementValue - _cache.nextElement.max;
if(!isNaN(_cache.nextElement.max) && the_pos < nextElementMaxValue) the_pos = nextElementMaxValue;
if(!isNaN(_cache.nextElement.min) && the_pos > nextElementMinValue) the_pos = nextElementMinValue;

// The the bar in the near beetween the near by area
the_pos = Math.max(the_pos, parseInt(barElm.previousElementSibling.style[flowProperty], 10));
if (barElm.nextElementSibling.nextElementSibling) {
Expand Down
Loading

0 comments on commit c281bde

Please sign in to comment.