diff options
Diffstat (limited to 'lib')
| -rw-r--r-- | lib/dom_utils.coffee | 64 | ||||
| -rw-r--r-- | lib/handler_stack.coffee | 15 | ||||
| -rw-r--r-- | lib/keyboard_utils.coffee | 9 | ||||
| -rw-r--r-- | lib/utils.coffee | 17 | 
4 files changed, 100 insertions, 5 deletions
| diff --git a/lib/dom_utils.coffee b/lib/dom_utils.coffee index 4f36e395..2ae9412e 100644 --- a/lib/dom_utils.coffee +++ b/lib/dom_utils.coffee @@ -231,5 +231,69 @@ DomUtils =          @remove()          false +  simulateTextEntry: (element, text) -> +    event = document.createEvent "TextEvent" +    event.initTextEvent "textInput", true, true, null, text +    element.dispatchEvent event + +  # Adapted from: http://roysharon.com/blog/37. +  # This finds the element containing the selection focus. +  getElementWithFocus: (selection, backwards) -> +    r = t = selection.getRangeAt 0 +    if selection.type == "Range" +      r = t.cloneRange() +      r.collapse backwards +    t = r.startContainer +    t = t.childNodes[r.startOffset] if t.nodeType == 1 +    o = t +    o = o.previousSibling while o and o.nodeType != 1 +    t = o || t?.parentNode +    t + +  # This calculates the caret coordinates within an input element.  It is used by edit mode to calculate the +  # caret position for scrolling.  It creates a hidden div contain a mirror of element, and all of the text +  # from element up to position, then calculates the scroll position. +  # From: https://github.com/component/textarea-caret-position/blob/master/index.js +  getCaretCoordinates: do -> +    # The properties that we copy to the mirrored div. +    properties = [ +      'direction', 'boxSizing', 'width', 'height', 'overflowX', 'overflowY', +      'borderTopWidth', 'borderRightWidth', 'borderBottomWidth', 'borderLeftWidth', +      'paddingTop', 'paddingRight', 'paddingBottom', 'paddingLeft', +      'fontStyle', 'fontVariant', 'fontWeight', 'fontStretch', 'fontSize', 'fontSizeAdjust', +      'lineHeight', 'fontFamily', +      'textAlign', 'textTransform', 'textIndent', 'textDecoration', +      'letterSpacing', 'wordSpacing' ] + +    (element, position) -> +      div = document.createElement "div" +      div.id = "vimium-input-textarea-caret-position-mirror-div" +      document.body.appendChild div + +      style = div.style +      computed = getComputedStyle element + +      style.whiteSpace = "pre-wrap" +      style.wordWrap = "break-word" if element.nodeName.toLowerCase() != "input" +      style.position = "absolute" +      style.visibility = "hidden" +      style[prop] = computed[prop] for prop in properties +      style.overflow = "hidden" + +      div.textContent = element.value.substring 0, position +      if element.nodeName.toLowerCase() == "input" +        div.textContent = div.textContent.replace /\s/g, "\u00a0" + +      span = document.createElement "span" +      span.textContent = element.value.substring(position) || "." +      div.appendChild span + +      coordinates = +        top: span.offsetTop + parseInt computed["borderTopWidth"] +        left: span.offsetLeft + parseInt computed["borderLeftWidth"] + +      document.body.removeChild div +      coordinates +  root = exports ? window  root.DomUtils = DomUtils diff --git a/lib/handler_stack.coffee b/lib/handler_stack.coffee index 3d635005..b0fefc7d 100644 --- a/lib/handler_stack.coffee +++ b/lib/handler_stack.coffee @@ -38,6 +38,7 @@ class HandlerStack    # @stopBubblingAndTrue.    bubbleEvent: (type, event) ->      @eventNumber += 1 +    eventNumber = @eventNumber      # We take a copy of the array in order to avoid interference from concurrent removes (for example, to      # avoid calling the same handler twice, because elements have been spliced out of the array by remove).      for handler in @stack[..].reverse() @@ -45,13 +46,15 @@ class HandlerStack        if handler?.id and handler[type]          @currentId = handler.id          result = handler[type].call @, event -        @logResult type, event, handler, result if @debug +        @logResult eventNumber, type, event, handler, result if @debug          if not result            DomUtils.suppressEvent event  if @isChromeEvent event            return false          return true if result == @stopBubblingAndTrue          return false if result == @stopBubblingAndFalse          return @bubbleEvent type, event if result == @restartBubbling +      else +        @logResult eventNumber, type, event, handler, "skip" if @debug      true    remove: (id = @currentId) -> @@ -80,7 +83,7 @@ class HandlerStack      false    # Debugging. -  logResult: (type, event, handler, result) -> +  logResult: (eventNumber, type, event, handler, result) ->      # FIXME(smblott).  Badge updating is too noisy, so we filter it out.  However, we do need to look at how      # many badge update events are happening.  It seems to be more than necessary. We also filter out      # registerKeyQueue as unnecessarily noisy and not particularly helpful. @@ -90,9 +93,15 @@ class HandlerStack          when @stopBubblingAndTrue then "stop/true"          when @stopBubblingAndFalse then "stop/false"          when @restartBubbling then "rebubble" +        when "skip" then "skip"          when true then "continue"      label ||= if result then "continue/truthy" else "suppress" -    console.log "#{@eventNumber}", type, handler._name, label +    console.log "#{eventNumber}", type, handler._name, label + +  show: -> +    console.log "#{@eventNumber}:" +    for handler in @stack[..].reverse() +      console.log "  ", handler._name    # For tests only.    reset: -> diff --git a/lib/keyboard_utils.coffee b/lib/keyboard_utils.coffee index 693c9b1c..5c95680c 100644 --- a/lib/keyboard_utils.coffee +++ b/lib/keyboard_utils.coffee @@ -1,6 +1,6 @@  KeyboardUtils =    keyCodes: -    { ESC: 27, backspace: 8, deleteKey: 46, enter: 13, space: 32, shiftKey: 16, ctrlKey: 17, f1: 112, +    { ESC: 27, backspace: 8, deleteKey: 46, enter: 13, ctrlEnter: 10, space: 32, shiftKey: 16, ctrlKey: 17, f1: 112,      f12: 123, tab: 9, downArrow: 40, upArrow: 38 }    keyNames: @@ -59,7 +59,12 @@ KeyboardUtils =    # identify any of chrome's own keyboard shortcuts as printable.    isPrintable: (event) ->      return false if event.metaKey or event.ctrlKey or event.altKey -    @getKeyChar(event)?.length == 1 +    keyChar = +      if event.type == "keypress" +        String.fromCharCode event.charCode +      else +        @getKeyChar event +    keyChar.length == 1  KeyboardUtils.init() diff --git a/lib/utils.coffee b/lib/utils.coffee index 661f7e84..64c87842 100644 --- a/lib/utils.coffee +++ b/lib/utils.coffee @@ -152,6 +152,23 @@ Utils =    # locale-sensitive uppercase detection    hasUpperCase: (s) -> s.toLowerCase() != s +  # Give objects (including elements) distinct identities. +  getIdentity: do -> +    identities = [] + +    (obj) -> +      index = identities.indexOf obj +      if index < 0 +        index = identities.length +        identities.push obj +      "identity-" + index + +  # Return a copy of object, but with some of its properties omitted. +  copyObjectOmittingProperties: (obj, properties...) -> +    obj = extend {}, obj +    delete obj[property] for property in properties +    obj +  # This creates a new function out of an existing function, where the new function takes fewer arguments. This  # allows us to pass around functions instead of functions + a partial list of arguments.  Function::curry = -> | 
