           </div>
         </div>
         """
-      # NOTE: The majority of presentation state logic is in the plugin
-      # stylesheet. We update the presentation state by using `classNames`.
+      # - `triggerContent` can be the name of the trigger element's attribute or a
+      #   function that provides custom content when given the trigger element.
+      triggerContent: null
+      # NOTE: For these tip plugins, the majority of presentation state logic is
+      # in the plugin stylesheet. We update the presentation state by using
+      # namespaced `classNames` generated in a closure.
+      # 
       # - `classNames.stem` - Empty string to remove the stem.
       # - `classNames.follow` - Empty string to disable cursor following.
       classNames: do ->


    # SnapTip Options
    # ---------------
    # These options extend the tip options.
    defaults: do (pre = 'js-snap-tip-') ->
      $.extend (deep = yes), {}, hlf.tip.defaults,
        # - `snap.toXAxis` is the switch for snapping along x-axis. Off by default.
        # - `snap.toYAxis` is the switch for snapping along y-axis. Off by default.
        # - `snap.toTrigger` is the switch snapping to trigger that builds on top of
        #   axis-snapping. On by default. 
        snap:
          toTrigger: on
          toXAxis: off

          onMouseMove = _.throttle @_onTriggerMouseMove, 16
        @$context.on 'mousemove', selector, onMouseMove

    # ### Positioning

    # 𝒇 `_onTriggerMouseMove` is actually the main tip toggling handler. To
    # explain, first we take into account of child elements triggering the mouse
    # event by deducing the event's actual `$trigger` element. Then we
    # `wakeByTrigger` if needed.
    _onTriggerMouseMove: (event) ->
      return no if not event.pageX?

      $trigger =
        if ($trigger = $(event.currentTarget)) and $trigger.hasClass @classNames.trigger then $trigger
        else $trigger.closest(@classNames.trigger)
      return no if not $trigger.length

      @wakeByTrigger $trigger, event

    # 𝒇 `_positionToTrigger` will properly update the tip offset per
    # `offsetOnTriggerMouseMove` and `_isDirection`. Also note that `_stemSize`
    # gets factored in.
    _positionToTrigger: ($trigger, mouseEvent, cursorHeight=@cursorHeight) ->
      return no if not mouseEvent?

      offset =
        top: mouseEvent.pageY
        left: mouseEvent.pageX
      offset = @offsetOnTriggerMouseMove(mouseEvent, offset, $trigger) or offset

      if @_isDirection('top', $trigger)
        offset.top -= @$tip.outerHeight() + @_stemSize()
      else if @_isDirection('bottom', $trigger)
        offset.top += @_stemSize() + cursorHeight

      if @_isDirection('left',  $trigger)
        tipWidth = @$tip.outerWidth()
        triggerWidth = $trigger.outerWidth()
        offset.left -= tipWidth
        #- If direction changed due to tip being wider than trigger.
        if tipWidth > triggerWidth
          offset.left += triggerWidth

      @$tip.css offset

    # 𝒇 `_setBounds` updates `_bounds` per `$viewport`'s inner bounds, and those
    # measures get used by `_updateDirectionByTrigger`.
    _setBounds: ->
      $viewport = if @$viewport.is('body') then $(window) else @$viewport
      @_bounds =
        top:    $.css @$viewport[0], 'padding-top', yes
        left:   $.css @$viewport[0], 'padding-left', yes
        bottom: $viewport.innerHeight()
        right:  $viewport.innerWidth()

    # ### Rendering

    # 𝒇 `_inflateByTrigger` will reset and update `$tip` and its content element for the given trigger, so
    # that it is ready to present, ie. it is 'inflated'. If the `resize` animation
    # is desired, we need to also specify the content element's dimensions for
    # respective transitions to take effect.
    _inflateByTrigger: ($trigger) ->
      $content = @selectByClass 'content'
      $content.text $trigger.data @attr('content')

      #- NOTE: A transition style is in place, so this causes animation.
      if @animations.resize.enabled
        contentSize = @_sizeForTrigger $trigger, (contentOnly = yes)
        $content
          .width contentSize.width
          .height contentSize.height

      compoundDirection =
        if $trigger.data(@attr('direction')) then $trigger.data(@attr('direction')).split(' ')
        else @defaultDirection
      @debugLog 'update direction class', compoundDirection
      @$tip
        .removeClass _.chain(@classNames).pick('top', 'bottom', 'right', 'left').values().join(' ')
        .addClass $.trim(
          _.reduce compoundDirection, (classListMemo, directionComponent) =>
            "#{classListMemo} #{@classNames[directionComponent]}"
          , ''
        )

    # 𝒇 `_render` comes with a base implementation that fills in and attaches
    # `$tip` to the DOM, specifically at the beginning of `$viewport`. It uses
    # the result of `htmlOnRender` and falls back to that of `_defaultHtml`. 
    # Render also sets up any animations per the `shouldAnimate` option.
