coffeescript-ui
Version:
Coffeescript User Interface System
396 lines (324 loc) • 10.5 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
###
# Template needs to be called like this:
#
# new CUI.Template
# name: "name-of-template" // a .cui-tmpl.cui-tmpl-name-of-template has to exist in the DOM tree
# map:
# key: selector // selector can be "true", than key is used like ".key", "_" is replaced by "-"
# layout:
# key: opts // key is the name of layout looked for, selector is assumed "true", opts are the
# // opts passed to the layout
#
# when inserted into the DOM, the template initializes all containing
# layouts
#
# Template.map
# Template.obj: the actual DOM element
#
class CUI.Template extends CUI.Element
constructor: (opts) ->
super(opts)
#try find it inside cached list
node = CUI.Template.nodeByName[]
CUI.util.assert(node, "CUI.Template", +" not found. Make sure to call Template.loadFile(...).")
= node.cloneNode(true)
if
CUI.dom.addClass(, )
if
CUI.dom.setAttributeMap(, )
# map elements which require mapping
=
if
return
initOpts: ->
super()
name:
mandatory: true
check: String
map_prefix:
check: String
init_flex_handles:
mandatory: true
default: false
check: Boolean
map:
type: "PlainObject"
default: {}
class:
check: String
attr:
check: "PlainObject"
@
initFlexHandles: (pane_opts={}) ->
# init any flex handles find in the markup
= {}
# txt = "Template.initFlexHandles[name=#{@_name}]"
# console.time(txt)
for fh_el in CUI.dom.matchSelector(, "[data-cui-flex-handle]")
opts =
if pane_opts[opts.name]
# merge opts
for k,v of pane_opts[opts.name]
if not opts.hasOwnProperty(k)
opts[k] = v
else
opts.manage_state = false
opts.element = fh_el
fh = new CUI.FlexHandle(opts)
if not CUI.util.isEmpty(fh_name = fh.getName())
# console.warn("Template.initFlexHandles", fh_name)
[fh_name] = fh
fh.init()
# console.timeEnd(txt)
@
getFlexHandle: (name) ->
CUI.util.assert(, "Template.getFlexHandle", "flexHandles are not initialized yet, call Template.initFlexHandles(opts) first.", name: name)
fh = [name]
CUI.util.assert(fh instanceof CUI.FlexHandle, "#{@__cls}.getFlexHandle", "FlexHandle \"#{name}\" not found, make sure you have specified a name in the cui-flex-handle attribute.", opts: , flexHandles: )
fh
getFlexHandles: ->
getElMap: (map) ->
el_map = {}
report = []
misses = 0
for k, v of map
if CUI.util.isNull(v)
continue
if v == true
clean_k = k.replace(/_/g, "-")
if
sel = "."++"-"+clean_k
else
prefix = CUI.util.toDash()
sel = ".ez-"+prefix+"-"+clean_k+",.cui-"+prefix+"-"+clean_k
sel = sel + ',[data-slot="'+CUI.escapeAttribute(k)+'"]'
else
sel = v
map_obj = CUI.dom.matchSelector(, sel, true)
if map_obj.length == 0
report.push("* #{k}: not found (#{sel})")
misses++
else if map_obj.length > 1
console.debug(k, v, "found more than once", map_obj, )
report.push("* #{k}: found more than once (#{sel})")
misses++
else
report.push("+ #{k}: found")
el_map[k] = map_obj[0]
# CUI.dom.addClass(el_map[k], "cui-template-empty")
map_obj[0].removeAttribute("data-slot")
do (k) =>
el_map[k].empty = =>
el_map[k]
el_map[k].append = (value) =>
el_map[k]
el_map[k].prepend = (value) =>
el_map[k]
if misses
CUI.util.assert(false, "Not all required elements were found for Template:\n\n\"#{@_name}\"\n\n"+report.join("\n"))
el_map
destroy: ->
# console.error "destroying...", CUI.util.getObjectClass(DOM.data(, "element")), CUI.util.getObjectClass([0])
CUI.dom.remove()
delete()
super()
addClass: (cls, key) ->
if key
CUI.util.assert([key], "#{@__cls}.addClass", "Key \"#{key}\" not found in map. Template: \"#{@_name}\".", map: , DOM: )
CUI.dom.addClass([key], cls)
else
CUI.dom.addClass(, cls)
removeClass: (cls, key) ->
if key
CUI.util.assert([key], "#{@__cls}.removeClass", "Key \"#{key}\" not found in map. Template: \"#{@_name}\".", map: , DOM: )
CUI.dom.removeClass([key], cls)
else
CUI.dom.removeClass(, cls)
hasClass: (cls, key) ->
if key
CUI.util.assert([key], "#{@__cls}.hasClass", "Key \"#{key}\" not found in map. Template: \"#{@_name}\".", map: , DOM: )
CUI.dom.hasClass([key], cls)
else
CUI.dom.hasClass(, cls)
has: (key) ->
!![key]
hide: (key) ->
if not key
CUI.dom.hideElement()
else
CUI.dom.hideElement([key])
show: (key) ->
if not key
CUI.dom.showElement()
else
CUI.dom.showElement([key])
__updateTemplateEmpty: ->
if CUI.util.isEmptyObject()
is_empty =
else
is_empty = true
for key of
if not
is_empty = false
break
if is_empty
CUI.dom.addClass(, "cui-template-empty")
else
CUI.dom.removeClass(, "cui-template-empty")
return
replace: (value, key, element) ->
CUI.util.assert(, "Template[#{@_name}].replace [#{@getUniqueId()}]", "Already destroyed")
if key
CUI.util.assert([key], "#{@__cls}.replace", "Key \"#{key}\" not found in map. Template: \"#{@_name}\".", map: , DOM: )
node =
return node
text: (value, key, element) ->
CUI.util.assert(CUI.util.isString(value), "#{@__cls}.text", "Value must be String", value: value, key: key, element: element)
if key
[key].textContent = value
else
.textContent = value
return
prepend: (value, key, element) ->
node =
return node
append: (value, key, element) ->
node =
return node
empty: (key) ->
node =
return node
__empty: (key) ->
CUI.util.assert(, "Template[#{@_name}].empty [#{@getUniqueId()}]", "Already destroyed", template: @, name: )
if
if key
return [key]
else
return
if key
CUI.util.assert([key], "#{@__cls}.empty", "Key \"#{key}\" not found in map. Template: \"#{@_name}\".", map: )
# console.debug "Template.destroyingChildren", key, [key]
CUI.dom.empty([key])
return [key]
if CUI.util.isEmptyObject()
# without map we empty the whole
CUI.dom.empty()
else
# with map we empty each individual map entry
for key of
CUI.dom.empty([key])
return
__append: (value, key, element, prepend) ->
if prepend
fn = "prepend"
else
fn = "append"
CUI.util.assert(, "Template[#{@_name}].#{fn} [#{@getUniqueId()}]", "Already destroyed")
if key
CUI.util.assert([key], "#{@__cls}.#{fn}", "Key \"#{key}\" not found in map. Template: \"#{@_name}\".", map: )
if CUI.util.isFunction(value)
value = value(element)
if not CUI.util.isArray(value)
value = [value]
appends = []
for _value in value
if _value?.DOM
appends.push(_value.DOM)
else
CUI.util.assert(not CUI.util.isPromise(_value), "Template.append", "value cannot be Promise", value: value)
if _value
appends.push(_value)
if key
node = [key]
else
node =
if appends.length > 0
CUI.dom[fn](node, appends)
node
get: (key) ->
CUI.util.assert([key], "#{@__cls}.get", "Key \"#{key}\" not found in map. Template: \"#{@_name}\".", map: , DOM: )
return [key]
isEmpty: (key) ->
if not key
return !.firstChild
CUI.util.assert([key], "#{@__cls}.isEmpty", "Key \"#{key}\" not found in map. Template: \"#{@_name}\".", map: )
return ![key].firstChild
removeEmptySlots: ->
for key, node of
if not node.firstChild
CUI.dom.remove(node)
@
: {}
: (filename) ->
: (html) ->
: (text) ->
: (filename, load_templates = false) ->
if filename.match("^(https://|http://|/)")
p = filename
else
p = CUI.getPathToScript()+filename
new CUI.XHR
url: p
responseType: "text"
.start()
.done (data) =>
return
.fail (xhr) ->
console.error("Template.loadFile: Unable to load filename: \"#{filename}\", see Console for more details. You can however, output easydbui.html manually before loading easydbui.js.", xhr)
: (start_element = document.documentElement) ->
count = 0
for el in CUI.dom.matchSelector(start_element, ".cui-tmpl,[data-template]")
name = null
name = el.getAttribute("data-template")
if CUI.util.isEmpty(name)
for cls in el.classList
if cls.startsWith("cui-tmpl-")
name = cls.substr(9)
if CUI.Template.nodeByName[name]
console.error("Template.load:", name, "already found in DOM tree. Make sure all elements exists only once.", el)
continue
break
if name
# console.debug("Template: ", name)
CUI.Template.nodeByName[name] = el
CUI.dom.remove(el)
el.classList.remove("cui-tmpl")
el.removeAttribute("data-template")
count = count + 1
return count
: (data, load_templates) ->
div = CUI.dom.element("DIV", style: "display:none;")
div.innerHTML = data
if not load_templates
document.body.appendChild(div)
else
count = CUI.Template.load(div)
if div.children.length > 0
document.body.appendChild(div)
console.warn("Template.loadFile:", filename, "contains extra content.", div)
if count == 0
console.warn("Template.loadFile:", filename, "contains no Templates.")
else
; # console.info("Template.loadFile:", count, "Template loaded from", filename)