B4J Question [BANano] EXSKCollapsable inside SKTabs (solved)

angel_

Well-Known Member
Licensed User
Longtime User
I'm trying to enter a layout with EXSKCollapsable inside a SKTabs but the layout shows extended and can't be collapsed, use the code from this thread


B4X:
Public Sub Load
    Collapse(SKTabs1.GetTabContents(0))
    SKTabs1.GetTabContents(1).LoadLayout("Layout2")
    SKTabs1.GetTabContents(2).LoadLayout("Layout3")
End Sub

Private Sub Collapse(elemento As BANanoElement)
    Dim body As BANanoElement = elemento
 
    ' some styling
    Dim panelStyle As String = "margin-bottom: -8px; border: 1px solid gray"
    Dim headerStyle As String = "background: #2c3e50;color : white;font-weight: 400"
    Dim contentStyle As String = "background-color: #ecf0f1"
 
    ' initialize the new compoent and add it to the body
    Dim coll As EXSKCollapsable
    coll.Initialize(Me, "collapse", "collapse")
    coll.OnlyOneOpen = False ' <-----------------------------------
    coll.Style = "border-radius: 8px; box-shadow: 0 4px 4px -2px rgb(0 0 0 / 50%);margin: 1rem"
    coll.AddToParent(body.Name)

    ' add panels and fill the header and content
    coll.AddPanel("panel1", panelStyle, headerStyle, contentStyle)
    coll.GetHeader("panel1").Append($"<h5 style="margin-bottom: 0px">Item 1</h5>"$) ' add some html
    coll.GetContent("panel1").LoadLayout("Layout1") ' or load a complete layout
End Sub
 
Solution
Try using this class. The original EXSKCollapsable used a hidden checkbox/radio component to keep track of the open/closed state, but this somehow interfered with other components in the BANanoSkeleton lib that use the same trick. I completely removed this and let the collapsable keep track of it itself.

NEW EXSKCollapsable:
B4X:
'Custom BANano View class

'Uncomment the events you want to show to the user and implement the HandleEvents in DesignerCreateView
'#Event: Focus (event As BANanoEvent)
'#Event: Blur (event As BANanoEvent)
'#Event: Resize (event As BANanoEvent)
'#Event: Scroll (event As BANanoEvent)
'#Event: Keydown (event As BANanoEvent)
'#Event: KeyPress (event As BANanoEvent)
'#Event: KeyUp (event As BANanoEvent)
#Event...

angel_

Well-Known Member
Licensed User
Longtime User
I use the BANano PWA template but the zip file is still quite large

B4X:
Sub MenuList_Click (returnName As String)
    SKTools.ShowToast("Clicked on " & returnName & "!", "info", 3000, True)
    ' here we can load the layout of the menu item we clicked
    Select Case returnName
        Case "page1"
            MainPageHolder.Element.Empty
            MainPageHolder.Element.LoadLayout("MyPage")
            Collapse(SKTabs1.GetTabContents(0))
    End Select
    ' and close the menu, if not always open
    If MainSidebar.AlwaysOpen = False Then
        MainSidebar.Close
    End If   
End Sub

Sub MainHamburgerMenu_Click (event As BANanoEvent)
    MainSidebar.Open
End Sub

Private Sub Collapse(TabElement As BANanoElement)
    Dim body As BANanoElement = TabElement
 
    ' some styling
    Dim panelStyle As String = "margin-bottom: -8px; border: 1px solid gray"
    Dim headerStyle As String = "background: #2c3e50;color : white;font-weight: 400"
    Dim contentStyle As String = "background-color: #ecf0f1"
 
    ' initialize the new compoent and add it to the body
    Dim coll As EXSKCollapsable
    coll.Initialize(Me, "collapse", "collapse")
    coll.OnlyOneOpen = False ' <-----------------------------------
    coll.Style = "border-radius: 8px; box-shadow: 0 4px 4px -2px rgb(0 0 0 / 50%);margin: 1rem"
    coll.AddToParent(body.Name)

    ' add panels and fill the header and content
    coll.AddPanel("panel1", panelStyle, headerStyle, contentStyle)
    coll.GetHeader("panel1").Append($"<h5 style="margin-bottom: 0px">Item 1</h5>"$) ' add some html
    coll.GetContent("panel1").LoadLayout("MyLayout1") ' or load a complete layout

    coll.AddPanel("panel2", panelStyle, headerStyle, contentStyle)
    coll.GetHeader("panel2").Append($"<h5 style="margin-bottom: 0px">Item 2</h5>"$)
    coll.GetContent("panel2").LoadLayout("MyLayout1")
