123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111 |
- class Menu
- constructor: ->
- @visible = false
- @items = []
- @node = null
- @height = 0
- @direction = "bottom"
- show: =>
- window.visible_menu?.hide()
- @visible = true
- window.visible_menu = @
- @direction = @getDirection()
- hide: =>
- @visible = false
- toggle: =>
- if @visible
- @hide()
- else
- @show()
- Page.projector.scheduleRender()
- addItem: (title, cb, selected=false) ->
- @items.push([title, cb, selected])
- storeNode: (node) =>
- @node = node
- # Animate visible
- if @visible
- node.className = node.className.replace("visible", "")
- setTimeout (=>
- node.className += " visible"
- node.attributes.style.value = @getStyle()
- ), 20
- node.style.maxHeight = "none"
- @height = node.offsetHeight
- node.style.maxHeight = "0px"
- @direction = @getDirection()
- getDirection: =>
- if @node and @node.parentNode.getBoundingClientRect().top + @height + 60 > document.body.clientHeight and @node.parentNode.getBoundingClientRect().top - @height > 0
- return "top"
- else
- return "bottom"
- handleClick: (e) =>
- keep_menu = false
- for item in @items
- [title, cb, selected] = item
- if title == e.currentTarget.textContent or e.currentTarget["data-title"] == title
- keep_menu = cb?(item)
- break
- if keep_menu != true and cb != null
- @hide()
- return false
- renderItem: (item) =>
- [title, cb, selected] = item
- if typeof(selected) == "function"
- selected = selected()
- if title == "---"
- return h("div.menu-item-separator", {key: Time.timestamp()})
- else
- if cb == null
- href = undefined
- onclick = @handleClick
- else if typeof(cb) == "string" # Url
- href = cb
- onclick = true
- else # Callback
- href = "#"+title
- onclick = @handleClick
- classes = {
- "selected": selected,
- "noaction": (cb == null)
- }
- return h("a.menu-item", {href: href, onclick: onclick, "data-title": title, key: title, classes: classes}, title)
- getStyle: =>
- if @visible
- max_height = @height
- else
- max_height = 0
- style = "max-height: #{max_height}px"
- if @direction == "top"
- style += ";margin-top: #{0 - @height - 50}px"
- else
- style += ";margin-top: 0px"
- return style
- render: (class_name="") =>
- if @visible or @node
- h("div.menu#{class_name}", {classes: {"visible": @visible}, style: @getStyle(), afterCreate: @storeNode}, @items.map(@renderItem))
- window.Menu = Menu
- # Hide menu on outside click
- document.body.addEventListener "mouseup", (e) ->
- if not window.visible_menu or not window.visible_menu.node
- return false
- menu_node = window.visible_menu.node
- menu_parents = [menu_node, menu_node.parentNode]
- if e.target.parentNode not in menu_parents and e.target.parentNode.parentNode not in menu_parents
- window.visible_menu.hide()
- Page.projector.scheduleRender()
|