Simon Lydell [Mon, 11 Jan 2016 18:32:02 +0000 (19:32 +0100)]
Fix memory leak in non-multi-process Firefox
Apparently, 'overflow' and 'underflow' events in web page content can be caught
in UI listeners in non-multi-process. `event.target` of 'overflow' events in the
browser UI are saved as scrollable elements, which accidentaly included web page
elements as well. Holding on to such elements after their owner tab is closed
caused a memory leak (ghost windows). This commit checks that the overflown
elements really are UI elements before saving them.
Simon Lydell [Sat, 9 Jan 2016 16:39:07 +0000 (17:39 +0100)]
Fix `:hover` clearing on click in multi-process
Because clicks simulated by VimFx apparently cannot be caught in non-frame
listeners (which is good), _two_ real clicks were needed to clear `:hover`. This
commit fixes that, which allowed for a nice code cleanup. Instead, a temporary
hack is used for non-multi-process to make it work there.
Simon Lydell [Wed, 6 Jan 2016 13:22:25 +0000 (14:22 +0100)]
Lock `:hover` when clicking with the `f` commands
Fixes #388.
Note that this commit also adds `pointer-evets: none;` to the hints container,
allowing to generate hints for elements only visible because of the mouse
pointer hovering something. Getting hints for hover-menus opened by `zf` but not
for hover-menus opened by moving the mouse was too confusing. The reason
`pointer-events: none;` wasn’t added before was that it prevented from scrolling
while hints were shown. While that was nice, it was just an edge case that
doesn't really matter. It is better to allow hints for hover-menus.
Simon Lydell [Wed, 6 Jan 2016 09:40:50 +0000 (10:40 +0100)]
Improve element matching for the `zF` command
- Always exclude `<menuitem>`s. They are never clickable by VimFx. (This could
be seen in the Responsive Design View).
- Oddly, `<menuseparator>`s are considered focusable, but of course shouldn't
get hints. Now they don't anymore.
- Make sure that browser elements in the web page content area (such as in the
Responsive Design View) only show up when their containing tab is selected.
Simon Lydell [Wed, 30 Dec 2015 15:43:26 +0000 (16:43 +0100)]
Make 'frameCanReceiveEvents' more robust
Instead of using a combination of `.readyState in ['interactive', 'complete']`
and the 'DOMWindowCreated' event, only set 'frameCanReceiveEvents' to `true`
when `.readyState == 'complete'`. Also, set it to `false` on the 'pagehide'
event. This simplifies things a bit, and hopefully makes VimFx more responsive
on slowly-loading pages. See #588.
Simon Lydell [Mon, 21 Dec 2015 07:16:00 +0000 (08:16 +0100)]
Treat contenteditable elements as other text inputs
This lets `gi` focus contenteditable elements, which are often indistinguishable
from `<input>`s and `<textarea>`. It also allowed for some nice code cleanup.
Simon Lydell [Wed, 9 Dec 2015 16:45:05 +0000 (17:45 +0100)]
Reset typed keys in "autoInsertMode"
Previously, if you typed for example a 'g' in a text input, click
outside it to unfocus, and then tried to use the `/` command, `g/` would be
triggered instead.
Simon Lydell [Tue, 8 Dec 2015 18:36:31 +0000 (19:36 +0100)]
Make it possible to scroll browser elements
The dev tools can contain scrollbars. This commit makes it possible to focus
such scrollable elements with `zF` and then scroll them using all of VimFx's
scrolling commands.
Simon Lydell [Sun, 6 Dec 2015 16:50:32 +0000 (17:50 +0100)]
Add command to click browser elements using markers
Fixes #236.
A note about the "hamburger menu" in the top-right corner:
It is possible to _open_ it with `zF`, but not possible to use `zF` inside of
it, because of `@popupPassthrough`. One _could_ an exception for that
menu/popup, but that doesn't help:
- `.elementFromPoint()` does not appear to find elements in popups, making it
difficult to determine if the buttons inside are visible or not.
- The markers appear _behind_ the popup, no matter what `z-index` is used.
- The popup seems to eat `<escape>`: When it is pressed, the popup is closed,
but the markers remain. The next `<escape>` press removes the markers. Not a
big deal, but slightly annoying.
Therefore I decided not to add support for that menu in this commit. (Perhaps
we'll be able to do that some time in the future.) Instead, I recommend using
the alt key shortcuts for the "regular" menubar.
Simon Lydell [Tue, 8 Dec 2015 19:43:51 +0000 (20:43 +0100)]
Remove try-catch in UI 'keydown' listener
Firefox unfortunately doesn't show the stack trace in its error consoles. Still,
there is one available on thrown `error` objects. That's why the try-catch used
to be there: To also show the stack trace. Wrapping the 'keydown' listener was a
good choice because most things happen on keydown in VimFx. However, since the
switch to multi-process Firefox, this is less useful. Most keys are captured in
frame script 'keydown' handlers, not in the UI, so the try-catch didn't do much.
One _could_ place the try-catch somewhere else instead, but now it's harder to
find a good place. Besides, I've not really missed the stack trace for the last
couple of months. The file name and line number is still reported which is good
enough.
Simon Lydell [Sun, 6 Dec 2015 14:53:18 +0000 (15:53 +0100)]
Add notifications to many commands
If nothing happens when activating a command, a notification is shown instead,
making it obvious that you actually triggered the command and didn't press the
wrong keys.
Simon Lydell [Fri, 4 Dec 2015 19:37:10 +0000 (20:37 +0100)]
Improve `gi` text selection
Before you have focused a text input (a prevented autofocus does _not_ count),
`gi` now selects all text in the text input it focuses (before, it only did so
for inputs that had autofocus prevented). The reason is that many sites prefill
search boxes with your query on search results pages. Then it’s nice if `gi`
selects all the text, letting you quickly replace it.
Simon Lydell [Fri, 4 Dec 2015 07:12:02 +0000 (08:12 +0100)]
Fix scrolling of `<html>` if `<body>` is scrollable
`document.activeElement` is never `null`. If no element if focused, it is
`document.body`. If `document.body` is scrollable, it means that `<html>` can
never be scrolled.
This commit only allows to scroll `<body>` if it has been explicitly focused (or
if it is the largest scrollable element, of course).
Simon Lydell [Thu, 3 Dec 2015 07:20:43 +0000 (08:20 +0100)]
Fix text selection when forusing text inputs
When using one of the `f` commands to focus a text input, the previous selection
or caret position should be retained, just as if you had clicked it. However,
before this commit all of their text was accidentally selected (as if you had
pressed `<tab>` to foucs).
This also improves the `gi` command. Previously, it _always_ selected all text.
Now it does so only if you use a count, or use `gi` to re-focus an input after a
prevented autofocus. In those cases you likely want to replace what's in the
input, but otherwise you're likely returning to the text input after a temporary
leave and want to continue typing where you left off.
Simon Lydell [Wed, 2 Dec 2015 06:37:53 +0000 (07:37 +0100)]
Fix some links not being targeted by `F`, `gf` and `gF`
In commit af0c4a07, links with an 'onclick' attribute stopped being considered
as "proper". The reason was to prevent such links from getting the same hint as
other links with the same href, because the 'onclick' likely makes all those
links behave differently.
However, on startpage.com the search result links actually are "proper" links,
but also have 'onclick' attributes and since that caused them not to be
considered as proper, they did not get hints when using `F`, `gf` and `gF`
commands.
This commit considers links with 'onclick' as proper again, and only excludes
them from getting the same hint as other links.
Simon Lydell [Mon, 30 Nov 2015 13:57:34 +0000 (14:57 +0100)]
Add window commands
- `w`: Open new window.
- `W`: Open new private window.
- `gw`: Move tab to new window.
- `gF`: Follow link in new window.
Fixes #402.
In #402 two more commands were discussed:
- `q`: Close window. Can easily make more harm than good. Also, why learn a
Firefox-specific shortcut to close a window, when you can use an OS-wide
shortcut?
- `Q`: Suggested only for symmetry with `x` and `X`. YAGNI.
Simon Lydell [Thu, 26 Nov 2015 09:51:41 +0000 (10:51 +0100)]
Rework "move tab to window" detection logic
The old detection was too unreliable and didn't catch all cases.
Also fixes a bug where the blacklist wasn't applied when going back or forward
in history to a blacklisted URL.
The long story:
If you move a tab into another window in multi-process, the frame script for the
web page of the tab is kept. That is good, since all state (such as scrollable
elements) is preserved.
In non-multi-process, that is not the case. A new frame script is loaded, so all
state is lost. That is unfortunate, but there's nothing we can do about it. In
non-multi-process, moving a tab to another window then works a bit like closing
the tab and opening a new one in the target winow with the same URL: All VimFx
state is lost, including the current mode. The blacklist is applied. However,
the web page content is the same, with DOM modifications and scroll position
preserved. This is not ideal for VimFx, but OK. Non-multi-process will be
dropped from Firefox not too far into the future anyway.
Let's focus on multi-process instead.
That no new frame script is loaded for the "new" (dragged) tab in the target
window has some interesting consequences. For example, `vim` objects for tabs
are created based on a frame script being loaded. Does this mean that no `vim`
object is created for this tab? It depends.
When a new tab is opened, Firefox might load a frame script for `about:blank`.
When the real web page starts loading, a new frame script is loaded.
The above can depend on whether you're moving (dragging) a tab to another
existing window, or moving a tab to an entirely new window (by right-clicking a
tab and choosing “Move to New Window” or dragging a tab and dropping it outside
a tab bar).
If a frame script for `about:blank` _is_ loaded, a `vim` object is created.
However, Firefox then moves over the web page from the old tab, and replaces the
`.messageManager` of the new tab’s `<browser>`! This means that the `vim` object
cannot receive messages from the just-moved-over web page (coming from the frame
script that was kept from the origin window, as mentioned earlier), because it
has attached its listeners to a message manager object that no longer exists.
In both cases it means that VimFx won't work correctly in those tabs. Therefore,
we need to detect tabs moved to other windows.
There does not seem to be any straight-forward way of detecting that, though.
However, we can abuse the fact the `vim` objects for those tabs will either be
missing or have the wrong `._messageManager` as a way of detecting it anyway.
(Since that isn't the case in non-multi-process, that's why we can't detect it
there.)
After having moved a tab to another window, the web page of the tab loads from
cache. This triggers a 'pageshow' event with `event.persisted === true`, just
like when navigating forward and backward in history. When this happens, the
frame scripts send a message to the UI process, which is caught at window level.
If there's no `vim` object for the `<browser>` that the message came from, or if
`vim._messageManager` is out of date, we know that the tab for the `<browser>`
element has just been moved to another window!
In that case, we want to find the `vim` object for the closed tab in the origin
window (the one that we started dragging, for example) and re-use it for the
"new" tab, in order to keep the current mode etc.
That is done be saving the `vim` object of the last closed tab, by listening for
the 'TabClose' event. It fires before the new tab in the target window is
created.
The whole process is very ugly and a bit complicated, but there's seems to be no
other way, and it does the job: Things work acceptably in non-multi-process and
(seemingly) perfectly in multi-process.