Jump To …

adapter.native.coffee

Native Opentip Adapter

Use this adapter if you don't use a framework like jQuery and you don't really care about oldschool browser compatibility.

class Adapter

  name: "native"

Invoke callback as soon as dom is ready Source: https://github.com/dperini/ContentLoaded/blob/master/src/contentloaded.js

  domReady: (callback) ->
    done = no
    top = true
    win = window
    doc = document

    return callback() if doc.readyState in [ "complete", "loaded" ]

    root = doc.documentElement
    add = (if doc.addEventListener then "addEventListener" else "attachEvent")
    rem = (if doc.addEventListener then "removeEventListener" else "detachEvent")
    pre = (if doc.addEventListener then "" else "on")

    init = (e) ->
      return  if e.type is "readystatechange" and doc.readyState isnt "complete"
      (if e.type is "load" then win else doc)[rem] pre + e.type, init, false
      unless done
        done = yes
        callback()

    poll = ->
      try
        root.doScroll "left"
      catch e
        setTimeout poll, 50
        return
      init "poll"

    unless doc.readyState is "complete"
      if doc.createEventObject and root.doScroll
        try
          top = not win.frameElement
        poll()  if top
      doc[add] pre + "DOMContentLoaded", init, false
      doc[add] pre + "readystatechange", init, false
      win[add] pre + "load", init, false

DOM

Create the HTML passed as string

  create: (htmlString) ->
    div = document.createElement "div"
    div.innerHTML = htmlString
    @wrap div.childNodes

Element handling

Wrap the element in the framework

  wrap: (element) ->
    if element instanceof NodeList
      element = (el for el in element)
    else if element not instanceof Array
      element = [ element ]
    element

Returns the unwrapped element

  unwrap: (element) -> @wrap(element)[0]

Returns the tag name of the element

  tagName: (element) -> @unwrap(element).tagName

Returns or sets the given attribute of element

  attr: (element, attr, value) ->
    if arguments.length == 3
      @unwrap(element).setAttribute attr, value
    else
      @unwrap(element).getAttribute? attr


  lastDataId = 0
  dataValues = { }

Returns or sets the given data of element

  data: (element, name, value) ->
    dataId = @attr element, "data-id"
    unless dataId
      dataId = ++lastDataId
      @attr element, "data-id", dataId
      dataValues[dataId] = { }

    if arguments.length == 3

Setter

      dataValues[dataId][name] = value
    else
      value = dataValues[dataId][name]
      return value if value?

      value = @attr element, "data-#{Opentip::dasherize name}"
      if value
        dataValues[dataId][name] = value
      return value

Finds elements by selector

  find: (element, selector) -> @unwrap(element).querySelector selector

Finds all elements by selector

  findAll: (element, selector) -> @unwrap(element).querySelectorAll selector

Updates the content of the element

  update: (element, content, escape) ->
    element = @unwrap element
    if escape
      element.innerHTML = "" # Clearing the content
      element.appendChild document.createTextNode content
    else
      element.innerHTML = content

Appends given child to element

  append: (element, child) ->
    unwrappedChild = @unwrap child
    unwrappedElement = @unwrap element
    unwrappedElement.appendChild unwrappedChild

Add a class

  addClass: (element, className) -> @unwrap(element).classList.add className

Remove a class

  removeClass: (element, className) -> @unwrap(element).classList.remove className

Set given css properties

  css: (element, properties) ->
    element = @unwrap @wrap element
    for own key, value of properties
      element.style[key] = value

Returns an object with given dimensions

  dimensions: (element) ->
    element = @unwrap @wrap element
    dimensions =
      width: element.offsetWidth
      height: element.offsetHeight

    unless dimensions.width and dimensions.height

The element is probably invisible. So make it visible

      revert =
        position: element.style.position || ''
        visibility: element.style.visibility || ''
        display: element.style.display || ''

      @css element,
        position: "absolute"
        visibility: "hidden"
        display: "block"

      dimensions =
        width: element.offsetWidth
        height: element.offsetHeight

      @css element, revert      

    dimensions

Returns the scroll offsets of current document

  scrollOffset: ->
    [
      window.pageXOffset or document.documentElement.scrollLeft or document.body.scrollLeft
      window.pageYOffset or document.documentElement.scrollTop or document.body.scrollTop
    ]

Returns the dimensions of the viewport (currently visible browser area)

  viewportDimensions: ->
    {
      width: document.documentElement.clientWidth
      height: document.documentElement.clientHeight
    }

Returns an object with x and y

  mousePosition: (e) ->
    pos = x: 0, y: 0

    e ?= window.event

    return unless e?

    if e.pageX or e.pageY
      pos.x = e.pageX
      pos.y = e.pageY
    else if e.clientX or e.clientY
      pos.x = e.clientX + document.body.scrollLeft + document.documentElement.scrollLeft
      pos.y = e.clientY + document.body.scrollTop + document.documentElement.scrollTop

    pos

Returns the offset of the element

  offset: (element) ->
    element = @unwrap element

    offset = {
      top: element.offsetTop
      left: element.offsetLeft
    }

    while element = element.offsetParent
      offset.top += element.offsetTop
      offset.left += element.offsetLeft

      if element != document.body
        offset.top -= element.scrollTop
        offset.left -= element.scrollLeft

    offset

Observe given eventName

  observe: (element, eventName, observer) -> @unwrap(element).addEventListener eventName, observer

Stop observing event

  stopObserving: (element, eventName, observer) -> @unwrap(element).removeEventListener eventName, observer

Perform an AJAX request and call the appropriate callbacks.

  ajax: (options) ->
    throw new Error "No url provided" unless options.url?

    if window.XMLHttpRequest

Mozilla, Safari, ...

      request = new XMLHttpRequest
    else if window.ActiveXObject

IE

      try
        request = new ActiveXObject "Msxml2.XMLHTTP"
      catch e
        try
          request = new ActiveXObject "Microsoft.XMLHTTP"
        catch e

    throw new Error "Can't create XMLHttpRequest" unless request

    request.onreadystatechange = ->
      if request.readyState == 4
        try
          if request.status == 200
            options.onSuccess? request.responseText
          else
            options.onError? "Server responded with status #{request.status}"
        catch e
          options.onError? e.message

        options.onComplete?()


    request.open options.method?.toUpperCase() ? "GET", options.url
    request.send()

Utility functions

Creates a shallow copy of the object

  clone: (object) ->
    newObject = { }
    for own key, val of object
      newObject[key] = val
    newObject

Copies all properties from sources to target

  extend: (target, sources...) ->
    for source in sources
      for own key, val of source
        target[key] = val
    target

Add the adapter to the list

Opentip.addAdapter new Adapter