Using the BBjDrawer Plugin

BBjDrawer is a custom BBj widget for the DWC (Dynamic Web Client) that allows developers to create a container which slides into the viewport to reveal additional options and information.

There is no limit to the number of drawers an application can create. In such cases, drawers will stack on top of one another.

Installation

Features

  • Easy to set up.

  • Simple to configure options.

  • Supports drawer stacking.

  • Flexible drawer positioning options.

  • Responsive.

  • Supports DWC Dark Mode.

And much more!

The gist

The following example demonstrates how to use the BBjDrawer widget, which provides a container, an instance of BBjChildWindow that can hold any valid BBjControl.

Example 1

use ::BBjDrawer/BBjDrawer.bbj::BBjDrawer

welcomePage! = new BBjDrawer(wnd!)
welcomePage!.setPlacement(BBjDrawer.PLACEMENT_BOTTOM_CENTER)
welcomePage!.setDrawerSize("90vh")

container! = welcomePage!.getContainer()
container!.addStyle("welcome-page")

container!.addImageCtrl("./assets/fun.svg")
container!.addStaticText("<html><h2>Welcome to DWC</h2></html>")
container!.addStaticText("<html><p>Lorem Ipsum is simply dummy.</p></html>")
btn! = container!.addButton("Get Started")
btn!.setCallback(BBjAPI.ON_BUTTON_PUSH,"toggleDrawer")
btn!.setAttribute("theme","primary")
btn!.setAttribute("expanse","l")

welcomePage!.open()

toggleDrawer:
  welcomePage!.toggle()
return

This example demonstrates the layout and functionality of a basic DWC Application.

Example 2

style! = "
: body,html {overflow: hidden}
:
: .dwc-toolbar {
:    display: flex;
:    align-items: center;
:    gap: var(--dwc-space-m);
:    padding: 0 var(--dwc-space-m);
: }
:
: .dwc-logo {
:    display: flex;
:    align-items: center;
:    justify-content: center;
:    padding: var(--dwc-space-m) 0;
:    margin-bottom: var(--dwc-space-m);
:    border-bottom: thin solid var(--dwc-color-default)
: }
:
: .dwc-logo img {
:    max-width: 100px;
: }
:
: .welcome-page {
:    display: flex;
:    flex-direction: column;
:    align-items: center;
:    justify-content: center;
:    padding: var(--dwc-space-2xl);
:    width: 100%;
: }
:
: .welcome-page img {
:    max-height: 300px;
: }
:
: .welcome-page p {
:    text-align: center;
: }
:"

use ::BBjAppLayout/BBjAppLayout.bbj::BBjAppLayout
use ::BBjDrawer/BBjDrawer.bbj::BBjDrawer

web! = BBjAPI().getWebManager()
rem The app should include a viewport meta tag which contains `viewport-fit=cover`, like the following.
rem This causes the viewport to be scaled to fill the device display.
web!.setMeta("viewport", "width=device-width, initial-scale=1.0, viewport-fit=cover, user-scalable=no")
web!.injectStyle(style!, 0)

sysgui! =  BBjAPI().openSysGui("X0")

declare auto BBjWindow wnd! 
wnd! = sysgui!.addWindow("BBjDrawer", $01001000$)
wnd!.setCallback(BBjAPI.ON_CLOSE,"eoj")

declare auto BBjAppLayout app! 
app! = new BBjAppLayout(wnd!)

rem Header
rem ==================
declare auto BBjChildWindow header! 
header! = app!.getHeader()

declare auto BBjChildWindow toolbar! 
toolbar! = header!.addChildWindow("", $00108800$, sysgui!.getAvailableContext())
toolbar!.addStyle("dwc-toolbar")
toolbar!.addStaticText("<html><dwc-icon-button name='menu-2' data-drawer-toggle></dwc-icon-button></html>")
toolbar!.addStaticText("<html><h3>DWC Application</h3></html>")

rem Drawer
rem ==================
declare auto BBjChildWindow drawer! 
drawer! = app!.getDrawer()
drawer!.addStyle("dwc-drawer")

declare auto BBjImageCtrl logo! 
logo! = drawer!.addImageCtrl("./assets/logo.png")
logo!.addStyle("dwc-logo")

declare auto BBjTabCtrl drawerMenu! 
drawerMenu! = drawer!.addTabCtrl()
drawerMenu!.setCallback(drawerMenu!.ON_TAB_SELECT,"onPageChanged")
drawerMenu!.setAttribute("nobody","true")
drawerMenu!.setAttribute("borderless","true")
drawerMenu!.setAttribute("placement","left")
drawerMenu!.addTab("<dwc-icon name='dashboard'></dwc-icon>      Dashboard"    , -1)
drawerMenu!.addTab("<dwc-icon name='shopping-cart'></dwc-icon>  Orders"       , -1)
drawerMenu!.addTab("<dwc-icon name='users'></dwc-icon>          Customers"    , -1)
drawerMenu!.addTab("<dwc-icon name='box'></dwc-icon>            Products"     , -1)
drawerMenu!.addTab("<dwc-icon name='files'></dwc-icon>          Documents"    , -1)
drawerMenu!.addTab("<dwc-icon name='checklist'></dwc-icon>      Tasks"        , -1)
drawerMenu!.addTab("<dwc-icon name='chart-dots-2'></dwc-icon>   Analytics"    , -1)

