       else
         resp = JSON.parse x.response
         alert resp.msg
+
+class Series
+  constructor: () ->
+    @tags = $ '#tags li a'
+    tag.addEventListener 'click', showTagInfo, false for tag in @tags
+
+    @tagShown = null
+    @tagInfo = null
+
+showTagInfo = (e) ->
+  a = e.targetElement
+
+  if THIS.tagShown? and THIS.tagShown is a.innerText
+    return
+
+  info = THIS.tagInfo
+  info.style.display = 'none'
+
+  if not info?
+    ajaxPost '/ajax/tag-info', 'tagName': a.innerText, false, (e) ->
+      resp = JSON.parse e.response
+      if resp.err isnt null
+        alert resp.msg
+        return
+
+      info = make 'div', 'id': 'tag-info'
+      info.innerHTML = resp.msg
+
+      $('#tag-upvote', info).addEventListener 'click', (e) ->
+        # ajax post...
+        false
+      , false
+
+      $('#tag-downvote', info).addEventListener 'click', (e) ->
+        # ajax post...
+        false
+      , false
+
+      THIS.tagInfo = info
+      document.body.appendChild info
+
+  if not info?
+    alert 'Something went wrong getting tag info'
+    return
+
+  desc = $ '#tag-desc', info
+  ajaxPost '/ajax/tag-desc', 'tagName': a.innerText, false, (e) ->
+    resp = JSON.parse e.response
+    if resp.err isnt null
+      alert resp.msg
+      return
+
+    desc.innerText = resp.msg
+
+  info.style.display = 'block'
+
+  info.style.left = a.offsetWidth + a.offsetLeft + 8 + 'px'
+  info.style.top = a.offsetHeight/2 + a.offsetTop - info.offsetHeight
+  THIS.tagShown = a.innerText
+
+  # if user clicks outside the popup, close it
+  document.body.addEventListener 'click', (e) ->
+    el = e.targetElement
+    if el isnt info and el.parentElement isnt info
+      hideTagInfo()
+    true # keep going down the click events.
+  , true
+
+hideTagInfo = ->
+  if not THIS.tagInfo?
+    return
+
+  tagInfo.style.display = 'none'
+  THIS.tagShown = ''
+
+pageObjects =
+  'series': Series
+
+THIS = null
 
 main = ->
   pairs = [

      console.log "Element: #{pair[0]}"
      console.log e.stack

window.addEventListener 'load', main, true
window.addEventListener 'load', ->
  $('head').appendChild make 'script',

  base = document if not base?
  base.querySelectorAll sel

HTMLElement::on = (evt, func, bubble) ->
  if evt.constructor.name is 'Array'
    this.addEventListener e, func, bubble for e in evt
  else
    # add a touchend event automatically for click events
    if evt is 'click'
      this.addEventListener 'touchend', func, bubble
    this.addEventListener evt, func, bubble
  
ajaxPost = (path, data, async, callbacks) ->
  x = new XMLHttpRequest()

  if callbacks?
    switch typeof(callbacks)
      when 'object'
        x.addEventListener(evt, callback, false) for evt, callback of callbacks

      when 'function'
        x.addEventListener 'load', callbacks, true

  x.open 'post', path, async

