diff options
Diffstat (limited to 'content_scripts/vimium_frontend.coffee')
| -rw-r--r-- | content_scripts/vimium_frontend.coffee | 292 | 
1 files changed, 17 insertions, 275 deletions
| diff --git a/content_scripts/vimium_frontend.coffee b/content_scripts/vimium_frontend.coffee index bffbd457..9d850419 100644 --- a/content_scripts/vimium_frontend.coffee +++ b/content_scripts/vimium_frontend.coffee @@ -5,10 +5,6 @@  # "domReady".  # -findModeQuery = { rawQuery: "", matchCount: 0 } -findModeQueryHasResults = false -findModeAnchorNode = null -findModeInitialRange = null  isShowingHelpDialog = false  keyPort = null  isEnabledForUrl = true @@ -433,7 +429,7 @@ extend window,                  hints[selectedInputIndex].classList.add 'internalVimiumSelectedInputHint'                  # Deactivate any active modes on this element (PostFindMode, or a suspended edit mode).                  @deactivateSingleton visibleInputs[selectedInputIndex].element -                visibleInputs[selectedInputIndex].element.focus() +                DomUtils.simulateSelect visibleInputs[selectedInputIndex].element                  @suppressEvent                else unless event.keyCode == KeyboardUtils.keyCodes.shiftKey                  @exit() @@ -446,7 +442,7 @@ extend window,            # Deactivate any active modes on this element (PostFindMode, or a suspended edit mode).            @deactivateSingleton visibleInputs[selectedInputIndex].element -          visibleInputs[selectedInputIndex].element.focus() +          DomUtils.simulateSelect visibleInputs[selectedInputIndex].element            if visibleInputs.length == 1              @exit()              return @@ -622,108 +618,7 @@ window.refreshCompletionKeys = (response) ->  isValidFirstKey = (keyChar) ->    validFirstKeys[keyChar] || /^[1-9]/.test(keyChar) -# This implements find-mode query history (using the "findModeRawQueryList" setting) as a list of raw queries, -# most recent first. -FindModeHistory = -  storage: chrome.storage.local -  key: "findModeRawQueryList" -  max: 50 -  rawQueryList: null - -  init: -> -    unless @rawQueryList -      @rawQueryList = [] # Prevent repeated initialization. -      @key = "findModeRawQueryListIncognito" if isIncognitoMode -      @storage.get @key, (items) => -        unless chrome.runtime.lastError -          @rawQueryList = items[@key] if items[@key] -          if isIncognitoMode and not items[@key] -            # This is the first incognito tab, so we need to initialize the incognito-mode query history. -            @storage.get "findModeRawQueryList", (items) => -              unless chrome.runtime.lastError -                @rawQueryList = items.findModeRawQueryList -                @storage.set findModeRawQueryListIncognito: @rawQueryList - -    chrome.storage.onChanged.addListener (changes, area) => -      @rawQueryList = changes[@key].newValue if changes[@key] - -  getQuery: (index = 0) -> -    @rawQueryList[index] or "" - -  saveQuery: (query) -> -    if 0 < query.length -      @rawQueryList = @refreshRawQueryList query, @rawQueryList -      newSetting = {}; newSetting[@key] = @rawQueryList -      @storage.set newSetting -      # If there are any active incognito-mode tabs, then propagte this query to those tabs too. -      unless isIncognitoMode -        @storage.get "findModeRawQueryListIncognito", (items) => -          if not chrome.runtime.lastError and items.findModeRawQueryListIncognito -            @storage.set -              findModeRawQueryListIncognito: @refreshRawQueryList query, items.findModeRawQueryListIncognito - -  refreshRawQueryList: (query, rawQueryList) -> -    ([ query ].concat rawQueryList.filter (q) => q != query)[0..@max] - -# should be called whenever rawQuery is modified. -updateFindModeQuery = -> -  # the query can be treated differently (e.g. as a plain string versus regex depending on the presence of -  # escape sequences. '\' is the escape character and needs to be escaped itself to be used as a normal -  # character. here we grep for the relevant escape sequences. -  findModeQuery.isRegex = Settings.get 'regexFindMode' -  hasNoIgnoreCaseFlag = false -  findModeQuery.parsedQuery = findModeQuery.rawQuery.replace /(\\{1,2})([rRI]?)/g, (match, slashes, flag) -> -    return match if flag == "" or slashes.length != 1 -    switch (flag) -      when "r" -        findModeQuery.isRegex = true -      when "R" -        findModeQuery.isRegex = false -      when "I" -        hasNoIgnoreCaseFlag = true -    "" - -  # default to 'smartcase' mode, unless noIgnoreCase is explicitly specified -  findModeQuery.ignoreCase = !hasNoIgnoreCaseFlag && !Utils.hasUpperCase(findModeQuery.parsedQuery) - -  # Don't count matches in the HUD. -  HUD.hide(true) - -  # if we are dealing with a regex, grep for all matches in the text, and then call window.find() on them -  # sequentially so the browser handles the scrolling / text selection. -  if findModeQuery.isRegex -    try -      pattern = new RegExp(findModeQuery.parsedQuery, "g" + (if findModeQuery.ignoreCase then "i" else "")) -    catch error -      # if we catch a SyntaxError, assume the user is not done typing yet and return quietly -      return -    # innerText will not return the text of hidden elements, and strip out tags while preserving newlines -    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 - -updateQueryForFindMode = (rawQuery) -> -  findModeQuery.rawQuery = rawQuery -  updateFindModeQuery() -  performFindInPlace() -  showFindModeHUDForQuery() - -handleKeyCharForFindMode = (keyChar) -> -  updateQueryForFindMode findModeQuery.rawQuery + keyChar - -handleEscapeForFindMode = -> +window.handleEscapeForFindMode = ->    document.body.classList.remove("vimiumFindMode")    # removing the class does not re-color existing selections. we recreate the current selection so it reverts    # back to the default color. @@ -734,158 +629,38 @@ handleEscapeForFindMode = ->      window.getSelection().addRange(range)    focusFoundLink() || selectFoundInputElement() -# Return true if character deleted, false otherwise. -handleDeleteForFindMode = -> -  if findModeQuery.rawQuery.length == 0 -    HUD.hide() -    false -  else -    updateQueryForFindMode findModeQuery.rawQuery.substring(0, findModeQuery.rawQuery.length - 1) -    true -  # <esc> sends us into insert mode if possible, but <cr> does not.  # <esc> corresponds approximately to 'nevermind, I have found it already' while <cr> means 'I want to save  # this query and do more searches with it' -handleEnterForFindMode = -> +window.handleEnterForFindMode = ->    focusFoundLink()    document.body.classList.add("vimiumFindMode") -  FindModeHistory.saveQuery findModeQuery.rawQuery - -class FindMode extends Mode -  constructor: (options = {}) -> -    @historyIndex = -1 -    @partialQuery = "" -    if options.returnToViewport -      @scrollX = window.scrollX -      @scrollY = window.scrollY -    super -      name: "find" -      indicator: false -      exitOnEscape: true -      exitOnClick: true - -      keydown: (event) => -        window.scrollTo @scrollX, @scrollY if options.returnToViewport -        if event.keyCode == keyCodes.backspace || event.keyCode == keyCodes.deleteKey -          @exit() unless handleDeleteForFindMode() -          @suppressEvent -        else if event.keyCode == keyCodes.enter -          handleEnterForFindMode() -          @exit() -          @suppressEvent -        else if event.keyCode == keyCodes.upArrow -          if rawQuery = FindModeHistory.getQuery @historyIndex + 1 -            @historyIndex += 1 -            @partialQuery = findModeQuery.rawQuery if @historyIndex == 0 -            updateQueryForFindMode rawQuery -          @suppressEvent -        else if event.keyCode == keyCodes.downArrow -          @historyIndex = Math.max -1, @historyIndex - 1 -          rawQuery = if 0 <= @historyIndex then FindModeHistory.getQuery @historyIndex else @partialQuery -          updateQueryForFindMode rawQuery -          @suppressEvent -        else -          DomUtils.suppressPropagation(event) -          handlerStack.stopBubblingAndFalse - -      keypress: (event) => -        handlerStack.neverContinueBubbling => -          if event.keyCode > 31 -            keyChar = String.fromCharCode event.charCode -            handleKeyCharForFindMode keyChar if keyChar - -      keyup: (event) => @suppressEvent - -  exit: (event) -> -    super() -    handleEscapeForFindMode() if event?.type == "keydown" and KeyboardUtils.isEscape event -    handleEscapeForFindMode() if event?.type == "click" -    if findModeQueryHasResults and event?.type != "click" -      new PostFindMode - -performFindInPlace = -> -  # Restore the selection.  That way, we're always searching forward from the same place, so we find the right -  # match as the user adds matching characters, or removes previously-matched characters. See #1434. -  findModeRestoreSelection() -  query = if findModeQuery.isRegex then getNextQueryFromRegexMatches(0) else findModeQuery.parsedQuery -  findModeQueryHasResults = executeFind(query, { caseSensitive: !findModeQuery.ignoreCase }) - -# :options is an optional dict. valid parameters are 'caseSensitive' and 'backwards'. -executeFind = (query, options) -> -  result = null -  options = options || {} - -  document.body.classList.add("vimiumFindMode") - -  # ignore the selectionchange event generated by find() -  document.removeEventListener("selectionchange",restoreDefaultSelectionHighlight, true) -  result = window.find(query, options.caseSensitive, options.backwards, true, false, true, false) -  setTimeout( -    -> document.addEventListener("selectionchange", restoreDefaultSelectionHighlight, true) -    0) - -  # We are either in normal mode ("n"), or find mode ("/").  We are not in insert mode.  Nevertheless, if a -  # previous find landed in an editable element, then that element may still be activated.  In this case, we -  # don't want to leave it behind (see #1412). -  if document.activeElement and DomUtils.isEditable document.activeElement -    document.activeElement.blur() unless DomUtils.isSelected document.activeElement - -  # we need to save the anchor node here because <esc> seems to nullify it, regardless of whether we do -  # preventDefault() -  findModeAnchorNode = document.getSelection().anchorNode -  result - -restoreDefaultSelectionHighlight = -> document.body.classList.remove("vimiumFindMode") +  FindMode.saveQuery()  focusFoundLink = -> -  if (findModeQueryHasResults) +  if (FindMode.query.hasResults)      link = getLinkFromSelection()      link.focus() if link  selectFoundInputElement = -> -  # if the found text is in an input element, getSelection().anchorNode will be null, so we use activeElement -  # instead. however, since the last focused element might not be the one currently pointed to by find (e.g. -  # the current one might be disabled and therefore unable to receive focus), we use the approximate -  # heuristic of checking that the last anchor node is an ancestor of our element. -  if (findModeQueryHasResults && document.activeElement && +  # Since the last focused element might not be the one currently pointed to by find (e.g.  the current one +  # might be disabled and therefore unable to receive focus), we use the approximate heuristic of checking +  # that the last anchor node is an ancestor of our element. +  findModeAnchorNode = document.getSelection().anchorNode +  if (FindMode.query.hasResults && document.activeElement &&        DomUtils.isSelectable(document.activeElement) &&        DomUtils.isDOMDescendant(findModeAnchorNode, document.activeElement))      DomUtils.simulateSelect(document.activeElement) -getNextQueryFromRegexMatches = (stepSize) -> -  # find()ing an empty query always returns false -  return "" unless findModeQuery.regexMatches - -  totalMatches = findModeQuery.regexMatches.length -  findModeQuery.activeRegexIndex += stepSize + totalMatches -  findModeQuery.activeRegexIndex %= totalMatches - -  findModeQuery.regexMatches[findModeQuery.activeRegexIndex] - -window.getFindModeQuery = (backwards) -> -  # check if the query has been changed by a script in another frame -  mostRecentQuery = FindModeHistory.getQuery() -  if (mostRecentQuery != findModeQuery.rawQuery) -    findModeQuery.rawQuery = mostRecentQuery -    updateFindModeQuery() - -  if findModeQuery.isRegex -    getNextQueryFromRegexMatches(if backwards then -1 else 1) -  else -    findModeQuery.parsedQuery -  findAndFocus = (backwards) ->    Marks.setPreviousPosition() -  query = getFindModeQuery backwards - -  findModeQueryHasResults = -    executeFind(query, { backwards: backwards, caseSensitive: !findModeQuery.ignoreCase }) +  FindMode.query.hasResults = FindMode.execute null, {backwards} -  if findModeQueryHasResults +  if FindMode.query.hasResults      focusFoundLink() -    new PostFindMode() if findModeQueryHasResults +    new PostFindMode()    else -    HUD.showForDuration("No matches for '" + findModeQuery.rawQuery + "'", 1000) +    HUD.showForDuration("No matches for '#{FindMode.query.rawQuery}'", 1000)  window.performFind = -> findAndFocus() @@ -992,43 +767,10 @@ window.goNext = ->    nextStrings = nextPatterns.split(",").filter( (s) -> s.trim().length )    findAndFollowRel("next") || findAndFollowLink(nextStrings) -showFindModeHUDForQuery = -> -  if findModeQuery.rawQuery and (findModeQueryHasResults || findModeQuery.parsedQuery.length == 0) -    plural = if findModeQuery.matchCount == 1 then "" else "es" -    HUD.show("/" + findModeQuery.rawQuery + " (" + findModeQuery.matchCount + " Match#{plural})") -  else if findModeQuery.rawQuery -    HUD.show("/" + findModeQuery.rawQuery + " (No Matches)") -  else -    HUD.show("/") - -getCurrentRange = -> -  selection = getSelection() -  if selection.type == "None" -    range = document.createRange() -    range.setStart document.body, 0 -    range.setEnd document.body, 0 -    range -  else -    selection.collapseToStart() if selection.type == "Range" -    selection.getRangeAt 0 - -findModeSaveSelection = -> -  findModeInitialRange = getCurrentRange() - -findModeRestoreSelection = (range = findModeInitialRange) -> -  selection = getSelection() -  selection.removeAllRanges() -  selection.addRange range -  # Enters find mode.  Returns the new find-mode instance. -window.enterFindMode = (options = {}) -> +window.enterFindMode = ->    Marks.setPreviousPosition() -  # Save the selection, so performFindInPlace can restore it. -  findModeSaveSelection() -  findModeQuery = rawQuery: "" -  findMode = new FindMode options -  HUD.show "/" -  findMode +  new FindMode()  window.showHelpDialog = (html, fid) ->    return if (isShowingHelpDialog || !document.body || fid != frameId) | 
