gaf-mobile
Version:
GAF mobile Web site
1,754 lines (1,478 loc) • 960 kB
JavaScript
(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 : {
'	' : '\t',
'
' : '\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 "&";
case "'":
return apos;
case '"':
return quot;
}
return "?";
};
var apos = "'", 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 "<";
case ">":
return ">";
case "&":
return "&";
case "'":
return "'";
case '"':
return """;
}
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"