UNPKG

gaf-mobile

Version:

GAF mobile Web site

1,754 lines (1,478 loc) 960 kB
(function(){ /*!************************************************************* * * Firebug Lite 1.4.0 * * Copyright (c) 2007, Parakey Inc. * Released under BSD license. * More information: http://getfirebug.com/firebuglite * **************************************************************/ /*! * CSS selectors powered by: * * Sizzle CSS Selector Engine - v1.0 * Copyright 2009, The Dojo Foundation * Released under the MIT, BSD, and GPL Licenses. * More information: http://sizzlejs.com/ */ /** @namespace describe lib */ // FIXME: xxxpedro if we use "var FBL = {}" the FBL won't appear in the DOM Panel in IE var FBL = {}; ( /** @scope s_lib @this FBL */ function() { // ************************************************************************************************ // ************************************************************************************************ // Constants var productionDir = "http://getfirebug.com/releases/lite/"; var bookmarkletVersion = 4; // ************************************************************************************************ var reNotWhitespace = /[^\s]/; var reSplitFile = /:\/{1,3}(.*?)\/([^\/]*?)\/?($|\?.*)/; // Globals this.reJavascript = /\s*javascript:\s*(.*)/; this.reChrome = /chrome:\/\/([^\/]*)\//; this.reFile = /file:\/\/([^\/]*)\//; // ************************************************************************************************ // properties var userAgent = navigator.userAgent.toLowerCase(); this.isFirefox = /firefox/.test(userAgent); this.isOpera = /opera/.test(userAgent); this.isSafari = /webkit/.test(userAgent); this.isIE = /msie/.test(userAgent) && !/opera/.test(userAgent); this.isIE6 = /msie 6/i.test(navigator.appVersion); this.browserVersion = (userAgent.match( /.+(?:rv|it|ra|ie)[\/: ]([\d.]+)/ ) || [0,'0'])[1]; this.isIElt8 = this.isIE && (this.browserVersion-0 < 8); // * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * this.NS = null; this.pixelsPerInch = null; // ************************************************************************************************ // Namespaces var namespaces = []; // * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * this.ns = function(fn) { var ns = {}; namespaces.push(fn, ns); return ns; }; var FBTrace = null; this.initialize = function() { // Firebug Lite is already running in persistent mode so we just quit if (window.firebug && firebug.firebuglite || window.console && console.firebuglite) return; // * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * // initialize environment // point the FBTrace object to the local variable if (FBL.FBTrace) FBTrace = FBL.FBTrace; else FBTrace = FBL.FBTrace = {}; // check if the actual window is a persisted chrome context var isChromeContext = window.Firebug && typeof window.Firebug.SharedEnv == "object"; // chrome context of the persistent application if (isChromeContext) { // TODO: xxxpedro persist - make a better synchronization sharedEnv = window.Firebug.SharedEnv; delete window.Firebug.SharedEnv; FBL.Env = sharedEnv; FBL.Env.isChromeContext = true; FBTrace.messageQueue = FBL.Env.traceMessageQueue; } // non-persistent application else { FBL.NS = document.documentElement.namespaceURI; FBL.Env.browser = window; FBL.Env.destroy = destroyEnvironment; if (document.documentElement.getAttribute("debug") == "true") FBL.Env.Options.startOpened = true; // find the URL location of the loaded application findLocation(); // TODO: get preferences here... // The problem is that we don't have the Firebug object yet, so we can't use // Firebug.loadPrefs. We're using the Store module directly instead. var prefs = FBL.Store.get("FirebugLite") || {}; FBL.Env.DefaultOptions = FBL.Env.Options; FBL.Env.Options = FBL.extend(FBL.Env.Options, prefs.options || {}); if (FBL.isFirefox && typeof FBL.Env.browser.console == "object" && FBL.Env.browser.console.firebug && FBL.Env.Options.disableWhenFirebugActive) return; } // exposes the FBL to the global namespace when in debug mode if (FBL.Env.isDebugMode) { FBL.Env.browser.FBL = FBL; } // check browser compatibilities this.isQuiksMode = FBL.Env.browser.document.compatMode == "BackCompat"; this.isIEQuiksMode = this.isIE && this.isQuiksMode; this.isIEStantandMode = this.isIE && !this.isQuiksMode; this.noFixedPosition = this.isIE6 || this.isIEQuiksMode; // after creating/synchronizing the environment, initialize the FBTrace module if (FBL.Env.Options.enableTrace) FBTrace.initialize(); if (FBTrace.DBG_INITIALIZE && isChromeContext) FBTrace.sysout("FBL.initialize - persistent application", "initialize chrome context"); // * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * // initialize namespaces if (FBTrace.DBG_INITIALIZE) FBTrace.sysout("FBL.initialize", namespaces.length/2+" namespaces BEGIN"); for (var i = 0; i < namespaces.length; i += 2) { var fn = namespaces[i]; var ns = namespaces[i+1]; fn.apply(ns); } if (FBTrace.DBG_INITIALIZE) { FBTrace.sysout("FBL.initialize", namespaces.length/2+" namespaces END"); FBTrace.sysout("FBL waitForDocument", "waiting document load"); } FBL.Ajax.initialize(); // * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * // finish environment initialization FBL.Firebug.loadPrefs(); if (FBL.Env.Options.enablePersistent) { // TODO: xxxpedro persist - make a better synchronization if (isChromeContext) { FBL.FirebugChrome.clone(FBL.Env.FirebugChrome); } else { FBL.Env.FirebugChrome = FBL.FirebugChrome; FBL.Env.traceMessageQueue = FBTrace.messageQueue; } } // * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * // wait document load waitForDocument(); }; var waitForDocument = function waitForDocument() { // document.body not available in XML+XSL documents in Firefox var doc = FBL.Env.browser.document; var body = doc.getElementsByTagName("body")[0]; if (body) { calculatePixelsPerInch(doc, body); onDocumentLoad(); } else setTimeout(waitForDocument, 50); }; var onDocumentLoad = function onDocumentLoad() { if (FBTrace.DBG_INITIALIZE) FBTrace.sysout("FBL onDocumentLoad", "document loaded"); // fix IE6 problem with cache of background images, causing a lot of flickering if (FBL.isIE6) fixIE6BackgroundImageCache(); // chrome context of the persistent application if (FBL.Env.Options.enablePersistent && FBL.Env.isChromeContext) { // finally, start the application in the chrome context FBL.Firebug.initialize(); // if is not development mode, remove the shared environment cache object // used to synchronize the both persistent contexts if (!FBL.Env.isDevelopmentMode) { sharedEnv.destroy(); sharedEnv = null; } } // non-persistent application else { FBL.FirebugChrome.create(); } }; // ************************************************************************************************ // Env var sharedEnv; this.Env = { // * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * // Env Options (will be transported to Firebug options) Options: { saveCookies: true, saveWindowPosition: false, saveCommandLineHistory: false, startOpened: false, startInNewWindow: false, showIconWhenHidden: true, overrideConsole: true, ignoreFirebugElements: true, disableWhenFirebugActive: true, disableXHRListener: false, disableResourceFetching: false, enableTrace: false, enablePersistent: false }, // * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * // Library location Location: { sourceDir: null, baseDir: null, skinDir: null, skin: null, app: null }, skin: "xp", useLocalSkin: false, // * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * // Env states isDevelopmentMode: false, isDebugMode: false, isChromeContext: false, // * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * // Env references browser: null, chrome: null }; // * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * var destroyEnvironment = function destroyEnvironment() { setTimeout(function() { FBL = null; }, 100); }; // ************************************************************************************************ // Library location var findLocation = function findLocation() { var reFirebugFile = /(firebug-lite(?:-\w+)?(?:\.js|\.jgz))(?:#(.+))?$/; var reGetFirebugSite = /(?:http|https):\/\/getfirebug.com\//; var isGetFirebugSite; var rePath = /^(.*\/)/; var reProtocol = /^\w+:\/\//; var path = null; var doc = document; // Firebug Lite 1.3.0 bookmarklet identification var script = doc.getElementById("FirebugLite"); var scriptSrc; var hasSrcAttribute = true; // If the script was loaded via bookmarklet, we already have the script tag if (script) { scriptSrc = script.src; file = reFirebugFile.exec(scriptSrc); var version = script.getAttribute("FirebugLite"); var number = version ? parseInt(version) : 0; if (!version || !number || number < bookmarkletVersion) { FBL.Env.bookmarkletOutdated = true; } } // otherwise we must search for the correct script tag else { for(var i=0, s=doc.getElementsByTagName("script"), si; si=s[i]; i++) { var file = null; if ( si.nodeName.toLowerCase() == "script" ) { if (file = reFirebugFile.exec(si.getAttribute("firebugSrc"))) { scriptSrc = si.getAttribute("firebugSrc"); hasSrcAttribute = false; } else if (file = reFirebugFile.exec(si.src)) { scriptSrc = si.src; } else continue; script = si; break; } } } // mark the script tag to be ignored by Firebug Lite if (script) script.firebugIgnore = true; if (file) { var fileName = file[1]; var fileOptions = file[2]; // absolute path if (reProtocol.test(scriptSrc)) { path = rePath.exec(scriptSrc)[1]; } // relative path else { var r = rePath.exec(scriptSrc); var src = r ? r[1] : scriptSrc; var backDir = /^((?:\.\.\/)+)(.*)/.exec(src); var reLastDir = /^(.*\/)[^\/]+\/$/; path = rePath.exec(location.href)[1]; // "../some/path" if (backDir) { var j = backDir[1].length/3; var p; while (j-- > 0) path = reLastDir.exec(path)[1]; path += backDir[2]; } else if(src.indexOf("/") != -1) { // "./some/path" if(/^\.\/./.test(src)) { path += src.substring(2); } // "/some/path" else if(/^\/./.test(src)) { var domain = /^(\w+:\/\/[^\/]+)/.exec(path); path = domain[1] + src; } // "some/path" else { path += src; } } } } FBL.Env.isChromeExtension = script && script.getAttribute("extension") == "Chrome"; if (FBL.Env.isChromeExtension) { path = productionDir; FBL.Env.bookmarkletOutdated = false; script = {innerHTML: "{showIconWhenHidden:false}"}; } isGetFirebugSite = reGetFirebugSite.test(path); if (isGetFirebugSite && path.indexOf("/releases/lite/") == -1) { // See Issue 4587 - If we are loading the script from getfirebug.com shortcut, like // https://getfirebug.com/firebug-lite.js, then we must manually add the full path, // otherwise the Env.Location will hold the wrong path, which will in turn lead to // undesirable effects like the problem in Issue 4587 path += "releases/lite/" + (fileName == "firebug-lite-beta.js" ? "beta/" : "latest/"); } var m = path && path.match(/([^\/]+)\/$/) || null; if (path && m) { var Env = FBL.Env; // Always use the local skin when running in the same domain // See Issue 3554: Firebug Lite should use local images when loaded locally Env.useLocalSkin = path.indexOf(location.protocol + "//" + location.host + "/") == 0 && // but we cannot use the locan skin when loaded from getfirebug.com, otherwise // the bookmarklet won't work when visiting getfirebug.com !isGetFirebugSite; // detecting development and debug modes via file name if (fileName == "firebug-lite-dev.js") { Env.isDevelopmentMode = true; Env.isDebugMode = true; } else if (fileName == "firebug-lite-debug.js") { Env.isDebugMode = true; } // process the <html debug="true"> if (Env.browser.document.documentElement.getAttribute("debug") == "true") { Env.Options.startOpened = true; } // process the Script URL Options if (fileOptions) { var options = fileOptions.split(","); for (var i = 0, length = options.length; i < length; i++) { var option = options[i]; var name, value; if (option.indexOf("=") != -1) { var parts = option.split("="); name = parts[0]; value = eval(unescape(parts[1])); } else { name = option; value = true; } if (name == "debug") { Env.isDebugMode = !!value; } else if (name in Env.Options) { Env.Options[name] = value; } else { Env[name] = value; } } } // process the Script JSON Options if (hasSrcAttribute) { var innerOptions = FBL.trim(script.innerHTML); if (innerOptions) { var innerOptionsObject = eval("(" + innerOptions + ")"); for (var name in innerOptionsObject) { var value = innerOptionsObject[name]; if (name == "debug") { Env.isDebugMode = !!value; } else if (name in Env.Options) { Env.Options[name] = value; } else { Env[name] = value; } } } } if (!Env.Options.saveCookies) FBL.Store.remove("FirebugLite"); // process the Debug Mode if (Env.isDebugMode) { Env.Options.startOpened = true; Env.Options.enableTrace = true; Env.Options.disableWhenFirebugActive = false; } var loc = Env.Location; var isProductionRelease = path.indexOf(productionDir) != -1; loc.sourceDir = path; loc.baseDir = path.substr(0, path.length - m[1].length - 1); loc.skinDir = (isProductionRelease ? path : loc.baseDir) + "skin/" + Env.skin + "/"; loc.skin = loc.skinDir + "firebug.html"; loc.app = path + fileName; } else { throw new Error("Firebug Error: Library path not found"); } }; // ************************************************************************************************ // Basics this.bind = function() // fn, thisObject, args => thisObject.fn(args, arguments); { var args = cloneArray(arguments), fn = args.shift(), object = args.shift(); return function() { return fn.apply(object, arrayInsert(cloneArray(args), 0, arguments)); }; }; this.bindFixed = function() // fn, thisObject, args => thisObject.fn(args); { var args = cloneArray(arguments), fn = args.shift(), object = args.shift(); return function() { return fn.apply(object, args); }; }; this.extend = function(l, r) { var newOb = {}; for (var n in l) newOb[n] = l[n]; for (var n in r) newOb[n] = r[n]; return newOb; }; this.descend = function(prototypeParent, childProperties) { function protoSetter() {}; protoSetter.prototype = prototypeParent; var newOb = new protoSetter(); for (var n in childProperties) newOb[n] = childProperties[n]; return newOb; }; this.append = function(l, r) { for (var n in r) l[n] = r[n]; return l; }; this.keys = function(map) // At least sometimes the keys will be on user-level window objects { var keys = []; try { for (var name in map) // enumeration is safe keys.push(name); // name is string, safe } catch (exc) { // Sometimes we get exceptions trying to iterate properties } return keys; // return is safe }; this.values = function(map) { var values = []; try { for (var name in map) { try { values.push(map[name]); } catch (exc) { // Sometimes we get exceptions trying to access properties if (FBTrace.DBG_ERRORS) FBTrace.sysout("lib.values FAILED ", exc); } } } catch (exc) { // Sometimes we get exceptions trying to iterate properties if (FBTrace.DBG_ERRORS) FBTrace.sysout("lib.values FAILED ", exc); } return values; }; this.remove = function(list, item) { for (var i = 0; i < list.length; ++i) { if (list[i] == item) { list.splice(i, 1); break; } } }; this.sliceArray = function(array, index) { var slice = []; for (var i = index; i < array.length; ++i) slice.push(array[i]); return slice; }; function cloneArray(array, fn) { var newArray = []; if (fn) for (var i = 0; i < array.length; ++i) newArray.push(fn(array[i])); else for (var i = 0; i < array.length; ++i) newArray.push(array[i]); return newArray; } function extendArray(array, array2) { var newArray = []; newArray.push.apply(newArray, array); newArray.push.apply(newArray, array2); return newArray; } this.extendArray = extendArray; this.cloneArray = cloneArray; function arrayInsert(array, index, other) { for (var i = 0; i < other.length; ++i) array.splice(i+index, 0, other[i]); return array; } // ************************************************************************************************ this.createStyleSheet = function(doc, url) { //TODO: xxxpedro //var style = doc.createElementNS("http://www.w3.org/1999/xhtml", "style"); var style = this.createElement("link"); style.setAttribute("charset","utf-8"); style.firebugIgnore = true; style.setAttribute("rel", "stylesheet"); style.setAttribute("type", "text/css"); style.setAttribute("href", url); //TODO: xxxpedro //style.innerHTML = this.getResource(url); return style; }; this.addStyleSheet = function(doc, style) { var heads = doc.getElementsByTagName("head"); if (heads.length) heads[0].appendChild(style); else doc.documentElement.appendChild(style); }; this.appendStylesheet = function(doc, uri) { // Make sure the stylesheet is not appended twice. if (this.$(uri, doc)) return; var styleSheet = this.createStyleSheet(doc, uri); styleSheet.setAttribute("id", uri); this.addStyleSheet(doc, styleSheet); }; this.addScript = function(doc, id, src) { var element = doc.createElementNS("http://www.w3.org/1999/xhtml", "html:script"); element.setAttribute("type", "text/javascript"); element.setAttribute("id", id); if (!FBTrace.DBG_CONSOLE) FBL.unwrapObject(element).firebugIgnore = true; element.innerHTML = src; if (doc.documentElement) doc.documentElement.appendChild(element); else { // See issue 1079, the svg test case gives this error if (FBTrace.DBG_ERRORS) FBTrace.sysout("lib.addScript doc has no documentElement:", doc); } return element; }; // ************************************************************************************************ this.getStyle = this.isIE ? function(el, name) { return el.currentStyle[name] || el.style[name] || undefined; } : function(el, name) { return el.ownerDocument.defaultView.getComputedStyle(el,null)[name] || el.style[name] || undefined; }; // ************************************************************************************************ // Whitespace and Entity conversions var entityConversionLists = this.entityConversionLists = { normal : { whitespace : { '\t' : '\u200c\u2192', '\n' : '\u200c\u00b6', '\r' : '\u200c\u00ac', ' ' : '\u200c\u00b7' } }, reverse : { whitespace : { '&Tab;' : '\t', '&NewLine;' : '\n', '\u200c\u2192' : '\t', '\u200c\u00b6' : '\n', '\u200c\u00ac' : '\r', '\u200c\u00b7' : ' ' } } }; var normal = entityConversionLists.normal, reverse = entityConversionLists.reverse; function addEntityMapToList(ccode, entity) { var lists = Array.prototype.slice.call(arguments, 2), len = lists.length, ch = String.fromCharCode(ccode); for (var i = 0; i < len; i++) { var list = lists[i]; normal[list]=normal[list] || {}; normal[list][ch] = '&' + entity + ';'; reverse[list]=reverse[list] || {}; reverse[list]['&' + entity + ';'] = ch; } }; var e = addEntityMapToList, white = 'whitespace', text = 'text', attr = 'attributes', css = 'css', editor = 'editor'; e(0x0022, 'quot', attr, css); e(0x0026, 'amp', attr, text, css); e(0x0027, 'apos', css); e(0x003c, 'lt', attr, text, css); e(0x003e, 'gt', attr, text, css); e(0xa9, 'copy', text, editor); e(0xae, 'reg', text, editor); e(0x2122, 'trade', text, editor); // See http://en.wikipedia.org/wiki/Dash e(0x2012, '#8210', attr, text, editor); // figure dash e(0x2013, 'ndash', attr, text, editor); // en dash e(0x2014, 'mdash', attr, text, editor); // em dash e(0x2015, '#8213', attr, text, editor); // horizontal bar e(0x00a0, 'nbsp', attr, text, white, editor); e(0x2002, 'ensp', attr, text, white, editor); e(0x2003, 'emsp', attr, text, white, editor); e(0x2009, 'thinsp', attr, text, white, editor); e(0x200c, 'zwnj', attr, text, white, editor); e(0x200d, 'zwj', attr, text, white, editor); e(0x200e, 'lrm', attr, text, white, editor); e(0x200f, 'rlm', attr, text, white, editor); e(0x200b, '#8203', attr, text, white, editor); // zero-width space (ZWSP) //************************************************************************************************ // Entity escaping var entityConversionRegexes = { normal : {}, reverse : {} }; var escapeEntitiesRegEx = { normal : function(list) { var chars = []; for ( var ch in list) { chars.push(ch); } return new RegExp('([' + chars.join('') + '])', 'gm'); }, reverse : function(list) { var chars = []; for ( var ch in list) { chars.push(ch); } return new RegExp('(' + chars.join('|') + ')', 'gm'); } }; function getEscapeRegexp(direction, lists) { var name = '', re; var groups = [].concat(lists); for (i = 0; i < groups.length; i++) { name += groups[i].group; } re = entityConversionRegexes[direction][name]; if (!re) { var list = {}; if (groups.length > 1) { for ( var i = 0; i < groups.length; i++) { var aList = entityConversionLists[direction][groups[i].group]; for ( var item in aList) list[item] = aList[item]; } } else if (groups.length==1) { list = entityConversionLists[direction][groups[0].group]; // faster for special case } else { list = {}; // perhaps should print out an error here? } re = entityConversionRegexes[direction][name] = escapeEntitiesRegEx[direction](list); } return re; }; function createSimpleEscape(name, direction) { return function(value) { var list = entityConversionLists[direction][name]; return String(value).replace( getEscapeRegexp(direction, { group : name, list : list }), function(ch) { return list[ch]; } ); }; }; function escapeGroupsForEntities(str, lists) { lists = [].concat(lists); var re = getEscapeRegexp('normal', lists), split = String(str).split(re), len = split.length, results = [], cur, r, i, ri = 0, l, list, last = ''; if (!len) return [ { str : String(str), group : '', name : '' } ]; for (i = 0; i < len; i++) { cur = split[i]; if (cur == '') continue; for (l = 0; l < lists.length; l++) { list = lists[l]; r = entityConversionLists.normal[list.group][cur]; // if (cur == ' ' && list.group == 'whitespace' && last == ' ') // only show for runs of more than one space // r = ' '; if (r) { results[ri] = { 'str' : r, 'class' : list['class'], 'extra' : list.extra[cur] ? list['class'] + list.extra[cur] : '' }; break; } } // last=cur; if (!r) results[ri] = { 'str' : cur, 'class' : '', 'extra' : '' }; ri++; } return results; }; this.escapeGroupsForEntities = escapeGroupsForEntities; function unescapeEntities(str, lists) { var re = getEscapeRegexp('reverse', lists), split = String(str).split(re), len = split.length, results = [], cur, r, i, ri = 0, l, list; if (!len) return str; lists = [].concat(lists); for (i = 0; i < len; i++) { cur = split[i]; if (cur == '') continue; for (l = 0; l < lists.length; l++) { list = lists[l]; r = entityConversionLists.reverse[list.group][cur]; if (r) { results[ri] = r; break; } } if (!r) results[ri] = cur; ri++; } return results.join('') || ''; }; // ************************************************************************************************ // String escaping var escapeForTextNode = this.escapeForTextNode = createSimpleEscape('text', 'normal'); var escapeForHtmlEditor = this.escapeForHtmlEditor = createSimpleEscape('editor', 'normal'); var escapeForElementAttribute = this.escapeForElementAttribute = createSimpleEscape('attributes', 'normal'); var escapeForCss = this.escapeForCss = createSimpleEscape('css', 'normal'); // deprecated compatibility functions //this.deprecateEscapeHTML = createSimpleEscape('text', 'normal'); //this.deprecatedUnescapeHTML = createSimpleEscape('text', 'reverse'); //this.escapeHTML = deprecated("use appropriate escapeFor... function", this.deprecateEscapeHTML); //this.unescapeHTML = deprecated("use appropriate unescapeFor... function", this.deprecatedUnescapeHTML); var escapeForSourceLine = this.escapeForSourceLine = createSimpleEscape('text', 'normal'); var unescapeWhitespace = createSimpleEscape('whitespace', 'reverse'); this.unescapeForTextNode = function(str) { if (Firebug.showTextNodesWithWhitespace) str = unescapeWhitespace(str); if (!Firebug.showTextNodesWithEntities) str = escapeForElementAttribute(str); return str; }; this.escapeNewLines = function(value) { return value.replace(/\r/g, "\\r").replace(/\n/g, "\\n"); }; this.stripNewLines = function(value) { return typeof(value) == "string" ? value.replace(/[\r\n]/g, " ") : value; }; this.escapeJS = function(value) { return value.replace(/\r/g, "\\r").replace(/\n/g, "\\n").replace('"', '\\"', "g"); }; function escapeHTMLAttribute(value) { function replaceChars(ch) { switch (ch) { case "&": return "&amp;"; case "'": return apos; case '"': return quot; } return "?"; }; var apos = "&#39;", quot = "&quot;", around = '"'; if( value.indexOf('"') == -1 ) { quot = '"'; apos = "'"; } else if( value.indexOf("'") == -1 ) { quot = '"'; around = "'"; } return around + (String(value).replace(/[&'"]/g, replaceChars)) + around; } function escapeHTML(value) { function replaceChars(ch) { switch (ch) { case "<": return "&lt;"; case ">": return "&gt;"; case "&": return "&amp;"; case "'": return "&#39;"; case '"': return "&quot;"; } return "?"; }; return String(value).replace(/[<>&"']/g, replaceChars); } this.escapeHTML = escapeHTML; this.cropString = function(text, limit) { text = text + ""; if (!limit) var halfLimit = 50; else var halfLimit = limit / 2; if (text.length > limit) return this.escapeNewLines(text.substr(0, halfLimit) + "..." + text.substr(text.length-halfLimit)); else return this.escapeNewLines(text); }; this.isWhitespace = function(text) { return !reNotWhitespace.exec(text); }; this.splitLines = function(text) { var reSplitLines2 = /.*(:?\r\n|\n|\r)?/mg; var lines; if (text.match) { lines = text.match(reSplitLines2); } else { var str = text+""; lines = str.match(reSplitLines2); } lines.pop(); return lines; }; // ************************************************************************************************ this.safeToString = function(ob) { if (this.isIE) { try { // FIXME: xxxpedro this is failing in IE for the global "external" object return ob + ""; } catch(E) { FBTrace.sysout("Lib.safeToString() failed for ", ob); return ""; } } try { if (ob && "toString" in ob && typeof ob.toString == "function") return ob.toString(); } catch (exc) { // xxxpedro it is not safe to use ob+""? return ob + ""; ///return "[an object with no toString() function]"; } }; // ************************************************************************************************ this.hasProperties = function(ob) { try { for (var name in ob) return true; } catch (exc) {} return false; }; // ************************************************************************************************ // String Util var reTrim = /^\s+|\s+$/g; this.trim = function(s) { return s.replace(reTrim, ""); }; // ************************************************************************************************ // Empty this.emptyFn = function(){}; // ************************************************************************************************ // Visibility this.isVisible = function(elt) { /* if (elt instanceof XULElement) { //FBTrace.sysout("isVisible elt.offsetWidth: "+elt.offsetWidth+" offsetHeight:"+ elt.offsetHeight+" localName:"+ elt.localName+" nameSpace:"+elt.nameSpaceURI+"\n"); return (!elt.hidden && !elt.collapsed); } /**/ return this.getStyle(elt, "visibility") != "hidden" && ( elt.offsetWidth > 0 || elt.offsetHeight > 0 || elt.tagName in invisibleTags || elt.namespaceURI == "http://www.w3.org/2000/svg" || elt.namespaceURI == "http://www.w3.org/1998/Math/MathML" ); }; this.collapse = function(elt, collapsed) { // IE6 doesn't support the [collapsed] CSS selector. IE7 does support the selector, // but it is causing a bug (the element disappears when you set the "collapsed" // attribute, but it doesn't appear when you remove the attribute. So, for those // cases, we need to use the class attribute. if (this.isIElt8) { if (collapsed) this.setClass(elt, "collapsed"); else this.removeClass(elt, "collapsed"); } else elt.setAttribute("collapsed", collapsed ? "true" : "false"); }; this.obscure = function(elt, obscured) { if (obscured) this.setClass(elt, "obscured"); else this.removeClass(elt, "obscured"); }; this.hide = function(elt, hidden) { elt.style.visibility = hidden ? "hidden" : "visible"; }; this.clearNode = function(node) { var nodeName = " " + node.nodeName.toLowerCase() + " "; var ignoreTags = " table tbody thead tfoot th tr td "; // IE can't use innerHTML of table elements if (this.isIE && ignoreTags.indexOf(nodeName) != -1) this.eraseNode(node); else node.innerHTML = ""; }; this.eraseNode = function(node) { while (node.lastChild) node.removeChild(node.lastChild); }; // ************************************************************************************************ // Window iteration this.iterateWindows = function(win, handler) { if (!win || !win.document) return; handler(win); if (win == top || !win.frames) return; // XXXjjb hack for chromeBug for (var i = 0; i < win.frames.length; ++i) { var subWin = win.frames[i]; if (subWin != win) this.iterateWindows(subWin, handler); } }; this.getRootWindow = function(win) { for (; win; win = win.parent) { if (!win.parent || win == win.parent || !this.instanceOf(win.parent, "Window")) return win; } return null; }; // ************************************************************************************************ // Graphics this.getClientOffset = function(elt) { var addOffset = function addOffset(elt, coords, view) { var p = elt.offsetParent; ///var style = isIE ? elt.currentStyle : view.getComputedStyle(elt, ""); var chrome = Firebug.chrome; if (elt.offsetLeft) ///coords.x += elt.offsetLeft + parseInt(style.borderLeftWidth); coords.x += elt.offsetLeft + chrome.getMeasurementInPixels(elt, "borderLeft"); if (elt.offsetTop) ///coords.y += elt.offsetTop + parseInt(style.borderTopWidth); coords.y += elt.offsetTop + chrome.getMeasurementInPixels(elt, "borderTop"); if (p) { if (p.nodeType == 1) addOffset(p, coords, view); } else { var otherView = isIE ? elt.ownerDocument.parentWindow : elt.ownerDocument.defaultView; // IE will fail when reading the frameElement property of a popup window. // We don't need it anyway once it is outside the (popup) viewport, so we're // ignoring the frameElement check when the window is a popup if (!otherView.opener && otherView.frameElement) addOffset(otherView.frameElement, coords, otherView); } }; var isIE = this.isIE; var coords = {x: 0, y: 0}; if (elt) { var view = isIE ? elt.ownerDocument.parentWindow : elt.ownerDocument.defaultView; addOffset(elt, coords, view); } return coords; }; this.getViewOffset = function(elt, singleFrame) { function addOffset(elt, coords, view) { var p = elt.offsetParent; coords.x += elt.offsetLeft - (p ? p.scrollLeft : 0); coords.y += elt.offsetTop - (p ? p.scrollTop : 0); if (p) { if (p.nodeType == 1) { var parentStyle = view.getComputedStyle(p, ""); if (parentStyle.position != "static") { coords.x += parseInt(parentStyle.borderLeftWidth); coords.y += parseInt(parentStyle.borderTopWidth); if (p.localName == "TABLE") { coords.x += parseInt(parentStyle.paddingLeft); coords.y += parseInt(parentStyle.paddingTop); } else if (p.localName == "BODY") { var style = view.getComputedStyle(elt, ""); coords.x += parseInt(style.marginLeft); coords.y += parseInt(style.marginTop); } } else if (p.localName == "BODY") { coords.x += parseInt(parentStyle.borderLeftWidth); coords.y += parseInt(parentStyle.borderTopWidth); } var parent = elt.parentNode; while (p != parent) { coords.x -= parent.scrollLeft; coords.y -= parent.scrollTop; parent = parent.parentNode; } addOffset(p, coords, view); } } else { if (elt.localName == "BODY") { var style = view.getComputedStyle(elt, ""); coords.x += parseInt(style.borderLeftWidth); coords.y += parseInt(style.borderTopWidth); var htmlStyle = view.getComputedStyle(elt.parentNode, ""); coords.x -= parseInt(htmlStyle.paddingLeft); coords.y -= parseInt(htmlStyle.paddingTop); } if (elt.scrollLeft) coords.x += elt.scrollLeft; if (elt.scrollTop) coords.y += elt.scrollTop; var win = elt.ownerDocument.defaultView; if (win && (!singleFrame && win.frameElement)) addOffset(win.frameElement, coords, win); } } var coords = {x: 0, y: 0}; if (elt) addOffset(elt, coords, elt.ownerDocument.defaultView); return coords; }; this.getLTRBWH = function(elt) { var bcrect, dims = {"left": 0, "top": 0, "right": 0, "bottom": 0, "width": 0, "height": 0}; if (elt) { bcrect = elt.getBoundingClientRect(); dims.left = bcrect.left; dims.top = bcrect.top; dims.right = bcrect.right; dims.bottom = bcrect.bottom; if(bcrect.width) { dims.width = bcrect.width; dims.height = bcrect.height; } else { dims.width = dims.right - dims.left; dims.height = dims.bottom - dims.top; } } return dims; }; this.applyBodyOffsets = function(elt, clientRect) { var od = elt.ownerDocument; if (!od.body) return clientRect; var style = od.defaultView.getComputedStyle(od.body, null); var pos = style.getPropertyValue('position'); if(pos === 'absolute' || pos === 'relative') { var borderLeft = parseInt(style.getPropertyValue('border-left-width').replace('px', ''),10) || 0; var borderTop = parseInt(style.getPropertyValue('border-top-width').replace('px', ''),10) || 0; var paddingLeft = parseInt(style.getPropertyValue('padding-left').replace('px', ''),10) || 0; var paddingTop = parseInt(style.getPropertyValue('padding-top').replace('px', ''),10) || 0; var marginLeft = parseInt(style.getPropertyValue('margin-left').replace('px', ''),10) || 0; var marginTop = parseInt(style.getPropertyValue('margin-top').replace('px', ''),10) || 0; var offsetX = borderLeft + paddingLeft + marginLeft; var offsetY = borderTop + paddingTop + marginTop; clientRect.left -= offsetX; clientRect.top -= offsetY; clientRect.right -= offsetX; clientRect.bottom -= offsetY; } return clientRect; }; this.getOffsetSize = function(elt) { return {width: elt.offsetWidth, height: elt.offsetHeight}; }; this.getOverflowParent = function(element) { for (var scrollParent = element.parentNode; scrollParent; scrollParent = scrollParent.offsetParent) { if (scrollParent.scrollHeight > scrollParent.offsetHeight) return scrollParent; } }; this.isScrolledToBottom = function(element) { var onBottom = (element.scrollTop + element.offsetHeight) == element.scrollHeight; if (FBTrace.DBG_CONSOLE) FBTrace.sysout("isScrolledToBottom offsetHeight: "+element.offsetHeight +" onBottom:"+onBottom); return onBottom; }; this.scrollToBottom = function(element) { element.scrollTop = element.scrollHeight; if (FBTrace.DBG_CONSOLE) { FBTrace.sysout("scrollToBottom reset scrollTop "+element.scrollTop+" = "+element.scrollHeight); if (element.scrollHeight == element.offsetHeight) FBTrace.sysout("scrollToBottom attempt to scroll non-scrollable element "+element, element); } return (element.scrollTop == element.scrollHeight); }; this.move = function(element, x, y) { element.style.left = x + "px"; element.style.top = y + "px"; }; this.resize = function(element, w, h) { element.style.width = w + "px"; element.style.height = h + "px"; }; this.linesIntoCenterView = function(element, scrollBox) // {before: int, after: int} { if (!scrollBox) scrollBox = this.getOverflowParent(element); if (!scrollBox) return; var offset = this.getClientOffset(element); var topSpace = offset.y - scrollBox.scrollTop; var bottomSpace = (scrollBox.scrollTop + scrollBox.clientHeight) - (offset.y + element.offsetHeight); if (topSpace < 0 || bottomSpace < 0) { var split = (scrollBox.clientHeight/2); var centerY = offset.y - split; scrollBox.scrollTop = centerY; topSpace = split; bottomSpace = split - element.offsetHeight; } return {before: Math.round((topSpace/element.offsetHeight) + 0.5), after: Math.round((bottomSpace/element.offsetHeight) + 0.5) }; }; this.scrollIntoCenterView = function(element, scrollBox, notX, notY) { if (!element) return; if (!scrollBox) scrollBox = this.getOverflowParent(element); if (!scrollBox) return; var offset = this.getClientOffset(element); if (!notY) { var topSpace = offset.y - scrollBox.scrollTop; var bottomSpace = (scrollBox.scrollTop + scrollBox.clientHeight) - (offset.y + element.offsetHeight); if (topSpace < 0 || bottomSpace < 0) { var centerY = offset.y - (scrollBox.clientHeight/2); scrollBox.scrollTop = centerY; } } if (!notX) { var leftSpace = offset.x - scrollBox.scrollLeft; var rightSpace = (scrollBox.scrollLeft + scrollBox.clientWidth) - (offset.x + element.clientWidth); if (leftSpace < 0 || rightSpace < 0) { var centerX = offset.x - (scrollBox.clientWidth/2); scrollBox.scrollLeft = centerX; } } if (FBTrace.DBG_SOURCEFILES) FBTrace.sysout("lib.scrollIntoCenterView ","Element:"+element.innerHTML); }; // ************************************************************************************************ // CSS var cssKeywordMap = null; var cssPropNames = null; var cssColorNames = null; var imageRules = null; this.getCSSKeywordsByProperty = function(propName) { if (!cssKeywordMap) { cssKeywordMap = {}; for (var name in this.cssInfo) { var list = []; var types = this.cssInfo[name]; for (var i = 0; i < types.length; ++i) { var keywords = this.cssKeywords[types[i]]; if (keywords) list.push.apply(list, keywords); } cssKeywordMap[name] = list; } } return propName in cssKeywordMap ? cssKeywordMap[propName] : []; }; this.getCSSPropertyNames = function() { if (!cssPropNames) { cssPropNames = []; for (var name in this.cssInfo) cssPropNames.push(name); } return cssPropNames; }; this.isColorKeyword = function(keyword) { if (keyword == "transparent") return false; if (!cssColorNames) { cssColorNames = []; var colors = this.cssKeywords["color"]; for (var i = 0; i < colors.length; ++i) cssColorNames.push(colors[i].toLowerCase()); var systemColors = this.cssKeywords["systemColor"]; for (var i = 0; i < systemColors.length; ++i) cssColorNames.push(systemColors[i].toLowerCase()); } return cssColorNames.indexOf ? // Array.indexOf is not available in IE cssColorNames.indexOf(keyword.toLowerCase()) != -1 : (" " + cssColorNames.join(" ") + " ").indexOf(" " + keyword.toLowerCase() + " ") != -1; }; this.isImageRule = function(rule) { if (!imageRules) { imageRules = []; for (var i in this.cssInfo) { var r = i.toLowerCase(); var suffix = "image"; if (r.match(suffix + "$") == suffix || r == "background") imageRules.push(r); } } return imageRules.indexOf ? // Array.indexOf is not available in IE imageRules.indexOf(rule.toLowerCase()) != -1 : (" " + imageRules.join(" ") + " ").indexOf(" " + rule.toLowerCase() + " ") != -1; }; this.copyTextStyles = function(fromNode, toNode, style) { var view = this.isIE ? fromNode.ownerDocument.parentWindow : fromNode.ownerDocument.defaultView; if (view) { if (!style) style = this.isIE ? fromNode.currentStyle : view.getComputedStyle(fromNode, ""); toNode.style.fontFamily = style.fontFamily; // TODO: xxxpedro need to create a FBL.getComputedStyle() because IE // returns wrong computed styles for inherited properties (like font-*) // // Also would be good to create a FBL.getStyle() toNode.style.fontSize = style.fontSize; toNode.style.fontWeight = style.fontWeight; toNode.style.fontStyle = style.fontStyle; return style; } }; this.copyBoxStyles = function(fromNode, toNode, style) { var view = this.isIE ? fromNode.ownerDocument.parentWindow : fromNode.ownerDocument.defaultView; if (view) { if (!style) style = this.isIE ? fromNode.currentStyle : view.getComputedStyle(fromNode, ""); toNode.style.marginTop = style.marginTop; toNode.style.marginRight = style.marginRight; toNode.style.marginBottom = style.marginBottom; toNode.style.marginLeft = style.marginLeft; toNode.style.borderTopWidth = style.borderTopWidth; toNode.style.borderRightWidth = style.borderRightWidth; toNode.style.borderBottomWidth = style.borderBottomWidth; toNode.style.borderLeftWidth = style.borderLeftWidth; return style; } }; this.readBoxStyles = function(style) { var styleNames = { "margin-top": "marginTop", "margin-right": "marginRight", "margin-left": "marginLeft", "margin-bottom": "marginBottom", "border-top-width": "borderTop", "border-right-width": "borderRight", "border-left-width": "borderLeft", "border-bottom-width": "borderBottom", "padding-top": "paddingTop", "padding-right": "paddingRight", "padding-left": "paddingLeft", "padding-bottom": "paddingBottom", "z-index": "zIndex"