diff --git a/common/content/bindings.xml b/common/content/bindings.xml index 746ca242..901e467e 100644 --- a/common/content/bindings.xml +++ b/common/content/bindings.xml @@ -19,11 +19,55 @@ - + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/common/content/buffer.js b/common/content/buffer.js index 5c2f0c97..0e3f54f2 100644 --- a/common/content/buffer.js +++ b/common/content/buffer.js @@ -148,39 +148,12 @@ var Buffer = Module("buffer", { buffer.viewSource([elem.getAttribute("href"), Number(elem.getAttribute("line"))]) }; - this.replaceProgressListener(this.progressListener); + this.cleanupProgressListener = util.overlayObject(window.XULBrowserWindow, + this.progressListener); }, cleanup: function () { - for (let prop in properties(this.progressListener)) - if (!this.progressListener.__lookupGetter__(prop) && - !callable(this.progressListener[prop])) - this.origProgressListener[prop] = this.progressListener[prop] - - this.replaceProgressListener(this.origProgressListener); - }, - - replaceProgressListener: function (newListener) { - // I hate this whole hack. --Kris - let obj = window.XULBrowserWindow, getter; - for (let prop in properties(obj)) - if ((getter = obj.__lookupGetter__(prop)) && !obj.__lookupSetter__(prop)) { - newListener.__defineGetter__(prop, getter); - delete obj[prop]; - } - - this.origProgressListener = window.XULBrowserWindow; - try { - config.browser.removeProgressListener(window.XULBrowserWindow); - } - catch (e) {} // Why? --djk - - config.browser.addProgressListener(newListener, Ci.nsIWebProgress.NOTIFY_ALL); - window.XULBrowserWindow = newListener; - window.QueryInterface(Ci.nsIInterfaceRequestor).getInterface(Ci.nsIWebNavigation) - .QueryInterface(Ci.nsIDocShellTreeItem).treeOwner - .QueryInterface(Ci.nsIInterfaceRequestor).getInterface(Ci.nsIXULWindow) - .XULBrowserWindow = newListener; + this.cleanupProgressListener(); }, destroy: function () { @@ -237,11 +210,6 @@ var Buffer = Module("buffer", { dactyl.initHelp(); config.styleHelp(); } - - // mark the buffer as loaded, we can't use buffer.loaded - // since that always refers to the current buffer, while doc can be - // any buffer, even in a background tab - doc.pageIsFullyLoaded = 1; } if (doc instanceof HTMLDocument) { @@ -266,10 +234,8 @@ var Buffer = Module("buffer", { /** * @property {Object} The document loading progress listener. */ - progressListener: update(Object.create(window.XULBrowserWindow), { - QueryInterface: XPCOMUtils.generateQI([Ci.nsISupportsWeakReference, Ci.nsIWebProgressListener]), - - loadCount: 0, + progressListener: { + dactylLoadCount: 0, // XXX: function may later be needed to detect a canceled synchronous openURL() onStateChange: function onStateChange(webProgress, request, flags, status) { @@ -280,12 +246,11 @@ var Buffer = Module("buffer", { // This fires when the load event is initiated // only thrown for the current tab, not when another tab changes if (flags & Ci.nsIWebProgressListener.STATE_START) { - webProgress.DOMWindow.document.pageIsFullyLoaded = 0; statusline.updateProgress(0); buffer._triggerLoadAutocmd("PageLoadPre", webProgress.DOMWindow.document); - if (document.commandDispatcher.focusedWindow == webProgress.DOMWindow && this.loadCount++) + if (document.commandDispatcher.focusedWindow == webProgress.DOMWindow && this.dactylLoadCount++) util.timeout(function () { modes.reset(false); }, dactyl.mode == modes.HINTS ? 500 : 0); } @@ -294,8 +259,6 @@ var Buffer = Module("buffer", { config.browser.mCurrentBrowser.collapsed = false; if (!dactyl.focusedElement) dactyl.focusContent(); - - webProgress.DOMWindow.document.pageIsFullyLoaded = (status == 0 ? 1 : 2); statusline.updateUrl(); } } @@ -366,7 +329,7 @@ var Buffer = Module("buffer", { break; } }, - }), + }, /** * @property {Array} The alternative style sheets for the current @@ -387,19 +350,12 @@ var Buffer = Module("buffer", { pageInfo: null, /** - * @property {number} A value indicating whether the buffer is loaded. - * Values may be: - * 0 - Loading. - * 1 - Fully loaded. - * 2 - Load failed. + * @property {number} True when the buffer is fully loaded. */ - get loaded() - Math.min.apply(Math, - buffer.allFrames().map(function (frame) - frame.document.pageIsFullyLoaded || 0)), - set loaded(val) - buffer.allFrames().forEach(function (frame) - frame.document.pageIsFullyLoaded = val), + get loaded() Math.min.apply(null, + buffer.allFrames() + .map(function (frame) ["loading", "interactive", "complete"] + .indexOf(frame.document.readyState))), /** * @property {Object} The local state store for the currently selected @@ -1217,6 +1173,13 @@ var Buffer = Module("buffer", { return elem || doc.body || doc.documentElement; }, + scrollTo: function scrollTo(elem, left, top) { + if (left != null) + elem.scrollLeft = left; + if (top != null) + elem.scrollTop = top; + }, + scrollVertical: function scrollVertical(elem, increment, number) { elem = elem || Buffer.findScrollable(number, false); let fontSize = parseInt(util.computedStyle(elem).fontSize); @@ -1227,10 +1190,8 @@ var Buffer = Module("buffer", { else throw Error(); - if (number < 0 ? elem.scrollTop > 0 : elem.scrollTop < elem.scrollHeight - elem.clientHeight) - elem.scrollTop += number * increment; - else - dactyl.beep(); + dactyl.assert(number < 0 ? elem.scrollTop > 0 : elem.scrollTop < elem.scrollHeight - elem.clientHeight); + Buffer.scrollTo(elem, null, elem.scrollTop + number * increment); }, scrollHorizontal: function scrollHorizontal(elem, increment, number) { @@ -1243,21 +1204,19 @@ var Buffer = Module("buffer", { else throw Error(); - if (number < 0 ? elem.scrollLeft > 0 : elem.scrollLeft < elem.scrollWidth - elem.clientWidth) - elem.scrollLeft += number * increment; - else - dactyl.beep(); + dactyl.assert(number < 0 ? elem.scrollLeft > 0 : elem.scrollLeft < elem.scrollWidth - elem.clientWidth); + Buffer.scrollTo(elem, elem.scrollLeft + number * increment, null); }, scrollToPercent: function scrollElemToPercent(elem, horizontal, vertical) { elem = elem || Buffer.findScrollable(0, vertical == null); marks.add("'", true); - if (horizontal != null) - elem.scrollLeft = (elem.scrollWidth - elem.clientWidth) * (horizontal / 100); - - if (vertical != null) - elem.scrollTop = (elem.scrollHeight - elem.clientHeight) * (vertical / 100); + Buffer.scrollTo(elem, + horizontal == null ? null + : (elem.scrollWidth - elem.clientWidth) * (horizontal / 100), + vertical == null ? null + : (elem.scrollHeight - elem.clientHeight) * (vertical / 100)); }, openUploadPrompt: function openUploadPrompt(elem) { diff --git a/common/content/configbase.js b/common/content/configbase.js index 6fb48960..d9378581 100644 --- a/common/content/configbase.js +++ b/common/content/configbase.js @@ -20,6 +20,16 @@ var ConfigBase = Class(ModuleBase, { highlight.styleableChrome = this.styleableChrome; highlight.loadCSS(this.CSS); highlight.loadCSS(this.helpCSS); + if (!util.haveGecko("2b")) + highlight.loadCSS(); let img = Image(); img.src = this.logo || "chrome://" + this.name + "/content/logo.png"; diff --git a/common/content/dactyl.js b/common/content/dactyl.js index 6ea9a0a8..36ce66f7 100644 --- a/common/content/dactyl.js +++ b/common/content/dactyl.js @@ -1335,9 +1335,12 @@ var Dactyl = Module("dactyl", XPCOM(Ci.nsISupportsWeakReference, ModuleBase), { styles.system.add("taboptions", "chrome://*", classes.length ? classes.join(",") + "{ display: none; }" : ""); - }, - validator: function (opts) dactyl.has("Gecko2") || - Option.validIf(!/[nN]/.test(opts), "Tab numbering not available in this " + config.host + " version") + + if (!dactyl.has("Gecko2")) { + tabs.tabBinding.enabled = Array.some(opts, function (k) k in this.opts, this); + tabs.updateTabCount(); + } + } } ].filter(function (group) !group.feature || dactyl.has(group.feature)); diff --git a/common/content/events.js b/common/content/events.js index deab0e50..b3aaf6c0 100644 --- a/common/content/events.js +++ b/common/content/events.js @@ -206,7 +206,6 @@ var Events = Module("events", { } catch (e) {} - buffer.loaded = 1; // even if not a full page load, assume it did load correctly before starting the macro modes.replaying = true; res = events.feedkeys(this._macros.get(this._lastMacro).keys, { noremap: true }); modes.replaying = false; @@ -657,15 +656,14 @@ var Events = Module("events", { commandline.clear(); // TODO: allow macros to be continued when page does not fully load with an option - let ret = (buffer.loaded == 1); - if (!ret) + if (!buffer.loaded) dactyl.echoerr("Page did not load completely in " + maxWaitTime + " seconds. Macro stopped."); // sometimes the input widget had focus when replaying a macro // maybe this call should be moved somewhere else? // dactyl.focusContent(true); - return ret; + return buffer.loaded; }, onDOMMenuBarActive: function () { @@ -1106,8 +1104,7 @@ var Events = Module("events", { else if (this.pendingArgMap) { let map = this.pendingArgMap; if (!Events.isEscape(key)) - if (!modes.replaying || this.waitForPageLoad()) - execute(map, null, this.count, key); + execute(map, null, this.count, key); return true; } else if (map && !event.skipmap && candidates.length == 0) { @@ -1136,8 +1133,7 @@ var Events = Module("events", { if (modes.replaying && !this.waitForPageLoad()) return true; - let ret = execute(map, null, this.count); - return !(map.route && ret); + return !execute(map, null, this.count) || !map.route } } else if (mappings.getCandidates(this.main, candidateCommand).length > 0 && !event.skipmap) { diff --git a/common/content/options.js b/common/content/options.js index 08d7599f..0b462af7 100644 --- a/common/content/options.js +++ b/common/content/options.js @@ -669,7 +669,7 @@ var Options = Module("options", { } let closure = function () options._optionMap[name]; - memoize(this._options, this._options.length, closure); + memoize(this._optionMap, name, function () Option(names, description, type, defaultValue, extraInfo)); for (let alias in values(names.slice(1))) memoize(this._optionMap, alias, closure); @@ -678,6 +678,8 @@ var Options = Module("options", { closure().initValue(); else memoize(this.needInit, this.needInit.length, closure); + this._floptions = (this._floptions || []).concat(name); + memoize(this._options, this._options.length, closure); // quickly access options with options["wildmode"]: this.__defineGetter__(name, function () this._optionMap[name].value); @@ -821,9 +823,9 @@ var Options = Module("options", { */ remove: function (name) { let opt = this.get(name); + this._options = this._options.filter(function (o) o != opt); for (let name in values(opt.names)) delete this._optionMap[name]; - this._options = this._options.filter(function (o) o != opt); }, /** @property {Object} The options store. */ diff --git a/common/content/tabs.js b/common/content/tabs.js index f7a6ad5f..fbefa2af 100644 --- a/common/content/tabs.js +++ b/common/content/tabs.js @@ -34,6 +34,11 @@ var Tabs = Module("tabs", { dactyl.commands["tabs.select"] = function (event) { tabs.select(event.originalTarget.getAttribute("identifier")); }; + + this.tabBinding = styles.system.add("tab-binding", "chrome://browser/content/browser.xul", String.replace(<>, /tab-./g, function (m) util.OS.isMacOSX ? "tab-mac" : m), + false, true); }, cleanup: function cleanup() { @@ -45,9 +50,9 @@ var Tabs = Module("tabs", { } }, - _updateTabCount: function () { - if (dactyl.has("Gecko2")) - for (let [i, tab] in Iterator(this.visibleTabs)) { + updateTabCount: function () { + for (let [i, tab] in Iterator(this.visibleTabs)) { + if (dactyl.has("Gecko2")) { function node(clas) document.getAnonymousElementByAttribute(tab, "class", clas); if (!node("dactyl-tab-number")) { let nodes = {}; @@ -60,8 +65,10 @@ var Tabs = Module("tabs", { tab.__defineGetter__("dactylOrdinal", function () Number(nodes.icon.value)); tab.__defineSetter__("dactylOrdinal", function (i) nodes.icon.value = nodes.label.textContent = i); } - tab.dactylOrdinal = i + 1; } + tab.setAttribute("dactylOrdinal", i + 1); + tab.dactylOrdinal = i + 1; + } statusline.updateTabCount(true); }, @@ -497,7 +504,7 @@ var Tabs = Module("tabs", { } }, { load: function () { - tabs._updateTabCount(); + tabs.updateTabCount(); }, commands: function () { commands.add(["bd[elete]", "bw[ipeout]", "bun[load]", "tabc[lose]"], @@ -864,7 +871,7 @@ var Tabs = Module("tabs", { events: function () { let tabContainer = config.tabbrowser.mTabContainer; ["TabMove", "TabOpen", "TabClose"].forEach(function (event) { - events.addSessionListener(tabContainer, event, this.closure._updateTabCount, false); + events.addSessionListener(tabContainer, event, this.closure.updateTabCount, false); }, this); events.addSessionListener(tabContainer, "TabSelect", this.closure._onTabSelect, false); }, diff --git a/common/modules/base.jsm b/common/modules/base.jsm index 1a23ff67..0d37df49 100644 --- a/common/modules/base.jsm +++ b/common/modules/base.jsm @@ -10,7 +10,6 @@ if (!JSMLoader) globals: {}, stale: {}, load: function load(url, target) { - dump("dactyl: load: " + url + "\n"); if (this.stale[url]) { delete this.stale[url]; let global = this.globals[url]; @@ -26,7 +25,6 @@ if (!JSMLoader) Components.classes["@mozilla.org/moz/jssubscript-loader;1"] .getService(Components.interfaces.mozIJSSubScriptLoader) .loadSubScript(url, global); - dump("dactyl: load reloaded: " + url + "\n"); } Components.utils.import(url, target); }, @@ -296,7 +294,10 @@ function deprecated(reason, fn) { (obj ? obj + "." : "") + (fn.name || name) + " is deprecated: " + reason); return func.apply(this, arguments); } - deprecatedMethod.seen = { "chrome://dactyl/content/javascript.js": true }; + deprecatedMethod.seen = { + "chrome://dactyl/content/javascript.js": true, + "resource://dactyl/util.jsm": true + }; return callable(fn) ? deprecatedMethod : Class.Property({ get: function () deprecatedMethod, @@ -692,10 +693,11 @@ function update(target) { desc = desc.value.init(k) || desc.value; if (typeof desc.value == "function" && Object.getPrototypeOf(target)) { let func = desc.value; - desc.value.superapply = function (self, args) + desc.value.__defineGetter__("super", function () Object.getPrototypeOf(target)[k]); + desc.value.superapply = function superapply(self, args) let (meth = Object.getPrototypeOf(target)[k]) meth && meth.apply(self, args); - desc.value.supercall = function (self) + desc.value.supercall = function supercall(self) func.superapply(self, Array.slice(arguments, 1)); } Object.defineProperty(target, k, desc); diff --git a/common/modules/util.jsm b/common/modules/util.jsm index 7c4e2ca9..8c79e8cd 100644 --- a/common/modules/util.jsm +++ b/common/modules/util.jsm @@ -1020,6 +1020,27 @@ var Util = Module("Util", XPCOM([Ci.nsIObserver, Ci.nsISupportsWeakReference]), }), true); }, + overlayObject: function (object, overrides) { + let original = Object.create(object); + overrides = update(Object.create(original), overrides); + + for each (let k in Object.getOwnPropertyNames(overrides)) { + let orig, desc = Object.getOwnPropertyDescriptor(overrides, k); + if (desc.value instanceof Class.Property) + desc = desc.value.init(k) || desc.value; + + for (let obj = object; obj && !orig; obj = Object.getPrototypeOf(obj)) + if (orig = Object.getOwnPropertyDescriptor(obj, k)) + Object.defineProperty(original, k, orig); + + Object.defineProperty(object, k, desc); + } + return function unwrap() { + for each (let k in Object.getOwnPropertyNames(original)) + Object.defineProperty(object, k, Object.getOwnPropertyDescriptor(original, k)); + } + }, + overlayWindow: function (url, fn) { if (url instanceof Ci.nsIDOMWindow) util._loadOverlay(url, fn); diff --git a/common/skin/dactyl.css b/common/skin/dactyl.css index f145dacd..73945471 100644 --- a/common/skin/dactyl.css +++ b/common/skin/dactyl.css @@ -77,9 +77,9 @@ @-moz-document url-prefix(chrome://) { -.tab-icon-image, .tab-throbber { -moz-box-ordinal-group: 10; } -[dactyl|highlight~=tab-number] { -moz-box-ordinal-group: 20; } -.tab-text, .tab-label, .tab-close-button { -moz-box-ordinal-group: 50; } +#TabsToolbar .tab-icon-image, .tab-throbber { -moz-box-ordinal-group: 10; } +[dactyl|highlight~=tab-number] { -moz-box-ordinal-group: 20; } +.tab-text, .tab-label, .tab-close-button { -moz-box-ordinal-group: 50; } [dactyl|highlight~=Bell] { -moz-appearance: none !important; @@ -117,7 +117,7 @@ label[collapsed=true] { /* fixes the min-height: 22px from firefox */ statusbarpanel { -moz-appearance: none !important; - border: 0; + border: 0 !important; min-height: 18px !important; background: transparent; } diff --git a/pentadactyl/NEWS b/pentadactyl/NEWS index be34680f..6d42bd9b 100644 --- a/pentadactyl/NEWS +++ b/pentadactyl/NEWS @@ -26,6 +26,8 @@ backspace. - Supports reverse incremental search. - Input boxes are not focused when matches are highlighted. + * It's now possible to map keys in many more modes, including + Hint, Multi-line Output, and Menu. * Ex command parsing improvements, including: - Multiple Ex commands may now be separated by | - Commands can continue over multiple lines in RC files by @@ -49,6 +51,9 @@ * The concept of completion contexts is now exposed to the user (see :h :contexts), allowing for powerful and fine-grained completion system customization. + * The external editor can now be configured to open to a given + line number and column, used for opening source links and + editing input fields with . See 'editor'. * Command changes: - :viusage, :optionusage and :exusage were replaced with :listkeys, :listoptions and :listcommands, providing more powerful and @@ -63,8 +68,11 @@ - Added :feedkeys command. - Added -sort option to :history. - Added several new options, including -javascript, to :abbrev and :map. - - Added :mksyntax command. + - Added :mksyntax command to auto-generate Vim syntax files. - :open now only opens files beginning with /, ./, ../, or ~/ + - :saveas now provides completions for default file names, and + automatically chooses a filename when the save target is a + directory. - Added :write !cmd and :write >>file. - Added :yank command. * Improvements to :style and :highlight: @@ -74,8 +82,9 @@ - Active filters are not highlighted in :style listings. - :style-related commands now divide their completions between those active and inactive for the current site. - - CSS property name completion is not available. + - CSS property name completion is now available. * IMPORTANT option changes: + - Boolean options no longer accept an argument. - 'cdpath' and 'runtimepath' no longer treat ",," specially. Use "." instead. - 'incsearch', 'hlsearch', 'ignorecase', and 'smartcase' have