michael@0: /*** michael@0: michael@0: MochiKit.Style 1.4.2 michael@0: michael@0: See for documentation, downloads, license, etc. michael@0: michael@0: (c) 2005-2006 Bob Ippolito, Beau Hartshorne. All rights Reserved. michael@0: michael@0: ***/ michael@0: michael@0: MochiKit.Base._deps('Style', ['Base', 'DOM']); michael@0: michael@0: MochiKit.Style.NAME = 'MochiKit.Style'; michael@0: MochiKit.Style.VERSION = '1.4.2'; michael@0: MochiKit.Style.__repr__ = function () { michael@0: return '[' + this.NAME + ' ' + this.VERSION + ']'; michael@0: }; michael@0: MochiKit.Style.toString = function () { michael@0: return this.__repr__(); michael@0: }; michael@0: michael@0: MochiKit.Style.EXPORT_OK = []; michael@0: michael@0: MochiKit.Style.EXPORT = [ michael@0: 'setStyle', michael@0: 'setOpacity', michael@0: 'getStyle', michael@0: 'getElementDimensions', michael@0: 'elementDimensions', // deprecated michael@0: 'setElementDimensions', michael@0: 'getElementPosition', michael@0: 'elementPosition', // deprecated michael@0: 'setElementPosition', michael@0: "makePositioned", michael@0: "undoPositioned", michael@0: "makeClipping", michael@0: "undoClipping", michael@0: 'setDisplayForElement', michael@0: 'hideElement', michael@0: 'showElement', michael@0: 'getViewportDimensions', michael@0: 'getViewportPosition', michael@0: 'Dimensions', michael@0: 'Coordinates' michael@0: ]; michael@0: michael@0: michael@0: /* michael@0: michael@0: Dimensions michael@0: michael@0: */ michael@0: /** @id MochiKit.Style.Dimensions */ michael@0: MochiKit.Style.Dimensions = function (w, h) { michael@0: this.w = w; michael@0: this.h = h; michael@0: }; michael@0: michael@0: MochiKit.Style.Dimensions.prototype.__repr__ = function () { michael@0: var repr = MochiKit.Base.repr; michael@0: return '{w: ' + repr(this.w) + ', h: ' + repr(this.h) + '}'; michael@0: }; michael@0: michael@0: MochiKit.Style.Dimensions.prototype.toString = function () { michael@0: return this.__repr__(); michael@0: }; michael@0: michael@0: michael@0: /* michael@0: michael@0: Coordinates michael@0: michael@0: */ michael@0: /** @id MochiKit.Style.Coordinates */ michael@0: MochiKit.Style.Coordinates = function (x, y) { michael@0: this.x = x; michael@0: this.y = y; michael@0: }; michael@0: michael@0: MochiKit.Style.Coordinates.prototype.__repr__ = function () { michael@0: var repr = MochiKit.Base.repr; michael@0: return '{x: ' + repr(this.x) + ', y: ' + repr(this.y) + '}'; michael@0: }; michael@0: michael@0: MochiKit.Style.Coordinates.prototype.toString = function () { michael@0: return this.__repr__(); michael@0: }; michael@0: michael@0: michael@0: MochiKit.Base.update(MochiKit.Style, { michael@0: michael@0: /** @id MochiKit.Style.getStyle */ michael@0: getStyle: function (elem, cssProperty) { michael@0: var dom = MochiKit.DOM; michael@0: var d = dom._document; michael@0: michael@0: elem = dom.getElement(elem); michael@0: cssProperty = MochiKit.Base.camelize(cssProperty); michael@0: michael@0: if (!elem || elem == d) { michael@0: return undefined; michael@0: } michael@0: if (cssProperty == 'opacity' && typeof(elem.filters) != 'undefined') { michael@0: var opacity = (MochiKit.Style.getStyle(elem, 'filter') || '').match(/alpha\(opacity=(.*)\)/); michael@0: if (opacity && opacity[1]) { michael@0: return parseFloat(opacity[1]) / 100; michael@0: } michael@0: return 1.0; michael@0: } michael@0: if (cssProperty == 'float' || cssProperty == 'cssFloat' || cssProperty == 'styleFloat') { michael@0: if (elem.style["float"]) { michael@0: return elem.style["float"]; michael@0: } else if (elem.style.cssFloat) { michael@0: return elem.style.cssFloat; michael@0: } else if (elem.style.styleFloat) { michael@0: return elem.style.styleFloat; michael@0: } else { michael@0: return "none"; michael@0: } michael@0: } michael@0: var value = elem.style ? elem.style[cssProperty] : null; michael@0: if (!value) { michael@0: if (d.defaultView && d.defaultView.getComputedStyle) { michael@0: var css = d.defaultView.getComputedStyle(elem, null); michael@0: cssProperty = cssProperty.replace(/([A-Z])/g, '-$1' michael@0: ).toLowerCase(); // from dojo.style.toSelectorCase michael@0: value = css ? css.getPropertyValue(cssProperty) : null; michael@0: } else if (elem.currentStyle) { michael@0: value = elem.currentStyle[cssProperty]; michael@0: if (/^\d/.test(value) && !/px$/.test(value) && cssProperty != 'fontWeight') { michael@0: /* Convert to px using an hack from Dean Edwards */ michael@0: var left = elem.style.left; michael@0: var rsLeft = elem.runtimeStyle.left; michael@0: elem.runtimeStyle.left = elem.currentStyle.left; michael@0: elem.style.left = value || 0; michael@0: value = elem.style.pixelLeft + "px"; michael@0: elem.style.left = left; michael@0: elem.runtimeStyle.left = rsLeft; michael@0: } michael@0: } michael@0: } michael@0: if (cssProperty == 'opacity') { michael@0: value = parseFloat(value); michael@0: } michael@0: michael@0: if (/Opera/.test(navigator.userAgent) && (MochiKit.Base.findValue(['left', 'top', 'right', 'bottom'], cssProperty) != -1)) { michael@0: if (MochiKit.Style.getStyle(elem, 'position') == 'static') { michael@0: value = 'auto'; michael@0: } michael@0: } michael@0: michael@0: return value == 'auto' ? null : value; michael@0: }, michael@0: michael@0: /** @id MochiKit.Style.setStyle */ michael@0: setStyle: function (elem, style) { michael@0: elem = MochiKit.DOM.getElement(elem); michael@0: for (var name in style) { michael@0: switch (name) { michael@0: case 'opacity': michael@0: MochiKit.Style.setOpacity(elem, style[name]); michael@0: break; michael@0: case 'float': michael@0: case 'cssFloat': michael@0: case 'styleFloat': michael@0: if (typeof(elem.style["float"]) != "undefined") { michael@0: elem.style["float"] = style[name]; michael@0: } else if (typeof(elem.style.cssFloat) != "undefined") { michael@0: elem.style.cssFloat = style[name]; michael@0: } else { michael@0: elem.style.styleFloat = style[name]; michael@0: } michael@0: break; michael@0: default: michael@0: elem.style[MochiKit.Base.camelize(name)] = style[name]; michael@0: } michael@0: } michael@0: }, michael@0: michael@0: /** @id MochiKit.Style.setOpacity */ michael@0: setOpacity: function (elem, o) { michael@0: elem = MochiKit.DOM.getElement(elem); michael@0: var self = MochiKit.Style; michael@0: if (o == 1) { michael@0: var toSet = /Gecko/.test(navigator.userAgent) && !(/Konqueror|AppleWebKit|KHTML/.test(navigator.userAgent)); michael@0: elem.style["opacity"] = toSet ? 0.999999 : 1.0; michael@0: if (/MSIE/.test(navigator.userAgent)) { michael@0: elem.style['filter'] = michael@0: self.getStyle(elem, 'filter').replace(/alpha\([^\)]*\)/gi, ''); michael@0: } michael@0: } else { michael@0: if (o < 0.00001) { michael@0: o = 0; michael@0: } michael@0: elem.style["opacity"] = o; michael@0: if (/MSIE/.test(navigator.userAgent)) { michael@0: elem.style['filter'] = michael@0: self.getStyle(elem, 'filter').replace(/alpha\([^\)]*\)/gi, '') + 'alpha(opacity=' + o * 100 + ')'; michael@0: } michael@0: } michael@0: }, michael@0: michael@0: /* michael@0: michael@0: getElementPosition is adapted from YAHOO.util.Dom.getXY v0.9.0. michael@0: Copyright: Copyright (c) 2006, Yahoo! Inc. All rights reserved. michael@0: License: BSD, http://developer.yahoo.net/yui/license.txt michael@0: michael@0: */ michael@0: michael@0: /** @id MochiKit.Style.getElementPosition */ michael@0: getElementPosition: function (elem, /* optional */relativeTo) { michael@0: var self = MochiKit.Style; michael@0: var dom = MochiKit.DOM; michael@0: elem = dom.getElement(elem); michael@0: michael@0: if (!elem || michael@0: (!(elem.x && elem.y) && michael@0: (!elem.parentNode === null || michael@0: self.getStyle(elem, 'display') == 'none'))) { michael@0: return undefined; michael@0: } michael@0: michael@0: var c = new self.Coordinates(0, 0); michael@0: var box = null; michael@0: var parent = null; michael@0: michael@0: var d = MochiKit.DOM._document; michael@0: var de = d.documentElement; michael@0: var b = d.body; michael@0: michael@0: if (!elem.parentNode && elem.x && elem.y) { michael@0: /* it's just a MochiKit.Style.Coordinates object */ michael@0: c.x += elem.x || 0; michael@0: c.y += elem.y || 0; michael@0: } else if (elem.getBoundingClientRect) { // IE shortcut michael@0: /* michael@0: michael@0: The IE shortcut can be off by two. We fix it. See: michael@0: http://msdn.microsoft.com/workshop/author/dhtml/reference/methods/getboundingclientrect.asp michael@0: michael@0: This is similar to the method used in michael@0: MochiKit.Signal.Event.mouse(). michael@0: michael@0: */ michael@0: box = elem.getBoundingClientRect(); michael@0: michael@0: c.x += box.left + michael@0: (de.scrollLeft || b.scrollLeft) - michael@0: (de.clientLeft || 0); michael@0: michael@0: c.y += box.top + michael@0: (de.scrollTop || b.scrollTop) - michael@0: (de.clientTop || 0); michael@0: michael@0: } else if (elem.offsetParent) { michael@0: c.x += elem.offsetLeft; michael@0: c.y += elem.offsetTop; michael@0: parent = elem.offsetParent; michael@0: michael@0: if (parent != elem) { michael@0: while (parent) { michael@0: c.x += parseInt(parent.style.borderLeftWidth) || 0; michael@0: c.y += parseInt(parent.style.borderTopWidth) || 0; michael@0: c.x += parent.offsetLeft; michael@0: c.y += parent.offsetTop; michael@0: parent = parent.offsetParent; michael@0: } michael@0: } michael@0: michael@0: /* michael@0: michael@0: Opera < 9 and old Safari (absolute) incorrectly account for michael@0: body offsetTop and offsetLeft. michael@0: michael@0: */ michael@0: var ua = navigator.userAgent.toLowerCase(); michael@0: if ((typeof(opera) != 'undefined' && michael@0: parseFloat(opera.version()) < 9) || michael@0: (ua.indexOf('AppleWebKit') != -1 && michael@0: self.getStyle(elem, 'position') == 'absolute')) { michael@0: michael@0: c.x -= b.offsetLeft; michael@0: c.y -= b.offsetTop; michael@0: michael@0: } michael@0: michael@0: // Adjust position for strange Opera scroll bug michael@0: if (elem.parentNode) { michael@0: parent = elem.parentNode; michael@0: } else { michael@0: parent = null; michael@0: } michael@0: while (parent) { michael@0: var tagName = parent.tagName.toUpperCase(); michael@0: if (tagName === 'BODY' || tagName === 'HTML') { michael@0: break; michael@0: } michael@0: var disp = self.getStyle(parent, 'display'); michael@0: // Handle strange Opera bug for some display michael@0: if (disp.search(/^inline|table-row.*$/i)) { michael@0: c.x -= parent.scrollLeft; michael@0: c.y -= parent.scrollTop; michael@0: } michael@0: if (parent.parentNode) { michael@0: parent = parent.parentNode; michael@0: } else { michael@0: parent = null; michael@0: } michael@0: } michael@0: } michael@0: michael@0: if (typeof(relativeTo) != 'undefined') { michael@0: relativeTo = arguments.callee(relativeTo); michael@0: if (relativeTo) { michael@0: c.x -= (relativeTo.x || 0); michael@0: c.y -= (relativeTo.y || 0); michael@0: } michael@0: } michael@0: michael@0: return c; michael@0: }, michael@0: michael@0: /** @id MochiKit.Style.setElementPosition */ michael@0: setElementPosition: function (elem, newPos/* optional */, units) { michael@0: elem = MochiKit.DOM.getElement(elem); michael@0: if (typeof(units) == 'undefined') { michael@0: units = 'px'; michael@0: } michael@0: var newStyle = {}; michael@0: var isUndefNull = MochiKit.Base.isUndefinedOrNull; michael@0: if (!isUndefNull(newPos.x)) { michael@0: newStyle['left'] = newPos.x + units; michael@0: } michael@0: if (!isUndefNull(newPos.y)) { michael@0: newStyle['top'] = newPos.y + units; michael@0: } michael@0: MochiKit.DOM.updateNodeAttributes(elem, {'style': newStyle}); michael@0: }, michael@0: michael@0: /** @id MochiKit.Style.makePositioned */ michael@0: makePositioned: function (element) { michael@0: element = MochiKit.DOM.getElement(element); michael@0: var pos = MochiKit.Style.getStyle(element, 'position'); michael@0: if (pos == 'static' || !pos) { michael@0: element.style.position = 'relative'; michael@0: // Opera returns the offset relative to the positioning context, michael@0: // when an element is position relative but top and left have michael@0: // not been defined michael@0: if (/Opera/.test(navigator.userAgent)) { michael@0: element.style.top = 0; michael@0: element.style.left = 0; michael@0: } michael@0: } michael@0: }, michael@0: michael@0: /** @id MochiKit.Style.undoPositioned */ michael@0: undoPositioned: function (element) { michael@0: element = MochiKit.DOM.getElement(element); michael@0: if (element.style.position == 'relative') { michael@0: element.style.position = element.style.top = element.style.left = element.style.bottom = element.style.right = ''; michael@0: } michael@0: }, michael@0: michael@0: /** @id MochiKit.Style.makeClipping */ michael@0: makeClipping: function (element) { michael@0: element = MochiKit.DOM.getElement(element); michael@0: var s = element.style; michael@0: var oldOverflow = { 'overflow': s.overflow, michael@0: 'overflow-x': s.overflowX, michael@0: 'overflow-y': s.overflowY }; michael@0: if ((MochiKit.Style.getStyle(element, 'overflow') || 'visible') != 'hidden') { michael@0: element.style.overflow = 'hidden'; michael@0: element.style.overflowX = 'hidden'; michael@0: element.style.overflowY = 'hidden'; michael@0: } michael@0: return oldOverflow; michael@0: }, michael@0: michael@0: /** @id MochiKit.Style.undoClipping */ michael@0: undoClipping: function (element, overflow) { michael@0: element = MochiKit.DOM.getElement(element); michael@0: if (typeof(overflow) == 'string') { michael@0: element.style.overflow = overflow; michael@0: } else if (overflow != null) { michael@0: element.style.overflow = overflow['overflow']; michael@0: element.style.overflowX = overflow['overflow-x']; michael@0: element.style.overflowY = overflow['overflow-y']; michael@0: } michael@0: }, michael@0: michael@0: /** @id MochiKit.Style.getElementDimensions */ michael@0: getElementDimensions: function (elem, contentSize/*optional*/) { michael@0: var self = MochiKit.Style; michael@0: var dom = MochiKit.DOM; michael@0: if (typeof(elem.w) == 'number' || typeof(elem.h) == 'number') { michael@0: return new self.Dimensions(elem.w || 0, elem.h || 0); michael@0: } michael@0: elem = dom.getElement(elem); michael@0: if (!elem) { michael@0: return undefined; michael@0: } michael@0: var disp = self.getStyle(elem, 'display'); michael@0: // display can be empty/undefined on WebKit/KHTML michael@0: if (disp == 'none' || disp == '' || typeof(disp) == 'undefined') { michael@0: var s = elem.style; michael@0: var originalVisibility = s.visibility; michael@0: var originalPosition = s.position; michael@0: var originalDisplay = s.display; michael@0: s.visibility = 'hidden'; michael@0: s.position = 'absolute'; michael@0: s.display = self._getDefaultDisplay(elem); michael@0: var originalWidth = elem.offsetWidth; michael@0: var originalHeight = elem.offsetHeight; michael@0: s.display = originalDisplay; michael@0: s.position = originalPosition; michael@0: s.visibility = originalVisibility; michael@0: } else { michael@0: originalWidth = elem.offsetWidth || 0; michael@0: originalHeight = elem.offsetHeight || 0; michael@0: } michael@0: if (contentSize) { michael@0: var tableCell = 'colSpan' in elem && 'rowSpan' in elem; michael@0: var collapse = (tableCell && elem.parentNode && self.getStyle( michael@0: elem.parentNode, 'borderCollapse') == 'collapse') michael@0: if (collapse) { michael@0: if (/MSIE/.test(navigator.userAgent)) { michael@0: var borderLeftQuota = elem.previousSibling? 0.5 : 1; michael@0: var borderRightQuota = elem.nextSibling? 0.5 : 1; michael@0: } michael@0: else { michael@0: var borderLeftQuota = 0.5; michael@0: var borderRightQuota = 0.5; michael@0: } michael@0: } else { michael@0: var borderLeftQuota = 1; michael@0: var borderRightQuota = 1; michael@0: } michael@0: originalWidth -= Math.round( michael@0: (parseFloat(self.getStyle(elem, 'paddingLeft')) || 0) michael@0: + (parseFloat(self.getStyle(elem, 'paddingRight')) || 0) michael@0: + borderLeftQuota * michael@0: (parseFloat(self.getStyle(elem, 'borderLeftWidth')) || 0) michael@0: + borderRightQuota * michael@0: (parseFloat(self.getStyle(elem, 'borderRightWidth')) || 0) michael@0: ); michael@0: if (tableCell) { michael@0: if (/Opera/.test(navigator.userAgent) michael@0: && !/Konqueror|AppleWebKit|KHTML/.test(navigator.userAgent)) { michael@0: var borderHeightQuota = 0; michael@0: } else if (/MSIE/.test(navigator.userAgent)) { michael@0: var borderHeightQuota = 1; michael@0: } else { michael@0: var borderHeightQuota = collapse? 0.5 : 1; michael@0: } michael@0: } else { michael@0: var borderHeightQuota = 1; michael@0: } michael@0: originalHeight -= Math.round( michael@0: (parseFloat(self.getStyle(elem, 'paddingTop')) || 0) michael@0: + (parseFloat(self.getStyle(elem, 'paddingBottom')) || 0) michael@0: + borderHeightQuota * ( michael@0: (parseFloat(self.getStyle(elem, 'borderTopWidth')) || 0) michael@0: + (parseFloat(self.getStyle(elem, 'borderBottomWidth')) || 0)) michael@0: ); michael@0: } michael@0: return new self.Dimensions(originalWidth, originalHeight); michael@0: }, michael@0: michael@0: /** @id MochiKit.Style.setElementDimensions */ michael@0: setElementDimensions: function (elem, newSize/* optional */, units) { michael@0: elem = MochiKit.DOM.getElement(elem); michael@0: if (typeof(units) == 'undefined') { michael@0: units = 'px'; michael@0: } michael@0: var newStyle = {}; michael@0: var isUndefNull = MochiKit.Base.isUndefinedOrNull; michael@0: if (!isUndefNull(newSize.w)) { michael@0: newStyle['width'] = newSize.w + units; michael@0: } michael@0: if (!isUndefNull(newSize.h)) { michael@0: newStyle['height'] = newSize.h + units; michael@0: } michael@0: MochiKit.DOM.updateNodeAttributes(elem, {'style': newStyle}); michael@0: }, michael@0: michael@0: _getDefaultDisplay: function (elem) { michael@0: var self = MochiKit.Style; michael@0: var dom = MochiKit.DOM; michael@0: elem = dom.getElement(elem); michael@0: if (!elem) { michael@0: return undefined; michael@0: } michael@0: var tagName = elem.tagName.toUpperCase(); michael@0: return self._defaultDisplay[tagName] || 'block'; michael@0: }, michael@0: michael@0: /** @id MochiKit.Style.setDisplayForElement */ michael@0: setDisplayForElement: function (display, element/*, ...*/) { michael@0: var elements = MochiKit.Base.extend(null, arguments, 1); michael@0: var getElement = MochiKit.DOM.getElement; michael@0: for (var i = 0; i < elements.length; i++) { michael@0: element = getElement(elements[i]); michael@0: if (element) { michael@0: element.style.display = display; michael@0: } michael@0: } michael@0: }, michael@0: michael@0: /** @id MochiKit.Style.getViewportDimensions */ michael@0: getViewportDimensions: function () { michael@0: var d = new MochiKit.Style.Dimensions(); michael@0: var w = MochiKit.DOM._window; michael@0: var b = MochiKit.DOM._document.body; michael@0: if (w.innerWidth) { michael@0: d.w = w.innerWidth; michael@0: d.h = w.innerHeight; michael@0: } else if (b && b.parentElement && b.parentElement.clientWidth) { michael@0: d.w = b.parentElement.clientWidth; michael@0: d.h = b.parentElement.clientHeight; michael@0: } else if (b && b.clientWidth) { michael@0: d.w = b.clientWidth; michael@0: d.h = b.clientHeight; michael@0: } michael@0: return d; michael@0: }, michael@0: michael@0: /** @id MochiKit.Style.getViewportPosition */ michael@0: getViewportPosition: function () { michael@0: var c = new MochiKit.Style.Coordinates(0, 0); michael@0: var d = MochiKit.DOM._document; michael@0: var de = d.documentElement; michael@0: var db = d.body; michael@0: if (de && (de.scrollTop || de.scrollLeft)) { michael@0: c.x = de.scrollLeft; michael@0: c.y = de.scrollTop; michael@0: } else if (db) { michael@0: c.x = db.scrollLeft; michael@0: c.y = db.scrollTop; michael@0: } michael@0: return c; michael@0: }, michael@0: michael@0: __new__: function () { michael@0: var m = MochiKit.Base; michael@0: michael@0: var inlines = ['A','ABBR','ACRONYM','B','BASEFONT','BDO','BIG','BR', michael@0: 'CITE','CODE','DFN','EM','FONT','I','IMG','KBD','LABEL', michael@0: 'Q','S','SAMP','SMALL','SPAN','STRIKE','STRONG','SUB', michael@0: 'SUP','TEXTAREA','TT','U','VAR']; michael@0: this._defaultDisplay = { 'TABLE': 'table', michael@0: 'THEAD': 'table-header-group', michael@0: 'TBODY': 'table-row-group', michael@0: 'TFOOT': 'table-footer-group', michael@0: 'COLGROUP': 'table-column-group', michael@0: 'COL': 'table-column', michael@0: 'TR': 'table-row', michael@0: 'TD': 'table-cell', michael@0: 'TH': 'table-cell', michael@0: 'CAPTION': 'table-caption', michael@0: 'LI': 'list-item', michael@0: 'INPUT': 'inline-block', michael@0: 'SELECT': 'inline-block' }; michael@0: // CSS 'display' support in IE6/7 is just broken... michael@0: if (/MSIE/.test(navigator.userAgent)) { michael@0: for (var k in this._defaultDisplay) { michael@0: var v = this._defaultDisplay[k]; michael@0: if (v.indexOf('table') == 0) { michael@0: this._defaultDisplay[k] = 'block'; michael@0: } michael@0: } michael@0: } michael@0: for (var i = 0; i < inlines.length; i++) { michael@0: this._defaultDisplay[inlines[i]] = 'inline'; michael@0: } michael@0: michael@0: this.elementPosition = this.getElementPosition; michael@0: this.elementDimensions = this.getElementDimensions; michael@0: michael@0: this.hideElement = m.partial(this.setDisplayForElement, 'none'); michael@0: // TODO: showElement could be improved by using getDefaultDisplay. michael@0: this.showElement = m.partial(this.setDisplayForElement, 'block'); michael@0: michael@0: this.EXPORT_TAGS = { michael@0: ':common': this.EXPORT, michael@0: ':all': m.concat(this.EXPORT, this.EXPORT_OK) michael@0: }; michael@0: michael@0: m.nameFunctions(this); michael@0: } michael@0: }); michael@0: michael@0: MochiKit.Style.__new__(); michael@0: MochiKit.Base._exportSymbols(this, MochiKit.Style);