RetroZilla/extensions/venkman/resources/content/venkman-records.js
2015-10-20 23:03:22 -04:00

1140 lines
36 KiB
JavaScript

/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*-
*
* ***** BEGIN LICENSE BLOCK *****
* Version: MPL 1.1/GPL 2.0/LGPL 2.1
*
* The contents of this file are subject to the Mozilla Public License Version
* 1.1 (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.mozilla.org/MPL/
*
* Software distributed under the License is distributed on an "AS IS" basis,
* WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License
* for the specific language governing rights and limitations under the
* License.
*
* The Original Code is The JavaScript Debugger.
*
* The Initial Developer of the Original Code is
* Netscape Communications Corporation.
* Portions created by the Initial Developer are Copyright (C) 1998
* the Initial Developer. All Rights Reserved.
*
* Contributor(s):
* Robert Ginda, <rginda@netscape.com>, original author
*
* Alternatively, the contents of this file may be used under the terms of
* either the GNU General Public License Version 2 or later (the "GPL"), or
* the GNU Lesser General Public License Version 2.1 or later (the "LGPL"),
* in which case the provisions of the GPL or the LGPL are applicable instead
* of those above. If you wish to allow use of your version of this file only
* under the terms of either the GPL or the LGPL, and not to allow others to
* use your version of this file under the terms of the MPL, indicate your
* decision by deleting the provisions above and replace them with the notice
* and other provisions required by the GPL or the LGPL. If you do not delete
* the provisions above, a recipient may use your version of this file under
* the terms of any one of the MPL, the GPL or the LGPL.
*
* ***** END LICENSE BLOCK ***** */
function initRecords()
{
var cmdary =
[/* "real" commands */
["show-functions", cmdShowFunctions, CMD_CONSOLE],
["show-ecmas", cmdShowECMAs, CMD_CONSOLE],
["show-constants", cmdShowConstants, CMD_CONSOLE],
/* aliases */
["toggle-functions", "show-functions toggle", 0],
["toggle-ecmas", "show-ecma toggle", 0],
["toggle-constants", "show-constants toggle", 0]
];
console.commandManager.defineCommands (cmdary);
var atomsvc = console.atomService;
WindowRecord.prototype.property = atomsvc.getAtom("item-window");
FileContainerRecord.prototype.property = atomsvc.getAtom("item-files");
FileRecord.prototype.property = atomsvc.getAtom("item-file");
FrameRecord.prototype.property = atomsvc.getAtom("item-frame");
FrameRecord.prototype.atomCurrent = atomsvc.getAtom("current-frame-flag");
ScriptInstanceRecord.prototype.atomUnknown = atomsvc.getAtom("item-unk");
ScriptInstanceRecord.prototype.atomHTML = atomsvc.getAtom("item-html");
ScriptInstanceRecord.prototype.atomJS = atomsvc.getAtom("item-js");
ScriptInstanceRecord.prototype.atomXUL = atomsvc.getAtom("item-xul");
ScriptInstanceRecord.prototype.atomXML = atomsvc.getAtom("item-xml");
ScriptInstanceRecord.prototype.atomDisabled =
atomsvc.getAtom("script-disabled");
ScriptRecord.prototype.atomFunction = atomsvc.getAtom("file-function");
ScriptRecord.prototype.atomBreakpoint = atomsvc.getAtom("item-has-bp");
ScriptRecord.prototype.atomDisabled = atomsvc.getAtom("script-disabled");
var prefs =
[
["valueRecord.showFunctions", false],
["valueRecord.showECMAProps", false],
["valueRecord.showConstants", false],
["valueRecord.brokenObjects", "^JavaPackage$"]
];
console.prefManager.addPrefs(prefs);
try
{
ValueRecord.prototype.brokenObjects =
new RegExp (console.prefs["valueRecord.brokenObjects"]);
}
catch (ex)
{
display (MSN_ERR_INVALID_PREF,
["valueRecord.brokenObjects",
console.prefs["valueRecord.brokenObjects"]], MT_ERROR);
display (formatException(ex), MT_ERROR);
ValueRecord.prototype.brokenObjects = /^JavaPackage$/;
}
ValueRecord.prototype.atomVoid = atomsvc.getAtom("item-void");
ValueRecord.prototype.atomNull = atomsvc.getAtom("item-null");
ValueRecord.prototype.atomBool = atomsvc.getAtom("item-bool");
ValueRecord.prototype.atomInt = atomsvc.getAtom("item-int");
ValueRecord.prototype.atomDouble = atomsvc.getAtom("item-double");
ValueRecord.prototype.atomString = atomsvc.getAtom("item-string");
ValueRecord.prototype.atomFunction = atomsvc.getAtom("item-function");
ValueRecord.prototype.atomObject = atomsvc.getAtom("item-object");
ValueRecord.prototype.atomError = atomsvc.getAtom("item-error");
ValueRecord.prototype.atomException = atomsvc.getAtom("item-exception");
ValueRecord.prototype.atomHinted = atomsvc.getAtom("item-hinted");
}
/*******************************************************************************
* Breakpoint Record.
* One prototype for all breakpoint types, works only in the Breakpoints View.
*******************************************************************************/
function BPRecord (breakWrapper)
{
this.setColumnPropertyName ("col-0", "name");
this.setColumnPropertyName ("col-1", "line");
this.breakWrapper = breakWrapper;
if ("pc" in breakWrapper)
{
this.type = "instance";
this.name = breakWrapper.scriptWrapper.functionName;
this.line = getMsg(MSN_FMT_PC, String(breakWrapper.pc));
}
else if (breakWrapper instanceof FutureBreakpoint)
{
this.type = "future";
var ary = breakWrapper.url.match(/\/([^\/?]+)(\?|$)/);
if (ary)
this.name = ary[1];
else
this.name = breakWrapper.url;
this.line = breakWrapper.lineNumber;
}
}
BPRecord.prototype = new XULTreeViewRecord(console.views.breaks.share);
/*******************************************************************************
* Stack Frame Record.
* Represents a jsdIStackFrame, for use in the Stack View only.
*******************************************************************************/
function FrameRecord (jsdFrame)
{
if (!(jsdFrame instanceof jsdIStackFrame))
throw new BadMojo (ERR_INVALID_PARAM, "value");
this.setColumnPropertyName ("col-0", "functionName");
this.setColumnPropertyName ("col-1", "location");
this.functionName = jsdFrame.functionName;
if (!jsdFrame.isNative)
{
this.scriptWrapper = getScriptWrapper(jsdFrame.script);
this.location = getMsg(MSN_FMT_FRAME_LOCATION,
[getFileFromPath(jsdFrame.script.fileName),
jsdFrame.line, jsdFrame.pc]);
this.functionName = this.scriptWrapper.functionName;
}
else
{
this.scriptWrapper = null;
this.location = MSG_URL_NATIVE;
}
this.jsdFrame = jsdFrame;
}
FrameRecord.prototype = new XULTreeViewRecord (console.views.stack.share);
/*******************************************************************************
* Window Record.
* Represents a DOM window with files and child windows. For use in the
* Windows View.
*******************************************************************************/
function WindowRecord (win, baseURL)
{
function none() { return ""; };
this.setColumnPropertyName ("col-0", "displayName");
this.window = win;
this.url = win.location.href;
if (this.url.search(/^\w+:/) == -1)
{
if (this.url[0] == "/")
{
this.url = win.location.protocol + "//" + win.location.host +
this.url;
}
else
{
this.url = baseURL + this.url;
}
this.baseURL = baseURL;
}
else
{
this.baseURL = getPathFromURL(this.url);
if (this.baseURL.indexOf("file:///") == 0)
this.baseURL = "file:/" + this.baseURL.substr(8)
}
this.reserveChildren(true);
this.shortName = getFileFromPath (this.url);
if (console.prefs["enableChromeFilter"] &&
(this.shortName == "navigator.xul" || this.shortName == "browser.xul"))
{
this.displayName = MSG_NAVIGATOR_XUL;
}
else
{
this.filesRecord = new FileContainerRecord(this);
this.displayName = this.shortName;
}
}
WindowRecord.prototype = new XULTreeViewRecord(console.views.windows.share);
WindowRecord.prototype.onPreOpen =
function wr_preopen()
{
this.childData = new Array();
if ("filesRecord" in this)
this.appendChild(this.filesRecord);
var framesLength = this.window.frames.length;
for (var i = 0; i < framesLength; ++i)
{
this.appendChild(new WindowRecord(this.window.frames[i].window,
this.baseURL));
}
}
/*******************************************************************************
* "File Container" Record.
* List of script tags found in the parent record's |window.document| property.
* For use in the Windows View, as a child of a WindowRecord.
*******************************************************************************/
function FileContainerRecord (windowRecord)
{
function files() { return MSG_FILES_REC; }
function none() { return ""; }
this.setColumnPropertyName ("col-0", files);
this.windowRecord = windowRecord;
this.reserveChildren(true);
}
FileContainerRecord.prototype =
new XULTreeViewRecord(console.views.windows.share);
FileContainerRecord.prototype.onPreOpen =
function fcr_getkids ()
{
if (!("parentRecord" in this))
return;
this.childData = new Array();
var doc = this.windowRecord.window.document;
var loc = this.windowRecord.window.location;
var nodeList = doc.getElementsByTagName("script");
for (var i = 0; i < nodeList.length; ++i)
{
var url = nodeList.item(i).getAttribute("src");
if (url)
{
if (url.search(/^\w+:/) == -1)
{
if (url[0] == "/")
url = loc.protocol + "//" + loc.host + url;
else
url = this.windowRecord.baseURL + url;
}
else
{
this.baseURL = getPathFromURL(url);
}
this.appendChild(new FileRecord(url));
}
}
}
/*******************************************************************************
* File Record
* Represents a URL, for use in the Windows View only.
*******************************************************************************/
function FileRecord (url)
{
function none() { return ""; }
this.setColumnPropertyName ("col-0", "shortName");
this.url = url;
this.shortName = getFileFromPath(url);
}
FileRecord.prototype = new XULTreeViewRecord(console.views.windows.share);
/*******************************************************************************
* Script Instance Record.
* Represents a ScriptInstance, for use in the Scripts View only.
*******************************************************************************/
function ScriptInstanceRecord(scriptInstance)
{
if (!ASSERT(scriptInstance.isSealed,
"Attempt to create ScriptInstanceRecord for unsealed instance"))
{
return null;
}
this.setColumnPropertyName ("col-0", "displayName");
this.setColumnPropertyValue ("col-1", "");
this.setColumnPropertyValue ("col-2", "");
this.reserveChildren(true);
this.url = scriptInstance.url;
var sv = console.views.scripts;
this.fileType = this.atomUnknown;
this.shortName = this.url;
this.group = 4;
this.scriptInstance = scriptInstance;
this.lastScriptCount = 0;
this.sequence = scriptInstance.sequence;
this.shortName = getFileFromPath(this.url);
var ary = this.shortName.match (/\.(js|html|xul|xml)$/i);
if (ary)
{
switch (ary[1].toLowerCase())
{
case "js":
this.fileType = this.atomJS;
this.group = 0;
break;
case "html":
this.group = 1;
this.fileType = this.atomHTML;
break;
case "xul":
this.group = 2;
this.fileType = this.atomXUL;
break;
case "xml":
this.group = 3;
this.fileType = this.atomXML;
break;
}
}
this.displayName = this.shortName;
this.sortName = this.shortName.toLowerCase();
return this;
}
ScriptInstanceRecord.prototype =
new XULTreeViewRecord(console.views.scripts.share);
ScriptInstanceRecord.prototype.onDragStart =
function scr_dragstart (e, transferData, dragAction)
{
transferData.data = new TransferData();
transferData.data.addDataForFlavour("text/x-venkman-file", this.fileName);
transferData.data.addDataForFlavour("text/x-moz-url", this.fileName);
transferData.data.addDataForFlavour("text/unicode", this.fileName);
transferData.data.addDataForFlavour("text/html",
"<a href='" + this.fileName +
"'>" + this.fileName + "</a>");
return true;
}
ScriptInstanceRecord.prototype.getProperties =
function scr_getprops (properties)
{
properties.AppendElement(this.fileType);
if (this.scriptInstance.disabledScripts > 0)
properties.AppendElement (this.atomDisabled);
}
ScriptInstanceRecord.prototype.super_resort = XTRootRecord.prototype.resort;
ScriptInstanceRecord.prototype.resort =
function scr_resort ()
{
console._groupFiles = console.prefs["scriptsView.groupFiles"];
this.super_resort();
delete console._groupFiles;
}
ScriptInstanceRecord.prototype.sortCompare =
function scr_compare (a, b)
{
if (0)
{
if (a.group < b.group)
return -1;
if (a.group > b.group)
return 1;
}
if (a.sortName < b.sortName)
return -1;
if (a.sortName > b.sortName)
return 1;
if (a.sequence < b.sequence)
return -1;
if (a.sequence > b.sequence)
return 1;
dd ("ack, all equal?");
return 0;
}
ScriptInstanceRecord.prototype.onPreOpen =
function scr_preopen ()
{
if (!this.scriptInstance.sourceText.isLoaded)
this.scriptInstance.sourceText.loadSource();
if (this.lastScriptCount != this.scriptInstance.scriptCount)
{
var sr;
console.views.scripts.freeze();
this.childData = new Array();
var scriptWrapper = this.scriptInstance.topLevel;
if (scriptWrapper)
{
sr = new ScriptRecord(scriptWrapper);
scriptWrapper.scriptRecord = sr;
this.appendChild(sr);
}
var functions = this.scriptInstance.functions;
for (var f in functions)
{
if (functions[f].jsdScript.isValid)
{
sr = new ScriptRecord(functions[f]);
functions[f].scriptRecord = sr;
this.appendChild(sr);
}
}
console.views.scripts.thaw();
this.lastScriptCount = this.scriptInstance.scriptCount;
}
}
/*******************************************************************************
* Script Record.
* Represents a ScriptWrapper, for use in the Scripts View only.
*******************************************************************************/
function ScriptRecord(scriptWrapper)
{
this.setColumnPropertyName ("col-0", "functionName");
this.setColumnPropertyName ("col-1", "baseLineNumber");
this.setColumnPropertyName ("col-2", "lineExtent");
this.functionName = scriptWrapper.functionName
this.baseLineNumber = scriptWrapper.jsdScript.baseLineNumber;
this.lineExtent = scriptWrapper.jsdScript.lineExtent;
this.scriptWrapper = scriptWrapper;
this.jsdurl = "jsd:sourcetext?url=" +
encodeURIComponent(this.scriptWrapper.jsdScript.fileName) +
"&base=" + this.baseLineNumber + "&extent=" + this.lineExtent +
"&name=" + this.functionName;
}
ScriptRecord.prototype = new XULTreeViewRecord(console.views.scripts.share);
ScriptRecord.prototype.onDragStart =
function sr_dragstart (e, transferData, dragAction)
{
var fileName = this.script.fileName;
transferData.data = new TransferData();
transferData.data.addDataForFlavour("text/x-jsd-url", this.jsdurl);
transferData.data.addDataForFlavour("text/x-moz-url", fileName);
transferData.data.addDataForFlavour("text/unicode", fileName);
transferData.data.addDataForFlavour("text/html",
"<a href='" + fileName +
"'>" + fileName + "</a>");
return true;
}
ScriptRecord.prototype.getProperties =
function sr_getprops (properties)
{
properties.AppendElement (this.atomFunction);
if (this.scriptWrapper.breakpointCount)
properties.AppendElement (this.atomBreakpoint);
if (this.scriptWrapper.jsdScript.isValid &&
this.scriptWrapper.jsdScript.flags & SCRIPT_NODEBUG)
{
properties.AppendElement (this.atomDisabled);
}
}
/*******************************************************************************
* Value Record.
* Use this to show a jsdIValue in any tree.
*******************************************************************************/
function cmdShowFunctions (e)
{
if (e.toggle != null)
{
e.toggle = getToggle(e.toggle, ValueRecord.prototype.showFunctions);
ValueRecord.prototype.showFunctions = e.toggle;
console.prefs["valueRecord.showFunctions"] = e.toggle;
}
if ("isInteractive" in e && e.isInteractive)
dispatch("pref valueRecord.showFunctions", { isInteractive: true });
}
function cmdShowECMAs (e)
{
if (e.toggle != null)
{
e.toggle = getToggle(e.toggle, ValueRecord.prototype.showECMAProps);
ValueRecord.prototype.showECMAProps = e.toggle;
console.prefs["valueRecord.showECMAProps"] = e.toggle;
}
if ("isInteractive" in e && e.isInteractive)
dispatch("pref valueRecord.showECMAProps", { isInteractive: true });
}
function cmdShowConstants (e)
{
if (e.toggle != null)
{
e.toggle = getToggle(e.toggle, ValueRecord.prototype.showConstants);
ValueRecord.prototype.showConstants = e.toggle;
console.prefs["valueRecord.showConstants"] = e.toggle;
}
if ("isInteractive" in e && e.isInteractive)
dispatch("pref valueRecord.showConstants", { isInteractive: true });
}
function ValueRecord (value, name, flags, jsdFrame)
{
if (!(value instanceof jsdIValue))
throw new BadMojo (ERR_INVALID_PARAM, "value", String(value));
this.setColumnPropertyName ("col-0", "displayName");
this.setColumnPropertyName ("col-1", "displayType");
this.setColumnPropertyName ("col-2", "displayValue");
this.setColumnPropertyName ("col-3", "displayFlags");
this.displayName = name;
this.displayFlags = formatFlags(flags);
this.name = name;
this.flags = flags;
this.value = value;
this.jsdFrame = jsdFrame;
this.jsType = null;
this.onPreRefresh = false;
this.refresh();
delete this.onPreRefresh;
}
ValueRecord.prototype = new XULTreeViewRecord (null);
ValueRecord.prototype.__defineGetter__("_share", vr_getshare);
function vr_getshare()
{
if ("__share" in this)
return this.__share;
if ("parentRecord" in this)
return this.__share = this.parentRecord._share;
ASSERT (0, "ValueRecord cannot be the root of a visible tree.");
return null;
}
ValueRecord.prototype.__defineGetter__("expression", vr_getexpressionl);
function vr_getexpressionl()
{
return this.getExpression();
}
ValueRecord.prototype.getExpression =
function vr_getexpression(extra)
{
var items = [this.displayName];
if ("value" in this.parentRecord)
{
var cur = this.parentRecord;
while (cur != console.views["locals"].childData &&
cur != console.views["locals"].scopeRecord)
{
if ("isECMAProto" in cur)
items.unshift("__proto__");
else if ("isECMAParent" in cur)
items.unshift("__parent__");
else
items.unshift(cur.displayName);
cur = cur.parentRecord;
}
}
if (typeof extra == "string")
items.push(extra);
return makeExpression(items);
}
ValueRecord.prototype.evalString =
function vr_evalstring(string)
{
//dd("ValueRecord(" + this.displayName + ").evalString(" + string + ")");
var rval = new Object();
if (this.jsdFrame.eval(string, JSD_URL_SCHEME + "value-record", 1, rval))
return rval.value;
return undefined;
}
ValueRecord.prototype.showFunctions = false;
ValueRecord.prototype.showECMAProps = false;
ValueRecord.prototype.showConstants = false;
ValueRecord.prototype.getProperties =
function vr_getprops (properties)
{
if ("valueIsException" in this || this.flags & PROP_EXCEPTION)
properties.AppendElement (this.atomException);
if (this.flags & PROP_ERROR)
properties.AppendElement (this.atomError);
if (this.flags & PROP_HINTED)
properties.AppendElement (this.atomHinted);
properties.AppendElement (this.property);
}
ValueRecord.prototype.onPreRefresh =
function vr_prerefresh ()
{
if (!ASSERT("parentRecord" in this, "onPreRefresh with no parent"))
return;
if ("isECMAProto" in this)
{
if (this.parentRecord.value.jsPrototype)
this.value = this.parentRecord.value.jsPrototype;
else
this.value = console.jsds.wrapValue(null);
}
else if ("isECMAParent" in this)
{
if (this.parentRecord.value.jsParent)
this.value = this.parentRecord.value.jsParent;
else
this.value = console.jsds.wrapValue(null);
}
else
{
var value = this.parentRecord.value;
var prop = value.getProperty (this.name);
if (prop)
{
this.flags = prop.flags;
this.value = prop.value;
}
else
{
ASSERT(this.jsdFrame, "ValueRecord(" + this.displayName +
").onPreRefresh: no jsdIStackFrame to safely eval on!");
this.value = this.evalString(this.expression);
this.flags = PROP_ENUMERATE | PROP_HINTED;
}
}
}
ValueRecord.prototype.refresh =
function vr_refresh ()
{
if (this.onPreRefresh)
{
try
{
this.onPreRefresh();
delete this.valueIsException;
}
catch (ex)
{
/*
dd ("caught exception refreshing " + this.displayName);
if (typeof ex == "object")
dd (dumpObjectTree(ex));
else
dd(ex);
*/
if (!(ex instanceof jsdIValue))
ex = console.jsds.wrapValue(ex);
this.value = ex;
this.valueIsException = true;
}
}
this.jsType = this.value.jsType;
delete this.alwaysHasChildren;
var strval;
switch (this.jsType)
{
case TYPE_VOID:
this.displayValue = MSG_TYPE_VOID
this.displayType = MSG_TYPE_VOID;
this.property = this.atomVoid;
break;
case TYPE_NULL:
this.displayValue = MSG_TYPE_NULL;
this.displayType = MSG_TYPE_NULL;
this.property = this.atomNull;
break;
case TYPE_BOOLEAN:
this.displayValue = this.value.stringValue;
this.displayType = MSG_TYPE_BOOLEAN;
this.property = this.atomBool;
break;
case TYPE_INT:
this.displayValue = this.value.intValue;
this.displayType = MSG_TYPE_INT;
this.property = this.atomInt;
break;
case TYPE_DOUBLE:
this.displayValue = this.value.doubleValue;
this.displayType = MSG_TYPE_DOUBLE;
this.property = this.atomDouble;
break;
case TYPE_STRING:
strval = this.value.stringValue;
if (strval.length > console.prefs["maxStringLength"])
strval = getMsg(MSN_FMT_LONGSTR, strval.length);
else
strval = strval.quote();
this.displayValue = strval;
this.displayType = MSG_TYPE_STRING;
this.property = this.atomString;
break;
case TYPE_FUNCTION:
case TYPE_OBJECT:
this.displayType = MSG_TYPE_OBJECT;
this.property = this.atomObject;
this.alwaysHasChildren = true;
this.value.refresh();
var ctor = this.value.jsClassName;
strval = null;
switch (ctor)
{
case "Function":
this.displayType = MSG_TYPE_FUNCTION;
ctor = (this.value.isNative ? MSG_CLASS_NATIVE_FUN :
MSG_CLASS_SCRIPT_FUN);
this.property = this.atomFunction;
break;
case "Object":
if (this.value.jsConstructor)
ctor = this.value.jsConstructor.jsFunctionName;
break;
case "XPCWrappedNative_NoHelper":
ctor = MSG_CLASS_CONST_XPCOBJ;
break;
case "XPC_WN_ModsAllowed_Proto_JSClass":
ctor = MSG_CLASS_XPCOBJ;
break;
case "String":
strval = this.value.stringValue;
if (strval.length > console.prefs["maxStringLength"])
strval = getMsg(MSN_FMT_LONGSTR, strval.length);
else
strval = strval.quote();
break;
case "Number":
case "Boolean":
strval = this.value.stringValue;
break;
}
if (strval != null)
{
this.displayValue = strval;
}
else
{
if (0) {
/* too slow... */
var propCount;
if (this.brokenObjects.test(ctor))
{
/* XXX these objects do Bad Things when you enumerate
* over them. */
propCount = 0;
}
else
{
propCount = this.countProperties();
}
this.displayValue = getMsg (MSN_FMT_OBJECT_VALUE,
[ctor, propCount]);
}
else
{
this.displayValue = "{" + ctor + "}";
}
}
/* if we have children, refresh them. */
if ("childData" in this && this.childData.length > 0)
{
if (!this.refreshChildren())
{
dd ("refreshChilren failed for " + this.displayName);
delete this.childData;
this.close();
}
}
break;
default:
ASSERT (0, "invalid value");
}
}
ValueRecord.prototype.countProperties =
function vr_countprops ()
{
ASSERT(this.jsdFrame, "ValueRecord(" + this.displayName +
").countProperties: no jsdIStackFrame to safely eval on!");
// Note: uses an inline function to avoid polluting the frame's scope.
var code = "(function(obj){" +
" var count = 0;" +
" for (var prop in obj)" +
" ++count;" +
" return count;" +
"})(" + this.expression + ")";
// rv is undefined if an exception occured.
var rv = this.evalString(code);
if (typeof rv == "undefined")
return 0;
return rv.intValue;
}
ValueRecord.prototype.listProperties =
function vr_listprops ()
{
function charEscapeReplace(s, c)
{
return String.fromCharCode(parseInt(c, 16));
};
// the ":" prefix for keys in the propMap avoid collisions with "real"
// pseudo-properties, such as __proto__. If we were to actually assign
// to those we would introduce bad side affects.
//dd ("listProperties {");
var i, jsval;
var propMap = new Object();
/* get the enumerable properties */
ASSERT(this.jsdFrame, "ValueRecord(" + this.displayName +
").listProperties: no jsdIStackFrame to safely eval on!");
var propList = new Array();
// quote() puts double-quotes at either end of the string,
// backspash-escapes double-quotes in the string, and (quite
// importantly) uses \xXX and \uXXXX escapes for non-ASCII
// characters.
// Note: uses an inline function to avoid polluting the frame's scope.
var code = "(function(obj){" +
" var string = '';" +
" for (var prop in obj) {" +
" if (string)" +
" string += ',';" +
" string += prop.quote();" +
" }" +
" return string;" +
"})(" + this.expression + ")";
// list is undefined if an exception occured.
var list = this.evalString(code);
if (typeof list != "undefined") {
list = list.stringValue;
//dd("ValueRecord(" + this.displayName +
// ").listProperties: list: " + list);
if (list) {
list = ('",' + list + ',"').split('","');
for (i = 0; i < list.length; i++)
{
if (!list[i])
continue;
var prop = list[i];
prop = prop.replace(/\\x([0-9a-f]{2})/i, charEscapeReplace);
prop = prop.replace(/\\u([0-9a-f]{4})/i, charEscapeReplace);
prop = prop.replace(/\\(.)/, "$1");
propList.push(prop);
//dd("ValueRecord(" + this.displayName +
// ").listProperties: prop: " + prop);
}
}
}
for (i = 0; i < propList.length; i++)
{
var p = propList[i];
var value;
try
{
value = this.evalString(this.getExpression(p));
if (this.showFunctions || value.jsType != TYPE_FUNCTION)
{
propMap[":" + p] = { name: p, value: value,
flags: PROP_ENUMERATE | PROP_HINTED };
}
else
{
//dd ("not including function " + name);
propMap[":" + p] = null;
}
}
catch (ex)
{
propMap[":" + p] = { name: p, value: console.jsds.wrapValue(ex),
flags: PROP_EXCEPTION };
}
//dd ("jsval props: adding " + p + ", " + propMap[":" + p]);
}
/* get the local properties, may or may not be enumerable */
var localProps = new Object()
this.value.getProperties(localProps, {});
localProps = localProps.value;
var len = localProps.length;
for (i = 0; i < len; ++i)
{
var prop = localProps[i];
var name = prop.name.stringValue;
if (!((":" + name) in propMap))
{
if ((this.showFunctions || prop.value.jsType != TYPE_FUNCTION) &&
(this.showConstants || !(prop.flags & PROP_READONLY)))
{
//dd ("localProps: adding " + name + ", " + prop);
propMap[":" + name] = { name: name, value: prop.value,
flags: prop.flags };
}
else
{
//dd ("not including function " + name);
propMap[":" + name] = null;
}
}
else
{
if (!this.showConstants && (prop.flags & PROP_READONLY))
propMap[":" + name] = null;
if (propMap[":" + name])
propMap[":" + name].flags = prop.flags;
}
}
/* sort the property list */
var nameList = keys(propMap);
//dd ("nameList is " + nameList);
nameList.sort();
var propertyList = new Array();
for (i = 0; i < nameList.length; ++i)
{
name = nameList[i];
if (propMap[name])
propertyList.push (propMap[name]);
}
//dd ("} " + propertyList.length + " properties");
return propertyList;
}
ValueRecord.prototype.refreshChildren =
function vr_refreshkids ()
{
var leadingProps = 0;
this.propertyList = this.listProperties();
for (var i = 0; i < this.childData.length; ++i)
{
if ("isECMAParent" in this.childData[i] ||
"isECMAProto" in this.childData[i])
{
++leadingProps;
}
else if (this.childData.length - leadingProps !=
this.propertyList.length)
{
dd ("refreshChildren: property length mismatch");
return false;
}
else if (this.childData[i]._colValues["col-0"] !=
this.propertyList[i - leadingProps].name)
{
dd ("refreshChildren: " +
this.childData[i]._colValues["col-0"] + " != " +
this.propertyList[i - leadingProps].name);
return false;
}
this.childData[i].refresh();
}
if (this.childData.length - leadingProps !=
this.propertyList.length)
{
dd ("refreshChildren: property length mismatch");
return false;
}
return true;
}
ValueRecord.prototype.onPreOpen =
function vr_preopen()
{
try
{
if (!ASSERT(this.value.jsType == TYPE_OBJECT ||
this.value.jsType == TYPE_FUNCTION,
"onPreOpen called for non object?"))
{
return;
}
this.childData = new Array();
this.propertyList = this.listProperties();
if (this.showECMAProps)
{
var rec;
if (this.value.jsPrototype)
{
rec = new ValueRecord(this.value.jsPrototype,
MSG_VAL_PROTO, "", this.jsdFrame);
rec.isECMAProto = true;
this.appendChild (rec);
}
if (this.value.jsParent)
{
rec = new ValueRecord(this.value.jsParent,
MSG_VAL_PARENT, "", this.jsdFrame);
rec.isECMAParent = true;
this.appendChild (rec);
}
}
if (!this.childData.length && !this.propertyList.length)
{
rec = new XTLabelRecord ("col-0", MSG_VAL_NONE,
["col-1", "col-2", "col-3"]);
this.appendChild(rec);
return;
}
for (var i = 0; i < this.propertyList.length; ++i)
{
var prop = this.propertyList[i];
this.appendChild(new ValueRecord(prop.value,
prop.name,
prop.flags,
this.jsdFrame));
}
}
catch (ex)
{
display (getMsg (MSN_ERR_FAILURE, ex), MT_ERROR);
}
}
ValueRecord.prototype.onPostClose =
function vr_destroy()
{
this.childData = new Array();
delete this.propertyList;
}