End Sub

link: https://we.tl/t-JYhaj7dwXA
 

Attachments

  • BANanoCollapse.zip
    5.9 KB · Views: 124
Upvote 0

alwaysbusy

Expert
Licensed User
Longtime User
Try using this class. The original EXSKCollapsable used a hidden checkbox/radio component to keep track of the open/closed state, but this somehow interfered with other components in the BANanoSkeleton lib that use the same trick. I completely removed this and let the collapsable keep track of it itself.

NEW EXSKCollapsable:
B4X:
'Custom BANano View class

'Uncomment the events you want to show to the user and implement the HandleEvents in DesignerCreateView
'#Event: Focus (event As BANanoEvent)
'#Event: Blur (event As BANanoEvent)
'#Event: Resize (event As BANanoEvent)
'#Event: Scroll (event As BANanoEvent)
'#Event: Keydown (event As BANanoEvent)
'#Event: KeyPress (event As BANanoEvent)
'#Event: KeyUp (event As BANanoEvent)
#Event: Click (panelID As string)
'#Event: ContextMenu (event As BANanoEvent)
'#Event: Dblclick (event As BANanoEvent)
'#Event: MouseDown (event As BANanoEvent)
'#Event: MouseEnter (event As BANanoEvent)
'#Event: MouseLeave (event As BANanoEvent)
'#Event: MouseMove (event As BANanoEvent)
'#Event: MouseOver (event As BANanoEvent)
'#Event: MouseOut (event As BANanoEvent)
'#Event: MouseUp (event As BANanoEvent)
'#Event: Wheel (event As BANanoEvent)
'#Event: Drag (event As BANanoEvent)
'#Event: DragEnd (event As BANanoEvent)
'#Event: DragEnter (event As BANanoEvent)
'#Event: DragStart (event As BANanoEvent)
'#Event: DragLeave (event As BANanoEvent)
'#Event: DragOver (event As BANanoEvent)
'#Event: Drop (event As BANanoEvent)
'#Event: TouchCancel (event As BANanoEvent)
'#Event: TouchEnd (event As BANanoEvent)
'#Event: TouchEnter (event As BANanoEvent)
'#Event: TouchLeave (event As BANanoEvent)
'#Event: TouchMove (event As BANanoEvent)
'#Event: TouchStart (event As BANanoEvent)
'#Event: Change (event As BANanoEvent)

' Properties that will be show in the ABStract Designer.  They will be passed in the props map in DesignerCreateView (Case Sensitive!)
#DesignerProperty: Key: Classes, DisplayName: Classes, FieldType: String, DefaultValue: , Description: Classes added to the HTML tag.
#DesignerProperty: Key: Style, DisplayName: Style, FieldType: String, DefaultValue: , Description: Styles added to the HTML tag. Must be a json String.
#DesignerProperty: Key: MarginLeft, DisplayName: Margin Left, FieldType: String, DefaultValue: , Description: Margin Left
#DesignerProperty: Key: MarginRight, DisplayName: Margin Right, FieldType: String, DefaultValue: , Description: Margin Right
#DesignerProperty: Key: MarginTop, DisplayName: Margin Top, FieldType: String, DefaultValue: , Description: Margin Top
#DesignerProperty: Key: MarginBottom, DisplayName: Margin Bottom, FieldType: String, DefaultValue: , Description: Margin Bottom
#DesignerProperty: Key: PaddingLeft, DisplayName: Padding Left, FieldType: String, DefaultValue: , Description: Padding Left
#DesignerProperty: Key: PaddingRight, DisplayName: Padding Right, FieldType: String, DefaultValue: , Description: Padding Right
#DesignerProperty: Key: PaddingTop, DisplayName: Padding Top, FieldType: String, DefaultValue: , Description: Padding Top
#DesignerProperty: Key: PaddingBottom, DisplayName: Padding Bottom, FieldType: String, DefaultValue: , Description: Padding Bottom

