/* -*- 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, , 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 ***** */ const DEFAULT_VURLS = ("x-vloc:/mainwindow/initial-container?target=container&id=outer&type=horizontal;" + // left vert (gutter) ("x-vloc:/mainwindow/outer?target=container&id=gutter&width=231&before=vright&type=vertical;" + // top tab ("x-vloc:/mainwindow/gutter?target=container&id=top-tab&height=177&before=vm-container-5&type=tab;" + "x-vloc:/mainwindow/top-tab?target=view&id=scripts&height=177&before=windows;" + "x-vloc:/mainwindow/top-tab?target=view&id=windows;" ) + // middle tab ("x-vloc:/mainwindow/gutter?target=container&id=mid-tab&height=121&type=tab;" + "x-vloc:/mainwindow/mid-tab?target=view&id=locals;" + "x-vloc:/mainwindow/mid-tab?target=view&id=watches;" ) + // bottom tab ("x-vloc:/mainwindow/gutter?target=container&id=bot-tab&height=100&type=tab;" + "x-vloc:/mainwindow/bot-tab?target=view&id=breaks&height=100&;" + "x-vloc:/mainwindow/bot-tab?target=view&id=stack&height=75;" ) ) + // right vert ("x-vloc:/mainwindow/outer?target=container&id=vright&width=560&type=vertical;" + "x-vloc:/mainwindow/vright?target=view&id=source2&before=session;" + "x-vloc:/mainwindow/vright?target=view&id=session&width=677" ) ) function initViews() { var prefs = [ ["layoutState.default", DEFAULT_VURLS], ["saveLayoutOnExit", true] ]; console.prefManager.addPrefs (prefs); const ATOM_CTRID = "@mozilla.org/atom-service;1"; const nsIAtomService = Components.interfaces.nsIAtomService; console.atomService = Components.classes[ATOM_CTRID].getService(nsIAtomService); console.viewManager = new ViewManager (console.commandManager, console.mainWindow); console.viewManager.realizeViews (console.views, console.menuSpecs["popup:showhide"]); console.views = console.viewManager.views; for (var viewId in console.views) { if (("enableMenuItem" in console.views[viewId]) && !console.views[viewId].enableMenuItem) { continue; } var toggleCommand = "toggle-" + viewId; if (toggleCommand in console.commandManager.commands) { var entry = [toggleCommand, { type: "checkbox", checkedif: "'currentContent' in console.views." + viewId }]; console.menuSpecs["popup:showhide"].items.push(entry); } } } function destroyViews() { console.viewManager.destroyWindows (); console.viewManager.unrealizeViews (console.views); } /** * Sync a XUL tree with the view that it represents. * * XUL trees seem to take a small amount of time to initialize themselves to * the point where they're willing to accept a view object. This method will * call itself back after a small delay if the XUL tree is not ready yet. */ function syncTreeView (treeContent, treeView, cb) { function ondblclick(event) { treeView.onRouteDblClick(event); }; function onkeypress(event) { treeView.onRouteKeyPress(event); }; function onfocus(event) { treeView.onRouteFocus(event); }; function onblur(event) { treeView.onRouteBlur(event); }; function tryAgain() { if ("treeBoxObject" in treeContent) { syncTreeView(treeContent, treeView, cb); } else { //dd ("trying to sync " + treeContent.getAttribute("id")); setTimeout (tryAgain, 500); } }; try { if (!("treeBoxObject" in treeContent)) throw "tantrum"; treeContent.treeBoxObject.view = treeView; if (treeView.selection) { treeView.selection.tree = treeContent.treeBoxObject; } } catch (ex) { setTimeout (tryAgain, 500); return; } if (!treeView) { if ("_listenersInstalled" in treeContent && treeContent._listenersInstalled) { treeContent._listenersInstalled = false; treeContent.removeEventListener("dblclick", ondblclick, false); treeContent.removeEventListener("keypress", onkeypress, false); treeContent.removeEventListener("focus", onfocus, false); treeContent.removeEventListener("blur", onblur, false); } } else if (!("_listenersInstalled" in treeContent) || !treeContent._listenersInstalled) { try { treeContent.addEventListener("dblclick", ondblclick, false); treeContent.addEventListener("keypress", onkeypress, false); treeContent.addEventListener("focus", onfocus, false); treeContent.addEventListener("blur", onblur, false); } catch (ex) { dd ("caught exception setting listeners: " + ex); } treeContent._listenersInstalled = true; } if (typeof cb == "function") cb(); } function getTreeContext (view, cx, recordContextGetter) { //dd ("getTreeContext {"); var i = 0; var selection = view.tree.view.selection; var row = selection.currentIndex; var rec; if (view instanceof XULTreeView) { rec = view.childData.locateChildByVisualRow (row); if (!rec) { //dd ("} no record at currentIndex " + row); return cx; } } else { rec = row; } cx.target = rec; recordContextGetter(cx, rec, i++); var rangeCount = selection.getRangeCount(); //dd ("walking ranges {"); for (var range = 0; range < rangeCount; ++range) { var min = new Object(); var max = new Object(); selection.getRangeAt(range, min, max); min = min.value; max = max.value; for (row = min; row <= max; ++row) { if (view instanceof XULTreeView) { rec = view.childData.locateChildByVisualRow(row); if (!rec) dd ("no record at range index " + row); } else { rec = row; } recordContextGetter(cx, rec, i++); } } //dd ("}"); //dd ("cleaning up {"); /* delete empty arrays as that may have been left behind. */ for (var p in cx) { if (cx[p] instanceof Array && !cx[p].length) delete cx[p]; } //dd ("}"); //dd ("}"); return cx; } function initContextMenu (document, id) { if (!document.getElementById(id)) { if (!ASSERT(id in console.menuSpecs, "unknown context menu " + id)) return; var dp = document.getElementById("dynamic-popups"); var popup = console.menuManager.appendPopupMenu (dp, null, id, id); var items = console.menuSpecs[id].items; console.menuManager.createMenuItems (popup, null, items); } } console.viewDragProxy = new Object(); console.viewDragProxy.onDragStart = Prophylactic(console.viewDragProxy, vpxy_dragstart); function vpxy_dragstart (event, transferData, action) { console.viewManager.onDragStart (event, transferData, action); return true; } console.viewDropProxy = new Object(); console.viewDropProxy.onDrop = function vpxy_drop (event, transferData, session) { console.viewManager.onViewDrop (event, transferData, session); /* when moving into a new view, the parent view won't repaint until * the mouse moves, or we do call the paintHack. */ paintHack(); return true; } console.viewDropProxy.onDragOver = function vpxy_dragover (event, flavor, session) { console.viewManager.onViewDragOver (event, flavor, session); return true; } console.viewDropProxy.onDragExit = function vpxy_dragexit (event, session) { console.viewManager.onViewDragExit (event, session); } console.viewDropProxy.getSupportedFlavours = function vpxy_getflavors () { return console.viewManager.getSupportedFlavours(); } console.views = new Object(); /******************************************************************************* * Breakpoints View ******************************************************************************/ console.views.breaks = new XULTreeView(); const VIEW_BREAKS = "breaks" console.views.breaks.viewId = VIEW_BREAKS; console.views.breaks.hooks = new Object(); console.views.breaks.hooks["hook-fbreak-set"] = function bv_hookFBreakSet (e) { var breakRecord = new BPRecord (e.fbreak); breakRecord.reserveChildren(); e.fbreak.breakRecord = breakRecord; console.views.breaks.childData.appendChild(breakRecord); } console.views.breaks.hooks["hook-fbreak-clear"] = function bv_hookFBreakClear (e) { var breakRecord = e.fbreak.breakRecord; delete e.fbreak.breakRecord; console.views.breaks.childData.removeChildAtIndex(breakRecord.childIndex); for (var i in breakRecord.childData) { console.views.breaks.childData.appendChild(breakRecord.childData[i]); } } console.views.breaks.hooks["hook-break-set"] = function bv_hookBreakSet (e) { var breakRecord = new BPRecord (e.breakWrapper); e.breakWrapper.breakRecord = breakRecord; if (e.breakWrapper.parentBP) { var parentRecord = e.breakWrapper.parentBP.breakRecord; parentRecord.appendChild(breakRecord); } else { console.views.breaks.childData.appendChild(breakRecord); } } console.views.breaks.hooks["hook-break-clear"] = function bv_hookBreakClear (e) { var breakRecord = e.breakWrapper.breakRecord; if (e.breakWrapper.parentBP) { var parentRecord = e.breakWrapper.parentBP.breakRecord; parentRecord.removeChildAtIndex(breakRecord.childIndex); } else { var idx = breakRecord.childIndex; console.views.breaks.childData.removeChildAtIndex(idx); } } console.views.breaks.init = function bv_init () { console.menuSpecs["context:breaks"] = { getContext: this.getContext, items: [ ["find-url"], ["-"], ["clear-break", { enabledif: "has('hasBreak')" }], ["clear-fbreak", { enabledif: "has('hasFBreak')" }], ["-"], ["clear-all"], ["fclear-all"], ["-"], ["save-breakpoints"], ["restore-settings"], ["-"], ["break-props"] ] }; this.atomBreak = console.atomService.getAtom("item-breakpoint"); this.atomFBreak = console.atomService.getAtom("future-breakpoint"); this.caption = MSG_VIEW_BREAKS; } console.views.breaks.onShow = function bv_show() { syncTreeView (getChildById(this.currentContent, "break-tree"), this); initContextMenu(this.currentContent.ownerDocument, "context:breaks"); } console.views.breaks.onHide = function bv_hide() { syncTreeView (getChildById(this.currentContent, "break-tree"), null); } console.views.breaks.onRowCommand = function bv_rowcommand (rec) { if (rec instanceof BPRecord) dispatch ("find-bp", {breakpoint: rec.breakWrapper}); } console.views.breaks.onKeyPress = function bv_keypress(rec, e) { if (e.keyCode == 46) { cx = this.getContext({}); if ("hasBreak" in cx) dispatch ("clear-break", cx); if ("hasFBreak" in cx) dispatch ("clear-fbreak", cx); } } console.views.breaks.getContext = function bv_getcx(cx) { cx.breakWrapperList = new Array(); cx.urlList = new Array(); cx.lineNumberList = new Array(); cx.pcList = new Array(); cx.scriptWrapperList = new Array(); function recordContextGetter (cx, rec, i) { if (i == 0) { cx.breakWrapper = rec.breakWrapper; if (rec.type == "instance") { cx.hasBreak = true; cx.scriptWrapper = rec.breakWrapper.scriptWrapper; cx.pc = rec.breakWrapper.pc; } else if (rec.type == "future") { cx.hasFBreak = true; cx.url = rec.breakWrapper.url; cx.lineNumber = rec.breakWrapper.lineNumber; } } else { cx.breakWrapperList.push(rec.breakWrapper); if (rec.type == "instance") { cx.hasBreak = true; cx.scriptWrapperList.push(rec.breakWrapper.scriptWrapper); cx.pcList.push(rec.breakWrapper.pc); } else if (rec.type == "instance") { cx.hasFBreak = true; cx.urlList.push(rec.breakWrapper.url); cx.lineNumberList.push(rec.breakWrapper.lineNumber); } } }; return getTreeContext (console.views.breaks, cx, recordContextGetter); } console.views.breaks.getCellProperties = function bv_cellprops (index, col, properties) { if (col.id == "breaks:col-0") { var row = this.childData.locateChildByVisualRow(index); if (row.type == "future") properties.AppendElement (this.atomFBreak); else properties.AppendElement (this.atomBreak); } } /******************************************************************************* * Locals View ******************************************************************************/ console.views.locals = new XULTreeView(); const VIEW_LOCALS = "locals"; console.views.locals.viewId = VIEW_LOCALS; console.views.locals.init = function lv_init () { var prefs = [ ["localsView.autoOpenMax", 25], ["localsView.savedStatesMax", 20] ]; console.prefManager.addPrefs(prefs); this.cmdary = [ ["copy-qual-name", cmdCopyQualName, 0] ]; console.menuSpecs["context:locals"] = { getContext: this.getContext, items: [ ["change-value", {enabledif: "cx.parentValue"}], ["watch-expr"], ["copy-qual-name", {enabledif: "has('expression')"}], ["-"], ["set-eval-obj", {type: "checkbox", checkedif: "has('jsdValue') && " + "cx.jsdValue.getWrappedValue() == " + "console.currentEvalObject", enabledif: "has('jsdValue') && " + "cx.jsdValue.jsType == TYPE_OBJECT"}], ["-"], ["find-creator", {enabledif: "cx.target instanceof ValueRecord && " + "cx.target.jsType == jsdIValue.TYPE_OBJECT && " + "cx.target.value.objectValue.creatorURL"}], ["find-ctor", {enabledif: "cx.target instanceof ValueRecord && " + "cx.target.jsType == jsdIValue.TYPE_OBJECT && " + "cx.target.value.objectValue.constructorURL"}], ["-"], ["toggle-functions", {type: "checkbox", checkedif: "ValueRecord.prototype.showFunctions"}], ["toggle-ecmas", {type: "checkbox", checkedif: "ValueRecord.prototype.showECMAProps"}], ["toggle-constants", {type: "checkbox", checkedif: "ValueRecord.prototype.showConstants"}] ] }; this.caption = MSG_VIEW_LOCALS; this.jsdFrame = null; this.savedStates = new Object(); this.stateTags = new Array(); } function cmdCopyQualName (e) { const CLIPBOARD_CTRID = "@mozilla.org/widget/clipboardhelper;1"; const nsIClipboardHelper = Components.interfaces.nsIClipboardHelper; var clipboardHelper = Components.classes[CLIPBOARD_CTRID].getService(nsIClipboardHelper); clipboardHelper.copyString(e.expression); } console.views.locals.clear = function lv_clear () { while (this.childData.childData.length) this.childData.removeChildAtIndex(0); } console.views.locals.changeFrame = function lv_renit (jsdFrame) { this.clear(); if (!jsdFrame) { delete this.jsdFrame; return; } this.jsdFrame = jsdFrame; var state; if (jsdFrame.script) { var tag = jsdFrame.script.tag; if (tag in this.savedStates) state = this.savedStates[tag]; } if (jsdFrame.scope) { this.scopeRecord = new ValueRecord(jsdFrame.scope, MSG_VAL_SCOPE, "", jsdFrame); this.scopeRecord.onPreRefresh = null; this.childData.appendChild(this.scopeRecord); if (!state && jsdFrame.scope.propertyCount < console.prefs["localsView.autoOpenMax"]) { this.scopeRecord.open(); } } else { this.scopeRecord = new XTLabelRecord ("locals:col-0", MSV_VAL_SCOPE, ["locals:col-1", "locals:col-2", "locals:col-3"]); this.scopeRecord.property = ValueRecord.prototype.atomObject; this.childData.appendChild(this.scopeRecord); } if (jsdFrame.thisValue) { this.thisRecord = new ValueRecord (jsdFrame.thisValue, MSG_VAL_THIS, "", jsdFrame); this.thisRecord.onPreRefresh = null; this.childData.appendChild(this.thisRecord); if (!state && jsdFrame.thisValue.propertyCount < console.prefs["localsView.autoOpenMax"]) { this.scopeRecord.open(); } } else { this.thisRecord = new XTLabelRecord ("locals:col-0", MSV_VAL_THIS, ["locals:col-1", "locals:col-2", "locals:col-3"]); this.thisRecord.property = ValueRecord.prototype.atomObject; this.childData.appendChild(this.thisRecord); } if (state) this.restoreState(state); } console.views.locals.restoreState = function lv_restore (state) { this.freeze(); if ("scopeState" in state) { this.scopeRecord.open(); this.restoreBranchState (this.scopeRecord.childData, state.scopeState, true); } if ("thisState" in state) { this.thisRecord.open(); this.restoreBranchState (this.thisRecord.childData, state.thisState, true); } this.thaw(); this.scrollTo (state.firstVisible, -1); } console.views.locals.saveState = function sv_save () { if (!ASSERT(this.jsdFrame, "no frame")) return; if (!this.jsdFrame.script) return; var tag = this.jsdFrame.script.tag; if (!tag in this.savedStates && this.stateTags.length == console.prefs["localsView.maxSavedStates"]) { delete this.savedStates[this.stateTags.shift()]; this.stateTags.push(tag); } var state = this.savedStates[tag] = new Object(); if (this.tree) state.firstVisible = this.tree.getFirstVisibleRow() + 1; else state.firstVisible = 1; if (this.scopeRecord && this.scopeRecord.isContainerOpen) { state.scopeState = { name: "scope" }; this.saveBranchState (state.scopeState, this.scopeRecord.childData, true); } if (this.thisRecord && this.thisRecord.isContainerOpen) { state.thisState = { name: "this" }; this.saveBranchState (state.thisState, this.thisRecord.childData, true); } //dd ("saved as\n" + dumpObjectTree(this.savedState, 10)); } console.views.locals.hooks = new Object() console.views.locals.hooks["hook-debug-stop"] = function lv_hookDebugStop (e) { console.views.locals.changeFrame(console.frames[0]); } console.views.locals.hooks["hook-eval-done"] = function lv_hookEvalDone (e) { console.views.locals.refresh(); } console.views.locals.hooks["find-frame"] = function lv_hookFindFrame (e) { console.views.locals.changeFrame(console.frames[e.frameIndex]); } console.views.locals.hooks["hook-debug-continue"] = function lv_hookDebugContinue (e) { console.views.locals.saveState(); console.views.locals.clear(); } console.views.locals.onShow = function lv_show () { syncTreeView (getChildById(this.currentContent, "locals-tree"), this); initContextMenu(this.currentContent.ownerDocument, "context:locals"); } console.views.locals.onHide = function lv_hide () { syncTreeView (getChildById(this.currentContent, "locals-tree"), null); } console.views.locals.onRowCommand = function lv_rowcommand(rec) { if (this.isContainerEmpty(rec.childIndex) && "value" in rec.parentRecord) { dispatch ("change-value", {parentValue: rec.parentRecord.value, propertyName: rec.displayName}); } } console.views.locals.getCellProperties = function lv_cellprops (index, col, properties) { if (col.id != "locals:col-0") return null; var row = this.childData.locateChildByVisualRow(index); if (row) { if ("getProperties" in row) return row.getProperties (properties); if (row.property) return properties.AppendElement (row.property); } return null; } console.views.locals.getContext = function lv_getcx(cx) { var locals = console.views.locals; cx.jsdValueList = new Array(); function recordContextGetter (cx, rec, i) { if (i == 0) { cx.jsdValue = rec.value; cx.expression = rec.expression; cx.propertyName = rec.displayName; } else { cx.jsdValueList.push(rec.value); } return cx; }; return getTreeContext (console.views.locals, cx, recordContextGetter); } console.views.locals.refresh = function lv_refresh() { if (!this.tree) return; var rootRecord = this.childData; if (!"childData" in rootRecord) return; this.freeze(); for (var i = 0; i < rootRecord.childData.length; ++i) rootRecord.childData[i].refresh(); this.thaw(); /* the refresh may have changed a property without altering the * size of the tree, so thaw might not invalidate. */ this.tree.invalidate(); } /******************************************************************************* * Scripts View ******************************************************************************/ console.views.scripts = new XULTreeView (); const VIEW_SCRIPTS = "scripts"; console.views.scripts.viewId = VIEW_SCRIPTS; console.views.scripts.init = function scv_init () { var debugIf = "'scriptWrapper' in cx && " + "cx.scriptWrapper.jsdScript.isValid && " + "cx.scriptWrapper.jsdScript.flags & SCRIPT_NODEBUG"; var profileIf = "'scriptWrapper' in cx && " + "cx.scriptWrapper.jsdScript.isValid && " + "cx.scriptWrapper.jsdScript.flags & SCRIPT_NOPROFILE"; var transientIf = "'scriptInstance' in cx && " + "cx.scriptInstance.scriptManager.disableTransients"; var prefs = [ ["scriptsView.groupFiles", true], ["scriptsView.showMostRecent", true] ]; console.prefManager.addPrefs(prefs); this.cmdary = [ ["show-most-recent", cmdShowMostRecent, CMD_CONSOLE], ["search-scripts", cmdSearchScripts, CMD_CONSOLE], ["toggle-scripts-search-box", cmdToggleScriptsSearchBox, CMD_CONSOLE], ["toggle-show-most-recent", "show-most-recent toggle", 0] ]; console.menuSpecs["context:scripts"] = { getContext: this.getContext, items: [ ["find-scriptinstance", {visibleif: "!has('scriptWrapper')"}], ["find-script", {visibleif: "has('scriptWrapper')"}], ["set-break"], ["clear-instance", {visibleif: "!has('scriptWrapper')"}], ["clear-script", {visibleif: "has('scriptWrapper')", enabledif: "cx.scriptWrapper.breakpointCount"}], ["scan-source"], ["-"], [">scripts:instance-flags"], [">scripts:wrapper-flags", {enabledif: "has('scriptWrapper')"}], ["-"], ["save-profile"], ["clear-profile"], ["-"], ["toggle-show-most-recent", {type: "checkbox", checkedif: "console.prefs['scriptsView.showMostRecent']"}], ["toggle-chrome", {type: "checkbox", checkedif: "console.prefs['enableChromeFilter']"}] ] }; console.menuSpecs["scripts:instance-flags"] = { label: MSG_MNU_SCRIPTS_INSTANCE, items: [ ["debug-transient", {type: "checkbox", checkedif: transientIf}], ["-"], ["debug-instance-on"], ["debug-instance-off"], ["debug-instance"], ["-"], ["profile-instance-on"], ["profile-instance-off"], ["profile-instance"], ] }; console.menuSpecs["scripts:wrapper-flags"] = { label: MSG_MNU_SCRIPTS_WRAPPER, items: [ ["debug-script", {type: "checkbox", checkedif: debugIf}], ["profile-script", {type: "checkbox", checkedif: profileIf}], ] }; this.caption = MSG_VIEW_SCRIPTS; this.childData.setSortColumn("baseLineNumber"); this.groupFiles = console.prefs["scriptsView.groupFiles"]; } function cmdSearchScripts (e) { var scriptsView = console.views.scripts; var rootNode = scriptsView.childData; var i; for (i = 0; i < rootNode.childData.length; ++i) { var scriptInstanceRecord = rootNode.childData[i]; if (e.pattern && (!scriptInstanceRecord.url || scriptInstanceRecord.url.indexOf(e.pattern) == -1)) { scriptInstanceRecord.searchExclude = true; if (!scriptInstanceRecord.isHidden) scriptInstanceRecord.hide(); } else { delete scriptInstanceRecord.searchExclude; if (!("recentExclude" in scriptInstanceRecord) && scriptInstanceRecord.isHidden) { scriptInstanceRecord.unHide(); } } } if (scriptsView.currentContent) { var textbox = getChildById(scriptsView.currentContent, "scripts-search"); textbox.value = e.pattern; } } function cmdShowMostRecent (e) { e.toggle = getToggle (e.toggle, console.prefs["scriptsView.showMostRecent"]); console.prefs["scriptsView.showMostRecent"] = e.toggle; var rootNode = console.views.scripts.childData; var i; var scriptInstanceRecord; if (e.toggle) { /* want to hide duplicate script instances */ for (i = 0; i < rootNode.childData.length; ++i) { scriptInstanceRecord = rootNode.childData[i]; var scriptInstance = scriptInstanceRecord.scriptInstance; var instances = scriptInstance.scriptManager.instances; var length = instances.length; if (scriptInstance != instances[length - 1]) { scriptInstanceRecord.recentExclude = true; if (!scriptInstanceRecord.isHidden) scriptInstanceRecord.hide(); } } } else { /* show all script instances */ for (i = 0; i < rootNode.childData.length; ++i) { scriptInstanceRecord = rootNode.childData[i]; delete scriptInstanceRecord.recentExclude; if (scriptInstanceRecord.isHidden && !("searchExclude" in scriptInstanceRecord)) { scriptInstanceRecord.unHide(); } } } } function cmdToggleScriptsSearchBox(e) { var scriptsView = console.views.scripts; if (scriptsView.currentContent) { var box = getChildById(scriptsView.currentContent, "scripts-search-box"); if (box.hasAttribute("hidden")) box.removeAttribute("hidden"); else box.setAttribute("hidden", "true"); } } console.views.scripts.hooks = new Object(); console.views.scripts.hooks["chrome-filter"] = function scv_hookChromeFilter(e) { var scriptsView = console.views.scripts; var nodes = scriptsView.childData; scriptsView.freeze(); //dd ("e.toggle is " + e.toggle); for (var m in console.scriptManagers) { if (console.scriptManagers[m].url.search(/^chrome:/) == 0 || ("componentPath" in console && console.scriptManagers[m].url.indexOf(console.componentPath) == 0)) { for (var i in console.scriptManagers[m].instances) { var instance = console.scriptManagers[m].instances[i]; if ("scriptInstanceRecord" in instance) { var rec = instance.scriptInstanceRecord; if (e.toggle) { if (!ASSERT("parentRecord" in rec, "Record for " + console.scriptManagers[m].url + " is already removed")) { continue; } /* filter is on, remove chrome file from scripts view */ /* dd ("removing " + console.scriptManagers[m].url + " kid at " + rec.childIndex); */ nodes.removeChildAtIndex(rec.childIndex); } else { if ("parentRecord" in rec) continue; //dd ("cmdChromeFilter: append " + // tov_formatRecord(rec, "")); nodes.appendChild(rec); } } } } } scriptsView.thaw(); if (scriptsView.tree) scriptsView.tree.invalidate(); } console.views.scripts.hooks["hook-break-set"] = console.views.scripts.hooks["hook-break-clear"] = console.views.scripts.hooks["hook-fbreak-set"] = console.views.scripts.hooks["hook-fbreak-clear"] = function sch_hookBreakChange(e) { if (console.views.scripts.tree) console.views.scripts.tree.invalidate(); } console.views.scripts.hooks["hook-guess-complete"] = function sch_hookGuessComplete(e) { if (!("scriptInstanceRecord" in e.scriptInstance)) return; var rec = e.scriptInstance.scriptInstanceRecord; if (!rec.childData.length) return; for (var i in rec.childData) { rec.childData[i].functionName = rec.childData[i].scriptWrapper.functionName; } if (console.views.scripts.tree) console.views.scripts.tree.invalidate(); } console.views.scripts.hooks["hook-script-instance-sealed"] = function scv_hookScriptInstanceSealed (e) { if (!e.scriptInstance.url || e.scriptInstance.url.search (/^(x-jsd|javascript)/) == 0) { return; } //dd ("instance sealed: " + e.scriptInstance.url); var scr = new ScriptInstanceRecord (e.scriptInstance); e.scriptInstance.scriptInstanceRecord = scr; if (console.prefs["enableChromeFilter"] && (e.scriptInstance.url.search(/^chrome:/) == 0 || "componentPath" in console && e.scriptInstance.url.indexOf(console.componentPath) == 0)) { return; } console.views.scripts.childData.appendChild(scr); var length = e.scriptInstance.scriptManager.instances.length; if (console.prefs["scriptsView.showMostRecent"] && length > 1) { var previous = e.scriptInstance.scriptManager.instances[length - 2]; if ("scriptInstanceRecord" in previous) { var record = previous.scriptInstanceRecord; record.recentExclude = true; if (!record.isHidden) record.hide(); } } } console.views.scripts.hooks["hook-script-instance-destroyed"] = function scv_hookScriptInstanceDestroyed (e) { if (!("scriptInstanceRecord" in e.scriptInstance)) return; var rec = e.scriptInstance.scriptInstanceRecord; if ("parentRecord" in rec) console.views.scripts.childData.removeChildAtIndex(rec.childIndex); var instances = e.scriptInstance.scriptManager.instances; if (instances.length) { var previous = instances[instances.length - 1]; if ("scriptInstanceRecord" in previous) { var record = previous.scriptInstanceRecord; if (!("searchExclude" in record)) record.unHide(); delete record.recentExclude; } } } console.views.scripts.hooks["debug-script"] = console.views.scripts.hooks["debug-instance"] = function scv_hookDebugFlagChanged (e) { if (console.views.scripts.tree) console.views.scripts.tree.invalidate(); } console.views.scripts.onSearchInput = function scv_oninput (event) { var scriptsView = this; function onTimeout () { var textbox = getChildById(scriptsView.currentContent, "scripts-search"); dispatch ("search-scripts", { pattern: textbox.value }); }; if ("searchTimeout" in this) clearTimeout(this.searchTimeout); this.searchTimeout = setTimeout (onTimeout, 500); } console.views.scripts.onSearchClear = function scv_onclear (event) { dispatch ("search-scripts"); } console.views.scripts.onShow = function scv_show () { syncTreeView (getChildById(this.currentContent, "scripts-tree"), this); initContextMenu(this.currentContent.ownerDocument, "context:scripts"); } console.views.scripts.onHide = function scv_hide () { syncTreeView (getChildById(this.currentContent, "scripts-tree"), null); } console.views.scripts.onRowCommand = function scv_rowcommand (rec) { if (rec instanceof ScriptRecord) dispatch ("find-script", { scriptWrapper: rec.scriptWrapper }); else if (rec instanceof ScriptInstanceRecord) dispatch ("find-sourcetext", { sourceText: rec.scriptInstance.sourceText }); } console.views.scripts.onClick = function scv_click (e) { if (e.originalTarget.localName == "treecol") { /* resort by column */ var rowIndex = new Object(); var col = new Object(); var childElt = new Object(); var treeBox = console.views.scripts.tree; treeBox.getCellAt(e.clientX, e.clientY, rowIndex, col, childElt); var prop; switch (col.value.id) { case "scripts:col-0": prop = "functionName"; break; case "scripts:col-1": prop = "baseLineNumber"; break; case "scripts:col-2": prop = "lineExtent"; break; } var scriptsRoot = console.views.scripts.childData; var dir = (prop == scriptsRoot._share.sortColumn) ? scriptsRoot._share.sortDirection * -1 : 1; //dd ("sort direction is " + dir); scriptsRoot.setSortColumn (prop, dir); } } console.views.scripts.onDragStart = Prophylactic(console.views.scripts, scv_dstart); function scv_dstart (e, transferData, dragAction) { var row = this.tree.getRowAt(e.clientX, e.clientY); if (row == -1) return false; row = this.childData.locateChildByVisualRow (row); var rv = false; if (row && ("onDragStart" in row)) rv = row.onDragStart (e, transferData, dragAction); return rv; } console.views.scripts.fullNameMode = false; console.views.scripts.setFullNameMode = function scv_setmode (flag) { this.fullNameMode = flag; for (var i = 0; i < this.childData.length; ++i) this.childData[i].setFullNameMode (flag); } console.views.scripts.getCellProperties = function scv_cellprops (index, col, properties) { if (col.id != "scripts:col-0") return null; var row = this.childData.locateChildByVisualRow(index); if (row) { if ("getProperties" in row) return row.getProperties (properties); if (row.property) return properties.AppendElement (row.property); } return null; } console.views.scripts.getContext = function scv_getcx(cx) { cx.urlList = new Array(); cx.scriptInstanceList = new Array(); cx.scriptWrapperList = new Array(); cx.lineNumberList = new Array(); cx.toggle = "toggle"; function recordContextGetter (cx, rec, i) { if (i == 0) { if (rec instanceof ScriptInstanceRecord) { cx.urlPattern = cx.url = rec.url; cx.scriptInstance = rec.scriptInstance; } else if (rec instanceof ScriptRecord) { cx.scriptWrapper = rec.scriptWrapper; cx.scriptInstance = rec.scriptWrapper.scriptInstance; cx.urlPattern = cx.url = cx.scriptInstance.url; cx.lineNumber = rec.baseLineNumber; } } else { if (rec instanceof ScriptInstanceRecord) { cx.urlList.push (rec.url); cx.scriptInstanceList.push(rec.scriptInstance); } else if (rec instanceof ScriptRecord) { cx.scriptWrapperList.push (rec.scriptWrapper); cx.lineNumberList.push (rec.baseLineNumber); } } return cx; }; return getTreeContext (console.views.scripts, cx, recordContextGetter); } /******************************************************************************* * Session View ******************************************************************************/ console.views.session = new Object(); const VIEW_SESSION = "session"; console.views.session.viewId = VIEW_SESSION; console.views.session.init = function ss_init () { function currentScheme (scheme) { var css; switch (scheme) { case "default": css = "console.prefs['sessionView.defaultCSS']"; break; case "dark": css = "console.prefs['sessionView.darkCSS']"; break; case "light": css = "console.prefs['sessionView.lightCSS']"; break; } return "console.prefs['sessionView.currentCSS'] == " + css; }; var prefs = [ ["sessionView.requireSlash", true], ["sessionView.commandHistory", 20], ["sessionView.dtabTime", 500], ["sessionView.maxHistory", 500], ["sessionView.outputWindow", "chrome://venkman/content/venkman-output-window.html?$css"], ["sessionView.currentCSS", "chrome://venkman/skin/venkman-output-dark.css"], ["sessionView.defaultCSS", "chrome://venkman/skin/venkman-output-default.css"], ["sessionView.darkCSS", "chrome://venkman/skin/venkman-output-dark.css"], ["sessionView.lightCSS", "chrome://venkman/skin/venkman-output-light.css"] ]; console.prefManager.addPrefs(prefs); console.menuSpecs["context:session"] = { items: [ ["stop", {type: "checkbox", checkedif: "console.jsds.interruptHook"}], ["cont"], ["next"], ["step"], ["finish"], ["-"], [">popup:emode"], [">popup:tmode"], ["-"], ["clear-session"], [">session:colors"] ] }; console.menuSpecs["session:colors"] = { label: MSG_MNU_SESSION_COLORS, items: [ ["session-css-default", {type: "checkbox", checkedif: currentScheme ("default")}], ["session-css-dark", {type: "checkbox", checkedif: currentScheme ("dark")}], ["session-css-light", {type: "checkbox", checkedif: currentScheme ("light")}] ] }; this.cmdary = [ ["session-css", cmdSessionCSS, CMD_CONSOLE], ["session-css-default", "session-css default", 0], ["session-css-dark", "session-css dark", 0], ["session-css-light", "session-css light", 0] ]; this.caption = MSG_VIEW_SESSION; /* input history (up/down arrow) related vars */ this.inputHistory = new Array(); this.lastHistoryReferenced = -1; this.incompleteLine = ""; /* tab complete */ this.lastTabUp = new Date(); this.messageCount = 0; this.outputTBody = new htmlTBody({ id: "session-output-tbody" }); this.zapDisplayFrame(); this.munger = new CMunger(); this.munger.enabled = true; this.munger.addRule ("quote", /(``|'')/, insertQuote); this.munger.addRule ("link", /((\w+):\/\/[^<>()\'\"\s]+|www(\.[^.<>()\'\"\s]+){2,}|x-jsd:help[\w&\?%]*)/, insertLink); this.munger.addRule ("word-hyphenator", new RegExp ("(\\S{" + MAX_WORD_LEN + ",})"), insertHyphenatedWord); } function cmdSessionCSS (e) { if (e.css) { var url; switch (e.css.toLowerCase()) { case "default": url = console.prefs["sessionView.defaultCSS"]; break; case "dark": url = console.prefs["sessionView.darkCSS"]; break; case "light": url = console.prefs["sessionView.lightCSS"]; break; default: url = e.css; break; } console.views.session.changeDisplayCSS (url); } feedback (e, getMsg(MSN_SESSION_CSS, console.prefs["sessionView.currentCSS"])); } console.views.session.hooks = new Object(); console.views.session.hooks["clear-session"] = function ss_clear(e) { var sessionView = console.views.session; sessionView.outputTBody = new htmlTBody({ id: "session-output-tbody" }); sessionView.messageCount = 0; if (sessionView.currentContent) sessionView.syncDisplayFrame(); } console.views.session.hooks["focus-input"] = function ss_hookFocus(e) { var sessionView = console.views.session; if ("inputElement" in sessionView) sessionView.inputElement.focus(); } console.views.session.hooks["set-eval-obj"] = function ss_setThisObj (e) { var urlFile; var functionName; if (console.currentEvalObject instanceof jsdIStackFrame) { if (console.currentEvalObject.script) { urlFile = getFileFromPath(console.currentEvalObject.script.fileName); var tag = console.currentEvalObject.script.tag; if (tag in console.scriptWrappers) functionName = console.scriptWrappers[tag].functionName; else functionName = MSG_VAL_UNKNOWN; } else { urlFile = "x-jsd:native"; functionName = console.currentEvalObject.functionName; } } else { var parent; var jsdValue = console.jsds.wrapValue (console.currentEvalObject); if (jsdValue.jsParent) parent = jsdValue.jsParent.getWrappedValue(); if (!parent) parent = console.currentEvalObject; if ("location" in parent) urlFile = getFileFromPath(parent.location.href); else urlFile = MSG_VAL_UNKNOWN; functionName = String(parent); } var sessionView = console.views.session; if (sessionView.currentContent) { var title = abbreviateWord(urlFile, 30); sessionView.currentContent.setAttribute ("title", getMsg(MSN_SESSION_TITLE, [title, functionName])); } } console.views.session.hooks["hook-session-display"] = function ss_hookDisplay (e) { var message = e.message; var msgtype = (e.msgtype) ? e.msgtype : MT_INFO; var monospace; var mtname; if (msgtype[0] == "#") { monospace = true; mtname = msgtype.substr(1); } else { mtname = msgtype; } function setAttribs (obj, c, attrs) { if (attrs) { for (var a in attrs) obj.setAttribute (a, attrs[a]); } obj.setAttribute("class", c); obj.setAttribute("msg-type", mtname); if (monospace) obj.setAttribute("monospace", "true"); } var msgRow = htmlTR("msg"); setAttribs(msgRow, "msg"); var msgData = htmlTD(); setAttribs(msgData, "msg-data"); if (typeof message == "string") msgData.appendChild(console.views.session.stringToDOM(message, msgtype)); else msgData.appendChild(message); msgRow.appendChild(msgData); var sessionView = console.views.session; if (sessionView.messageCount == console.prefs["sessionView.maxHistory"]) sessionView.outputTBody.removeChild(sessionView.outputTBody.firstChild); sessionView.outputTBody.appendChild(msgRow); sessionView.scrollDown(); } console.views.session.hooks["hook-window-resized"] = function ss_hookResize (e) { console.views.session.scrollDown(); } console.views.session.changeDisplayCSS = function ss_changecss (url) { console.prefs["sessionView.currentCSS"] = url; if (this.outputDocument) { this.zapDisplayFrame(); this.syncDisplayFrame(); } } console.views.session.zapDisplayFrame = function ss_zap () { if (this.outputTBody && this.outputTBody.parentNode) this.outputTBody.parentNode.removeChild(this.outputTBody); if ("iframe" in this && this.iframe) this.iframe.setAttribute ("src", "about:blank"); this.iframe = null; this.outputTable = null; this.outputWindow = null; this.outputDocument = null; this.intputElement = null; } console.views.session.syncDisplayFrame = function ss_syncframe () { var sessionView = this; function tryAgain () { //dd ("session view trying again..."); sessionView.syncDisplayFrame(); }; var doc = this.currentContent.ownerDocument; try { this.iframe = doc.getElementById("session-output-iframe"); if ("contentDocument" in this.iframe) { /* iframe looks ready */ this.outputDocument = this.iframe.contentDocument; if (this.iframe.getAttribute ("src") == "about:blank") { /* but it doesn't point to the right place yet */ var docURL = console.prefs["sessionView.outputWindow"]; var css = console.prefs["sessionView.currentCSS"]; docURL = docURL.replace ("$css", css); this.iframe.setAttribute("src", docURL); } else { /* now it is, get the DOM nodes */ var win = this.currentContent.ownerWindow; for (var f = 0; f < win.frames.length; ++f) { if (win.frames[f].document == this.outputDocument) { this.outputWindow = win.frames[f]; break; } } this.outputTable = this.outputDocument.getElementById("session-output-table"); this.inputElement = doc.getElementById("session-sl-input"); this.inputLabel = doc.getElementById("session-input-label"); this.hooks["set-eval-obj"](); } } } catch (ex) { //dd ("caught exception showing session view, will try again later."); //dd (dumpObjectTree(ex)); } if (!this.outputDocument || !this.outputTable || !this.inputElement) { setTimeout (tryAgain, 500); return; } if (this.outputTable.firstChild) this.outputTable.removeChild (this.outputTable.firstChild); this.outputTable.appendChild (this.outputTBody); this.scrollDown(); } console.views.session.scrollDown = function ss_scroll() { if (this.outputWindow) this.outputWindow.scrollTo(0, this.outputDocument.height); } console.views.session.onShow = function ss_show () { this.syncDisplayFrame(); this.hooks["focus-input"](); initContextMenu(this.currentContent.ownerDocument, "context:session"); } console.views.session.onHide = function ss_hide () { this.zapDisplayFrame(); } console.views.session.stringToDOM = function ss_stringToDOM (message, msgtype) { var ary = message.split ("\n"); var span = htmlSpan(); for (var l in ary) { this.munger.munge(ary[l], span, msgtype); span.appendChild (htmlBR()); } return span; } console.views.session.onInputCompleteLine = function ss_icline (e) { if (this.inputHistory.length == 0 || this.inputHistory[0] != e.line) this.inputHistory.unshift (e.line); if (this.inputHistory.length > console.prefs["sessionView.commandHistory"]) this.inputHistory.pop(); this.lastHistoryReferenced = -1; this.incompleteLine = ""; if (console.prefs["sessionView.requireSlash"]) { if (e.line[0] == "/") e.line = e.line.substr(1); else e.line = "eval " + e.line; } var ev = {isInteractive: true, initialEvent: e}; dispatch (e.line, ev, CMD_CONSOLE); } console.views.session.onSLKeyPress = function ss_slkeypress (e) { var w = this.outputWindow; var newOfs; switch (e.keyCode) { case 13: if (!e.target.value) return; e.line = e.target.value; this.onInputCompleteLine (e); e.target.value = ""; break; case 38: /* up */ e.preventDefault() if (this.lastHistoryReferenced == -2) { this.lastHistoryReferenced = -1; e.target.value = this.incompleteLine; } else if (this.lastHistoryReferenced < this.inputHistory.length - 1) { e.target.value = this.inputHistory[++this.lastHistoryReferenced]; } break; case 40: /* down */ e.preventDefault() if (this.lastHistoryReferenced > 0) e.target.value = this.inputHistory[--this.lastHistoryReferenced]; else if (this.lastHistoryReferenced == -1) { e.target.value = ""; this.lastHistoryReferenced = -2; } else { this.lastHistoryReferenced = -1; e.target.value = this.incompleteLine; } break; case 33: /* pgup */ newOfs = w.pageYOffset - (w.innerHeight / 2); if (newOfs > 0) w.scrollTo (w.pageXOffset, newOfs); else w.scrollTo (w.pageXOffset, 0); break; case 34: /* pgdn */ newOfs = w.pageYOffset + (w.innerHeight / 2); if (newOfs < (w.innerHeight + w.pageYOffset)) w.scrollTo (w.pageXOffset, newOfs); else w.scrollTo (w.pageXOffset, (w.innerHeight + w.pageYOffset)); break; case 9: /* tab */ e.preventDefault(); this.onTabCompleteRequest(e); break; default: this.lastHistoryReferenced = -1; this.incompleteLine = e.target.value; break; } } console.views.session.onTabCompleteRequest = function ss_tabcomplete (e) { var selStart = e.target.selectionStart; var selEnd = e.target.selectionEnd; var v = e.target.value; if (selStart != selEnd) { /* text is highlighted, just move caret to end and exit */ e.target.selectionStart = e.target.selectionEnd = v.length; return; } var firstSpace = v.indexOf(" "); if (firstSpace == -1) firstSpace = v.length; var pfx; var d; if ((selStart <= firstSpace)) { /* The cursor is positioned before the first space, so we're completing * a command */ var startPos; var slash; if (console.prefs["sessionView.requireSlash"]) { if (v[0] != "/") return; startPos = 1; slash = "/"; } else { startPos = 0; slash = ""; } var partialCommand = v.substring(startPos, firstSpace).toLowerCase(); var cmds = console.commandManager.listNames(partialCommand, CMD_CONSOLE); if (cmds.length == 0) { /* partial didn't match a thing */ display (getMsg(MSN_NO_CMDMATCH, partialCommand), MT_ERROR); } else if (cmds.length == 1) { /* partial matched exactly one command */ pfx = slash + cmds[0]; if (firstSpace == v.length) v = pfx + " "; else v = pfx + v.substr (firstSpace); e.target.value = v; e.target.selectionStart = e.target.selectionEnd = pfx.length + 1; } else if (cmds.length > 1) { /* partial matched more than one command */ d = new Date(); if ((d - this.lastTabUp) <= console.prefs["sessionView.dtabTime"]) display (getMsg (MSN_CMDMATCH, [partialCommand, cmds.join(MSG_COMMASP)])); else this.lastTabUp = d; pfx = slash + getCommonPfx(cmds); if (firstSpace == v.length) v = pfx; else v = pfx + v.substr (firstSpace); e.target.value = v; e.target.selectionStart = e.target.selectionEnd = pfx.length; } } } /******************************************************************************* * Stack View ******************************************************************************/ console.views.stack = new XULTreeView(); const VIEW_STACK = "stack"; console.views.stack.viewId = VIEW_STACK; console.views.stack.init = function skv_init() { var debugIf = "'scriptWrapper' in cx && " + "cx.scriptWrapper.jsdScript.isValid && " + "cx.scriptWrapper.jsdScript.flags & SCRIPT_NODEBUG"; var profileIf = "'scriptWrapper' in cx && " + "cx.scriptWrapper.jsdScript.isValid && " + "cx.scriptWrapper.jsdScript.flags & SCRIPT_NOPROFILE"; this.cmdary = [ ["copy-frames", cmdCopyFrames, 0] ]; console.menuSpecs["context:stack"] = { getContext: this.getContext, items: [ ["find-script"], ["copy-frames"], ["-"], ["set-break"], ["clear-script", {enabledif: "cx.scriptWrapper.breakpointCount"}], ["-"], ["debug-script", {type: "checkbox", checkedif: debugIf}], ["profile-script", {type: "checkbox", checkedif: profileIf}], ] }; this.caption = MSG_VIEW_STACK; } function cmdCopyFrames (e) { var stackString = ""; var numFrames = e.jsdFrameList.length; var startSearch = 0; for (var i = 0; i < numFrames; ++i) { var jsdFrame = e.jsdFrameList[i]; var frameIdx = arrayIndexOf(console.frames, jsdFrame, startSearch); if (!ASSERT(frameIdx != -1, "e.jsdFrameList[" + i + "] is not in console.frames!")) { return; } stackString += getMsg(MSN_FMT_FRAME_LINE, [frameIdx, formatFrame(jsdFrame)]) + "\n"; startSearch = frameIdx + 1; } const CLIPBOARD_CTRID = "@mozilla.org/widget/clipboardhelper;1"; const nsIClipboardHelper = Components.interfaces.nsIClipboardHelper; var clipboardHelper = Components.classes[CLIPBOARD_CTRID].getService(nsIClipboardHelper); clipboardHelper.copyString(stackString); } console.views.stack.hooks = new Object(); console.views.stack.hooks["hook-debug-stop"] = function skv_hookDebugStop (e) { var frameRec; for (var i = 0; i < console.frames.length; ++i) { frameRec = new FrameRecord(console.frames[i]); console.views.stack.childData.appendChild (frameRec); } console.views.stack.hooks["find-frame"]({ frameIndex: 0 }); } console.views.stack.hooks["hook-debug-continue"] = function skv_hookDebugCont (e) { while (console.views.stack.childData.childData.length) console.views.stack.childData.removeChildAtIndex(0); delete console.views.stack.lastFrameIndex; } console.views.stack.hooks["hook-guess-complete"] = function skv_hookGuessComplete(e) { var frameRecs = console.views.stack.childData.childData; for (var i = 0; i < frameRecs.length; ++i) { if (!frameRecs[i].jsdFrame.isNative) frameRecs[i].functionName = frameRecs[i].scriptWrapper.functionName; } if (console.views.stack.tree) console.views.stack.tree.invalidate(); } console.views.stack.hooks["find-frame"] = function skv_hookFrame (e) { var stackView = console.views.stack; var childData = stackView.childData.childData; if ("lastFrameIndex" in stackView) delete childData[stackView.lastFrameIndex].property; childData[e.frameIndex].property = FrameRecord.prototype.atomCurrent; stackView.lastFrameIndex = e.frameIndex; if (console.views.stack.tree) { stackView.scrollTo (e.frameIndex, 0); stackView.tree.view.selection.currentIndex = e.frameIndex; stackView.tree.invalidate(); } } console.views.stack.onShow = function skv_show() { syncTreeView (getChildById(this.currentContent, "stack-tree"), this); initContextMenu(this.currentContent.ownerDocument, "context:stack"); } console.views.stack.onHide = function skv_hide() { syncTreeView (getChildById(this.currentContent, "stack-tree"), null); } console.views.stack.onRowCommand = function skv_rowcommand (rec) { var rowIndex = rec.childIndex; if (rowIndex >= 0 && rowIndex < console.frames.length) dispatch ("frame", { frameIndex: rowIndex }); } console.views.stack.getContext = function sv_getcx(cx) { cx.jsdFrameList = new Array(); cx.urlList = new Array(); cx.scriptInstanceList = new Array(); cx.scriptWrapperList = new Array(); cx.lineNumberList = new Array(); cx.toggle = "toggle"; function recordContextGetter (cx, rec, i) { var line; if (rec.scriptWrapper.jsdScript.isValid) line = rec.scriptWrapper.jsdScript.baseLineNumber if (i == 0) { cx.jsdFrame = rec.jsdFrame; if (rec.scriptWrapper) { cx.scriptWrapper = rec.scriptWrapper; cx.scriptInstance = rec.scriptWrapper.scriptInstance; cx.urlPattern = cx.url = cx.scriptInstance.url; cx.lineNumber = line; } } else { cx.jsdFrameList.push (rec.jsdFrame); if (rec.scriptWrapper) { cx.scriptWrapperList.push (rec.scriptWrapper); cx.scriptInstanceList.push(rec.scriptWrapper.scriptInstance); cx.urlList.push (rec.scriptWrapper.scriptInstance.url); cx.lineNumberList.push(line); } } return cx; }; return getTreeContext (console.views.stack, cx, recordContextGetter); } console.views.stack.getCellProperties = function sv_cellprops (index, col, properties) { if (col.id != "stack:col-0") return; var row = this.childData.locateChildByVisualRow(index); if (row) { if ("getProperties" in row) row.getProperties (properties); else if (row.property) properties.AppendElement (row.property); } return; } /******************************************************************************* * Source2 View *******************************************************************************/ console.views.source2 = new Object(); const VIEW_SOURCE2 = "source2"; console.views.source2.viewId = VIEW_SOURCE2; console.views.source2.init = function ss_init () { var prefs = [ ["source2View.maxTabs", 5], ["source2View.showCloseButton", true], ["source2View.middleClickClose", false] ]; console.prefManager.addPrefs(prefs); this.cmdary = [ ["close-source-tab", cmdCloseTab, CMD_CONSOLE], ["find-string", cmdFindString, CMD_CONSOLE], ["save-source-tab", cmdSaveTab, CMD_CONSOLE], ["reload-source-tab", cmdReloadTab, CMD_CONSOLE], ["source-coloring", cmdToggleColoring, 0], ["toggle-source-coloring", "source-coloring toggle", 0] ]; console.menuSpecs["context:source2"] = { getContext: this.getContext, items: [ ["close-source-tab"], ["reload-source-tab"], ["save-source-tab", {enabledif: "console.views.source2.canSave()"}], ["find-string"], ["-"], ["break", {enabledif: "cx.lineIsExecutable && !has('hasBreak')"}], ["clear", {enabledif: "has('hasBreak')"}], ["set-fbreak", {enabledif: "!has('hasFBreak')"}], ["fclear", {enabledif: "has('hasFBreak')"}], ["-"], ["run-to"], ["cont"], ["next"], ["step"], ["finish"], ["-"], ["toggle-source-coloring", {type: "checkbox", checkedif: "console.prefs['services.source.colorize']"}], ["toggle-pprint", {type: "checkbox", checkedif: "console.prefs['prettyprint']"}], ["-"], ["break-props"] ] }; this.caption = MSG_VIEW_SOURCE2; this.deck = null; this.tabs = null; this.heading = null; this.sourceTabList = new Array(); this.highlightTab = null; this.highlightNodes = new Array(); } function cmdCloseTab (e) { var source2View = console.views.source2; if (source2View.tabs && e.index == null) { e.index = source2View.tabs.selectedIndex; } else if (!source2View.tabs || e.index < 0 || e.index > source2View.sourceTabList.length - 1) { display (MSN_ERR_INVALID_PARAM, ["index", e.index], MT_ERROR); return; } source2View.removeSourceTabAtIndex (e.index); } function cmdFindString (e) { var source2View = console.views.source2; if (!source2View.tabs) return; var index = source2View.tabs.selectedIndex; if (!(index in source2View.sourceTabList)) return; var browser = source2View.sourceTabList[index].iframe; if (typeof nsFindInstData != "undefined") { if (!("findData" in console)) console.findData = new nsFindInstData(); console.findData.browser = browser; console.findData.rootSearchWindow = browser.contentWindow; console.findData.currentSearchWindow = browser.contentWindow; findInPage(console.findData); } else { findInPage(browser, browser.contentWindow, browser.contentWindow); } } function cmdReloadTab (e) { const WINDOW = Components.interfaces.nsIWebProgress.NOTIFY_STATE_WINDOW; if (console.views.source2.sourceTabList.length == 0) return; var source2View = console.views.source2; function cb(status) { sourceTab.iframe.addProgressListener (source2View.progressListener, WINDOW); sourceTab.iframe.reload(); }; if (source2View.tabs && e.index == null) { e.index = source2View.tabs.selectedIndex; } else if (!source2View.tabs || e.index < 0 || e.index > source2View.sourceTabList.length - 1) { display (MSN_ERR_INVALID_PARAM, ["index", e.index], MT_ERROR); return; } var sourceTab = console.views.source2.sourceTabList[e.index]; source2View.onSourceTabUnloaded (sourceTab, Components.results.NS_OK); sourceTab.sourceText.reloadSource(cb); } function cmdSaveTab (e) { var source2View = console.views.source2; if (source2View.tabs && e.index == null) { e.index = source2View.tabs.selectedIndex; if (!(e.index in source2View.sourceTabList)) return null; } else if (!source2View.tabs || e.index < 0 || e.index > source2View.sourceTabList.length - 1) { display (MSN_ERR_INVALID_PARAM, ["index", e.index], MT_ERROR); return null; } var sourceText = source2View.sourceTabList[e.index].sourceText; var fileString; if (!e.targetFile || e.targetFile == "?") { var fileName = sourceText.url; //dd ("fileName is " + fileName); if (fileName.search(/^\w+:/) != -1) { var shortName = getFileFromPath(fileName); if (fileName != shortName) fileName = shortName; else fileName = ""; } else fileName = ""; var rv = pickSaveAs(MSG_SAVE_SOURCE, "*.js $xml $text $all", fileName); if (rv.reason == PICK_CANCEL) return null; e.targetFile = rv.file; fileString = rv.file.leafName; } else { fileString = e.targetFile; } var file = fopen (e.targetFile, MODE_WRONLY | MODE_CREATE | MODE_TRUNCATE); if (fileString.search (/xml$/i) == -1) { for (var i = 0; i < sourceText.lines.length; ++i) file.write(sourceText.lines[i] + "\n"); } else { if ("markup" in sourceText) file.write (sourceText.markup); else display (MSG_ERR_FORMAT_NOT_AVAILABLE, MT_ERROR); } file.close(); return file.localFile.path; } function cmdToggleColoring (e) { if (e.toggle != null) { if (e.toggle == "toggle") e.toggle = !console.prefs["services.source.colorize"]; console.prefs["services.source.colorize"] = e.toggle; } if ("isInteractive" in e && e.isInteractive) dispatch("pref services.source.colorize", { isInteractive: true }); } console.views.source2.canSave = function s2v_cansave () { return this.tabs && this.sourceTabList.length > 0; } console.views.source2.getContext = function s2v_getcontext (cx) { var source2View = console.views.source2; cx.lineIsExecutable = false; var sourceText; if (document.popupNode.localName == "tab") { cx.index = source2View.getIndexOfTab(document.popupNode); sourceText = source2View.sourceTabList[cx.index].sourceText; cx.url = cx.urlPattern = sourceText.url; } else { cx.index = source2View.tabs.selectedIndex; sourceText = source2View.sourceTabList[cx.index].sourceText; cx.url = cx.urlPattern = sourceText.url; var target = document.popupNode; while (target) { if (target.localName == "line") break; target = target.parentNode; } if (target) { cx.lineNumber = parseInt(target.childNodes[1].firstChild.data); var row = cx.lineNumber - 1; if (sourceText.lineMap && sourceText.lineMap[row] & LINE_BREAKABLE) { cx.lineIsExecutable = true; if ("scriptInstance" in sourceText) { var scriptInstance = sourceText.scriptInstance; var scriptWrapper = scriptInstance.getScriptWrapperAtLine(cx.lineNumber); if (scriptWrapper && scriptWrapper.jsdScript.isValid) { cx.scriptWrapper = scriptWrapper; cx.pc = scriptWrapper.jsdScript.lineToPc(cx.lineNumber, PCMAP_SOURCETEXT); } } else if ("scriptWrapper" in sourceText && sourceText.scriptWrapper.jsdScript.isValid) { cx.scriptWrapper = sourceText.scriptWrapper; cx.pc = cx.scriptWrapper.jsdScript.lineToPc(cx.lineNumber, PCMAP_PRETTYPRINT); } } if (sourceText.lineMap && sourceText.lineMap[row] & LINE_BREAK) { cx.hasBreak = true; if ("scriptInstance" in sourceText) { cx.breakWrapper = sourceText.scriptInstance.getBreakpoint(cx.lineNumber); } else if ("scriptWrapper" in sourceText && "pc" in cx) { cx.breakWrapper = sourceText.scriptWrapper.getBreakpoint(cx.pc); } if ("breakWrapper" in cx && cx.breakWrapper.parentBP) cx.hasFBreak = true; } else if (sourceText.lineMap && sourceText.lineMap[row] & LINE_FBREAK) { cx.hasFBreak = true; cx.breakWrapper = getFutureBreakpoint(cx.url, cx.lineNumber); } } } return cx; } /* * scroll the source so |line| is at either the top, center, or bottom * of the view, depending on the value of |align|. * * line is the one based target line. * if align is negative, the line will be scrolled to the top, if align is * zero the line will be centered, and if align is greater than 0 the line * will be scrolled to the bottom. 0 is the default. */ console.views.source2.scrollTabTo = function s2v_scrollto (sourceTab, line, align) { //dd ("scrolling to " + line + ", " + align); if (!sourceTab.content) { //dd ("scrollTabTo: sourceTab not loaded yet"); sourceTab.scrollPosition = [line, align]; return; } var window = sourceTab.iframe.contentWindow; var viewportHeight = window.innerHeight; var style = window.getComputedStyle(sourceTab.content, null); var cssValue = style.getPropertyCSSValue("height"); var documentHeight = cssValue.getFloatValue(CSSPrimitiveValue.CSS_PX); var lineCount = sourceTab.sourceText.lines.length; var lineHeight = documentHeight / lineCount; var targetPos; if (align < 0) targetPos = (line - 1) * lineHeight; else if (align > 0) targetPos = (line + 1) * lineHeight - viewportHeight; else targetPos = (line - 1) * lineHeight - viewportHeight / 2; if (targetPos < 0) targetPos = 0; else if (targetPos > documentHeight) targetPos = documentHeight; window.scrollTo (window.pageXOffset, targetPos); } console.views.source2.updateLineMargin = function s2v_updatemargin (sourceTab, line) { if (!("lineMap" in sourceTab.sourceText)) return; if (!sourceTab.content) return; var node = sourceTab.content.childNodes[line * 2 - 1]; if (!ASSERT(node, "no node at line " + line)) return; node = node.childNodes[0]; var lineMap = sourceTab.sourceText.lineMap; var data = MSG_MARGIN_NONE; //dd ("updateLineMargin: line " + line); --line; if (line in lineMap) { var flags = lineMap[line]; //dd ("updateLineMargin: flags " + flags); if (flags & LINE_BREAKABLE) { node.setAttribute ("x", "t"); data = MSG_MARGIN_BREAKABLE; } else { node.removeAttribute ("x"); } if (flags & LINE_FBREAK) { node.setAttribute ("f", "t"); data = MSG_MARGIN_FBREAK; } else { node.removeAttribute ("f"); } if (flags & LINE_BREAK) { node.setAttribute ("b", "t"); data = MSG_MARGIN_BREAK; } else { node.removeAttribute ("b"); } } else { node.removeAttribute ("x"); node.removeAttribute ("f"); node.removeAttribute ("b"); } //dd ("node data was " + node.firstChild.data + ", wil be ``" + data + "''"); //dd (dumpObjectTree(node)); node.firstChild.data = data; } console.views.source2.initMargin = function s2v_initmargin (sourceTab) { if (!("lineMap" in sourceTab.sourceText)) return; var CHUNK_SIZE = 1000; var CHUNK_DELAY = 100; var lineMap = sourceTab.sourceText.lineMap; var source2View = this; function initChunk (start) { var stop = Math.min (lineMap.length, start + CHUNK_SIZE); for (var i = start; i < stop; ++i) { if (i in lineMap && lineMap[i] != LINE_BREAKABLE) source2View.updateLineMargin (sourceTab, i + 1); } if (i != lineMap.length) setTimeout (initChunk, CHUNK_DELAY, i); }; initChunk (0); } console.views.source2.markStopLine = function s2v_marktab (sourceTab, currentFrame) { if ("stopNode" in sourceTab) this.unmarkStopLine(sourceTab); if (!currentFrame) return; if (!sourceTab.content) { //dd ("markStopLine: sourceTab not loaded yet"); return; } if (!ASSERT(currentFrame.script, "current frame has no script")) return; var tag = currentFrame.script.tag; var sourceText = sourceTab.sourceText; var line = -1; if ("scriptInstance" in sourceText) { if (sourceText.scriptInstance.containsScriptTag (tag) || tag in sourceText.scriptInstance.scriptManager.transients) { line = currentFrame.line; } } else if ("scriptWrapper" in sourceText && sourceText.scriptWrapper.tag == tag) { line = currentFrame.script.pcToLine (currentFrame.pc, PCMAP_PRETTYPRINT); } if (line > 0) { //dd ("marking stop line " + line); var stopNode = sourceTab.content.childNodes[line * 2 - 1]; if (!ASSERT(stopNode, "no node at line " + line)) return; //dd ("stopNode: " + stopNode.localName); stopNode.setAttribute ("stoppedAt", "true"); sourceTab.stopNode = stopNode; } } console.views.source2.unmarkStopLine = function s2v_unmarktab (sourceTab) { if ("stopNode" in sourceTab) { //dd ("unmarking stop line"); sourceTab.stopNode.removeAttribute ("stoppedAt"); delete sourceTab.stopNode; } else { //dd ("unmarkStopLine: sourceTab had no stop line"); } } console.views.source2.markHighlight = function s2v_markhigh () { if (!this.highlightTab.content) { //dd ("highlight tab is not loaded yet"); return; } if (!ASSERT(this.highlightNodes.length == 0, "something is already highlighted")) { return; } for (var i = this.highlightStart; i <= this.highlightEnd; ++i) { var node = this.highlightTab.content.childNodes[i * 2 - 1]; if (!ASSERT(node, "no node at line " + i)) return; node.setAttribute ("highlighted", "true"); this.highlightNodes.push (node); } } console.views.source2.unmarkHighlight = function s2v_unmarkhigh () { if (this.highlightTab) { while (this.highlightNodes.length) this.highlightNodes.pop().removeAttribute ("highlighted"); } } console.views.source2.clearHighlight = function s2v_clearhigh () { this.unmarkHighlight(); this.highlightTab = null; this.highlightStart = -1; this.highlightEnd = -1; } console.views.source2.onSourceClick = function s2v_sourceclick (event) { var source2View = console.views.source2; if (!source2View.tabs) return; var sourceTab = source2View.sourceTabList[source2View.tabs.selectedIndex]; var sourceText = sourceTab.sourceText; if (!("onMarginClick" in sourceText)) return; var target = event.target; while (target) { if (target.localName == "margin") break; target = target.parentNode; } if (target && target.localName == "margin" && event.button == 0) { var line = parseInt (target.nextSibling.firstChild.data); sourceText.onMarginClick (event, line); } } console.views.source2.onSourceTabUnloaded = function s2v_tabunloaded (sourceTab, status) { this.unmarkStopLine (sourceTab); sourceTab.content = null; if (sourceTab == this.highlightTab) this.unmarkHighlight(); } console.views.source2.onSourceTabLoaded = function s2v_tabloaded (sourceTab, status) { var collection = sourceTab.iframe.contentDocument.getElementsByTagName("source-listing"); sourceTab.content = collection[0]; if (!sourceTab.content) { //dd ("tab loaded, but had no content, about:blank crap?"); return; } this.markStopLine (sourceTab, getCurrentFrame()); if (sourceTab == this.highlightTab) this.markHighlight(); if ("scrollPosition" in sourceTab) { this.scrollTabTo (sourceTab, sourceTab.scrollPosition[0], sourceTab.scrollPosition[1]); } this.initMargin (sourceTab); } console.views.source2.syncOutputFrame = function s2v_syncframe (iframe) { const nsIWebProgress = Components.interfaces.nsIWebProgress; const ALL = nsIWebProgress.NOTIFY_ALL; const DOCUMENT = nsIWebProgress.NOTIFY_STATE_DOCUMENT; const WINDOW = nsIWebProgress.NOTIFY_STATE_WINDOW; var source2View = this; function tryAgain () { dd ("source2 view trying again..."); source2View.syncOutputFrame(iframe); }; var doc = this.currentContent.ownerDocument; try { if ("contentDocument" in iframe && "webProgress" in iframe) { var listener = console.views.source2.progressListener; iframe.addProgressListener (listener, WINDOW); iframe.loadURI (iframe.getAttribute ("targetSrc")); if (iframe.hasAttribute ("raiseOnSync")) { var i = this.getIndexOfDOMWindow (iframe.webProgress.DOMWindow); this.showTab(i); iframe.removeAttribute ("raiseOnSync"); } } else { setTimeout (tryAgain, 500); } } catch (ex) { dd ("caught exception showing session view, will try again later."); dd (ex); dd (dumpObjectTree(ex)); setTimeout (tryAgain, 500); } } console.views.source2.syncOutputDeck = function s2v_syncdeck () { if (!ASSERT("currentContent" in this, "not inserted anywhere")) return; for (var i = 0; i < this.sourceTabList.length; ++i) { this.createFrameFor (this.sourceTabList[i], i, ("lastSelectedTab" in this && this.lastSelectedTab == i)); } delete this.lastSelectedTab; } console.views.source2.clearOutputDeck = function s2v_cleardeck () { for (var i = 0; i < this.sourceTabList.length; ++i) { var sourceTab = this.sourceTabList[i]; sourceTab.tab = null; sourceTab.iframe = null; this.onSourceTabUnloaded (this.sourceTabList[i], Components.results.NS_OK); } if (this.tabs) { i = this.tabs.childNodes.length; while (i > 0) this.tabs.removeChild(this.tabs.childNodes[--i]); i = this.deck.childNodes.length; while (i > 0) this.deck.removeChild (this.deck.childNodes[--i]); var bloke = document.createElement ("tab"); bloke.setAttribute ("id", "source2-bloke"); bloke.setAttribute ("hidden", "true"); this.tabs.appendChild (bloke); bloke.selected = true; } } console.views.source2.createFrameFor = function s2v_createframe (sourceTab, index, raiseFlag) { if (!ASSERT(this.deck, "we're deckless")) return null; var bloke = getChildById (this.tabs, "source2-bloke"); if (bloke) this.tabs.removeChild(bloke); var document = this.currentContent.ownerDocument; var tab = document.createElement ("tab"); tab.selected = false; tab.setAttribute ("class", "source2-tab"); tab.setAttribute ("context", "context:source2"); tab.setAttribute ("align", "center"); tab.setAttribute ("flex", "1"); tab.setAttribute("onclick", "console.views.source2.onTabClick(event)"); var tabicon = document.createElement("image"); tabicon.setAttribute("class", "tab-icon"); tab.appendChild(tabicon); var label = document.createElement("label"); tab.label = label; label.setAttribute("value", sourceTab.sourceText.shortName); label.setAttribute("crop", "center"); label.setAttribute("flex", "1"); tab.appendChild(label); tab.appendChild(document.createElement("spacer")); if (console.prefs["source2View.showCloseButton"]) { var closeButton = document.createElement("image"); closeButton.setAttribute("class", "tab-close-button"); closeButton.setAttribute("onclick", "console.views.source2.onCloseButton(event)"); tab.appendChild(closeButton); } if (index < this.tabs.childNodes.length) this.tabs.insertBefore (tab, this.tabs.childNodes[index]); else this.tabs.appendChild (tab); if (!this.tabs.firstChild.hasAttribute("first-tab")) { this.tabs.firstChild.setAttribute("first-tab", "true"); if (this.tabs.firstChild.nextSibling) this.tabs.firstChild.nextSibling.removeAttribute("first-tab"); } sourceTab.tab = tab; var tabPanel = document.createElement("tabpanel"); var iframe = document.createElement("browser"); iframe.setAttribute ("flex", "1"); iframe.setAttribute ("context", "context:source2"); iframe.setAttribute ("disablehistory", "true"); iframe.setAttribute ("disablesecurity", "true"); iframe.setAttribute ("type", "content"); iframe.setAttribute ("onclick", "console.views.source2.onSourceClick(event);"); iframe.setAttribute ("targetSrc", sourceTab.sourceText.jsdURL); if (raiseFlag) iframe.setAttribute ("raiseOnSync", "true"); tabPanel.appendChild (iframe); if (this.deck.childNodes.length > index) this.deck.insertBefore (tabPanel, this.deck.childNodes[index]); else this.deck.appendChild(tabPanel); sourceTab.iframe = iframe; this.syncOutputFrame (iframe); return iframe; } console.views.source2.loadSourceTextAtIndex = function s2v_loadsource (sourceText, index) { var sourceTab; if (index in this.sourceTabList) { sourceTab = this.sourceTabList[index]; sourceTab.content = null; sourceTab.sourceText = sourceText; if ("currentContent" in this) { if (!ASSERT(sourceTab.tab, "existing sourcetab not fully initialized")) { return null; } sourceTab.tab.label.setAttribute("value", sourceText.shortName); sourceTab.iframe.setAttribute("targetSrc", sourceText.jsdURL); sourceTab.iframe.setAttribute("raiseOnSync", "true"); this.syncOutputFrame(sourceTab.iframe); } } else { sourceTab = { sourceText: sourceText, tab: null, iframe: null, content: null }; this.sourceTabList[index] = sourceTab; if ("currentContent" in this) { this.createFrameFor(sourceTab, index, true); } } return sourceTab; } console.views.source2.addSourceText = function s2v_addsource (sourceText) { var index = this.getIndexOfSourceText (sourceText); if (index != -1) { this.showTab(index); return this.sourceTabList[index]; } if (this.sourceTabList.length < console.prefs["source2View.maxTabs"]) index = this.sourceTabList.length; else index = 0; return this.loadSourceTextAtIndex (sourceText, index); } console.views.source2.onCloseButton = function s2v_onclose(e) { var index = this.getIndexOfTab(e.target.parentNode); this.removeSourceTabAtIndex(index); e.stopPropagation(); } console.views.source2.onTabClick = function s2v_ontab(e) { var tab; if (e.target.localName == "tab") tab = e.target; else tab = e.target.parentNode; var index = this.getIndexOfTab(tab); if (e.which == 2 && console.prefs["source2View.middleClickClose"]) this.removeSourceTabAtIndex(index); else this.showTab(index); } console.views.source2.removeSourceText = function s2v_removetext (sourceText) { var index = this.getIndexOfSourceText (sourceText); if (index != -1) this.removeSourceTabAtIndex (index); } console.views.source2.removeSourceTabAtIndex = function s2v_removeindex (index) { var sourceTab = this.sourceTabList[index]; if (this.highlightTab == sourceTab) this.unmarkHighlight(); sourceTab.tab = null; sourceTab.iframe = null; sourceTab.content = null; sourceTab.stopNode = null; arrayRemoveAt (this.sourceTabList, index); if (this.tabs) { var lastIndex = this.tabs.selectedIndex; this.tabs.removeItemAt(index); this.deck.removeChild(this.deck.childNodes[index]); if (lastIndex >= this.sourceTabList.length) lastIndex = this.sourceTabList.length - 1; if (lastIndex >= 0) this.showTab(lastIndex); if (index == 0 && this.tabs.firstChild) this.tabs.firstChild.setAttribute("first-tab", "true"); } else if (this.lastSelectedTab > this.sourceTabList.length) { this.lastSelectedTab = this.sourceTabList.length; } if (this.sourceTabList.length == 0) this.clearOutputDeck(); } console.views.source2.getIndexOfSourceTab = function s2v_getstabindex (sourceTab) { var index = -1; for (var i = 0; i < this.sourceTabList.length; ++i) { if (this.sourceTabList[i] == sourceTab) { index = i; break; } } return index; } console.views.source2.getIndexOfSourceText = function s2v_getstextindex (sourceText) { var index = -1; for (var i = 0; i < this.sourceTabList.length; ++i) { if (this.sourceTabList[i].sourceText == sourceText) { index = i; break; } } return index; } console.views.source2.getIndexOfTab = function s2v_gettabindex (tab) { var child = this.tabs.firstChild; var i = 0; while (child) { if (child == tab) return i; ++i; child = child.nextSibling; } return -1; } console.views.source2.getIndexOfDOMWindow = function s2v_getindex (window) { var child = this.deck.firstChild; var i = 0; while (child) { if (child.firstChild.webProgress.DOMWindow == window) return i; ++i; child = child.nextSibling; } return -1; } console.views.source2.getSourceTabForDOMWindow = function s2v_getbutton (window) { var i = this.getIndexOfDOMWindow(window); if (i == -1) return null; return this.sourceTabList[i]; } console.views.source2.showTab = function s2v_showtab (index) { //dd ("show tab " + index); if (this.tabs) { for (var i = 0; i < this.tabs.childNodes.length; ++i) { var tab = this.tabs.childNodes[i]; tab.selected = false; tab.removeAttribute("selected"); tab.removeAttribute("beforeselected"); tab.removeAttribute("afterselected"); } tab = this.tabs.childNodes[index]; tab.selected = true; tab.setAttribute("selected", "true"); if (tab.previousSibling) tab.previousSibling.setAttribute("beforeselected", "true"); if (tab.nextSibling) tab.nextSibling.setAttribute("afterselected", "true"); this.tabs.selectedItem = tab; if (!ASSERT(index <= (this.deck.childNodes.length - 1) && index >= 0, "index ``" + index + "'' out of range")) { return; } this.deck.selectedIndex = index; this.heading.value = this.sourceTabList[index].sourceText.url; } else this.lastSelectedTab = index; } console.views.source2.progressListener = new Object(); console.views.source2.progressListener.QueryInterface = function s2v_qi () { //dd ("qi!"); return this; } console.views.source2.progressListener.onStateChange = function s2v_statechange (webProgress, request, stateFlags, status) { const nsIWebProgressListener = Components.interfaces.nsIWebProgressListener; const START = nsIWebProgressListener.STATE_START; const STOP = nsIWebProgressListener.STATE_STOP; //dd ("state change " + stateFlags + ", " + status); var source2View = console.views.source2; var sourceTab; if (stateFlags & START) { //dd ("start load"); sourceTab = source2View.getSourceTabForDOMWindow(webProgress.DOMWindow); if (!ASSERT(sourceTab, "can't find tab for window")) { webProgress.removeProgressListener (this); return; } sourceTab.tab.setAttribute ("loading", "true"); } else if (stateFlags == 786448) { /* dd ("stop load " + stateFlags + " " + webProgress.DOMWindow.location.href); */ sourceTab = source2View.getSourceTabForDOMWindow(webProgress.DOMWindow); if (webProgress.DOMWindow.location.href != sourceTab.iframe.getAttribute("targetSrc")) { return; } webProgress.removeProgressListener (this); if (!ASSERT(sourceTab, "can't find tab for window")) return; sourceTab.tab.removeAttribute ("loading"); source2View.onSourceTabLoaded (sourceTab, status); } } console.views.source2.progressListener.onProgressChange = function s2v_progresschange (webProgress, request, currentSelf, totalSelf, currentMax, selfMax) { //dd ("progress change "); } console.views.source2.progressListener.onLocationChange = function s2v_statechange (webProgress, request, uri) { //dd ("location change " + uri); } console.views.source2.progressListener.onStatusChange = function s2v_statechange (webProgress, request, status, message) { //dd ("status change " + status + ", " + message); } console.views.source2.progressListener.onSecurityChange = function s2v_statechange (webProgress, request, state) { //dd ("security change"); } console.views.source2.hooks = new Object(); console.views.source2.hooks["hook-script-instance-destroyed"] = function s2v_hookScriptInstanceDestroyed (e) { if ("_sourceText" in e.scriptInstance) console.views.source2.removeSourceText (e.scriptInstance.sourceText); } console.views.source2.hooks["hook-debug-stop"] = console.views.source2.hooks["frame"] = function s2v_hookDebugStop (e) { var source2View = console.views.source2; var currentFrame = getCurrentFrame(); for (var i = 0; i < source2View.sourceTabList.length; ++i) source2View.markStopLine (source2View.sourceTabList[i], currentFrame); } console.views.source2.hooks["hook-debug-continue"] = function s2v_hookDebugCont (e) { var source2View = console.views.source2; for (var i = 0; i < source2View.sourceTabList.length; ++i) source2View.unmarkStopLine (source2View.sourceTabList[i]); } console.views.source2.hooks["hook-break-set"] = console.views.source2.hooks["hook-break-clear"] = function s2v_hookBreakSet (e) { var source2View = console.views.source2; for (var i = 0; i < source2View.sourceTabList.length; ++i) { var jsdScript; var line = -1; var sourceTab = source2View.sourceTabList[i]; var sourceText = sourceTab.sourceText; if ("scriptInstance" in sourceText && sourceText.scriptInstance == e.breakWrapper.scriptWrapper.scriptInstance) { jsdScript = e.breakWrapper.scriptWrapper.jsdScript; if (jsdScript.isValid) line = jsdScript.pcToLine (e.breakWrapper.pc, PCMAP_SOURCETEXT); } else if ("scriptWrapper" in sourceText && sourceText.scriptWrapper == e.breakWrapper.scriptWrapper) { jsdScript = e.breakWrapper.scriptWrapper.jsdScript; if (jsdScript.isValid) line = jsdScript.pcToLine (e.breakWrapper.pc, PCMAP_PRETTYPRINT); } if (line > 0) source2View.updateLineMargin (sourceTab, line); } } console.views.source2.hooks["hook-fbreak-set"] = console.views.source2.hooks["hook-fbreak-clear"] = function s2v_hookBreakSet (e) { var source2View = console.views.source2; for (var i = 0; i < source2View.sourceTabList.length; ++i) { var sourceTab = source2View.sourceTabList[i]; var sourceText = sourceTab.sourceText; if (sourceText.url.indexOf(e.fbreak.url) != -1) source2View.updateLineMargin (sourceTab, e.fbreak.lineNumber); } } console.views.source2.hooks["hook-display-sourcetext"] = console.views.source2.hooks["hook-display-sourcetext-soft"] = function s2v_hookDisplay (e) { var source2View = console.views.source2; source2View.unmarkHighlight(); var sourceTab = source2View.addSourceText (e.sourceText); if (e.rangeStart) { source2View.highlightStart = e.rangeStart; source2View.highlightEnd = e.rangeEnd; source2View.highlightTab = sourceTab; source2View.markHighlight(); } source2View.scrollTabTo (sourceTab, e.targetLine, 0); } console.views.source2.onShow = function s2v_show () { var source2View = this; function tryAgain () { //dd ("source2 view trying again..."); source2View.onShow(); }; //var version; //var help; try { this.tabs = getChildById (this.currentContent, "source2-tabs"); this.deck = getChildById (this.currentContent, "source2-deck"); this.heading = getChildById(this.currentContent, "source2-heading"); //this.bloke = getChildById (this.currentContent, "source2-bloke"); //version = getChildById (this.currentContent, "source2-version-label"); //help = getChildById (this.currentContent, "source2-help-label"); } catch (ex) { //dd ("caught exception showing source2 view..."); //dd (dumpObjectTree(ex)); } if (!this.deck || !this.tabs) { setTimeout (tryAgain, 500); return; } //version.setAttribute ("value", console.userAgent); //help.setAttribute ("value", MSG_SOURCE2_HELP); this.syncOutputDeck(); initContextMenu(this.currentContent.ownerDocument, "context:source2"); } console.views.source2.onHide = function s2v_hide () { if (this.sourceTabList.length > 0) this.lastSelectedTab = this.tabs.selectedIndex; this.clearOutputDeck(); this.deck = null; this.tabs = null; this.heading = null; } /******************************************************************************* * Source View *******************************************************************************/ console.views.source = new BasicOView(); const VIEW_SOURCE = "source"; console.views.source.viewId = VIEW_SOURCE; console.views.source.details = null; console.views.source.prettyPrint = false; console.views.source.init = function sv_init() { this.savedState = new Object(); console.prefManager.addPref("sourceView.enableMenuItem", false); this.enableMenuItem = console.prefs["sourceView.enableMenuItem"]; console.menuSpecs["context:source"] = { getContext: this.getContext, items: [ ["break", {enabledif: "cx.lineIsExecutable && !has('hasBreak')"}], ["clear", {enabledif: "has('hasBreak')"}], ["fbreak", {enabledif: "!has('hasFBreak')"}], ["fclear", {enabledif: "has('hasFBreak')"}], ["-"], ["run-to"], ["cont"], ["next"], ["step"], ["finish"], ["-"], ["toggle-pprint", {type: "checkbox", checkedif: "console.prefs['prettyprint']"}], ["-"], ["break-props"] ] }; this.caption = MSG_VIEW_SOURCE; var atomsvc = console.atomService; this.atomCurrent = atomsvc.getAtom("current-line"); this.atomHighlightStart = atomsvc.getAtom("highlight-start"); this.atomHighlightRange = atomsvc.getAtom("highlight-range"); this.atomHighlightEnd = atomsvc.getAtom("highlight-end"); this.atomBreak = atomsvc.getAtom("breakpoint"); this.atomFBreak = atomsvc.getAtom("future-breakpoint"); this.atomCode = atomsvc.getAtom("code"); this.atomPrettyPrint = atomsvc.getAtom("prettyprint"); this.atomWhitespace = atomsvc.getAtom("whitespace"); } console.views.source.hooks = new Object(); console.views.source.hooks["hook-break-set"] = console.views.source.hooks["hook-break-clear"] = console.views.source.hooks["hook-fbreak-set"] = console.views.source.hooks["hook-fbreak-clear"] = function sv_hookBreakChange(e) { if (console.views.source.tree) console.views.source.tree.invalidate(); } console.views.source.hooks["hook-debug-continue"] = function sv_hookDebugCont (e) { /* Invalidate on continue to remove the highlight line. */ if (console.views.source.tree) console.views.source.tree.invalidate(); } /** * Display requested sourcetext. */ console.views.source.hooks["hook-display-sourcetext"] = console.views.source.hooks["hook-display-sourcetext-soft"] = function sv_hookDisplay (e) { var sourceView = console.views.source; sourceView.details = e.details; sourceView.displaySourceText(e.sourceText, Boolean(e.targetLine)); sourceView.rangeStart = e.rangeStart - 1; sourceView.rangeEnd = e.rangeEnd - 1; var targetLine; if (e.targetLine == null) targetLine = sourceView.rangeStart; else targetLine = e.targetLine - 1; if (sourceView.tree) { if (e.targetLine && e.command.name == "hook-display-sourcetext-soft") { sourceView.softScrollTo (targetLine); } else if (sourceView.rangeEnd && (targetLine > e.rangeStart && targetLine <= e.rangeEnd) || (e.rangeStart == e.rangeEnd)) { /* if there is a range, and the target is in the range, * scroll target to the center */ sourceView.scrollTo (targetLine, 0); } else { /* otherwise scroll near the top */ sourceView.scrollTo (targetLine - 2, -1); } } else { var url = e.sourceText.url; if (!(url in sourceView.savedState)) sourceView.savedState[url] = new Object(); sourceView.savedState[url].topLine = targetLine; } console.views.source.currentLine = targetLine + 1; console.views.source.syncHeader(); } /** * Sync with the pretty print state as it changes. */ console.views.source.hooks["hook-source-load-complete"] = function sv_hookLoadComplete (e) { console.views.source.syncTreeView(); } console.views.source.hooks["pprint"] = function sv_hookLoadComplete (e) { console.views.source.prettyPrint = e.toggle; } console.views.source.onShow = function sv_show () { var sourceView = this; function cb () { if ("childData" in sourceView) { var sourceText = sourceView.childData; if (sourceText && sourceText.url in sourceView.savedState) { //dd ("clearing lastRowCount"); delete sourceView.savedState[sourceText.url].lastRowCount; } } sourceView.syncTreeView(); sourceView.urlLabel = getChildById(sourceView.currentContent, "source-url"); sourceView.syncHeader(); }; syncTreeView (getChildById(this.currentContent, "source-tree"), this, cb); initContextMenu(this.currentContent.ownerDocument, "context:source"); } console.views.source.onHide = function sv_hide () { syncTreeView (getChildById(this.currentContent, "source-tree"), null); delete this.urlLabel; } console.views.source.onClick = function sv_click (e) { var target = e.originalTarget; if (target.localName == "treechildren") { var row = new Object(); var col = new Object(); var childElt = new Object(); var treeBox = console.views.source.tree; treeBox.getCellAt(e.clientX, e.clientY, row, col, childElt); if (row.value == -1) return; colID = col.value.id; row = row.value; if (colID == "source:col-0") { if ("onMarginClick" in console.views.source.childData) console.views.source.childData.onMarginClick (e, row.value + 1); } } } console.views.source.onSelect = function sv_select (e) { var sourceView = console.views.source; sourceView.currentLine = sourceView.tree.view.selection.currentIndex + 1; console.views.source.syncHeader(); } console.views.source.super_scrollTo = BasicOView.prototype.scrollTo; console.views.source.scrollTo = function sv_scrollto (line, align) { if (!("childData" in this)) return; if (!this.childData.isLoaded) { /* the source hasn't been loaded yet, store line/align for processing * when the load is done. */ this.childData.pendingScroll = line; this.childData.pendingScrollType = align; return; } this.super_scrollTo(line, align); if (this.tree) this.tree.invalidate(); } console.views.source.syncHeader = function sv_synch () { if ("urlLabel" in this) { var value; if ("childData" in this) { value = getMsg(MSN_SOURCEHEADER_URL, [this.childData.url, this.currentLine]); } else { value = MSG_VAL_NONE; } this.urlLabel.setAttribute ("value", value); } } console.views.source.syncTreeView = function sv_synct (skipScrollRestore) { if (this.tree) { if (!("childData" in this) || !this.childData) { this.rowCount = 0; this.tree.rowCountChanged (0, 0); this.tree.invalidate(); return; }; var url = this.childData.url; var state; if (url in this.savedState) state = this.savedState[url]; else { //dd ("making new state"); state = this.savedState[url] = new Object(); } if (!("lastRowCount" in state) || state.lastRowCount != this.rowCount) { //dd ("notifying new row count " + this.rowCount); this.tree.rowCountChanged(0, this.rowCount); } state.lastRowCount = this.rowCount; if (!skipScrollRestore && "topLine" in state) this.scrollTo (state.topLine, 1); this.tree.invalidate(); delete state.topLine; } } /* * pass in a SourceText to be displayed on this tree */ console.views.source.displaySourceText = function sv_dsource (sourceText, skipScrollRestore) { var sourceView = this; if (!sourceText) { delete this.childData; this.rowCount = 0; this.syncTreeView(); return; } if (!ASSERT(sourceText.isLoaded, "Source text for '" + sourceText.url + "' has not been loaded.")) { return; } if ("childData" in this && sourceText == this.childData) return; /* save the current position before we change to another source */ if ("childData" in this && this.tree) { this.savedState[this.childData.url].topLine = this.tree.getFirstVisibleRow() + 1; } this.childData = sourceText; this.rowCount = sourceText.lines.length; //var hdr = document.getElementById("source-line-text"); //hdr.setAttribute ("label", sourceText.fileName); this.syncTreeView(skipScrollRestore); } /* * "soft" scroll to a line number in the current source. soft, in this * case, means that if the target line somewhere in the center of the * source view already, then we can just exit. otherwise, we'll center on the * target line. this is used when single stepping through source, when constant * one-line scrolls would be distracting. * * the line parameter is one based. */ console.views.source.softScrollTo = function sv_lscroll (line) { if (!("childData" in this)) return; if (!this.childData.isLoaded) { /* the source hasn't been loaded yet, queue the scroll for later. */ this.childData.pendingScroll = line; this.childData.pendingScrollType = 0; return; } delete this.childData.pendingScroll; delete this.childData.pendingScrollType; var first = this.tree.getFirstVisibleRow(); var last = this.tree.getLastVisibleRow(); var fuzz = 2; if (line < (first + fuzz) || line > (last - fuzz)) this.scrollTo (line - 2, -1); else this.tree.invalidate(); /* invalidate to show the new currentLine if * we don't have to scroll. */ } /** * Create a context object for use in the sourceView context menu. */ console.views.source.getContext = function sv_getcx(cx) { if (!cx) cx = new Object(); var sourceText = console.views.source.childData; cx.url = cx.urlPattern = sourceText.url; cx.breakWrapperList = new Array(); cx.lineNumberList = new Array(); cx.lineIsExecutable = null; function rowContextGetter (cx, row, i) { if (!("lineMap" in sourceText)) return cx; if (i == 0) { cx.lineNumber = row + 1; if (sourceText.lineMap[row] & LINE_BREAKABLE) { cx.lineIsExecutable = true; if ("scriptInstance" in sourceText) { var scriptInstance = sourceText.scriptInstance; var scriptWrapper = scriptInstance.getScriptWrapperAtLine(cx.lineNumber); if (scriptWrapper) { cx.scriptWrapper = scriptWrapper; cx.pc = scriptWrapper.jsdScript.lineToPc(cx.lineNumber, PCMAP_SOURCETEXT); } } else if ("scriptWrapper" in sourceText) { cx.scriptWrapper = sourceText.scriptWrapper; cx.pc = cx.scriptWrapper.jsdScript.lineToPc(cx.lineNumber, PCMAP_PRETTYPRINT); } } if (sourceText.lineMap[row] & LINE_BREAK) { cx.hasBreak = true; cx.breakWrapper = sourceText.scriptInstance.getBreakpoint(row + 1); if (cx.breakWrapper.parentBP) cx.hasFBreak = true; } else if (sourceText.lineMap[row] & LINE_FBREAK) { cx.hasFBreak = true; cx.breakWrapper = getFutureBreakpoint(cx.url, row + 1); } } else { if (sourceText.lineMap[row] & LINE_BREAK) { cx.hasBreak = true; var wrapper = sourceText.scriptInstance.getBreakpoint(row + 1); if (wrapper.parentBP) cx.hasFBreak = true; cx.breakWrapperList.push(wrapper); } else if (sourceText.lineMap[row] & LINE_FBREAK) { cx.hasFBreak = true; cx.breakWrapperList.push(getFutureBreakpoint(cx.url, row + 1)); } } return cx; }; getTreeContext (console.views.source, cx, rowContextGetter); return cx; } /* nsITreeView */ console.views.source.getRowProperties = function sv_rowprops (row, properties) { var prettyPrint = console.prefs["prettyprint"]; if ("frames" in console) { if (((!prettyPrint && row == console.stopLine - 1) || (prettyPrint && row == console.pp_stopLine - 1)) && console.stopFile == this.childData.url) { properties.AppendElement(this.atomCurrent); } } } /* nsITreeView */ console.views.source.getCellProperties = function sv_cellprops (row, col, properties) { if (!("childData" in this) || !this.childData.isLoaded || row < 0 || row >= this.childData.lines.length) return; var line = this.childData.lines[row]; if (!line) return; if (col.id == "source:col-0") { if ("lineMap" in this.childData && row in this.childData.lineMap) { var flags = this.childData.lineMap[row]; if (flags & LINE_BREAK) properties.AppendElement(this.atomBreak); if (flags & LINE_FBREAK) properties.AppendElement(this.atomFBreak); if (flags & LINE_BREAKABLE) properties.AppendElement(this.atomCode); } } if (this.rangeEnd != null) { if (row == this.rangeStart) { properties.AppendElement(this.atomHighlightStart); } else if (row == this.rangeEnd) { properties.AppendElement(this.atomHighlightEnd); } else if (row > this.rangeStart && row < this.rangeEnd) { properties.AppendElement(this.atomHighlightRange); } } if ("frames" in console) { if (((!this.prettyPrint && row == console.stopLine - 1) || (this.prettyPrint && row == console.pp_stopLine - 1)) && console.stopFile == this.childData.url) { properties.AppendElement(this.atomCurrent); } } } /* nsITreeView */ console.views.source.getCellText = function sv_getcelltext (row, col) { if (!this.childData.isLoaded || row < 0 || row > this.childData.lines.length) return ""; var ary = col.id.match (/:(.*)/); if (ary) col = ary[1]; switch (col) { case "col-2": return this.childData.lines[row]; case "col-1": return row + 1; default: return ""; } } /******************************************************************************* * Watch View *******************************************************************************/ console.views.watches = new XULTreeView(); const VIEW_WATCHES = "watches"; console.views.watches.viewId = VIEW_WATCHES; console.views.watches.init = function wv_init() { this.cmdary = [ ["watch-expr", cmdWatchExpr, CMD_CONSOLE], ["watch-exprd", cmdWatchExpr, CMD_CONSOLE], ["remove-watch", cmdUnwatch, CMD_CONSOLE], ["save-watches", cmdSaveWatches, CMD_CONSOLE], ["watch-property", cmdWatchProperty, 0], ]; console.menuSpecs["context:watches"] = { getContext: this.getContext, items: [ ["change-value", {enabledif: "cx.parentValue"}], ["-"], ["watch-expr"], ["remove-watch"], ["set-eval-obj", {type: "checkbox", checkedif: "has('jsdValue') && " + "cx.jsdValue.getWrappedValue() == " + "console.currentEvalObject", enabledif: "has('jsdValue') && " + "cx.jsdValue.jsType == TYPE_OBJECT"}], ["-"], ["find-creator", {enabledif: "cx.target instanceof ValueRecord && " + "cx.target.jsType == jsdIValue.TYPE_OBJECT && " + "cx.target.value.objectValue.creatorURL"}], ["find-ctor", {enabledif: "cx.target instanceof ValueRecord && " + "cx.target.jsType == jsdIValue.TYPE_OBJECT && " + "cx.target.value.objectValue.constructorURL"}], ["-"], ["toggle-functions", {type: "checkbox", checkedif: "ValueRecord.prototype.showFunctions"}], ["toggle-ecmas", {type: "checkbox", checkedif: "ValueRecord.prototype.showECMAProps"}], ["-"], ["save-watches"], ["restore-settings"] ] }; this.caption = MSG_VIEW_WATCHES; } console.views.watches.destroy = function lv_destroy () { var childRecords = this.childData.childData; for (var i = 0; i < childRecords.length; ++i) delete childRecords[i].onPreRefresh; delete this.childData; } console.views.watches.hooks = new Object(); console.views.watches.hooks["hook-debug-stop"] = console.views.watches.hooks["hook-eval-done"] = function lv_hookEvalDone (e) { console.views.watches.refresh(); } console.views.watches.onShow = function wv_show() { syncTreeView (getChildById(this.currentContent, "watch-tree"), this); initContextMenu(this.currentContent.ownerDocument, "context:watches"); } console.views.watches.onHide = function onHide() { syncTreeView (getChildById(this.currentContent, "watch-tree"), null); } console.views.watches.getCellProperties = function wv_cellprops (index, col, properties) { if (col.id != "watches:col-0") return null; var row = this.childData.locateChildByVisualRow(index); if (row) { if ("getProperties" in row) return row.getProperties (properties); if (row.property) return properties.AppendElement (row.property); } return null; } console.views.watches.getContext = function wv_getcx(cx) { cx.jsdValueList = new Array(); cx.indexList = new Array(); function recordContextGetter (cx, rec, i) { if (rec instanceof ValueRecord) { if (i == 0) { cx.jsdValue = rec.value; if ("value" in rec.parentRecord) cx.parentValue = rec.parentRecord.value; else cx.parentValue = null; cx.propertyName = rec.displayName; if (rec.parentRecord == console.views.watches.childData) cx.index = rec.childIndex; } else { cx.jsdValueList.push(rec.value); if (rec.parentRecord == console.views.watches.childData) cx.indexList.push(rec.childIndex); } } }; return getTreeContext (console.views.watches, cx, recordContextGetter); } console.views.watches.refresh = function wv_refresh() { if (!this.tree) return; var rootRecord = this.childData; if (!"childData" in rootRecord) return; this.freeze(); for (var i = 0; i < rootRecord.childData.length; ++i) rootRecord.childData[i].refresh() this.thaw(); /* the refresh may have changed a property without altering the * size of the tree, so thaw might not invalidate. */ this.tree.invalidate(); } console.views.watches.onRowCommand = function wv_rowcommand(rec) { if ("value" in rec.parentRecord) { dispatch ("change-value", {parentValue: rec.parentRecord.value, propertyName: rec.displayName}); } } console.views.watches.onKeyPress = function wv_keypress(rec, e) { if (e.keyCode == 46) { var cx = this.getContext({}); if ("index" in cx) dispatch ("remove-watch", cx); } } function cmdUnwatch (e) { var watches = console.views.watches.childData; function unwatch (index) { if (!index in watches) { display (getMsg(MSN_ERR_INVALID_PARAM, ["index", index]), MT_ERROR); return; } watches.removeChildAtIndex(index); }; if (e.indexList) { e.indexList = e.indexList.sort(); for (var i = e.indexList.length - 1; i >= 0; --i) unwatch(e.indexList[i]); } else { unwatch (e.index); } } function cmdWatchExpr (e) { var watches = console.views.watches; if (!e.expression) { if ("isInteractive" in e && e.isInteractive) { var watchData = console.views.watches.childData.childData; var len = watchData.length; if (len == 0) { display (getMsg(MSG_NO_WATCHES_SET)); return null; } display (getMsg(MSN_WATCH_HEADER, len)); for (var i = 0; i < len; ++i) { display (getMsg(MSN_FMT_WATCH_ITEM, [i, watchData[i].displayName, watchData[i].displayValue])); } return null; } var parent; if (watches.currentContent) parent = watches.currentContent.ownerWindow; else parent = window; e.expression = prompt(MSG_ENTER_WATCH, "", parent); if (!e.expression) return null; } var refresher; if (e.command.name == "watch-expr") { if (!("currentEvalObject" in console)) { display (MSG_ERR_NO_EVAL_OBJECT, MT_ERROR); return null; } refresher = function () { if ("frames" in console) { this.jsdFrame = getCurrentFrame(); this.value = evalInTargetScope(e.expression, true); } else { /* This is a security protection; leaving the * object open allows access to child items when * we have no frame to safely eval them on. */ this.close(); throw MSG_VAL_NA; } }; } else { refresher = function () { var rv = evalInDebuggerScope(e.expression, true); this.value = console.jsds.wrapValue(rv); }; } var rec = new ValueRecord(console.jsds.wrapValue(null), e.expression, 0); rec.onPreRefresh = refresher; rec.refresh(); watches.childData.appendChild(rec); watches.refresh(); return rec; } function cmdWatchProperty (e) { var rec = new ValueRecord(console.jsds.wrapValue(null), e.propertyName, 0); rec.onPreRefresh = function () { var prop = e.jsdValue.getProperty(e.propertyName); this.value = prop.value; this.flags = prop.flags; this.displayFlags = this.flags; }; rec.onPreRefresh(); console.views.watches.childData.appendChild(rec); return rec; } function cmdSaveWatches(e) { var needClose = false; var file = e.settingsFile; if (!file || file == "?") { rv = pickSaveAs(MSG_SAVE_FILE, "*.js"); if (rv.reason == PICK_CANCEL) return; e.settingsFile = file = fopen(rv.file, ">"); needClose = true; } else if (typeof file == "string") { e.settingsFile = file = fopen(file, ">"); needClose = true; } file.write ("\n//Watch settings start...\n"); var watchData = console.views.watches.childData.childData; var len = watchData.length; for (var i = 0; i < len; ++i) { file.write("dispatch('watch-expr " + watchData[i].displayName + "');\n"); } file.write ("\n" + MSG_WATCHES_RESTORED.quote() + ";\n"); if (needClose) file.close(); } /******************************************************************************* * Windows View *******************************************************************************/ console.views.windows = new XULTreeView(); const VIEW_WINDOWS = "windows"; console.views.windows.viewId = VIEW_WINDOWS; console.views.windows.init = function winv_init () { console.menuSpecs["context:windows"] = { getContext: this.getContext, items: [ ["find-url"], ["set-eval-obj", {type: "checkbox", checkedif: "has('jsdValue') && " + "cx.jsdValue.getWrappedValue() == " + "console.currentEvalObject", enabledif: "has('jsdValue') && " + "cx.jsdValue.jsType == TYPE_OBJECT"}] ] }; this.caption = MSG_VIEW_WINDOWS; } console.views.windows.hooks = new Object(); console.views.windows.hooks["hook-window-opened"] = function winv_hookWindowOpened (e) { console.views.windows.childData.appendChild (new WindowRecord(e.window, "")); } console.views.windows.hooks["hook-window-closed"] = function winv_hookWindowClosed (e) { var winRecord = console.views.windows.locateChildByWindow(e.window); if (!ASSERT(winRecord, "Can't find window record for closed window.")) return; console.views.windows.childData.removeChildAtIndex(winRecord.childIndex); } console.views.windows.hooks["chrome-filter"] = function scv_hookChromeFilter(e) { if (e.toggle != null) { var windowsView = console.views.windows; var rootRecord = console.views.windows.childData; windowsView.freeze(); rootRecord.childData = new Array(); var enumerator = console.windowWatcher.getWindowEnumerator(); while (enumerator.hasMoreElements()) { var window = enumerator.getNext(); if (!isWindowFiltered(window)) rootRecord.appendChild (new WindowRecord(window, "")); } windowsView.thaw(); if (windowsView.tree) windowsView.tree.invalidate(); } } console.views.windows.onShow = function winv_show () { syncTreeView (getChildById(this.currentContent, "windows-tree"), this); initContextMenu(this.currentContent.ownerDocument, "context:windows"); } console.views.windows.onHide = function winv_hide () { syncTreeView (getChildById(this.currentContent, "windows-tree"), null); } console.views.windows.getCellProperties = function winv_cellprops (index, col, properties) { if (col.id == "windows:col-0") { var row = this.childData.locateChildByVisualRow(index); if (row) properties.AppendElement (row.property); } return; } console.views.windows.onRowCommand = function winv_rowcommand (rec) { if ("url" in rec) dispatch ("find-url", { url: rec.url }); } console.views.windows.getContext = function winv_getcx(cx) { cx.jsdValueList = new Array(); cx.urlList = new Array(); function recordContextGetter (cx, rec, i) { if (i == 0) { if (rec instanceof WindowRecord || rec instanceof FileRecord) { if ("window" in rec) cx.jsdValue = console.jsds.wrapValue(rec.window); cx.url = rec.url; } } else { if (rec instanceof WindowRecord || rec instanceof FileRecord) { if ("window" in rec) cx.jsdValueList.push(console.jsds.wrapValue(rec.window)); cx.urlList.push (rec.url); } } }; return getTreeContext (console.views.windows, cx, recordContextGetter); } console.views.windows.locateChildByWindow = function winv_find (win) { var children = this.childData.childData; for (var i = 0; i < children.length; ++i) { var child = children[i]; if (child.window == win) return child; } return null; } /************************/ function formatRecord (rec, indent) { var str = ""; for (var i in rec._colValues) str += rec._colValues[i] + ", "; str += "["; str += rec.calculateVisualRow() + ", "; str += rec.childIndex + ", "; str += rec.level + ", "; str += rec.visualFootprint + ", "; str += rec.isContainerOpen + ", "; str += rec.isHidden + "]"; dd (indent + str); } function formatBranch (rec, indent) { for (var i = 0; i < rec.childData.length; ++i) { formatRecord (rec.childData[i], indent); if (rec.childData[i].childData) formatBranch(rec.childData[i], indent + " "); } }