From a0e80802d096c6ba4ba79d493a4b708280b52866 Mon Sep 17 00:00:00 2001 From: "rginda%netscape.com" Date: Thu, 18 Jul 2002 00:54:32 +0000 Subject: [PATCH] - venkman only - bug 157638, "Land VENKMAN_FLOATS_MY_BOAT branch", a=scc Landing the 3 month old branch, which fixes the following bugs... 121409, 103898, 116102, 116099, 127750, 127099, 121501, 127102, 127737, 127733, 150481, 156776, 156769, 153381, 153066, 152946, 127752, 116286, 143682, 130398, 129692, 156111, 127736, 130050, 139565, 128604, 127751, 127732, 127727, 103425, 85634, 139557, 125394 git-svn-id: svn://10.0.0.236/trunk@125420 18797224-902f-48f8-a5cc-f745e15eee43 --- .../extensions/venkman/js/venkman-service.js | 350 +- .../resources/content/command-manager.js | 599 +-- .../venkman/resources/content/html-consts.js | 5 + .../venkman/resources/content/menu-manager.js | 497 +++ .../venkman/resources/content/profile.csv.tpl | 4 + .../resources/content/profile.html.tpl | 14 +- .../venkman/resources/content/profile.txt.tpl | 30 + .../venkman/resources/content/profile.xml.tpl | 43 + .../venkman/resources/content/tests/tree.js | 36 +- .../venkman/resources/content/tests/tree.xul | 1 - .../venkman/resources/content/tree-utils.js | 476 ++- .../resources/content/venkman-bindings.xml | 88 + .../resources/content/venkman-commands.js | 1416 ++++--- .../resources/content/venkman-debugger.js | 1500 ++++--- .../venkman/resources/content/venkman-dev.js | 19 +- .../resources/content/venkman-floater.js | 71 + .../resources/content/venkman-floater.xul | 75 + .../resources/content/venkman-handlers.js | 497 +-- .../resources/content/venkman-jsdurl.js | 1002 +++++ .../resources/content/venkman-menus.js | 422 +- .../resources/content/venkman-menus.xul | 21 +- .../venkman/resources/content/venkman-msg.js | 242 +- .../resources/content/venkman-munger.js | 24 +- .../resources/content/venkman-output-base.css | 120 + .../content/venkman-output-window.html | 21 +- .../resources/content/venkman-prefs.js | 45 +- .../resources/content/venkman-profiler.js | 384 ++ .../resources/content/venkman-records.js | 871 ++++ .../resources/content/venkman-scripts.xul | 9 +- .../content/venkman-source2-window.html | 15 + .../resources/content/venkman-static.js | 1671 ++++---- .../resources/content/venkman-trees.js | 1790 -------- .../resources/content/venkman-url-loader.js | 2 +- .../resources/content/venkman-utils.js | 268 +- .../resources/content/venkman-views.js | 3751 +++++++++++++++++ .../resources/content/venkman-views.xul | 260 ++ .../venkman/resources/content/venkman.xul | 133 +- .../venkman/resources/content/view-manager.js | 1066 +++++ mozilla/extensions/venkman/resources/jar.mn | 86 +- .../resources/locale/en-US/venkman-help.tpl | 163 + .../resources/locale/en-US/venkman.dtd | 89 +- .../resources/locale/en-US/venkman.properties | 594 ++- .../resources/skin/images/arrow-down.png | Bin 0 -> 318 bytes .../resources/skin/images/arrow-left.png | Bin 0 -> 319 bytes .../resources/skin/images/arrow-right.png | Bin 0 -> 324 bytes .../resources/skin/images/arrow-up.png | Bin 0 -> 319 bytes .../skin/images/breakpoint-future.gif | Bin 0 -> 82 bytes .../{proj-breakpoint.png => breakpoint.png} | Bin .../{proj-breakpoints.png => breakpoints.png} | Bin .../venkman/resources/skin/images/clear.png | Bin 0 -> 283 bytes .../skin/images/{proj-files.png => files.png} | Bin .../resources/skin/images/proj-bl-item.png | Bin 400 -> 0 bytes .../resources/skin/images/proj-blacklist.png | Bin 236 -> 0 bytes .../venkman/resources/skin/images/shaded.png | Bin 0 -> 160 bytes .../images/{watch-stack.png => stack.png} | Bin .../images/{watch-bool.png => value-bool.png} | Bin .../{watch-double.png => value-double.png} | Bin .../{watch-frame.png => value-frame.png} | Bin ...{watch-function.png => value-function.png} | Bin .../images/{watch-int.png => value-int.png} | Bin .../images/{watch-null.png => value-null.png} | Bin .../{watch-object.png => value-object.png} | Bin .../{watch-string.png => value-string.png} | Bin .../images/{watch-void.png => value-void.png} | Bin .../skin/images/view-close-button.png | Bin 0 -> 175 bytes .../resources/skin/images/view-pop-button.png | Bin 0 -> 297 bytes .../images/{proj-window.png => window.png} | Bin .../images/{proj-windows.png => windows.png} | Bin .../venkman/resources/skin/venkman-help.css | 119 + .../resources/skin/venkman-output-dark.css | 92 + .../resources/skin/venkman-output-default.css | 150 +- .../resources/skin/venkman-output-light.css | 98 + .../venkman/resources/skin/venkman-source.css | 119 + .../venkman/resources/skin/venkman.css | 409 +- 74 files changed, 14219 insertions(+), 5538 deletions(-) create mode 100644 mozilla/extensions/venkman/resources/content/menu-manager.js create mode 100644 mozilla/extensions/venkman/resources/content/profile.csv.tpl create mode 100644 mozilla/extensions/venkman/resources/content/profile.txt.tpl create mode 100644 mozilla/extensions/venkman/resources/content/profile.xml.tpl create mode 100644 mozilla/extensions/venkman/resources/content/venkman-bindings.xml create mode 100644 mozilla/extensions/venkman/resources/content/venkman-floater.js create mode 100644 mozilla/extensions/venkman/resources/content/venkman-floater.xul create mode 100644 mozilla/extensions/venkman/resources/content/venkman-jsdurl.js create mode 100644 mozilla/extensions/venkman/resources/content/venkman-output-base.css create mode 100644 mozilla/extensions/venkman/resources/content/venkman-profiler.js create mode 100644 mozilla/extensions/venkman/resources/content/venkman-records.js create mode 100644 mozilla/extensions/venkman/resources/content/venkman-source2-window.html delete mode 100644 mozilla/extensions/venkman/resources/content/venkman-trees.js create mode 100644 mozilla/extensions/venkman/resources/content/venkman-views.js create mode 100644 mozilla/extensions/venkman/resources/content/venkman-views.xul create mode 100644 mozilla/extensions/venkman/resources/content/view-manager.js create mode 100644 mozilla/extensions/venkman/resources/locale/en-US/venkman-help.tpl create mode 100644 mozilla/extensions/venkman/resources/skin/images/arrow-down.png create mode 100644 mozilla/extensions/venkman/resources/skin/images/arrow-left.png create mode 100644 mozilla/extensions/venkman/resources/skin/images/arrow-right.png create mode 100644 mozilla/extensions/venkman/resources/skin/images/arrow-up.png create mode 100644 mozilla/extensions/venkman/resources/skin/images/breakpoint-future.gif rename mozilla/extensions/venkman/resources/skin/images/{proj-breakpoint.png => breakpoint.png} (100%) rename mozilla/extensions/venkman/resources/skin/images/{proj-breakpoints.png => breakpoints.png} (100%) create mode 100644 mozilla/extensions/venkman/resources/skin/images/clear.png rename mozilla/extensions/venkman/resources/skin/images/{proj-files.png => files.png} (100%) delete mode 100644 mozilla/extensions/venkman/resources/skin/images/proj-bl-item.png delete mode 100644 mozilla/extensions/venkman/resources/skin/images/proj-blacklist.png create mode 100644 mozilla/extensions/venkman/resources/skin/images/shaded.png rename mozilla/extensions/venkman/resources/skin/images/{watch-stack.png => stack.png} (100%) rename mozilla/extensions/venkman/resources/skin/images/{watch-bool.png => value-bool.png} (100%) rename mozilla/extensions/venkman/resources/skin/images/{watch-double.png => value-double.png} (100%) rename mozilla/extensions/venkman/resources/skin/images/{watch-frame.png => value-frame.png} (100%) rename mozilla/extensions/venkman/resources/skin/images/{watch-function.png => value-function.png} (100%) rename mozilla/extensions/venkman/resources/skin/images/{watch-int.png => value-int.png} (100%) rename mozilla/extensions/venkman/resources/skin/images/{watch-null.png => value-null.png} (100%) rename mozilla/extensions/venkman/resources/skin/images/{watch-object.png => value-object.png} (100%) rename mozilla/extensions/venkman/resources/skin/images/{watch-string.png => value-string.png} (100%) rename mozilla/extensions/venkman/resources/skin/images/{watch-void.png => value-void.png} (100%) create mode 100644 mozilla/extensions/venkman/resources/skin/images/view-close-button.png create mode 100644 mozilla/extensions/venkman/resources/skin/images/view-pop-button.png rename mozilla/extensions/venkman/resources/skin/images/{proj-window.png => window.png} (100%) rename mozilla/extensions/venkman/resources/skin/images/{proj-windows.png => windows.png} (100%) create mode 100644 mozilla/extensions/venkman/resources/skin/venkman-help.css create mode 100644 mozilla/extensions/venkman/resources/skin/venkman-output-dark.css create mode 100644 mozilla/extensions/venkman/resources/skin/venkman-output-light.css create mode 100644 mozilla/extensions/venkman/resources/skin/venkman-source.css diff --git a/mozilla/extensions/venkman/js/venkman-service.js b/mozilla/extensions/venkman/js/venkman-service.js index 77207d36a26..8294af74e17 100644 --- a/mozilla/extensions/venkman/js/venkman-service.js +++ b/mozilla/extensions/venkman/js/venkman-service.js @@ -36,13 +36,41 @@ /* components defined in this file */ const CLINE_SERVICE_CTRID = "@mozilla.org/commandlinehandler/general-startup;1?type=venkman"; -const CATMAN_CTRID = "@mozilla.org/categorymanager;1"; const CLINE_SERVICE_CID = Components.ID("{18269616-1dd2-11b2-afa8-b612439bda27}"); +const JSDPROT_HANDLER_CTRID = + "@mozilla.org/network/protocol;1?name=x-jsd"; +const JSDPROT_HANDLER_CID = + Components.ID("{12ec790d-304e-4525-89a9-3e723d489d14}"); -const nsICmdLineHandler = Components.interfaces.nsICmdLineHandler; -const nsICategoryManager = Components.interfaces.nsICategoryManager; -const nsISupports = Components.interfaces.nsISupports; +/* components used by this file */ +const CATMAN_CTRID = "@mozilla.org/categorymanager;1"; +const STRING_STREAM_CTRID = "@mozilla.org/io/string-input-stream;1"; +const MEDIATOR_CTRID = + "@mozilla.org/appshell/window-mediator;1"; +const SIMPLEURI_CTRID = "@mozilla.org/network/simple-uri;1"; + +const nsIWindowMediator = Components.interfaces.nsIWindowMediator; +const nsICmdLineHandler = Components.interfaces.nsICmdLineHandler; +const nsICategoryManager = Components.interfaces.nsICategoryManager; +const nsIProtocolHandler = Components.interfaces.nsIProtocolHandler; +const nsIURI = Components.interfaces.nsIURI; +const nsIURL = Components.interfaces.nsIURL; +const nsIStringInputStream = Components.interfaces.nsIStringInputStream; +const nsIChannel = Components.interfaces.nsIChannel; +const nsIRequest = Components.interfaces.nsIRequest; +const nsIProgressEventSink = Components.interfaces.nsIProgressEventSink; +const nsISupports = Components.interfaces.nsISupports; + +function findDebuggerWindow () +{ + var windowManager = + Components.classes[MEDIATOR_CTRID].getService(nsIWindowMediator); + + var window = windowManager.getMostRecentWindow("mozapp:venkman"); + + return window; +} /* Command Line handler service */ function CLineService() @@ -50,17 +78,17 @@ function CLineService() CLineService.prototype.commandLineArgument = "-venkman"; CLineService.prototype.prefNameForStartup = "general.startup.venkman"; -CLineService.prototype.chromeUrlForTask="chrome://venkman/content"; -CLineService.prototype.helpText = "Start with JavaScript debugger"; -CLineService.prototype.handlesArgs=false; -CLineService.prototype.defaultArgs =""; -CLineService.prototype.openWindowWithArgs=false; +CLineService.prototype.chromeUrlForTask = "chrome://venkman/content"; +CLineService.prototype.helpText = "Start with JavaScript Debugger."; +CLineService.prototype.handlesArgs = false; +CLineService.prototype.defaultArgs = ""; +CLineService.prototype.openWindowWithArgs = false; /* factory for command line handler service (CLineService) */ var CLineFactory = new Object(); CLineFactory.createInstance = -function (outer, iid) { +function clf_create (outer, iid) { if (outer != null) throw Components.results.NS_ERROR_NO_AGGREGATION; @@ -70,6 +98,277 @@ function (outer, iid) { return new CLineService(); } +/* x-jsd: protocol handler */ + +const JSD_DEFAULT_PORT = 2206; /* Dana's apartment number. */ + +/* protocol handler factory object */ +var JSDProtocolHandlerFactory = new Object(); + +JSDProtocolHandlerFactory.createInstance = +function jsdhf_create (outer, iid) { + if (outer != null) + throw Components.results.NS_ERROR_NO_AGGREGATION; + + if (!iid.equals(nsIProtocolHandler) && !iid.equals(nsISupports)) + throw Components.results.NS_ERROR_INVALID_ARG; + + return new JSDProtocolHandler(); +} + +function JSDURI (spec, charset) +{ + this.spec = this.prePath = spec; + this.charset = this.originCharset = charset; +} + +JSDURI.prototype.QueryInterface = +function jsdch_qi (iid) +{ + + if (!iid.equals(nsIURI) && !iid.equals(nsIURL) && + !iid.equals(nsISupports)) + throw Components.results.NS_ERROR_NO_INTERFACE; + + return this; +} + +JSDURI.prototype.scheme = "x-jsd"; + + +JSDURI.prototype.fileBaseName = +JSDURI.prototype.fileExtension = +JSDURI.prototype.filePath = +JSDURI.prototype.param = +JSDURI.prototype.query = +JSDURI.prototype.ref = +JSDURI.prototype.directory = +JSDURI.prototype.fileName = +JSDURI.prototype.username = +JSDURI.prototype.password = +JSDURI.prototype.hostPort = +JSDURI.prototype.path = +JSDURI.prototype.asciiHost = +JSDURI.prototype.userPass = ""; + +JSDURI.prototype.port = JSD_DEFAULT_PORT; + +JSDURI.prototype.schemeIs = +function jsduri_schemeis (scheme) +{ + return scheme.toLowerCase() == "x-jsd"; +} + +JSDURI.prototype.getCommonBaseSpec = +function jsduri_commonbase (uri) +{ + return "x-jsd:"; +} + +JSDURI.prototype.getRelativeSpec = +function jsduri_commonbase (uri) +{ + return uri; +} + +JSDURI.prototype.equals = +function jsduri_equals (uri) +{ + return uri.spec == this.spec; +} + +JSDURI.prototype.clone = +function jsduri_clone () +{ + return new JSDURI (this.spec); +} + +JSDURI.prototype.resolve = +function jsduri_resolve(path) +{ + //dump ("resolve " + path + " from " + this.spec + "\n"); + if (path[0] == "#") + return this.spec + path; + + return path; +} + +function JSDProtocolHandler() +{ + /* nothing here */ +} + +JSDProtocolHandler.prototype.scheme = "x-jsd"; +JSDProtocolHandler.prototype.defaultPort = JSD_DEFAULT_PORT; +JSDProtocolHandler.prototype.protocolFlags = nsIProtocolHandler.URI_NORELATIVE; + +JSDProtocolHandler.prototype.allowPort = +function jsdph_allowport (aPort, aScheme) +{ + return false; +} + +JSDProtocolHandler.prototype.newURI = +function jsdph_newuri (spec, charset, baseURI) +{ + if (baseURI) + { + debug ("-*- jsdHandler: aBaseURI passed to newURI, bailing.\n"); + return null; + } + + var clazz = Components.classes[SIMPLEURI_CTRID]; + var uri = clazz.createInstance(nsIURI); + uri.spec = spec; + return uri; +} + +JSDProtocolHandler.prototype.newChannel = +function jsdph_newchannel (uri) +{ + return new JSDChannel (uri); +} + +function JSDChannel (uri) +{ + this.URI = uri; + this.originalURI = uri; + this._isPending = true; + var clazz = Components.classes[STRING_STREAM_CTRID]; + this.stringStream = clazz.createInstance(nsIStringInputStream); +} + +JSDChannel.prototype.QueryInterface = +function jsdch_qi (iid) +{ + + if (!iid.equals(nsIChannel) && !iid.equals(nsIRequest) && + !iid.equals(nsISupports)) + throw Components.results.NS_ERROR_NO_INTERFACE; + + return this; +} + +/* nsIChannel */ +JSDChannel.prototype.loadAttributes = null; +JSDChannel.prototype.contentType = "text/html"; +JSDChannel.prototype.contentLength = -1; +JSDChannel.prototype.owner = null; +JSDChannel.prototype.loadGroup = null; +JSDChannel.prototype.notificationCallbacks = null; +JSDChannel.prototype.securityInfo = null; + +JSDChannel.prototype.open = +function jsdch_open() +{ + throw Components.results.NS_ERROR_NOT_IMPLEMENTED; +} + +JSDChannel.prototype.asyncOpen = +function jsdch_aopen (streamListener, context) +{ + this.streamListener = streamListener; + this.context = context; + if (this.loadGroup) + this.loadGroup.addRequest (this, null); + + var window = findDebuggerWindow(); + var ary = this.URI.spec.match (/x-jsd:([^:]+)/); + var exception; + + if (window && "console" in window && ary) + { + try + { + window.asyncOpenJSDURL (this, streamListener, context); + return; + } + catch (ex) + { + exception = ex; + } + } + + var str = + "ErrorCould not load <" + + this.URI.spec + ">
"; + + if (!ary) + { + str += "Error parsing uri."; + } + else if (exception) + { + str += "Internal error: " + exception + "
" + 
+            exception.stack;
+    }
+    else
+    {
+        str += "Debugger is not running.";
+    }
+    
+    str += "";
+    
+    this.respond (str);
+}
+
+JSDChannel.prototype.respond =
+function jsdch_respond (str)
+{
+    this.streamListener.onStartRequest (this, this.context);
+
+    var len = str.length;
+    this.stringStream.setData (str, len);
+    this.streamListener.onDataAvailable (this, this.context,
+                                         this.stringStream, 0, len);
+    this.streamListener.onStopRequest (this, this.context,
+                                       Components.results.NS_OK);
+    if (this.loadGroup)
+        this.loadGroup.removeRequest (this, null, Components.results.NS_OK);
+    this._isPending = false;    
+}
+
+/* nsIRequest */
+JSDChannel.prototype.isPending =
+function jsdch_ispending ()
+{
+    return this._isPending;
+}
+
+JSDChannel.prototype.status = Components.results.NS_OK;
+
+JSDChannel.prototype.cancel =
+function jsdch_cancel (status)
+{
+    if (this._isPending)
+    {
+        this._isPending = false;
+        this.streamListener.onStopRequest (this, this.context, status);
+        if (this.loadGroup)
+        {
+            try
+            {
+                this.loadGroup.removeRequest (this, null, status);
+            }
+            catch (ex)
+            {
+                debug ("we're not in the load group?\n");
+            }
+        }
+    }
+    
+    this.status = status;
+}
+
+JSDChannel.prototype.suspend =
+JSDChannel.prototype.resume =
+function jsdch_notimpl ()
+{
+    throw Components.results.NS_ERROR_NOT_IMPLEMENTED;
+}
+
+/*****************************************************************************/
+
 var Module = new Object();
 
 Module.registerSelf =
