MaterialSB/MaterialSB.sbi
2026-01-24 21:36:45 +01:00

1678 lines
44 KiB
Plaintext

; MaterialSB - A MaterializeCSS wrapper for SpiderBasic
;
; This library replaces SpiderBasic's default UI with MaterializeCSS components.
; Components are designed to closely match their Materialize equivalents.
;
; Usage:
; IncludeFile "MaterialSB/MaterialSB.sbi"
; MaterialSB::Download(@MyCallback())
;
; For documentation, see: https://materializeweb.com/
DeclareModule MaterialSB
;{ Initialization
Declare Download(*callback)
Declare AutoInit()
Declare Init(Element, Options)
;}
;{ Parent Management
Declare CloseCurrentParent(depth = 1)
Declare GetCurrentParent()
Declare SetCurrentParent(Parent)
;}
;{ HTML Helpers
Declare.s Paragraph(Text.s, Color.s = "")
Declare.s Paragraph_ex(Text.s, Class.s = "", Style.s = "")
Declare.s Header(Text.s, Level, Color.s = "")
Declare.s Header_ex(Text.s, Level, Class.s = "", Style.s = "")
Declare Append(Content.s, Parent = #Null)
Declare.s Link(Text.s, *Callback, Color.s = "")
Declare.s Link_ex(Text.s, *Callback, Class.s = "", Style.s = "")
;}
;{ Element Manipulation
Declare SetAttribute(Element, Attribute.s, Value.s)
Declare SetClass(Element, Class.s)
Declare SetContent(Element, Content.s)
Declare AddClass(Element, Class.s)
Declare AddContent(Element, Content.s)
Declare GetValue(Element)
Declare SetValue(Element, Value.s)
;}
;{ Theme
Declare GetDarkThemeState()
Declare SetDarkTheme(State)
;}
;{ Style Constants
#Class_Hide_On_Small_Only = "hide-on-small-only"
#Class_Hide_On_Small_And_Down = "hide-on-small-and-down"
#Class_Hide_On_Med_And_Down = "hide-on-med-and-down"
#Class_Hide_On_Med_And_Up = "hide-on-med-and-up"
#Class_Hide_On_Med_Only = "hide-on-med-only"
#Class_Hide_On_Large_Only = "hide-on-large-only"
#Class_Show_On_Large = "show-on-large"
#Class_Show_On_Medium = "show-on-medium"
#Class_Show_On_Small = "show-on-small"
#Class_Show_On_Medium_And_Up = "show-on-medium-and-up"
#Class_Show_On_Medium_And_Down = "show-on-medium-and-down"
#Class_Pulse = "pulse"
#Class_Centered = "center-align"
#Class_LeftAlign = "left-align"
#Class_RightAlign = "right-align"
;}
;{ Color Constants
; Base colors
#Color_Red = "red"
#Color_Pink = "pink"
#Color_Purple = "purple"
#Color_DeepPurple = "deep-purple"
#Color_Indigo = "indigo"
#Color_Blue = "blue"
#Color_LightBlue = "light-blue"
#Color_Cyan = "cyan"
#Color_Teal = "teal"
#Color_Green = "green"
#Color_LightGreen = "light-green"
#Color_Lime = "lime"
#Color_Yellow = "yellow"
#Color_Amber = "amber"
#Color_Orange = "orange"
#Color_DeepOrange = "deep-orange"
#Color_Brown = "brown"
#Color_Grey = "grey"
#Color_BlueGrey = "blue-grey"
#Color_Black = "black"
#Color_White = "white"
#Color_Transparent = "transparent"
; Color modifiers (append to base color)
#Color_Lighten_5 = " lighten-5"
#Color_Lighten_4 = " lighten-4"
#Color_Lighten_3 = " lighten-3"
#Color_Lighten_2 = " lighten-2"
#Color_Lighten_1 = " lighten-1"
#Color_Darken_1 = " darken-1"
#Color_Darken_2 = " darken-2"
#Color_Darken_3 = " darken-3"
#Color_Darken_4 = " darken-4"
#Color_Accent_1 = " accent-1"
#Color_Accent_2 = " accent-2"
#Color_Accent_3 = " accent-3"
#Color_Accent_4 = " accent-4"
#Color_Text = "-text"
;}
;{ Navbar
EnumerationBinary NavbarFlags
#Navbar_Default = 0
#Navbar_Align_Right = 1
#Navbar_Align_Center
#Navbar_Bottom
#Navbar_Shadow1
#Navbar_Shadow2
#Navbar_Shadow3
#Navbar_Container
EndEnumeration
Declare Navbar(Flags = #Navbar_Default)
Declare NavbarAddLogo(Text.s, ImagePath.s = "", Link.s = "", Flags = #Navbar_Default, Parent = #Null)
Declare NavbarAddLink(Text.s, Link.s, Parent = #Null)
Declare NavbarAddSidenavTrigger(SidenavID.s, Parent = #Null)
;}
;{ Sidenav
EnumerationBinary SidenavFlags
#Sidenav_Default = 0
#Sidenav_Fixed = 1
#Sidenav_Right
#Sidenav_CloseOnClick
EndEnumeration
Declare Sidenav(Flags = #Sidenav_Default)
Declare SidenavAddLink(Text.s, Link.s, Icon.s = "", Parent = #Null)
Declare SidenavAddDivider(Parent = #Null)
Declare SidenavAddSubheader(Text.s, Parent = #Null)
Declare SidenavAddUserView(Name.s, Email.s, AvatarPath.s = "", BackgroundPath.s = "", Parent = #Null)
;}
;{ Grid
EnumerationBinary GridFlags
#Grid_Default = 0
#Grid_Container = 1
EndEnumeration
Declare Row(Flags = #Grid_Default, Parent = #Null)
Declare Col(S, M = 0, L = 0, XL = 0, Flags = #Grid_Default, Parent = #Null)
;}
;{ Media
EnumerationBinary MediaFlags
#Media_Default = 0
#Media_Responsive = 1
#Media_Circle
#Media_Controls
EndEnumeration
Declare Image(Source.s, Alt.s = "", Flags = #Media_Default, Parent = #Null)
Declare Video(Source.s, Type.s = "video/mp4", Flags = #Media_Default, Parent = #Null)
Declare YoutubeVideo(Source.s, Flags = #Media_Default, Parent = #Null)
;}
;{ Table
EnumerationBinary TableFlags
#Table_Default = 0
#Table_Striped = 1
#Table_Highlight
#Table_Centered
#Table_Responsive
EndEnumeration
Declare Table(Title.s, Flags = #Table_Default, Parent = #Null)
Declare TableAddColumn(Title.s, Table)
Declare TableAddItem(Text.s, Table)
Declare TableSetText(Text.s, Item, ColumnIndex)
;}
;{ Button
EnumerationBinary ButtonFlags
#Button_Default = 0
#Button_Tonal = 1
#Button_Outlined
#Button_Elevated
#Button_Text
#Button_Floating
#Button_Large
#Button_Small
#Button_IconLeft
#Button_Disabled
EndEnumeration
Declare Button(Text.s, *Callback, Flags = #Button_Default, Parent = #Null)
Declare ButtonSetCallback(Button, *Callback)
;}
;{ Card
EnumerationBinary CardFlags
#Card_Default = 0
#Card_Panel = 1
#Card_Small
#Card_Medium
#Card_Large
#Card_Horizontal
EndEnumeration
Declare Card(Text.s = "", Flags = #Card_Default, Parent = #Null)
Declare CardImage(Source.s, Parent = #Null)
Declare CardContent(Parent = #Null)
Declare CardTitle(Text.s, Parent = #Null)
Declare CardAction(Parent = #Null)
;}
;{ Carousel
EnumerationBinary CarouselFlags
#Carousel_Default = 0
#Carousel_Slider = 1
EndEnumeration
Declare Carousel(Flags = #Carousel_Default, Parent = #Null)
Declare CarouselAddItem(Carousel, ImageSource.s, Link.s)
;}
;{ Tabs
EnumerationBinary TabFlags
#Tab_Default = 0
#Tab_Disabled = 1
EndEnumeration
Declare Tab(Flags = #Tab_Default, Parent = #Null)
Declare TabAddItem(Title.s, Tab, ID.s, Flags = #Tab_Default)
;}
;{ Modal
EnumerationBinary ModalFlags
#Modal_Default = 0
#Modal_FixedFooter = 1
#Modal_BottomSheet
#Modal_Dismissible
EndEnumeration
Declare Modal(Flags = #Modal_Default)
Declare ModalHeader(Text.s, Parent = #Null)
Declare ModalContent(Parent = #Null)
Declare ModalFooter(Parent = #Null)
Declare ModalOpen(ModalElement)
Declare ModalClose(ModalElement)
;}
;{ Toast
EnumerationBinary ToastFlags
#Toast_Default = 0
#Toast_Rounded = 1
EndEnumeration
Declare Toast(Text.s, Duration = 4000, Flags = #Toast_Default, Color.s = "")
Declare ToastDismissAll()
;}
;{ Forms
EnumerationBinary InputFlags
#Input_Default = 0
#Input_Outlined = 1
#Input_Password
#Input_Email
#Input_Number
#Input_Tel
#Input_Url
#Input_Date
#Input_Time
#Input_Disabled
#Input_Readonly
EndEnumeration
EnumerationBinary TextareaFlags
#Textarea_Default = 0
#Textarea_Outlined = 1
#Textarea_Disabled
#Textarea_Readonly
EndEnumeration
EnumerationBinary CheckboxFlags
#Checkbox_Default = 0
#Checkbox_Filled = 1
#Checkbox_Checked
#Checkbox_Disabled
EndEnumeration
EnumerationBinary RadioFlags
#Radio_Default = 0
#Radio_WithGap = 1
#Radio_Checked
#Radio_Disabled
EndEnumeration
EnumerationBinary SwitchFlags
#Switch_Default = 0
#Switch_Checked = 1
#Switch_Disabled
EndEnumeration
EnumerationBinary SelectFlags
#Dropdown_Default = 0
#Dropdown_Outlined = 1
#Dropdown_Multiple
#Dropdown_Disabled
EndEnumeration
EnumerationBinary RangeFlags
#Range_Default = 0
#Range_Disabled = 1
EndEnumeration
Declare TextInput(Label.s = "", Placeholder.s = "", Flags = #Input_Default, Parent = #Null)
Declare Textarea(Label.s = "", Placeholder.s = "", Flags = #Textarea_Default, Parent = #Null)
Declare Checkbox(Label.s, Flags = #Checkbox_Default, Parent = #Null)
Declare Radio(Name.s, Label.s, Flags = #Radio_Default, Parent = #Null)
Declare Switch(LabelOff.s, LabelOn.s, Flags = #Switch_Default, Parent = #Null)
Declare Dropdown(Label.s = "", Flags = #Dropdown_Default, Parent = #Null)
Declare DropdownAddOption(Text.s, Value.s, DropdownElement, Selected = #False)
Declare Range(Min = 0, Max = 100, Value = 50, Flags = #Range_Default, Parent = #Null)
Declare InputSetCallback(InputElement, *Callback)
;}
EndDeclareModule
Module MaterialSB
EnableExplicit
;{ Private Variables
Global download_callback
Global current_parent
Global current_navbar
Global current_sidenav
Global current_modal
Global dropdown_menu_index = 0
Global input_id_counter = 0
Global NewList parent_list()
;}
;{ Private Macros
Macro CheckParent()
If Parent = #Null
If current_parent = #Null
!materialsb$g_current_parent = document.body.firstElementChild;
EndIf
Parent = current_parent
EndIf
EndMacro
Macro PushParent()
AddElement(parent_list())
parent_list() = current_parent
EndMacro
;}
;{ Private Declarations
Declare Handler_Download(url.s, success)
;}
;===========================================================================
; Initialization
;===========================================================================
Procedure Download(*callback)
download_callback = *callback
LoadScript("LocalFiles/CSS/materialize.min.css", @Handler_Download(), #PB_Script_CSS)
EndProcedure
Procedure AutoInit()
!M.AutoInit();
EndProcedure
Procedure Init(Element, Options)
Protected check
!v_check = v_element.matches(".carousel");
If check
!M.Carousel.init(v_element, v_options);
ProcedureReturn #True
EndIf
!v_check = v_element.matches("select");
If check
!M.FormSelect.init(v_element, v_options);
ProcedureReturn #True
EndIf
!v_check = v_element.matches(".sidenav");
If check
!M.Sidenav.init(v_element, v_options);
ProcedureReturn #True
EndIf
!v_check = v_element.matches(".modal");
If check
!M.Modal.init(v_element, v_options);
ProcedureReturn #True
EndIf
ProcedureReturn #False
EndProcedure
;===========================================================================
; Parent Management
;===========================================================================
Procedure CloseCurrentParent(depth = 1)
While depth > 0 And ListSize(parent_list())
current_parent = parent_list()
DeleteElement(parent_list())
depth - 1
Wend
ProcedureReturn current_parent
EndProcedure
Procedure GetCurrentParent()
ProcedureReturn current_parent
EndProcedure
Procedure SetCurrentParent(Parent)
PushParent()
current_parent = Parent
ProcedureReturn current_parent
EndProcedure
;===========================================================================
; HTML Helpers
;===========================================================================
Procedure.s Paragraph(Text.s, Color.s = "")
Protected Result.s, Count = CountString(Text, ~"\n") + 1, i
If Color = ""
Result = "<p>"
Else
Result = ~"<p class=\"" + Color + ~"-text\">"
EndIf
Result + StringField(Text, 1, ~"\n")
For i = 2 To Count
Result + "<br>" + StringField(Text, i, ~"\n")
Next
ProcedureReturn Result + "</p>"
EndProcedure
Procedure.s Paragraph_ex(Text.s, Class.s = "", Style.s = "")
Protected Result.s = "<p", Count = CountString(Text, ~"\n") + 1, i
If Class <> ""
Result + ~" class=\"" + Class + ~"\""
EndIf
If Style <> ""
Result + ~" style=\"" + Style + ~"\""
EndIf
Result + ">"
Result + StringField(Text, 1, ~"\n")
For i = 2 To Count
Result + "<br>" + StringField(Text, i, ~"\n")
Next
ProcedureReturn Result + "</p>"
EndProcedure
Procedure.s Header(Text.s, Level, Color.s = "")
Protected Result.s = "<h" + Str(Level)
If Color <> ""
Result + ~" class=\"" + Color + ~"-text\""
EndIf
ProcedureReturn Result + ">" + Text + "</h" + Str(Level) + ">"
EndProcedure
Procedure.s Header_ex(Text.s, Level, Class.s = "", Style.s = "")
Protected Result.s = "<h" + Str(Level)
If Class <> ""
Result + ~" class=\"" + Class + ~"\""
EndIf
If Style <> ""
Result + ~" style=\"" + Style + ~"\""
EndIf
ProcedureReturn Result + ">" + Text + "</h" + Str(Level) + ">"
EndProcedure
Procedure Append(Content.s, Parent = #Null)
CheckParent()
!v_parent.innerHTML += v_content;
EndProcedure
Procedure.s Link(Text.s, *Callback, Color.s = "")
Protected Result.s, Callback.s, Pos
If Color <> ""
Color = ~" class=\"" + Color + ~"-text\""
EndIf
If *Callback = #Null
Result = ~"<a href=\"#\"" + Color + ">"
Else
; A very hacky approach to to approach native SB behavior: we need to get the name of the function out of the callback
! v_callback = String(p_callback);
Pos = FindString(Callback, "(") - 10
Callback = Mid(Callback, 10, Pos)
Result = ~"<a href=\"#\" onclick=\"" + Callback + ~"()\"" + Color + ">"
EndIf
Result + Text + "</a>"
ProcedureReturn Result
EndProcedure
Procedure.s Link_ex(Text.s, *Callback, Class.s = "", Style.s = "")
Protected Result.s = ~"<a href=\"#\"", Callback.s, Pos
If Class <> ""
Result + ~" class=\"" + Class + ~"\""
EndIf
If Style <> ""
Result + ~" style=\"" + Style + ~"\""
EndIf
If *Callback <> #Null
; A very hacky approach to approach native SB behavior: we need to get the name of the function out of the callback
! v_callback = String(p_callback);
Pos = FindString(Callback, "(") - 10
Callback = Mid(Callback, 10, Pos)
Result + ~" onclick=\"" + Callback + ~"()\""
EndIf
Result + ">" + Text + "</a>"
ProcedureReturn Result
EndProcedure
;===========================================================================
; Element Manipulation
;===========================================================================
Procedure SetAttribute(Element, Attribute.s, Value.s)
!v_element.setAttribute(v_attribute, v_value);
EndProcedure
Procedure SetClass(Element, Class.s)
!v_element.className = v_class;
EndProcedure
Procedure SetContent(Element, Content.s)
!v_element.innerHTML = v_content;
EndProcedure
Procedure AddClass(Element, Class.s)
Protected Count = CountString(Class, " ") + 1, i, ClassName.s
For i = 1 To Count
ClassName = StringField(Class, i, " ")
!v_element.classList.add(v_classname);
Next
EndProcedure
Procedure AddContent(Element, Content.s)
!v_element.insertAdjacentHTML('beforeend', v_content);
EndProcedure
Procedure GetValue(Element)
Protected Result
!v_result = v_element.value;
ProcedureReturn Result
EndProcedure
Procedure SetValue(Element, Value.s)
!v_element.value = v_value;
EndProcedure
;===========================================================================
; Theme
;===========================================================================
Procedure GetDarkThemeState()
Protected theme.s
!v_theme = document.documentElement.getAttribute("theme");
ProcedureReturn Bool(theme = "dark")
EndProcedure
Procedure SetDarkTheme(State)
If Bool(State) <> GetDarkThemeState()
If State
!document.documentElement.setAttribute("theme", "dark");
Else
!document.documentElement.setAttribute("theme", "light");
EndIf
EndIf
EndProcedure
;===========================================================================
; Navbar
;===========================================================================
Procedure Navbar(Flags = #Navbar_Default)
Protected Wrapper
!materialsb$g_current_navbar = document.createElement('nav');
If Flags & #Navbar_Bottom
!materialsb$g_current_navbar.style.position = "absolute";
!materialsb$g_current_navbar.style.bottom = "0";
EndIf
If Flags & #Navbar_Shadow1
!materialsb$g_current_navbar.classList.add("z-depth-1");
ElseIf Flags & #Navbar_Shadow2
!materialsb$g_current_navbar.classList.add("z-depth-2");
ElseIf Flags & #Navbar_Shadow3
!materialsb$g_current_navbar.classList.add("z-depth-5");
EndIf
!v_wrapper = document.createElement('div');
!v_wrapper.className = "nav-wrapper";
If Flags & #Navbar_Container
!v_wrapper.classList.add("container");
EndIf
!materialsb$g_current_navbar.append(v_wrapper);
!document.body.prepend(materialsb$g_current_navbar);
ProcedureReturn Wrapper
EndProcedure
Procedure NavbarAddLogo(Text.s, ImagePath.s = "", Link.s = "", Flags = #Navbar_Default, Parent = #Null)
Protected Logo
If Parent = #Null
!v_parent = materialsb$g_current_navbar.firstElementChild;
Else
!v_parent = v_parent.firstElementChild;
EndIf
If ImagePath <> ""
!v_text = '<img src="' + v_imagepath + '" alt="' + v_text + '">';
EndIf
If Link = ""
!v_parent.innerHTML += '<a class="brand-logo">' + v_text + '</a>';
Else
!v_parent.innerHTML += '<a href="' + v_link + '" class="brand-logo">' + v_text + '</a>';
EndIf
!v_logo = v_parent.lastElementChild;
If Flags & #Navbar_Align_Center
!v_logo.classList.add("center");
ElseIf Flags & #Navbar_Align_Right
!v_logo.classList.add("right");
; Remove right alignment from any existing UL elements
!for (const child of v_parent.children) {
! if (child.tagName === 'UL') child.classList.remove("right");
!}
EndIf
ProcedureReturn Logo
EndProcedure
Procedure NavbarAddLink(Text.s, Link.s, Parent = #Null)
Protected LinkElement
If Parent = #Null
!v_parent = materialsb$g_current_navbar.firstElementChild;
EndIf
; Find existing list elements
!var _list = null, _dropdown = null;
!for (const child of v_parent.children) {
! if (child.tagName === 'UL' && child.classList.contains("hide-on-med-and-down")) _list = child;
! if (child.tagName === 'UL' && child.classList.contains("dropdown-content")) _dropdown = child;
!}
; Create lists if this is the first link
!if (_list === null) {
! var _rightLogo = false;
! for (const child of v_parent.children) {
! if (child.tagName === 'A' && child.classList.contains("right")) { _rightLogo = true; break; }
! }
! var _menuId = 'materialsb_dropdown' + materialsb$g_dropdown_menu_index;
! v_parent.innerHTML += '<ul id="' + _menuId + '" class="dropdown-content"><li><a href="' + v_link + '">' + v_text + '</a></li></ul>';
! if (_rightLogo) {
! v_parent.innerHTML += '<ul class="hide-on-large-only"><li><a class="dropdown-trigger" href="#!" data-target="' + _menuId + '"><i class="material-icons">menu</i></a></li></ul>';
! v_parent.innerHTML += '<ul class="hide-on-med-and-down"><li><a href="' + v_link + '">' + v_text + '</a></li></ul>';
! } else {
! v_parent.innerHTML += '<ul class="hide-on-large-only right"><li><a class="dropdown-trigger" href="#!" data-target="' + _menuId + '"><i class="material-icons">menu</i></a></li></ul>';
! v_parent.innerHTML += '<ul class="hide-on-med-and-down right"><li><a href="' + v_link + '">' + v_text + '</a></li></ul>';
! }
! v_linkelement = v_parent.lastElementChild.lastElementChild;
!} else {
! _list.innerHTML += '<li><a href="' + v_link + '">' + v_text + '</a></li>';
! _dropdown.innerHTML += '<li><a href="' + v_link + '">' + v_text + '</a></li>';
! v_linkelement = _list.lastElementChild;
!}
dropdown_menu_index + 1
ProcedureReturn LinkElement
EndProcedure
Procedure NavbarAddSidenavTrigger(SidenavID.s, Parent = #Null)
Protected Trigger
If Parent = #Null
!v_parent = materialsb$g_current_navbar.firstElementChild;
EndIf
!v_trigger = document.createElement('a');
!v_trigger.href = "#";
!v_trigger.setAttribute('data-target', v_sidenavid);
!v_trigger.className = "sidenav-trigger";
!v_trigger.innerHTML = '<i class="material-icons">menu</i>';
!v_parent.prepend(v_trigger);
ProcedureReturn Trigger
EndProcedure
;===========================================================================
; Sidenav
;===========================================================================
Procedure Sidenav(Flags = #Sidenav_Default)
!materialsb$g_current_sidenav = document.createElement('ul');
!materialsb$g_current_sidenav.className = "sidenav";
If Flags & #Sidenav_Fixed
!materialsb$g_current_sidenav.classList.add("sidenav-fixed");
EndIf
; Sidenav must be added to body, not inside navbar
!document.body.append(materialsb$g_current_sidenav);
ProcedureReturn current_sidenav
EndProcedure
Procedure SidenavAddLink(Text.s, Link.s, Icon.s = "", Parent = #Null)
Protected Result
If Parent = #Null
!v_parent = materialsb$g_current_sidenav;
EndIf
!v_result = document.createElement('li');
If Icon <> ""
!v_result.innerHTML = '<a href="' + v_link + '"><i class="material-icons">' + v_icon + '</i>' + v_text + '</a>';
Else
!v_result.innerHTML = '<a href="' + v_link + '">' + v_text + '</a>';
EndIf
!v_parent.append(v_result);
ProcedureReturn Result
EndProcedure
Procedure SidenavAddDivider(Parent = #Null)
Protected Result
If Parent = #Null
!v_parent = materialsb$g_current_sidenav;
EndIf
!v_result = document.createElement('li');
!v_result.innerHTML = '<div class="divider"></div>';
!v_parent.append(v_result);
ProcedureReturn Result
EndProcedure
Procedure SidenavAddSubheader(Text.s, Parent = #Null)
Protected Result
If Parent = #Null
!v_parent = materialsb$g_current_sidenav;
EndIf
!v_result = document.createElement('li');
!v_result.innerHTML = '<a class="subheader">' + v_text + '</a>';
!v_parent.append(v_result);
ProcedureReturn Result
EndProcedure
Procedure SidenavAddUserView(Name.s, Email.s, AvatarPath.s = "", BackgroundPath.s = "", Parent = #Null)
Protected Result
If Parent = #Null
!v_parent = materialsb$g_current_sidenav;
EndIf
!v_result = document.createElement('li');
!var _userView = document.createElement('div');
!_userView.className = "user-view";
; Background
If BackgroundPath <> ""
!var _bg = document.createElement('div');
!_bg.className = "background";
!_bg.innerHTML = '<img src="' + v_backgroundpath + '">';
!_userView.append(_bg);
EndIf
; Avatar
If AvatarPath <> ""
!var _avatar = document.createElement('a');
!_avatar.href = "#user";
!_avatar.innerHTML = '<img class="circle" src="' + v_avatarpath + '">';
!_userView.append(_avatar);
EndIf
; Name
If Name <> ""
!var _name = document.createElement('a');
!_name.href = "#name";
!_name.innerHTML = '<span class="white-text name">' + v_name + '</span>';
!_userView.append(_name);
EndIf
; Email
If Email <> ""
!var _email = document.createElement('a');
!_email.href = "#email";
!_email.innerHTML = '<span class="white-text email">' + v_email + '</span>';
!_userView.append(_email);
EndIf
!v_result.append(_userView);
!v_parent.append(v_result);
ProcedureReturn Result
EndProcedure
;===========================================================================
; Grid
;===========================================================================
Procedure Row(Flags = #Grid_Default, Parent = #Null)
CheckParent()
PushParent()
!materialsb$g_current_parent = document.createElement('div');
!materialsb$g_current_parent.className = "row";
If Flags & #Grid_Container
!materialsb$g_current_parent.classList.add("container");
EndIf
!v_parent.append(materialsb$g_current_parent);
ProcedureReturn current_parent
EndProcedure
Procedure Col(S, M = 0, L = 0, XL = 0, Flags = #Grid_Default, Parent = #Null)
CheckParent()
PushParent()
!materialsb$g_current_parent = document.createElement('div');
!materialsb$g_current_parent.className = "col s" + v_s;
If M
!materialsb$g_current_parent.classList.add("m" + v_m);
EndIf
If L
!materialsb$g_current_parent.classList.add("l" + v_l);
EndIf
If XL
!materialsb$g_current_parent.classList.add("xl" + v_xl);
EndIf
If Flags & #Grid_Container
!materialsb$g_current_parent.classList.add("container");
EndIf
!v_parent.append(materialsb$g_current_parent);
ProcedureReturn current_parent
EndProcedure
;===========================================================================
; Media
;===========================================================================
Procedure Image(Source.s, Alt.s = "", Flags = #Media_Default, Parent = #Null)
Protected Result
CheckParent()
!v_result = document.createElement('img');
!v_result.src = v_source;
!v_result.alt = v_alt;
If Flags & #Media_Circle
!v_result.classList.add("circle");
EndIf
If Flags & #Media_Responsive
!v_result.classList.add("responsive-img");
EndIf
!v_parent.append(v_result);
ProcedureReturn Result
EndProcedure
Procedure Video(Source.s, Type.s = "video/mp4", Flags = #Media_Default, Parent = #Null)
Protected Result
CheckParent()
!v_result = document.createElement('video');
!v_result.innerHTML = '<source src="' + v_source + '" type="' + v_type + '">';
If Flags & #Media_Controls
!v_result.controls = true;
EndIf
If Flags & #Media_Responsive
!v_result.classList.add("responsive-video");
EndIf
!v_parent.append(v_result);
ProcedureReturn Result
EndProcedure
Procedure YoutubeVideo(Source.s, Flags = #Media_Default, Parent = #Null)
Protected Result
CheckParent()
!v_result = document.createElement('div');
If Flags & #Media_Responsive
!v_result.classList.add("video-container");
EndIf
!v_result.innerHTML = '<iframe src="' + v_source + '" frameborder="0" allowfullscreen></iframe>';
!v_parent.append(v_result);
ProcedureReturn Result
EndProcedure
;===========================================================================
; Table
;===========================================================================
Procedure Table(Title.s, Flags = #Table_Default, Parent = #Null)
Protected Result
CheckParent()
!v_result = document.createElement('table');
!var _thead = document.createElement('thead');
!var _tr = document.createElement('tr');
!var _th = document.createElement('th');
!_th.innerHTML = v_title;
!var _tbody = document.createElement('tbody');
If Flags & #Table_Striped
!v_result.classList.add("striped");
EndIf
If Flags & #Table_Highlight
!v_result.classList.add("highlight");
EndIf
If Flags & #Table_Centered
!v_result.classList.add("centered");
EndIf
If Flags & #Table_Responsive
!v_result.classList.add("responsive-table");
EndIf
!_tr.append(_th);
!_thead.append(_tr);
!v_result.append(_thead);
!v_result.append(_tbody);
!v_parent.append(v_result);
ProcedureReturn Result
EndProcedure
Procedure TableAddColumn(Title.s, Table)
Protected Result
!v_result = document.createElement('th');
!v_result.innerHTML = v_title;
!v_table.firstChild.firstChild.append(v_result);
ProcedureReturn Result
EndProcedure
Procedure TableAddItem(Text.s, Table)
Protected Result, Count, i, ColumnText.s
!v_result = document.createElement('tr');
!v_count = Math.min(v_table.firstChild.firstChild.childElementCount, v_text.split('\n').length);
For i = 1 To Count
ColumnText = StringField(Text, i, Chr(10))
!var _td = document.createElement('td');
!_td.innerHTML = v_columntext;
!v_result.append(_td);
Next
!v_table.lastChild.append(v_result);
ProcedureReturn Result
EndProcedure
Procedure TableSetText(Text.s, Item, ColumnIndex)
Protected Count
!v_count = v_item.childElementCount;
While Count < (ColumnIndex + 1)
!v_item.append(document.createElement('td'));
Count + 1
Wend
!v_item.children[v_columnindex].innerHTML = v_text;
EndProcedure
;===========================================================================
; Button
;===========================================================================
Procedure Button(Text.s, *Callback, Flags = #Button_Default, Parent = #Null)
Protected Result
CheckParent()
!v_result = document.createElement('a');
!v_result.innerHTML = v_text;
!v_result.tabIndex = 0;
; Button size
Select #True
Case Bool(Flags & #Button_Floating)
!v_result.classList.add("btn-floating");
Case Bool(Flags & #Button_Large)
!v_result.classList.add("btn-large");
Case Bool(Flags & #Button_Small)
!v_result.classList.add("btn-small");
Default
!v_result.classList.add("btn");
EndSelect
; Button variant
Select #True
Case Bool(Flags & #Button_Tonal)
!v_result.classList.add("tonal");
Case Bool(Flags & #Button_Outlined)
!v_result.classList.add("outlined");
Case Bool(Flags & #Button_Elevated)
!v_result.classList.add("elevated");
Case Bool(Flags & #Button_Text)
!v_result.classList.add("text");
Default
!v_result.classList.add("filled");
EndSelect
If Flags & #Button_Disabled
!v_result.classList.add("disabled");
EndIf
If *Callback <> #Null
!v_result.addEventListener('click', p_callback);
EndIf
; add a 5 pixels margin around every buttons.
!v_result.style.margin = '5px';
!v_parent.append(v_result);
ProcedureReturn Result
EndProcedure
Procedure ButtonSetCallback(Button, *Callback)
!v_button.addEventListener('click', p_callback);
EndProcedure
;===========================================================================
; Card
;===========================================================================
Procedure Card(Text.s = "", Flags = #Card_Default, Parent = #Null)
CheckParent()
PushParent()
!materialsb$g_current_parent = document.createElement('div');
If Flags & #Card_Panel
!materialsb$g_current_parent.classList.add("card-panel");
Else
!materialsb$g_current_parent.classList.add("card");
EndIf
If Flags & #Card_Small
!materialsb$g_current_parent.classList.add("small");
EndIf
If Flags & #Card_Medium
!materialsb$g_current_parent.classList.add("medium");
EndIf
If Flags & #Card_Large
!materialsb$g_current_parent.classList.add("large");
EndIf
If Flags & #Card_Horizontal
!materialsb$g_current_parent.classList.add("horizontal");
EndIf
If Text <> ""
!materialsb$g_current_parent.innerHTML = v_text;
EndIf
!v_parent.append(materialsb$g_current_parent);
ProcedureReturn current_parent
EndProcedure
Procedure CardImage(Source.s, Parent = #Null)
Protected Result
CheckParent()
!v_result = document.createElement('div');
!v_result.className = "card-image";
!v_result.innerHTML = '<img src="' + v_source + '">';
!v_parent.append(v_result);
ProcedureReturn Result
EndProcedure
Procedure CardContent(Parent = #Null)
CheckParent()
PushParent()
!materialsb$g_current_parent = document.createElement('div');
!materialsb$g_current_parent.className = "card-content";
!v_parent.append(materialsb$g_current_parent);
ProcedureReturn current_parent
EndProcedure
Procedure CardTitle(Text.s, Parent = #Null)
Protected Result
CheckParent()
!v_result = document.createElement('span');
!v_result.className = "card-title";
!v_result.innerHTML = v_text;
!v_parent.append(v_result);
ProcedureReturn Result
EndProcedure
Procedure CardAction(Parent = #Null)
CheckParent()
PushParent()
!materialsb$g_current_parent = document.createElement('div');
!materialsb$g_current_parent.className = "card-action";
!v_parent.append(materialsb$g_current_parent);
ProcedureReturn current_parent
EndProcedure
;===========================================================================
; Carousel
;===========================================================================
Procedure Carousel(Flags = #Carousel_Default, Parent = #Null)
Protected Result
CheckParent()
!v_result = document.createElement('div');
!v_result.className = "carousel";
If Flags & #Carousel_Slider
!v_result.classList.add("carousel-slider");
EndIf
!v_parent.append(v_result);
ProcedureReturn Result
EndProcedure
Procedure CarouselAddItem(Carousel, ImageSource.s, Link.s)
Protected Result
!v_result = document.createElement('a');
!v_result.className = "carousel-item";
!v_result.href = v_link;
!v_result.innerHTML = '<img src="' + v_imagesource + '">';
!v_carousel.append(v_result);
ProcedureReturn Result
EndProcedure
;===========================================================================
; Tabs
;===========================================================================
Procedure Tab(Flags = #Tab_Default, Parent = #Null)
Protected Result
CheckParent()
!v_result = document.createElement('ul');
!v_result.className = "tabs";
!v_parent.append(v_result);
ProcedureReturn Result
EndProcedure
Procedure TabAddItem(Title.s, Tab, ID.s, Flags = #Tab_Default)
Protected Result
!v_result = document.createElement('li');
!v_result.className = "tab";
!v_result.innerHTML = '<a href="#' + v_id + '">' + v_title + '</a>';
If Flags & #Tab_Disabled
!v_result.classList.add("disabled");
EndIf
!v_tab.append(v_result);
ProcedureReturn Result
EndProcedure
;===========================================================================
; Modal
;===========================================================================
Procedure Modal(Flags = #Modal_Default)
Protected Result, ID.s
!v_result = document.createElement('div');
!v_result.className = "modal";
; MaterializeCSS 2.1.1+ uses the Popover API
!v_result.setAttribute('popover', '');
If Flags & #Modal_FixedFooter
!v_result.classList.add("modal-fixed-footer");
EndIf
If Flags & #Modal_BottomSheet
!v_result.classList.add("bottom-sheet");
EndIf
; Modal must be added directly to body, outside of main content
!document.body.appendChild(v_result);
; Store reference for ModalContent/ModalFooter
!materialsb$g_current_modal = v_result;
ProcedureReturn Result
EndProcedure
Procedure ModalHeader(Text.s, Parent = #Null)
Protected Result
If Parent = #Null
!v_parent = materialsb$g_current_modal;
EndIf
!v_result = document.createElement('div');
!v_result.className = "modal-header";
!v_result.innerHTML = v_text;
!v_parent.appendChild(v_result);
ProcedureReturn Result
EndProcedure
Procedure ModalContent(Parent = #Null)
Protected Result
If Parent = #Null
!v_parent = materialsb$g_current_modal;
EndIf
!v_result = document.createElement('div');
!v_result.className = "modal-content";
!v_parent.appendChild(v_result);
; Set as current parent for adding content
PushParent()
current_parent = Result
ProcedureReturn Result
EndProcedure
Procedure ModalFooter(Parent = #Null)
Protected Result
If Parent = #Null
!v_parent = materialsb$g_current_modal;
EndIf
!v_result = document.createElement('div');
!v_result.className = "modal-footer";
!v_parent.appendChild(v_result);
; Set as current parent for adding buttons
PushParent()
current_parent = Result
ProcedureReturn Result
EndProcedure
Procedure ModalOpen(ModalElement)
!v_modalelement.showPopover();
EndProcedure
Procedure ModalClose(ModalElement)
!v_modalelement.hidePopover();
EndProcedure
;===========================================================================
; Toast
;===========================================================================
Procedure Toast(Text.s, Duration = 4000, Flags = #Toast_Default, Color.s = "")
Protected Classes.s = ""
If Flags & #Toast_Rounded
Classes = "rounded"
EndIf
; Add color class if specified
If Color <> ""
If Classes <> ""
Classes + " "
EndIf
Classes + Color
EndIf
; toast changed in 2.1.1 See: github.com/materializecss/materialize/issues/604
!new M.Toast({
! text: v_text,
! classes: v_classes,
! displayLength: v_duration
!});
EndProcedure
Procedure ToastDismissAll()
!M.Toast.dismissAll();
EndProcedure
;===========================================================================
; Forms
;===========================================================================
Procedure TextInput(Label.s = "", Placeholder.s = "", Flags = #Input_Default, Parent = #Null)
Protected Result, InputType.s = "text"
CheckParent()
; Determine input type from flags
If Flags & #Input_Password
InputType = "password"
ElseIf Flags & #Input_Email
InputType = "email"
ElseIf Flags & #Input_Number
InputType = "number"
ElseIf Flags & #Input_Tel
InputType = "tel"
ElseIf Flags & #Input_Url
InputType = "url"
ElseIf Flags & #Input_Date
InputType = "date"
ElseIf Flags & #Input_Time
InputType = "time"
EndIf
; Create wrapper div
!var _wrapper = document.createElement('div');
!_wrapper.className = "input-field";
If Flags & #Input_Outlined
!_wrapper.classList.add("outlined");
EndIf
; Create input element
!v_result = document.createElement('input');
!v_result.type = v_inputtype;
If Placeholder <> ""
!v_result.placeholder = v_placeholder;
EndIf
If Flags & #Input_Disabled
!v_result.disabled = true;
EndIf
If Flags & #Input_Readonly
!v_result.readOnly = true;
EndIf
!_wrapper.append(v_result);
; Create label if provided
If Label <> ""
!var _label = document.createElement('label');
; !_label.htmlFor = v_id;
!_label.innerHTML = v_label;
!_wrapper.append(_label);
EndIf
!v_parent.append(_wrapper);
ProcedureReturn Result
EndProcedure
Procedure Textarea(Label.s = "", Placeholder.s = "", Flags = #Textarea_Default, Parent = #Null)
Protected Result
CheckParent()
; Create wrapper div
!var _wrapper = document.createElement('div');
!_wrapper.className = "input-field";
If Flags & #Textarea_Outlined
!_wrapper.classList.add("outlined");
EndIf
; Create textarea element
!v_result = document.createElement('textarea');
!v_result.className = "materialsb-textarea";
If Placeholder <> ""
!v_result.placeholder = v_placeholder;
EndIf
If Flags & #Textarea_Disabled
!v_result.disabled = true;
EndIf
If Flags & #Textarea_Readonly
!v_result.readOnly = true;
EndIf
!_wrapper.append(v_result);
; Create label if provided
If Label <> ""
; !var _label = document.createElement('label');
; !_label.htmlFor = v_id;
; !_label.innerHTML = v_label;
; !_wrapper.append(_label);
EndIf
!v_parent.append(_wrapper);
ProcedureReturn Result
EndProcedure
Procedure Checkbox(Label.s, Flags = #Checkbox_Default, Parent = #Null)
Protected Result
CheckParent()
; Create label wrapper (MaterialSB structure)
!var _label = document.createElement('label');
; Create checkbox input
!v_result = document.createElement('input');
!v_result.type = "checkbox";
If Flags & #Checkbox_Filled
!v_result.classList.add("filled-in");
EndIf
If Flags & #Checkbox_Checked
!v_result.checked = true;
EndIf
If Flags & #Checkbox_Disabled
!v_result.disabled = true;
EndIf
!_label.append(v_result);
; Create span for label text
!var _span = document.createElement('span');
!_span.innerHTML = v_label;
!_label.append(_span);
; Wrap in p for proper spacing
!var _p = document.createElement('p');
!_p.append(_label);
!v_parent.append(_p);
ProcedureReturn Result
EndProcedure
Procedure Radio(Name.s, Label.s, Flags = #Radio_Default, Parent = #Null)
Protected Result
CheckParent()
; Create label wrapper
!var _label = document.createElement('label');
; Create radio input
!v_result = document.createElement('input');
!v_result.type = "radio";
!v_result.name = v_name;
If Flags & #Radio_WithGap
!v_result.classList.add("with-gap");
EndIf
If Flags & #Radio_Checked
!v_result.checked = true;
EndIf
If Flags & #Radio_Disabled
!v_result.disabled = true;
EndIf
!_label.append(v_result);
; Create span for label text
!var _span = document.createElement('span');
!_span.innerHTML = v_label;
!_label.append(_span);
; Wrap in p for proper spacing
!var _p = document.createElement('p');
!_p.append(_label);
!v_parent.append(_p);
ProcedureReturn Result
EndProcedure
Procedure Switch(LabelOff.s, LabelOn.s, Flags = #Switch_Default, Parent = #Null)
Protected Result
CheckParent()
; Create switch wrapper
!var _wrapper = document.createElement('div');
!_wrapper.className = "switch";
; Create label
!var _label = document.createElement('label');
!_label.innerHTML = v_labeloff;
; Create checkbox input
!v_result = document.createElement('input');
!v_result.type = "checkbox";
If Flags & #Switch_Checked
!v_result.checked = true;
EndIf
If Flags & #Switch_Disabled
!v_result.disabled = true;
EndIf
!_label.append(v_result);
; Create lever span
!var _lever = document.createElement('span');
!_lever.className = "lever";
!_label.append(_lever);
; Add "on" label text
!_label.innerHTML += v_labelon;
!_wrapper.append(_label);
!v_parent.append(_wrapper);
ProcedureReturn Result
EndProcedure
Procedure Dropdown(Label.s = "", Flags = #Dropdown_Default, Parent = #Null)
Protected Result
CheckParent()
; Create wrapper div
!var _wrapper = document.createElement('div');
!_wrapper.className = "input-field";
If Flags & #Dropdown_Outlined
!_wrapper.classList.add("outlined");
EndIf
; Create select element
!v_result = document.createElement('select');
If Flags & #Dropdown_Multiple
!v_result.multiple = true;
EndIf
If Flags & #Dropdown_Disabled
!v_result.disabled = true;
EndIf
!_wrapper.append(v_result);
; Create label if provided
If Label <> ""
!var _label = document.createElement('label');
!_label.innerHTML = v_label;
!_wrapper.append(_label);
EndIf
!v_parent.append(_wrapper);
ProcedureReturn Result
EndProcedure
Procedure DropdownAddOption(Text.s, Value.s, SelectElement, Selected = #False)
Protected Result
!v_result = document.createElement('option');
!v_result.value = v_value;
!v_result.innerHTML = v_text;
If Selected
!v_result.selected = true;
EndIf
!v_selectelement.append(v_result);
ProcedureReturn Result
EndProcedure
Procedure Range(Min = 0, Max = 100, Value = 50, Flags = #Range_Default, Parent = #Null)
Protected Result
CheckParent()
; Create wrapper
!var _wrapper = document.createElement('p');
!_wrapper.className = "range-field";
; Create range input
!v_result = document.createElement('input');
!v_result.type = "range";
!v_result.min = v_min;
!v_result.max = v_max;
!v_result.value = v_value;
If Flags & #Range_Disabled
!v_result.disabled = true;
EndIf
!_wrapper.append(v_result);
!v_parent.append(_wrapper);
ProcedureReturn Result
EndProcedure
Procedure InputSetCallback(InputElement, *Callback)
!v_inputelement.addEventListener('input', p_callback);
EndProcedure
;===========================================================================
; Private Procedures
;===========================================================================
Procedure Handler_Download(url.s, success)
If success
Select url
Case "LocalFiles/CSS/materialize.min.css"
LoadScript("LocalFiles/CSS/material-icons.css", @Handler_Download(), #PB_Script_CSS)
Case "LocalFiles/CSS/material-icons.css"
LoadScript("LocalFiles/JS/materialize.min.js", @Handler_Download(), #PB_Script_JavaScript)
Case "LocalFiles/JS/materialize.min.js"
; Remove SpiderBasic's default styles
!$('link[href="/spiderbasic/libraries/javascript/dojo/themes/flat/flat.css"]').remove();
!$('link[href="/spiderbasic/libraries/javascript/dojo/dgrid/css/dgrid.css"]').remove();
!$('link[href="/spiderbasic/libraries/javascript/themes/flat/window.css"]').remove();
!document.body.removeAttribute('id');
!document.body.removeAttribute('class');
!document.body.removeAttribute('oncontextmenu');
!document.body.removeAttribute('onload');
; Initialize
SetDarkTheme(#True)
!document.body.style.minHeight = '100vh';
; Create main container
!materialsb$g_current_parent = document.createElement('main');
!document.body.append(materialsb$g_current_parent);
; Remove SB's scroll event
! $(document).off('scroll');
; Call user callback
!materialsb$g_download_callback(1);
EndSelect
Else
!materialsb$g_download_callback(0);
EndIf
EndProcedure
EndModule
; IDE Options = SpiderBasic 3.10 (Windows - x86)
; CursorPosition = 516
; Folding = IACAAAAAAAAAAAAg
; iOSAppOrientation = 0
; AndroidAppCode = 0
; AndroidAppOrientation = 0
; EnableXP
; DPIAware
; CompileSourceDirectory