504 lines
14 KiB
Plaintext
504 lines
14 KiB
Plaintext
/**
|
|
* box-sizing Polyfill
|
|
*
|
|
* A polyfill for box-sizing: border-box for IE6 & IE7.
|
|
*
|
|
* JScript
|
|
*
|
|
* This program is free software: you can redistribute it and/or modify
|
|
* it under the terms of the GNU Lesser General Public License as published
|
|
* by the Free Software Foundation, either version 3 of the License, or
|
|
* (at your option) any later version.
|
|
*
|
|
* This program is distributed in the hope that it will be useful,
|
|
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
|
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
|
* GNU Lesser General Public License for more details.
|
|
*
|
|
* See <http://www.gnu.org/licenses/lgpl-3.0.txt>
|
|
*
|
|
* @category JScript
|
|
* @package box-sizing-polyfill
|
|
* @author Christian Schepp Schaefer <schaepp@gmx.de> <http://twitter.com/derSchepp>
|
|
* @copyright 2012 Christian Schepp Schaefer
|
|
* @license http://www.gnu.org/copyleft/lesser.html The GNU LESSER GENERAL PUBLIC LICENSE, Version 3.0
|
|
* @link http://github.com/Schepp/box-sizing-polyfill
|
|
*
|
|
* PREFACE:
|
|
*
|
|
* This box-sizing polyfill is based on previous work done by Erik Arvidsson,
|
|
* which he published in 2002 on http://webfx.eae.net/dhtml/boxsizing/boxsizing.html.
|
|
*
|
|
* USAGE:
|
|
*
|
|
* Add the behavior/HTC after every `box-sizing: border-box;` that you assign:
|
|
*
|
|
* box-sizing: border-box;
|
|
* *behavior: url(/scripts/boxsizing.htc);`
|
|
*
|
|
* Prefix the `behavior` property with a star, like seen above, so it will only be seen by
|
|
* IE6 & IE7, not by IE8+ who already implement box-sizing.
|
|
*
|
|
* The URL to the HTC file must be relative to your HTML(!) document, not relative to your CSS.
|
|
* That's why I'd advise you to use absolute paths like in the example.
|
|
*
|
|
*/
|
|
<component lightWeight="true">
|
|
<attach event="onpropertychange" onevent="checkPropertyChange()" />
|
|
<attach event="ondetach" onevent="restore()" />
|
|
<attach event="onresize" for="window" onevent="update()" />
|
|
<script type="text/javascript">
|
|
//<![CDATA[
|
|
|
|
var viewportwidth = (typeof window.innerWidth != 'undefined' ? window.innerWidth : element.document.documentElement.clientWidth);
|
|
|
|
// Shortcut for the document object
|
|
var doc = element.document;
|
|
|
|
// Buffer for multiple resize events
|
|
var resizetimeout = null;
|
|
|
|
// Don't apply box-sizing to certain elements
|
|
var apply = false;
|
|
switch(element.nodeName){
|
|
case '#comment':
|
|
case 'HTML':
|
|
case 'HEAD':
|
|
case 'TITLE':
|
|
case 'SCRIPT':
|
|
case 'STYLE':
|
|
case 'LINK':
|
|
case 'META':
|
|
break;
|
|
|
|
default:
|
|
apply = true;
|
|
break;
|
|
}
|
|
|
|
/*
|
|
* update gets called during resize events, then waits until there are no further resize events, and finally triggers a recalculation
|
|
*/
|
|
function update(){
|
|
if(resizetimeout !== null){
|
|
window.clearTimeout(resizetimeout);
|
|
}
|
|
resizetimeout = window.setTimeout(function(){
|
|
try{
|
|
restore();
|
|
init();
|
|
}
|
|
catch(e){}
|
|
resizetimeout = null;
|
|
},100);
|
|
}
|
|
|
|
/*
|
|
* restore gets called when the behavior is being detached (see event binding at the top),
|
|
* resets everything like it was before applying the behavior
|
|
*/
|
|
function restore(){
|
|
if(apply){
|
|
try{
|
|
element.runtimeStyle.removeAttribute("width");
|
|
element.runtimeStyle.removeAttribute("height");
|
|
}
|
|
catch(e){}
|
|
}
|
|
}
|
|
|
|
/*
|
|
* init gets called once at the start and then never again,
|
|
* triggers box-sizing calculations and updates width and height
|
|
*/
|
|
function init(){
|
|
if(apply){
|
|
updateBorderBoxWidth();
|
|
updateBorderBoxHeight();
|
|
}
|
|
}
|
|
|
|
/*
|
|
* checkPropertyChange gets called as soon as an element property changes
|
|
* (see event binding at the top), it then checks if any property influencing its
|
|
* dimensions was changed and if yes recalculates width and height
|
|
*/
|
|
function checkPropertyChange(){
|
|
if(apply){
|
|
var pn = event.propertyName;
|
|
if(pn === "style.boxSizing" && element.style.boxSizing === ""){
|
|
element.style.removeAttribute("boxSizing");
|
|
element.runtimeStyle.removeAttribute("boxSizing");
|
|
element.runtimeStyle.removeAttribute("width");
|
|
element.runtimeStyle.removeAttribute("height");
|
|
}
|
|
switch (pn){
|
|
case "style.width":
|
|
case "style.minWidth":
|
|
case "style.maxWidth":
|
|
case "style.borderLeftWidth":
|
|
case "style.borderLeftStyle":
|
|
case "style.borderRightWidth":
|
|
case "style.borderRightStyle":
|
|
case "style.paddingLeft":
|
|
case "style.paddingRight":
|
|
updateBorderBoxWidth();
|
|
break;
|
|
|
|
case "style.height":
|
|
case "style.minHeight":
|
|
case "style.maxHeight":
|
|
case "style.borderTopWidth":
|
|
case "style.borderTopStyle":
|
|
case "style.borderBottomWidth":
|
|
case "style.borderBottomStyle":
|
|
case "style.paddingTop":
|
|
case "style.paddingBottom":
|
|
updateBorderBoxHeight();
|
|
break;
|
|
|
|
case "className":
|
|
case "style.boxSizing":
|
|
updateBorderBoxWidth();
|
|
updateBorderBoxHeight();
|
|
break;
|
|
}
|
|
}
|
|
}
|
|
|
|
/*
|
|
* Helper function, taken from Dean Edward's IE7 framework,
|
|
* added by Schepp on 12.06.2010.
|
|
* http://code.google.com/p/ie7-js/
|
|
*
|
|
* Allows us to convert from relative to pixel-values.
|
|
*/
|
|
function getPixelValue(value){
|
|
var PIXEL = /^\d+(px)?$/i;
|
|
if (PIXEL.test(value)) return parseInt(value);
|
|
var style = element.style.left;
|
|
var runtimeStyle = element.runtimeStyle.left;
|
|
element.runtimeStyle.left = element.currentStyle.left;
|
|
element.style.left = value || 0;
|
|
value = parseInt(element.style.pixelLeft);
|
|
element.style.left = style;
|
|
element.runtimeStyle.left = runtimeStyle;
|
|
|
|
return value;
|
|
}
|
|
|
|
function getPixelWidth(object, value){
|
|
// For Pixel Values
|
|
var PIXEL = /^\d+(px)?$/i;
|
|
if (PIXEL.test(value)) return parseInt(value);
|
|
|
|
// For Percentage Values
|
|
var PERCENT = /^[\d\.]+%$/i;
|
|
if (PERCENT.test(value)){
|
|
try{
|
|
var parentPaddingLeft = getPixelWidth(object.parentElement,object.parentElement.currentStyle.paddingLeft);
|
|
var parentPaddingRight = getPixelWidth(object.parentElement,object.parentElement.currentStyle.paddingRight);
|
|
var parentBorderLeft = getPixelWidth(object.parentElement,object.parentElement.currentStyle.borderLeftWidth);
|
|
var parentBorderRight = getPixelWidth(object.parentElement,object.parentElement.currentStyle.borderRightWidth);
|
|
|
|
//var parentWidth = getPixelWidth(object.parentElement,(object.parentElement.currentStyle.width != "auto" ? object.parentElement.currentStyle.width : "100%"));
|
|
var parentWidth = object.parentElement.offsetWidth - parentPaddingLeft - parentPaddingRight - parentBorderLeft - parentBorderRight;
|
|
var value = (parseFloat(value) / 100) * parentWidth;
|
|
}
|
|
catch(e){
|
|
var value = (parseFloat(value) / 100) * element.document.documentElement.clientWidth;
|
|
}
|
|
return parseInt(value);
|
|
}
|
|
|
|
// For EM Values
|
|
var style = object.style.left;
|
|
var runtimeStyle = object.runtimeStyle.left;
|
|
object.runtimeStyle.left = object.currentStyle.left;
|
|
object.style.left = value || 0;
|
|
value = parseInt(object.style.pixelLeft);
|
|
object.style.left = style;
|
|
object.runtimeStyle.left = runtimeStyle;
|
|
|
|
return value;
|
|
}
|
|
|
|
function getPixelHeight(object, value){
|
|
// For Pixel Values
|
|
var PIXEL = /^\d+(px)?$/i;
|
|
if (PIXEL.test(value)) return parseInt(value);
|
|
|
|
// For Percentage Values
|
|
var PERCENT = /^[\d\.]+%$/i;
|
|
if (PERCENT.test(value)){
|
|
try{
|
|
if(object.parentElement.currentStyle.height != "auto"){
|
|
switch(object.parentElement.nodeName){
|
|
default:
|
|
if(object.parentElement.currentStyle.height !== "auto"){
|
|
var parentPaddingTop = getPixelWidth(object.parentElement,object.parentElement.currentStyle.paddingTop);
|
|
var parentPaddingBottom = getPixelWidth(object.parentElement,object.parentElement.currentStyle.paddingBottom);
|
|
var parentBorderTop = getPixelWidth(object.parentElement,object.parentElement.currentStyle.borderTopWidth);
|
|
var parentBorderBottom = getPixelWidth(object.parentElement,object.parentElement.currentStyle.borderBottomWidth);
|
|
|
|
var parentHeight = object.parentElement.offsetHeight - parentPaddingTop - parentPaddingBottom - parentBorderTop - parentBorderBottom;
|
|
//var parentHeight = getPixelHeight(object.parentElement,object.parentElement.currentStyle.height);
|
|
|
|
value = (parseFloat(value) / 100) * parentHeight;
|
|
}
|
|
else {
|
|
value = "auto";
|
|
}
|
|
break;
|
|
|
|
case 'HTML':
|
|
parentHeight = element.document.documentElement.clientHeight;
|
|
if(parentHeight !== "auto"){
|
|
value = (parseFloat(value) / 100) * parentHeight;
|
|
}
|
|
else {
|
|
value = "auto";
|
|
}
|
|
break;
|
|
}
|
|
if(value !== "auto") value = parseInt(value);
|
|
}
|
|
else {
|
|
value = "auto";
|
|
}
|
|
}
|
|
catch(e){
|
|
value = "auto";
|
|
}
|
|
return value;
|
|
}
|
|
|
|
// For EM Values
|
|
var style = object.style.left;
|
|
var runtimeStyle = object.runtimeStyle.left;
|
|
object.runtimeStyle.left = object.currentStyle.left;
|
|
object.style.left = value || 0;
|
|
value = parseInt(object.style.pixelLeft);
|
|
object.style.left = style;
|
|
object.runtimeStyle.left = runtimeStyle;
|
|
|
|
return value;
|
|
}
|
|
|
|
|
|
/*
|
|
* getBorderWidth & friends
|
|
* Border width getters
|
|
*/
|
|
function getBorderWidth(sSide){
|
|
if(element.currentStyle["border" + sSide + "Style"] == "none"){
|
|
return 0;
|
|
}
|
|
var n = getPixelValue(element.currentStyle["border" + sSide + "Width"]);
|
|
return n || 0;
|
|
}
|
|
function getBorderLeftWidth() { return getBorderWidth("Left"); }
|
|
function getBorderRightWidth() { return getBorderWidth("Right"); }
|
|
function getBorderTopWidth() { return getBorderWidth("Top"); }
|
|
function getBorderBottomWidth() { return getBorderWidth("Bottom"); }
|
|
|
|
|
|
/*
|
|
* getPadding & friends
|
|
* Padding width getters
|
|
*/
|
|
function getPadding(sSide) {
|
|
var n = getPixelValue(element.currentStyle["padding" + sSide]);
|
|
return n || 0;
|
|
}
|
|
function getPaddingLeft() { return getPadding("Left"); }
|
|
function getPaddingRight() { return getPadding("Right"); }
|
|
function getPaddingTop() { return getPadding("Top"); }
|
|
function getPaddingBottom() { return getPadding("Bottom"); }
|
|
|
|
|
|
|
|
/*
|
|
* getBoxSizing
|
|
* Get the box-sizing value for the current element
|
|
*/
|
|
function getBoxSizing(){
|
|
var s = element.style;
|
|
var cs = element.currentStyle
|
|
if(typeof s.boxSizing != "undefined" && s.boxSizing != ""){
|
|
return s.boxSizing;
|
|
}
|
|
if(typeof s["box-sizing"] != "undefined" && s["box-sizing"] != ""){
|
|
return s["box-sizing"];
|
|
}
|
|
if(typeof cs.boxSizing != "undefined" && cs.boxSizing != ""){
|
|
return cs.boxSizing;
|
|
}
|
|
if(typeof cs["box-sizing"] != "undefined" && cs["box-sizing"] != ""){
|
|
return cs["box-sizing"];
|
|
}
|
|
return getDocumentBoxSizing();
|
|
}
|
|
|
|
|
|
/*
|
|
* getDocumentBoxSizing
|
|
* Get the default document box sizing (check for quirks mode)
|
|
*/
|
|
function getDocumentBoxSizing(){
|
|
if(doc.compatMode === null || doc.compatMode === "BackCompat"){
|
|
return "border-box";
|
|
}
|
|
return "content-box"
|
|
}
|
|
|
|
|
|
/*
|
|
* setBorderBoxWidth & friends
|
|
* Width and height setters
|
|
*/
|
|
function setBorderBoxWidth(n){
|
|
element.runtimeStyle.width = Math.max(0, n - getBorderLeftWidth() -
|
|
getPaddingLeft() - getPaddingRight() - getBorderRightWidth()) + "px";
|
|
}
|
|
function setBorderBoxMinWidth(n){
|
|
element.runtimeStyle.minWidth = Math.max(0, n - getBorderLeftWidth() -
|
|
getPaddingLeft() - getPaddingRight() - getBorderRightWidth()) + "px";
|
|
}
|
|
function setBorderBoxMaxWidth(n){
|
|
element.runtimeStyle.maxWidth = Math.max(0, n - getBorderLeftWidth() -
|
|
getPaddingLeft() - getPaddingRight() - getBorderRightWidth()) + "px";
|
|
}
|
|
function setBorderBoxHeight(n){
|
|
element.runtimeStyle.height = Math.max(0, n - getBorderTopWidth() -
|
|
getPaddingTop() - getPaddingBottom() - getBorderBottomWidth()) + "px";
|
|
}
|
|
function setBorderBoxMinHeight(n){
|
|
element.runtimeStyle.minHeight = Math.max(0, n - getBorderTopWidth() -
|
|
getPaddingTop() - getPaddingBottom() - getBorderBottomWidth()) + "px";
|
|
}
|
|
function setBorderBoxMaxHeight(n){
|
|
element.runtimeStyle.maxHeight = Math.max(0, n - getBorderTopWidth() -
|
|
getPaddingTop() - getPaddingBottom() - getBorderBottomWidth()) + "px";
|
|
}
|
|
function setContentBoxWidth(n){
|
|
element.runtimeStyle.width = Math.max(0, n + getBorderLeftWidth() +
|
|
getPaddingLeft() + getPaddingRight() + getBorderRightWidth()) + "px";
|
|
}
|
|
function setContentBoxMinWidth(n){
|
|
element.runtimeStyle.minWidth = Math.max(0, n + getBorderLeftWidth() +
|
|
getPaddingLeft() + getPaddingRight() + getBorderRightWidth()) + "px";
|
|
}
|
|
function setContentBoxMaxWidth(n){
|
|
element.runtimeStyle.maxWidth = Math.max(0, n + getBorderLeftWidth() +
|
|
getPaddingLeft() + getPaddingRight() + getBorderRightWidth()) + "px";
|
|
}
|
|
function setContentBoxHeight(n){
|
|
element.runtimeStyle.height = Math.max(0, n + getBorderTopWidth() +
|
|
getPaddingTop() + getPaddingBottom() + getBorderBottomWidth()) + "px";
|
|
}
|
|
function setContentBoxMinHeight(n){
|
|
element.runtimeStyle.minHeight = Math.max(0, n + getBorderTopWidth() +
|
|
getPaddingTop() + getPaddingBottom() + getBorderBottomWidth()) + "px";
|
|
}
|
|
function setContentBoxMaxHeight(n){
|
|
element.runtimeStyle.maxHeight = Math.max(0, n + getBorderTopWidth() +
|
|
getPaddingTop() + getPaddingBottom() + getBorderBottomWidth()) + "px";
|
|
}
|
|
|
|
|
|
/*
|
|
* updateBorderBoxWidth & updateBorderBoxHeight
|
|
*
|
|
*/
|
|
function updateBorderBoxWidth() {
|
|
if(getDocumentBoxSizing() == getBoxSizing()){
|
|
return;
|
|
}
|
|
|
|
var csw = element.currentStyle.width;
|
|
if(csw != "auto"){
|
|
csw = getPixelWidth(element,csw);
|
|
if(getBoxSizing() == "border-box"){
|
|
setBorderBoxWidth(parseInt(csw));
|
|
}
|
|
else{
|
|
setContentBoxWidth(parseInt(csw));
|
|
}
|
|
}
|
|
|
|
csw = element.currentStyle.minWidth;
|
|
if(csw != "none"){
|
|
csw = getPixelWidth(element,csw);
|
|
if(getBoxSizing() == "border-box"){
|
|
setBorderBoxMinWidth(parseInt(csw));
|
|
}
|
|
else{
|
|
setContentBoxMinWidth(parseInt(csw));
|
|
}
|
|
}
|
|
|
|
csw = element.currentStyle.maxWidth;
|
|
if(csw != "none"){
|
|
csw = getPixelWidth(element,csw);
|
|
if(getBoxSizing() == "border-box"){
|
|
setBorderBoxMaxWidth(parseInt(csw));
|
|
}
|
|
else{
|
|
setContentBoxMaxWidth(parseInt(csw));
|
|
}
|
|
}
|
|
}
|
|
|
|
function updateBorderBoxHeight() {
|
|
if(getDocumentBoxSizing() == getBoxSizing()){
|
|
return;
|
|
}
|
|
|
|
var csh = element.currentStyle.height;
|
|
if(csh != "auto"){
|
|
csh = getPixelHeight(element,csh);
|
|
if(csh !== "auto"){
|
|
if(getBoxSizing() == "border-box"){
|
|
setBorderBoxHeight(parseInt(csh));
|
|
}
|
|
else{
|
|
setContentBoxHeight(parseInt(csh));
|
|
}
|
|
}
|
|
}
|
|
|
|
csh = element.currentStyle.minHeight;
|
|
if(csh != "none"){
|
|
csh = getPixelHeight(element,csh);
|
|
if(csh !== "none"){
|
|
if(getBoxSizing() == "border-box"){
|
|
setBorderBoxMinHeight(parseInt(csh));
|
|
}
|
|
else{
|
|
setContentBoxMinHeight(parseInt(csh));
|
|
}
|
|
}
|
|
}
|
|
|
|
csh = element.currentStyle.maxHeight;
|
|
if(csh != "none"){
|
|
csh = getPixelHeight(element,csh);
|
|
if(csh !== "none"){
|
|
if(getBoxSizing() == "border-box"){
|
|
setBorderBoxMaxHeight(parseInt(csh));
|
|
}
|
|
else{
|
|
setContentBoxMaxHeight(parseInt(csh));
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
|
|
// Run the calculations
|
|
init();
|
|
|
|
//]]>
|
|
</script>
|
|
</component> |