@@ -77,7 +376,8 @@ function (compMgr, fileSpec, location, type)
 {
     debug("*** Registering -venkman handler.\n");
     
-    compMgr = compMgr.QueryInterface(Components.interfaces.nsIComponentRegistrar);
+    compMgr =
+        compMgr.QueryInterface(Components.interfaces.nsIComponentRegistrar);
 
     compMgr.registerFactoryLocation(CLINE_SERVICE_CID,
                                     "Venkman CommandLine Service",
@@ -90,7 +390,26 @@ function (compMgr, fileSpec, location, type)
 	catman.addCategoryEntry("command-line-argument-handlers",
                             "venkman command line handler",
                             CLINE_SERVICE_CTRID, true, true);
-    
+
+    debug("*** Registering x-jsd protocol handler.\n");
+    compMgr.registerFactoryLocation(JSDPROT_HANDLER_CID,
+                                    "x-jsd protocol handler",
+                                    JSDPROT_HANDLER_CTRID, 
+                                    fileSpec, 
+                                    location,
+                                    type);
+    try
+    {
+        const JSD_CTRID = "@mozilla.org/js/jsd/debugger-service;1";
+        const jsdIDebuggerService = Components.interfaces.jsdIDebuggerService;
+        var jsds = Components.classes[JSD_CTRID].getService(jsdIDebuggerService);
+        jsds.initAtStartup = true;
+    }
+    catch (ex)
+    {
+        debug ("*** ERROR initializing debugger service");
+        debug (ex);
+    }
 }
 
 Module.unregisterSelf =
@@ -109,11 +428,8 @@ function (compMgr, cid, iid) {
     if (cid.equals(CLINE_SERVICE_CID))
         return CLineFactory;
 
-    if (cid.equals(IRCCNT_HANDLER_CID))
-        return IRCContentHandlerFactory;
-
-    if (cid.equals(IRCPROT_HANDLER_CID))
-        return IRCProtocolHandlerFactory;
+    if (cid.equals(JSDPROT_HANDLER_CID))
+        return JSDProtocolHandlerFactory;
     
     if (!iid.equals(Components.interfaces.nsIFactory))
         throw Components.results.NS_ERROR_NOT_IMPLEMENTED;
diff --git a/mozilla/extensions/venkman/resources/content/command-manager.js b/mozilla/extensions/venkman/resources/content/command-manager.js
index 6d0557198db..88cf64c8be5 100644
--- a/mozilla/extensions/venkman/resources/content/command-manager.js
+++ b/mozilla/extensions/venkman/resources/content/command-manager.js
@@ -33,7 +33,7 @@ function getAccessKey (str)
     return str[i + 1];
 }
 
-function CommandRecord (name, func, usage, help, label, flags)
+function CommandRecord (name, func, usage, help, label, flags, keystr)
 {
     this.name = name;
     this.func = func;
@@ -41,11 +41,13 @@ function CommandRecord (name, func, usage, help, label, flags)
     this.scanUsage();
     this.help = help;
     this.label = label ? label : name;
+    this.labelstr = label.replace ("&", "");
     this.flags = flags;
     this._enabled = true;
-    this.key = null;
-    this.keystr = MSG_VAL_NA;
-    this.uiElements = new Object();
+    this.keyNodes = new Array();
+    this.keystr = keystr;
+    this.uiElements = new Array();
+
 }
 
 CommandRecord.prototype.__defineGetter__ ("enabled", cr_getenable);
@@ -57,7 +59,7 @@ function cr_getenable ()
 CommandRecord.prototype.__defineSetter__ ("enabled", cr_setenable);
 function cr_setenable (state)
 {
-    for (var i in this.uiElements)
+    for (var i = 0; i < this.uiElements.length; ++i)
     {
         if (state)
             this.uiElements[i].removeAttribute ("disabled");
@@ -96,7 +98,7 @@ function cr_scanusage()
     var capNext = false;
     
     this._usage = spec;
-    this.argNames = new Array();    
+    this.argNames = new Array();
 
     for (var i = 0; i < len; ++i)
     {
@@ -141,7 +143,7 @@ function cr_getdocs(flagFormatter)
     var str;
     str  = getMsg(MSN_DOC_COMMANDLABEL,
                   [this.label.replace("&", ""), this.name]) + "\n";
-    str += getMsg(MSN_DOC_KEY, this.keystr) + "\n";
+    str += getMsg(MSN_DOC_KEY, this.keystr ? this.keystr : MSG_VAL_NA) + "\n";
     str += getMsg(MSN_DOC_SYNTAX, [this.name, this.usage]) + "\n";
     str += MSG_DOC_NOTES + "\n";
     str += (flagFormatter ? flagFormatter(this.flags) : this.flags) + "\n\n";
@@ -152,151 +154,137 @@ function cr_getdocs(flagFormatter)
 
 CommandRecord.prototype.argNames = new Array();
 
-function CommandManager ()
+function CommandManager (defaultBundle)
 {
     this.commands = new Object();
+    this.defaultBundle = defaultBundle;
+}
+
+CommandManager.prototype.defineCommands =
+function cmgr_defcmds (cmdary)
+{
+    var len = cmdary.length;
+    var commands = new Object();
+    var bundle =  ("stringBundle" in cmdary ?
+                   cmdary.stringBundle : 
+                   this.defaultBundle);
+    
+    for (var i = 0; i < len; ++i)
+    {
+        var name  = cmdary[i][0];
+        var func  = cmdary[i][1];
+        var flags = cmdary[i][2];
+        var usage = getMsgFrom(bundle, "cmd." + name + ".params", null, "");
+
+        var helpDefault;
+        var labelDefault = name;
+        var aliasFor;
+        if (flags & CMD_NO_HELP)
+            helpDefault = MSG_NO_HELP;
+
+        if (typeof func == "string")
+        {
+            var ary = func.match(/(\S+)/);
+            if (ary)
+                aliasFor = ary[1];
+            helpDefault = getMsg (MSN_DEFAULT_ALIAS_HELP, func); 
+            labelDefault = getMsgFrom (bundle,
+                                       "cmd." + aliasFor + ".label", null, name);
+        }
+
+        var label = getMsgFrom(bundle,
+                               "cmd." + name + ".label", null, labelDefault);
+        var help  = getMsgFrom(bundle,
+                               "cmd." + name + ".help", null, helpDefault);
+        var keystr = getMsgFrom (bundle, "cmd." + name + ".key", null, "");
+        var command = new CommandRecord (name, func, usage, help, label, flags,
+                                         keystr);
+        if (aliasFor)
+            command.aliasFor = aliasFor;
+        this.addCommand(command);
+        commands[name] = command;
+    }
+
+    return commands;
+}
+
+CommandManager.prototype.installKeys =
+function cmgr_instkeys (document, commands)
+{
+    var parentElem = document.getElementById("dynamic-keys");
+    if (!parentElem)
+    {
+        parentElem = document.createElement("keyset");
+        parentElem.setAttribute ("id", "dynamic-keys");
+        document.firstChild.appendChild (parentElem);
+    }
+
+    if (!commands)
+        commands = this.commands;
+    
+    for (var c in commands)
+        this.installKey (parentElem, commands[c]);
 }
 
 /**
- * Internal use only.
+ * Create a  node relative to a DOM node.  Usually called once per command,
+ * per document, so that accelerator keys work in all application windows.
  *
- * |showPopup| is called from the "onpopupshowing" event of menus
- * managed by the CommandManager.  If a command is disabled, represents a command
- * that cannot be "satisfied" by the current command context |cx|, or has an
- * "enabledif" attribute that eval()s to false, then the menuitem is disabled.
- * In addition "checkedif" and "visibleif" attributes are eval()d and
- * acted upon accordingly.
+ * @param parentElem  A reference to the DOM node which should contain the new
+ *                     node.
+ * @param command     reference to the CommandRecord to install.
  */
-CommandManager.showPopup =
-function cmgr_showpop (id)
+CommandManager.prototype.installKey =
+function cmgr_instkey (parentElem, command)
 {
-    /* returns true if the command context has the properties required to
-     * execute the command associated with |menuitem|.
-     */
-    function satisfied()
+    if (!command.keystr)
+        return;
+
+    var ary = command.keystr.match (/(.*\s)?([\S]+)$/);
+    if (!ASSERT(ary, "couldn't parse key string ``" + command.keystr +
+                "'' for command ``" + command.name + "''"))
     {
-        if (menuitem.hasAttribute("isSeparator"))
-            return true;
-
-        if (!("commandManager" in cx))
-        {
-            dd ("no commandManager in cx");
-            return false;
-        }
-        
-        var name = menuitem.getAttribute("commandname");
-        if (!ASSERT (name in cx.commandManager.commands,
-                     "menu contains unknown command '" + name + "'"))
-            return false;
-
-        var command = cx.commandManager.commands[name];
-
-        var rv = cx.commandManager.isCommandSatisfied(cx, command);
-        delete cx.parseError;
-        return rv;
+        return;
     }
     
-    /* Convenience function for "enabledif", etc, attributes. */
-    function has (prop)
-    {
-        return (prop in cx);
-    }
+    var key = document.createElement ("key");
+    key.setAttribute ("id", "key:" + command.name);
+    key.setAttribute ("oncommand", "dispatch('" + command.name + "');");
+    key.setAttribute ("modifiers", ary[1]);
+    if (ary[2].indexOf("VK_") == 0)
+        key.setAttribute ("keycode", ary[2]);
+    else
+        key.setAttribute ("key", ary[2]);
     
-    /* evals the attribute named |attr| on the node |node|. */
-    function evalIfAttribute (node, attr)
+    parentElem.appendChild(key);
+    command.keyNodes.push(key);
+}
+
+CommandManager.prototype.uninstallKeys =
+function cmgr_uninstkeys (commands)
+{
+    if (!commands)
+        commands = this.commands;
+    
+    for (var c in commands)
+        this.uninstallKey (commands[c]);
+}
+
+CommandManager.prototype.uninstallKey =
+function cmgr_uninstkey (command)
+{
+    for (var i in command.keyNodes)
     {
-        var ex;
-        var expr = node.getAttribute(attr);
-        if (!expr)
-            return true;
-        
-        expr = expr.replace (/\Wor\W/gi, " || ");
-        expr = expr.replace (/\Wand\W/gi, " && ");
         try
         {
-            return eval("(" + expr + ")");
+            /* document may no longer exist in a useful state. */
+            command.keyNodes[i].parentNode.removeChild(command.keyNodes[i]);
         }
         catch (ex)
         {
-            dd ("caught exception evaling '" + node.getAttribute("id") + "'.'" +
-                attr + "'\n" + ex);
+            dd ("*** caught exception uninstalling key node: " + ex);
         }
-        return true;
     }
-    
-    var cx;
-    
-    /* If the host provided a |contextFunction|, use it now.  Remember the
-     * return result as this.cx for use if something from this menu is actually
-     * dispatched.  this.cx is deleted in |hidePopup|. */
-    if (typeof this.contextFunction == "function")
-        cx = this.cx = this.contextFunction (id);
-    else
-        cx = new Object();
-
-    /* make this a member of cx so the |this| value is useful to attriutes. */
-
-    var popup = document.getElementById (id);
-    var menuitem = popup.firstChild;
-
-    do
-    {
-        /* should it be visible? */
-        if (menuitem.hasAttribute("visibleif"))
-        {
-            if (evalIfAttribute(menuitem, "visibleif"))
-                menuitem.removeAttribute ("hidden");
-            else
-            {
-                menuitem.setAttribute ("hidden", "true");
-                continue;
-            }
-        }
-        
-        /* ok, it's visible, maybe it should be disabled? */
-        if (satisfied())
-        {
-            if (menuitem.hasAttribute("enabledif"))
-            {
-                if (evalIfAttribute(menuitem, "enabledif"))
-                    menuitem.removeAttribute ("disabled");
-                else
-                    menuitem.setAttribute ("disabled", "true");
-            }
-            else
-                menuitem.removeAttribute ("disabled");
-        }
-        else
-        {
-            menuitem.setAttribute ("disabled", "true");
-        }
-        
-        /* should it have a check? */
-        if (menuitem.hasAttribute("checkedif"))
-        {
-            if (evalIfAttribute(menuitem, "checkedif"))
-                menuitem.setAttribute ("checked", "true");
-            else
-                menuitem.removeAttribute ("checked");
-        }
-        
-    } while ((menuitem = menuitem.nextSibling));
-
-    return true;
-}
-
-/**
- * Internal use only.
- *
- * |hidePopup| is called from the "onpopuphiding" event of menus
- * managed by the CommandManager.  Here we just clean up the context, which
- * would have (and may have) become the event object used by any command
- * dispatched while the menu was open.
- */
-CommandManager.hidePopup =
-function cmgr_hidepop (id)
-{
-    delete this.cx;
 }
 
 /**
@@ -308,255 +296,120 @@ function cmgr_add (command)
     this.commands[command.name] = command;
 }
 
-/**
- * Set the accelerator key used to trigger a command.  Multiple keys can be
- * assigned to a command, but only the last one will appear in the documentation
- * entry for the command.
- * @param parent   ID of the keyset to add the  to.
- * @param command  reference to the CommandRecord which should be dispatced.
- * @param keystr   String representation of the key, in the format
- *                  (|), where the parameter names
- *                 represent attributes on the  object.
- */
-CommandManager.prototype.setKey =
-function cmgr_add (parent, command, keystr)
+CommandManager.prototype.removeCommands = 
+function cmgr_removes (commands)
 {
-    var parentElem = document.getElementById(parent);
-    if (!ASSERT(parentElem, "setKey: couldn't get parent '" + parent +
-                "' for " + command.name))
-        return;
+    for (var c in commands)
+        this.removeCommand(commands[c]);
+}
 
-    var ary = keystr.match (/(.*\s)?([\S]+)$/);
-    var key = document.createElement ("key");
-    key.setAttribute ("id", "key:" + command.name);
-    key.setAttribute ("oncommand",
-                      "dispatch('" + command.name + "');");
-    key.setAttribute ("modifiers", ary[1]);
-    if (ary[2].indexOf("VK_") == 0)
-        key.setAttribute ("keycode", ary[2]);
+CommandManager.prototype.removeCommand = 
+function cmgr_remove (command)
+{
+    delete this.commands[command.name];
+}
+
+/**
+ * Register a hook for a particular command name.  |id| is a human readable
+ * identifier for the hook, and can be used to unregister the hook.  If you
+ * re-use a hook id, the previous hook function will be replaced.
+ * If |before| is |true|, the hook will be called *before* the command executes,
+ * if |before| is |false|, or not specified, the hook will be called *after*
+ * the command executes.
+ */
+CommandManager.prototype.addHook =
+function cmgr_hook (commandName, func, id, before)
+{
+    if (!ASSERT(commandName in this.commands,
+                "Unknown command '" + commandName + "'"))
+    {
+        return;
+    }
+    
+    var command = this.commands[commandName];
+    
+    if (before)
+    {
+        if (!("beforeHookNames" in command))
+            command.beforeHookNames = new Array();
+        if (!("beforeHooks" in command))
+            command.beforeHooks = new Object();
+        if (id in command.beforeHooks)
+        {
+            arrayRemoveAt(command.beforeHookNames,
+                          command.beforeHooks[id][id + "_hookIndex"]);
+        }
+        command.beforeHooks[id] = func;
+        command.beforeHookNames.push(id);
+    }
     else
-        key.setAttribute ("key", ary[2]);
-    
-    parentElem.appendChild(key);
-    command.key = key;
-    command.keystr = keystr;
+    {
+        if (!("afterHookNames" in command))
+            command.afterHookNames = new Array();
+        if (!("afterHooks" in command))
+            command.afterHooks = new Object();
+        func[id + "_hookIndex"] = command.afterHookNames.length
+        command.afterHooks[id] = func;
+        command.afterHookNames.push(id);
+    }
 }
 
-/**
- * Internal use only.
- *
- * Registers event handlers on a given menu.
- */
-CommandManager.prototype.hookPopup =
-function cmgr_hookpop (id)
+CommandManager.prototype.addHooks =
+function cmgr_hooks (hooks, prefix)
 {
-    var element = document.getElementById (id);
-    element.setAttribute ("onpopupshowing",
-                          "return CommandManager.showPopup('" + id + "');");
-    element.setAttribute ("onpopuphiding",
-                          "return CommandManager.hidePopup();");
+    if (!prefix)
+        prefix = "";
+    
+    for (var h in hooks)
+    {
+        this.addHook(h, hooks[h], prefix + ":" + h, 
+                     ("before" in hooks[h]) ? hooks[h].before : false);
+    }
 }
 
-/**
- * Appends a sub-menu to an existing menu.
- * @param parent  ID of the parent menu to add this submenu to.
- * @param id      ID of the sub-menu to add.
- * @param label   Text to use for this sub-menu.  The & character can be
- *                used to indicate the accesskey.
- * @param attribs Object containing CSS attributes to set on the element.
- */
-CommandManager.prototype.appendSubMenu =
-function cmgr_addsmenu (parent, id, label, attribs)
+CommandManager.prototype.removeHooks =
+function cmgr_remhooks (hooks, prefix)
 {
-    var menu = document.getElementById (id);
-    if (!menu)
-    {
-        var parentElem = document.getElementById(parent + "-popup");
-        if (!parentElem)
-            parentElem = document.getElementById(parent);
-        
-        if (!ASSERT(parentElem, "addSubMenu: couldn't get parent '" + parent +
-                    "' for " + id))
-            return;
+    if (!prefix)
+        prefix = "";
     
-        menu = document.createElement ("menu");
-        menu.setAttribute ("id", id);
-        parentElem.appendChild(menu);
-    }
-    
-    menu.setAttribute ("accesskey", getAccessKey(label));
-    menu.setAttribute ("label", label.replace("&", ""));
-    menu.setAttribute ("isSeparator", true);
-    var menupopup = document.createElement ("menupopup");
-    menupopup.setAttribute ("id", id + "-popup");
-    if (typeof attribs == "object")
+    for (var h in hooks)
     {
-        for (var p in attribs)
-            menupopup.setAttribute (p, attribs[p]);
+        this.removeHook(h, prefix + ":" + h, 
+                        ("before" in hooks[h]) ? hooks[h].before : false);
     }
-
-    menu.appendChild(menupopup);    
-    this.hookPopup (id + "-popup");
 }
 
-/**
- * Appends a popup to an existing popupset.
- * @param parent  ID of the popupset to add this popup to.
- * @param id      ID of the popup to add.
- * @param label   Text to use for this popup.  Popup menus don't normally have
- *                labels, but we set a "label" attribute anyway, in case
- *                the host wants it for some reason.  Any "&" characters will
- *                be stripped.
- * @param attribs Object containing CSS attributes to set on the element.
- */
-CommandManager.prototype.appendPopupMenu =
-function cmgr_addsmenu (parent, id, label, attribs)
+CommandManager.prototype.removeHook =
+function cmgr_unhook (commandName, id, before)
 {
-    var parentElem = document.getElementById (parent);
-    if (!ASSERT(parentElem, "addPopupMenu: couldn't get parent '" + parent +
-                "' for " + id))
-        return;
+    var command = this.commands[commandName];
 
-    var popup = document.createElement ("popup");
-    popup.setAttribute ("label", label.replace("&", ""));
-    popup.setAttribute ("id", id);
-    if (typeof attribs == "object")
+    if (before)
     {
-        for (var p in attribs)
-            popup.setAttribute (p, attribs[p]);
+        arrayRemoveAt(command.beforeHookNames,
+                      command.beforeHooks[id][id + "_hookIndex"]);
+        delete command.beforeHooks[id][id + "_hookIndex"];
+        delete command.beforeHooks[id];
+        if (keys(command.beforeHooks).length == 0)
+        {
+            delete command.beforeHookNames;
+            delete command.beforeHooks;
+        }
+    }
+    else
+    {
+        arrayRemoveAt(command.afterHookNames,
+                      command.afterHooks[id][id + "_hookIndex"]);
+        delete command.afterHooks[id][id + "_hookIndex"];
+        delete command.afterHooks[id];
+        if (command.afterHookNames.length == 0)
+        {
+            delete command.afterHookNames;
+            delete command.afterHooks;
+        }
     }
 
-    parentElem.appendChild(popup);    
-    this.hookPopup (id);
-}
-
-/**
- * Appends a menuitem to an existing menu or popup.
- * @param parent  ID of the popup to add this menuitem to.
- * @param command A reference to the CommandRecord this menu item will represent.
- * @param attribs Object containing CSS attributes to set on the element.
- */
-CommandManager.prototype.appendMenuItem =
-function cmgr_addmenu (parent, command, attribs)
-{
-    if (command == "-")
-    {
-        this.appendMenuSeparator(parent, attribs);
-        return;
-    }
-    
-    var parentElem = document.getElementById(parent + "-popup");
-    if (!parentElem)
-        parentElem = document.getElementById(parent);
-    
-    if (!ASSERT(parentElem, "appendMenuItem: couldn't get parent '" + parent +
-                "' for " + command.name))
-        return;
-    
-    var menuitem = document.createElement ("menuitem");
-    var id = parent + ":" + command.name;
-    menuitem.setAttribute ("id", id);
-    menuitem.setAttribute ("commandname", command.name);
-    menuitem.setAttribute ("key", "key:" + command.name);
-    menuitem.setAttribute ("accesskey", getAccessKey(command.label));
-    menuitem.setAttribute ("label", command.label.replace("&", ""));
-    menuitem.setAttribute ("oncommand",
-                           "dispatch('" + command.name + "');");
-    if (typeof attribs == "object")
-    {
-        for (var p in attribs)
-            menuitem.setAttribute (p, attribs[p]);
-    }
-    
-    command.uiElements[id] = menuitem;
-    parentElem.appendChild (menuitem);
-}
-
-/**
- * Appends a menuseparator to an existing menu or popup.
- * @param parent  ID of the popup to add this menuitem to.
- */
-CommandManager.prototype.appendMenuSeparator =
-function cmgr_addsep (parent)
-{
-    var parentElem = document.getElementById(parent + "-popup");
-    if (!parentElem)
-        parentElem = document.getElementById(parent);
-    
-    if (!ASSERT(parentElem, "appendMenuSeparator: couldn't get parent '" + 
-                parent + "'"))
-        return;
-    
-    var menuitem = document.createElement ("menuseparator");
-    menuitem.setAttribute ("isSeparator", true);
-    if (typeof attribs == "object")
-    {
-        for (var p in attribs)
-            menuitem.setAttribute (p, attribs[p]);
-    }
-    parentElem.appendChild (menuitem);
-}
-
-/**
- * Appends a toolbaritem to an existing box element.
- * @param parent  ID of the box to add this toolbaritem to.
- * @param command A reference to the CommandRecord this toolbaritem will
- *                represent.
- * @param attribs Object containing CSS attributes to set on the element.
- */
-CommandManager.prototype.appendToolbarItem =
-function cmgr_addtb (parent, command, attribs)
-{
-    if (command == "-")
-    {
-        this.appendToolbarSeparator(parent, attribs);
-        return;
-    }
-
-    var parentElem = document.getElementById(parent);
-    
-    if (!ASSERT(parentElem, "appendToolbarItem: couldn't get parent '" + parent +
-                "' for " + command.name))
-        return;
-    
-    var tbitem = document.createElement ("toolbarbutton");
-    // separate toolbar id's with a "-" character, because : intereferes with css
-    var id = parent + "-" + command.name;
-    tbitem.setAttribute ("id", id);
-    tbitem.setAttribute ("class", "toolbarbutton-1");
-    tbitem.setAttribute ("label", command.label.replace("&", ""));
-    tbitem.setAttribute ("oncommand",
-                         "dispatch('" + command.name + "');");
-    if (typeof attribs == "object")
-    {
-        for (var p in attribs)
-            tbitem.setAttribute (p, attribs[p]);
-    }
-    
-    command.uiElements[id] = tbitem;
-    parentElem.appendChild (tbitem);
-}
-
-/**
- * Appends a toolbarseparator to an existing box.
- * @param parent  ID of the box to add this toolbarseparator to.
- */
-CommandManager.prototype.appendToolbarSeparator =
-function cmgr_addmenu (parent)
-{
-    var parentElem = document.getElementById(parent);    
-    if (!ASSERT(parentElem, "appendToolbarSeparator: couldn't get parent '" + 
-                parent + "'"))
-        return;
-    
-    var tbitem = document.createElement ("toolbarseparator");
-    tbitem.setAttribute ("isSeparator", true);
-    if (typeof attribs == "object")
-    {
-        for (var p in attribs)
-            tbitem.setAttribute (p, attribs[p]);
-    }
-    parentElem.appendChild (tbitem);
 }
 
 /**
@@ -574,8 +427,8 @@ function cmgr_list (partialName, flags)
      * all commands if |partialName| is not specified */
     function compare (a, b)
     {
-        a = a.label.toLowerCase().replace("&", "");
-        b = b.label.toLowerCase().replace("&", "");
+        a = a.labelstr.toLowerCase();
+        b = b.labelstr.toLowerCase();
 
         if (a == b)
             return 0;
@@ -723,7 +576,7 @@ function parse_parseargsraw (e)
         }
     }
         
-    if (e.inputData)
+    if ("inputData" in e && e.inputData)
     {
         /* if data has been provided, parse it */
         e.unparsedData = e.inputData;
@@ -792,7 +645,7 @@ function parse_parseargsraw (e)
  * Returns true if |e| has the properties required to call the command |command|.
  * If |command| is not provided, |e.command| is used instead.
  * @param e        Event object to test against the command.
- * @param command  Command to text.
+ * @param command  Command to test.
  */
 CommandManager.prototype.isCommandSatisfied =
 function cmgr_isok (e, command)
@@ -821,7 +674,7 @@ function cmgr_isok (e, command)
 }
 
 /**
- * Internally use only.
+ * Internal use only.
  * See parseArguments above and the |argTypes| object below.
  *
  * Parses the next argument by calling an appropriate parser function, or the
@@ -868,7 +721,7 @@ function at_alias (list, type)
  * Parses an integer, stores result in |e[name]|.
  */
 CommandManager.prototype.argTypes["int"] =
-function parse_number (e, name)
+function parse_int (e, name)
 {
     var ary = e.unparsedData.match (/(\d+)(?:\s+(.*))?$/);
     if (!ary)
@@ -886,7 +739,7 @@ function parse_number (e, name)
  * Stores result in |e[name]|.
  */
 CommandManager.prototype.argTypes["word"] =
-function parse_number (e, name)
+function parse_word (e, name)
 {
     var ary = e.unparsedData.match (/(\S+)(?:\s+(.*))?$/);
     if (!ary)
@@ -905,13 +758,13 @@ function parse_number (e, name)
  * Stores result in |e[name]|.
  */
 CommandManager.prototype.argTypes["state"] =
-function parse_number (e, name)
+function parse_state (e, name)
 {
     var ary =
         e.unparsedData.match (/(true|on|yes|1|false|off|no|0)(?:\s+(.*))?$/i);
     if (!ary)
         return false;
-    if (ary[1].toLowerCase().search(/true|on|yes|1/i) != -1)
+    if (ary[1].search(/true|on|yes|1/i) != -1)
         e[name] = true;
     else
         e[name] = false;
@@ -929,7 +782,7 @@ function parse_number (e, name)
  * Stores result in |e[name]|.
  */
 CommandManager.prototype.argTypes["toggle"] =
-function parse_number (e, name)
+function parse_toggle (e, name)
 {
     var ary = e.unparsedData.match
         (/(toggle|true|on|yes|1|false|off|no|0)(?:\s+(.*))?$/i);
@@ -954,7 +807,7 @@ function parse_number (e, name)
  * Stores result in |e[name]|.
  */
 CommandManager.prototype.argTypes["rest"] =
-function parse_number (e, name)
+function parse_rest (e, name)
 {
     e[name] = e.unparsedData;
     e.unparsedData = "";
diff --git a/mozilla/extensions/venkman/resources/content/html-consts.js b/mozilla/extensions/venkman/resources/content/html-consts.js
index 0a988e9d272..283df86d636 100644
--- a/mozilla/extensions/venkman/resources/content/html-consts.js
+++ b/mozilla/extensions/venkman/resources/content/html-consts.js
@@ -92,6 +92,11 @@ function htmlBR(attribs)
     return HTML("html:br", attribs, argumentsAsArray(arguments, 1));
 }
 
+function htmlWBR(attribs)
+{
+    return HTML("html:wbr", attribs, argumentsAsArray(arguments, 1));
+}
+    
 function htmlImg(attribs, src)
 {
     var img = HTML("html:img", attribs, argumentsAsArray(arguments, 2));
diff --git a/mozilla/extensions/venkman/resources/content/menu-manager.js b/mozilla/extensions/venkman/resources/content/menu-manager.js
new file mode 100644
index 00000000000..4ba1a2ea8fe
--- /dev/null
+++ b/mozilla/extensions/venkman/resources/content/menu-manager.js
@@ -0,0 +1,497 @@
+/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*-
+ *
+ * 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 Netscape are
+ * Copyright (C) 1998 Netscape Communications Corporation.
+ *
+ * Alternatively, the contents of this file may be used under the
+ * terms of the GNU Public License (the "GPL"), in which case the
+ * provisions of the GPL are applicable instead of those above.
+ * If you wish to allow use of your version of this file only
+ * under the terms of the GPL and not to allow others to use your
+ * version of this file under the MPL, indicate your decision by
+ * deleting the provisions above and replace them with the notice
+ * and other provisions required by the GPL.  If you do not delete
+ * the provisions above, a recipient may use your version of this
+ * file under either the MPL or the GPL.
+ *
+ * Contributor(s):
+ *  Robert Ginda, , original author
+ *
+ */
+
+function MenuManager (commandManager, menuSpecs, contextFunction, commandStr)
+{
+    var menuManager = this;
+
+    this.commandManager = commandManager;
+    this.menuSpecs = menuSpecs;
+    this.contextFunction = contextFunction;
+    this.commandStr = commandStr;
+
+    this.onPopupShowing =
+        function mmgr_onshow (event) { return menuManager.showPopup (event); };
+    this.onPopupHiding =
+        function mmgr_onhide (event) { return menuManager.hidePopup (event); };
+}
+
+/**
+ * Internal use only.
+ *
+ * Registers event handlers on a given menu.
+ */
+MenuManager.prototype.hookPopup =
+function mmgr_hookpop (node)
+{
+    node.addEventListener ("popupshowing", this.onPopupShowing, false);
+    node.addEventListener ("popuphiding",  this.onPopupHiding, false);
+}
+
+/**
+ * Internal use only.
+ *
+ * |showPopup| is called from the "onpopupshowing" event of menus
+ * managed by the CommandManager.  If a command is disabled, represents a command
+ * that cannot be "satisfied" by the current command context |cx|, or has an
+ * "enabledif" attribute that eval()s to false, then the menuitem is disabled.
+ * In addition "checkedif" and "visibleif" attributes are eval()d and
+ * acted upon accordingly.
+ */
+MenuManager.prototype.showPopup =
+function mmgr_showpop (event)
+{
+    //dd ("showPopup {");
+    /* returns true if the command context has the properties required to
+     * execute the command associated with |menuitem|.
+     */
+    function satisfied()
+    {
+        if (menuitem.hasAttribute("isSeparator"))
+            return true;
+
+        if (!("menuManager" in cx))
+        {
+            dd ("no menuManager in cx");
+            return false;
+        }
+        
+        var name = menuitem.getAttribute("commandname");
+        var commandManager = cx.menuManager.commandManager;
+        var commands = commandManager.commands;
+
+        if (!ASSERT (name in commands,
+                     "menu contains unknown command '" + name + "'"))
+        {
+            return false;
+        }
+
+        var rv = commandManager.isCommandSatisfied(cx, commands[name]);
+        delete cx.parseError;
+        return rv;
+    };
+    
+    /* Convenience function for "enabledif", etc, attributes. */
+    function has (prop)
+    {
+        return (prop in cx);
+    };
+    
+    /* evals the attribute named |attr| on the node |node|. */
+    function evalIfAttribute (node, attr)
+    {
+        var ex;
+        var expr = node.getAttribute(attr);
+        if (!expr)
+            return true;
+        
+        expr = expr.replace (/\Wand\W/gi, " && ");
+
+        try
+        {
+            return eval("(" + expr + ")");
+        }
+        catch (ex)
+        {
+            dd ("caught exception evaling '" + node.getAttribute("id") + "'.'" +
+                attr + "'\n" + ex);
+        }
+        return true;
+    };
+    
+    var cx;
+    var popup = event.originalTarget;
+    var menuitem = popup.firstChild;
+
+    
+    /* If the host provided a |contextFunction|, use it now.  Remember the
+     * return result as this.cx for use if something from this menu is actually
+     * dispatched.  this.cx is deleted in |hidePopup|. */
+    if (typeof this.contextFunction == "function")
+    {
+        cx = this.cx = this.contextFunction (popup.getAttribute("menuName"),
+                                             event);
+    }
+    else
+    {
+        cx = this.cx = { menuManager: this, originalEvent: event };
+    }
+
+    do
+    {
+        /* should it be visible? */
+        if (menuitem.hasAttribute("visibleif"))
+        {
+            if (evalIfAttribute(menuitem, "visibleif"))
+                menuitem.removeAttribute ("hidden");
+            else
+            {
+                menuitem.setAttribute ("hidden", "true");
+                continue;
+            }
+        }
+        
+        /* ok, it's visible, maybe it should be disabled? */
+        if (satisfied())
+        {
+            if (menuitem.hasAttribute("enabledif"))
+            {
+                if (evalIfAttribute(menuitem, "enabledif"))
+                    menuitem.removeAttribute ("disabled");
+                else
+                    menuitem.setAttribute ("disabled", "true");
+            }
+            else
+                menuitem.removeAttribute ("disabled");
+        }
+        else
+        {
+            menuitem.setAttribute ("disabled", "true");
+        }
+        
+        /* should it have a check? */
+        if (menuitem.hasAttribute("checkedif"))
+        {
+            if (evalIfAttribute(menuitem, "checkedif"))
+                menuitem.setAttribute ("checked", "true");
+            else
+                menuitem.removeAttribute ("checked");
+        }
+        
+    } while ((menuitem = menuitem.nextSibling));
+
+    //dd ("}");
+    
+    return true;
+}
+
+/**
+ * Internal use only.
+ *
+ * |hidePopup| is called from the "onpopuphiding" event of menus
+ * managed by the CommandManager.  Nothing to do here anymore.
+ * We used to just clean up this.cx, but that's a problem for nested
+ * menus.
+ */
+MenuManager.prototype.hidePopup =
+function mmgr_hidepop (id)
+{
+    return true;
+}
+
+/**
+ * Appends a sub-menu to an existing menu.
+ * @param parentNode  DOM Node to insert into
+ * @param beforeNode  DOM Node already contained by parentNode, to insert before
+ * @param id      ID of the sub-menu to add.
+ * @param label   Text to use for this sub-menu.  The & character can be
+ *                used to indicate the accesskey.
+ * @param attribs Object containing CSS attributes to set on the element.
+ */
+MenuManager.prototype.appendSubMenu =
+function mmgr_addsmenu (parentNode, beforeNode, menuName, domId, label, attribs)
+{
+    var document = parentNode.ownerDocument;
+    
+    /* sometimes the menu is already there, for overlay purposes. */
+    var menu = document.getElementById(domId);
+    
+    if (!menu)
+    {
+        menu = document.createElement ("menu");
+        menu.setAttribute ("id", domId);
+        parentNode.insertBefore(menu, beforeNode);
+    }
+
+    var menupopup = menu.firstChild;
+    
+    if (!menupopup)
+    {
+        menupopup = document.createElement ("menupopup");
+        menupopup.setAttribute ("id", domId + "-popup");
+        menu.appendChild(menupopup);    
+        menupopup = menu.firstChild;
+    }
+
+    menupopup.setAttribute ("menuName", menuName);
+
+    menu.setAttribute ("accesskey", getAccessKey(label));
+    menu.setAttribute ("label", label.replace("&", ""));
+    menu.setAttribute ("isSeparator", true);
+
+    if (typeof attribs == "object")
+    {
+        for (var p in attribs)
+            menu.setAttribute (p, attribs[p]);
+    }
+
+    this.hookPopup (menupopup);
+
+    return menupopup;
+}
+
+/**
+ * Appends a popup to an existing popupset.
+ * @param parentNode  DOM Node to insert into
+ * @param beforeNode  DOM Node already contained by parentNode, to insert before
+ * @param id      ID of the popup to add.
+ * @param label   Text to use for this popup.  Popup menus don't normally have
+ *                labels, but we set a "label" attribute anyway, in case
+ *                the host wants it for some reason.  Any "&" characters will
+ *                be stripped.
+ * @param attribs Object containing CSS attributes to set on the element.
+ */
+MenuManager.prototype.appendPopupMenu =
+function mmgr_addpmenu (parentNode, beforeNode, menuName, id, label, attribs)
+{
+    var document = parentNode.ownerDocument;
+    var popup = document.createElement ("popup");
+    popup.setAttribute ("id", id);
+    if (label)
+        popup.setAttribute ("label", label.replace("&", ""));
+    if (typeof attribs == "object")
+    {
+        for (var p in attribs)
+            popup.setAttribute (p, attribs[p]);
+    }
+
+    popup.setAttribute ("menuName", menuName);
+
+    parentNode.insertBefore(popup, beforeNode);
+    this.hookPopup (popup);
+
+    return popup;
+}
+
+/**
+ * Appends a menuitem to an existing menu or popup.
+ * @param parentNode  DOM Node to insert into
+ * @param beforeNode  DOM Node already contained by parentNode, to insert before
+ * @param command A reference to the CommandRecord this menu item will represent.
+ * @param attribs Object containing CSS attributes to set on the element.
+ */
+MenuManager.prototype.appendMenuItem =
+function mmgr_addmenu (parentNode, beforeNode, commandName, attribs)
+{
+    var menuManager = this;    
+    
+    var document = parentNode.ownerDocument;
+    if (commandName == "-")
+        return this.appendMenuSeparator(parentNode, beforeNode, attribs);
+    
+    var parentId = parentNode.getAttribute("id");
+    
+    if (!ASSERT(commandName in this.commandManager.commands,
+                "unknown command " + commandName + " targeted for " +
+                parentId))
+    {
+        return null;
+    }
+
+    var command = this.commandManager.commands[commandName];
+    var menuitem = document.createElement ("menuitem");
+    menuitem.setAttribute ("id", parentId + ":" + commandName);
+    menuitem.setAttribute ("commandname", command.name);
+    menuitem.setAttribute ("key", "key:" + command.name);
+    menuitem.setAttribute ("accesskey", getAccessKey(command.label));
+    menuitem.setAttribute ("label", command.label.replace("&", ""));
+    menuitem.setAttribute ("oncommand", this.commandStr);
+
+    if (typeof attribs == "object")
+    {
+        for (var p in attribs)
+            menuitem.setAttribute (p, attribs[p]);
+    }
+    
+    command.uiElements.push(menuitem);
+    parentNode.insertBefore (menuitem, beforeNode);
+
+    return menuitem;
+}
+
+/**
+ * Appends a menuseparator to an existing menu or popup.
+ * @param parentNode  DOM Node to insert into
+ * @param beforeNode  DOM Node already contained by parentNode, to insert before
+ * @param attribs Object containing CSS attributes to set on the element.
+ */
+MenuManager.prototype.appendMenuSeparator =
+function mmgr_addsep (parentNode, beforeNode, attribs)
+{
+    var document = parentNode.ownerDocument;
+    var menuitem = document.createElement ("menuseparator");
+    menuitem.setAttribute ("isSeparator", true);
+    if (typeof attribs == "object")
+    {
+        for (var p in attribs)
+            menuitem.setAttribute (p, attribs[p]);
+    }
+    parentNode.insertBefore (menuitem, beforeNode);
+
+    return menuitem;
+}
+
+/**
+ * Appends a toolbaritem to an existing box element.
+ * @param parentNode  DOM Node to insert into
+ * @param beforeNode  DOM Node already contained by parentNode, to insert before
+ * @param command A reference to the CommandRecord this toolbaritem will
+ *                represent.
+ * @param attribs Object containing CSS attributes to set on the element.
+ */
+MenuManager.prototype.appendToolbarItem =
+function mmgr_addtb (parentNode, beforeNode, commandName, attribs)
+{
+    if (commandName == "-")
+        return this.appendToolbarSeparator(parentNode, beforeNode, attribs);
+
+    var parentId = parentNode.getAttribute("id");
+    
+    if (!ASSERT(commandName in this.commandManager.commands,
+                "unknown command " + commandName + " targeted for " +
+                parentId))
+    {
+        return null;
+    }
+    
+    var command = this.commandManager.commands[commandName];
+    var document = parentNode.ownerDocument;    
+    var tbitem = document.createElement ("toolbarbutton");
+
+    var id = parentNode.getAttribute("id") + ":" + commandName;
+    tbitem.setAttribute ("id", id);
+    tbitem.setAttribute ("class", "toolbarbutton-1");
+    tbitem.setAttribute ("label", command.label.replace("&", ""));
+    tbitem.setAttribute ("oncommand",
+                         "dispatch('" + commandName + "');");
+    if (typeof attribs == "object")
+    {
+        for (var p in attribs)
+            tbitem.setAttribute (p, attribs[p]);
+    }
+    
+    command.uiElements.push(tbitem);
+    parentNode.insertBefore (tbitem, beforeNode);
+
+    return tbitem;
+}
+
+/**
+ * Appends a toolbarseparator to an existing box.
+ * @param parentNode  DOM Node to insert into
+ * @param beforeNode  DOM Node already contained by parentNode, to insert before
+ * @param attribs Object containing CSS attributes to set on the element.
+ */
+MenuManager.prototype.appendToolbarSeparator =
+function mmgr_addmenu (parentNode, beforeNode, attribs)
+{
+    var document = parentNode.ownerDocument;    
+    var tbitem = document.createElement ("toolbarseparator");
+    tbitem.setAttribute ("isSeparator", true);
+    if (typeof attribs == "object")
+    {
+        for (var p in attribs)
+            tbitem.setAttribute (p, attribs[p]);
+    }
+    parentNode.appendChild (tbitem);
+
+    return tbitem;
+}
+
+/**
+ * Creates menu DOM nodes from a menu specification.
+ * @param parentNode  DOM Node to insert into
+ * @param beforeNode  DOM Node already contained by parentNode, to insert before
+ * @param menuSpec    array of menu items
+ */
+MenuManager.prototype.createMenu =
+function mmgr_newmenu (parentNode, beforeNode, menuName, domId, attribs)
+{
+    if (typeof domId == "undefined")
+        domId = menuName;
+    
+    if (!ASSERT(menuName in this.menuSpecs, "unknown menu name " + menuName))
+        return null;
+
+    var menuSpec = this.menuSpecs[menuName];
+    
+    var subMenu = this.appendSubMenu (parentNode, beforeNode, menuName, domId,
+                                      menuSpec.label, attribs);
+
+    this.createMenuItems (subMenu, null, menuSpec.items);
+    return subMenu;
+}
+
+MenuManager.prototype.createMenuItems =
+function mmgr_newitems (parentNode, beforeNode, menuItems)
+{
+    function itemAttribs()
+    {
+        return (1 in menuItems[i]) ? menuItems[i][1] : null;
+    };
+
+    var parentId = parentNode.getAttribute("id");
+    
+    for (var i in menuItems)
+    {
+        var itemName = menuItems[i][0];
+        if (itemName[0] == ">")
+        {
+            itemName = itemName.substr(1);
+            if (!ASSERT(itemName in this.menuSpecs,
+                        "unknown submenu " + itemName + " referenced in " +
+                        parentId))
+            {
+                continue;
+            }
+            this.createMenu (parentNode, beforeNode, itemName,
+                             parentId + ":" + itemName, itemAttribs());
+        }
+        else if (itemName in this.commandManager.commands)
+        {
+            this.appendMenuItem (parentNode, beforeNode, itemName,
+                                 itemAttribs());
+        }
+        else if (itemName == "-")
+        {
+            this.appendMenuSeparator (parentNode, beforeNode, itemAttribs());
+        }
+        else
+        {
+            dd ("unknown command " + itemName + " referenced in " + parentId);
+        }
+    }
+        
+}
diff --git a/mozilla/extensions/venkman/resources/content/profile.csv.tpl b/mozilla/extensions/venkman/resources/content/profile.csv.tpl
new file mode 100644
index 00000000000..b21f081ff97
--- /dev/null
+++ b/mozilla/extensions/venkman/resources/content/profile.csv.tpl
@@ -0,0 +1,4 @@
+# full-url, file-name, function-name, start-line, end-line, call-count, recurse-depth, total-time, min-time, max-time, avg-time
+@-item-start
+$full-url, $file-name, $function-name, $start-line, $end-line, $call-count, $recurse-depth, $total-time, $min-time, $max-time, $avg-time
+@-item-end
diff --git a/mozilla/extensions/venkman/resources/content/profile.html.tpl b/mozilla/extensions/venkman/resources/content/profile.html.tpl
index fbfd811f252..6e6c993a020 100644
--- a/mozilla/extensions/venkman/resources/content/profile.html.tpl
+++ b/mozilla/extensions/venkman/resources/content/profile.html.tpl
@@ -70,14 +70,16 @@
     $user-agent
JavaScript Debugger Version: $venkman-agent
+ Sorted By: + $sort-key
- +@-section-start

$section-link

- +@-range-start

$range-min - $range-max ms

@@ -85,7 +87,7 @@ Next File | Previous Range | Next Range ] - +@-item-start @@ -103,12 +105,12 @@ width="$item-above-pct%"> - +@-item-end
- +@-range-end
- +@-section-end
No job is too big, no fee is too big. diff --git a/mozilla/extensions/venkman/resources/content/profile.txt.tpl b/mozilla/extensions/venkman/resources/content/profile.txt.tpl new file mode 100644 index 00000000000..3b9d1330fbb --- /dev/null +++ b/mozilla/extensions/venkman/resources/content/profile.txt.tpl @@ -0,0 +1,30 @@ + + Venkman Profile Report + +Created .......... $full-date +User Agent ....... $user-agent +Debugger Version . $venkman-agent +Sorted By ........ $sort-key + +================================================================================= +@-section-start +$section-number <$full-url> + +@-range-start + $file-name: $range-min - $range-max milliseconds +@-item-start + Function Name: $function-name (Lines $start-line - $end-line) + Total Calls: $call-count (max recurse $recurse-depth) + Total Time: $total-time (min/max/avg $min-time/$max-time/$avg-time) + +@-item-end + ------------------------------------------------------------------------------- + +@-range-end +================================================================================= + +@-section-end + + +Thanks for using Venkman, the Mozilla JavaScript Debugger. + diff --git a/mozilla/extensions/venkman/resources/content/profile.xml.tpl b/mozilla/extensions/venkman/resources/content/profile.xml.tpl new file mode 100644 index 00000000000..8303db94fb5 --- /dev/null +++ b/mozilla/extensions/venkman/resources/content/profile.xml.tpl @@ -0,0 +1,43 @@ + + + +@-section-start +
+@-range-start + +@-item-start + +@-item-end + +@-range-end +
+@-section-end +
diff --git a/mozilla/extensions/venkman/resources/content/tests/tree.js b/mozilla/extensions/venkman/resources/content/tests/tree.js index 2fa87c7183f..75a077f59d3 100644 --- a/mozilla/extensions/venkman/resources/content/tests/tree.js +++ b/mozilla/extensions/venkman/resources/content/tests/tree.js @@ -33,8 +33,7 @@ * */ -var sampleShare = new Object(); -var sampleTree = new TreeOView(sampleShare); +var sampleTree = new XULTreeView(); function SampleRecord (name, gender) { @@ -44,7 +43,7 @@ function SampleRecord (name, gender) this.gender = gender; } -SampleRecord.prototype = new TreeOViewRecord(sampleShare); +SampleRecord.prototype = new XULTreeViewRecord(sampleTree.share); sampleTree.childData.appendChild (new SampleRecord ("vinnie", "male")); var betty = new SampleRecord ("betty", "female"); @@ -108,7 +107,6 @@ function nativeFrameTest() { function compare(a, b) { - debugger; if (a > b) return 1; @@ -126,6 +124,7 @@ function dbg() { var a = 0; dbg2(); + nativeFrameTest(); var c = 0; } @@ -141,7 +140,33 @@ function dbg2() var fun = dbg; var obj = new Object(); debugger; - guessThis(); + + try + { + guessThis(); + throwSomething(); + } + catch (ex) + { + dd ("caught " + ex); + } + + var rv = returnSomething(); + dd ("returned " + rv); +} + +function throwSomething() +{ + var str = "this is a test"; + var obj = { message: "this is only a test" }; + throw "momma from the train"; +} + +function returnSomething() +{ + var str = "this is a test"; + var obj = { message: "this is only a test" }; + return "your library books on time!"; } function dt() @@ -178,4 +203,3 @@ function switchTest () break; } } - diff --git a/mozilla/extensions/venkman/resources/content/tests/tree.xul b/mozilla/extensions/venkman/resources/content/tests/tree.xul index 2310e3b922f..cf2568a1213 100644 --- a/mozilla/extensions/venkman/resources/content/tests/tree.xul +++ b/mozilla/extensions/venkman/resources/content/tests/tree.xul @@ -31,7 +31,6 @@ -