coffeescript-ui
Version:
Coffeescript User Interface System
426 lines (339 loc) • 11.6 kB
text/coffeescript
###
* coffeescript-ui - Coffeescript User Interface System (CUI)
* Copyright (c) 2013 - 2016 Programmfabrik GmbH
* MIT Licence
* https://github.com/programmfabrik/coffeescript-ui, http://www.coffeescript-ui.org
###
# {Layout} is used for all layout related stuff, like {HorizontalLayout},
# {VerticalLayout}, {BorderLayout}, {Toolbar}, {Pane}, etc.
#
# It features an automatic {Buttonbar} generation for all panes (see {Layout#append})
class CUI.Layout extends CUI.DOMElement
#Construct a new Layout.
#
# [Object] options for layout creation
# options [String] maximize the center so that it pushes top pane to top and bottom pane to the bottom of the parent element
# options [Object] pane name of the pane on its options, check {Layout.initPane} for the options.
# TODO document other options
# TODO create a Pane Class
constructor: (opts) ->
super(opts)
= false
initOpts: ->
super()
absolute:
check: Boolean
maximize:
check: Boolean
maximize_horizontal:
check: Boolean
maximize_vertical:
check: Boolean
auto_buttonbar:
default: true
mandatory: true
check: Boolean
center:
default: {}
check: "PlainObject"
for pn in
readOpts: ->
# DEBUG
# without absolute "help", FF and Safari perform badly, Chrome & IE (Edge) are fine
super()
if
CUI.util.assert(, "new "+, "opts.absolute needs opts.maximize to be set.", opts: )
@
maximizeAddClasses: ->
if
if
if
@
maximizeReadOpts: ->
if CUI.util.isNull() and
CUI.util.isNull() and
CUI.util.isNull()
= true
if
CUI.util.assert(not and not , "new "+CUI.util.getObjectClass(@), "opts.maximize cannot be set together with opts.maximize_horizontal or opts.maximize_vertical", opts: )
= true
= true
else
if
= true
if
= true
if and
= true
@
init: ->
getTemplateMap: ->
map = {}
for pn in
map[pn] = true
map
__init: ->
CUI.util.assert(not( == false and == true), "Layout.__init", "opts.maximize == false and opts.absolute == true is not allowed.", opts: )
=
.push("center")
=
= new CUI.Template
name:
map_prefix:
map:
# if and
# CUI.Events.listen
# type: "content-resize"
# instance: @
# node:
# call: (ev) =>
# console.debug "context-resizse stopped"
# if CUI.dom.closest(ev.getTarget(), '.cui-absolute')
# # no stopping inside absolute layouts
# return
# ev.stopPropagation()
if
CUI.util.assert(CUI.dom.getAttribute(, "data-cui-absolute-container") in ["row","column"], "new CUI.Layout", "opts.absolute: template must include a cui-absolute-container attribute set to \"row\" or \"column\".")
CUI.dom.waitForDOMInsert(node: )
.done =>
# console.debug "Layout[absolute] inserted",
CUI.Layout.all()
# _call = (event) =>
# console.error "Layout.setAbsolute[#{event.getDebug()}]:", [0]
# # console.error "Layout[viewport-resize] received", [0]
# #
# event.stopPropagation()
# Layout.setAbsolute()
# CUI.Events.listen
# type: "viewport-resize"
# node:
# instance: @
# call: _call
# CUI.Events.listen
# type: "content-resize"
# node:
# instance: @
# call: _call
else
CUI.dom.removeAttribute(, "data-cui-absolute-container")
for child in .children
CUI.dom.removeAttribute(child, "data-cui-absolute-set")
= {}
if
has_flex_handles = true
# console.warn(CUI.util.getObjectClass(@)+".initFlexHandles", , .__uniqueId, [0])
pane_opts = {}
for pn in
pane = @["_#{pn}"]
if pane?.flexHandle
pane_opts[pn] = pane.flexHandle
.initFlexHandles(pane_opts)
else
has_flex_handles = false
# every pane gets a method "<pane>: ->" to retrieve
# the DOM element from the template
for pn in
do (pn) =>
@[pn] = =>
CUI.util.assert(@["_#{pn}"], "#{@__cls}.#{pn}", "Pane \"#{pn}\" not initialized.", opts: )
CUI.util.assert(not .isDestroyed(), "Layout already destroyed, cannot get pane \"#{pn}\".")
.map[pn]
pane = @["_#{pn}"]
if pane
if has_flex_handles and pn != "center" and not pane.flexHandle
.getFlexHandle(pn).destroy()
else
# console.debug(CUI.util.getObjectClass(@), "removing uninitialized pane", pn, @)
CUI.dom.remove(.map[pn])
if has_flex_handles
.getFlexHandle(pn).destroy()
= true
destroy: ->
CUI.Events.ignore(instance: @)
super()
getMapPrefix: ->
undefined
#initialive pane option
__initPane: (options, pane_name) ->
CUI.util.assert(pane_name, "Layout.initPane", "pane_name must be set", options: options, pane_name: pane_name)
opts = CUI.Element.readOpts(options, "new CUI.Layout.__initPane",
class:
check: String
content: {}
flexHandle: {}
)
if opts.class
.addClass(opts.class, pane_name)
# returns true if this Layout has at least one
# flexHandle
hasFlexHandles: ->
true
# init default panes, so that they are in markup
initDefaultPanes: ->
for pn in
if not .hasOwnProperty(pn)
[pn] = {}
@
getPanes: ->
CUI.util.assert(false, "#{@__cls}.getPanes", "Needs implementation")
getSupportedPanes: ->
CUI.util.assert(false, "#{@__cls}.getSupportedPanes", "Needs implementation")
getLayout: ->
getButtonbar: (key) ->
if not [key]
[key] = new CUI.Buttonbar()
# console.info("#{@__cls}: automatically generated Buttonbar for #{key}.")
CUI.DOMElement::append.call(@, [key], key)
[key]
__callAutoButtonbar: (value, key) ->
if CUI.util.isFunction(value)
value = value(@)
get_value = (v) ->
if CUI.util.isPlainObject(v)
return new CUI.defaults.class.Button(v)
else
return v
value = get_value(value)
if CUI.util.isArray(value)
for _v in value
v = get_value(_v)
if v instanceof CUI.Button
.addButton(v)
else
CUI.DOMElement::append.call(@, _v, key)
else if value instanceof CUI.Button
.addButton(value)
else
return CUI.DOMElement::append.call(@, value, key)
# [jQuery, Function, Array, ...] value the value to append to the layer
# [String] key the name of the pane
# [Boolean] auto_buttonbar if set to true (default), automatically generate a {Buttonbar} for Buttons passed directly, in an Array or thru a Function
#
# [jQuery] the DOM node (created and) appended
append: (value, key, auto_buttonbar = ) ->
if auto_buttonbar
return
else
return super(value, key)
replace: (value, key, auto_buttonbar = ) ->
if auto_buttonbar
delete([key])
return
else
return super(value, key)
setAbsolute: ->
CUI.Layout.__all()
unsetAbsolute: ->
.removeAttribute("data-cui-absolute-check-value")
.removeAttribute("data-cui-absolute-values")
for child in CUI.dom.children()
CUI.dom.setStyle child,
top: ""
left: ""
right: ""
bottom: ""
@
getName: ->
CUI.util.assert(false, "#{@__cls}.getName", "Needs to be overwritten.")
: (layout) ->
# console.error "Layout.setAbsolute", layout[0]
CUI.util.assert(CUI.util.isElement(layout), "Layout.setAbsolute", "layout needs to be HTMLElement", layout: layout)
direction = CUI.dom.getAttribute(layout, "data-cui-absolute-container")
switch direction
when "row"
rect_key = "marginBoxWidth"
rect_check_key = "marginBoxHeight"
when "column"
rect_key = "marginBoxHeight"
rect_check_key = "marginBoxWidth"
else
CUI.util.assert(false, "Layout.setAbsolute", "cui-absolute-container is not set for .cui-absolute container or not set to row or column.", container: layout, direction: direction)
# measure all children
values = []
children = CUI.dom.children(layout)
for child, idx in children
values[idx] = CUI.dom.getDimensions(child)[rect_key]
abs_values = values.join(",")
check_value = CUI.dom.getDimensions(layout)[rect_check_key]+""
# console.debug layout, abs_values, CUI.dom.getAttribute(layout, "data-cui-absolute-values")
# console.debug layout, check_value, CUI.dom.getAttribute(layout, "data-cui-absolute-check-value")
if CUI.dom.getAttribute(layout, "data-cui-absolute-values") == abs_values and
CUI.dom.getAttribute(layout, "data-cui-absolute-check-value") == check_value
# nothing to do
return false
if CUI.dom.getAttribute(layout, "data-cui-absolute-check-value") != check_value
CUI.dom.setAttribute(layout, "data-cui-absolute-check-value", check_value)
if CUI.dom.getAttribute(layout, "data-cui-absolute-values") != abs_values
CUI.dom.setAttribute(layout, "data-cui-absolute-values", abs_values)
# console.debug(txt, values)
for child, idx in children
set = CUI.dom.getAttribute(child, "data-cui-absolute-set")
if not set
continue
css = {}
for key in set.split(",")
switch key
when "left", "top"
# this is left hand
if idx > 0
value = values.slice(0, idx).reduce((a,b) -> a+b)
else
value = 0
when "right", "bottom"
if idx + 1 < values.length
value = values.slice(idx+1).reduce((a,b) -> a+b)
else
value = 0
else
CUI.util.assert(false, "Layout.setAbsolute: Unknown key #{key} in data-cui-absolute-set.")
# console.debug idx, key, value
css[key] = value
CUI.dom.setStyle(child, css)
# CUI.Events.trigger
# type: "viewport-resize"
# exclude_self: true
# node: layout
return true
: ->
layouts = []
changed = 0
for layout, idx in CUI.dom.matchSelector(document.documentElement, ".cui-absolute")
if CUI.Layout.setAbsolute(layout)
changed++
if changed > 0
# console.info("Layout.setAbsolute[all]: changed: ", changed)
# console.debug "triggering viewport resize"
CUI.Events.trigger(type: "viewport-resize")
@
: ->
CUI.scheduleCallback(call: CUI.Layout.__all)
CUI.ready ->
CUI.Events.listen
type: ["viewport-resize", "content-resize"]
call: (ev, info) ->
if info.FlexHandle
CUI.Layout.__all()
else
CUI.Layout.all()