rem Content
rem ==================
declare auto BBjChildWindow content! 
content! = app!.getContent()
content!.addStaticText("<html><h1>Application Title</h1></html>")
pageContent! = content!.addStaticText("<html><p>Content for Dashboard goes here</p></html>")

btn! = content!.addButton("Open Welcome Page")
btn!.setCallback(BBjAPI.ON_BUTTON_PUSH,"toggleDrawer")

rem Welcome Page
rem ==================
declare auto BBjDrawer welcomePage!
welcomePage! = new BBjDrawer(wnd!)
welcomePage!.setPlacement(BBjDrawer.PLACEMENT_BOTTOM_CENTER)
welcomePage!.setSize("90vh")

declare auto BBjChildWindow content! 
content! = welcomePage!.getContent()
content!.addStyle("welcome-page")
content!.addImageCtrl("./assets/fun.svg")
content!.addStaticText("<html><h2>Welcome to DWC</h2></html>")
content!.addStaticText("<html><p>Lorem Ipsum is simply dummy text of the printing and typesetting industry.</p></html>")
btn! = content!.addButton("Get Started")
btn!.setCallback(BBjAPI.ON_BUTTON_PUSH,"toggleDrawer")
btn!.setAttribute("theme","primary")
btn!.setAttribute("expanse","l")

wait 1
welcomePage!.open()

process_events

onPageChanged:
  event! = sysgui!.getLastEvent() 
  title$ = event!.getTitle().replaceAll("<[^>]*>","").trim()

  pageContent!.setText("<html><p>Content for " + title$ + " goes here</p></html>")
return

toggleDrawer:
  welcomePage!.toggle()
return

eoj:
release

Drawer Placement

BBjDrawer Placement Options:

  • BBjDrawer.PLACEMENT_LEFT

  • BBjDrawer.PLACEMENT_RIGHT

  • BBjDrawer.PLACEMENT_TOP

  • BBjDrawer.PLACEMENT_TOP_CENTER

  • BBjDrawer.PLACEMENT_BOTTOM

  • BBjDrawer.PLACEMENT_BOTTOM_CENTER

Example 3

use ::BBjDrawer/BBjDrawer.bbj::BBjDrawer

welcomePage! = new BBjDrawer(wnd!)
welcomePage!.setPlacement(BBjDrawer.PLACEMENT_BOTTOM_CENTER)

Drawer Sizing

The drawer size can be configured using BBjDrawer methods.

  • BBjDrawer::setDrawerSize(BBjString size!): sets the size of the drawer. If the drawer is placed on the left or right, the value defines its width, if placed on the top or bottom, it defines the height.

  • BBjDrawer::setDrawerMaxSize(BBjString size!): if the drawer is placed on the left or right, the size sets the maximum width, if placed on the top or bottom, it sets the maximum height.

Example 4

use ::BBjDrawer/BBjDrawer.bbj::BBjDrawer

welcomePage! = new BBjDrawer(wnd!)
welcomePage!.setDrawerSize("90vh")

When using drawer BBjDrawer.PLACEMENT_BOTTOM_CENTER or BBjDrawer.PLACEMENT_TOP_CENTER, the maximum width can be set using the CSS custom property --dwc-drawer-max-width. By default, the maximum width is 576px.

Events

The BBjDrawer widget supports three events:

  • ON_OPENED: Fired when the drawer is opened.

  • ON_CLOSED: Fired when the drawer is closed.

  • ON_TOGGLED: Fired when the drawer is toggled.

The event's payload is an instance of ::BBjDrawer/BBjDrawer.bbj::BBjDrawerEvent.

Example 5

use ::BBjDrawer/BBjDrawer.bbj::BBjDrawer
use ::BBjDrawer/BBjDrawer.bbj::BBjDrawerEvent

drawer! = new BBjDrawer(wnd!)
drawer!.setCallback(BBjDrawer.ON_TOGGLED, "onDrawerToggled")

onDrawerToggled:
  declare auto BBjDrawerEvent payload!
  event! = sysgui!.getLastEvent()
  payload! = event!.getObject()

  let x = MSGBOX("Is Opened = " + str(payload!.isOpened()), 0, "Drawer Toggled")
return

Contact Picker Sample

The following example demonstrates how to use the BBjDrawer widget to build a contact picker based on ChileCompany customer data.

Example 6

