// // Copyright (c) 2016, Brian Frank and Andy Frank // Licensed under the Academic Free License version 3.0 // // History: // 17 Jun 2016 Andy Frank Creation // using dom ** ** AccordionBox displays collapsible content panels for presenting ** information in a limited amount of vertical space, where the ** header element is used to collapse or expand the child content. ** ** See also: [docDomkit]`docDomkit::Layout` ** @Js class AccordionBox : Box { new make() : super() { this.style.addClass("domkit-AccordionBox") this.onEvent("mousedown", false) |e| { onMouseDown(e) } } ** Add a new group with given header and child nodes. Optionally ** configure default expansion state with 'expanded' paramter ** (defaults to collapsed). This addGroup(Elem header, Elem[] kids, Bool expanded := false) { // default display styles for all nodes header.style->display = "block" kids.each |k| { k.style->display = "none" } // wrap into group node group := Elem { it.style.addClass("domkit-AccordionBox-group collapsed") } group.add(header) group.addAll(kids) this.add(group) // check if we need to expand group if (expanded) expand(this.children.size-1, true) return this } ** Return 'true' if given group is expanded, or 'false' if not. Bool isExpanded(Int groupIndex) { group := this.children.getSafe(groupIndex) if (group == null) return false // TODO: throw err? return group.style.hasClass("expanded") } ** Set expanded state for given group. Void expand(Int groupIndex, Bool expanded) { group := this.children.getSafe(groupIndex) if (group == null) return // TODO: throw err? if (expanded) { // expand group.style.removeClass("collapsed").addClass("expanded") group.children.each |k| { k.style->display = "block" } } else { // collapse group.style.removeClass("expanded").addClass("collapsed") group.children.eachRange(1..-1) |k| { k.style->display = "none" } } } ** Toggle a group or fire action for child. private Void onMouseDown(Event e) { // find group kids := this.children group := kids.find |g| { g.containsChild(e.target) } if (group == null) return // toggle if fired on header if (group.firstChild.containsChild(e.target)) { index := kids.findIndex |g| { g == group } expand(index, !isExpanded(index)) } } }