/* -*- Mode: javascript; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */ /* vim: set ft=javascript ts=2 et sw=2 tw=80: */ /* This Source Code Form is subject to the terms of the Mozilla Public * License, v. 2.0. If a copy of the MPL was not distributed with this * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ "use strict"; const SOURCE_URL_DEFAULT_MAX_LENGTH = 64; // chars const SOURCE_SYNTAX_HIGHLIGHT_MAX_FILE_SIZE = 1048576; // 1 MB in bytes const STACK_FRAMES_SOURCE_URL_MAX_LENGTH = 15; // chars const STACK_FRAMES_SOURCE_URL_TRIM_SECTION = "center"; const STACK_FRAMES_POPUP_SOURCE_URL_MAX_LENGTH = 32; // chars const STACK_FRAMES_POPUP_SOURCE_URL_TRIM_SECTION = "center"; const STACK_FRAMES_SCROLL_DELAY = 100; // ms const PANES_APPEARANCE_DELAY = 50; // ms const BREAKPOINT_LINE_TOOLTIP_MAX_LENGTH = 1000; // chars const BREAKPOINT_CONDITIONAL_POPUP_POSITION = "before_start"; const BREAKPOINT_CONDITIONAL_POPUP_OFFSET_X = 7; // px const BREAKPOINT_CONDITIONAL_POPUP_OFFSET_Y = -3; // px const FILTERED_SOURCES_MAX_RESULTS = 10; const GLOBAL_SEARCH_EXPAND_MAX_RESULTS = 50; const GLOBAL_SEARCH_LINE_MAX_LENGTH = 300; // chars const GLOBAL_SEARCH_ACTION_MAX_DELAY = 1500; // ms const SEARCH_GLOBAL_FLAG = "!"; const SEARCH_TOKEN_FLAG = "#"; const SEARCH_LINE_FLAG = ":"; const SEARCH_VARIABLE_FLAG = "*"; /** * Object defining the debugger view components. */ let DebuggerView = { /** * Initializes the debugger view. * * @param function aCallback * Called after the view finishes initializing. */ initialize: function DV_initialize(aCallback) { dumpn("Initializing the DebuggerView"); this._initializeWindow(); this._initializePanes(); this.Toolbar.initialize(); this.Options.initialize(); this.Filtering.initialize(); this.FilteredSources.initialize(); this.ChromeGlobals.initialize(); this.StackFrames.initialize(); this.Sources.initialize(); this.WatchExpressions.initialize(); this.GlobalSearch.initialize(); this.Variables = new VariablesView(document.getElementById("variables")); this.Variables.searchPlaceholder = L10N.getStr("emptyVariablesFilterText"); this.Variables.emptyText = L10N.getStr("emptyVariablesText"); this.Variables.onlyEnumVisible = Prefs.variablesOnlyEnumVisible; this.Variables.searchEnabled = Prefs.variablesSearchboxVisible; this.Variables.eval = DebuggerController.StackFrames.evaluate; this.Variables.lazyEmpty = true; this._initializeEditor(aCallback); }, /** * Destroys the debugger view. * * @param function aCallback * Called after the view finishes destroying. */ destroy: function DV_destroy(aCallback) { dumpn("Destroying the DebuggerView"); this.Toolbar.destroy(); this.Options.destroy(); this.Filtering.destroy(); this.FilteredSources.destroy(); this.ChromeGlobals.destroy(); this.StackFrames.destroy(); this.Sources.destroy(); this.WatchExpressions.destroy(); this.GlobalSearch.destroy(); this._destroyWindow(); this._destroyPanes(); this._destroyEditor(); aCallback(); }, /** * Initializes the UI for the window. */ _initializeWindow: function DV__initializeWindow() { dumpn("Initializing the DebuggerView window"); let isRemote = window._isRemoteDebugger; let isChrome = window._isChromeDebugger; if (isRemote || isChrome) { window.moveTo(Prefs.windowX, Prefs.windowY); window.resizeTo(Prefs.windowWidth, Prefs.windowHeight); if (isRemote) { document.title = L10N.getStr("remoteDebuggerWindowTitle"); } else { document.title = L10N.getStr("chromeDebuggerWindowTitle"); } } }, /** * Destroys the UI for the window. */ _destroyWindow: function DV__destroyWindow() { dumpn("Destroying the DebuggerView window"); if (window._isRemoteDebugger || window._isChromeDebugger) { Prefs.windowX = window.screenX; Prefs.windowY = window.screenY; Prefs.windowWidth = window.outerWidth; Prefs.windowHeight = window.outerHeight; } }, /** * Initializes the UI for all the displayed panes. */ _initializePanes: function DV__initializePanes() { dumpn("Initializing the DebuggerView panes"); this._sourcesPane = document.getElementById("sources-pane"); this._instrumentsPane = document.getElementById("instruments-pane"); this._instrumentsPaneToggleButton = document.getElementById("instruments-pane-toggle"); this._collapsePaneString = L10N.getStr("collapsePanes"); this._expandPaneString = L10N.getStr("expandPanes"); this._sourcesPane.setAttribute("width", Prefs.sourcesWidth); this._instrumentsPane.setAttribute("width", Prefs.instrumentsWidth); this.toggleInstrumentsPane({ visible: Prefs.panesVisibleOnStartup }); }, /** * Destroys the UI for all the displayed panes. */ _destroyPanes: function DV__destroyPanes() { dumpn("Destroying the DebuggerView panes"); Prefs.sourcesWidth = this._sourcesPane.getAttribute("width"); Prefs.instrumentsWidth = this._instrumentsPane.getAttribute("width"); this._sourcesPane = null; this._instrumentsPane = null; this._instrumentsPaneToggleButton = null; }, /** * Initializes the SourceEditor instance. * * @param function aCallback * Called after the editor finishes initializing. */ _initializeEditor: function DV__initializeEditor(aCallback) { dumpn("Initializing the DebuggerView editor"); let placeholder = document.getElementById("editor"); let config = { mode: SourceEditor.MODES.JAVASCRIPT, readOnly: true, showLineNumbers: true, showAnnotationRuler: true, showOverviewRuler: true }; this.editor = new SourceEditor(); this.editor.init(placeholder, config, function() { this._loadingText = L10N.getStr("loadingText"); this._onEditorLoad(); aCallback(); }.bind(this)); }, /** * The load event handler for the source editor, also executing any necessary * post-load operations. */ _onEditorLoad: function DV__onEditorLoad() { dumpn("Finished loading the DebuggerView editor"); DebuggerController.Breakpoints.initialize(); window.dispatchEvent(document, "Debugger:EditorLoaded", this.editor); this.editor.focus(); }, /** * Destroys the SourceEditor instance and also executes any necessary * post-unload operations. */ _destroyEditor: function DV__destroyEditor() { dumpn("Destroying the DebuggerView editor"); DebuggerController.Breakpoints.destroy(); window.dispatchEvent(document, "Debugger:EditorUnloaded", this.editor); }, /** * Sets the proper editor mode (JS or HTML) according to the specified * content type, or by determining the type from the url or text content. * * @param string aUrl * The source url. * @param string aContentType [optional] * The source content type. * @param string aTextContent [optional] * The source text content. */ setEditorMode: function DV_setEditorMode(aUrl, aContentType = "", aTextContent = "") { if (aContentType) { if (/javascript/.test(aContentType)) { this.editor.setMode(SourceEditor.MODES.JAVASCRIPT); } else { this.editor.setMode(SourceEditor.MODES.HTML); } } else if (aTextContent.match(/^\s*