style! = "
: .root {
:   display: flex;
:   align-items: center;
:   justify-content: center;
:   width: 100vw;
:   height: 100vh;
: }
:  
: .contactsList {
:   padding: var(--dwc-space-m);
: }
:
: .bookEntry {
:   display: flex;
:   gap: 1rem;
:   align-items: center;
:   padding: var(--dwc-space-s);
:   cursor: var(--dwc-cursor-click);
:   transition: background-color var(--dwc-transition);
:   border-bottom: thin solid var(--dwc-color-default) !important;
: }
:
: .bookEntry:hover {
:   background-color: var(--dwc-color-primary-alt);
: }
:
: .bookEntry__avatar {
:   display: flex;
:   align-items: center;
:   width: var(--dwc-size-l);
:   height: var(--dwc-size-l);
:   border-radius: var(--dwc-border-radius-round);
: }
:
: .bookEntry__avatar img {
:   width: 100%;
:   height: 100%;
: }
:
: .bookEntry__info {
:   flex: 1;
:   display: flex;
:   flex-direction: column;
: }
:
: .bookEntry__location {
:   font-size: var(--dwc-font-size-s);
:   color: var(--dwc-color-default-text);
: }  
:"

use ::BBjDrawer/BBjDrawer.bbj::BBjDrawer
use com.basiscomponents.db.ResultSet
use com.basiscomponents.bc.SqlQueryBC

web! = BBjAPI().getWebManager()
web!.injectStyle(style!, 0)

sysgui! =  BBjAPI().openSysGui("X0")

declare auto BBjWindow wnd! 
wnd! = sysgui!.addWindow("BBjDrawer", $01101000$)
wnd!.addPanelStyle("root")
wnd!.setCallback(BBjAPI.ON_CLOSE,"eoj")

declare auto BBjButton contactsButton! 
contactsButton! = wnd!.addButton("Open Contacts Picker")
contactsButton!.setCallback(BBjAPI.ON_BUTTON_PUSH,"onOpenContactsDrawer")
contactsButton!.setAttribute("theme", "primary")
contactsButton!.setAttribute("expanse", "l")

rem Contacts Drawer
rem ==================
declare auto BBjDrawer contactsDrawer! 
contactsDrawer! = new BBjDrawer(wnd!)
contactsDrawer!.setPlacement(BBjDrawer.PLACEMENT_BOTTOM_CENTER)
contactsDrawer!.setSize("70vh")

declare auto BBjChildWindow contactsDrawer! 
content! = contactsDrawer!.getContent()
content!.addStyle("contactsList")

sql! = new SqlQueryBC(BBjAPI().getJDBCConnection("ChileCompany"))
items! = sql!.retrieve("SELECT * FROM CUSTOMER")
iterator! = items!.iterator()

while iterator!.hasNext()
  item! = iterator!.next()
  firstName! = item!.getField("FIRST_NAME").getString().trim()
  lastName! = item!.getField("LAST_NAME").getString().trim()
  fullName! = firstName! + " " + lastName!
  phone! = item!.getField("PHONE").getString().trim()
  country! = item!.getField("COUNTRY").getString().trim()
  city! = item!.getField("CITY").getString().trim()
  fullLocation! = country! + " - " + city!

  card! = content!.addChildWindow("", $00108800$, sysgui!.getAvailableContext())
  card!.addStyle("bookEntry")

  avatarContent! = "<html><img src=""https://ui-avatars.com/api/?name=" + fullName! + "&&background=random"" /></html>"
  avatar! = card!.addStaticText(avatarContent!)
  avatar!.addStyle("bookEntry__avatar")

  info! = card!.addChildWindow("", $00108800$, sysgui!.getAvailableContext())
  info!.addStyle("bookEntry__info")

  name! = info!.addStaticText(fullName!)
  name!.addStyle("bookEntry__name")

  location! = info!.addStaticText(fullLocation!)
  location!.addStyle("bookEntry__location")

  call! = card!.addButton("<html><dwc-icon name=""phone""></dwc-icon></html>")
  call!.setEnabled(len(phone!) > 0)
  call!.setUserData(phone!)
  call!.setCallback(call!.ON_BUTTON_PUSH, "onCall")
wend

wait 1
contactsDrawer!.open()

process_events

onOpenContactsDrawer:
  contactsDrawer!.open()
return

onCall:
  contactsDrawer!.close()
  
  ev! = BBjAPI().getLastEvent()
  control! = ev!.getControl()
  phone! = str(control!.getUserData())
  script! = "" +
:    "(() => {" +
:    " const link = document.createElement('a');" +
:    " link.href='tel:" + phone! + "';" +
:    " link.style.visibility='hidden';" +
:    " document.body.appendChild(link);" +
:    " link.click();" +
:    " document.body.removeChild(link)" +
:    "})()"
  BBjAPI().getSysGui().executeScript(script!)
return

eoj:
release