1 /* 2 * ***** BEGIN LICENSE BLOCK ***** 3 * Zimbra Collaboration Suite Web Client 4 * Copyright (C) 2005, 2006, 2007, 2009, 2010, 2011, 2012, 2013, 2014, 2015, 2016 Synacor, Inc. 5 * 6 * The contents of this file are subject to the Common Public Attribution License Version 1.0 (the "License"); 7 * you may not use this file except in compliance with the License. 8 * You may obtain a copy of the License at: https://www.zimbra.com/license 9 * The License is based on the Mozilla Public License Version 1.1 but Sections 14 and 15 10 * have been added to cover use of software over a computer network and provide for limited attribution 11 * for the Original Developer. In addition, Exhibit A has been modified to be consistent with Exhibit B. 12 * 13 * Software distributed under the License is distributed on an "AS IS" basis, 14 * WITHOUT WARRANTY OF ANY KIND, either express or implied. 15 * See the License for the specific language governing rights and limitations under the License. 16 * The Original Code is Zimbra Open Source Web Client. 17 * The Initial Developer of the Original Code is Zimbra, Inc. All rights to the Original Code were 18 * transferred by Zimbra, Inc. to Synacor, Inc. on September 14, 2015. 19 * 20 * All portions of the code are Copyright (C) 2005, 2006, 2007, 2009, 2010, 2011, 2012, 2013, 2014, 2015, 2016 Synacor, Inc. All Rights Reserved. 21 * ***** END LICENSE BLOCK ***** 22 */ 23 24 /** 25 * Default constructor. 26 * @constructor 27 * @class 28 * This is a static class that defines a number of constants and helper methods that 29 * support the working with CSS. 30 * 31 * @author Ross Dargahi 32 * 33 * @private 34 */ 35 DwtCssStyle = function() { 36 } 37 38 // Common class name constants used in Dwt 39 40 /** 41 * "mouseOver": transitory state while mouse is over the item. 42 */ 43 DwtCssStyle.HOVER = "hover"; 44 45 /** 46 * "mouseDown": transitory state while left mouse button is being pressed on the item. 47 */ 48 DwtCssStyle.ACTIVE = "active"; 49 50 /** 51 * item is "on", (for example: selected tab, select item(s) in list, or button that stays depressed). 52 */ 53 DwtCssStyle.SELECTED = "selected"; 54 55 /** 56 * Currently used for item that is currently viewed, but not selected (other checkboxes are checked, or a right click action is on a different item). 57 */ 58 DwtCssStyle.ALT_SELECTED = "altSelected"; 59 60 /** 61 * "disabled": item is not actionable (for example: because not appropriate or some other condition needs to be true). 62 */ 63 DwtCssStyle.DISABLED = "disabled"; 64 65 /** 66 * "focused": item has keyboard focus. 67 */ 68 DwtCssStyle.FOCUSED = "focused"; 69 70 /** 71 * UI component is target of some external action, for example: 72 * <ul> 73 * <li>item is the target of right-click (for example: show menu)</li> 74 * <li>item is the thing being dragged</li> 75 * </ul> 76 */ 77 DwtCssStyle.ACTIONED = "actioned"; 78 79 /** 80 * Matched item in a list (for example: in conv list view, items that match the search. NOT used if *all* items match the search). 81 */ 82 DwtCssStyle.MATCHED = "matched"; 83 84 /** 85 * UI component is the current, valid drop target. 86 */ 87 DwtCssStyle.DRAG_OVER = "dragOver"; 88 89 /** 90 * Item being dragged is over a valid drop target. 91 */ 92 DwtCssStyle.DROPPABLE = "droppable"; 93 94 /** 95 * Item being dragged is NOT over a valid drop target. 96 */ 97 DwtCssStyle.NOT_DROPPABLE = "notDroppable"; 98 99 /** 100 * Represents of an item *as it is being dragged* (for example: thing moving around the screen). 101 */ 102 DwtCssStyle.DRAG_PROXY = "dragProxy"; 103 104 /** 105 * Class applies only to linux browsers. 106 */ 107 DwtCssStyle.LINUX = "linux"; 108 109 110 DwtCssStyle.getProperty = 111 function(htmlElement, cssPropName) { 112 var result; 113 if (htmlElement.ownerDocument == null) { 114 // IE5.5 does not support ownerDocument 115 for (var parent = htmlElement.parentNode; parent.parentNode != null; parent = parent.parentNode) {} 116 var doc = parent; 117 } else { 118 var doc = htmlElement.ownerDocument; 119 } 120 121 if (doc.defaultView && doc.defaultView.getComputedStyle) { 122 var cssDecl = doc.defaultView.getComputedStyle(htmlElement, ""); 123 if (cssDecl && cssDecl.length > 0) { //on Chrome/Safari it returns cssDecl with length 0 for some elements for some reason. (a wild guess could be invisible items, as it happens with invite toolbar when it's invisible) So in that case fall back on the other ways. 124 return cssDecl.getPropertyValue(cssPropName); 125 } 126 } 127 128 // Convert CSS -> DOM name for IE etc 129 var tokens = cssPropName.split("-"); 130 // Shift one word off the array and capitalize the rest 131 var propName = tokens.shift() + AjxUtil.map(tokens, AjxStringUtil.capitalize).join(""); 132 133 if (htmlElement.currentStyle) { 134 return htmlElement.currentStyle[propName]; 135 } else if (htmlElement.style) { 136 return htmlElement.style[propName]; 137 } 138 }; 139 140 DwtCssStyle.getComputedStyleObject = 141 function(htmlElement) { 142 if (htmlElement.ownerDocument == null) { 143 // IE5.5 does not suppoert ownerDocument 144 for (var parent = htmlElement.parentNode; parent.parentNode != null; parent = parent.parentNode) {} 145 var doc = parent; 146 } else { 147 var doc = htmlElement.ownerDocument; 148 } 149 150 if (doc.defaultView) { 151 var style = doc.defaultView.getComputedStyle(htmlElement, null); 152 if (!style && htmlElement.style) { 153 // TODO: destructive ? 154 htmlElement.style.display = ""; 155 style = doc.defaultView.getComputedStyle(htmlElement, null); 156 } 157 return style || {}; 158 } else if (htmlElement.currentStyle) 159 return htmlElement.currentStyle; 160 else if (htmlElement.style) 161 return htmlElement.style; 162 }; 163 164 DwtCssStyle.removeProperty = function(el, prop) { 165 if (prop instanceof Array) { 166 for (var i = prop.length; --i >= 0;) 167 DwtCssStyle.removeProperty(el, prop[i]); 168 } else { 169 if (AjxEnv.isIE) { 170 el.style.removeAttribute(prop, true); 171 } else { 172 prop = prop.replace(/([A-Z])/g, "-$1"); 173 el.style.removeProperty(prop); 174 } 175 } 176 }; 177 178 /** 179 * Adds a rule to a stylesheet. 180 * 181 * @param {StyleSheet} stylesheet a CSS stylesheet 182 * @param {string} selector rule selector 183 * @param {string} declaration styles 184 * @param {string} index insertion index (optional) 185 * 186 * @return index at which rule was inserted (for later removal) 187 */ 188 DwtCssStyle.addRule = 189 function(stylesheet, selector, declaration, index) { 190 if (stylesheet.addRule) { // IE 191 //if index is not specified insert at the end so that new rule takes precedence 192 index = index || (stylesheet.rules.length); 193 stylesheet.addRule(selector, declaration, index); 194 } 195 else { 196 //if index is not specified insert at the end so that new rule takes precedence 197 index = index || (stylesheet.cssRules.length); 198 stylesheet.insertRule(selector + "{" + declaration + "}", index); 199 } 200 return index; 201 }; 202 203 /** 204 * Removes the rule at the given index. 205 * 206 * @param {StyleSheet} stylesheet a CSS stylesheet 207 * @param {string} index insertion index (optional) 208 */ 209 DwtCssStyle.removeRule = 210 function(stylesheet, index) { 211 if (stylesheet.removeRule) { // IE 212 stylesheet.removeRule(index); 213 } 214 else { 215 stylesheet.deleteRule(index); 216 } 217 }; 218 219 DwtCssStyle.__PIXEL_RE = /^(-?[0-9]+(?:\.[0-9]*)?)px$/; 220 DwtCssStyle.__DIMENSION_RE = /^(-?[0-9]+(?:\.[0-9]*)?)([a-z]*|%)$/; 221 DwtCssStyle.__NUMBER_RE = /^(-?[0-9]+(?:\.[0-9]*)?)+$/ 222 223 /** 224 * Obtain the font size of the root element in pixels. 225 */ 226 DwtCssStyle.__getRootFontSize = function() { 227 228 var fontsize = DwtCssStyle.getProperty(document.documentElement, 'font-size'); 229 230 if (!DwtCssStyle.__PIXEL_RE.test(fontsize)) { 231 DBG.println(AjxDebug.DBG1, 'font size of root element is not in pixels!'); 232 return -1; 233 } 234 235 return parseInt(fontsize); 236 }; 237 238 /** 239 * Convert a CSS value to a pixel count; unhandled units raise an error. 240 * 241 * @param {String} val a font size value in some form 242 * 243 * @return {Number} the size in pixels, or -1 if there is an error 244 */ 245 DwtCssStyle.asPixelCount = function(val) { 246 247 if (!val) { 248 DBG.println(AjxDebug.DBG1, 'DwtCssStyle.asPixelCount: missing argument'); 249 return -1; 250 } 251 252 var dimension, unit, match; 253 254 // assume pixels if no unit is specified 255 if (typeof val === 'number' || DwtCssStyle.__NUMBER_RE.test(val)) { 256 dimension = Number(val); 257 unit = 'px'; 258 } else if ((match = DwtCssStyle.__DIMENSION_RE.exec(val))) { 259 dimension = Number(match[1]); 260 unit = match[2]; 261 } else { 262 DBG.println(AjxDebug.DBG1, 'DwtCssStyle.asPixelCount: unsupported argument: ' + val); 263 return -1; 264 } 265 266 switch (unit) { 267 case 'rem': { 268 var rootFontSize = DwtCssStyle.__getRootFontSize(); 269 return rootFontSize !== -1 ? dimension * rootFontSize : -1; 270 } 271 272 // see http://www.w3.org/TR/css3-values/#absolute-lengths 273 case 'mm': { 274 dimension /= 10; 275 } 276 277 case 'cm': { 278 dimension /= 2.54; 279 } 280 281 case 'in': { 282 dimension *= 6; 283 } 284 285 case 'pc': { 286 dimension *= 12; 287 } 288 289 case 'pt': { 290 dimension /= 0.75; 291 } 292 293 case 'px': { 294 return dimension; 295 } 296 297 case 'ch': 298 case 'em': 299 case 'ex': { 300 DBG.println(AjxDebug.DBG1, 'DwtCssStyle.asPixelCount: cannot convert context-dependent CSS unit ' + unit); 301 return -1; 302 } 303 304 default: { 305 DBG.println(AjxDebug.DBG1, 'DwtCssStyle.asPixelCount: unrecognized CSS unit ' + unit); 306 return -1; 307 } 308 } 309 }; 310