diff --git a/browser/app/profile/firefox.js b/browser/app/profile/firefox.js index 4bd970bc093..821d68f8a24 100644 --- a/browser/app/profile/firefox.js +++ b/browser/app/profile/firefox.js @@ -1033,6 +1033,12 @@ pref("devtools.hud.loglimit.cssparser", 200); pref("devtools.hud.loglimit.exception", 200); pref("devtools.hud.loglimit.console", 200); +// The developer tools editor configuration: +// - tabsize: how many spaces to use when a Tab character is displayed. +// - expandtab: expand Tab characters to spaces. +pref("devtools.editor.tabsize", 4); +pref("devtools.editor.expandtab", true); + // Whether the character encoding menu is under the main Firefox button. This // preference is a string so that localizers can alter it. pref("browser.menu.showCharacterEncoding", "chrome://browser/locale/browser.properties"); diff --git a/browser/base/content/scratchpad.js b/browser/base/content/scratchpad.js index 6781d02c052..abb932cd266 100644 --- a/browser/base/content/scratchpad.js +++ b/browser/base/content/scratchpad.js @@ -64,6 +64,9 @@ const SCRATCHPAD_L10N = "chrome://browser/locale/scratchpad.properties"; const SCRATCHPAD_WINDOW_FEATURES = "chrome,titlebar,toolbar,centerscreen,resizable,dialog=no"; const DEVTOOLS_CHROME_ENABLED = "devtools.chrome.enabled"; +const PREF_TABSIZE = "devtools.editor.tabsize"; +const PREF_EXPANDTAB = "devtools.editor.expandtab"; + /** * The scratchpad object handles the Scratchpad window functionality. */ @@ -628,7 +631,53 @@ var Scratchpad = { errorConsoleCommand.removeAttribute("disabled"); chromeContextCommand.removeAttribute("disabled"); } + + let tabsize = Services.prefs.getIntPref(PREF_TABSIZE); + if (tabsize < 1) { + // tabsize is invalid, clear back to the default value. + Services.prefs.clearUserPref(PREF_TABSIZE); + tabsize = Services.prefs.getIntPref(PREF_TABSIZE); + } + + let expandtab = Services.prefs.getBoolPref(PREF_EXPANDTAB); + this._tabCharacter = expandtab ? (new Array(tabsize + 1)).join(" ") : "\t"; + this.textbox.style.MozTabSize = tabsize; + this.insertIntro(); + + // Make the Tab key work. + this.textbox.addEventListener("keypress", this.onKeypress.bind(this), false); + + this.textbox.focus(); + }, + + /** + * The textbox keypress event handler which allows users to indent code using + * the Tab key. + * + * @param nsIDOMEvent aEvent + */ + onKeypress: function SP_onKeypress(aEvent) + { + if (aEvent.keyCode == aEvent.DOM_VK_TAB) { + this.insertTextAtCaret(this._tabCharacter); + aEvent.preventDefault(); + } + }, + + /** + * Insert text at the current caret location. + * + * @param string aText + */ + insertTextAtCaret: function SP_insertTextAtCaret(aText) + { + let firstPiece = this.textbox.value.substring(0, this.textbox.selectionStart); + let lastPiece = this.textbox.value.substring(this.textbox.selectionEnd); + this.textbox.value = firstPiece + aText + lastPiece; + + let newCaretPosition = firstPiece.length + aText.length; + this.selectRange(newCaretPosition, newCaretPosition); }, }; diff --git a/browser/base/content/test/Makefile.in b/browser/base/content/test/Makefile.in index 4915d246214..73260d58464 100644 --- a/browser/base/content/test/Makefile.in +++ b/browser/base/content/test/Makefile.in @@ -201,6 +201,7 @@ _BROWSER_FILES = \ browser_scratchpad_files.js \ browser_scratchpad_ui.js \ browser_scratchpad_bug_646070_chrome_context_pref.js \ + browser_scratchpad_bug_660560_tab.js \ browser_overflowScroll.js \ browser_locationBarExternalLoad.js \ browser_pageInfo.js \ diff --git a/browser/base/content/test/browser_scratchpad_bug_660560_tab.js b/browser/base/content/test/browser_scratchpad_bug_660560_tab.js new file mode 100644 index 00000000000..eca5ea2f86f --- /dev/null +++ b/browser/base/content/test/browser_scratchpad_bug_660560_tab.js @@ -0,0 +1,116 @@ +/* vim: set ts=2 et sw=2 tw=80: */ +/* Any copyright is dedicated to the Public Domain. + http://creativecommons.org/publicdomain/zero/1.0/ */ + +// Reference to the Scratchpad chrome window object. +let gScratchpadWindow; + +function test() +{ + waitForExplicitFinish(); + + gBrowser.selectedTab = gBrowser.addTab(); + gBrowser.selectedBrowser.addEventListener("load", function() { + gBrowser.selectedBrowser.removeEventListener("load", arguments.callee, true); + + ok(window.Scratchpad, "Scratchpad variable exists"); + + Services.prefs.setIntPref("devtools.editor.tabsize", 5); + + gScratchpadWindow = Scratchpad.openScratchpad(); + gScratchpadWindow.addEventListener("load", runTests, false); + }, true); + + content.location = "data:text/html,Scratchpad test for the Tab key, bug 660560"; +} + +function runTests() +{ + gScratchpadWindow.removeEventListener("load", arguments.callee, false); + + let sp = gScratchpadWindow.Scratchpad; + ok(sp, "Scratchpad object exists in new window"); + + is(gScratchpadWindow.document.activeElement, sp.textbox.inputField, + "The textbox has focus"); + + is(sp.textbox.style.MozTabSize, 5, "-moz-tab-size is correct"); + + sp.textbox.value = "window.foo;"; + sp.selectRange(1, 3); + + EventUtils.synthesizeKey("VK_TAB", {}, gScratchpadWindow); + + is(sp.textbox.value, "w dow.foo;", + "Tab key added 5 spaces"); + + is(sp.textbox.selectionStart, 6, "caret location is correct"); + + is(sp.textbox.selectionStart, sp.textbox.selectionEnd, + "caret location is correct, confirmed"); + + // Test the new insertTextAtCaret() method. + + sp.insertTextAtCaret("omg"); + + is(sp.textbox.value, "w omgdow.foo;", "insertTextAtCaret() works"); + + is(sp.textbox.selectionStart, 9, "caret location is correct after update"); + + is(sp.textbox.selectionStart, sp.textbox.selectionEnd, + "caret location is correct, confirmed"); + + gScratchpadWindow.close(); + + Services.prefs.setIntPref("devtools.editor.tabsize", 6); + Services.prefs.setBoolPref("devtools.editor.expandtab", false); + gScratchpadWindow = Scratchpad.openScratchpad(); + gScratchpadWindow.addEventListener("load", runTests2, false); +} + +function runTests2() +{ + gScratchpadWindow.removeEventListener("load", arguments.callee, false); + + let sp = gScratchpadWindow.Scratchpad; + + is(sp.textbox.style.MozTabSize, 6, "-moz-tab-size is correct"); + + sp.textbox.value = "window.foo;"; + sp.selectRange(1, 3); + + EventUtils.synthesizeKey("VK_TAB", {}, gScratchpadWindow); + + is(sp.textbox.value, "w\tdow.foo;", "Tab key added the tab character"); + + is(sp.textbox.selectionStart, 2, "caret location is correct"); + + is(sp.textbox.selectionStart, sp.textbox.selectionEnd, + "caret location is correct, confirmed"); + + gScratchpadWindow.close(); + + // check with an invalid tabsize value. + Services.prefs.setIntPref("devtools.editor.tabsize", 0); + Services.prefs.setBoolPref("devtools.editor.expandtab", true); + gScratchpadWindow = Scratchpad.openScratchpad(); + gScratchpadWindow.addEventListener("load", runTests3, false); +} + +function runTests3() +{ + gScratchpadWindow.removeEventListener("load", arguments.callee, false); + + let sp = gScratchpadWindow.Scratchpad; + + is(sp.textbox.style.MozTabSize, 4, "-moz-tab-size is correct"); + + Services.prefs.clearUserPref("devtools.editor.tabsize"); + Services.prefs.clearUserPref("devtools.editor.expandtab"); + + gScratchpadWindow.close(); + gScratchpadWindow = null; + + gBrowser.removeCurrentTab(); + finish(); +}