aboutsummaryrefslogtreecommitdiffstats
path: root/content_scripts
diff options
context:
space:
mode:
Diffstat (limited to 'content_scripts')
-rw-r--r--content_scripts/file_urls.css6
-rw-r--r--content_scripts/link_hints.coffee52
-rw-r--r--content_scripts/scroller.coffee26
-rw-r--r--content_scripts/vimium.css8
-rw-r--r--content_scripts/vimium_frontend.coffee29
-rw-r--r--content_scripts/vomnibar.coffee14
6 files changed, 88 insertions, 47 deletions
diff --git a/content_scripts/file_urls.css b/content_scripts/file_urls.css
new file mode 100644
index 00000000..fd63c224
--- /dev/null
+++ b/content_scripts/file_urls.css
@@ -0,0 +1,6 @@
+/* Chrome file:// URLs set draggable=true for links to files (CSS selector .icon.file). This automatically
+ * sets -webkit-user-select: none, which disables selecting the file names and so prevents Vimium's search
+ * from working as expected. Here, we reset the value back to default. */
+.icon.file {
+ -webkit-user-select: auto !important;
+}
diff --git a/content_scripts/link_hints.coffee b/content_scripts/link_hints.coffee
index f2479d0f..24314b26 100644
--- a/content_scripts/link_hints.coffee
+++ b/content_scripts/link_hints.coffee
@@ -9,7 +9,8 @@
# typing the text of the link itself.
#
OPEN_IN_CURRENT_TAB = {}
-OPEN_IN_NEW_TAB = {}
+OPEN_IN_NEW_BG_TAB = {}
+OPEN_IN_NEW_FG_TAB = {}
OPEN_WITH_QUEUE = {}
COPY_LINK_URL = {}
OPEN_INCOGNITO = {}
@@ -24,7 +25,8 @@ LinkHints =
delayMode: false
# Handle the link hinting marker generation and matching. Must be initialized after settings have been
# loaded, so that we can retrieve the option setting.
- markerMatcher: undefined
+ getMarkerMatcher: ->
+ if settings.get("filterLinkHints") then filterHints else alphabetHints
# lock to ensure only one instance runs at a time
isActive: false
@@ -32,7 +34,6 @@ LinkHints =
# To be called after linkHints has been generated from linkHintsBase.
#
init: ->
- @markerMatcher = if settings.get("filterLinkHints") then filterHints else alphabetHints
#
# Generate an XPath describing what a clickable element is.
@@ -46,7 +47,8 @@ LinkHints =
"@contenteditable='' or translate(@contenteditable, 'TRUE', 'true')='true']"])
# We need this as a top-level function because our command system doesn't yet support arguments.
- activateModeToOpenInNewTab: -> @activateMode(OPEN_IN_NEW_TAB)
+ activateModeToOpenInNewTab: -> @activateMode(OPEN_IN_NEW_BG_TAB)
+ activateModeToOpenInNewForegroundTab: -> @activateMode(OPEN_IN_NEW_FG_TAB)
activateModeToCopyLinkUrl: -> @activateMode(COPY_LINK_URL)
activateModeWithQueue: -> @activateMode(OPEN_WITH_QUEUE)
activateModeToOpenIncognito: -> @activateMode(OPEN_INCOGNITO)
@@ -60,7 +62,8 @@ LinkHints =
@isActive = true
@setOpenLinkMode(mode)
- hintMarkers = @markerMatcher.fillInMarkers(@createMarkerFor(el) for el in @getVisibleClickableElements())
+ hintMarkers = (@createMarkerFor(el) for el in @getVisibleClickableElements())
+ @getMarkerMatcher().fillInMarkers(hintMarkers)
# Note(philc): Append these markers as top level children instead of as child nodes to the link itself,
# because some clickable elements cannot contain children, e.g. submit buttons. This has the caveat
@@ -77,15 +80,18 @@ LinkHints =
})
setOpenLinkMode: (@mode) ->
- if @mode is OPEN_IN_NEW_TAB or @mode is OPEN_WITH_QUEUE
- if @mode is OPEN_IN_NEW_TAB
+ if @mode is OPEN_IN_NEW_BG_TAB or @mode is OPEN_IN_NEW_FG_TAB or @mode is OPEN_WITH_QUEUE
+ if @mode is OPEN_IN_NEW_BG_TAB
HUD.show("Open link in new tab")
+ else if @mode is OPEN_IN_NEW_FG_TAB
+ HUD.show("Open link in new tab and switch to it")
else
HUD.show("Open multiple links in a new tab")
@linkActivator = (link) ->
# When "clicking" on a link, dispatch the event with the appropriate meta key (CMD on Mac, CTRL on
# windows) to open it in a new tab if necessary.
DomUtils.simulateClick(link, {
+ shiftKey: @mode is OPEN_IN_NEW_FG_TAB,
metaKey: KeyboardUtils.platform == "Mac",
ctrlKey: KeyboardUtils.platform != "Mac" })
else if @mode is COPY_LINK_URL
@@ -101,9 +107,7 @@ LinkHints =
url: link.href)
else # OPEN_IN_CURRENT_TAB
HUD.show("Open link in current tab")
- # When we're opening the link in the current tab, don't navigate to the selected link immediately
- # we want to give the user some time to notice which link has received focus.
- @linkActivator = (link) -> setTimeout(DomUtils.simulateClick.bind(DomUtils, link), 400)
+ @linkActivator = (link) -> DomUtils.simulateClick.bind(DomUtils, link)()
#
# Creates a link marker for the given link.
@@ -161,29 +165,29 @@ LinkHints =
visibleElements
#
- # Handles shift and esc keys. The other keys are passed to markerMatcher.matchHintsByKey.
+ # Handles shift and esc keys. The other keys are passed to getMarkerMatcher().matchHintsByKey.
#
onKeyDownInMode: (hintMarkers, event) ->
return if @delayMode
- if (event.keyCode == keyCodes.shiftKey && @mode != COPY_LINK_URL)
+ if ((event.keyCode == keyCodes.shiftKey or event.keyCode == keyCodes.ctrlKey) and
+ (@mode == OPEN_IN_CURRENT_TAB or
+ @mode == OPEN_IN_NEW_BG_TAB or
+ @mode == OPEN_IN_NEW_FG_TAB))
# Toggle whether to open link in a new or current tab.
prev_mode = @mode
- @setOpenLinkMode(if @mode is OPEN_IN_CURRENT_TAB then OPEN_IN_NEW_TAB else OPEN_IN_CURRENT_TAB)
+ if event.keyCode == keyCodes.shiftKey
+ @setOpenLinkMode(if @mode is OPEN_IN_CURRENT_TAB then OPEN_IN_NEW_BG_TAB else OPEN_IN_CURRENT_TAB)
- handlerStack.push({
- keyup: (event) =>
- return if (event.keyCode != keyCodes.shiftKey)
- @setOpenLinkMode(prev_mode) if @isActive
- @remove()
- })
+ else # event.keyCode == keyCodes.ctrlKey
+ @setOpenLinkMode(if @mode is OPEN_IN_NEW_FG_TAB then OPEN_IN_NEW_BG_TAB else OPEN_IN_NEW_FG_TAB)
# TODO(philc): Ignore keys that have modifiers.
if (KeyboardUtils.isEscape(event))
@deactivateMode()
- else if (event.keyCode != keyCodes.shiftKey)
- keyResult = @markerMatcher.matchHintsByKey(hintMarkers, event)
+ else
+ keyResult = @getMarkerMatcher().matchHintsByKey(hintMarkers, event)
linksMatched = keyResult.linksMatched
delay = keyResult.delay ? 0
if (linksMatched.length == 0)
@@ -194,7 +198,7 @@ LinkHints =
for marker in hintMarkers
@hideMarker(marker)
for matched in linksMatched
- @showMarker(matched, @markerMatcher.hintKeystrokeQueue.length)
+ @showMarker(matched, @getMarkerMatcher().hintKeystrokeQueue.length)
false # We've handled this key, so prevent propagation.
#
@@ -239,8 +243,8 @@ LinkHints =
#
deactivateMode: (delay, callback) ->
deactivate = =>
- if (LinkHints.markerMatcher.deactivate)
- LinkHints.markerMatcher.deactivate()
+ if (LinkHints.getMarkerMatcher().deactivate)
+ LinkHints.getMarkerMatcher().deactivate()
if (LinkHints.hintMarkerContainingDiv)
DomUtils.removeElement LinkHints.hintMarkerContainingDiv
LinkHints.hintMarkerContainingDiv = null
diff --git a/content_scripts/scroller.coffee b/content_scripts/scroller.coffee
index 08ab14a1..f3c632b3 100644
--- a/content_scripts/scroller.coffee
+++ b/content_scripts/scroller.coffee
@@ -39,17 +39,17 @@ ensureScrollChange = (direction, changeFn) ->
loop
oldScrollValue = element[axisName]
changeFn(element, axisName)
+ break unless (element[axisName] == oldScrollValue && element != document.body)
lastElement = element
# we may have an orphaned element. if so, just scroll the body element.
element = element.parentElement || document.body
- break unless (lastElement[axisName] == oldScrollValue && lastElement != document.body)
# if the activated element has been scrolled completely offscreen, subsequent changes in its scroll
# position will not provide any more visual feedback to the user. therefore we deactivate it so that
# subsequent scrolls only move the parent element.
rect = activatedElement.getBoundingClientRect()
if (rect.bottom < 0 || rect.top > window.innerHeight || rect.right < 0 || rect.left > window.innerWidth)
- activatedElement = lastElement
+ activatedElement = element
# scroll the active element in :direction by :amount * :factor.
# :factor is needed because :amount can take on string values, which scrollBy converts to element dimensions.
@@ -65,12 +65,13 @@ root.scrollBy = (direction, amount, factor = 1) ->
if (!activatedElement || !isRendered(activatedElement))
activatedElement = document.body
- amount = getDimension activatedElement, direction, amount if Utils.isString amount
-
- amount *= factor
-
- if (amount != 0)
- ensureScrollChange direction, (element, axisName) -> element[axisName] += amount
+ ensureScrollChange direction, (element, axisName) ->
+ if Utils.isString amount
+ elementAmount = getDimension element, direction, amount
+ else
+ elementAmount = amount
+ elementAmount *= factor
+ element[axisName] += elementAmount
root.scrollTo = (direction, pos) ->
return unless document.body
@@ -78,9 +79,12 @@ root.scrollTo = (direction, pos) ->
if (!activatedElement || !isRendered(activatedElement))
activatedElement = document.body
- pos = getDimension activatedElement, direction, pos if Utils.isString pos
-
- ensureScrollChange direction, (element, axisName) -> element[axisName] = pos
+ ensureScrollChange direction, (element, axisName) ->
+ if Utils.isString pos
+ elementPos = getDimension element, direction, pos
+ else
+ elementPos = pos
+ element[axisName] = elementPos
# TODO refactor and put this together with the code in getVisibleClientRect
isRendered = (element) ->
diff --git a/content_scripts/vimium.css b/content_scripts/vimium.css
index ccbcb339..a63fc3a5 100644
--- a/content_scripts/vimium.css
+++ b/content_scripts/vimium.css
@@ -175,14 +175,14 @@ div#vimiumHelpDialog div.advanced { display: none; }
div#vimiumHelpDialog div.advanced td:nth-of-type(3) { color: #555; }
div#vimiumHelpDialog a.closeButton {
position:absolute;
- right:10px;
+ right:7px;
top:5px;
font-family:"courier new";
font-weight:bold;
color:#555;
text-decoration:none;
padding-left:10px;
- font-size:16px;
+ font-size:20px;
}
div#vimiumHelpDialog a {
text-decoration: underline;
@@ -296,6 +296,8 @@ body.vimiumFindMode ::selection {
}
#vomnibar input {
+ color: #000;
+ font-family: 'Helvetica Neue', Helvetica, Arial, sans-serif;
font-size: 20px;
height: 34px;
margin-bottom: 0;
@@ -332,6 +334,8 @@ body.vimiumFindMode ::selection {
font-size: 16px;
color: black;
position: relative;
+ display: list-item;
+ margin: auto;
}
#vomnibar li:last-of-type {
diff --git a/content_scripts/vimium_frontend.coffee b/content_scripts/vimium_frontend.coffee
index a2139df6..896253a6 100644
--- a/content_scripts/vimium_frontend.coffee
+++ b/content_scripts/vimium_frontend.coffee
@@ -8,7 +8,7 @@ window.handlerStack = new HandlerStack
insertModeLock = null
findMode = false
-findModeQuery = { rawQuery: "" }
+findModeQuery = { rawQuery: "", matchCount: 0 }
findModeQueryHasResults = false
findModeAnchorNode = null
isShowingHelpDialog = false
@@ -554,6 +554,18 @@ updateFindModeQuery = ->
text = document.body.innerText
findModeQuery.regexMatches = text.match(pattern)
findModeQuery.activeRegexIndex = 0
+ findModeQuery.matchCount = findModeQuery.regexMatches?.length
+ # if we are doing a basic plain string match, we still want to grep for matches of the string, so we can
+ # show a the number of results. We can grep on document.body.innerText, as it should be indistinguishable
+ # from the internal representation used by window.find.
+ else
+ # escape all special characters, so RegExp just parses the string 'as is'.
+ # Taken from http://stackoverflow.com/questions/3446170/escape-string-for-use-in-javascript-regex
+ escapeRegExp = /[\-\[\]\/\{\}\(\)\*\+\?\.\\\^\$\|]/g
+ parsedNonRegexQuery = findModeQuery.parsedQuery.replace(escapeRegExp, (char) -> "\\" + char)
+ pattern = new RegExp(parsedNonRegexQuery, "g" + (if findModeQuery.ignoreCase then "i" else ""))
+ text = document.body.innerText
+ findModeQuery.matchCount = text.match(pattern)?.length
handleKeyCharForFindMode = (keyChar) ->
findModeQuery.rawQuery += keyChar
@@ -799,7 +811,7 @@ findAndFollowRel = (value) ->
for tag in relTags
elements = document.getElementsByTagName(tag)
for element in elements
- if (element.hasAttribute("rel") && element.rel == value)
+ if (element.hasAttribute("rel") && element.rel.toLowerCase() == value)
followLink(element)
return true
@@ -815,7 +827,7 @@ window.goNext = ->
showFindModeHUDForQuery = ->
if (findModeQueryHasResults || findModeQuery.parsedQuery.length == 0)
- HUD.show("/" + findModeQuery.rawQuery)
+ HUD.show("/" + findModeQuery.rawQuery + " (" + findModeQuery.matchCount + " Matches)")
else
HUD.show("/" + findModeQuery.rawQuery + " (No Matches)")
@@ -839,7 +851,7 @@ window.showHelpDialog = (html, fid) ->
container.innerHTML = html
container.getElementsByClassName("closeButton")[0].addEventListener("click", hideHelpDialog, false)
-
+
VimiumHelpDialog =
# This setting is pulled out of local storage. It's false by default.
getShowAdvancedCommands: -> settings.get("helpDialog_showAdvancedCommands")
@@ -869,8 +881,9 @@ window.showHelpDialog = (html, fid) ->
VimiumHelpDialog.init()
- container.getElementsByClassName("optionsPage")[0].addEventListener("click",
- -> chrome.runtime.sendMessage({ handler: "openOptionsPageInNewTab" })
+ container.getElementsByClassName("optionsPage")[0].addEventListener("click", (clickEvent) ->
+ clickEvent.preventDefault()
+ chrome.runtime.sendMessage({handler: "openOptionsPageInNewTab"})
false)
@@ -908,7 +921,7 @@ HUD =
show: (text) ->
return unless HUD.enabled()
clearTimeout(HUD._showForDurationTimerId)
- HUD.displayElement().innerHTML = text
+ HUD.displayElement().innerText = text
clearInterval(HUD._tweenId)
HUD._tweenId = Tween.fade(HUD.displayElement(), 1.0, 150)
HUD.displayElement().style.display = ""
@@ -917,7 +930,7 @@ HUD =
HUD.upgradeNotificationElement().innerHTML = "Vimium has been updated to
<a class='vimiumReset'
href='https://chrome.google.com/extensions/detail/dbepggeogbaibhgnhhndojpepiihcmeb'>
- #{version}</a>.<a class='vimiumReset close-button' href='#'>x</a>"
+ #{version}</a>.<a class='vimiumReset close-button' href='#'>&times;</a>"
links = HUD.upgradeNotificationElement().getElementsByTagName("a")
links[0].addEventListener("click", HUD.onUpdateLinkClicked, false)
links[1].addEventListener "click", (event) ->
diff --git a/content_scripts/vomnibar.coffee b/content_scripts/vomnibar.coffee
index 6782ab28..6997d387 100644
--- a/content_scripts/vomnibar.coffee
+++ b/content_scripts/vomnibar.coffee
@@ -68,8 +68,18 @@ class VomnibarUI
@update(true)
updateSelection: ->
+ # We have taken the option to add some global state here (previousCompletionType) to tell if a search
+ # item has just appeared or disappeared, if that happens we either set the initialSelectionValue to 0 or 1
+ # I feel that this approach is cleaner than bubbling the state up from the suggestion level
+ # so we just inspect it afterwards
+ if @completions[0]
+ if @previousCompletionType != "search" && @completions[0].type == "search"
+ @selection = 0
+ else if @previousCompletionType == "search" && @completions[0].type != "search"
+ @selection = -1
for i in [0...@completionList.children.length]
@completionList.children[i].className = (if i == @selection then "vomnibarSelected" else "")
+ @previousCompletionType = @completions[0].type if @completions[0]
#
# Returns the user's action ("up", "down", "enter", "dismiss" or null) based on their keypress.
@@ -192,8 +202,8 @@ class BackgroundCompleter
filter: (query, callback) ->
id = Utils.createUniqueId()
- @filterPort.onMessage.addListener (msg) ->
- return if (msg.id != id)
+ @filterPort.onMessage.addListener (msg) =>
+ @filterPort.onMessage.removeListener(arguments.callee)
# The result objects coming from the background page will be of the form:
# { html: "", type: "", url: "" }
# type will be one of [tab, bookmark, history, domain].