UNPKG

can

Version:

MIT-licensed, client-side, JavaScript framework that makes building rich web applications easy.

269 lines (223 loc) 8.73 kB
/* --- name: Element.Style description: Contains methods for interacting with the styles of Elements in a fashionable way. license: MIT-style license. requires: Element provides: Element.Style ... */ (function(){ var html = document.html, el; //<ltIE9> // Check for oldIE, which does not remove styles when they're set to null el = document.createElement('div'); el.style.color = 'red'; el.style.color = null; var doesNotRemoveStyles = el.style.color == 'red'; // check for oldIE, which returns border* shorthand styles in the wrong order (color-width-style instead of width-style-color) var border = '1px solid #123abc'; el.style.border = border; var returnsBordersInWrongOrder = el.style.border != border; el = null; //</ltIE9> var hasGetComputedStyle = !!window.getComputedStyle, supportBorderRadius = document.createElement('div').style.borderRadius != null; Element.Properties.styles = {set: function(styles){ this.setStyles(styles); }}; var hasOpacity = (html.style.opacity != null), hasFilter = (html.style.filter != null), reAlpha = /alpha\(opacity=([\d.]+)\)/i; var setVisibility = function(element, opacity){ element.store('$opacity', opacity); element.style.visibility = opacity > 0 || opacity == null ? 'visible' : 'hidden'; }; //<ltIE9> var setFilter = function(element, regexp, value){ var style = element.style, filter = style.filter || element.getComputedStyle('filter') || ''; style.filter = (regexp.test(filter) ? filter.replace(regexp, value) : filter + ' ' + value).trim(); if (!style.filter) style.removeAttribute('filter'); }; //</ltIE9> var setOpacity = (hasOpacity ? function(element, opacity){ element.style.opacity = opacity; } : (hasFilter ? function(element, opacity){ if (!element.currentStyle || !element.currentStyle.hasLayout) element.style.zoom = 1; if (opacity == null || opacity == 1){ setFilter(element, reAlpha, ''); if (opacity == 1 && getOpacity(element) != 1) setFilter(element, reAlpha, 'alpha(opacity=100)'); } else { setFilter(element, reAlpha, 'alpha(opacity=' + (opacity * 100).limit(0, 100).round() + ')'); } } : setVisibility)); var getOpacity = (hasOpacity ? function(element){ var opacity = element.style.opacity || element.getComputedStyle('opacity'); return (opacity == '') ? 1 : opacity.toFloat(); } : (hasFilter ? function(element){ var filter = (element.style.filter || element.getComputedStyle('filter')), opacity; if (filter) opacity = filter.match(reAlpha); return (opacity == null || filter == null) ? 1 : (opacity[1] / 100); } : function(element){ var opacity = element.retrieve('$opacity'); if (opacity == null) opacity = (element.style.visibility == 'hidden' ? 0 : 1); return opacity; })); var floatName = (html.style.cssFloat == null) ? 'styleFloat' : 'cssFloat', namedPositions = {left: '0%', top: '0%', center: '50%', right: '100%', bottom: '100%'}, hasBackgroundPositionXY = (html.style.backgroundPositionX != null), prefixPattern = /^-(ms)-/; var camelCase = function(property){ return property.replace(prefixPattern, '$1-').camelCase(); } //<ltIE9> var removeStyle = function(style, property){ if (property == 'backgroundPosition'){ style.removeAttribute(property + 'X'); property += 'Y'; } style.removeAttribute(property); }; //</ltIE9> Element.implement({ getComputedStyle: function(property){ if (!hasGetComputedStyle && this.currentStyle) return this.currentStyle[camelCase(property)]; var defaultView = Element.getDocument(this).defaultView, computed = defaultView ? defaultView.getComputedStyle(this, null) : null; return (computed) ? computed.getPropertyValue((property == floatName) ? 'float' : property.hyphenate()) : ''; }, setStyle: function(property, value){ if (property == 'opacity'){ if (value != null) value = parseFloat(value); setOpacity(this, value); return this; } property = camelCase(property == 'float' ? floatName : property); if (typeOf(value) != 'string'){ var map = (Element.Styles[property] || '@').split(' '); value = Array.from(value).map(function(val, i){ if (!map[i]) return ''; return (typeOf(val) == 'number') ? map[i].replace('@', Math.round(val)) : val; }).join(' '); } else if (value == String(Number(value))){ value = Math.round(value); } this.style[property] = value; //<ltIE9> if ((value == '' || value == null) && doesNotRemoveStyles && this.style.removeAttribute){ removeStyle(this.style, property); } //</ltIE9> return this; }, getStyle: function(property){ if (property == 'opacity') return getOpacity(this); property = camelCase(property == 'float' ? floatName : property); if (supportBorderRadius && property.indexOf('borderRadius') != -1){ return ['borderTopLeftRadius', 'borderTopRightRadius', 'borderBottomRightRadius', 'borderBottomLeftRadius'].map(function(corner){ return this.style[corner] || '0px'; }, this).join(' '); } var result = this.style[property]; if (!result || property == 'zIndex'){ if (Element.ShortStyles.hasOwnProperty(property)){ result = []; for (var s in Element.ShortStyles[property]) result.push(this.getStyle(s)); return result.join(' '); } result = this.getComputedStyle(property); } if (hasBackgroundPositionXY && /^backgroundPosition[XY]?$/.test(property)){ return result.replace(/(top|right|bottom|left)/g, function(position){ return namedPositions[position]; }) || '0px'; } if (!result && property == 'backgroundPosition') return '0px 0px'; if (result){ result = String(result); var color = result.match(/rgba?\([\d\s,]+\)/); if (color) result = result.replace(color[0], color[0].rgbToHex()); } if (!hasGetComputedStyle && !this.style[property]){ if ((/^(height|width)$/).test(property) && !(/px$/.test(result))){ var values = (property == 'width') ? ['left', 'right'] : ['top', 'bottom'], size = 0; values.each(function(value){ size += this.getStyle('border-' + value + '-width').toInt() + this.getStyle('padding-' + value).toInt(); }, this); return this['offset' + property.capitalize()] - size + 'px'; } if ((/^border(.+)Width|margin|padding/).test(property) && isNaN(parseFloat(result))){ return '0px'; } } //<ltIE9> if (returnsBordersInWrongOrder && /^border(Top|Right|Bottom|Left)?$/.test(property) && /^#/.test(result)){ return result.replace(/^(.+)\s(.+)\s(.+)$/, '$2 $3 $1'); } //</ltIE9> return result; }, setStyles: function(styles){ for (var style in styles) this.setStyle(style, styles[style]); return this; }, getStyles: function(){ var result = {}; Array.flatten(arguments).each(function(key){ result[key] = this.getStyle(key); }, this); return result; } }); Element.Styles = { left: '@px', top: '@px', bottom: '@px', right: '@px', width: '@px', height: '@px', maxWidth: '@px', maxHeight: '@px', minWidth: '@px', minHeight: '@px', backgroundColor: 'rgb(@, @, @)', backgroundSize: '@px', backgroundPosition: '@px @px', color: 'rgb(@, @, @)', fontSize: '@px', letterSpacing: '@px', lineHeight: '@px', clip: 'rect(@px @px @px @px)', margin: '@px @px @px @px', padding: '@px @px @px @px', border: '@px @ rgb(@, @, @) @px @ rgb(@, @, @) @px @ rgb(@, @, @)', borderWidth: '@px @px @px @px', borderStyle: '@ @ @ @', borderColor: 'rgb(@, @, @) rgb(@, @, @) rgb(@, @, @) rgb(@, @, @)', zIndex: '@', 'zoom': '@', fontWeight: '@', textIndent: '@px', opacity: '@', borderRadius: '@px @px @px @px' }; //<1.3compat> Element.implement({ setOpacity: function(value){ setOpacity(this, value); return this; }, getOpacity: function(){ return getOpacity(this); } }); Element.Properties.opacity = { set: function(opacity){ setOpacity(this, opacity); setVisibility(this, opacity); }, get: function(){ return getOpacity(this); } }; //</1.3compat> //<1.2compat> Element.Styles = new Hash(Element.Styles); //</1.2compat> Element.ShortStyles = {margin: {}, padding: {}, border: {}, borderWidth: {}, borderStyle: {}, borderColor: {}}; ['Top', 'Right', 'Bottom', 'Left'].each(function(direction){ var Short = Element.ShortStyles; var All = Element.Styles; ['margin', 'padding'].each(function(style){ var sd = style + direction; Short[style][sd] = All[sd] = '@px'; }); var bd = 'border' + direction; Short.border[bd] = All[bd] = '@px @ rgb(@, @, @)'; var bdw = bd + 'Width', bds = bd + 'Style', bdc = bd + 'Color'; Short[bd] = {}; Short.borderWidth[bdw] = Short[bd][bdw] = All[bdw] = '@px'; Short.borderStyle[bds] = Short[bd][bds] = All[bds] = '@'; Short.borderColor[bdc] = Short[bd][bdc] = All[bdc] = 'rgb(@, @, @)'; }); if (hasBackgroundPositionXY) Element.ShortStyles.backgroundPosition = {backgroundPositionX: '@', backgroundPositionY: '@'}; })();