1234567891011121314151617181920212223242526272829303132333435363738394041424344454647484950515253545556575859606162636465666768697071727374757677787980818283848586878889909192939495969798991001011021031041051061071081091101111121131141151161171181191201211221231241251261271281291301311321331341351361371381391401411421431441451461471481491501511521531541551561571581591601611621631641651661671681691701711721731741751761771781791801811821831841851861871881891901911921931941951961971981992002012022032042052062072082092102112122132142152162172182192202212222232242252262272282292302312322332342352362372382392402412422432442452462472482492502512522532542552562572582592602612622632642652662672682692702712722732742752762772782792802812822832842852862872882892902912922932942952962972982993003013023033043053063073083093103113123133143153163173183193203213223233243253263273283293303313323333343353363373383393403413423433443453463473483493503513523533543553563573583593603613623633643653663673683693703713723733743753763773783793803813823833843853863873883893903913923933943953963973983994004014024034044054064074084094104114124134144154164174184194204214224234244254264274284294304314324334344354364374384394404414424434444454464474484494504514524534544554564574584594604614624634644654664674684694704714724734744754764774784794804814824834844854864874884894904914924934944954964974984995005015025035045055065075085095105115125135145155165175185195205215225235245255265275285295305315325335345355365375385395405415425435445455465475485495505515525535545555565575585595605615625635645655665675685695705715725735745755765775785795805815825835845855865875885895905915925935945955965975985996006016026036046056066076086096106116126136146156166176186196206216226236246256266276286296306316326336346356366376386396406416426436446456466476486496506516526536546556566576586596606616626636646656666676686696706716726736746756766776786796806816826836846856866876886896906916926936946956966976986997007017027037047057067077087097107117127137147157167177187197207217227237247257267277287297307317327337347357367377387397407417427437447457467477487497507517527537547557567577587597607617627637647657667677687697707717727737747757767777787797807817827837847857867877887897907917927937947957967977987998008018028038048058068078088098108118128138148158168178188198208218228238248258268278288298308318328338348358368378388398408418428438448458468478488498508518528538548558568578588598608618628638648658668678688698708718728738748758768778788798808818828838848858868878888898908918928938948958968978988999009019029039049059069079089099109119129139149159169179189199209219229239249259269279289299309319329339349359369379389399409419429439449459469479489499509519529539549559569579589599609619629639649659669679689699709719729739749759769779789799809819829839849859869879889899909919929939949959969979989991000100110021003100410051006100710081009101010111012101310141015101610171018101910201021102210231024102510261027102810291030103110321033103410351036103710381039104010411042104310441045104610471048104910501051105210531054105510561057105810591060106110621063106410651066106710681069107010711072107310741075107610771078107910801081108210831084108510861087108810891090109110921093109410951096109710981099110011011102110311041105110611071108110911101111111211131114111511161117111811191120112111221123112411251126112711281129113011311132113311341135113611371138113911401141114211431144114511461147114811491150115111521153115411551156115711581159116011611162116311641165116611671168116911701171117211731174117511761177117811791180118111821183118411851186118711881189119011911192119311941195119611971198119912001201120212031204120512061207120812091210121112121213121412151216121712181219122012211222122312241225122612271228122912301231123212331234123512361237123812391240124112421243124412451246124712481249125012511252125312541255125612571258125912601261126212631264126512661267126812691270127112721273127412751276127712781279128012811282128312841285128612871288128912901291129212931294129512961297129812991300130113021303130413051306130713081309131013111312131313141315131613171318131913201321132213231324132513261327132813291330133113321333133413351336133713381339134013411342134313441345134613471348134913501351135213531354135513561357135813591360136113621363136413651366136713681369137013711372137313741375137613771378137913801381138213831384138513861387138813891390139113921393139413951396139713981399140014011402140314041405140614071408140914101411141214131414141514161417141814191420142114221423142414251426142714281429143014311432143314341435143614371438143914401441144214431444144514461447144814491450145114521453145414551456145714581459146014611462146314641465146614671468146914701471147214731474147514761477147814791480148114821483148414851486148714881489149014911492149314941495149614971498149915001501150215031504150515061507150815091510151115121513151415151516151715181519152015211522152315241525152615271528152915301531153215331534153515361537153815391540154115421543154415451546154715481549155015511552155315541555155615571558155915601561156215631564156515661567156815691570157115721573157415751576157715781579158015811582158315841585158615871588158915901591159215931594159515961597159815991600160116021603160416051606160716081609161016111612161316141615161616171618161916201621162216231624162516261627162816291630163116321633163416351636163716381639164016411642164316441645164616471648164916501651165216531654165516561657165816591660166116621663166416651666166716681669167016711672167316741675167616771678167916801681168216831684168516861687168816891690169116921693169416951696169716981699170017011702170317041705170617071708170917101711171217131714171517161717171817191720172117221723172417251726172717281729173017311732173317341735173617371738173917401741174217431744174517461747174817491750175117521753175417551756175717581759176017611762176317641765176617671768176917701771177217731774177517761777177817791780178117821783178417851786178717881789179017911792179317941795179617971798179918001801180218031804180518061807180818091810181118121813181418151816181718181819182018211822182318241825182618271828182918301831183218331834183518361837183818391840184118421843184418451846184718481849185018511852185318541855185618571858185918601861186218631864186518661867186818691870187118721873187418751876187718781879188018811882188318841885188618871888188918901891189218931894189518961897189818991900190119021903190419051906190719081909191019111912191319141915191619171918191919201921192219231924192519261927192819291930193119321933193419351936193719381939194019411942194319441945194619471948194919501951195219531954195519561957195819591960196119621963196419651966196719681969197019711972197319741975197619771978197919801981198219831984198519861987198819891990199119921993199419951996199719981999200020012002200320042005200620072008200920102011201220132014201520162017201820192020202120222023202420252026202720282029203020312032203320342035203620372038203920402041204220432044204520462047204820492050205120522053205420552056205720582059206020612062206320642065206620672068206920702071 |
- // Copyright 2006 The Closure Library Authors. All Rights Reserved.
- //
- // Licensed under the Apache License, Version 2.0 (the "License");
- // you may not use this file except in compliance with the License.
- // You may obtain a copy of the License at
- //
- // http://www.apache.org/licenses/LICENSE-2.0
- //
- // Unless required by applicable law or agreed to in writing, software
- // distributed under the License is distributed on an "AS-IS" BASIS,
- // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- // See the License for the specific language governing permissions and
- // limitations under the License.
- /**
- * @fileoverview Utilities for element styles.
- *
- * @author arv@google.com (Erik Arvidsson)
- * @author eae@google.com (Emil A Eklund)
- * @see ../demos/inline_block_quirks.html
- * @see ../demos/inline_block_standards.html
- * @see ../demos/style_viewport.html
- */
- goog.provide('goog.style');
- goog.require('goog.array');
- goog.require('goog.asserts');
- goog.require('goog.dom');
- goog.require('goog.dom.NodeType');
- goog.require('goog.dom.TagName');
- goog.require('goog.dom.vendor');
- goog.require('goog.html.SafeStyleSheet');
- goog.require('goog.html.legacyconversions');
- goog.require('goog.math.Box');
- goog.require('goog.math.Coordinate');
- goog.require('goog.math.Rect');
- goog.require('goog.math.Size');
- goog.require('goog.object');
- goog.require('goog.reflect');
- goog.require('goog.string');
- goog.require('goog.userAgent');
- goog.forwardDeclare('goog.events.Event');
- /**
- * Sets a style value on an element.
- *
- * This function is not indended to patch issues in the browser's style
- * handling, but to allow easy programmatic access to setting dash-separated
- * style properties. An example is setting a batch of properties from a data
- * object without overwriting old styles. When possible, use native APIs:
- * elem.style.propertyKey = 'value' or (if obliterating old styles is fine)
- * elem.style.cssText = 'property1: value1; property2: value2'.
- *
- * @param {Element} element The element to change.
- * @param {string|Object} style If a string, a style name. If an object, a hash
- * of style names to style values.
- * @param {string|number|boolean=} opt_value If style was a string, then this
- * should be the value.
- */
- goog.style.setStyle = function(element, style, opt_value) {
- if (goog.isString(style)) {
- goog.style.setStyle_(element, opt_value, style);
- } else {
- for (var key in style) {
- goog.style.setStyle_(element, style[key], key);
- }
- }
- };
- /**
- * Sets a style value on an element, with parameters swapped to work with
- * {@code goog.object.forEach()}. Prepends a vendor-specific prefix when
- * necessary.
- * @param {Element} element The element to change.
- * @param {string|number|boolean|undefined} value Style value.
- * @param {string} style Style name.
- * @private
- */
- goog.style.setStyle_ = function(element, value, style) {
- var propertyName = goog.style.getVendorJsStyleName_(element, style);
- if (propertyName) {
- // TODO(johnlenz): coerce to string?
- element.style[propertyName] = /** @type {?} */ (value);
- }
- };
- /**
- * Style name cache that stores previous property name lookups.
- *
- * This is used by setStyle to speed up property lookups, entries look like:
- * { StyleName: ActualPropertyName }
- *
- * @private {!Object<string, string>}
- */
- goog.style.styleNameCache_ = {};
- /**
- * Returns the style property name in camel-case. If it does not exist and a
- * vendor-specific version of the property does exist, then return the vendor-
- * specific property name instead.
- * @param {Element} element The element to change.
- * @param {string} style Style name.
- * @return {string} Vendor-specific style.
- * @private
- */
- goog.style.getVendorJsStyleName_ = function(element, style) {
- var propertyName = goog.style.styleNameCache_[style];
- if (!propertyName) {
- var camelStyle = goog.string.toCamelCase(style);
- propertyName = camelStyle;
- if (element.style[camelStyle] === undefined) {
- var prefixedStyle = goog.dom.vendor.getVendorJsPrefix() +
- goog.string.toTitleCase(camelStyle);
- if (element.style[prefixedStyle] !== undefined) {
- propertyName = prefixedStyle;
- }
- }
- goog.style.styleNameCache_[style] = propertyName;
- }
- return propertyName;
- };
- /**
- * Returns the style property name in CSS notation. If it does not exist and a
- * vendor-specific version of the property does exist, then return the vendor-
- * specific property name instead.
- * @param {Element} element The element to change.
- * @param {string} style Style name.
- * @return {string} Vendor-specific style.
- * @private
- */
- goog.style.getVendorStyleName_ = function(element, style) {
- var camelStyle = goog.string.toCamelCase(style);
- if (element.style[camelStyle] === undefined) {
- var prefixedStyle = goog.dom.vendor.getVendorJsPrefix() +
- goog.string.toTitleCase(camelStyle);
- if (element.style[prefixedStyle] !== undefined) {
- return goog.dom.vendor.getVendorPrefix() + '-' + style;
- }
- }
- return style;
- };
- /**
- * Retrieves an explicitly-set style value of a node. This returns '' if there
- * isn't a style attribute on the element or if this style property has not been
- * explicitly set in script.
- *
- * @param {Element} element Element to get style of.
- * @param {string} property Property to get, css-style (if you have a camel-case
- * property, use element.style[style]).
- * @return {string} Style value.
- */
- goog.style.getStyle = function(element, property) {
- // element.style is '' for well-known properties which are unset.
- // For for browser specific styles as 'filter' is undefined
- // so we need to return '' explicitly to make it consistent across
- // browsers.
- var styleValue = element.style[goog.string.toCamelCase(property)];
- // Using typeof here because of a bug in Safari 5.1, where this value
- // was undefined, but === undefined returned false.
- if (typeof(styleValue) !== 'undefined') {
- return styleValue;
- }
- return element.style[goog.style.getVendorJsStyleName_(element, property)] ||
- '';
- };
- /**
- * Retrieves a computed style value of a node. It returns empty string if the
- * value cannot be computed (which will be the case in Internet Explorer) or
- * "none" if the property requested is an SVG one and it has not been
- * explicitly set (firefox and webkit).
- *
- * @param {Element} element Element to get style of.
- * @param {string} property Property to get (camel-case).
- * @return {string} Style value.
- */
- goog.style.getComputedStyle = function(element, property) {
- var doc = goog.dom.getOwnerDocument(element);
- if (doc.defaultView && doc.defaultView.getComputedStyle) {
- var styles = doc.defaultView.getComputedStyle(element, null);
- if (styles) {
- // element.style[..] is undefined for browser specific styles
- // as 'filter'.
- return styles[property] || styles.getPropertyValue(property) || '';
- }
- }
- return '';
- };
- /**
- * Gets the cascaded style value of a node, or null if the value cannot be
- * computed (only Internet Explorer can do this).
- *
- * @param {Element} element Element to get style of.
- * @param {string} style Property to get (camel-case).
- * @return {string} Style value.
- */
- goog.style.getCascadedStyle = function(element, style) {
- // TODO(nicksantos): This should be documented to return null. #fixTypes
- return /** @type {string} */ (
- element.currentStyle ? element.currentStyle[style] : null);
- };
- /**
- * Cross-browser pseudo get computed style. It returns the computed style where
- * available. If not available it tries the cascaded style value (IE
- * currentStyle) and in worst case the inline style value. It shouldn't be
- * called directly, see http://wiki/Main/ComputedStyleVsCascadedStyle for
- * discussion.
- *
- * @param {Element} element Element to get style of.
- * @param {string} style Property to get (must be camelCase, not css-style.).
- * @return {string} Style value.
- * @private
- */
- goog.style.getStyle_ = function(element, style) {
- return goog.style.getComputedStyle(element, style) ||
- goog.style.getCascadedStyle(element, style) ||
- (element.style && element.style[style]);
- };
- /**
- * Retrieves the computed value of the box-sizing CSS attribute.
- * Browser support: http://caniuse.com/css3-boxsizing.
- * @param {!Element} element The element whose box-sizing to get.
- * @return {?string} 'content-box', 'border-box' or 'padding-box'. null if
- * box-sizing is not supported (IE7 and below).
- */
- goog.style.getComputedBoxSizing = function(element) {
- return goog.style.getStyle_(element, 'boxSizing') ||
- goog.style.getStyle_(element, 'MozBoxSizing') ||
- goog.style.getStyle_(element, 'WebkitBoxSizing') || null;
- };
- /**
- * Retrieves the computed value of the position CSS attribute.
- * @param {Element} element The element to get the position of.
- * @return {string} Position value.
- */
- goog.style.getComputedPosition = function(element) {
- return goog.style.getStyle_(element, 'position');
- };
- /**
- * Retrieves the computed background color string for a given element. The
- * string returned is suitable for assigning to another element's
- * background-color, but is not guaranteed to be in any particular string
- * format. Accessing the color in a numeric form may not be possible in all
- * browsers or with all input.
- *
- * If the background color for the element is defined as a hexadecimal value,
- * the resulting string can be parsed by goog.color.parse in all supported
- * browsers.
- *
- * Whether named colors like "red" or "lightblue" get translated into a
- * format which can be parsed is browser dependent. Calling this function on
- * transparent elements will return "transparent" in most browsers or
- * "rgba(0, 0, 0, 0)" in WebKit.
- * @param {Element} element The element to get the background color of.
- * @return {string} The computed string value of the background color.
- */
- goog.style.getBackgroundColor = function(element) {
- return goog.style.getStyle_(element, 'backgroundColor');
- };
- /**
- * Retrieves the computed value of the overflow-x CSS attribute.
- * @param {Element} element The element to get the overflow-x of.
- * @return {string} The computed string value of the overflow-x attribute.
- */
- goog.style.getComputedOverflowX = function(element) {
- return goog.style.getStyle_(element, 'overflowX');
- };
- /**
- * Retrieves the computed value of the overflow-y CSS attribute.
- * @param {Element} element The element to get the overflow-y of.
- * @return {string} The computed string value of the overflow-y attribute.
- */
- goog.style.getComputedOverflowY = function(element) {
- return goog.style.getStyle_(element, 'overflowY');
- };
- /**
- * Retrieves the computed value of the z-index CSS attribute.
- * @param {Element} element The element to get the z-index of.
- * @return {string|number} The computed value of the z-index attribute.
- */
- goog.style.getComputedZIndex = function(element) {
- return goog.style.getStyle_(element, 'zIndex');
- };
- /**
- * Retrieves the computed value of the text-align CSS attribute.
- * @param {Element} element The element to get the text-align of.
- * @return {string} The computed string value of the text-align attribute.
- */
- goog.style.getComputedTextAlign = function(element) {
- return goog.style.getStyle_(element, 'textAlign');
- };
- /**
- * Retrieves the computed value of the cursor CSS attribute.
- * @param {Element} element The element to get the cursor of.
- * @return {string} The computed string value of the cursor attribute.
- */
- goog.style.getComputedCursor = function(element) {
- return goog.style.getStyle_(element, 'cursor');
- };
- /**
- * Retrieves the computed value of the CSS transform attribute.
- * @param {Element} element The element to get the transform of.
- * @return {string} The computed string representation of the transform matrix.
- */
- goog.style.getComputedTransform = function(element) {
- var property = goog.style.getVendorStyleName_(element, 'transform');
- return goog.style.getStyle_(element, property) ||
- goog.style.getStyle_(element, 'transform');
- };
- /**
- * Sets the top/left values of an element. If no unit is specified in the
- * argument then it will add px. The second argument is required if the first
- * argument is a string or number and is ignored if the first argument
- * is a coordinate.
- * @param {Element} el Element to move.
- * @param {string|number|goog.math.Coordinate} arg1 Left position or coordinate.
- * @param {string|number=} opt_arg2 Top position.
- */
- goog.style.setPosition = function(el, arg1, opt_arg2) {
- var x, y;
- if (arg1 instanceof goog.math.Coordinate) {
- x = arg1.x;
- y = arg1.y;
- } else {
- x = arg1;
- y = opt_arg2;
- }
- el.style.left = goog.style.getPixelStyleValue_(
- /** @type {number|string} */ (x), false);
- el.style.top = goog.style.getPixelStyleValue_(
- /** @type {number|string} */ (y), false);
- };
- /**
- * Gets the offsetLeft and offsetTop properties of an element and returns them
- * in a Coordinate object
- * @param {Element} element Element.
- * @return {!goog.math.Coordinate} The position.
- */
- goog.style.getPosition = function(element) {
- return new goog.math.Coordinate(
- /** @type {!HTMLElement} */ (element).offsetLeft,
- /** @type {!HTMLElement} */ (element).offsetTop);
- };
- /**
- * Returns the viewport element for a particular document
- * @param {Node=} opt_node DOM node (Document is OK) to get the viewport element
- * of.
- * @return {Element} document.documentElement or document.body.
- */
- goog.style.getClientViewportElement = function(opt_node) {
- var doc;
- if (opt_node) {
- doc = goog.dom.getOwnerDocument(opt_node);
- } else {
- doc = goog.dom.getDocument();
- }
- // In old IE versions the document.body represented the viewport
- if (goog.userAgent.IE && !goog.userAgent.isDocumentModeOrHigher(9) &&
- !goog.dom.getDomHelper(doc).isCss1CompatMode()) {
- return doc.body;
- }
- return doc.documentElement;
- };
- /**
- * Calculates the viewport coordinates relative to the page/document
- * containing the node. The viewport may be the browser viewport for
- * non-iframe document, or the iframe container for iframe'd document.
- * @param {!Document} doc The document to use as the reference point.
- * @return {!goog.math.Coordinate} The page offset of the viewport.
- */
- goog.style.getViewportPageOffset = function(doc) {
- var body = doc.body;
- var documentElement = doc.documentElement;
- var scrollLeft = body.scrollLeft || documentElement.scrollLeft;
- var scrollTop = body.scrollTop || documentElement.scrollTop;
- return new goog.math.Coordinate(scrollLeft, scrollTop);
- };
- /**
- * Gets the client rectangle of the DOM element.
- *
- * getBoundingClientRect is part of a new CSS object model draft (with a
- * long-time presence in IE), replacing the error-prone parent offset
- * computation and the now-deprecated Gecko getBoxObjectFor.
- *
- * This utility patches common browser bugs in getBoundingClientRect. It
- * will fail if getBoundingClientRect is unsupported.
- *
- * If the element is not in the DOM, the result is undefined, and an error may
- * be thrown depending on user agent.
- *
- * @param {!Element} el The element whose bounding rectangle is being queried.
- * @return {Object} A native bounding rectangle with numerical left, top,
- * right, and bottom. Reported by Firefox to be of object type ClientRect.
- * @private
- */
- goog.style.getBoundingClientRect_ = function(el) {
- var rect;
- try {
- rect = el.getBoundingClientRect();
- } catch (e) {
- // In IE < 9, calling getBoundingClientRect on an orphan element raises an
- // "Unspecified Error". All other browsers return zeros.
- return {'left': 0, 'top': 0, 'right': 0, 'bottom': 0};
- }
- // Patch the result in IE only, so that this function can be inlined if
- // compiled for non-IE.
- if (goog.userAgent.IE && el.ownerDocument.body) {
- // In IE, most of the time, 2 extra pixels are added to the top and left
- // due to the implicit 2-pixel inset border. In IE6/7 quirks mode and
- // IE6 standards mode, this border can be overridden by setting the
- // document element's border to zero -- thus, we cannot rely on the
- // offset always being 2 pixels.
- // In quirks mode, the offset can be determined by querying the body's
- // clientLeft/clientTop, but in standards mode, it is found by querying
- // the document element's clientLeft/clientTop. Since we already called
- // getBoundingClientRect we have already forced a reflow, so it is not
- // too expensive just to query them all.
- // See: http://msdn.microsoft.com/en-us/library/ms536433(VS.85).aspx
- var doc = el.ownerDocument;
- rect.left -= doc.documentElement.clientLeft + doc.body.clientLeft;
- rect.top -= doc.documentElement.clientTop + doc.body.clientTop;
- }
- return rect;
- };
- /**
- * Returns the first parent that could affect the position of a given element.
- * @param {Element} element The element to get the offset parent for.
- * @return {Element} The first offset parent or null if one cannot be found.
- */
- goog.style.getOffsetParent = function(element) {
- // element.offsetParent does the right thing in IE7 and below. In other
- // browsers it only includes elements with position absolute, relative or
- // fixed, not elements with overflow set to auto or scroll.
- if (goog.userAgent.IE && !goog.userAgent.isDocumentModeOrHigher(8)) {
- goog.asserts.assert(element && 'offsetParent' in element);
- return element.offsetParent;
- }
- var doc = goog.dom.getOwnerDocument(element);
- var positionStyle = goog.style.getStyle_(element, 'position');
- var skipStatic = positionStyle == 'fixed' || positionStyle == 'absolute';
- for (var parent = element.parentNode; parent && parent != doc;
- parent = parent.parentNode) {
- // Skip shadowDOM roots.
- if (parent.nodeType == goog.dom.NodeType.DOCUMENT_FRAGMENT && parent.host) {
- parent = parent.host;
- }
- positionStyle =
- goog.style.getStyle_(/** @type {!Element} */ (parent), 'position');
- skipStatic = skipStatic && positionStyle == 'static' &&
- parent != doc.documentElement && parent != doc.body;
- if (!skipStatic &&
- (parent.scrollWidth > parent.clientWidth ||
- parent.scrollHeight > parent.clientHeight ||
- positionStyle == 'fixed' || positionStyle == 'absolute' ||
- positionStyle == 'relative')) {
- return /** @type {!Element} */ (parent);
- }
- }
- return null;
- };
- /**
- * Calculates and returns the visible rectangle for a given element. Returns a
- * box describing the visible portion of the nearest scrollable offset ancestor.
- * Coordinates are given relative to the document.
- *
- * @param {Element} element Element to get the visible rect for.
- * @return {goog.math.Box} Bounding elementBox describing the visible rect or
- * null if scrollable ancestor isn't inside the visible viewport.
- */
- goog.style.getVisibleRectForElement = function(element) {
- var visibleRect = new goog.math.Box(0, Infinity, Infinity, 0);
- var dom = goog.dom.getDomHelper(element);
- var body = dom.getDocument().body;
- var documentElement = dom.getDocument().documentElement;
- var scrollEl = dom.getDocumentScrollElement();
- // Determine the size of the visible rect by climbing the dom accounting for
- // all scrollable containers.
- for (var el = element; el = goog.style.getOffsetParent(el);) {
- // clientWidth is zero for inline block elements in IE.
- // on WEBKIT, body element can have clientHeight = 0 and scrollHeight > 0
- if ((!goog.userAgent.IE || el.clientWidth != 0) &&
- (!goog.userAgent.WEBKIT || el.clientHeight != 0 || el != body) &&
- // body may have overflow set on it, yet we still get the entire
- // viewport. In some browsers, el.offsetParent may be
- // document.documentElement, so check for that too.
- (el != body && el != documentElement &&
- goog.style.getStyle_(el, 'overflow') != 'visible')) {
- var pos = goog.style.getPageOffset(el);
- var client = goog.style.getClientLeftTop(el);
- pos.x += client.x;
- pos.y += client.y;
- visibleRect.top = Math.max(visibleRect.top, pos.y);
- visibleRect.right = Math.min(visibleRect.right, pos.x + el.clientWidth);
- visibleRect.bottom =
- Math.min(visibleRect.bottom, pos.y + el.clientHeight);
- visibleRect.left = Math.max(visibleRect.left, pos.x);
- }
- }
- // Clip by window's viewport.
- var scrollX = scrollEl.scrollLeft, scrollY = scrollEl.scrollTop;
- visibleRect.left = Math.max(visibleRect.left, scrollX);
- visibleRect.top = Math.max(visibleRect.top, scrollY);
- var winSize = dom.getViewportSize();
- visibleRect.right = Math.min(visibleRect.right, scrollX + winSize.width);
- visibleRect.bottom = Math.min(visibleRect.bottom, scrollY + winSize.height);
- return visibleRect.top >= 0 && visibleRect.left >= 0 &&
- visibleRect.bottom > visibleRect.top &&
- visibleRect.right > visibleRect.left ?
- visibleRect :
- null;
- };
- /**
- * Calculate the scroll position of {@code container} with the minimum amount so
- * that the content and the borders of the given {@code element} become visible.
- * If the element is bigger than the container, its top left corner will be
- * aligned as close to the container's top left corner as possible.
- *
- * @param {Element} element The element to make visible.
- * @param {Element=} opt_container The container to scroll. If not set, then the
- * document scroll element will be used.
- * @param {boolean=} opt_center Whether to center the element in the container.
- * Defaults to false.
- * @return {!goog.math.Coordinate} The new scroll position of the container,
- * in form of goog.math.Coordinate(scrollLeft, scrollTop).
- */
- goog.style.getContainerOffsetToScrollInto = function(
- element, opt_container, opt_center) {
- var container = opt_container || goog.dom.getDocumentScrollElement();
- // Absolute position of the element's border's top left corner.
- var elementPos = goog.style.getPageOffset(element);
- // Absolute position of the container's border's top left corner.
- var containerPos = goog.style.getPageOffset(container);
- var containerBorder = goog.style.getBorderBox(container);
- if (container == goog.dom.getDocumentScrollElement()) {
- // The element position is calculated based on the page offset, and the
- // document scroll element holds the scroll position within the page. We can
- // use the scroll position to calculate the relative position from the
- // element.
- var relX = elementPos.x - container.scrollLeft;
- var relY = elementPos.y - container.scrollTop;
- if (goog.userAgent.IE && !goog.userAgent.isDocumentModeOrHigher(10)) {
- // In older versions of IE getPageOffset(element) does not include the
- // container border so it has to be added to accommodate.
- relX += containerBorder.left;
- relY += containerBorder.top;
- }
- } else {
- // Relative pos. of the element's border box to the container's content box.
- var relX = elementPos.x - containerPos.x - containerBorder.left;
- var relY = elementPos.y - containerPos.y - containerBorder.top;
- }
- // How much the element can move in the container, i.e. the difference between
- // the element's bottom-right-most and top-left-most position where it's
- // fully visible.
- var elementSize = goog.style.getSizeWithDisplay_(element);
- var spaceX = container.clientWidth - elementSize.width;
- var spaceY = container.clientHeight - elementSize.height;
- var scrollLeft = container.scrollLeft;
- var scrollTop = container.scrollTop;
- if (opt_center) {
- // All browsers round non-integer scroll positions down.
- scrollLeft += relX - spaceX / 2;
- scrollTop += relY - spaceY / 2;
- } else {
- // This formula was designed to give the correct scroll values in the
- // following cases:
- // - element is higher than container (spaceY < 0) => scroll down by relY
- // - element is not higher that container (spaceY >= 0):
- // - it is above container (relY < 0) => scroll up by abs(relY)
- // - it is below container (relY > spaceY) => scroll down by relY - spaceY
- // - it is in the container => don't scroll
- scrollLeft += Math.min(relX, Math.max(relX - spaceX, 0));
- scrollTop += Math.min(relY, Math.max(relY - spaceY, 0));
- }
- return new goog.math.Coordinate(scrollLeft, scrollTop);
- };
- /**
- * Changes the scroll position of {@code container} with the minimum amount so
- * that the content and the borders of the given {@code element} become visible.
- * If the element is bigger than the container, its top left corner will be
- * aligned as close to the container's top left corner as possible.
- *
- * @param {Element} element The element to make visible.
- * @param {Element=} opt_container The container to scroll. If not set, then the
- * document scroll element will be used.
- * @param {boolean=} opt_center Whether to center the element in the container.
- * Defaults to false.
- */
- goog.style.scrollIntoContainerView = function(
- element, opt_container, opt_center) {
- var container = opt_container || goog.dom.getDocumentScrollElement();
- var offset =
- goog.style.getContainerOffsetToScrollInto(element, container, opt_center);
- container.scrollLeft = offset.x;
- container.scrollTop = offset.y;
- };
- /**
- * Returns clientLeft (width of the left border and, if the directionality is
- * right to left, the vertical scrollbar) and clientTop as a coordinate object.
- *
- * @param {Element} el Element to get clientLeft for.
- * @return {!goog.math.Coordinate} Client left and top.
- */
- goog.style.getClientLeftTop = function(el) {
- return new goog.math.Coordinate(el.clientLeft, el.clientTop);
- };
- /**
- * Returns a Coordinate object relative to the top-left of the HTML document.
- * Implemented as a single function to save having to do two recursive loops in
- * opera and safari just to get both coordinates. If you just want one value do
- * use goog.style.getPageOffsetLeft() and goog.style.getPageOffsetTop(), but
- * note if you call both those methods the tree will be analysed twice.
- *
- * @param {Element} el Element to get the page offset for.
- * @return {!goog.math.Coordinate} The page offset.
- */
- goog.style.getPageOffset = function(el) {
- var doc = goog.dom.getOwnerDocument(el);
- // TODO(gboyer): Update the jsdoc in a way that doesn't break the universe.
- goog.asserts.assertObject(el, 'Parameter is required');
- // NOTE(arv): If element is hidden (display none or disconnected or any the
- // ancestors are hidden) we get (0,0) by default but we still do the
- // accumulation of scroll position.
- // TODO(arv): Should we check if the node is disconnected and in that case
- // return (0,0)?
- var pos = new goog.math.Coordinate(0, 0);
- var viewportElement = goog.style.getClientViewportElement(doc);
- if (el == viewportElement) {
- // viewport is always at 0,0 as that defined the coordinate system for this
- // function - this avoids special case checks in the code below
- return pos;
- }
- var box = goog.style.getBoundingClientRect_(el);
- // Must add the scroll coordinates in to get the absolute page offset
- // of element since getBoundingClientRect returns relative coordinates to
- // the viewport.
- var scrollCoord = goog.dom.getDomHelper(doc).getDocumentScroll();
- pos.x = box.left + scrollCoord.x;
- pos.y = box.top + scrollCoord.y;
- return pos;
- };
- /**
- * Returns the left coordinate of an element relative to the HTML document
- * @param {Element} el Elements.
- * @return {number} The left coordinate.
- */
- goog.style.getPageOffsetLeft = function(el) {
- return goog.style.getPageOffset(el).x;
- };
- /**
- * Returns the top coordinate of an element relative to the HTML document
- * @param {Element} el Elements.
- * @return {number} The top coordinate.
- */
- goog.style.getPageOffsetTop = function(el) {
- return goog.style.getPageOffset(el).y;
- };
- /**
- * Returns a Coordinate object relative to the top-left of an HTML document
- * in an ancestor frame of this element. Used for measuring the position of
- * an element inside a frame relative to a containing frame.
- *
- * @param {Element} el Element to get the page offset for.
- * @param {Window} relativeWin The window to measure relative to. If relativeWin
- * is not in the ancestor frame chain of the element, we measure relative to
- * the top-most window.
- * @return {!goog.math.Coordinate} The page offset.
- */
- goog.style.getFramedPageOffset = function(el, relativeWin) {
- var position = new goog.math.Coordinate(0, 0);
- // Iterate up the ancestor frame chain, keeping track of the current window
- // and the current element in that window.
- var currentWin = goog.dom.getWindow(goog.dom.getOwnerDocument(el));
- // MS Edge throws when accessing "parent" if el's containing iframe has been
- // deleted.
- if (!goog.reflect.canAccessProperty(currentWin, 'parent')) {
- return position;
- }
- var currentEl = el;
- do {
- // if we're at the top window, we want to get the page offset.
- // if we're at an inner frame, we only want to get the window position
- // so that we can determine the actual page offset in the context of
- // the outer window.
- var offset = currentWin == relativeWin ?
- goog.style.getPageOffset(currentEl) :
- goog.style.getClientPositionForElement_(goog.asserts.assert(currentEl));
- position.x += offset.x;
- position.y += offset.y;
- } while (currentWin && currentWin != relativeWin &&
- currentWin != currentWin.parent &&
- (currentEl = currentWin.frameElement) &&
- (currentWin = currentWin.parent));
- return position;
- };
- /**
- * Translates the specified rect relative to origBase page, for newBase page.
- * If origBase and newBase are the same, this function does nothing.
- *
- * @param {goog.math.Rect} rect The source rectangle relative to origBase page,
- * and it will have the translated result.
- * @param {goog.dom.DomHelper} origBase The DomHelper for the input rectangle.
- * @param {goog.dom.DomHelper} newBase The DomHelper for the resultant
- * coordinate. This must be a DOM for an ancestor frame of origBase
- * or the same as origBase.
- */
- goog.style.translateRectForAnotherFrame = function(rect, origBase, newBase) {
- if (origBase.getDocument() != newBase.getDocument()) {
- var body = origBase.getDocument().body;
- var pos = goog.style.getFramedPageOffset(body, newBase.getWindow());
- // Adjust Body's margin.
- pos = goog.math.Coordinate.difference(pos, goog.style.getPageOffset(body));
- if (goog.userAgent.IE && !goog.userAgent.isDocumentModeOrHigher(9) &&
- !origBase.isCss1CompatMode()) {
- pos = goog.math.Coordinate.difference(pos, origBase.getDocumentScroll());
- }
- rect.left += pos.x;
- rect.top += pos.y;
- }
- };
- /**
- * Returns the position of an element relative to another element in the
- * document. A relative to B
- * @param {Element|Event|goog.events.Event} a Element or mouse event whose
- * position we're calculating.
- * @param {Element|Event|goog.events.Event} b Element or mouse event position
- * is relative to.
- * @return {!goog.math.Coordinate} The relative position.
- */
- goog.style.getRelativePosition = function(a, b) {
- var ap = goog.style.getClientPosition(a);
- var bp = goog.style.getClientPosition(b);
- return new goog.math.Coordinate(ap.x - bp.x, ap.y - bp.y);
- };
- /**
- * Returns the position of the event or the element's border box relative to
- * the client viewport.
- * @param {!Element} el Element whose position to get.
- * @return {!goog.math.Coordinate} The position.
- * @private
- */
- goog.style.getClientPositionForElement_ = function(el) {
- var box = goog.style.getBoundingClientRect_(el);
- return new goog.math.Coordinate(box.left, box.top);
- };
- /**
- * Returns the position of the event or the element's border box relative to
- * the client viewport. If an event is passed, and if this event is a "touch"
- * event, then the position of the first changedTouches will be returned.
- * @param {Element|Event|goog.events.Event} el Element or a mouse / touch event.
- * @return {!goog.math.Coordinate} The position.
- */
- goog.style.getClientPosition = function(el) {
- goog.asserts.assert(el);
- if (el.nodeType == goog.dom.NodeType.ELEMENT) {
- return goog.style.getClientPositionForElement_(
- /** @type {!Element} */ (el));
- } else {
- var targetEvent = el.changedTouches ? el.changedTouches[0] : el;
- return new goog.math.Coordinate(targetEvent.clientX, targetEvent.clientY);
- }
- };
- /**
- * Moves an element to the given coordinates relative to the client viewport.
- * @param {Element} el Absolutely positioned element to set page offset for.
- * It must be in the document.
- * @param {number|goog.math.Coordinate} x Left position of the element's margin
- * box or a coordinate object.
- * @param {number=} opt_y Top position of the element's margin box.
- */
- goog.style.setPageOffset = function(el, x, opt_y) {
- // Get current pageoffset
- var cur = goog.style.getPageOffset(el);
- if (x instanceof goog.math.Coordinate) {
- opt_y = x.y;
- x = x.x;
- }
- // NOTE(arv): We cannot allow strings for x and y. We could but that would
- // require us to manually transform between different units
- // Work out deltas
- var dx = goog.asserts.assertNumber(x) - cur.x;
- var dy = Number(opt_y) - cur.y;
- // Set position to current left/top + delta
- goog.style.setPosition(
- el, /** @type {!HTMLElement} */ (el).offsetLeft + dx,
- /** @type {!HTMLElement} */ (el).offsetTop + dy);
- };
- /**
- * Sets the width/height values of an element. If an argument is numeric,
- * or a goog.math.Size is passed, it is assumed to be pixels and will add
- * 'px' after converting it to an integer in string form. (This just sets the
- * CSS width and height properties so it might set content-box or border-box
- * size depending on the box model the browser is using.)
- *
- * @param {Element} element Element to set the size of.
- * @param {string|number|goog.math.Size} w Width of the element, or a
- * size object.
- * @param {string|number=} opt_h Height of the element. Required if w is not a
- * size object.
- */
- goog.style.setSize = function(element, w, opt_h) {
- var h;
- if (w instanceof goog.math.Size) {
- h = w.height;
- w = w.width;
- } else {
- if (opt_h == undefined) {
- throw Error('missing height argument');
- }
- h = opt_h;
- }
- goog.style.setWidth(element, /** @type {string|number} */ (w));
- goog.style.setHeight(element, h);
- };
- /**
- * Helper function to create a string to be set into a pixel-value style
- * property of an element. Can round to the nearest integer value.
- *
- * @param {string|number} value The style value to be used. If a number,
- * 'px' will be appended, otherwise the value will be applied directly.
- * @param {boolean} round Whether to round the nearest integer (if property
- * is a number).
- * @return {string} The string value for the property.
- * @private
- */
- goog.style.getPixelStyleValue_ = function(value, round) {
- if (typeof value == 'number') {
- value = (round ? Math.round(value) : value) + 'px';
- }
- return value;
- };
- /**
- * Set the height of an element. Sets the element's style property.
- * @param {Element} element Element to set the height of.
- * @param {string|number} height The height value to set. If a number, 'px'
- * will be appended, otherwise the value will be applied directly.
- */
- goog.style.setHeight = function(element, height) {
- element.style.height = goog.style.getPixelStyleValue_(height, true);
- };
- /**
- * Set the width of an element. Sets the element's style property.
- * @param {Element} element Element to set the width of.
- * @param {string|number} width The width value to set. If a number, 'px'
- * will be appended, otherwise the value will be applied directly.
- */
- goog.style.setWidth = function(element, width) {
- element.style.width = goog.style.getPixelStyleValue_(width, true);
- };
- /**
- * Gets the height and width of an element, even if its display is none.
- *
- * Specifically, this returns the height and width of the border box,
- * irrespective of the box model in effect.
- *
- * Note that this function does not take CSS transforms into account. Please see
- * {@code goog.style.getTransformedSize}.
- * @param {Element} element Element to get size of.
- * @return {!goog.math.Size} Object with width/height properties.
- */
- goog.style.getSize = function(element) {
- return goog.style.evaluateWithTemporaryDisplay_(
- goog.style.getSizeWithDisplay_, /** @type {!Element} */ (element));
- };
- /**
- * Call {@code fn} on {@code element} such that {@code element}'s dimensions are
- * accurate when it's passed to {@code fn}.
- * @param {function(!Element): T} fn Function to call with {@code element} as
- * an argument after temporarily changing {@code element}'s display such
- * that its dimensions are accurate.
- * @param {!Element} element Element (which may have display none) to use as
- * argument to {@code fn}.
- * @return {T} Value returned by calling {@code fn} with {@code element}.
- * @template T
- * @private
- */
- goog.style.evaluateWithTemporaryDisplay_ = function(fn, element) {
- if (goog.style.getStyle_(element, 'display') != 'none') {
- return fn(element);
- }
- var style = element.style;
- var originalDisplay = style.display;
- var originalVisibility = style.visibility;
- var originalPosition = style.position;
- style.visibility = 'hidden';
- style.position = 'absolute';
- style.display = 'inline';
- var retVal = fn(element);
- style.display = originalDisplay;
- style.position = originalPosition;
- style.visibility = originalVisibility;
- return retVal;
- };
- /**
- * Gets the height and width of an element when the display is not none.
- * @param {Element} element Element to get size of.
- * @return {!goog.math.Size} Object with width/height properties.
- * @private
- */
- goog.style.getSizeWithDisplay_ = function(element) {
- var offsetWidth = /** @type {!HTMLElement} */ (element).offsetWidth;
- var offsetHeight = /** @type {!HTMLElement} */ (element).offsetHeight;
- var webkitOffsetsZero =
- goog.userAgent.WEBKIT && !offsetWidth && !offsetHeight;
- if ((!goog.isDef(offsetWidth) || webkitOffsetsZero) &&
- element.getBoundingClientRect) {
- // Fall back to calling getBoundingClientRect when offsetWidth or
- // offsetHeight are not defined, or when they are zero in WebKit browsers.
- // This makes sure that we return for the correct size for SVG elements, but
- // will still return 0 on Webkit prior to 534.8, see
- // http://trac.webkit.org/changeset/67252.
- var clientRect = goog.style.getBoundingClientRect_(element);
- return new goog.math.Size(
- clientRect.right - clientRect.left, clientRect.bottom - clientRect.top);
- }
- return new goog.math.Size(offsetWidth, offsetHeight);
- };
- /**
- * Gets the height and width of an element, post transform, even if its display
- * is none.
- *
- * This is like {@code goog.style.getSize}, except:
- * <ol>
- * <li>Takes webkitTransforms such as rotate and scale into account.
- * <li>Will return null if {@code element} doesn't respond to
- * {@code getBoundingClientRect}.
- * <li>Currently doesn't make sense on non-WebKit browsers which don't support
- * webkitTransforms.
- * </ol>
- * @param {!Element} element Element to get size of.
- * @return {goog.math.Size} Object with width/height properties.
- */
- goog.style.getTransformedSize = function(element) {
- if (!element.getBoundingClientRect) {
- return null;
- }
- var clientRect = goog.style.evaluateWithTemporaryDisplay_(
- goog.style.getBoundingClientRect_, element);
- return new goog.math.Size(
- clientRect.right - clientRect.left, clientRect.bottom - clientRect.top);
- };
- /**
- * Returns a bounding rectangle for a given element in page space.
- * @param {Element} element Element to get bounds of. Must not be display none.
- * @return {!goog.math.Rect} Bounding rectangle for the element.
- */
- goog.style.getBounds = function(element) {
- var o = goog.style.getPageOffset(element);
- var s = goog.style.getSize(element);
- return new goog.math.Rect(o.x, o.y, s.width, s.height);
- };
- /**
- * Converts a CSS selector in the form style-property to styleProperty.
- * @param {*} selector CSS Selector.
- * @return {string} Camel case selector.
- * @deprecated Use goog.string.toCamelCase instead.
- */
- goog.style.toCamelCase = function(selector) {
- return goog.string.toCamelCase(String(selector));
- };
- /**
- * Converts a CSS selector in the form styleProperty to style-property.
- * @param {string} selector Camel case selector.
- * @return {string} Selector cased.
- * @deprecated Use goog.string.toSelectorCase instead.
- */
- goog.style.toSelectorCase = function(selector) {
- return goog.string.toSelectorCase(selector);
- };
- /**
- * Gets the opacity of a node (x-browser). This gets the inline style opacity
- * of the node, and does not take into account the cascaded or the computed
- * style for this node.
- * @param {Element} el Element whose opacity has to be found.
- * @return {number|string} Opacity between 0 and 1 or an empty string {@code ''}
- * if the opacity is not set.
- */
- goog.style.getOpacity = function(el) {
- goog.asserts.assert(el);
- var style = el.style;
- var result = '';
- if ('opacity' in style) {
- result = style.opacity;
- } else if ('MozOpacity' in style) {
- result = style.MozOpacity;
- } else if ('filter' in style) {
- var match = style.filter.match(/alpha\(opacity=([\d.]+)\)/);
- if (match) {
- result = String(match[1] / 100);
- }
- }
- return result == '' ? result : Number(result);
- };
- /**
- * Sets the opacity of a node (x-browser).
- * @param {Element} el Elements whose opacity has to be set.
- * @param {number|string} alpha Opacity between 0 and 1 or an empty string
- * {@code ''} to clear the opacity.
- */
- goog.style.setOpacity = function(el, alpha) {
- goog.asserts.assert(el);
- var style = el.style;
- if ('opacity' in style) {
- style.opacity = alpha;
- } else if ('MozOpacity' in style) {
- style.MozOpacity = alpha;
- } else if ('filter' in style) {
- // TODO(arv): Overwriting the filter might have undesired side effects.
- if (alpha === '') {
- style.filter = '';
- } else {
- style.filter = 'alpha(opacity=' + (Number(alpha) * 100) + ')';
- }
- }
- };
- /**
- * Sets the background of an element to a transparent image in a browser-
- * independent manner.
- *
- * This function does not support repeating backgrounds or alternate background
- * positions to match the behavior of Internet Explorer. It also does not
- * support sizingMethods other than crop since they cannot be replicated in
- * browsers other than Internet Explorer.
- *
- * @param {Element} el The element to set background on.
- * @param {string} src The image source URL.
- */
- goog.style.setTransparentBackgroundImage = function(el, src) {
- var style = el.style;
- // It is safe to use the style.filter in IE only. In Safari 'filter' is in
- // style object but access to style.filter causes it to throw an exception.
- // Note: IE8 supports images with an alpha channel.
- if (goog.userAgent.IE && !goog.userAgent.isVersionOrHigher('8')) {
- // See TODO in setOpacity.
- style.filter = 'progid:DXImageTransform.Microsoft.AlphaImageLoader(' +
- 'src="' + src + '", sizingMethod="crop")';
- } else {
- // Set style properties individually instead of using background shorthand
- // to prevent overwriting a pre-existing background color.
- style.backgroundImage = 'url(' + src + ')';
- style.backgroundPosition = 'top left';
- style.backgroundRepeat = 'no-repeat';
- }
- };
- /**
- * Clears the background image of an element in a browser independent manner.
- * @param {Element} el The element to clear background image for.
- */
- goog.style.clearTransparentBackgroundImage = function(el) {
- var style = el.style;
- if ('filter' in style) {
- // See TODO in setOpacity.
- style.filter = '';
- } else {
- // Set style properties individually instead of using background shorthand
- // to prevent overwriting a pre-existing background color.
- style.backgroundImage = 'none';
- }
- };
- /**
- * Shows or hides an element from the page. Hiding the element is done by
- * setting the display property to "none", removing the element from the
- * rendering hierarchy so it takes up no space. To show the element, the default
- * inherited display property is restored (defined either in stylesheets or by
- * the browser's default style rules.)
- *
- * Caveat 1: if the inherited display property for the element is set to "none"
- * by the stylesheets, that is the property that will be restored by a call to
- * showElement(), effectively toggling the display between "none" and "none".
- *
- * Caveat 2: if the element display style is set inline (by setting either
- * element.style.display or a style attribute in the HTML), a call to
- * showElement will clear that setting and defer to the inherited style in the
- * stylesheet.
- * @param {Element} el Element to show or hide.
- * @param {*} display True to render the element in its default style,
- * false to disable rendering the element.
- * @deprecated Use goog.style.setElementShown instead.
- */
- goog.style.showElement = function(el, display) {
- goog.style.setElementShown(el, display);
- };
- /**
- * Shows or hides an element from the page. Hiding the element is done by
- * setting the display property to "none", removing the element from the
- * rendering hierarchy so it takes up no space. To show the element, the default
- * inherited display property is restored (defined either in stylesheets or by
- * the browser's default style rules).
- *
- * Caveat 1: if the inherited display property for the element is set to "none"
- * by the stylesheets, that is the property that will be restored by a call to
- * setElementShown(), effectively toggling the display between "none" and
- * "none".
- *
- * Caveat 2: if the element display style is set inline (by setting either
- * element.style.display or a style attribute in the HTML), a call to
- * setElementShown will clear that setting and defer to the inherited style in
- * the stylesheet.
- * @param {Element} el Element to show or hide.
- * @param {*} isShown True to render the element in its default style,
- * false to disable rendering the element.
- */
- goog.style.setElementShown = function(el, isShown) {
- el.style.display = isShown ? '' : 'none';
- };
- /**
- * Test whether the given element has been shown or hidden via a call to
- * {@link #setElementShown}.
- *
- * Note this is strictly a companion method for a call
- * to {@link #setElementShown} and the same caveats apply; in particular, this
- * method does not guarantee that the return value will be consistent with
- * whether or not the element is actually visible.
- *
- * @param {Element} el The element to test.
- * @return {boolean} Whether the element has been shown.
- * @see #setElementShown
- */
- goog.style.isElementShown = function(el) {
- return el.style.display != 'none';
- };
- /**
- * Installs the styles string into the window that contains opt_node. If
- * opt_node is null, the main window is used.
- * @param {string} stylesString The style string to install.
- * @param {Node=} opt_node Node whose parent document should have the
- * styles installed.
- * @return {!Element|!StyleSheet} The style element created.
- * @deprecated Use {@link #installSafeStyleSheet} instead.
- */
- goog.style.installStyles = function(stylesString, opt_node) {
- return goog.style.installSafeStyleSheet(
- goog.html.legacyconversions.safeStyleSheetFromString(stylesString),
- opt_node);
- };
- /**
- * Installs the style sheet into the window that contains opt_node. If
- * opt_node is null, the main window is used.
- * @param {!goog.html.SafeStyleSheet} safeStyleSheet The style sheet to install.
- * @param {?Node=} opt_node Node whose parent document should have the
- * styles installed.
- * @return {!Element|!StyleSheet} The style element created.
- */
- goog.style.installSafeStyleSheet = function(safeStyleSheet, opt_node) {
- var dh = goog.dom.getDomHelper(opt_node);
- var styleSheet = null;
- // IE < 11 requires createStyleSheet. Note that doc.createStyleSheet will be
- // undefined as of IE 11.
- var doc = dh.getDocument();
- if (goog.userAgent.IE && doc.createStyleSheet) {
- styleSheet = doc.createStyleSheet();
- goog.style.setSafeStyleSheet(styleSheet, safeStyleSheet);
- } else {
- var head = dh.getElementsByTagNameAndClass(goog.dom.TagName.HEAD)[0];
- // In opera documents are not guaranteed to have a head element, thus we
- // have to make sure one exists before using it.
- if (!head) {
- var body = dh.getElementsByTagNameAndClass(goog.dom.TagName.BODY)[0];
- head = dh.createDom(goog.dom.TagName.HEAD);
- body.parentNode.insertBefore(head, body);
- }
- styleSheet = dh.createDom(goog.dom.TagName.STYLE);
- // NOTE(user): Setting styles after the style element has been appended
- // to the head results in a nasty Webkit bug in certain scenarios. Please
- // refer to https://bugs.webkit.org/show_bug.cgi?id=26307 for additional
- // details.
- goog.style.setSafeStyleSheet(styleSheet, safeStyleSheet);
- dh.appendChild(head, styleSheet);
- }
- return styleSheet;
- };
- /**
- * Removes the styles added by {@link #installStyles}.
- * @param {Element|StyleSheet} styleSheet The value returned by
- * {@link #installStyles}.
- */
- goog.style.uninstallStyles = function(styleSheet) {
- var node = styleSheet.ownerNode || styleSheet.owningElement ||
- /** @type {Element} */ (styleSheet);
- goog.dom.removeNode(node);
- };
- /**
- * Sets the content of a style element. The style element can be any valid
- * style element. This element will have its content completely replaced by
- * the stylesString.
- * @param {Element|StyleSheet} element A stylesheet element as returned by
- * installStyles.
- * @param {string} stylesString The new content of the stylesheet.
- * @deprecated Use {@link #setSafeStyleSheet} instead.
- */
- goog.style.setStyles = function(element, stylesString) {
- goog.style.setSafeStyleSheet(/** @type {!Element|!StyleSheet} */ (element),
- goog.html.legacyconversions.safeStyleSheetFromString(stylesString));
- };
- /**
- * Sets the content of a style element. The style element can be any valid
- * style element. This element will have its content completely replaced by
- * the safeStyleSheet.
- * @param {!Element|!StyleSheet} element A stylesheet element as returned by
- * installStyles.
- * @param {!goog.html.SafeStyleSheet} safeStyleSheet The new content of the
- * stylesheet.
- */
- goog.style.setSafeStyleSheet = function(element, safeStyleSheet) {
- var stylesString = goog.html.SafeStyleSheet.unwrap(safeStyleSheet);
- if (goog.userAgent.IE && goog.isDef(element.cssText)) {
- // Adding the selectors individually caused the browser to hang if the
- // selector was invalid or there were CSS comments. Setting the cssText of
- // the style node works fine and ignores CSS that IE doesn't understand.
- // However IE >= 11 doesn't support cssText any more, so we make sure that
- // cssText is a defined property and otherwise fall back to innerHTML.
- element.cssText = stylesString;
- } else {
- // Setting textContent doesn't work in Safari, see b/29340337.
- element.innerHTML = stylesString;
- }
- };
- /**
- * Sets 'white-space: pre-wrap' for a node (x-browser).
- *
- * There are as many ways of specifying pre-wrap as there are browsers.
- *
- * CSS3/IE8: white-space: pre-wrap;
- * Mozilla: white-space: -moz-pre-wrap;
- * Opera: white-space: -o-pre-wrap;
- * IE6/7: white-space: pre; word-wrap: break-word;
- *
- * @param {Element} el Element to enable pre-wrap for.
- */
- goog.style.setPreWrap = function(el) {
- var style = el.style;
- if (goog.userAgent.IE && !goog.userAgent.isVersionOrHigher('8')) {
- style.whiteSpace = 'pre';
- style.wordWrap = 'break-word';
- } else if (goog.userAgent.GECKO) {
- style.whiteSpace = '-moz-pre-wrap';
- } else {
- style.whiteSpace = 'pre-wrap';
- }
- };
- /**
- * Sets 'display: inline-block' for an element (cross-browser).
- * @param {Element} el Element to which the inline-block display style is to be
- * applied.
- * @see ../demos/inline_block_quirks.html
- * @see ../demos/inline_block_standards.html
- */
- goog.style.setInlineBlock = function(el) {
- var style = el.style;
- // Without position:relative, weirdness ensues. Just accept it and move on.
- style.position = 'relative';
- if (goog.userAgent.IE && !goog.userAgent.isVersionOrHigher('8')) {
- // IE8 supports inline-block so fall through to the else
- // Zoom:1 forces hasLayout, display:inline gives inline behavior.
- style.zoom = '1';
- style.display = 'inline';
- } else {
- // Opera, Webkit, and Safari seem to do OK with the standard inline-block
- // style.
- style.display = 'inline-block';
- }
- };
- /**
- * Returns true if the element is using right to left (rtl) direction.
- * @param {Element} el The element to test.
- * @return {boolean} True for right to left, false for left to right.
- */
- goog.style.isRightToLeft = function(el) {
- return 'rtl' == goog.style.getStyle_(el, 'direction');
- };
- /**
- * The CSS style property corresponding to an element being
- * unselectable on the current browser platform (null if none).
- * Opera and IE instead use a DOM attribute 'unselectable'. MS Edge uses
- * the Webkit prefix.
- * @type {?string}
- * @private
- */
- goog.style.unselectableStyle_ = goog.userAgent.GECKO ?
- 'MozUserSelect' :
- goog.userAgent.WEBKIT || goog.userAgent.EDGE ? 'WebkitUserSelect' : null;
- /**
- * Returns true if the element is set to be unselectable, false otherwise.
- * Note that on some platforms (e.g. Mozilla), even if an element isn't set
- * to be unselectable, it will behave as such if any of its ancestors is
- * unselectable.
- * @param {Element} el Element to check.
- * @return {boolean} Whether the element is set to be unselectable.
- */
- goog.style.isUnselectable = function(el) {
- if (goog.style.unselectableStyle_) {
- return el.style[goog.style.unselectableStyle_].toLowerCase() == 'none';
- } else if (goog.userAgent.IE || goog.userAgent.OPERA) {
- return el.getAttribute('unselectable') == 'on';
- }
- return false;
- };
- /**
- * Makes the element and its descendants selectable or unselectable. Note
- * that on some platforms (e.g. Mozilla), even if an element isn't set to
- * be unselectable, it will behave as such if any of its ancestors is
- * unselectable.
- * @param {Element} el The element to alter.
- * @param {boolean} unselectable Whether the element and its descendants
- * should be made unselectable.
- * @param {boolean=} opt_noRecurse Whether to only alter the element's own
- * selectable state, and leave its descendants alone; defaults to false.
- */
- goog.style.setUnselectable = function(el, unselectable, opt_noRecurse) {
- // TODO(attila): Do we need all of TR_DomUtil.makeUnselectable() in Closure?
- var descendants = !opt_noRecurse ? el.getElementsByTagName('*') : null;
- var name = goog.style.unselectableStyle_;
- if (name) {
- // Add/remove the appropriate CSS style to/from the element and its
- // descendants.
- var value = unselectable ? 'none' : '';
- // MathML elements do not have a style property. Verify before setting.
- if (el.style) {
- el.style[name] = value;
- }
- if (descendants) {
- for (var i = 0, descendant; descendant = descendants[i]; i++) {
- if (descendant.style) {
- descendant.style[name] = value;
- }
- }
- }
- } else if (goog.userAgent.IE || goog.userAgent.OPERA) {
- // Toggle the 'unselectable' attribute on the element and its descendants.
- var value = unselectable ? 'on' : '';
- el.setAttribute('unselectable', value);
- if (descendants) {
- for (var i = 0, descendant; descendant = descendants[i]; i++) {
- descendant.setAttribute('unselectable', value);
- }
- }
- }
- };
- /**
- * Gets the border box size for an element.
- * @param {Element} element The element to get the size for.
- * @return {!goog.math.Size} The border box size.
- */
- goog.style.getBorderBoxSize = function(element) {
- return new goog.math.Size(
- /** @type {!HTMLElement} */ (element).offsetWidth,
- /** @type {!HTMLElement} */ (element).offsetHeight);
- };
- /**
- * Sets the border box size of an element. This is potentially expensive in IE
- * if the document is CSS1Compat mode
- * @param {Element} element The element to set the size on.
- * @param {goog.math.Size} size The new size.
- */
- goog.style.setBorderBoxSize = function(element, size) {
- var doc = goog.dom.getOwnerDocument(element);
- var isCss1CompatMode = goog.dom.getDomHelper(doc).isCss1CompatMode();
- if (goog.userAgent.IE && !goog.userAgent.isVersionOrHigher('10') &&
- (!isCss1CompatMode || !goog.userAgent.isVersionOrHigher('8'))) {
- var style = element.style;
- if (isCss1CompatMode) {
- var paddingBox = goog.style.getPaddingBox(element);
- var borderBox = goog.style.getBorderBox(element);
- style.pixelWidth = size.width - borderBox.left - paddingBox.left -
- paddingBox.right - borderBox.right;
- style.pixelHeight = size.height - borderBox.top - paddingBox.top -
- paddingBox.bottom - borderBox.bottom;
- } else {
- style.pixelWidth = size.width;
- style.pixelHeight = size.height;
- }
- } else {
- goog.style.setBoxSizingSize_(element, size, 'border-box');
- }
- };
- /**
- * Gets the content box size for an element. This is potentially expensive in
- * all browsers.
- * @param {Element} element The element to get the size for.
- * @return {!goog.math.Size} The content box size.
- */
- goog.style.getContentBoxSize = function(element) {
- var doc = goog.dom.getOwnerDocument(element);
- var ieCurrentStyle = goog.userAgent.IE && element.currentStyle;
- if (ieCurrentStyle && goog.dom.getDomHelper(doc).isCss1CompatMode() &&
- ieCurrentStyle.width != 'auto' && ieCurrentStyle.height != 'auto' &&
- !ieCurrentStyle.boxSizing) {
- // If IE in CSS1Compat mode than just use the width and height.
- // If we have a boxSizing then fall back on measuring the borders etc.
- var width = goog.style.getIePixelValue_(
- element, /** @type {string} */ (ieCurrentStyle.width), 'width',
- 'pixelWidth');
- var height = goog.style.getIePixelValue_(
- element, /** @type {string} */ (ieCurrentStyle.height), 'height',
- 'pixelHeight');
- return new goog.math.Size(width, height);
- } else {
- var borderBoxSize = goog.style.getBorderBoxSize(element);
- var paddingBox = goog.style.getPaddingBox(element);
- var borderBox = goog.style.getBorderBox(element);
- return new goog.math.Size(
- borderBoxSize.width - borderBox.left - paddingBox.left -
- paddingBox.right - borderBox.right,
- borderBoxSize.height - borderBox.top - paddingBox.top -
- paddingBox.bottom - borderBox.bottom);
- }
- };
- /**
- * Sets the content box size of an element. This is potentially expensive in IE
- * if the document is BackCompat mode.
- * @param {Element} element The element to set the size on.
- * @param {goog.math.Size} size The new size.
- */
- goog.style.setContentBoxSize = function(element, size) {
- var doc = goog.dom.getOwnerDocument(element);
- var isCss1CompatMode = goog.dom.getDomHelper(doc).isCss1CompatMode();
- if (goog.userAgent.IE && !goog.userAgent.isVersionOrHigher('10') &&
- (!isCss1CompatMode || !goog.userAgent.isVersionOrHigher('8'))) {
- var style = element.style;
- if (isCss1CompatMode) {
- style.pixelWidth = size.width;
- style.pixelHeight = size.height;
- } else {
- var paddingBox = goog.style.getPaddingBox(element);
- var borderBox = goog.style.getBorderBox(element);
- style.pixelWidth = size.width + borderBox.left + paddingBox.left +
- paddingBox.right + borderBox.right;
- style.pixelHeight = size.height + borderBox.top + paddingBox.top +
- paddingBox.bottom + borderBox.bottom;
- }
- } else {
- goog.style.setBoxSizingSize_(element, size, 'content-box');
- }
- };
- /**
- * Helper function that sets the box sizing as well as the width and height
- * @param {Element} element The element to set the size on.
- * @param {goog.math.Size} size The new size to set.
- * @param {string} boxSizing The box-sizing value.
- * @private
- */
- goog.style.setBoxSizingSize_ = function(element, size, boxSizing) {
- var style = element.style;
- if (goog.userAgent.GECKO) {
- style.MozBoxSizing = boxSizing;
- } else if (goog.userAgent.WEBKIT) {
- style.WebkitBoxSizing = boxSizing;
- } else {
- // Includes IE8 and Opera 9.50+
- style.boxSizing = boxSizing;
- }
- // Setting this to a negative value will throw an exception on IE
- // (and doesn't do anything different than setting it to 0).
- style.width = Math.max(size.width, 0) + 'px';
- style.height = Math.max(size.height, 0) + 'px';
- };
- /**
- * IE specific function that converts a non pixel unit to pixels.
- * @param {Element} element The element to convert the value for.
- * @param {string} value The current value as a string. The value must not be
- * ''.
- * @param {string} name The CSS property name to use for the converstion. This
- * should be 'left', 'top', 'width' or 'height'.
- * @param {string} pixelName The CSS pixel property name to use to get the
- * value in pixels.
- * @return {number} The value in pixels.
- * @private
- */
- goog.style.getIePixelValue_ = function(element, value, name, pixelName) {
- // Try if we already have a pixel value. IE does not do half pixels so we
- // only check if it matches a number followed by 'px'.
- if (/^\d+px?$/.test(value)) {
- return parseInt(value, 10);
- } else {
- var oldStyleValue = element.style[name];
- var oldRuntimeValue = element.runtimeStyle[name];
- // set runtime style to prevent changes
- element.runtimeStyle[name] = element.currentStyle[name];
- element.style[name] = value;
- var pixelValue = element.style[pixelName];
- // restore
- element.style[name] = oldStyleValue;
- element.runtimeStyle[name] = oldRuntimeValue;
- return +pixelValue;
- }
- };
- /**
- * Helper function for getting the pixel padding or margin for IE.
- * @param {Element} element The element to get the padding for.
- * @param {string} propName The property name.
- * @return {number} The pixel padding.
- * @private
- */
- goog.style.getIePixelDistance_ = function(element, propName) {
- var value = goog.style.getCascadedStyle(element, propName);
- return value ?
- goog.style.getIePixelValue_(element, value, 'left', 'pixelLeft') :
- 0;
- };
- /**
- * Gets the computed paddings or margins (on all sides) in pixels.
- * @param {Element} element The element to get the padding for.
- * @param {string} stylePrefix Pass 'padding' to retrieve the padding box,
- * or 'margin' to retrieve the margin box.
- * @return {!goog.math.Box} The computed paddings or margins.
- * @private
- */
- goog.style.getBox_ = function(element, stylePrefix) {
- if (goog.userAgent.IE) {
- var left = goog.style.getIePixelDistance_(element, stylePrefix + 'Left');
- var right = goog.style.getIePixelDistance_(element, stylePrefix + 'Right');
- var top = goog.style.getIePixelDistance_(element, stylePrefix + 'Top');
- var bottom =
- goog.style.getIePixelDistance_(element, stylePrefix + 'Bottom');
- return new goog.math.Box(top, right, bottom, left);
- } else {
- // On non-IE browsers, getComputedStyle is always non-null.
- var left = goog.style.getComputedStyle(element, stylePrefix + 'Left');
- var right = goog.style.getComputedStyle(element, stylePrefix + 'Right');
- var top = goog.style.getComputedStyle(element, stylePrefix + 'Top');
- var bottom = goog.style.getComputedStyle(element, stylePrefix + 'Bottom');
- // NOTE(arv): Gecko can return floating point numbers for the computed
- // style values.
- return new goog.math.Box(
- parseFloat(top), parseFloat(right), parseFloat(bottom),
- parseFloat(left));
- }
- };
- /**
- * Gets the computed paddings (on all sides) in pixels.
- * @param {Element} element The element to get the padding for.
- * @return {!goog.math.Box} The computed paddings.
- */
- goog.style.getPaddingBox = function(element) {
- return goog.style.getBox_(element, 'padding');
- };
- /**
- * Gets the computed margins (on all sides) in pixels.
- * @param {Element} element The element to get the margins for.
- * @return {!goog.math.Box} The computed margins.
- */
- goog.style.getMarginBox = function(element) {
- return goog.style.getBox_(element, 'margin');
- };
- /**
- * A map used to map the border width keywords to a pixel width.
- * @type {!Object}
- * @private
- */
- goog.style.ieBorderWidthKeywords_ = {
- 'thin': 2,
- 'medium': 4,
- 'thick': 6
- };
- /**
- * Helper function for IE to get the pixel border.
- * @param {Element} element The element to get the pixel border for.
- * @param {string} prop The part of the property name.
- * @return {number} The value in pixels.
- * @private
- */
- goog.style.getIePixelBorder_ = function(element, prop) {
- if (goog.style.getCascadedStyle(element, prop + 'Style') == 'none') {
- return 0;
- }
- var width = goog.style.getCascadedStyle(element, prop + 'Width');
- if (width in goog.style.ieBorderWidthKeywords_) {
- return goog.style.ieBorderWidthKeywords_[width];
- }
- return goog.style.getIePixelValue_(element, width, 'left', 'pixelLeft');
- };
- /**
- * Gets the computed border widths (on all sides) in pixels
- * @param {Element} element The element to get the border widths for.
- * @return {!goog.math.Box} The computed border widths.
- */
- goog.style.getBorderBox = function(element) {
- if (goog.userAgent.IE && !goog.userAgent.isDocumentModeOrHigher(9)) {
- var left = goog.style.getIePixelBorder_(element, 'borderLeft');
- var right = goog.style.getIePixelBorder_(element, 'borderRight');
- var top = goog.style.getIePixelBorder_(element, 'borderTop');
- var bottom = goog.style.getIePixelBorder_(element, 'borderBottom');
- return new goog.math.Box(top, right, bottom, left);
- } else {
- // On non-IE browsers, getComputedStyle is always non-null.
- var left = goog.style.getComputedStyle(element, 'borderLeftWidth');
- var right = goog.style.getComputedStyle(element, 'borderRightWidth');
- var top = goog.style.getComputedStyle(element, 'borderTopWidth');
- var bottom = goog.style.getComputedStyle(element, 'borderBottomWidth');
- return new goog.math.Box(
- parseFloat(top), parseFloat(right), parseFloat(bottom),
- parseFloat(left));
- }
- };
- /**
- * Returns the font face applied to a given node. Opera and IE should return
- * the font actually displayed. Firefox returns the author's most-preferred
- * font (whether the browser is capable of displaying it or not.)
- * @param {Element} el The element whose font family is returned.
- * @return {string} The font family applied to el.
- */
- goog.style.getFontFamily = function(el) {
- var doc = goog.dom.getOwnerDocument(el);
- var font = '';
- // The moveToElementText method from the TextRange only works if the element
- // is attached to the owner document.
- if (doc.body.createTextRange && goog.dom.contains(doc, el)) {
- var range = doc.body.createTextRange();
- range.moveToElementText(el);
- try {
- font = range.queryCommandValue('FontName');
- } catch (e) {
- // This is a workaround for a awkward exception.
- // On some IE, there is an exception coming from it.
- // The error description from this exception is:
- // This window has already been registered as a drop target
- // This is bogus description, likely due to a bug in ie.
- font = '';
- }
- }
- if (!font) {
- // Note if for some reason IE can't derive FontName with a TextRange, we
- // fallback to using currentStyle
- font = goog.style.getStyle_(el, 'fontFamily');
- }
- // Firefox returns the applied font-family string (author's list of
- // preferred fonts.) We want to return the most-preferred font, in lieu of
- // the *actually* applied font.
- var fontsArray = font.split(',');
- if (fontsArray.length > 1) font = fontsArray[0];
- // Sanitize for x-browser consistency:
- // Strip quotes because browsers aren't consistent with how they're
- // applied; Opera always encloses, Firefox sometimes, and IE never.
- return goog.string.stripQuotes(font, '"\'');
- };
- /**
- * Regular expression used for getLengthUnits.
- * @type {RegExp}
- * @private
- */
- goog.style.lengthUnitRegex_ = /[^\d]+$/;
- /**
- * Returns the units used for a CSS length measurement.
- * @param {string} value A CSS length quantity.
- * @return {?string} The units of measurement.
- */
- goog.style.getLengthUnits = function(value) {
- var units = value.match(goog.style.lengthUnitRegex_);
- return units && units[0] || null;
- };
- /**
- * Map of absolute CSS length units
- * @type {!Object}
- * @private
- */
- goog.style.ABSOLUTE_CSS_LENGTH_UNITS_ = {
- 'cm': 1,
- 'in': 1,
- 'mm': 1,
- 'pc': 1,
- 'pt': 1
- };
- /**
- * Map of relative CSS length units that can be accurately converted to px
- * font-size values using getIePixelValue_. Only units that are defined in
- * relation to a font size are convertible (%, small, etc. are not).
- * @type {!Object}
- * @private
- */
- goog.style.CONVERTIBLE_RELATIVE_CSS_UNITS_ = {
- 'em': 1,
- 'ex': 1
- };
- /**
- * Returns the font size, in pixels, of text in an element.
- * @param {Element} el The element whose font size is returned.
- * @return {number} The font size (in pixels).
- */
- goog.style.getFontSize = function(el) {
- var fontSize = goog.style.getStyle_(el, 'fontSize');
- var sizeUnits = goog.style.getLengthUnits(fontSize);
- if (fontSize && 'px' == sizeUnits) {
- // NOTE(user): This could be parseFloat instead, but IE doesn't return
- // decimal fractions in getStyle_ and Firefox reports the fractions, but
- // ignores them when rendering. Interestingly enough, when we force the
- // issue and size something to e.g., 50% of 25px, the browsers round in
- // opposite directions with Firefox reporting 12px and IE 13px. I punt.
- return parseInt(fontSize, 10);
- }
- // In IE, we can convert absolute length units to a px value using
- // goog.style.getIePixelValue_. Units defined in relation to a font size
- // (em, ex) are applied relative to the element's parentNode and can also
- // be converted.
- if (goog.userAgent.IE) {
- if (String(sizeUnits) in goog.style.ABSOLUTE_CSS_LENGTH_UNITS_) {
- return goog.style.getIePixelValue_(el, fontSize, 'left', 'pixelLeft');
- } else if (
- el.parentNode && el.parentNode.nodeType == goog.dom.NodeType.ELEMENT &&
- String(sizeUnits) in goog.style.CONVERTIBLE_RELATIVE_CSS_UNITS_) {
- // Check the parent size - if it is the same it means the relative size
- // value is inherited and we therefore don't want to count it twice. If
- // it is different, this element either has explicit style or has a CSS
- // rule applying to it.
- var parentElement = /** @type {!Element} */ (el.parentNode);
- var parentSize = goog.style.getStyle_(parentElement, 'fontSize');
- return goog.style.getIePixelValue_(
- parentElement, fontSize == parentSize ? '1em' : fontSize, 'left',
- 'pixelLeft');
- }
- }
- // Sometimes we can't cleanly find the font size (some units relative to a
- // node's parent's font size are difficult: %, smaller et al), so we create
- // an invisible, absolutely-positioned span sized to be the height of an 'M'
- // rendered in its parent's (i.e., our target element's) font size. This is
- // the definition of CSS's font size attribute.
- var sizeElement = goog.dom.createDom(goog.dom.TagName.SPAN, {
- 'style': 'visibility:hidden;position:absolute;' +
- 'line-height:0;padding:0;margin:0;border:0;height:1em;'
- });
- goog.dom.appendChild(el, sizeElement);
- fontSize = sizeElement.offsetHeight;
- goog.dom.removeNode(sizeElement);
- return fontSize;
- };
- /**
- * Parses a style attribute value. Converts CSS property names to camel case.
- * @param {string} value The style attribute value.
- * @return {!Object} Map of CSS properties to string values.
- */
- goog.style.parseStyleAttribute = function(value) {
- var result = {};
- goog.array.forEach(value.split(/\s*;\s*/), function(pair) {
- var keyValue = pair.match(/\s*([\w-]+)\s*\:(.+)/);
- if (keyValue) {
- var styleName = keyValue[1];
- var styleValue = goog.string.trim(keyValue[2]);
- result[goog.string.toCamelCase(styleName.toLowerCase())] = styleValue;
- }
- });
- return result;
- };
- /**
- * Reverse of parseStyleAttribute; that is, takes a style object and returns the
- * corresponding attribute value. Converts camel case property names to proper
- * CSS selector names.
- * @param {Object} obj Map of CSS properties to values.
- * @return {string} The style attribute value.
- */
- goog.style.toStyleAttribute = function(obj) {
- var buffer = [];
- goog.object.forEach(obj, function(value, key) {
- buffer.push(goog.string.toSelectorCase(key), ':', value, ';');
- });
- return buffer.join('');
- };
- /**
- * Sets CSS float property on an element.
- * @param {Element} el The element to set float property on.
- * @param {string} value The value of float CSS property to set on this element.
- */
- goog.style.setFloat = function(el, value) {
- el.style[goog.userAgent.IE ? 'styleFloat' : 'cssFloat'] = value;
- };
- /**
- * Gets value of explicitly-set float CSS property on an element.
- * @param {Element} el The element to get float property of.
- * @return {string} The value of explicitly-set float CSS property on this
- * element.
- */
- goog.style.getFloat = function(el) {
- return el.style[goog.userAgent.IE ? 'styleFloat' : 'cssFloat'] || '';
- };
- /**
- * Returns the scroll bar width (represents the width of both horizontal
- * and vertical scroll).
- *
- * @param {string=} opt_className An optional class name (or names) to apply
- * to the invisible div created to measure the scrollbar. This is necessary
- * if some scrollbars are styled differently than others.
- * @return {number} The scroll bar width in px.
- */
- goog.style.getScrollbarWidth = function(opt_className) {
- // Add two hidden divs. The child div is larger than the parent and
- // forces scrollbars to appear on it.
- // Using overflow:scroll does not work consistently with scrollbars that
- // are styled with ::-webkit-scrollbar.
- var outerDiv = goog.dom.createElement(goog.dom.TagName.DIV);
- if (opt_className) {
- outerDiv.className = opt_className;
- }
- outerDiv.style.cssText = 'overflow:auto;' +
- 'position:absolute;top:0;width:100px;height:100px';
- var innerDiv = goog.dom.createElement(goog.dom.TagName.DIV);
- goog.style.setSize(innerDiv, '200px', '200px');
- outerDiv.appendChild(innerDiv);
- goog.dom.appendChild(goog.dom.getDocument().body, outerDiv);
- var width = outerDiv.offsetWidth - outerDiv.clientWidth;
- goog.dom.removeNode(outerDiv);
- return width;
- };
- /**
- * Regular expression to extract x and y translation components from a CSS
- * transform Matrix representation.
- *
- * @type {!RegExp}
- * @const
- * @private
- */
- goog.style.MATRIX_TRANSLATION_REGEX_ = new RegExp(
- 'matrix\\([0-9\\.\\-]+, [0-9\\.\\-]+, ' +
- '[0-9\\.\\-]+, [0-9\\.\\-]+, ' +
- '([0-9\\.\\-]+)p?x?, ([0-9\\.\\-]+)p?x?\\)');
- /**
- * Returns the x,y translation component of any CSS transforms applied to the
- * element, in pixels.
- *
- * @param {!Element} element The element to get the translation of.
- * @return {!goog.math.Coordinate} The CSS translation of the element in px.
- */
- goog.style.getCssTranslation = function(element) {
- var transform = goog.style.getComputedTransform(element);
- if (!transform) {
- return new goog.math.Coordinate(0, 0);
- }
- var matches = transform.match(goog.style.MATRIX_TRANSLATION_REGEX_);
- if (!matches) {
- return new goog.math.Coordinate(0, 0);
- }
- return new goog.math.Coordinate(
- parseFloat(matches[1]), parseFloat(matches[2]));
- };
|