blob: 440bebe7ff54e5ad10e3ac9731464287c1eaa80c [file] [log] [blame]
// Copyright (c) 2013, the Dart project authors. Please see the AUTHORS file
// for details. All rights reserved. Use of this source code is governed by a
// BSD-style license that can be found in the LICENSE file.
part of html;
/**
* A rectangle representing all the content of the element in the
* [box model](http://www.w3.org/TR/CSS2/box.html).
*/
class _ContentCssRect extends CssRect {
_ContentCssRect(element) : super(element);
num get height => _element.offsetHeight +
_addOrSubtractToBoxModel(_HEIGHT, _CONTENT);
num get width => _element.offsetWidth +
_addOrSubtractToBoxModel(_WIDTH, _CONTENT);
/**
* Set the height to `newHeight`.
*
* newHeight can be either a [num] representing the height in pixels or a
* [Dimension] object. Values of newHeight that are less than zero are
* converted to effectively setting the height to 0. This is equivalent to the
* `height` function in jQuery and the calculated `height` CSS value,
* converted to a num in pixels.
*/
set height(newHeight) {
if (newHeight is Dimension) {
if (newHeight.value < 0) newHeight = new Dimension.px(0);
_element.style.height = newHeight.toString();
} else {
if (newHeight < 0) newHeight = 0;
_element.style.height = '${newHeight}px';
}
}
/**
* Set the current computed width in pixels of this element.
*
* newWidth can be either a [num] representing the width in pixels or a
* [Dimension] object. This is equivalent to the `width` function in jQuery
* and the calculated
* `width` CSS value, converted to a dimensionless num in pixels.
*/
set width(newWidth) {
if (newWidth is Dimension) {
if (newWidth.value < 0) newWidth = new Dimension.px(0);
_element.style.width = newWidth.toString();
} else {
if (newWidth < 0) newWidth = 0;
_element.style.width = '${newWidth}px';
}
}
num get left => _element.getBoundingClientRect().left -
_addOrSubtractToBoxModel(['left'], _CONTENT);
num get top => _element.getBoundingClientRect().top -
_addOrSubtractToBoxModel(['top'], _CONTENT);
}
/**
* A list of element content rectangles in the
* [box model](http://www.w3.org/TR/CSS2/box.html).
*/
class _ContentCssListRect extends _ContentCssRect {
List<Element> _elementList;
_ContentCssListRect(elementList) : super(elementList.first) {
_elementList = elementList;
}
/**
* Set the height to `newHeight`.
*
* Values of newHeight that are less than zero are converted to effectively
* setting the height to 0. This is equivalent to the `height`
* function in jQuery and the calculated `height` CSS value, converted to a
* num in pixels.
*/
set height(newHeight) {
_elementList.forEach((e) => e.contentEdge.height = newHeight);
}
/**
* Set the current computed width in pixels of this element.
*
* This is equivalent to the `width` function in jQuery and the calculated
* `width` CSS value, converted to a dimensionless num in pixels.
*/
set width(newWidth) {
_elementList.forEach((e) => e.contentEdge.width = newWidth);
}
}
/**
* A rectangle representing the dimensions of the space occupied by the
* element's content + padding in the
* [box model](http://www.w3.org/TR/CSS2/box.html).
*/
class _PaddingCssRect extends CssRect {
_PaddingCssRect(element) : super(element);
num get height => _element.offsetHeight +
_addOrSubtractToBoxModel(_HEIGHT, _PADDING);
num get width => _element.offsetWidth +
_addOrSubtractToBoxModel(_WIDTH, _PADDING);
num get left => _element.getBoundingClientRect().left -
_addOrSubtractToBoxModel(['left'], _PADDING);
num get top => _element.getBoundingClientRect().top -
_addOrSubtractToBoxModel(['top'], _PADDING);
}
/**
* A rectangle representing the dimensions of the space occupied by the
* element's content + padding + border in the
* [box model](http://www.w3.org/TR/CSS2/box.html).
*/
class _BorderCssRect extends CssRect {
_BorderCssRect(element) : super(element);
num get height => _element.offsetHeight;
num get width => _element.offsetWidth;
num get left => _element.getBoundingClientRect().left;
num get top => _element.getBoundingClientRect().top;
}
/**
* A rectangle representing the dimensions of the space occupied by the
* element's content + padding + border + margin in the
* [box model](http://www.w3.org/TR/CSS2/box.html).
*/
class _MarginCssRect extends CssRect {
_MarginCssRect(element) : super(element);
num get height => _element.offsetHeight +
_addOrSubtractToBoxModel(_HEIGHT, _MARGIN);
num get width =>
_element.offsetWidth + _addOrSubtractToBoxModel(_WIDTH, _MARGIN);
num get left => _element.getBoundingClientRect().left -
_addOrSubtractToBoxModel(['left'], _MARGIN);
num get top => _element.getBoundingClientRect().top -
_addOrSubtractToBoxModel(['top'], _MARGIN);
}
/**
* A class for representing CSS dimensions.
*
* In contrast to the more general purpose [Rectangle] class, this class's
* values are mutable, so one can change the height of an element
* programmatically.
*
* _Important_ _note_: use of these methods will perform CSS calculations that
* can trigger a browser reflow. Therefore, use of these properties _during_ an
* animation frame is discouraged. See also:
* [Browser Reflow](https://developers.google.com/speed/articles/reflow)
*/
abstract class CssRect extends MutableRectangle<num> {
Element _element;
CssRect(this._element) : super(0, 0, 0, 0);
num get left;
num get top;
/**
* The height of this rectangle.
*
* This is equivalent to the `height` function in jQuery and the calculated
* `height` CSS value, converted to a dimensionless num in pixels. Unlike
* [getBoundingClientRect], `height` will return the same numerical width if
* the element is hidden or not.
*/
num get height;
/**
* The width of this rectangle.
*
* This is equivalent to the `width` function in jQuery and the calculated
* `width` CSS value, converted to a dimensionless num in pixels. Unlike
* [getBoundingClientRect], `width` will return the same numerical width if
* the element is hidden or not.
*/
num get width;
/**
* Set the height to `newHeight`.
*
* newHeight can be either a [num] representing the height in pixels or a
* [Dimension] object. Values of newHeight that are less than zero are
* converted to effectively setting the height to 0. This is equivalent to the
* `height` function in jQuery and the calculated `height` CSS value,
* converted to a num in pixels.
*
* Note that only the content height can actually be set via this method.
*/
set height(newHeight) {
throw new UnsupportedError("Can only set height for content rect.");
}
/**
* Set the current computed width in pixels of this element.
*
* newWidth can be either a [num] representing the width in pixels or a
* [Dimension] object. This is equivalent to the `width` function in jQuery
* and the calculated
* `width` CSS value, converted to a dimensionless num in pixels.
*
* Note that only the content width can be set via this method.
*/
set width(newWidth) {
throw new UnsupportedError("Can only set width for content rect.");
}
/**
* Return a value that is used to modify the initial height or width
* measurement of an element. Depending on the value (ideally an enum) passed
* to augmentingMeasurement, we may need to add or subtract margin, padding,
* or border values, depending on the measurement we're trying to obtain.
*/
num _addOrSubtractToBoxModel(List<String> dimensions,
String augmentingMeasurement) {
// getComputedStyle always returns pixel values (hence, computed), so we're
// always dealing with pixels in this method.
var styles = _element.getComputedStyle();
var val = 0;
for (String measurement in dimensions) {
// The border-box and default box model both exclude margin in the regular
// height/width calculation, so add it if we want it for this measurement.
if (augmentingMeasurement == _MARGIN) {
val += new Dimension.css(styles.getPropertyValue(
'$augmentingMeasurement-$measurement')).value;
}
// The border-box includes padding and border, so remove it if we want
// just the content itself.
if (augmentingMeasurement == _CONTENT) {
val -= new Dimension.css(
styles.getPropertyValue('${_PADDING}-$measurement')).value;
}
// At this point, we don't wan't to augment with border or margin,
// so remove border.
if (augmentingMeasurement != _MARGIN) {
val -= new Dimension.css(styles.getPropertyValue(
'border-${measurement}-width')).value;
}
}
return val;
}
}
final _HEIGHT = ['top', 'bottom'];
final _WIDTH = ['right', 'left'];
final _CONTENT = 'content';
final _PADDING = 'padding';
final _MARGIN = 'margin';