#DesignerProperty: Key: OnlyOne, DisplayName: Only one open, FieldType: Boolean, DefaultValue: false, Description: Only allow one panel open at the same time
Sub Class_Globals
    Private BANano As BANano 'ignore
    Private mName As String 'ignore
    Private mEventName As String 'ignore
    Private mCallBack As Object 'ignore
    Private mTarget As BANanoElement 'ignore
    Private mElement As BANanoElement 'ignore
 
 
    Private mClasses As String = ""
    Private mStyle As String = ""
    Public MarginLeft As String = ""
    Public MarginRight As String = ""
    Public MarginTop As String = ""
    Public MarginBottom As String = ""
    Public PaddingLeft As String = ""
    Public PaddingRight As String = ""
    Public PaddingTop As String = ""
    Public PaddingBottom As String = ""
    Private mOnlyOne As Boolean = False
    
    Private Checkeds As Map
End Sub

Public Sub Initialize (CallBack As Object, Name As String, EventName As String)
    mName = Name
    mEventName = EventName.ToLowerCase
    mCallBack = CallBack
    
    Checkeds.Initialize
End Sub

' returns the BANanoElement
public Sub getElement() As BANanoElement
    Return mElement
End Sub

' returns the tag id
public Sub getID() As String
    Return mName
End Sub

' this is the place where you create the view in html and run initialize javascript
Public Sub DesignerCreateView (Target As BANanoElement, Props As Map)
    mTarget = Target

    If Props <> Null Then
        mClasses = Props.Get("Classes")
        mStyle = Props.Get("Style")
        MarginLeft = Props.Get("MarginLeft")
        MarginRight = Props.Get("MarginRight")
        MarginTop = Props.Get("MarginTop")
        MarginBottom = Props.Get("MarginBottom")
        PaddingLeft = Props.Get("PaddingLeft")
        PaddingRight = Props.Get("PaddingRight")
        PaddingTop = Props.Get("PaddingTop")
        PaddingBottom = Props.Get("PaddingBottom")
   
        mOnlyOne = Props.Get("OnlyOne")
    End If
 
    Dim exStyle As String = BuildExStyle
 
    mElement = mTarget.Append($"<div id="${mName}" class="skcoll-tabs ${mClasses}" style="${exStyle}${mStyle}">"$).Get("#" & mName)
End Sub

public Sub AddToParent(targetID As String)
    mTarget = BANano.GetElement("#" & targetID.ToLowerCase)
    DesignerCreateView(mTarget, Null)
End Sub

public Sub Remove()
    mTarget.Empty
    BANano.SetMeToNull
End Sub

public Sub Trigger(event As String, params() As String)
    If mElement <> Null Then
        mElement.Trigger(event, params)
    End If
End Sub

public Sub BuildExStyle() As String
    Dim sb As StringBuilder
    sb.Initialize
    If MarginLeft <> "" Then sb.Append("margin-left: " & MarginLeft & ";")
    If MarginRight <> "" Then sb.Append("margin-right: " & MarginRight & ";")
    If MarginTop <> "" Then sb.Append("margin-top: " & MarginTop & ";")
    If MarginBottom <> "" Then sb.Append("margin-bottom: " & MarginBottom & ";")
    If PaddingLeft <> "" Then sb.Append("padding-left: " & PaddingLeft & ";")
    If PaddingRight <> "" Then sb.Append("padding-right: " & PaddingRight & ";")
    If PaddingTop <> "" Then sb.Append("padding-top: " & PaddingTop & ";")
    If PaddingBottom <> "" Then sb.Append("padding-bottom: " & PaddingBottom & ";")
    Return sb.ToString
End Sub

#Region Property Getters and Setters
public Sub setClasses(Classes As String)
    If mElement <> Null Then
        mElement.AddClass(Classes)
    End If
    mClasses = Classes
End Sub

public Sub getClasses() As String
    Return mClasses
End Sub

public Sub setStyle(Style As String)
    If mElement <> Null Then
        mElement.SetStyle(Style)
    End If
    mStyle = Style
End Sub

public Sub getStyle() As String
    Return mStyle
End Sub
#End Region

