/* @flow */

type ListenerFunction = (el: Element, name: string, ev: Event) => void;
type Listeners = {[name: string]: ListenerFunction[]}

export default class Actions {
  rootElement: Element;
  listeners: Listeners;
  boundListener: Function;

  constructor(el: Element) {
    this.rootElement = el
    this.listeners = {}
  }

  activate() {
    this.boundListener = this.handleClick.bind(this)
    this.rootElement.addEventListener('click', this.boundListener)
  }

  deactivate() {
    if (this.boundListener) {
      this.rootElement.removeEventListener('click', this.boundListener)
    }

    delete this.boundListener
    delete this.rootElement
    this.listeners = {}
  }

  add<T>(name: string, listener: ListenerFunction, thisObj: T): Actions {
    if (!this.listeners[name]) {
      this.listeners[name] = []
    }

    this.listeners[name].push(listener.bind(thisObj))
    return this
  }

  handleClick(ev: Event) {
    let target = ev.target

    if (!(target instanceof Element)) {
      return
    }

    if (target instanceof HTMLElement) {
      if (target.nodeName == 'BUTTON' && target.getAttribute('type') == 'submit') {
        return
      }
    }

    let root = this.rootElement.parentNode
    while (target && target != root && target != document) {
      if (target instanceof HTMLElement) {
        let name = target.getAttribute('data-click')
        if (name) {
          this.fire(name, target, ev)
          return
        }
      }

      target = target.parentNode
    }
  }

  fire(name: string, target: Element, ev: Event) {
    if (!this.listeners[name]) {
      return
    }

    this.listeners[name].forEach((fn: ListenerFunction) => {
      fn(target, name, ev)
    })

    ev.stopPropagation()
    ev.preventDefault()
  }
}

@@ -1372,140 +1372,566 @@
 k')%0A
-        if (name) %7B%0A          this.fire(name, target, ev)%0A          return%0A        %7D%0A      %7D%0A%0A      target = target.parentNode%0A    %7D
+%0A        // If the element doesn't have a data-click property but is something%0A        // you'd want to click on (like a text field), return without firing.%0A        if (this.isClickable(target) && !name) %7B%0A          return%0A        %7D%0A%0A        if (name) %7B%0A          this.fire(name, target, ev)%0A          return%0A        %7D%0A      %7D%0A%0A      target = target.parentNode%0A    %7D%0A  %7D%0A%0A  isClickable(el: HTMLElement) %7B%0A    switch (el.nodeName) %7B%0A      case 'BUTTON':%0A      case 'LINK':%0A      case 'INPUT':%0A      case 'TEXTAREA':%0A        return true%0A    %7D%0A%0A    return false
 %0A  %7D

Fix a bug where clicking on a clickable element ~sometimes~ would close popovers, etc.