' add a new panel. Then use GetHeader and GetContent to fill them
public Sub AddPanel(panelID As String, panelStyle As String, HeaderStyle As String, ContentStyle As String)
    mElement.Append($"[BANCLEAN]
        <div id="${mName}${panelID}" class="skcoll-tab" style="${panelStyle}">
            <label id="${mName}${panelID}header" data-panelid="${panelID}" class="skcoll-tab-header" style="${HeaderStyle}"></label>
            <div id="${mName}${panelID}content" class="skcoll-tab-content"  style="${ContentStyle}">
        </div>"$)    
    Dim mElementHeader As BANanoElement
    mElementHeader.Initialize("#" & mName & panelID & "header")
    Dim event As BANanoEvent    
    Checkeds.Put(panelID, False)
    mElementHeader.AddEventListener("click", BANano.CallBack(Me, "HandleClick", event),True)
End Sub

public Sub GetHeader(PanelID As String) As BANanoElement
    Dim tmpElem As BANanoElement
    tmpElem.Initialize("#" & mName & PanelID & "header")
    Return tmpElem
End Sub

public Sub GetContent(PanelID As String) As BANanoElement
    Dim tmpElem As BANanoElement
    tmpElem.Initialize("#" & mName & PanelID & "content")
    Return tmpElem
End Sub

public Sub setOnlyOneOpen(bool As Boolean)
    mOnlyOne = bool
End Sub

public Sub CloseAllPanels()
    Dim inputs() As BANanoElement = mElement.Find(".skcoll-tab-header")
    For i = 0 To inputs.Length - 1
        Dim panelId As String = inputs(i).GetData("panelid")
        inputs(i).RemoveClass("skcoll-input-checked")            
        Checkeds.Put(panelId, False)        
    Next
End Sub

public Sub OpenPanel(panelId As String)
    If mOnlyOne Then
        Dim inputs() As BANanoElement = mElement.Find(".skcoll-tab-header")
        For i = 0 To inputs.Length - 1
            Dim panelId As String = inputs(i).GetData("panelid")
            inputs(i).RemoveClass("skcoll-input-checked")                
            Checkeds.Put(panelId, False)        
        Next
    End If    
    Dim input As BANanoElement
    input.Initialize("#" & mName & panelId & "header")
    input.AddClass("skcoll-input-checked")
    If mOnlyOne Then
        For Each key As String In Checkeds.Keys
            Checkeds.Put(key, False)
        Next
    End If
    Checkeds.Put(panelId, True)
End Sub

#Region Internal Events
private Sub HandleClick(event As BANanoEvent) 'ignore    
    Dim tmpElem As BANanoElement
    tmpElem.Initialize(event.Target)
    Dim panelID As String = tmpElem.GetData("panelid")
    If panelID = Null Then
        Dim elems() As BANanoElement = tmpElem.Closest("label")
        If elems.Length > 0 Then
            panelID = elems(0).GetData("panelid")
        End If
    End If
    Dim WasOpen As Boolean = Checkeds.Get(panelID)
    If mOnlyOne Then
        Dim inputs() As BANanoElement = mElement.Find(".skcoll-tab-header")
        For i = 0 To inputs.Length - 1
            Dim panelID2 As String = inputs(i).GetData("panelid")
            inputs(i).RemoveClass("skcoll-input-checked")
            Checkeds.Put(panelID2, False)            
        Next
    End If    
    tmpElem.Initialize("#" & mName & panelID & "header")
    If WasOpen = False Then
        tmpElem.AddClass("skcoll-input-checked")
        Checkeds.Put(panelID, True)
    Else
        tmpElem.RemoveClass("skcoll-input-checked")
        Checkeds.Put(panelID, False)
    End If
    BANano.CallSub(mCallBack, mEventName & "_click", Array(panelID))
End Sub
#End Region

#if CSS
.skcoll-input {
  position: absolute;
  opacity: 0;
  z-index: -1;
}
.skcoll-tabs {
  overflow: hidden;
}
.skcoll-tab {
  width: 100%;
  overflow: hidden;
}
.skcoll-tab-header {
  display: flex;
  justify-content: space-between;
  padding: 1em;
  cursor: pointer;
}
.skcoll-tab-header::after {
  content: "❯";
  width: 1em;
  height: 1em;
  text-align: center;
  transition: all 0.35s;
}
.skcoll-tab-content {
  max-height: 0;
  padding: 0 1em;
  transition: all 0.35s;
}
.skcoll-input-checked + .skcoll-tab-header::after {
  transform: rotate(90deg);
}
.skcoll-input-checked ~ .skcoll-tab-content {
  max-height: 100vh;
  padding: 1em;
}
#End If

Alwaysbusy
 
Upvote 0
Solution
Top